diff options
1309 files changed, 100096 insertions, 70989 deletions
diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..48d8031bd0 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,40 @@ +language: erlang + +otp_release: + - 18.0 + +sudo: false + +addons: + apt: + packages: + - autoconf + - libncurses-dev + - build-essential + - libssl-dev + - libwxgtk2.8-dev + - libgl1-mesa-dev + - libglu1-mesa-dev + - libpng3 + - default-jdk + - g++ + - xsltproc + +before_script: + - set -e + - export ERL_TOP=$PWD + - export PATH=$ERL_TOP/bin:$PATH + - export ERL_LIBS='' + - export MAKEFLAGS=-j6 + - kerl_deactivate + +script: + - ./otp_build all -a + +after_success: + - ./otp_build tests && make release_docs + +after_script: + - cd $ERL_TOP/release/tests/test_server && $ERL_TOP/bin/erl -s ts install -s ts smoke_test batch -s init stop + + diff --git a/HOWTO/INSTALL-WIN32.md b/HOWTO/INSTALL-WIN32.md index 79d89551c0..067c939d7a 100644 --- a/HOWTO/INSTALL-WIN32.md +++ b/HOWTO/INSTALL-WIN32.md @@ -4,82 +4,110 @@ How to Build Erlang/OTP on Windows Introduction ------------ -This file describes how to build the Erlang emulator and the OTP -libraries on Windows. The instructions apply to versions of Windows -supporting the Cygwin emulated gnuish environment for Windows or the -Msys ditto. We've built on the following platforms: Windows 2003 -server, Windows XP Home/Professional, Windows Vista and Windows 7 (32 -and 64 bit). You can probably build on Windows 2000, but you will not -be able to install the latest Microsoft SDK, so you have to go back to -some earlier compiler. Any Windows95'ish platform will surely get you -into trouble, what I'm not sure of, but it certainly will... - -The procedure described uses either Cygwin or Msys as a build -environment, you run the bash shell in Cygwin/Msys and use gnu -make/configure/autoconf etc to do the build. The emulator C-source -code is, however, mostly compiled with Microsoft Visual C++™, -producing a native Windows binary. This is the same procedure as we -use to build the pre-built binaries. The fact that we use VC++ and not -gcc is explained further in the FAQ section. - -I describe the build procedure to make it possible for open source -customers to build the emulator, given that they have the needed -tools. The binary Windows releases is still a preferred alternative if -one does not have Microsoft's development tools and/or don't want to -install Cygwin or Msys. - -To use Cygwin/Msys, one needs basic experience from a Unix environment, if -one does not know how to set environment variables, run programs etc -in a Unix environment, one will be quite lost in the Cygwin os Msys -ditto. I can unfortunately not teach all the world how to use -Cygwin and bash, neither how to install Cygwin nor perform basic tasks -on a computer. Please refer to other documentation on the net for -help, or use the binary release instead if you have problems using the -tools. - -However, if you feel comfortable with the environment and build +This section describes how to build the Erlang emulator and the OTP +libraries on Windows. Note that the Windows binary releases are still +a preferred alternative if one does not have Microsoft’s development +tools and/or don’t want to install Cygwin, MSYS or MSYS2. + +The instructions apply to versions of Windows supporting the Cygwin +emulated gnuish environment or the MSYS or MSYS2 ditto. We’ve built on +the following platforms: Windows 2012, Windows 7, Windows 8 and Windows 10. +It’s probably possible to build on older platforms too, but you might +not be able to install the appropriate Microsoft SDK, Visual Studio or +OpenSSL, in which case you will need to go back to earlier compilers etc. + +The procedure described uses either Cygwin, MSYS or MSYS2 as a build +environment. You run the bash shell in Cygwin/MSYS/MSYS2 and use the gnu +make/configure/autoconf etc to do the build. The emulator C-source code +is, however, mostly compiled with Microsoft Visual C++™, producing a +native Windows binary. This is the same procedure as we use to build the +pre-built binaries. Why we use VC++ and not gcc is explained further in +the FAQ section. + +If you are not familiar with Cygwin, MSYS, MSYS2 or a Unix environment, +you’ll probably need to read up a bit on how that works. There are plenty of +documentation about this online. + +These instructions apply for both 32-bit and 64-bit Windows. Note that even +if you build a 64-bit version of Erlang, most of the directories and files +involved are still named win32. Some occurances of the name win64 are +however present. The installation file for a 64-bit Windows version of +Erlang, for example, is `otp_win64_%OTP-REL%.exe`. + +If you feel comfortable with the environment and build system, and have all the necessary tools, you have a great opportunity to make the Erlang/OTP distribution for Windows better. Please submit -any suggestions and patches to the appropriate [mailing lists] [1] to let +any suggestions to our [JIRA] [2] and patches to our [git project] [3] to let them find their way into the next version of Erlang. If making changes to the build system (like makefiles etc) please bear in mind that the same makefiles are used on Unix/VxWorks, so that your changes -don't break other platforms. That of course goes for C-code too, system +don't break other platforms. That of course goes for C-code too; system specific code resides in the `$ERL_TOP/erts/emulator/sys/win32` and `$ERL_TOP/erts/etc/win32` directories mostly. The `$ERL_TOP/erts/emulator/beam` directory is for common code. -Before the R9C release of Erlang/OTP, the Windows release was built -partly on a Unix (Solaris) box and partly on a Windows box, using Perl -hacks to communicate and sync between the two machines. R9C was the -first release ever built solely on Windows, where no Unix machine is -needed at all. Now we've used this build procedure for a couple of +We've used this build procedure for a couple of releases, and it has worked fine for us. Still, there might be all sorts of troubles on different machines and with different -setups. I'll try to give hints wherever I've encountered difficulties, +setups. We'll try to give hints wherever we've encountered difficulties, but please share your experiences by using the [erlang-questions] [1] -mailing list. I cannot of course help everyone with all -their problems, please try to solve the problems and submit -solutions/workarounds. Remember, it's all about sharing, not about -demanding... - -Starting with R15B, our build system runs both on Cygwin and Msys -(MinGW's fork of an early cygwin version). Msys is a smaller package -to install and may on some machines run slightly faster. If Cygwin -gives you trouble, try Msys instead, and v.v. Beginning with R15B -there is also a native 64bit version of Erlang for 64bit Windows 7 -(only). These instructions apply to both the 32bit VM and the 64bit -ditto. - -Note that even if you build a 64bit VM, most of the directories and -files involved are still named win32. You can view the name win32 as -meaning any windows version not beeing 16bit. A few occurences of the -name Win64 are however present in the system, for example the -installation file for a 64 bit windows version of Erlang is by default -named `otp_win64_<version>.exe`. - -Lets go then, I'll start with a little FAQ, based on in house questions -and misunderstandings. +mailing list. We cannot, of course, help everyone with all +their issues, so please try to solve such issues and submit +solutions/workarounds. + +Lets go then! We’ll start with a short version of the setup procedure, +followed by some FAQ, and then we’ll go into more details of the setup. + + +Short Version +-------------------------- +In the following sections, we've described as much as we could about the +installation of the tools needed. Once the tools are installed, building +is quite easy. We have also tried to make these instructions understandable +for people with limited Unix experience. Cygwin/MSYS/MSYS2 is a whole new +environment to some Windows users, why careful explanation of environment +variables etc seemed to be in place. + +This is the short story though, for the experienced and impatient: + + * Get and install complete Cygwin (latest), complete MinGW with MSYS or + complete MSYS2 + + * Install Visual Studio 12.0 (2013) + + * Install Microsofts Windows SDK 8.1 + + * Get and install Sun's JDK 1.6.0 or later + + * Get and install NSIS 2.01 or later (up to 2.46 tried and working) + + * Get, build and install OpenSSL 0.9.8r or later (up to 1.0.2d + tried & working) with static libs. + + * Get the Erlang source distribution (from + <http://www.erlang.org/download.html>) and unpack with + Cygwin's/MSYS's/MSYS2's `tar`. + + * Set `ERL_TOP` to where you unpacked the source distribution + + * `$ cd $ERL_TOP` + + * Modify PATH and other environment variables so that all these tools + are runnable from a bash shell. Still standing in `$ERL_TOP`, issue + the following commands (for 32-bit Windows, remove the x64 from the + first row and change `otp_win64_%OTP-REL%` to `otp_win32_%OTP-REL%` on + the last row): + + $ eval `./otp_build env_win32 x64` + $ ./otp_build autoconf + $ ./otp_build configure + $ ./otp_build boot -a + $ ./otp_build release -a + $ ./otp_build installer_win32 + $ release/win32/otp_win64_%OTP-REL% /S + + Voila! `Start->Programs->Erlang OTP %OTP-REL%->Erlang` starts the Erlang + Windows shell. Frequently Asked Questions @@ -88,12 +116,12 @@ Frequently Asked Questions * Q: So, now I can build Erlang using GCC on Windows? A: No, unfortunately not. You'll need Microsoft's Visual C++ - still, a Bourne-shell script (cc.sh) wraps the Visual C++ compiler + still. A Bourne-shell script (cc.sh) wraps the Visual C++ compiler and runs it from within the Cygwin environment. All other tools needed to build Erlang are free-ware/open source, but not the C compiler. The Windows SDK is however enough to build Erlang, you do not need to buy Visual C++, just download the SDK (SDK version - 7.1 == Visual studio 2010). + 8.1 == Visual studio 2013). * Q: Why haven't you got rid of VC++ then, you \*\*\*\*\*\*? @@ -106,18 +134,17 @@ Frequently Asked Questions mingw build will possibly be back, but as long as VC++ gives better performance, the commercial build will be a VC++ one. -* Q: OK, you need VC++, but now you've started to demand a very recent - (and expensive) version of Visual studio, not the old and stable VC++ - 6.0 that was used in earlier versions. Why? +* Q: OK, you need VC++, but now you've started to demand a quite recent + (and expensive) version of Visual Studio. Why? A: Well, it's not expensive, it's free (as in free beer). Just download and install the latest Windows SDK from Microsoft and all the tools you need are there. The included debugger (WinDbg) is - also quite usable, it's what I used when porting Erlang to 64bit - Windows. Another reason to use the latest Microsoft compilers is + also quite usable. That's what I used when porting Erlang to 64bit + Windows. Another reason to use later Microsoft compilers is DLL compatibility. DLL's using a new version of the standard library might not load if the VM is compiled with an old VC++ - version, why we should aim to use the latest freely available SDK + version. So we should aim to use the latest freely available SDK and compiler. * Q: Can/will I build a Cygwin binary with the procedure you describe? @@ -130,9 +157,7 @@ Frequently Asked Questions some problems. Fixing those problems might be easy or might be hard. I suggest you try yourself and share your experience. No one would be happier if a simple `./configure && make` would produce a fully fledged - Cygwin binary. Ericsson does however not pay me to do a Cygwin port, so - such a port would have to happen in spare time, which is a limited - resource... + Cygwin binary. * Q: Hah, I saw you, you used GCC even though you said you didn't! @@ -142,7 +167,7 @@ Frequently Asked Questions particular file, `beam_emu.c` benefits immensely from being able to use the GCC labels-as-values extension, which boosts emulator performance by up to 50%. That does unfortunately not (yet) mean - that all of OTP could be compiled using GCC, that particular + that all of OTP could be compiled using GCC. That particular source code does not do anything system specific and actually is adopted to the fact that GCC is used to compile it on Windows. @@ -152,229 +177,184 @@ Frequently Asked Questions A: No, never. The hassle of keeping the project files up to date and do all the steps that constitute an OTP build from within the VC++ GUI is simply not worth it, maybe even impossible. A VC++ project - file for Erlang/OTP will never happen, at least I will never make - one. Clicking around in super-multi-tab'd dialogs to add a file or - compiler option when it's so much easier in a makefile is simply not - my style. + file for Erlang/OTP will never happen. * Q: So how does it all work then? - A: Cygwin or Msys is the environment, which closely resembles the - environments found on any Unix machine. It's almost like you had a + A: Cygwin, MSYS or MSYS2 is the environment, which closely resembles the + environment found on any Unix machine. It's almost like you had a virtual Unix machine inside Windows. Configure, given certain parameters, then creates makefiles that are used by the - Cygwin/Msys gnu-make to built the system. Most of the actual - compilers etc are not, however, Cygwin/Msys tools, so I've written + environment's gnu-make to built the system. Most of the actual + compilers etc are not, however, Cygwin/MSYS/MSYS2 tools, so we've written a couple of wrappers (Bourne-shell scripts), which reside in `$ERL_TOP/etc/win32/cygwin_tools` and `$ERL_TOP/etc/win32/msys_tools`. They all do conversion of parameters and switches common in the Unix environment to fit the native Windows tools. Most notable is of course the paths, which - in Cygwin/Msys are Unix-like paths with "forward slashes" (/) and - no drive letters, the Cygwin specific command `cygpath` is used - for most of the path conversions in a Cygwin environment, other - tools are used (when needed) in the corresponding Msys + in Cygwin/MSYS/MSYS2 are Unix-like paths with "forward slashes" (/) and + no drive letters. The Cygwin specific command `cygpath` is used + for most of the path conversions in a Cygwin environment. Other + tools are used (when needed) in the corresponding MSYS and MSYS2 environment. Luckily most compilers accept forward slashes instead of backslashes as path separators, but one still have to get the drive letters etc right, though. The wrapper scripts are not general in - the sense that, for example, cc.sh would understand and translates - every possible gcc option and passes correct options to + the sense that, for example, cc.sh would understand and translate + every possible gcc option and pass correct options to cl.exe. The principle is that the scripts are powerful enough to allow building of Erlang/OTP, no more, no less. They might need - extensions to cope with changes during the development of Erlang, - that's one of the reasons I made them into shell-scripts and not - Perl-scripts, I believe they are easier to understand and change - that way. I might be wrong though, cause another reason I didn't - write them in Perl is because I've never liked Perl and my Perl - code is no pleasant reading... + extensions to cope with changes during the development of Erlang, and + that's one of the reasons we made them into shell-scripts and not + Perl-scripts. We believe they are easier to understand and change + that way. In `$ERL_TOP`, there is a script called `otp_build`. That script handles the hassle of giving all the right parameters to `configure`/`make` and also helps you set up the correct environment variables to work with - the Erlang source under Cygwin. + the Erlang source under Cygwin/MSYS/MSYS2. * Q: You use and need Cygwin, but then you haven't taken the time to port Erlang to the Cygwin environment but instead focus on your commercial release, is that really ethical? - A: No, not really, but see this as a step in the right direction. I'm - aiming at GCC compiled emulators and a Cygwin version, but I really - need to do other things as well... In time, but don't hold your - breath... + A: No, not really, but see this as a step in the right direction. * Q: Can I build something that looks exactly as the commercial release? - A: Yes, we use the exactly same build procedure. + A: Yes, we use the exact same build procedure. -* Q: Which version of Cygwin/Msys and other tools do you use then? +* Q: Which version of Cygwin/MSYS/MSYS2 and other tools do you use then? - A: For Cygwin and Msys alike, we try to use the latest releases + A: For Cygwin, MSYS and MSYS2 alike, we try to use the latest releases available when building. What versions you use shouldn't really - matter, I try to include workarounds for the bugs I've found in - different Cygwin/Msys releases, please help me add workarounds - for new Cygwin/Msys-related bugs as soon as you encounter - them. Also please do submit bug reports to the appropriate Cygwin - and/or Msys developers. The GCC we used for %OTP-REL% was version - 4.7.0 (MinGW 64bit) and 4.3.4 (Cygwin 32bit). We used VC++ 10.0 - (i.e. Visual studio 2010), Sun's JDK 1.5.0\_17 (32bit) and Sun's - JDK 1.7.0\_1 (64bit), NSIS 2.46, and Win32 OpenSSL 0.9.8r. Please + matter. We try to include workarounds for the bugs we've found in + different Cygwin/MSYS/MSYS2 releases. Please help us add workarounds + for new Cygwin/MSYS/MSYS2-related bugs as soon as you encounter + them. Also please do submit bug reports to the appropriate Cygwin, MSYS + and/or MSYS2 developers. The GCC we used for %OTP-REL% was version + 4.8.1 (MinGW 32bit) and 4.8.5 (MSYS2 64bit). We used VC++ 12.0 + (i.e. Visual studio 2013), Sun's JDK 1.6.0\_45 (32bit) and Sun's + JDK 1.7.0\_1 (64bit), NSIS 2.46, and Win32 OpenSSL 1.0.2d. Please read the next section for details on what you need. -* Q: Can you help me setup X in Cygwin? +* Q: Can you help me setup X in Cygwin/MSYS/MSYS2? - A: No, unfortunately I haven't got time to help with Cygwin related - user problems, please read Cygwin related web sites, newsgroups and + A: No, unfortunately we haven't got time to help with Cygwin/MSYS/MSYS2 + related user problems, please read related websites, newsgroups and mailing lists. -* Q: Why is the instruction so long? Is it really that complicated? - - A: Partly it's long because I babble too much, partly because I've - described as much as I could about the installation of the needed - tools. Once the tools are installed, building is quite easy. I also - have tried to make this instruction understandable for people with - limited Unix experience. Cygwin/Msys is a whole new environment to some - Windows users, why careful explanation of environment variables etc - seemed to be in place. The short story, for the experienced and - impatient is: - - * Get and install complete Cygwin (latest) or complete MinGW with msys - - * Install Microsofts Windows SDK 7.1 (and .Net 4) - - * Get and install Sun's JDK 1.5.0 or higher - - * Get and install NSIS 2.01 or higher (up to 2.46 tried and working) - - * Get, build and install OpenSSL 0.9.8r or higher (up to 1.0.0a - tried & working) with static libs. - - * Get the Erlang source distribution (from - <http://www.erlang.org/download.html>) and unpack with Cygwin's `tar`. - - * Set `ERL_TOP` to where you unpacked the source distribution - - * `$ cd $ERL_TOP` - - * Get (from <http://www.erlang.org/download/tcltk85_win32_bin.tar.gz>) - and unpack the prebuilt TCL/TK binaries for windows with cygwin tar, - standing in `$ERL_TOP` - - * Modify PATH and other environment variables so that all these tools - are runnable from a bash shell. Still standing in `$ERL_TOP`, issue - the following commands: - - $ eval `./otp_build env_win32` - $ ./otp_build autoconf - $ ./otp_build configure - $ ./otp_build boot -a - $ ./otp_build release -a - $ ./otp_build installer_win32 - $ release/win32/otp_win32_%OTP-REL% /S - - Voila! `Start->Programs->Erlang OTP %OTP-REL%->Erlang` starts the Erlang - Windows shell. - Tools you Need and Their Environment ------------------------------------ You need some tools to be able to build Erlang/OTP on Windows. Most -notably you'll need Cygwin or Msys and Microsofts Windows SDK, but -you also might want a Java compiler, the NSIS install system and -OpenSSL. Well' here's the list: +notably you'll need Cygwin, MSYS or MSYS2, Visual Studio and Microsofts +Windows SDK, but you might also want a Java compiler, the NSIS install +system and OpenSSL. Well, here's some information about the different +tools: * Cygwin, the very latest is usually best. Get all the development - tools and of course all the basic ditto. In fact getting the complete - package might be a good idea, as you'll start to love Cygwin after a - while if you're accustomed to Unix. Make sure to get jar and also make - sure *not* to install a Cygwin'ish Java... The Cygwin jar command is - used but Sun's Java compiler and virtual machine... + tools and of course all the basic ditto. Make sure to get jar and + also make sure *not* to install a Cygwin'ish Java, since the Cygwin + jar command is used but Sun's Java compiler and virtual machine. If you are going to build a 64bit Windows version, you should make - sure to get MinGW's 64bit gcc installed with cygwin. It's in one of + sure to get MinGW's 64bit gcc installed with Cygwin. It's in one of the development packages. URL: <http://www.cygwin.com> - Get the installer from the web site and use that to install - Cygwin. Be sure to have fair privileges. If you're on a NT domain you + Get the installer from the website and use it to install + Cygwin. Be sure to have fair privileges. If you're on an NT domain you should consider running `mkpasswd -d` and `mkgroup -d` after the installation to get the user databases correct. See their respective manual pages. - When you start you first bash shell, you will get an awful prompt. You + When you start your first bash shell, you will get an awful prompt. You might also have a `PATH` environment variable that contains backslashes and such. Edit `$HOME/.profile` and `$HOME/.bashrc` to set fair prompts - and set a correct PATH. Also do a `export SHELL` in `.profile`. For some + and a correct PATH. Also do an `export SHELL` in `.profile`. For some non-obvious reason the environment variable `$SHELL` is not exported in bash. Also note that `.profile` is run at login time and `.bashrc` when sub shells are created. You'll need to explicitly source `.bashrc` from `.profile` if you want the commands there to be run at login time (like - setting up aliases, shell functions and the like). I personally - usually do like this at the end of `.profile`: + setting up aliases, shell functions and the like). You can for example + do like this at the end of `.profile`: ENV=$HOME/.bashrc export ENV . $ENV - You might also, if you're a hard core type of person at least, want to - setup X-windows (XFree86), that might be as easy as running startx - from the command prompt and it might be much harder. Use Google to - find help... + You might also want to setup X-windows (XFree86). That might be as easy + as running startx from the command prompt and it might be much harder. + Use Google to find help. If you don't use X-windows, you might want to setup the Windows console window by selecting properties in the console system menu (upper left corner of the window, the Cygwin icon in the title bar). Especially setting a larger screen buffer size (lines) is useful as it gets you a scrollbar so you can see whatever error messages - that might appear... + that might appear. - If you want to use (t)csh instead of bash you're on your own, I - haven't tried and know of no one that has. I expect - that you use bash in all shell examples. + There are a few other shells available, but in all examples below we assume + that you use bash. -* Alternatively you download MinGW and Msys. You'll find the latest +* Alternatively you download MinGW and MSYS. You'll find the latest installer at: URL: <http://sourceforge.net/projects/mingw/files/Installer/mingw-get-inst/> - Make sure to install everything they've got. + Make sure to install the basic dev tools, but avoid the MinGW autoconf and + install the msys one instead. To be able to build the 64bit VM, you will also need the 64bit MinGW compiler from: - URL: <http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Automated%20Builds/> + URL: <http://sourceforge.net/projects/mingw-w64/files/latest/download?source=files> - The latest version should do it. Make sure you download the - `mingw-w64-bin_i686-mingw_<something>.zip`, not a linux + We've tried up to 1.0, but the latest version should do. Make sure you + download the `mingw-w64-bin_i686-mingw_<something>.zip`, not a linux version. You unzip the package on top of your MinGW installation (`c:\MinGW`) and that's it. - Setting up your environment in Msys is similar to setting it up in - Cygwin. +* A third alternative is to download and install MSYS2 from: -* Microsofts Windows SDK version 7.1 (corresponding to VC++ 10.0 and - Visual Studio 2010). You'll find it here: - - URL: <http://www.microsoft.com/download/en/details.aspx?id=8279> + URL: <https://msys2.github.io/> + + When you've followed the instructions there, you also need to install + these packages: autoconf, make, perl, and tar. You do so by running + the following in the msys console: + + pacman -S msys/autoconf msys/make msys/perl msys/tar + + You also need a gcc. If you installed the 64 bit MSYS2 you run: - but before you install that, you need to have .Net 4 installed, - you'll find that here: + mingw64/mingw-w64-x86_64-gcc - URL: <http://www.microsoft.com/download/en/details.aspx?id=17851> + And for 32 bit MSYS2: - Use the web installer for the SDK, at least when I tried - downloading the whole package as an image, I got SDK 7.0 instead, - which is not what you want... + pacman -S mingw32/mingw-w64-i686-gcc + pacman -S mingw-w64-i686-editrights - There will be a Windows command file in `%PROGRAMFILES%\Mirosoft - SDKs\Windows\v7.1\Bin\SetEnv.cmd` that set's the appropriate +* Visual Studio 2013 (Visual Studio 12.0). Download and run the web + installer from: + + https://www.visualstudio.com/ + +* Microsofts Windows SDK version 8.1 (corresponding to VC++ 12.0 and + Visual Studio 2013). You'll find it here: + + URL: <https://msdn.microsoft.com/en-us/windows/desktop/bg162891.aspx> + +* To help setup the environment, there is a bat file, + `%PROGRAMFILES%\Mirosoft Visual Studio 12.0\VC\vcvarsall.bat`, + that set's the appropriate environment for a Windows command prompt. This is not appropriate for bash, so you'll need to convert it to bash-style environments by editing your `.bash_profile`. In my case, where the SDK is installed in the default directory and `%PROGRAMFILES%` is `C:\Program Files`, the commands for setting up a 32bit build - environment (on a 64bit or 32bit machine) look like this (in cygwin): + environment (on a 64bit or 32bit machine) look like this (in Cygwin): # Some common paths C_DRV=/cygdrive/c @@ -383,309 +363,290 @@ OpenSSL. Well' here's the list: # nsis NSIS_BIN=$PRG_FLS/NSIS # java - JAVA_BIN=$PRG_FLS/Java/jdk1.6.0_16/bin + JAVA_BIN=$PROGRAMFILES/Java/jdk1.7.0_02/bin ## ## MS SDK ## - CYGWIN=nowinsymlinks - MVS10="$PRG_FILES/Microsoft Visual Studio 10.0" - WIN_MVS10="C:\\Program Files\\Microsoft Visual Studio 10.0" - SDK10="$PRG_FILES/Microsoft SDKs/Windows/v7.1" - WIN_SDK10="C:\\Program Files\\Microsoft SDKs\\Windows\\v7.1" + CYGWIN=nowinsymlinks + + VISUAL_STUDIO_ROOT=$PRG_FLS/Microsoft\ Visual\ Studio\ 12.0 + WIN_VISUAL_STUDIO_ROOT="C:\\Program Files\\Microsoft Visual Studio 12.0" + SDK=$PRG_FLS/Windows\ Kits/8.1 + WIN_SDK="C:\\Program Files\\Windows Kits\\8.1" PATH="$NSIS_BIN:\ - $MVS10/Common7/IDE:\ - $MVS10/Common7/Tools:\ - $MVS10/VC/Bin:\ - $MVS10/VC/Bin/VCPackages:\ - $SDK10/Bin/NETFX 4.0 Tools:\ - $SDK10/Bin:\ + $VISUAL_STUDIO_ROOT/VC/bin:\ + $VISUAL_STUDIO_ROOT/VC/vcpackages:\ + $VISUAL_STUDIO_ROOT/Common7/IDE:\ + $VISUAL_STUDIO_ROOT/Common7/Tools:\ + $SDK/bin/x86 /usr/local/bin:/usr/bin:/bin:\ /cygdrive/c/WINDOWS/system32:/cygdrive/c/WINDOWS:\ /cygdrive/c/WINDOWS/system32/Wbem:\ $JAVA_BIN" - LIBPATH="$WIN_MVS10\\VC\\LIB" + LIBPATH="$WIN_VISUAL_STUDIO_ROOT\\VC\\lib" - LIB="$WIN_MVS10\\VC\\LIB;$WIN_SDK10\\LIB" + LIB="$WIN_VISUAL_STUDIO_ROOT\\VC\\lib\\;$WIN_SDK\\lib\\winv6.3\\um\\x86" - INCLUDE="$WIN_MVS10\\VC\\INCLUDE;$WIN_SDK10\\INCLUDE;$WIN_SDK10\\INCLUDE\\gl" + INCLUDE="$WIN_VISUAL_STUDIO_ROOT\\VC\\include\\;$WIN_SDK\\include\\shared\\; + $WIN_SDK\\include\\um;$WIN_SDK\\include\\winrt\\;$WIN_SDK\\include\\um\\gl" - export CYGWIN PATH LIBPATH LIB INCLUDE + export CYGWIN PATH LIBPATH LIB INCLUDE - If you're using Msys instead, the only thing you need to change is - the `C_DRV` setting, which would read: + If you're using MinGW's MSYS instead, you need to change the `C_DRV` setting, + which would read: C_DRV=/c - And of course you might need to change `C:\Program Files` etc if - you're using a non-english version of Windows (XP). Note that in - later versions of Windows, the national adoptions of the program - files directories etc are not on the file system but only in the - explorer, so even if explorer says that your programs reside in - e.g. `C:\Program`, they might still reside in `C:\Program Files` - in reality... - - If you are building a 64 bit version of Erlang, you should set up - PATHs etc a little differently. I use the following script to - make things work in both Cygwin and Msys: - - make_winpath() - { - P=$1 - if [ "$IN_CYGWIN" = "true" ]; then - cygpath -d "$P" - else - (cd "$P" && /bin/cmd //C "for %i in (".") do @echo %~fsi") - fi - } - - make_upath() - { - P=$1 - if [ "$IN_CYGWIN" = "true" ]; then - cygpath "$P" - else - echo "$P" | /bin/sed 's,^\([a-zA-Z]\):\\,/\L\1/,;s,\\,/,g' - fi - } - - # Some common paths - if [ -x /usr/bin/msysinfo ]; then - # Without this the path conversion won't work - COMSPEC='C:\Windows\SysWOW64\cmd.exe' - MSYSTEM=MINGW32 - export MSYSTEM COMSPEC - IN_CYGWIN=false - else - CYGWIN=nowinsymlinks - export CYGWIN - IN_CYGWIN=true - fi - - if [ "$IN_CYGWIN" = "true" ]; then - PATH=/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:\ - /cygdrive/c/windows/system32:/cygdrive/c/windows:/cygdrive/c/windows/system32/Wbem - else - PATH=/usr/local/bin:/mingw/bin:/bin:/c/Windows/system32:/c/Windows:\ - /c/Windows/System32/Wbem - fi - - if [ "$IN_CYGWIN" = "true" ]; then - C_DRV=/cygdrive/c - else - C_DRV=/c - fi - - PRG_FLS64=$C_DRV/Program\ Files - PRG_FLS32=$C_DRV/Program\ Files\ \(x86\) - VISUAL_STUDIO_ROOT32=$PRG_FLS32/Microsoft\ Visual\ Studio\ 10.0 - MS_SDK_ROOT64=$PRG_FLS64/Microsoft\ SDKs/Windows/v7.1 - - # Okay, now mangle the paths and get rid of spaces by using short names - WIN_VCROOT32=`make_winpath "$VISUAL_STUDIO_ROOT32"` - VCROOT32=`make_upath $WIN_VCROOT32` - WIN_SDKROOT64=`make_winpath "$MS_SDK_ROOT64"` - SDKROOT64=`make_upath $WIN_SDKROOT64` - WIN_PROGRAMFILES32=`make_winpath "$PRG_FLS32"` - PROGRAMFILES32=`make_upath $WIN_PROGRAMFILES32` - - WIN_PROGRAMFILES64=`make_winpath "$PRG_FLS64"` - PROGRAMFILES64=`make_upath $WIN_PROGRAMFILES64` - - # nsis - NSIS_BIN=$PROGRAMFILES32/NSIS - # java - JAVA_BIN=$PROGRAMFILES64/Java/jdk1.7.0_01/bin - - ## The PATH variable should be Unix'ish - VCPATH=$VCROOT32/Common7/IDE:$VCROOT32/VC/BIN/amd64:$VCROOT32/Common7/Tools:\ - $VCROOT32/VC/VCPackages:$SDKROOT64/bin/NETFX4~1.0TO/x64:$SDKROOT64/bin/x64:\ - $SDKROOT64/bin - - ## Microsoft SDK libs - - LIBPATH=$WIN_VCROOT32\\VC\\LIB\\amd64 - LIB=$WIN_VCROOT32\\VC\\LIB\\amd64\;$WIN_SDKROOT64\\LIB\\X64 - INCLUDE=$WIN_VCROOT32\\VC\\INCLUDE\;$WIN_SDKROOT64\\include\;\ - $WIN_SDKROOT64\\include\\gl - - # Put nsis, c compiler and java in path - PATH=$NSIS_BIN:$VCPATH:$PATH:$JAVA_BIN - - # Make sure LIB and INCLUDE is available for others - export PATH LIBPATH LIB INCLUDE - - All this is derived from the SetEnv.cmd command file mentioned - earlier. The bottom line is to set the PATH so that NSIS and - Microsoft SDK is found before the Msys/Cygwin tools and that Java - is last in the PATH. - - Make a simple hello world (maybe one that prints out - `sizeof(void *)`) and try to compile it with the `cl` command from within - bash. If that does not work, your environment needs fixing. Also - remember to fix up the PATH environment, especially old Erlang - installations might have inserted quoted paths that Cygwin/Msys - does not understand. Remove or correct such paths. There should be - no backslashes in your path environment variable in Cygwin bash, - but LIB and INCLUDE should contain Windows style paths with - semicolon, drive letters and backslashes. + and you also need to change the PATH environment variable to: -* Sun's Java JDK 1.5.0 or higher. Our Java code (jinterface, ic) is - written for JDK 1.5.0. Get it for Windows and install it, the JRE is - not enough. If you don't care about Java, you can skip this step, the - result will be that jinterface is not built. + MINGW_BIN=/c/MinGW/bin - URL: <http://java.sun.com> - Add javac *LAST* to your path environment in bash, in my case this means: + PATH="$NSIS_BIN:\ + $VISUAL_STUDIO_ROOT/VC/bin:\ + $VISUAL_STUDIO_ROOT/VC/vcpackages:\ + $VISUAL_STUDIO_ROOT/Common7/IDE:\ + $VISUAL_STUDIO_ROOT/Common7/Tools:\ + $SDK/bin/x86:/usr/local/bin:\ + $MINGW_BIN:\ + /bin:/c/Windows/system32:/c/Windows:\ + /c/Windows/System32/Wbem:\ + $JAVA_BIN" - `PATH="$PATH:/cygdrive/c/Program Files/Java/jdk1.5.0_17/bin"` + For MSYS2 you use the same `C_DRV` and PATH as for MSYS, only update the `MINGW_BIN`: - No `CLASSPATH` or anything is needed. Type `javac` at the bash prompt - and you should get a list of available Java options. Make sure by - typing `type java` that you use the Java you installed. Note however that - Cygwin's `jar.exe` is used, that's why the JDK bin-directory should be - added last in the `PATH`. + MINGW_BIN=/mingw32/bin + -* Nullsoft NSIS installer system. You need this to build the self - installing package. It's a free open source installer that's much - nicer to use than the commercial Wise and Install shield - installers. This is the installer we use for commercial releases as - well from R9C an on. + If you are building a 64 bit version of Erlang, you should set up + PATHs etc a little differently. We have two templates to make things + work in both Cygwin and MSYS but needs editing to work with MSYS2 (see the + comments in the script). + The following one is for 32 bits: + + make_winpath() + { + P=$1 + if [ "$IN_CYGWIN" = "true" ]; then + cygpath -d "$P" + else + (cd "$P" && /bin/cmd //C "for %i in (".") do @echo %~fsi") + fi + } + + make_upath() + { + P=$1 + if [ "$IN_CYGWIN" = "true" ]; then + cygpath "$P" + else + echo "$P" | /bin/sed 's,^\([a-zA-Z]\):\\,/\L\1/,;s,\\,/,g' + fi + } - URL: <http://www.nullsoft.com/free/nsis> + # Some common paths + if [ -x /usr/bin/msys-?.0.dll ]; then + # Without this the path conversion won't work + COMSPEC='C:\Windows\System32\cmd.exe' + MSYSTEM=MINGW32 # Comment out this line if in MSYS2 + export MSYSTEM COMSPEC + # For MSYS2: Change /mingw/bin to the msys bin dir on the line below + PATH=/usr/local/bin:/mingw/bin:/bin:/c/Windows/system32:\ + /c/Windows:/c/Windows/System32/Wbem + C_DRV=/c + IN_CYGWIN=false + else + PATH=/ldisk/overrides:/usr/local/bin:/usr/bin:/bin:\ + /usr/X11R6/bin:/cygdrive/c/windows/system32:\ + /cygdrive/c/windows:/cygdrive/c/windows/system32/Wbem + C_DRV=/cygdrive/c + IN_CYGWIN=true + fi + + obe_otp_gcc_vsn_map=" + .*=>default + " + obe_otp_64_gcc_vsn_map=" + .*=>default + " + # Program Files + PRG_FLS=$C_DRV/Program\ Files - Install the lot, especially the modern user interface components, as - it's definitely needed. Put `makensis` in your path, in my case: + # Visual Studio + VISUAL_STUDIO_ROOT=$PRG_FLS/Microsoft\ Visual\ Studio\ 12.0 + WIN_VISUAL_STUDIO_ROOT="C:\\Program Files\\Microsoft Visual Studio 12.0" - PATH=/cygdrive/c/Program\ Files/NSIS:$PATH + # SDK + SDK=$PRG_FLS/Windows\ Kits/8.1 + WIN_SDK="C:\\Program Files\\Windows Kits\\8.1" - type makensis at the bash prompt and you should get a list of options - if everything is OK. + # NSIS + NSIS_BIN=$PROGRAMFILES/NSIS -* OpenSSL. This is if you want the SSL and crypto applications to - compile (and run). There are prebuilt binaries available, but I - strongly recommend building this yourself. It's quite easy. + # Java + JAVA_BIN=$PROGRAMFILES/Java/jdk1.7.0_02/bin - First get the source from + ## The PATH variable should be Cygwin'ish + VCPATH= + $VISUAL_STUDIO_ROOT/VC/bin:\ + $VISUAL_STUDIO_ROOT/VC/vcpackages:\ + $VISUAL_STUDIO_ROOT/Common7/IDE:\ + $VISUAL_STUDIO_ROOT/Common7/Tools:\ + $SDK/bin/x86 - URL: <http://openssl.org/source/> + ## Microsoft SDK libs + LIBPATH=$WIN_VISUAL_STUDIO_ROOT\\VC\\lib - I would recommend using 0.9.8r. + LIB=$WIN_VISUAL_STUDIO_ROOT\\VC\\lib\\;$WIN_KITS\\lib\\winv6.3\\um\\x86 - Download the tar file and unpack it (using your bash prompt) into - a directory of your choise. + INCLUDE=$WIN_VISUAL_STUDIO_ROOT\\VC\\include\\;\ + $WIN_KITS\\include\\shared\\;$WIN_KITS\\include\\um;\ + $WIN_KITS\\include\\winrt\\;$WIN_KITS\\include\\um\\gl - You will need a Windowish Perl for the build. ActiveState has one: + # Put nsis, c compiler and java in path + export PATH=$VCPATH:$PATH:$JAVA_BIN:$NSIS_BIN - URL: <http://www.activestate.com/activeperl/downloads> + # Make sure LIB and INCLUDE is available for others + export LIBPATH LIB INCLUDE - Download and install that. Disable options to associate it with - the .pl suffix and/or adding things to PATH, they are not needed. - Now fire up the Microsoft Windows SDK command prompt in RELEASE - mode for the architecture you are going to build. The easiest is - to copy the shortcut from the SDKs start menu item and edit the - command line in the shortcut (Right click->Properties) to end with - `/Release`. Make sure the banner when you double click your - shortcut (the text in the resulting command window) says - `Targeting Windows XP x64 Release` if you are going to do a 64 bit - build and `Targeting Windows XP x86 Release` if you are building a - 32 bit version. - Now cd to where you unpacked the OpenSSL source using your Release - Windows command prompt (it should be on the same drive as where - you are going to install it if everything is to work smothly). + The first part of the 64 bit template is identical to the 32 bit one, + but there are some environment variable differences: - C:\> cd <some dir> + # Program Files + PRG_FLS64=$C_DRV/Program\ Files + PRG_FLS32=$C_DRV/Program\ Files\ \(x86\) - Add ActiveState (or some other windows perl, not cygwins) to your PATH: + # Visual Studio + VISUAL_STUDIO_ROOT=$PRG_FLS32/Microsoft\ Visual\ Studio\ 12.0 + WIN_VISUAL_STUDIO_ROOT="C:\\Program Files (x86)\\Microsoft Visual Studio 12.0" - C:\...\> set PATH=C:\Perl\bin;%PATH% + # SDK + SDK=$PRG_FLS32/Windows\ Kits/8.1 + WIN_SDK="C:\\Program Files (x86)\\Windows Kits\\8.1" - Or if you installed the 64bit perl: - - C:\...\> set PATH=C:\Perl64\bin;%PATH% + # NSIS + NSIS_BIN=$PROGRAMFILES/NSIS + # Java + JAVA_BIN=$PROGRAMFILES/Java/jdk1.7.0_02/bin - Configure OpenSSL for 32 bit: + ## The PATH variable should be Cygwin'ish + VCPATH= + $VISUAL_STUDIO_ROOT/VC/bin/amd64:\ + $VISUAL_STUDIO_ROOT/VC/vcpackages:\ + $VISUAL_STUDIO_ROOT/Common7/IDE:\ + $VISUAL_STUDIO_ROOT/Common7/Tools:\ + $SDK/bin/x86 - C:\...\> perl Configure VC-WIN32 --prefix=/OpenSSL + ## Microsoft SDK libs + LIBPATH=$WIN_VISUAL_STUDIO_ROOT\\VC\\lib\\amd64 - Or for 64 bit: + LIB=$WIN_VISUAL_STUDIO_ROOT\\VC\\lib\\amd64\\;\ + $WIN_KITS\\lib\\winv6.3\\um\\x64 - C:\...\> perl Configure VC-WIN64A --prefix=/OpenSSL-Win64 + INCLUDE=$WIN_VISUAL_STUDIO_ROOT\\VC\\include\\;\ + $WIN_KITS\\include\\shared\\;$WIN_KITS\\include\\um;\ + $WIN_KITS\\include\\winrt\\;$WIN_KITS\\include\\um\\gl - Do some setup (for 32 bit): + # Put nsis, c compiler and java in path + export PATH=$VCPATH:$PATH:$JAVA_BIN:$NSIS_BIN - C:\...\> ms\do_ms + # Make sure LIB and INCLUDE is available for others + export LIBPATH LIB INCLUDE - The same for 64 bit: - C:\...\> ms\do_win64a + Make sure to set the PATH so that NSIS and Microsoft SDK is found + before the MSYS/Cygwin tools and that Java is last in the PATH. - Then build static libraries and install: + Make a simple hello world and try to compile it with the `cl` + command from within bash. If that does not work, your environment + needs fixing. Remember, there should be + no backslashes in your path environment variable in Cygwin bash, + but LIB and INCLUDE should contain Windows style paths with + semicolon, drive letters and backslashes. - C:\...\> nmake -f ms\nt.mak - C:\...\> nmake -f ms\nt.mak install +* Sun's Java JDK 1.6.0 or later. Our Java code (jinterface, ic) is + written for JDK 1.6.0. Get it for Windows and install it, the JRE is + not enough. If you don't care about Java, you can skip this step. The + result will be that jinterface is not built. + + URL: <http://java.sun.com> + + Add javac *LAST* to your path environment in bash, in my case this means: + + `PATH="$PATH:/cygdrive/c/Program Files/Java/jdk1.7.0_02/bin"` + + No `CLASSPATH` or anything is needed. Type `javac` in the bash prompt + and you should get a list of available Java options. Make sure, e.g by + typing `type java`, that you use the Java you installed. Note however that + Cygwin's/MinGW's/MSYS2's `jar.exe` is used. That's why the JDK bin-directory should be + added last in the `PATH`. + +* Nullsoft NSIS installer system. You need this to build the self + installing package. It's a free open source installer that's much + nicer to use than the commercial Wise and Install shield + installers. This is the installer we use for commercial releases as + well. + + URL: <http://nsis.sourceforge.net/download> + + Install the lot, especially the modern user interface components, as + it's definitely needed. Put `makensis` in your path, in my case: + + PATH=/cygdrive/c/Program\ Files/NSIS:$PATH + + Type makensis at the bash prompt and you should get a list of options + if everything is OK. + +* OpenSSL. This is if you want the SSL and crypto applications to + compile (and run). There are prebuilt binaries, which you can just + download and install, available here: + + URL: <http://openssl.org/community/binaries.html> - That's it - you now have your perfectly consistent static build of - openssl. If you want to get rid of any possibly patented - algorithms in the lib, just read up on the OpenSSL FAQ and follow - the instructions. + We would recommend using 1.0.2d. - The installation locations chosen are where configure will look - for OpenSSL, so try to keep them as is. - -* Building with wxWidgets. Download wxWidgets-3.0.2 or higher patch - release. +* Building with wxWidgets. Download wxWidgets-3.0.2 or higher. - Install or unpack it to `DRIVE:/PATH/cygwin/opt/local/pgm`. + Install or unpack it to the pgm folder: + Cygwin: + `DRIVE:/PATH/cygwin/opt/local/pgm` + MSYS: + `DRIVE:/PATH/MinGW/msys/1.0/opt/local/pgm` + MSYS2: + `DRIVE:/PATH/msys<32/64>/opt/local/pgm` - edit: `C:\cygwin\opt\local\pgm\wxMSW-3.0.2\include\wx\msw\setup.h` - enable `wxUSE_POSTSCRIPT` + If the `wxUSE_POSTSCRIPT` isn't enabled in `<path\to\pgm>\wxMSW-3.0.2\include\wx\msw\setup.h`, + enable it. build: From a command prompt with the VC tools available (See the instructions for OpenSSL build above for help on starting the proper command prompt in RELEASE mode): - C:\...\> cd C:\cygwin\opt\local\pgm\wxMSW-3.0.2\build\msw + C:\...\> cd <path\to\pgm>\wxMSW-3.0.2\build\msw C:\...\> nmake BUILD=release SHARED=0 DIR_SUFFIX_CPU= -f makefile.vc Or - if building a 64bit version: - C:\...\> cd C:\cygwin\opt\local\pgm\wxMSW-3.0.2\build\msw + C:\...\> cd <path\to\pgm>\wxMSW-3.0.2\build\msw C:\...\> nmake TARGET_CPU=amd64 BUILD=release SHARED=0 DIR_SUFFIX_CPU= -f makefile.vc -* The Erlang source distribution (from <http://www.erlang.org/download.html>). - The same as for Unix platforms. Preferably use tar from within Cygwin to +* Get the Erlang source distribution (from <http://www.erlang.org/download.html>). + The same as for Unix platforms. Preferably use tar from within Cygwin, MSYS or MSYS2 to unpack the source tar.gz (`tar zxf otp_src_%OTP-REL%.tar.gz`). - set the environment `ERL_TOP` to point to the root directory of the + Set the environment `ERL_TOP` to point to the root directory of the source distribution. Let's say I stood in `$HOME/src` and unpacked `otp_src_%OTP-REL%.tar.gz`, I then add the following to `.profile`: ERL_TOP=$HOME/src/otp_src_%OTP-REL% export $ERL_TOP -* The TCL/TK binaries. You could compile Tcl/Tk for windows yourself, - but you can get a stripped down version from our website which is - suitable to include in the final binary package. If you want to supply - tcl/tk yourself, read the instructions about how the tcl/tk tar file - used in the build is constructed under `$ERL_TOP/lib/gs/tcl`. The easy - way is to download <http://www.erlang.org/download/tcltk85_win32_bin.tar.gz> - and unpack it standing in the `$ERL_TOP` directory. This will create the - file `win32.tar.gz` in `$ERL_TOP/lib/gs/tcl/binaries`. - - One last alternative is to create a file named `SKIP` in the - `$ERL_TOP/lib/gs/` after configure is run, but that will give you an - erlang system without gs (which might be okay as you probably will use - wx anyway). - - Note that there is no special 64bit version of TCL/TK needed, you - can use the 32bit program even for a 64bit build. The Shell Environment --------------------- @@ -726,37 +687,18 @@ be easy after this. You could run `./otp_build env_win32` without sets seems OK. The path is cleaned of spaces if possible (using DOS style short names instead), the variables `OVERRIDE_TARGET`, `CC`, `CXX`, `AR` and `RANLIB` are set to their respective wrappers and the directories -`$ERL_TOP/erts/etc/win32/cygwin_tools/vc` and -`$ERL_TOP/erts/etc/win32/cygwin_tool` are added first in the PATH. - -Try now a `type erlc`. That should result in the erlc wrapper script -(which does not have the .sh extension, for reasons best kept -untold...). It should reside in `$ERL_TOP/erts/etc/win32/cygwin_tools` -or `$ERL_TOP/erts/etc/win32/msys_tools`. You could also try `which -cc.sh`, which `ar.sh` etc. +`$ERL_TOP/erts/etc/win32/<cygwin/msys>_tools/vc` and +`$ERL_TOP/erts/etc/win32/<cygwin/msys>_tool` are added first in the PATH. -Now you're ready to build... +Now you can check which erlc you have by writing `type erlc` in your shell. +It should reside in `$ERL_TOP/erts/etc/win32/cygwin_tools` +or `$ERL_TOP/erts/etc/win32/msys_tools`. Building and Installing ----------------------- -Now it's assumed that you have executed `` eval `./otp_build env_win32` `` or -`` eval `./otp_build env_win32 x64` `` for this particular shell... - -Building is easiest using the `otp_build` script. That script takes care -of running configure, bootstrapping etc on Windows in a simple -way. The `otp_build` script is the utility we use ourselves to build on -different platforms and it therefore contains code for all sorts of -platforms. The principle is, however, that for non-Unix platforms, one -uses `./otp_build env_<target>` to set up environment and then the -script knows how to build on the platform "by itself". You've already -run `./otp_build env_win32` in the step above, so now it's mostly like -we build on any platform. OK, here are then steps; Assuming you will -want to build a full installation executable with NSIS, you can omit -`<installation directory>` and the release will be copied to -`$ERL_TOP/release/win32`: and there is where the packed self installing -executable will reside too. +Building is easiest using the `otp_build` script: $ ./otp_build autoconf # Ignore the warning blob about versions of autoconf $ ./otp_build configure <optional configure options> @@ -764,18 +706,18 @@ executable will reside too. $ ./otp_build release -a <installation directory> $ ./otp_build installer_win32 <installation directory> # optional -Now you will have a file called `otp_win32_R12B.exe` in the -`<installation directory>`, i.e. `$ERL_TOP/release/win32`. +Now you will have a file called `otp_win32_%OTP-REL%.exe` or `otp_win64_%OTP-REL%.exe` +in the `<installation directory>`, i.e. `$ERL_TOP/release/win32`. Lets get into more detail: 1. `$ ./otp_build autoconf` - This step rebuilds the configure scripts - to work correctly in the cygwin environment. In an ideal world, this + to work correctly in your environment. In an ideal world, this would not be needed, but alas, we have encountered several incompatibilities between our distributed configure scripts (generated - on a Linux platform) and the cygwin environment over the - years. Running autoconf on cygwin ensures that the configure scripts - are generated in a cygwin-compatible way and that they will work well + on a Linux platform) and the Cygwin/MSYS/MSYS2 environment over the + years. Running autoconf in Cygwin/MSYS/MSYS2 ensures that the configure + scripts are generated in a compatible way and that they will work well in the next step. 2. `$ ./otp_build configure` - This runs the newly generated configure @@ -784,38 +726,21 @@ Lets get into more detail: this awkward target name and behave accordingly. The CC variable also makes the compiler be `cc.sh`, which wraps MSVC++, so all configure tests regarding the C compiler gets to run the right compiler. A lot of - the tests are not needed on Windows, but I thought it best to run the - whole configure anyway. The only configure option you might want to - supply is `--with-ssl`, which might be needed if you have built your - own OpenSSL distribution. The Shining Lights distribution should be - found automatically by `configure`, if that fails, add a - `--with-ssl=<dir>` that specifies the root directory of your OpenSSL - installation. + the tests are not needed on Windows, but we thought it best to run the + whole configure anyway. 3. `$ ./otp_build boot -a` - This uses the bootstrap directory (shipped with the source, `$ERL_TOP/bootstrap`) to build a complete OTP - system. It first builds an emulator and sets up a minimal OTP system - under `$ERL_TOP/bootstrap`, then starts to compile the different OTP - compilers to make the `$ERL_TOP/bootstrap` system potent enough to be - able to compile all Erlang code in OTP. Then, all Erlang and C code - under `$ERL_TOP/lib` is built using the bootstrap system, giving a - complete OTP system (although not installed). When this is done, one - can run Erlang from within the source tree, just type `$ERL_TOP/bin/erl` - and you should have a prompt. If you omit the -a flag, you'll get a - smaller system, that might be useful during development. Now - exit from Erlang and start making a release of the thing: + system. When this is done you can run erl from within the source tree; + just type `$ERL_TOP/bin/erl` and you whould have the prompt. 4. `$ ./otp_build release -a` - Builds a commercial release tree from the - source tree, default is to put it in `$ERL_TOP/release/win32`, you can + source tree. The default is to put it in `$ERL_TOP/release/win32`. You can give any directory as parameter (Cygwin style), but it doesn't really - matter if you're going to build a self extracting installer too. You - could of course build release to the final directory and then run - `./Install.exe` standing in the directory where the release was put, - that will create a fully functional OTP installation. But let's make - the nifty installer: - -5. `$ ./otp_build installer_win32` - Create the self extracting installer - executable. The executable `otp_win32_%OTP-REL%.exe` will be placed + matter if you're going to build a self extracting installer too. + +5. `$ ./otp_build installer_win32` - Creates the self extracting installer executable. + The executable `otp_win32_%OTP-REL%.exe` or `otp_win64_%OTP-REL%.exe` will be placed in the top directory of the release created in the previous step. If no release directory is specified, the release is expected to have been built to `$ERL_TOP/release/win32`, which also will be the place @@ -824,7 +749,7 @@ Lets get into more detail: /tmp/erl_release`), you're expected to give the same parameter here, (i.e. `./otp_build installer_win32 /tmp/erl_release`). You need to have a full NSIS installation and `makensis.exe` in your path for this to - work of course. Once you have created the installer, you can run it to + work. Once you have created the installer, you can run it to install Erlang/OTP in the regular way, just run the executable and follow the steps in the installation wizard. To get all default settings in the installation without any questions asked, you run the executable @@ -844,37 +769,17 @@ Lets get into more detail: and after a while Erlang/OTP-%OTP-REL% will have been installed in `C:\Program Files\erl%ERTS-VSN%\`, with shortcuts in the menu etc. - The necessary setup of an Erlang installation is actually done by the - program `Install.exe`, which resides in the release top. That program - creates `.ini`-files and copies the correct boot scripts. If one has - the correct directory tree (like after a `./otp_build release -a`), only - the running of `Install.exe` is necessary to get a fully functional - OTP. What the self extracting installer adds is (of course) the - possibility to distribute the binary easily, together with adding - shortcuts to the Windows start menu. There is also some adding of - entries in the registry, to associate `.erl` and `.beam` files with - Erlang and get nifty icons, but that's not something you'll really need - to run Erlang. The registry is also used to store uninstall information, - but if one has not used the self extracting installer, one cannot - (need not) do any uninstall, one just scratches the release directory - and everything is gone. Erlang/OTP does not *need* to put anything - in the Windows registry at all, and does not if you don't use the self - extracting installer. In other words the installer is pure cosmetics. - -> *NOTE*: Beginning with R9C, the Windows installer does *not* add Erlang -> to the system wide path. If one wants to have Erlang in the path, one -> has to add it by hand. Development ----------- Once the system is built, you might want to change it. Having a test -release in some nice directory might be useful, but you also can run +release in some nice directory might be useful, but you can also run Erlang from within the source tree. The target `local_setup`, makes the program `$ERL_TOP/bin/erl.exe` usable and it also uses all the OTP libraries in the source tree. -If you hack the emulator, you can then build the emulator executable +If you hack the emulator, you can build the emulator executable by standing in `$ERL_TOP/erts/emulator` and do a simple $ make opt @@ -923,12 +828,12 @@ or even in the source directory... $ cd $ERL_TOP/lib/stdlib/src $ make opt -Note that you're expected o have a fresh Erlang in your path when +Note that you're expected to have a fresh Erlang in your path when doing this, preferably the plain %OTP-REL% you have built in the previous steps. You could also add `$ERL_TOP/bootstrap/bin` to your `PATH` before -rebuilding specific libraries, that would give you a good enough +rebuilding specific libraries. That would give you a good enough Erlang system to compile any OTP erlang code. Setting up the path -correctly is a little bit tricky, you still need to have +correctly is a little bit tricky. You still need to have `$ERL_TOP/erts/etc/win32/cygwin_tools/vc` and `$ERL_TOP/erts/etc/win32/cygwin_tools` *before* the actual emulator in the path. A typical setting of the path for using the bootstrap @@ -963,57 +868,27 @@ Remember that: That's basically all you need to get going. + Using GIT --------- -You might want to check out versions of the source code from GitHUB. That is possible directly in cygwin, but not in Msys. There is a project MsysGIT: +You might want to check out versions of the source code from GitHUB. That is possible directly in Cygwin, but not in MSYS. There is a project MsysGIT: URL:<http://code.google.com/p/msysgit/> that makes a nice Git port. The msys prompt you get from MsysGIT is however not compatible with the full version from MinGW, so you will need to check out files using MsysGIT's command prompt and then switch -to a common Msys command prompt for building. Also all test suites -cannot be built as MsysGIT/Msys does not handle symbolic links. To -build test suites on Windows, you will need Cygwin for now. Hopefully -all symbolic links will disappear from our repository soon and this -issue will disappear. +to a common MSYS command prompt for building. Also all test suites +cannot be built as MsysGIT/MSYS does not handle symbolic links. -Final Words ------------ -My hope is that the possibility to build the whole system on Windows -will open up for free development on this platform too. There are many -things one might want to do better in the Windows version, like the -window-style command prompt as well as pure Cygwin porting. Although i -realize it's a much larger step to start building on Windows (with all -the software you need) than for instance on Linux, I sincerely hope -that some of you will make the effort and start submitting Windows -friendly patches. - -The first build system for Erlang using Cygwin on Windows was created -by Per Bergkvist. I haven't used his build system, but it's rumored to -be good. The idea to do this came from his work, so credit is well -deserved. - -Of course this would have been completely impossible without the -excellent Cygwin. The guys at Cygnus solutions and -Redhat deserve a huge THANKS! as well as all the other people in the -free software community who have helped in creating the magnificent -software that constitutes Cygwin. - -Also the people developing the alternative command prompt Msys and -the MinGW compiler are worth huge THANKS! The 64bit port would have -been impossible without the 64bit MinGW compiler. - -Good luck and Happy Hacking, -Patrik, OTP Copyright and License --------------------- %CopyrightBegin% -Copyright Ericsson AB 2003-2014. All Rights Reserved. +Copyright Ericsson AB 2003-2015. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -1030,6 +905,8 @@ limitations under the License. %CopyrightEnd% - [1]: http://www.erlang.org/faq.html "mailing lists" + [1]: http://www.erlang.org/static/doc/mailinglist.html + [2]: http://bugs.erlang.org + [3]: https://github.com/erlang/otp [?TOC]: true diff --git a/HOWTO/INSTALL.md b/HOWTO/INSTALL.md index f8900c501b..43bcdb3a9e 100644 --- a/HOWTO/INSTALL.md +++ b/HOWTO/INSTALL.md @@ -76,10 +76,10 @@ also find the utilities needed for building the documentation. Read more and download from <http://www.openssl.org>. * Oracle Java SE JDK -- The Java Development Kit (Standard Edition). Required for building the application `jinterface` and parts of `ic` and `orber`. - At least version 1.5.0 of the JDK is required. + At least version 1.6.0 of the JDK is required. Download from <http://www.oracle.com/technetwork/java/javase/downloads>. - We have also tested with IBM's JDK 1.5.0. + We have also tested with IBM's JDK 1.6.0. * X Windows -- Development headers and libraries are needed to build the Erlang/OTP application `gs` on Unix/Linux. * `flex` -- Headers and libraries are needed to build the flex @@ -210,6 +210,14 @@ the `$PATH`. $ export PATH=$ERL_TOP/bin:$PATH # Assuming bash/sh +For the FOP print formatter, two steps must be taken: + +* Adding the location of your installation of `fop` in `$FOP_HOME`. + + $ export FOP_HOME=/path/to/fop/dir # Assuming bash/sh + +* Adding the `fop` script (in `$FOP_HOME`) to your `$PATH`, either by adding `$FOP_HOME` to `$PATH`, or by copying the `fop` script to a directory already in your `$PATH`. + Build the documentation. $ make docs @@ -366,9 +374,15 @@ Some of the available `configure` options are: `jinterface` application won't be built) * `--{enable,disable}-dynamic-ssl-lib` - Dynamic OpenSSL libraries * `--{enable,disable}-builtin-zlib` - Use the built-in source for zlib. -* `--with-ssl=PATH` - Specify location of OpenSSL include and lib * `--{with,without}-ssl` - OpenSSL (without implies that the `crypto`, `ssh`, and `ssl` won't be built) +* `--with-ssl=PATH` - Specify location of OpenSSL include and lib +* `--with-ssl-incl=PATH` - Location of OpenSSL `include` directory, + if different than specified by `--with-ssl=PATH` +* `--with-ssl-rpath=yes|no|PATHS` - Runtime library path for OpenSSL. + Default is `yes`, which equates to a number of standard locations. If + `no`, then no runtime library paths will be used. Anything else should be + a comma separated list of paths. * `--with-libatomic_ops=PATH` - Use the `libatomic_ops` library for atomic memory accesses. If `configure` should inform you about no native atomic implementation available, you typically want to try using the @@ -392,7 +406,7 @@ Some of the available `configure` options are: that has to be the same as the filename. You also have to define `STATIC_ERLANG_{NIF,DRIVER}` when compiling the .o files for the nif/driver. If your nif/driver depends on some other dynamic library, you now have to link - that to the Erlang VM binary. This is easily achived by passing `LIBS=-llibname` + that to the Erlang VM binary. This is easily achieved by passing `LIBS=-llibname` to configure. * `--without-$app` - By default all applications in Erlang/OTP will be included in a release. If this is not wanted it is possible to specify that Erlang/OTP @@ -400,6 +414,18 @@ Some of the available `configure` options are: no automatic dependency handling between applications. If you disable an application that another application depends on, you also have to disable the dependant application. +* `--enable-gettimeofday-as-os-system-time` - Force usage of `gettimeofday()` for + OS system time. +* `--enable-prefer-elapsed-monotonic-time-during-suspend` - Prefer an OS monotonic + time source with elapsed time during suspend. +* `--disable-prefer-elapsed-monotonic-time-during-suspend` - Do not prefer an OS + monotonic time source with elapsed time during suspend. +* `--with-clock-resolution=high|low` - Try to find clock sources for OS system + time, and OS monotonic time with higher or lower resolution than chosen by + default. Note that both alternatives may have a negative impact on the performance + and scalability compared to the default clock sources chosen. +* `--disable-saved-compile-time` - Disable saving of compile date and time + in the emulator binary. * `--enable-dirty-schedulers` - Enable the **experimental** dirty schedulers functionality. Note that the dirty schedulers functionality is experimental, and **not supported**. This functionality **will** be subject to backward @@ -496,7 +522,7 @@ If you have Xcode 4.3, or later, you will also need to download If you want to build the `wx` application, you will need to get wxWidgets-3.0 (`wxWidgets-3.0.0.tar.bz2` from <http://sourceforge.net/projects/wxwindows/files/3.0.0/>) or get it from github with bug fixes: - $ git clone --branch WX_3_0_branch [email protected]:wxWidgets/wxWidgets.git + $ git clone --branch WX_3_0_BRANCH [email protected]:wxWidgets/wxWidgets.git Be aware that the wxWidgets-3.0 is a new release of wxWidgets, it is not as mature as the old releases and the OS X port still lags behind the other ports. diff --git a/OTP_VERSION b/OTP_VERSION index 0034b6527f..1dd1077fc0 100644 --- a/OTP_VERSION +++ b/OTP_VERSION @@ -1 +1 @@ -18.0 +18.3.4.3 @@ -61,6 +61,12 @@ In short: * Once or twice a week, a status email called ["What's cooking in Erlang/OTP"] [4] will be sent to the [`erlang-patches`] [3] mailing list. +Bug Reports +-------------------------- + +Please look at the [instructions for submitting bugs reports] [6]. + + Copyright and License --------------------- @@ -89,3 +95,4 @@ Copyright and License [3]: http://www.erlang.org/static/doc/mailinglist.html [4]: http://erlang.github.com/otp/ [5]: HOWTO/INSTALL.md + [6]: https://github.com/erlang/otp/wiki/Bug-reports diff --git a/bootstrap/bin/start.boot b/bootstrap/bin/start.boot Binary files differindex 25c092961c..ea3b3775aa 100644 --- a/bootstrap/bin/start.boot +++ b/bootstrap/bin/start.boot diff --git a/bootstrap/bin/start_clean.boot b/bootstrap/bin/start_clean.boot Binary files differindex 25c092961c..ea3b3775aa 100644 --- a/bootstrap/bin/start_clean.boot +++ b/bootstrap/bin/start_clean.boot diff --git a/bootstrap/lib/compiler/ebin/beam_asm.beam b/bootstrap/lib/compiler/ebin/beam_asm.beam Binary files differindex b25c33084f..91c487f3d5 100644 --- a/bootstrap/lib/compiler/ebin/beam_asm.beam +++ b/bootstrap/lib/compiler/ebin/beam_asm.beam diff --git a/bootstrap/lib/compiler/ebin/beam_block.beam b/bootstrap/lib/compiler/ebin/beam_block.beam Binary files differindex 59084464a0..5d1e45fd72 100644 --- a/bootstrap/lib/compiler/ebin/beam_block.beam +++ b/bootstrap/lib/compiler/ebin/beam_block.beam diff --git a/bootstrap/lib/compiler/ebin/beam_bool.beam b/bootstrap/lib/compiler/ebin/beam_bool.beam Binary files differindex 0fa7612114..e503ad7484 100644 --- a/bootstrap/lib/compiler/ebin/beam_bool.beam +++ b/bootstrap/lib/compiler/ebin/beam_bool.beam diff --git a/bootstrap/lib/compiler/ebin/beam_bsm.beam b/bootstrap/lib/compiler/ebin/beam_bsm.beam Binary files differindex a6757dfcfb..2f18ae4f30 100644 --- a/bootstrap/lib/compiler/ebin/beam_bsm.beam +++ b/bootstrap/lib/compiler/ebin/beam_bsm.beam diff --git a/bootstrap/lib/compiler/ebin/beam_disasm.beam b/bootstrap/lib/compiler/ebin/beam_disasm.beam Binary files differindex b63864c96c..7c5dca424f 100644 --- a/bootstrap/lib/compiler/ebin/beam_disasm.beam +++ b/bootstrap/lib/compiler/ebin/beam_disasm.beam diff --git a/bootstrap/lib/compiler/ebin/beam_jump.beam b/bootstrap/lib/compiler/ebin/beam_jump.beam Binary files differindex 8dd6375403..630a370a94 100644 --- a/bootstrap/lib/compiler/ebin/beam_jump.beam +++ b/bootstrap/lib/compiler/ebin/beam_jump.beam diff --git a/bootstrap/lib/compiler/ebin/beam_validator.beam b/bootstrap/lib/compiler/ebin/beam_validator.beam Binary files differindex 38b749d9ae..8b13cea141 100644 --- a/bootstrap/lib/compiler/ebin/beam_validator.beam +++ b/bootstrap/lib/compiler/ebin/beam_validator.beam diff --git a/bootstrap/lib/compiler/ebin/cerl.beam b/bootstrap/lib/compiler/ebin/cerl.beam Binary files differindex 758861af20..7ff73413d7 100644 --- a/bootstrap/lib/compiler/ebin/cerl.beam +++ b/bootstrap/lib/compiler/ebin/cerl.beam diff --git a/bootstrap/lib/compiler/ebin/cerl_trees.beam b/bootstrap/lib/compiler/ebin/cerl_trees.beam Binary files differindex fc1a7e04f8..b23668fb2b 100644 --- a/bootstrap/lib/compiler/ebin/cerl_trees.beam +++ b/bootstrap/lib/compiler/ebin/cerl_trees.beam diff --git a/bootstrap/lib/compiler/ebin/compiler.app b/bootstrap/lib/compiler/ebin/compiler.app index d3b2296ea4..4dd52e31bf 100644 --- a/bootstrap/lib/compiler/ebin/compiler.app +++ b/bootstrap/lib/compiler/ebin/compiler.app @@ -19,7 +19,7 @@ {application, compiler, [{description, "ERTS CXC 138 10"}, - {vsn, "6.0"}, + {vsn, "6.0.2"}, {modules, [ beam_a, beam_asm, diff --git a/bootstrap/lib/compiler/ebin/compiler.appup b/bootstrap/lib/compiler/ebin/compiler.appup index 889b72bd6b..ceb96264d5 100644 --- a/bootstrap/lib/compiler/ebin/compiler.appup +++ b/bootstrap/lib/compiler/ebin/compiler.appup @@ -16,7 +16,7 @@ %% limitations under the License. %% %% %CopyrightEnd% -{"5.0.4", +{"6.0.2", [{<<".*">>,[{restart_application, compiler}]}], [{<<".*">>,[{restart_application, compiler}]}] }. diff --git a/bootstrap/lib/compiler/ebin/sys_core_fold.beam b/bootstrap/lib/compiler/ebin/sys_core_fold.beam Binary files differindex 1b5467a54b..cbdef8e1d7 100644 --- a/bootstrap/lib/compiler/ebin/sys_core_fold.beam +++ b/bootstrap/lib/compiler/ebin/sys_core_fold.beam diff --git a/bootstrap/lib/compiler/ebin/v3_codegen.beam b/bootstrap/lib/compiler/ebin/v3_codegen.beam Binary files differindex e53f0fcd12..10647442a3 100644 --- a/bootstrap/lib/compiler/ebin/v3_codegen.beam +++ b/bootstrap/lib/compiler/ebin/v3_codegen.beam diff --git a/bootstrap/lib/compiler/ebin/v3_core.beam b/bootstrap/lib/compiler/ebin/v3_core.beam Binary files differindex e4c5f51f77..5c5a124e4c 100644 --- a/bootstrap/lib/compiler/ebin/v3_core.beam +++ b/bootstrap/lib/compiler/ebin/v3_core.beam diff --git a/bootstrap/lib/kernel/ebin/application.beam b/bootstrap/lib/kernel/ebin/application.beam Binary files differindex d8e98c021b..97c6d9d415 100644 --- a/bootstrap/lib/kernel/ebin/application.beam +++ b/bootstrap/lib/kernel/ebin/application.beam diff --git a/bootstrap/lib/kernel/ebin/code.beam b/bootstrap/lib/kernel/ebin/code.beam Binary files differindex 55d123c6a2..71b2025094 100644 --- a/bootstrap/lib/kernel/ebin/code.beam +++ b/bootstrap/lib/kernel/ebin/code.beam diff --git a/bootstrap/lib/kernel/ebin/code_server.beam b/bootstrap/lib/kernel/ebin/code_server.beam Binary files differindex aa75ae9bd1..f2400a9a6f 100644 --- a/bootstrap/lib/kernel/ebin/code_server.beam +++ b/bootstrap/lib/kernel/ebin/code_server.beam diff --git a/bootstrap/lib/kernel/ebin/disk_log_1.beam b/bootstrap/lib/kernel/ebin/disk_log_1.beam Binary files differindex 55a9365f05..9c887c8ed9 100644 --- a/bootstrap/lib/kernel/ebin/disk_log_1.beam +++ b/bootstrap/lib/kernel/ebin/disk_log_1.beam diff --git a/bootstrap/lib/kernel/ebin/dist_util.beam b/bootstrap/lib/kernel/ebin/dist_util.beam Binary files differindex c92373c68e..f87dd4a45c 100644 --- a/bootstrap/lib/kernel/ebin/dist_util.beam +++ b/bootstrap/lib/kernel/ebin/dist_util.beam diff --git a/bootstrap/lib/kernel/ebin/erl_epmd.beam b/bootstrap/lib/kernel/ebin/erl_epmd.beam Binary files differindex 92d6387af3..8910de12ef 100644 --- a/bootstrap/lib/kernel/ebin/erl_epmd.beam +++ b/bootstrap/lib/kernel/ebin/erl_epmd.beam diff --git a/bootstrap/lib/kernel/ebin/file_io_server.beam b/bootstrap/lib/kernel/ebin/file_io_server.beam Binary files differindex be820676ed..b9c53bde49 100644 --- a/bootstrap/lib/kernel/ebin/file_io_server.beam +++ b/bootstrap/lib/kernel/ebin/file_io_server.beam diff --git a/bootstrap/lib/kernel/ebin/heart.beam b/bootstrap/lib/kernel/ebin/heart.beam Binary files differindex d4972ecdd2..8892785416 100644 --- a/bootstrap/lib/kernel/ebin/heart.beam +++ b/bootstrap/lib/kernel/ebin/heart.beam diff --git a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam Binary files differindex fc12b6b194..9da5cce487 100644 --- a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam +++ b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam diff --git a/bootstrap/lib/kernel/ebin/inet.beam b/bootstrap/lib/kernel/ebin/inet.beam Binary files differindex a76806293f..75743c63cc 100644 --- a/bootstrap/lib/kernel/ebin/inet.beam +++ b/bootstrap/lib/kernel/ebin/inet.beam diff --git a/bootstrap/lib/kernel/ebin/inet6_tcp.beam b/bootstrap/lib/kernel/ebin/inet6_tcp.beam Binary files differindex d080a1200b..96dd4739ea 100644 --- a/bootstrap/lib/kernel/ebin/inet6_tcp.beam +++ b/bootstrap/lib/kernel/ebin/inet6_tcp.beam diff --git a/bootstrap/lib/kernel/ebin/inet6_tcp_dist.beam b/bootstrap/lib/kernel/ebin/inet6_tcp_dist.beam Binary files differindex 3f98206013..1be1dc1c57 100644 --- a/bootstrap/lib/kernel/ebin/inet6_tcp_dist.beam +++ b/bootstrap/lib/kernel/ebin/inet6_tcp_dist.beam diff --git a/bootstrap/lib/kernel/ebin/inet_db.beam b/bootstrap/lib/kernel/ebin/inet_db.beam Binary files differindex 8c7c6ba218..6401f0fcfa 100644 --- a/bootstrap/lib/kernel/ebin/inet_db.beam +++ b/bootstrap/lib/kernel/ebin/inet_db.beam diff --git a/bootstrap/lib/kernel/ebin/inet_dns.beam b/bootstrap/lib/kernel/ebin/inet_dns.beam Binary files differindex 0c5b6c73e1..b1c3bf3369 100644 --- a/bootstrap/lib/kernel/ebin/inet_dns.beam +++ b/bootstrap/lib/kernel/ebin/inet_dns.beam diff --git a/bootstrap/lib/kernel/ebin/inet_tcp.beam b/bootstrap/lib/kernel/ebin/inet_tcp.beam Binary files differindex 60e0d9f569..c2b42fef1c 100644 --- a/bootstrap/lib/kernel/ebin/inet_tcp.beam +++ b/bootstrap/lib/kernel/ebin/inet_tcp.beam diff --git a/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam b/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam Binary files differindex a3635e5dde..1b389cbb4d 100644 --- a/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam +++ b/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam diff --git a/bootstrap/lib/kernel/ebin/kernel.app b/bootstrap/lib/kernel/ebin/kernel.app index 85ba41bcef..14f526c30c 100644 --- a/bootstrap/lib/kernel/ebin/kernel.app +++ b/bootstrap/lib/kernel/ebin/kernel.app @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2015. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -22,7 +22,7 @@ {application, kernel, [ {description, "ERTS CXC 138 10"}, - {vsn, "4.0"}, + {vsn, "4.1.1"}, {modules, [application, application_controller, application_master, @@ -116,6 +116,6 @@ {applications, []}, {env, [{error_logger, tty}]}, {mod, {kernel, []}}, - {runtime_dependencies, ["erts-7.0", "stdlib-2.5", "sasl-2.4"]} + {runtime_dependencies, ["erts-7.3", "stdlib-2.6", "sasl-2.6"]} ] }. diff --git a/bootstrap/lib/kernel/ebin/kernel.appup b/bootstrap/lib/kernel/ebin/kernel.appup index d09e0c6347..7810fb611b 100644 --- a/bootstrap/lib/kernel/ebin/kernel.appup +++ b/bootstrap/lib/kernel/ebin/kernel.appup @@ -16,9 +16,11 @@ %% limitations under the License. %% %% %CopyrightEnd% -{"4.0", +{"4.1.1", %% Up from - max one major revision back - [{<<"3\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}], % OTP-17 + [{<<"4\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.* + {<<"3\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}], % OTP-17 %% Down to - max one major revision back - [{<<"3\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}] % OTP-17 + [{<<"4\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.* + {<<"3\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}] % OTP-17 }. diff --git a/bootstrap/lib/kernel/ebin/net_kernel.beam b/bootstrap/lib/kernel/ebin/net_kernel.beam Binary files differindex 9a0bfa2ba4..e0bb445bf5 100644 --- a/bootstrap/lib/kernel/ebin/net_kernel.beam +++ b/bootstrap/lib/kernel/ebin/net_kernel.beam diff --git a/bootstrap/lib/kernel/ebin/seq_trace.beam b/bootstrap/lib/kernel/ebin/seq_trace.beam Binary files differindex 13489135a2..efc5b7dc2a 100644 --- a/bootstrap/lib/kernel/ebin/seq_trace.beam +++ b/bootstrap/lib/kernel/ebin/seq_trace.beam diff --git a/bootstrap/lib/kernel/ebin/user_drv.beam b/bootstrap/lib/kernel/ebin/user_drv.beam Binary files differindex 726a130b55..6027806558 100644 --- a/bootstrap/lib/kernel/ebin/user_drv.beam +++ b/bootstrap/lib/kernel/ebin/user_drv.beam diff --git a/bootstrap/lib/stdlib/ebin/beam_lib.beam b/bootstrap/lib/stdlib/ebin/beam_lib.beam Binary files differindex abf4949465..4d2303a8a5 100644 --- a/bootstrap/lib/stdlib/ebin/beam_lib.beam +++ b/bootstrap/lib/stdlib/ebin/beam_lib.beam diff --git a/bootstrap/lib/stdlib/ebin/dets.beam b/bootstrap/lib/stdlib/ebin/dets.beam Binary files differindex 100996bf85..916557d6ad 100644 --- a/bootstrap/lib/stdlib/ebin/dets.beam +++ b/bootstrap/lib/stdlib/ebin/dets.beam diff --git a/bootstrap/lib/stdlib/ebin/dets_utils.beam b/bootstrap/lib/stdlib/ebin/dets_utils.beam Binary files differindex f2d1d86a60..bcb506710b 100644 --- a/bootstrap/lib/stdlib/ebin/dets_utils.beam +++ b/bootstrap/lib/stdlib/ebin/dets_utils.beam diff --git a/bootstrap/lib/stdlib/ebin/dets_v8.beam b/bootstrap/lib/stdlib/ebin/dets_v8.beam Binary files differindex eca5a85114..30784ed4a6 100644 --- a/bootstrap/lib/stdlib/ebin/dets_v8.beam +++ b/bootstrap/lib/stdlib/ebin/dets_v8.beam diff --git a/bootstrap/lib/stdlib/ebin/dets_v9.beam b/bootstrap/lib/stdlib/ebin/dets_v9.beam Binary files differindex 711ca0b9f0..cda91beaaf 100644 --- a/bootstrap/lib/stdlib/ebin/dets_v9.beam +++ b/bootstrap/lib/stdlib/ebin/dets_v9.beam diff --git a/bootstrap/lib/stdlib/ebin/dict.beam b/bootstrap/lib/stdlib/ebin/dict.beam Binary files differindex 6ba808d6af..9ba2a9b62a 100644 --- a/bootstrap/lib/stdlib/ebin/dict.beam +++ b/bootstrap/lib/stdlib/ebin/dict.beam diff --git a/bootstrap/lib/stdlib/ebin/digraph.beam b/bootstrap/lib/stdlib/ebin/digraph.beam Binary files differindex 40db38c992..01933d662b 100644 --- a/bootstrap/lib/stdlib/ebin/digraph.beam +++ b/bootstrap/lib/stdlib/ebin/digraph.beam diff --git a/bootstrap/lib/stdlib/ebin/edlin.beam b/bootstrap/lib/stdlib/ebin/edlin.beam Binary files differindex 4d052a0c50..51d61d7a0b 100644 --- a/bootstrap/lib/stdlib/ebin/edlin.beam +++ b/bootstrap/lib/stdlib/ebin/edlin.beam diff --git a/bootstrap/lib/stdlib/ebin/erl_eval.beam b/bootstrap/lib/stdlib/ebin/erl_eval.beam Binary files differindex 2354a065ca..6b8c0cd4c9 100644 --- a/bootstrap/lib/stdlib/ebin/erl_eval.beam +++ b/bootstrap/lib/stdlib/ebin/erl_eval.beam diff --git a/bootstrap/lib/stdlib/ebin/erl_lint.beam b/bootstrap/lib/stdlib/ebin/erl_lint.beam Binary files differindex 16cacefb7c..744f2cdb36 100644 --- a/bootstrap/lib/stdlib/ebin/erl_lint.beam +++ b/bootstrap/lib/stdlib/ebin/erl_lint.beam diff --git a/bootstrap/lib/stdlib/ebin/erl_parse.beam b/bootstrap/lib/stdlib/ebin/erl_parse.beam Binary files differindex 0522f5c05e..4b0e853390 100644 --- a/bootstrap/lib/stdlib/ebin/erl_parse.beam +++ b/bootstrap/lib/stdlib/ebin/erl_parse.beam diff --git a/bootstrap/lib/stdlib/ebin/erl_pp.beam b/bootstrap/lib/stdlib/ebin/erl_pp.beam Binary files differindex f38ba5fa71..d40913093a 100644 --- a/bootstrap/lib/stdlib/ebin/erl_pp.beam +++ b/bootstrap/lib/stdlib/ebin/erl_pp.beam diff --git a/bootstrap/lib/stdlib/ebin/error_logger_file_h.beam b/bootstrap/lib/stdlib/ebin/error_logger_file_h.beam Binary files differindex 5c1bc6045f..0b98a9ceed 100644 --- a/bootstrap/lib/stdlib/ebin/error_logger_file_h.beam +++ b/bootstrap/lib/stdlib/ebin/error_logger_file_h.beam diff --git a/bootstrap/lib/stdlib/ebin/error_logger_tty_h.beam b/bootstrap/lib/stdlib/ebin/error_logger_tty_h.beam Binary files differindex 9711f57e43..565904b903 100644 --- a/bootstrap/lib/stdlib/ebin/error_logger_tty_h.beam +++ b/bootstrap/lib/stdlib/ebin/error_logger_tty_h.beam diff --git a/bootstrap/lib/stdlib/ebin/ets.beam b/bootstrap/lib/stdlib/ebin/ets.beam Binary files differindex 7d30fc9fc1..9ac333dbee 100644 --- a/bootstrap/lib/stdlib/ebin/ets.beam +++ b/bootstrap/lib/stdlib/ebin/ets.beam diff --git a/bootstrap/lib/stdlib/ebin/file_sorter.beam b/bootstrap/lib/stdlib/ebin/file_sorter.beam Binary files differindex a2a82fb77d..24dbd901e5 100644 --- a/bootstrap/lib/stdlib/ebin/file_sorter.beam +++ b/bootstrap/lib/stdlib/ebin/file_sorter.beam diff --git a/bootstrap/lib/stdlib/ebin/gen_event.beam b/bootstrap/lib/stdlib/ebin/gen_event.beam Binary files differindex bc3e71f6a7..d22f9ec402 100644 --- a/bootstrap/lib/stdlib/ebin/gen_event.beam +++ b/bootstrap/lib/stdlib/ebin/gen_event.beam diff --git a/bootstrap/lib/stdlib/ebin/gen_fsm.beam b/bootstrap/lib/stdlib/ebin/gen_fsm.beam Binary files differindex 268b8798c8..119c20e1d7 100644 --- a/bootstrap/lib/stdlib/ebin/gen_fsm.beam +++ b/bootstrap/lib/stdlib/ebin/gen_fsm.beam diff --git a/bootstrap/lib/stdlib/ebin/gen_server.beam b/bootstrap/lib/stdlib/ebin/gen_server.beam Binary files differindex 1e1e530eea..d6e5d223fb 100644 --- a/bootstrap/lib/stdlib/ebin/gen_server.beam +++ b/bootstrap/lib/stdlib/ebin/gen_server.beam diff --git a/bootstrap/lib/stdlib/ebin/lists.beam b/bootstrap/lib/stdlib/ebin/lists.beam Binary files differindex 9db37e21d4..b2dabc7d22 100644 --- a/bootstrap/lib/stdlib/ebin/lists.beam +++ b/bootstrap/lib/stdlib/ebin/lists.beam diff --git a/bootstrap/lib/stdlib/ebin/maps.beam b/bootstrap/lib/stdlib/ebin/maps.beam Binary files differindex d1aa8bb9dd..02e46c38be 100644 --- a/bootstrap/lib/stdlib/ebin/maps.beam +++ b/bootstrap/lib/stdlib/ebin/maps.beam diff --git a/bootstrap/lib/stdlib/ebin/otp_internal.beam b/bootstrap/lib/stdlib/ebin/otp_internal.beam Binary files differindex 52b13fb974..7ceb6e46fb 100644 --- a/bootstrap/lib/stdlib/ebin/otp_internal.beam +++ b/bootstrap/lib/stdlib/ebin/otp_internal.beam diff --git a/bootstrap/lib/stdlib/ebin/proc_lib.beam b/bootstrap/lib/stdlib/ebin/proc_lib.beam Binary files differindex cb6a8d6049..0f732c8cae 100644 --- a/bootstrap/lib/stdlib/ebin/proc_lib.beam +++ b/bootstrap/lib/stdlib/ebin/proc_lib.beam diff --git a/bootstrap/lib/stdlib/ebin/qlc.beam b/bootstrap/lib/stdlib/ebin/qlc.beam Binary files differindex 652604afc0..d9bdf2b93c 100644 --- a/bootstrap/lib/stdlib/ebin/qlc.beam +++ b/bootstrap/lib/stdlib/ebin/qlc.beam diff --git a/bootstrap/lib/stdlib/ebin/qlc_pt.beam b/bootstrap/lib/stdlib/ebin/qlc_pt.beam Binary files differindex 0e59d769a4..90bc537b85 100644 --- a/bootstrap/lib/stdlib/ebin/qlc_pt.beam +++ b/bootstrap/lib/stdlib/ebin/qlc_pt.beam diff --git a/bootstrap/lib/stdlib/ebin/rand.beam b/bootstrap/lib/stdlib/ebin/rand.beam Binary files differindex b6e0d20bd7..0f3ffb7542 100644 --- a/bootstrap/lib/stdlib/ebin/rand.beam +++ b/bootstrap/lib/stdlib/ebin/rand.beam diff --git a/bootstrap/lib/stdlib/ebin/re.beam b/bootstrap/lib/stdlib/ebin/re.beam Binary files differindex 9e140def2c..875c4a5513 100644 --- a/bootstrap/lib/stdlib/ebin/re.beam +++ b/bootstrap/lib/stdlib/ebin/re.beam diff --git a/bootstrap/lib/stdlib/ebin/shell.beam b/bootstrap/lib/stdlib/ebin/shell.beam Binary files differindex 3b2d0eb0fa..9ad6d68ebd 100644 --- a/bootstrap/lib/stdlib/ebin/shell.beam +++ b/bootstrap/lib/stdlib/ebin/shell.beam diff --git a/bootstrap/lib/stdlib/ebin/sofs.beam b/bootstrap/lib/stdlib/ebin/sofs.beam Binary files differindex 976483833f..c7862afc2f 100644 --- a/bootstrap/lib/stdlib/ebin/sofs.beam +++ b/bootstrap/lib/stdlib/ebin/sofs.beam diff --git a/bootstrap/lib/stdlib/ebin/stdlib.app b/bootstrap/lib/stdlib/ebin/stdlib.app index 4a52c6a443..7287cbd451 100644 --- a/bootstrap/lib/stdlib/ebin/stdlib.app +++ b/bootstrap/lib/stdlib/ebin/stdlib.app @@ -20,7 +20,7 @@ %% {application, stdlib, [{description, "ERTS CXC 138 10"}, - {vsn, "2.5"}, + {vsn, "2.7"}, {modules, [array, base64, beam_lib, @@ -105,7 +105,7 @@ dets]}, {applications, [kernel]}, {env, []}, - {runtime_dependencies, ["sasl-2.4","kernel-4.0","erts-7.0","crypto-3.3", + {runtime_dependencies, ["sasl-2.6","kernel-4.1","erts-7.3","crypto-3.3", "compiler-5.0"]} ]}. diff --git a/bootstrap/lib/stdlib/ebin/stdlib.appup b/bootstrap/lib/stdlib/ebin/stdlib.appup index 689485f421..e545adc484 100644 --- a/bootstrap/lib/stdlib/ebin/stdlib.appup +++ b/bootstrap/lib/stdlib/ebin/stdlib.appup @@ -16,9 +16,11 @@ %% limitations under the License. %% %% %CopyrightEnd% -{"2.5", +{"2.7", %% Up from - max one major revision back - [{<<"2\\.[0-4](\\.[0-9]+)*">>,[restart_new_emulator]}], %% 17.0-17.5 + [{<<"2\\.[5-8](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.* + {<<"2\\.[0-4](\\.[0-9]+)*">>,[restart_new_emulator]}], % 17.0-17.5 %% Down to - max one major revision back - [{<<"2\\.[0-4](\\.[0-9]+)*">>,[restart_new_emulator]}] %% 17.0-17.5 + [{<<"2\\.[5-8](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.* + {<<"2\\.[0-4](\\.[0-9]+)*">>,[restart_new_emulator]}] % 17.0-17.5 }. diff --git a/bootstrap/lib/stdlib/ebin/supervisor.beam b/bootstrap/lib/stdlib/ebin/supervisor.beam Binary files differindex 6dd01bf004..65790d73dc 100644 --- a/bootstrap/lib/stdlib/ebin/supervisor.beam +++ b/bootstrap/lib/stdlib/ebin/supervisor.beam diff --git a/bootstrap/lib/stdlib/ebin/supervisor_bridge.beam b/bootstrap/lib/stdlib/ebin/supervisor_bridge.beam Binary files differindex 1ebc561ee5..4af6cc8f40 100644 --- a/bootstrap/lib/stdlib/ebin/supervisor_bridge.beam +++ b/bootstrap/lib/stdlib/ebin/supervisor_bridge.beam diff --git a/bootstrap/lib/stdlib/ebin/unicode.beam b/bootstrap/lib/stdlib/ebin/unicode.beam Binary files differindex 16557d5631..dc8fdcaf86 100644 --- a/bootstrap/lib/stdlib/ebin/unicode.beam +++ b/bootstrap/lib/stdlib/ebin/unicode.beam diff --git a/bootstrap/lib/stdlib/ebin/zip.beam b/bootstrap/lib/stdlib/ebin/zip.beam Binary files differindex e80b6ae0cd..200b0f705c 100644 --- a/bootstrap/lib/stdlib/ebin/zip.beam +++ b/bootstrap/lib/stdlib/ebin/zip.beam diff --git a/bootstrap/lib/stdlib/include/assert.hrl b/bootstrap/lib/stdlib/include/assert.hrl new file mode 100644 index 0000000000..f913760102 --- /dev/null +++ b/bootstrap/lib/stdlib/include/assert.hrl @@ -0,0 +1,261 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright (C) 2004-2014 Richard Carlsson, Mickaël Rémond +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +-ifndef(ASSERT_HRL). +-define(ASSERT_HRL, true). + +%% Asserts are enabled unless NOASSERT is defined, and ASSERT can be used to +%% override it: if both ASSERT and NOASSERT are defined, then ASSERT takes +%% precedence, and NOASSERT will become undefined. +%% +%% Furthermore, if NODEBUG is defined, it implies NOASSERT, unless DEBUG or +%% ASSERT are defined. +%% +%% If asserts are disabled, all assert macros are defined to be the atom +%% 'ok'. If asserts are enabled, all assert macros are defined to yield 'ok' +%% as the result if the test succeeds, and raise an error exception if the +%% test fails. The error term will then have the form {Name, Info} where +%% Name is the name of the macro and Info is a list of tagged tuples. + +%% allow NODEBUG to imply NOASSERT, unless DEBUG +-ifdef(NODEBUG). +-ifndef(DEBUG). +-ifndef(NOASSERT). +-define(NOASSERT, true). +-endif. +-endif. +-endif. + +%% allow ASSERT to override NOASSERT +-ifdef(ASSERT). +-undef(NOASSERT). +-endif. + +%% Assert macros must not depend on any non-kernel or stdlib libraries. +%% +%% We must use fun-call wrappers ((fun () -> ... end)()) to avoid +%% exporting local variables, and furthermore we only use variable names +%% prefixed with "__", that hopefully will not be bound outside the fun. +%% It is not possible to nest assert macros. + +-ifdef(NOASSERT). +-define(assert(BoolExpr),ok). +-else. +%% The assert macro is written the way it is so as not to cause warnings +%% for clauses that cannot match, even if the expression is a constant. +-define(assert(BoolExpr), + begin + ((fun () -> + case (BoolExpr) of + true -> ok; + __V -> erlang:error({assert, + [{module, ?MODULE}, + {line, ?LINE}, + {expression, (??BoolExpr)}, + {expected, true}, + case __V of false -> {value, __V}; + _ -> {not_boolean,__V} + end]}) + end + end)()) + end). +-endif. + +%% This is the inverse case of assert, for convenience. +-ifdef(NOASSERT). +-define(assertNot(BoolExpr),ok). +-else. +-define(assertNot(BoolExpr), + begin + ((fun () -> + case (BoolExpr) of + false -> ok; + __V -> erlang:error({assert, + [{module, ?MODULE}, + {line, ?LINE}, + {expression, (??BoolExpr)}, + {expected, false}, + case __V of true -> {value, __V}; + _ -> {not_boolean,__V} + end]}) + end + end)()) + end). +-endif. + +%% This is mostly a convenience which gives more detailed reports. +%% Note: Guard is a guarded pattern, and can not be used for value. +-ifdef(NOASSERT). +-define(assertMatch(Guard, Expr), ok). +-else. +-define(assertMatch(Guard, Expr), + begin + ((fun () -> + case (Expr) of + Guard -> ok; + __V -> erlang:error({assertMatch, + [{module, ?MODULE}, + {line, ?LINE}, + {expression, (??Expr)}, + {pattern, (??Guard)}, + {value, __V}]}) + end + end)()) + end). +-endif. + +%% This is the inverse case of assertMatch, for convenience. +-ifdef(NOASSERT). +-define(assertNotMatch(Guard, Expr), ok). +-else. +-define(assertNotMatch(Guard, Expr), + begin + ((fun () -> + __V = (Expr), + case __V of + Guard -> erlang:error({assertNotMatch, + [{module, ?MODULE}, + {line, ?LINE}, + {expression, (??Expr)}, + {pattern, (??Guard)}, + {value, __V}]}); + _ -> ok + end + end)()) + end). +-endif. + +%% This is a convenience macro which gives more detailed reports when +%% the expected LHS value is not a pattern, but a computed value +-ifdef(NOASSERT). +-define(assertEqual(Expect, Expr), ok). +-else. +-define(assertEqual(Expect, Expr), + begin + ((fun (__X) -> + case (Expr) of + __X -> ok; + __V -> erlang:error({assertEqual, + [{module, ?MODULE}, + {line, ?LINE}, + {expression, (??Expr)}, + {expected, __X}, + {value, __V}]}) + end + end)(Expect)) + end). +-endif. + +%% This is the inverse case of assertEqual, for convenience. +-ifdef(NOASSERT). +-define(assertNotEqual(Unexpected, Expr), ok). +-else. +-define(assertNotEqual(Unexpected, Expr), + begin + ((fun (__X) -> + case (Expr) of + __X -> erlang:error({assertNotEqual, + [{module, ?MODULE}, + {line, ?LINE}, + {expression, (??Expr)}, + {value, __X}]}); + _ -> ok + end + end)(Unexpected)) + end). +-endif. + +%% Note: Class and Term are patterns, and can not be used for value. +%% Term can be a guarded pattern, but Class cannot. +-ifdef(NOASSERT). +-define(assertException(Class, Term, Expr), ok). +-else. +-define(assertException(Class, Term, Expr), + begin + ((fun () -> + try (Expr) of + __V -> erlang:error({assertException, + [{module, ?MODULE}, + {line, ?LINE}, + {expression, (??Expr)}, + {pattern, + "{ "++(??Class)++" , "++(??Term) + ++" , [...] }"}, + {unexpected_success, __V}]}) + catch + Class:Term -> ok; + __C:__T -> + erlang:error({assertException, + [{module, ?MODULE}, + {line, ?LINE}, + {expression, (??Expr)}, + {pattern, + "{ "++(??Class)++" , "++(??Term) + ++" , [...] }"}, + {unexpected_exception, + {__C, __T, + erlang:get_stacktrace()}}]}) + end + end)()) + end). +-endif. + +-define(assertError(Term, Expr), ?assertException(error, Term, Expr)). +-define(assertExit(Term, Expr), ?assertException(exit, Term, Expr)). +-define(assertThrow(Term, Expr), ?assertException(throw, Term, Expr)). + +%% This is the inverse case of assertException, for convenience. +%% Note: Class and Term are patterns, and can not be used for value. +%% Both Class and Term can be guarded patterns. +-ifdef(NOASSERT). +-define(assertNotException(Class, Term, Expr), ok). +-else. +-define(assertNotException(Class, Term, Expr), + begin + ((fun () -> + try (Expr) of + _ -> ok + catch + __C:__T -> + case __C of + Class -> + case __T of + Term -> + erlang:error({assertNotException, + [{module, ?MODULE}, + {line, ?LINE}, + {expression, (??Expr)}, + {pattern, + "{ "++(??Class)++" , " + ++(??Term)++" , [...] }"}, + {unexpected_exception, + {__C, __T, + erlang:get_stacktrace() + }}]}); + _ -> ok + end; + _ -> ok + end + end + end)()) + end). +-endif. + +-endif. % ASSERT_HRL diff --git a/configure.in b/configure.in index 64b0bdac6d..40498f2ff9 100644 --- a/configure.in +++ b/configure.in @@ -271,7 +271,7 @@ AC_ARG_WITH(ssl-rpath, AS_HELP_STRING([--with-ssl-rpath=yes|no|PATHS], [runtime library path for OpenSSL. Default is 'yes', which equates to a number of standard locations. If 'no', then no runtime - library paths wil be used. Anything else should be a + library paths will be used. Anything else should be a comma separated list of paths.])) AC_ARG_ENABLE(dynamic-ssl-lib, diff --git a/erts/aclocal.m4 b/erts/aclocal.m4 index 01541aff72..ec9b66bf29 100644 --- a/erts/aclocal.m4 +++ b/erts/aclocal.m4 @@ -142,18 +142,18 @@ MIXED_MSYS=no AC_MSG_CHECKING(for mixed cygwin or msys and native VC++ environment) if test "X$host" = "Xwin32" -a "x$GCC" != "xyes"; then - if test -x /usr/bin/cygpath; then - CFLAGS="-O2" - MIXED_CYGWIN=yes - AC_MSG_RESULT([Cygwin and VC]) - MIXED_CYGWIN_VC=yes - CPPFLAGS="$CPPFLAGS -DERTS_MIXED_CYGWIN_VC" - elif test -x /usr/bin/msysinfo; then + if test -x /usr/bin/msys-?.0.dll; then CFLAGS="-O2" MIXED_MSYS=yes AC_MSG_RESULT([MSYS and VC]) MIXED_MSYS_VC=yes CPPFLAGS="$CPPFLAGS -DERTS_MIXED_MSYS_VC" + elif test -x /usr/bin/cygpath; then + CFLAGS="-O2" + MIXED_CYGWIN=yes + AC_MSG_RESULT([Cygwin and VC]) + MIXED_CYGWIN_VC=yes + CPPFLAGS="$CPPFLAGS -DERTS_MIXED_CYGWIN_VC" else AC_MSG_RESULT([undeterminable]) AC_MSG_ERROR(Seems to be mixed windows but not with cygwin, cannot handle this!) @@ -726,9 +726,15 @@ esac AC_DEFUN(ERL_MONOTONIC_CLOCK, [ - default_resolution_clock_gettime_monotonic="CLOCK_HIGHRES CLOCK_BOOTTIME CLOCK_MONOTONIC" - low_resolution_clock_gettime_monotonic="CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC_FAST" - high_resolution_clock_gettime_monotonic="CLOCK_MONOTONIC_PRECISE" + if test "$3" = "yes"; then + default_resolution_clock_gettime_monotonic="CLOCK_HIGHRES CLOCK_BOOTTIME CLOCK_MONOTONIC" + low_resolution_clock_gettime_monotonic="CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC_FAST" + high_resolution_clock_gettime_monotonic="CLOCK_MONOTONIC_PRECISE" + else + default_resolution_clock_gettime_monotonic="CLOCK_HIGHRES CLOCK_UPTIME CLOCK_MONOTONIC" + low_resolution_clock_gettime_monotonic="CLOCK_MONOTONIC_COARSE CLOCK_UPTIME_FAST" + high_resolution_clock_gettime_monotonic="CLOCK_UPTIME_PRECISE" + fi case "$1" in high_resolution) @@ -744,8 +750,8 @@ AC_DEFUN(ERL_MONOTONIC_CLOCK, prefer_resolution_clock_gettime_monotonic="$2" ;; *) - check_msg="" - prefer_resolution_clock_gettime_monotonic= + check_msg="custom " + prefer_resolution_clock_gettime_monotonic="$2" ;; esac @@ -934,16 +940,16 @@ AC_DEFUN(ERL_WALL_CLOCK, erl_wall_clock_low_resolution=no erl_wall_clock_id= - case $erl_cv_clock_gettime_wall_$1-$erl_cv_mach_clock_get_time_wall-$ac_cv_func_gettimeofday-$host_os in - *-*-*-win32) + case $1-$erl_cv_clock_gettime_wall_$1-$erl_cv_mach_clock_get_time_wall-$ac_cv_func_gettimeofday-$host_os in + *-*-*-*-win32) erl_wall_clock_func=WindowsAPI erl_wall_clock_low_resolution=yes ;; - no-yes-*-*) + high_resolution-no-yes-*-*) erl_wall_clock_func=mach_clock_get_time erl_wall_clock_id=CALENDAR_CLOCK ;; - CLOCK_*-*-*-*) + *-CLOCK_*-*-*-*) erl_wall_clock_func=clock_gettime erl_wall_clock_id=$erl_cv_clock_gettime_wall_$1 for low_res_id in $low_resolution_clock_gettime_wall; do @@ -953,7 +959,7 @@ AC_DEFUN(ERL_WALL_CLOCK, fi done ;; - no-no-yes-*) + *-no-*-yes-*) erl_wall_clock_func=gettimeofday ;; *) @@ -1466,7 +1472,7 @@ AC_ARG_WITH(with_sparc_memory_order, LM_CHECK_THR_LIB ERL_INTERNAL_LIBS -ERL_MONOTONIC_CLOCK(high_resolution) +ERL_MONOTONIC_CLOCK(try_find_pthread_compatible, CLOCK_HIGHRES CLOCK_MONOTONIC, no) case $erl_monotonic_clock_func in clock_gettime) @@ -1900,7 +1906,7 @@ case "$THR_LIB_NAME" in #define _DARWIN_C_SOURCE #include <pthread.h>], [char buff[256]; pthread_getname_np(pthread_self(), buff, 256);], - pthread_getname=normal) + pthread_getname=linux) AC_TRY_LINK([#define __USE_GNU #define _DARWIN_C_SOURCE #include <pthread.h>], @@ -2111,63 +2117,159 @@ esac case "$GCC-$host_cpu" in yes-i86pc | yes-i*86 | yes-x86_64 | yes-amd64) + + if test $ac_cv_sizeof_void_p = 4; then + dw_cmpxchg="cmpxchg8b" + else + dw_cmpxchg="cmpxchg16b" + fi + gcc_dw_cmpxchg_asm=no - AC_MSG_CHECKING([for gcc double word cmpxchg asm support]) - AC_TRY_COMPILE([], + gcc_pic_dw_cmpxchg_asm=no + gcc_cflags_pic=no + gcc_cmpxchg8b_pic_no_clobber_ebx=no + gcc_cmpxchg8b_pic_no_clobber_ebx_register_shortage=no + + save_CFLAGS="$CFLAGS" + + # Check if it works out of the box using passed CFLAGS + # and with -fPIC added to CFLAGS if the passed CFLAGS + # doesn't trigger position independent code + pic_cmpxchg=unknown + while true; do + + case $pic_cmpxchg in + yes) pic_text="pic ";; + *) pic_text="";; + esac + + AC_MSG_CHECKING([for gcc $pic_text$dw_cmpxchg plain asm support]) + + plain_cmpxchg=no + AC_TRY_COMPILE([], [ char xchgd; long new[2], xchg[2], *p; __asm__ __volatile__( -#if ETHR_SIZEOF_PTR == 4 && defined(__PIC__) && __PIC__ - "pushl %%ebx\n\t" - "movl %8, %%ebx\n\t" -#endif #if ETHR_SIZEOF_PTR == 4 "lock; cmpxchg8b %0\n\t" #else "lock; cmpxchg16b %0\n\t" #endif "setz %3\n\t" -#if ETHR_SIZEOF_PTR == 4 && defined(__PIC__) && __PIC__ - "popl %%ebx\n\t" -#endif - : "=m"(*p), "=d"(xchg[1]), "=a"(xchg[0]), "=c"(xchgd) - : "m"(*p), "1"(xchg[1]), "2"(xchg[0]), "3"(new[1]), -#if ETHR_SIZEOF_PTR == 4 && defined(__PIC__) && __PIC__ - "r"(new[0]) -#else - "b"(new[0]) -#endif + : "=m"(*p), "=d"(xchg[1]), "=a"(xchg[0]), "=q"(xchgd) + : "m"(*p), "1"(xchg[1]), "2"(xchg[0]), "c"(new[1]), "b"(new[0]) : "cc", "memory"); + ], + [plain_cmpxchg=yes]) + + AC_MSG_RESULT([$plain_cmpxchg]) + + if test $pic_cmpxchg = yes; then + gcc_pic_dw_cmpxchg_asm=$plain_cmpxchg + break + fi + gcc_dw_cmpxchg_asm=$plain_cmpxchg + + # If not already compiling to position independent + # code add -fPIC to CFLAGS and do it again. This + # since we want also want to know how to compile + # to position independent code since this might + # cause problems with the use of the EBX register + # as input to the asm on 32-bit x86 and old gcc + # compilers (gcc vsn < 5). + + AC_TRY_COMPILE([], + [ +#if !defined(__PIC__) || !__PIC__ +# error no pic +#endif ], - [gcc_dw_cmpxchg_asm=yes]) - if test $gcc_dw_cmpxchg_asm = no && test $ac_cv_sizeof_void_p = 4; then + [pic_cmpxchg=yes + gcc_cflags_pic=yes], + [pic_cmpxchg=no]) + + if test $pic_cmpxchg = yes; then + gcc_pic_dw_cmpxchg_asm=$gcc_dw_cmpxchg_asm + break + fi + + CFLAGS="$save_CFLAGS -fPIC" + pic_cmpxchg=yes + + done + + if test $gcc_pic_dw_cmpxchg_asm = no && test $ac_cv_sizeof_void_p = 4; then + + AC_MSG_CHECKING([for gcc pic cmpxchg8b asm support with EBX workaround]) + + # Check if we can work around it by managing the ebx + # register explicitly in the asm... + AC_TRY_COMPILE([], + [ + char xchgd; + long new[2], xchg[2], *p; + __asm__ __volatile__( + "pushl %%ebx\n\t" + "movl %8, %%ebx\n\t" + "lock; cmpxchg8b %0\n\t" + "setz %3\n\t" + "popl %%ebx\n\t" + : "=m"(*p), "=d"(xchg[1]), "=a"(xchg[0]), "=q"(xchgd) + : "m"(*p), "1"(xchg[1]), "2"(xchg[0]), "c"(new[1]), "r"(new[0]) + : "cc", "memory"); + ], + [gcc_pic_dw_cmpxchg_asm=yes + gcc_cmpxchg8b_pic_no_clobber_ebx=yes]) + + AC_MSG_RESULT([$gcc_pic_dw_cmpxchg_asm]) + + if test $gcc_pic_dw_cmpxchg_asm = no; then + + AC_MSG_CHECKING([for gcc pic cmpxchg8b asm support with EBX and register shortage workarounds]) + # If no optimization is enabled we sometimes get a + # register shortage. Check if we can work around + # this... + + AC_TRY_COMPILE([], [ char xchgd; long new[2], xchg[2], *p; -#if !defined(__PIC__) || !__PIC__ -# error nope -#endif __asm__ __volatile__( - "pushl %%ebx\n\t" - "movl (%7), %%ebx\n\t" - "movl 4(%7), %%ecx\n\t" - "lock; cmpxchg8b %0\n\t" - "setz %3\n\t" - "popl %%ebx\n\t" - : "=m"(*p), "=d"(xchg[1]), "=a"(xchg[0]), "=c"(xchgd) - : "m"(*p), "1"(xchg[1]), "2"(xchg[0]), "3"(new) + "pushl %%ebx\n\t" + "movl (%7), %%ebx\n\t" + "movl 4(%7), %%ecx\n\t" + "lock; cmpxchg8b %0\n\t" + "setz %3\n\t" + "popl %%ebx\n\t" + : "=m"(*p), "=d"(xchg[1]), "=a"(xchg[0]), "=c"(xchgd) + : "m"(*p), "1"(xchg[1]), "2"(xchg[0]), "r"(new) : "cc", "memory"); ], - [gcc_dw_cmpxchg_asm=yes]) - if test "$gcc_dw_cmpxchg_asm" = "yes"; then - AC_DEFINE(ETHR_CMPXCHG8B_REGISTER_SHORTAGE, 1, [Define if you get a register shortage with cmpxchg8b and position independent code]) + [gcc_pic_dw_cmpxchg_asm=yes + gcc_cmpxchg8b_pic_no_clobber_ebx=yes + gcc_cmpxchg8b_pic_no_clobber_ebx_register_shortage=yes]) + + AC_MSG_RESULT([$gcc_pic_dw_cmpxchg_asm]) fi + + if test $gcc_cflags_pic = yes; then + gcc_dw_cmpxchg_asm=$gcc_pic_dw_cmpxchg_asm + fi + + fi + + CFLAGS="$save_CFLAGS" + + if test "$gcc_cmpxchg8b_pic_no_clobber_ebx" = "yes"; then + AC_DEFINE(ETHR_CMPXCHG8B_PIC_NO_CLOBBER_EBX, 1, [Define if gcc wont let you clobber ebx with cmpxchg8b and position independent code]) + fi + if test "$gcc_cmpxchg8b_pic_no_clobber_ebx_register_shortage" = "yes"; then + AC_DEFINE(ETHR_CMPXCHG8B_REGISTER_SHORTAGE, 1, [Define if you get a register shortage with cmpxchg8b and position independent code]) fi - AC_MSG_RESULT([$gcc_dw_cmpxchg_asm]) if test "$gcc_dw_cmpxchg_asm" = "yes"; then AC_DEFINE(ETHR_GCC_HAVE_DW_CMPXCHG_ASM_SUPPORT, 1, [Define if you use a gcc that supports the double word cmpxchg instruction]) fi;; @@ -2202,7 +2304,7 @@ AC_DEFUN(ERL_TIME_CORRECTION, AC_ARG_WITH(clock-resolution, AS_HELP_STRING([--with-clock-resolution=high|low|default], - [specify wanted clock resolution)])) + [specify wanted clock resolution])) AC_ARG_WITH(clock-gettime-realtime-id, AS_HELP_STRING([--with-clock-gettime-realtime-id=CLOCKID], @@ -2212,6 +2314,24 @@ AC_ARG_WITH(clock-gettime-monotonic-id, AS_HELP_STRING([--with-clock-gettime-monotonic-id=CLOCKID], [specify clock id to use with clock_gettime() for monotonic time)])) +AC_ARG_ENABLE(prefer-elapsed-monotonic-time-during-suspend, +AS_HELP_STRING([--enable-prefer-elapsed-monotonic-time-during-suspend], + [Prefer an OS monotonic time source with elapsed time during suspend]) +AS_HELP_STRING([--disable-prefer-elapsed-monotonic-time-during-suspend], + [Do not prefer an OS monotonic time source with elapsed time during suspend]), +[ case "$enableval" in + yes) prefer_elapsed_monotonic_time_during_suspend=yes ;; + *) prefer_elapsed_monotonic_time_during_suspend=no ;; + esac ], prefer_elapsed_monotonic_time_during_suspend=no) + +AC_ARG_ENABLE(gettimeofday-as-os-system-time, + AS_HELP_STRING([--enable-gettimeofday-as-os-system-time], + [Force usage of gettimeofday() for OS system time]), +[ case "$enableval" in + yes) force_gettimeofday_os_system_time=yes ;; + *) force_gettimeofday_os_system_time=no ;; + esac ], force_gettimeofday_os_system_time=no) + case "$with_clock_resolution" in ""|no|yes) with_clock_resolution=default;; @@ -2222,6 +2342,17 @@ case "$with_clock_resolution" in ;; esac +if test "$force_gettimeofday_os_system_time" = "yes"; then + + AC_CHECK_FUNCS([gettimeofday]) + if test "$ac_cv_func_gettimeofday" = "yes"; then + AC_DEFINE(OS_SYSTEM_TIME_GETTIMEOFDAY, [1], [Define if you want to implement erts_os_system_time() using gettimeofday()]) + else + AC_MSG_ERROR([No gettimeofday() available]) + fi + +else # $force_gettimeofday_os_system_time != yes + case "$with_clock_gettime_realtime_id" in ""|no) with_clock_gettime_realtime_id=no @@ -2239,23 +2370,6 @@ case "$with_clock_gettime_realtime_id" in ;; esac -case "$with_clock_gettime_monotonic_id" in - ""|no) - with_clock_gettime_monotonic_id=no - ;; - CLOCK_*CPUTIME*) - AC_MSG_ERROR([Invalid clock_gettime() monotonic clock id: Refusing to use the cputime clock id $with_clock_gettime_monotonic_id as monotonic clock id]) - ;; - CLOCK_REALTIME*|CLOCK_TAI*) - AC_MSG_ERROR([Invalid clock_gettime() monotonic clock id: Refusing to use the realtime clock id $with_clock_gettime_monotonic_id as monotonic clock id]) - ;; - CLOCK_*) - ;; - *) - AC_MSG_ERROR([Invalid clock_gettime() clock id: $with_clock_gettime_monotonic_id]) - ;; -esac - case "$with_clock_resolution-$with_clock_gettime_realtime_id" in high-no) ERL_WALL_CLOCK(high_resolution);; @@ -2278,6 +2392,9 @@ case "$erl_wall_clock_func-$erl_wall_clock_id-$with_clock_gettime_realtime_id" i esac case $erl_wall_clock_func in + none) + AC_MSG_ERROR([No wall clock source found]) + ;; mach_clock_get_time) AC_DEFINE(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME, [1], [Define if you want to implement erts_os_system_time() using mach clock_get_time()]) ;; @@ -2296,15 +2413,34 @@ if test "x$erl_wall_clock_id" != "x"; then AC_DEFINE_UNQUOTED(WALL_CLOCK_ID, [$erl_wall_clock_id], [Define to wall clock id to use]) fi +fi # $force_gettimeofday_os_system_time != yes + +case "$with_clock_gettime_monotonic_id" in + ""|no) + with_clock_gettime_monotonic_id=no + ;; + CLOCK_*CPUTIME*) + AC_MSG_ERROR([Invalid clock_gettime() monotonic clock id: Refusing to use the cputime clock id $with_clock_gettime_monotonic_id as monotonic clock id]) + ;; + CLOCK_REALTIME*|CLOCK_TAI*) + AC_MSG_ERROR([Invalid clock_gettime() monotonic clock id: Refusing to use the realtime clock id $with_clock_gettime_monotonic_id as monotonic clock id]) + ;; + CLOCK_*) + ;; + *) + AC_MSG_ERROR([Invalid clock_gettime() clock id: $with_clock_gettime_monotonic_id]) + ;; +esac + case "$with_clock_resolution-$with_clock_gettime_monotonic_id" in high-no) - ERL_MONOTONIC_CLOCK(high_resolution);; + ERL_MONOTONIC_CLOCK(high_resolution, undefined, $prefer_elapsed_monotonic_time_during_suspend);; low-no) - ERL_MONOTONIC_CLOCK(low_resolution);; + ERL_MONOTONIC_CLOCK(low_resolution, undefined, $prefer_elapsed_monotonic_time_during_suspend);; default-no) - ERL_MONOTONIC_CLOCK(default_resolution);; + ERL_MONOTONIC_CLOCK(default_resolution, undefined, $prefer_elapsed_monotonic_time_during_suspend);; *) - ERL_MONOTONIC_CLOCK(custom_resolution, $with_clock_gettime_monotonic_id);; + ERL_MONOTONIC_CLOCK(custom_resolution, $with_clock_gettime_monotonic_id, $prefer_elapsed_monotonic_time_during_suspend);; esac case "$erl_monotonic_clock_func-$erl_monotonic_clock_id-$with_clock_gettime_monotonic_id" in @@ -2352,7 +2488,7 @@ if test $erl_cv_clock_gettime_monotonic_raw = yes; then AC_DEFINE(HAVE_CLOCK_GETTIME_MONOTONIC_RAW, [1], [Define if you have clock_gettime(CLOCK_MONOTONIC_RAW, _)]) fi -ERL_MONOTONIC_CLOCK(high_resolution) +ERL_MONOTONIC_CLOCK(high_resolution, undefined, no) case $$erl_monotonic_clock_low_resolution-$erl_monotonic_clock_func in no-mach_clock_get_time) diff --git a/erts/configure.in b/erts/configure.in index 22ca7ec17d..4ade3b3086 100644 --- a/erts/configure.in +++ b/erts/configure.in @@ -342,6 +342,15 @@ AS_HELP_STRING([--enable-systemd], [enable systemd support in epmd]), [], [enable_systemd=no]) +AC_ARG_ENABLE(saved-compile-time, +AS_HELP_STRING([--disable-saved-compile-time], [disable saved compile time]), +[ case "$enableval" in + no) save_compile_time=0 ;; + *) save_compile_time=1 ;; + esac ], save_compile_time=1) + +AC_DEFINE_UNQUOTED(ERTS_SAVED_COMPILE_TIME, $save_compile_time, [Save compile time?]) + dnl Magic test for clearcase. OTP_RELEASE= if test "${ERLANG_COMMERCIAL_BUILD}" != ""; then @@ -459,7 +468,7 @@ case $host_os in win32) # The ethread library requires _WIN32_WINNT of at least 0x0403. # -D_WIN32_WINNT=* from CPPFLAGS is saved in ETHR_DEFS. - CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0501 -DWINVER=0x0501" + CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0600 -DWINVER=0x0600" ;; darwin*) CPPFLAGS="$CPPFLAGS -D_XOPEN_SOURCE" @@ -4102,7 +4111,7 @@ AC_ARG_WITH(ssl-rpath, AS_HELP_STRING([--with-ssl-rpath=yes|no|PATHS], [runtime library path for OpenSSL. Default is "yes", which equates to a number of standard locations. If "no", then no runtime - library paths wil be used. Anything else should be a + library paths will be used. Anything else should be a comma separated list of paths.]), [ case X$with_ssl in diff --git a/erts/doc/src/absform.xml b/erts/doc/src/absform.xml index 547d5e583d..186c9a1143 100644 --- a/erts/doc/src/absform.xml +++ b/erts/doc/src/absform.xml @@ -11,7 +11,7 @@ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software @@ -19,7 +19,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. - + </legalnotice> <title>The Abstract Format</title> @@ -35,24 +35,24 @@ <p></p> <p>This document describes the standard representation of parse trees for Erlang programs as Erlang terms. This representation is known as the <em>abstract format</em>. - Functions dealing with such parse trees are <c><![CDATA[compile:forms/[1,2]]]></c> + Functions dealing with such parse trees are <c>compile:forms/[1,2]</c> and functions in the modules - <c><![CDATA[epp]]></c>, - <c><![CDATA[erl_eval]]></c>, - <c><![CDATA[erl_lint]]></c>, - <c><![CDATA[erl_pp]]></c>, - <c><![CDATA[erl_parse]]></c>, + <c>epp</c>, + <c>erl_eval</c>, + <c>erl_lint</c>, + <c>erl_pp</c>, + <c>erl_parse</c>, and - <c><![CDATA[io]]></c>. + <c>io</c>. They are also used as input and output for parse transforms (see the module - <c><![CDATA[compile]]></c>).</p> - <p>We use the function <c><![CDATA[Rep]]></c> to denote the mapping from an Erlang source - construct <c><![CDATA[C]]></c> to its abstract format representation <c><![CDATA[R]]></c>, and write - <c><![CDATA[R = Rep(C)]]></c>. + <c>compile</c>).</p> + <p>We use the function <c>Rep</c> to denote the mapping from an Erlang source + construct <c>C</c> to its abstract format representation <c>R</c>, and write + <c>R = Rep(C)</c>. </p> - <p>The word <c><![CDATA[LINE]]></c> below represents an integer, and denotes the + <p>The word <c>LINE</c> below represents an integer, and denotes the number of the line in the source file where the construction occurred. - Several instances of <c><![CDATA[LINE]]></c> in the same construction may denote + Several instances of <c>LINE</c> in the same construction may denote different lines.</p> <p>Since operators are not terms in their own right, when operators are mentioned below, the representation of an operator should be taken to @@ -61,229 +61,116 @@ </p> <section> - <title>Module declarations and forms</title> + <title>Module Declarations and Forms</title> <p>A module declaration consists of a sequence of forms that are either function declarations or attributes.</p> <list type="bulleted"> <item>If D is a module declaration consisting of the forms - <c><![CDATA[F_1]]></c>, ..., <c><![CDATA[F_k]]></c>, then - Rep(D) = <c><![CDATA[[Rep(F_1), ..., Rep(F_k)]]]></c>.</item> - <item>If F is an attribute <c><![CDATA[-module(Mod)]]></c>, then - Rep(F) = <c><![CDATA[{attribute,LINE,module,Mod}]]></c>.</item> - <item>If F is an attribute <c><![CDATA[-export([Fun_1/A_1, ..., Fun_k/A_k])]]></c>, then - Rep(F) = <c><![CDATA[{attribute,LINE,export,[{Fun_1,A_1}, ..., {Fun_k,A_k}]}]]></c>.</item> - <item>If F is an attribute <c><![CDATA[-import(Mod,[Fun_1/A_1, ..., Fun_k/A_k])]]></c>, then - Rep(F) = <c><![CDATA[{attribute,LINE,import,{Mod,[{Fun_1,A_1}, ..., {Fun_k,A_k}]}}]]></c>.</item> - <item>If F is an attribute <c><![CDATA[-compile(Options)]]></c>, then - Rep(F) = <c><![CDATA[{attribute,LINE,compile,Options}]]></c>.</item> - <item>If F is an attribute <c><![CDATA[-file(File,Line)]]></c>, then - Rep(F) = <c><![CDATA[{attribute,LINE,file,{File,Line}}]]></c>.</item> - <item>If F is a record declaration <c><![CDATA[-record(Name,{V_1, ..., V_k})]]></c>, then - Rep(F) = - <c><![CDATA[{attribute,LINE,record,{Name,[Rep(V_1), ..., Rep(V_k)]}}]]></c>. For Rep(V), see below.</item> - <item>If F is a type attribute (i.e. <c><![CDATA[opaque]]></c> or - <c><![CDATA[type]]></c>) - <c><![CDATA[-Attr Name(A_1, ..., A_k) :: T]]></c> where each - <c><![CDATA[A_i]]></c> is a variable, then Rep(F) = - <c><![CDATA[{attribute,LINE,Attr,{Name,Rep(T),[Rep(A_1), ..., Rep(A_k)]}}]]></c>. - For Rep(T), see below.</item> - <item>If F is a type spec (i.e. <c><![CDATA[callback]]></c> or - <c><![CDATA[spec]]></c>) - <c><![CDATA[-Attr F Tc_1; ...; Tc_k]]></c>, - where each <c><![CDATA[Tc_i]]></c> is a fun type clause with an - argument sequence of the same length <c><![CDATA[Arity]]></c>, then - Rep(F) = - <c><![CDATA[{Attr,LINE,{{F,Arity},[Rep(Tc_1), ..., Rep(Tc_k)]}}]]></c>. - For Rep(Tc_i), see below.</item> - <item>If F is a type spec (i.e. <c><![CDATA[callback]]></c> or - <c><![CDATA[spec]]></c>) - <c><![CDATA[-Attr Mod:F Tc_1; ...; Tc_k]]></c>, - where each <c><![CDATA[Tc_i]]></c> is a fun type clause with an - argument sequence of the same length <c><![CDATA[Arity]]></c>, then - Rep(F) = - <c><![CDATA[{Attr,LINE,{{Mod,F,Arity},[Rep(Tc_1), ..., Rep(Tc_k)]}}]]></c>. - For Rep(Tc_i), see below.</item> - <item>If F is a wild attribute <c><![CDATA[-A(T)]]></c>, then - Rep(F) = <c><![CDATA[{attribute,LINE,A,T}]]></c>. + <c>F_1</c>, ..., <c>F_k</c>, then + Rep(D) = <c>[Rep(F_1), ..., Rep(F_k)]</c>.</item> + <item>If F is an attribute <c>-module(Mod)</c>, then + Rep(F) = <c>{attribute,LINE,module,Mod}</c>.</item> + <item>If F is an attribute <c>-behavior(Behavior)</c>, then + Rep(F) = <c>{attribute,LINE,behavior,Behavior}</c>.</item> + <item>If F is an attribute <c>-behaviour(Behaviour)</c>, then + Rep(F) = <c>{attribute,LINE,behaviour,Behaviour}</c>.</item> + <item>If F is an attribute <c>-export([Fun_1/A_1, ..., Fun_k/A_k])</c>, then + Rep(F) = <c>{attribute,LINE,export,[{Fun_1,A_1}, ..., {Fun_k,A_k}]}</c>.</item> + <item>If F is an attribute <c>-import(Mod,[Fun_1/A_1, ..., Fun_k/A_k])</c>, then + Rep(F) = <c>{attribute,LINE,import,{Mod,[{Fun_1,A_1}, ..., {Fun_k,A_k}]}}</c>.</item> + <item>If F is an attribute <c>-export_type([Type_1/A_1, ..., Type_k/A_k])</c>, then + Rep(F) = <c>{attribute,LINE,export_type,[{Type_1,A_1}, ..., {Type_k,A_k}]}</c>.</item> + <item>If F is an attribute <c>-compile(Options)</c>, then + Rep(F) = <c>{attribute,LINE,compile,Options}</c>.</item> + <item>If F is an attribute <c>-file(File,Line)</c>, then + Rep(F) = <c>{attribute,LINE,file,{File,Line}}</c>.</item> + <item>If F is a record declaration + <c>-record(Name,{V_1, ..., V_k})</c>, then Rep(F) = + <c>{attribute,LINE,record,{Name,[Rep(V_1), ..., Rep(V_k)]}}</c>. + For Rep(V), see below.</item> + <item>If F is a type declaration + <c>-Type Name(V_1, ..., V_k) :: T</c>, where + <c>Type</c> is either the atom <c>type</c> or the atom <c>opaque</c>, + each <c>V_i</c> is a variable, and <c>T</c> is a type, then Rep(F) = + <c>{attribute,LINE,Type,{Name,Rep(T),[Rep(V_1), ..., Rep(V_k)]}}</c>. + </item> + <item>If F is a function specification + <c>-Spec Name Ft_1; ...; Ft_k</c>, + where <c>Spec</c> is either the atom <c>spec</c> or the atom + <c>callback</c>, and each <c>Ft_i</c> is a possibly constrained + function type with an argument sequence of the same length + <c>Arity</c>, then Rep(F) = + <c>{attribute,Line,Spec,{{Name,Arity},[Rep(Ft_1), ..., Rep(Ft_k)]}}</c>. + </item> + <item>If F is a function specification + <c>-spec Mod:Name Ft_1; ...; Ft_k</c>, + where each <c>Ft_i</c> is a possibly constrained + function type with an argument sequence of the same length + <c>Arity</c>, then Rep(F) = + <c>{attribute,Line,spec,{{Mod,Name,Arity},[Rep(Ft_1), ..., Rep(Ft_k)]}}</c>. + </item> + <item>If F is a wild attribute <c>-A(T)</c>, then + Rep(F) = <c>{attribute,LINE,A,T}</c>. <br></br></item> - <item>If F is a function declaration <c><![CDATA[Name Fc_1 ; ... ; Name Fc_k]]></c>, - where each <c><![CDATA[Fc_i]]></c> is a function clause with a - pattern sequence of the same length <c><![CDATA[Arity]]></c>, then - Rep(F) = <c><![CDATA[{function,LINE,Name,Arity,[Rep(Fc_1), ...,Rep(Fc_k)]}]]></c>.</item> + <item>If F is a function declaration + <c>Name Fc_1 ; ... ; Name Fc_k</c>, + where each <c>Fc_i</c> is a function clause with a + pattern sequence of the same length <c>Arity</c>, then + Rep(F) = <c>{function,LINE,Name,Arity,[Rep(Fc_1), ...,Rep(Fc_k)]}</c>. + </item> </list> <section> - <title>Type clauses</title> - <list type="bulleted"> - <item>If T is a fun type clause - <c><![CDATA[(A_1, ..., A_n) -> Ret]]></c>, where each - <c><![CDATA[A_i]]></c> and <c><![CDATA[Ret]]></c> are types, then - Rep(T) = - <c><![CDATA[{type,LINE,'fun',[{type,LINE,product,[Rep(A_1), ..., Rep(A_n)]},Rep(Ret)]}]]></c>. - </item> - <item>If T is a bounded fun type clause <c><![CDATA[Tc when Tg]]></c>, - where <c><![CDATA[Tc]]></c> is an unbounded fun type clause and - <c><![CDATA[Tg]]></c> is a type guard sequence, then Rep(T) = - <c><![CDATA[{type,LINE,bounded_fun,[Rep(Tc),Rep(Tg)]}]]></c>.</item> - </list> - </section> - - <section> - <title>Type guards</title> - <list type="bulleted"> - <item>If G is a constraint <c><![CDATA[F(A_1, ..., A_k)]]></c>, where - <c><![CDATA[F]]></c> is an atom and each <c><![CDATA[A_i]]></c> is a - type, then Rep(G) = - <c><![CDATA[{type,LINE,constraint,[Rep(F),[Rep(A_1), ..., Rep(A_k)]]}]]></c>. - </item> - <item>If G is a type definition <c><![CDATA[Name :: Type]]></c>, - where <c><![CDATA[Name]]></c> is a variable and - <c><![CDATA[Type]]></c> is a type, then Rep(G) = - <c><![CDATA[{type,LINE,constraint,[{atom,LINE,is_subtype},[Rep(Name),Rep(Type)]]}]]></c>.</item> - </list> - </section> - - <section> - <title>Types</title> + <title>Record Fields</title> + <p>Each field in a record declaration may have an optional + explicit default initializer expression, as well as an + optional type.</p> <list type="bulleted"> - <item>If T is a type definition <c><![CDATA[Name :: Type]]></c>, - where <c><![CDATA[Name]]></c> is a variable and - <c><![CDATA[Type]]></c> is a type, then Rep(T) = - <c><![CDATA[{ann_type,LINE,[Rep(Name),Rep(Type)]}]]></c>.</item> - <item>If T is a type union <c><![CDATA[A_1 | ... | A_k]]></c>, - where each <c><![CDATA[A_i]]></c> is a type, then Rep(T) = - <c><![CDATA[{type,LINE,union,[Rep(A_1), ..., Rep(A_k)]}]]></c>.</item> - <item>If T is a type range <c><![CDATA[L .. R]]></c>, - where <c><![CDATA[L]]></c> and <c><![CDATA[R]]></c> are types, then - Rep(T) = <c><![CDATA[{type,LINE,range,[Rep(L), Rep(R)]}]]></c>.</item> - <item>If T is a binary operation <c><![CDATA[L Op R]]></c>, - where <c><![CDATA[Op]]></c> is an arithmetic or bitwise binary operator - and <c><![CDATA[L]]></c> and <c><![CDATA[R]]></c> are types, then - Rep(T) = <c><![CDATA[{op,LINE,Op,Rep(L),Rep(R)}]]></c>.</item> - <item>If T is <c><![CDATA[Op A]]></c>, where <c><![CDATA[Op]]></c> is an - arithmetic or bitwise unary operator and <c><![CDATA[A]]></c> is a - type, then Rep(T) = <c><![CDATA[{op,LINE,Op,Rep(A)}]]></c>.</item> - <item>If T is a fun type <c><![CDATA[fun()]]></c>, then Rep(T) = - <c><![CDATA[{type,LINE,'fun',[]}]]></c>.</item> - <item>If T is a variable <c><![CDATA[V]]></c>, then Rep(T) = - <c><![CDATA[{var,LINE,A}]]></c>, where <c><![CDATA[A]]></c> is an atom - with a printname consisting of the same characters as - <c><![CDATA[V]]></c>.</item> - <item>If T is an atomic literal L and L is not a string literal, then - Rep(T) = Rep(L).</item> - <item>If T is a tuple or map type <c><![CDATA[F()]]></c> (i.e. - <c><![CDATA[tuple]]></c> or <c><![CDATA[map]]></c>), then Rep(T) = - <c><![CDATA[{type,LINE,F,any}]]></c>.</item> - <item>If T is a type <c><![CDATA[F(A_1, ..., A_k)]]></c>, where each - <c><![CDATA[A_i]]></c> is a type, then Rep(T) = - <c><![CDATA[{user_type,LINE,F,[Rep(A_1), ..., Rep(A_k)]}]]></c>.</item> - <item>If T is a remote type <c><![CDATA[M:F(A_1, ..., A_k)]]></c>, where - each <c><![CDATA[A_i]]></c> is a type and <c><![CDATA[M]]></c> and - <c><![CDATA[F]]></c>, then Rep(T) = - <c><![CDATA[{remote_type,LINE,[Rep(M),Rep(F),[Rep(A_1), ..., Rep(A_k)]]}]]></c>. + <item>If V is <c>A</c>, then + Rep(V) = <c>{record_field,LINE,Rep(A)}</c>.</item> + <item>If V is <c>A = E</c>, + where <c>E</c> is an expression, then + Rep(V) = <c>{record_field,LINE,Rep(A),Rep(E)}</c>.</item> + <item>If V is <c>A :: T</c>, where <c>T</c> is a + type and it does not contain + <c>undefined</c> syntactically, then Rep(V) = + <c>{typed_record_field,{record_field,LINE,Rep(A)},Rep(undefined | T)}</c>. </item> - <item>If T is the nil type <c><![CDATA[[]]]></c>, then Rep(T) = - <c><![CDATA[{type,LINE,nil,[]}]]></c>.</item> - <item>If T is a list type <c><![CDATA[[A]]]></c>, where - <c><![CDATA[A]]></c> is a type, then Rep(T) = - <c><![CDATA[{type,LINE,list,[Rep(A)]}]]></c>.</item> - <item>If T is a non-empty list type <c><![CDATA[[A, ...]]]></c>, where - <c><![CDATA[A]]></c> is a type, then Rep(T) = - <c><![CDATA[{type,LINE,nonempty_list,[Rep(A)]}]]></c>.</item> - <item>If T is a map type <c><![CDATA[#{P_1, ..., P_k}]]></c>, where each - <c><![CDATA[P_i]]></c> is a map pair type, then Rep(T) = - <c><![CDATA[{type,LINE,map,[Rep(P_1), ..., Rep(P_k)]}]]></c>.</item> - <item>If T is a map pair type <c><![CDATA[K => V]]></c>, where - <c><![CDATA[K]]></c> and <c><![CDATA[V]]></c> are types, - then Rep(T) = - <c><![CDATA[{type,LINE,map_field_assoc,[Rep(K),Rep(V)]}]]></c>.</item> - <item>If T is a tuple type <c><![CDATA[{A_1, ..., A_k}]]></c>, where - each <c><![CDATA[A_i]]></c> is a type, then Rep(T) = - <c><![CDATA[{type,LINE,tuple,[Rep(A_1), ..., Rep(A_k)]}]]></c>.</item> - <item>If T is a record type <c><![CDATA[#Name{}]]></c>, where - <c><![CDATA[Name]]></c> is an atom, then Rep(T) = - <c><![CDATA[{type,LINE,record,[Rep(Name)]}]]></c>.</item> - <item>If T is a record type <c><![CDATA[#Name{F_1, ..., F_k}]]></c>, - where <c><![CDATA[Name]]></c> is an atom, then Rep(T) = - <c><![CDATA[{type,LINE,record,[Rep(Name),[Rep(F_1), ..., Rep(F_k)]]}]]></c>. + <item>If V is <c>A :: T</c>, where <c>T</c> is a type, then Rep(V) = + <c>{typed_record_field,{record_field,LINE,Rep(A)},Rep(T)}</c>. + </item> + <item>If V is <c>A = E :: T</c>, where + <c>E</c> is an expression and <c>T</c> is a type, then Rep(V) = + <c>{typed_record_field,{record_field,LINE,Rep(A),Rep(E)},Rep(T)}</c>. </item> - <item>If T is a record field type <c><![CDATA[Name :: Type]]></c>, - where <c><![CDATA[Name]]></c> is an atom, then Rep(T) = - <c><![CDATA[{type,LINE,field_type,[Rep(Name),Rep(Type)]}]]></c>.</item> - <item>If T is a record field type <c><![CDATA[<<>>]]></c>, then Rep(T) = - <c><![CDATA[{type,LINE,binary,[{integer,LINE,0},{integer,LINE,0}]}]]></c>. - </item> - <item>If T is a binary type <c><![CDATA[<< _ : B >>]]></c>, where - <c><![CDATA[B]]></c> is a type, then Rep(T) = - <c><![CDATA[{type,LINE,binary,[Rep(B),{integer,LINE,0}]}]]></c>.</item> - <item>If T is a binary type <c><![CDATA[<< _ : _ * U >>]]></c>, - where <c><![CDATA[U]]></c> is a type, then Rep(T) = - <c><![CDATA[{type,LINE,binary,[{integer,LINE,0},Rep(U)]}]]></c>.</item> - <item>If T is a binary type <c><![CDATA[<< _ : B , _ : _ * U >>]]></c>, - where <c><![CDATA[B]]></c> and <c><![CDATA[U]]></c> is a type, then - Rep(T) = - <c><![CDATA[{type,LINE,binary,[Rep(B),Rep(U)]}]]></c>.</item> - - <item>If T is a fun type <c><![CDATA[fun((...) -> Ret)]]></c>, then - Rep(T) = <c><![CDATA[{type,LINE,'fun',[{type,LINE,product,[]},Rep(Ret)]}]]></c>. - </item> - <item>If T is a fun type <c><![CDATA[fun(Tc)]]></c>, where - <c><![CDATA[Tc]]></c> is an unbounded fun type clause, - then Rep(T) = <c><![CDATA[Rep(Tc)]]></c>.</item> </list> </section> <section> - <title>Record fields</title> - <p>Each field in a record declaration may have an optional - explicit default initializer expression</p> - <list type="bulleted"> - <item>If V is <c><![CDATA[A]]></c>, then - Rep(V) = <c><![CDATA[{record_field,LINE,Rep(A)}]]></c>.</item> - <item>If V is <c><![CDATA[A = E]]></c>, then - Rep(V) = <c><![CDATA[{record_field,LINE,Rep(A),Rep(E)}]]></c>.</item> - <item>If V is <c><![CDATA[A :: T]]></c>, where <c><![CDATA[A]]></c> is - an atom and <c><![CDATA[T]]></c> is a type and it does not contain - <c><![CDATA[undefined]]></c> syntactically, then Rep(V) = - <c><![CDATA[{typed_record_field,{record_field,LINE,Rep(A)},Rep(undefined | T)}]]></c>. - Note that if <![CDATA[T]]> is an annotated type, it will be wrapped in - parentheses.</item> - <item>If V is <c><![CDATA[A :: T]]></c>, where <c><![CDATA[A]]></c> is - an atom and <c><![CDATA[T]]></c> is a type, then Rep(V) = - <c><![CDATA[{typed_record_field,{record_field,LINE,Rep(A)},Rep(T)}]]></c>. - </item> - <item>If V is <c><![CDATA[A = E :: T]]></c>, where <c><![CDATA[A]]></c> - is an atom, <c><![CDATA[E]]></c> is an expression and - <c><![CDATA[T]]></c> is a type, then Rep(V) = - <c><![CDATA[{typed_record_field,{record_field,LINE,Rep(A),Rep(E)},Rep(T)}]]></c>. - </item> - </list> - </section> - - <section> - <title>Representation of parse errors and end of file</title> + <title>Representation of Parse Errors and End-of-file</title> <p>In addition to the representations of forms, the list that represents - a module declaration (as returned by functions in <c><![CDATA[erl_parse]]></c> and - <c><![CDATA[epp]]></c>) may contain tuples <c><![CDATA[{error,E}]]></c> and <c><![CDATA[{warning,W}]]></c>, denoting - syntactically incorrect forms and warnings, and <c><![CDATA[{eof,LINE}]]></c>, denoting an end - of stream encountered before a complete form had been parsed.</p> + a module declaration (as returned by functions in <c>erl_parse</c> and + <c>epp</c>) may contain tuples <c>{error,E}</c> and + <c>{warning,W}</c>, denoting syntactically incorrect forms and + warnings, and <c>{eof,LINE}</c>, denoting an end-of-stream + encountered before a complete form had been parsed.</p> </section> </section> <section> - <title>Atomic literals</title> + <title>Atomic Literals</title> <p>There are five kinds of atomic literals, which are represented in the same way in patterns, expressions and guards:</p> <list type="bulleted"> <item>If L is an integer or character literal, then - Rep(L) = <c><![CDATA[{integer,LINE,L}]]></c>.</item> + Rep(L) = <c>{integer,LINE,L}</c>.</item> <item>If L is a float literal, then - Rep(L) = <c><![CDATA[{float,LINE,L}]]></c>.</item> + Rep(L) = <c>{float,LINE,L}</c>.</item> <item>If L is a string literal consisting of the characters - <c><![CDATA[C_1]]></c>, ..., <c><![CDATA[C_k]]></c>, then - Rep(L) = <c><![CDATA[{string,LINE,[C_1, ..., C_k]}]]></c>.</item> + <c>C_1</c>, ..., <c>C_k</c>, then + Rep(L) = <c>{string,LINE,[C_1, ..., C_k]}</c>.</item> <item>If L is an atom literal, then - Rep(L) = <c><![CDATA[{atom,LINE,L}]]></c>.</item> + Rep(L) = <c>{atom,LINE,L}</c>.</item> </list> <p>Note that negative integer and float literals do not occur as such; they are parsed as an application of the unary negation operator.</p> @@ -291,47 +178,47 @@ <section> <title>Patterns</title> - <p>If <c><![CDATA[Ps]]></c> is a sequence of patterns <c><![CDATA[P_1, ..., P_k]]></c>, then - Rep(Ps) = <c><![CDATA[[Rep(P_1), ..., Rep(P_k)]]]></c>. Such sequences occur as the + <p>If <c>Ps</c> is a sequence of patterns <c>P_1, ..., P_k</c>, then + Rep(Ps) = <c>[Rep(P_1), ..., Rep(P_k)]</c>. Such sequences occur as the list of arguments to a function or fun.</p> <p>Individual patterns are represented as follows:</p> <list type="bulleted"> <item>If P is an atomic literal L, then Rep(P) = Rep(L).</item> - <item>If P is a compound pattern <c><![CDATA[P_1 = P_2]]></c>, then - Rep(P) = <c><![CDATA[{match,LINE,Rep(P_1),Rep(P_2)}]]></c>.</item> - <item>If P is a variable pattern <c><![CDATA[V]]></c>, then - Rep(P) = <c><![CDATA[{var,LINE,A}]]></c>, + <item>If P is a compound pattern <c>P_1 = P_2</c>, then + Rep(P) = <c>{match,LINE,Rep(P_1),Rep(P_2)}</c>.</item> + <item>If P is a variable pattern <c>V</c>, then + Rep(P) = <c>{var,LINE,A}</c>, where A is an atom with a printname consisting of the same characters as - <c><![CDATA[V]]></c>.</item> - <item>If P is a universal pattern <c><![CDATA[_]]></c>, then - Rep(P) = <c><![CDATA[{var,LINE,'_'}]]></c>.</item> - <item>If P is a tuple pattern <c><![CDATA[{P_1, ..., P_k}]]></c>, then - Rep(P) = <c><![CDATA[{tuple,LINE,[Rep(P_1), ..., Rep(P_k)]}]]></c>.</item> - <item>If P is a nil pattern <c><![CDATA[[]]]></c>, then - Rep(P) = <c><![CDATA[{nil,LINE}]]></c>.</item> - <item>If P is a cons pattern <c><![CDATA[[P_h | P_t]]]></c>, then - Rep(P) = <c><![CDATA[{cons,LINE,Rep(P_h),Rep(P_t)}]]></c>.</item> - <item>If E is a binary pattern <c><![CDATA[<<P_1:Size_1/TSL_1, ..., P_k:Size_k/TSL_k>>]]></c>, then - Rep(E) = <c><![CDATA[{bin,LINE,[{bin_element,LINE,Rep(P_1),Rep(Size_1),Rep(TSL_1)}, ..., {bin_element,LINE,Rep(P_k),Rep(Size_k),Rep(TSL_k)}]}]]></c>. + <c>V</c>.</item> + <item>If P is a universal pattern <c>_</c>, then + Rep(P) = <c>{var,LINE,'_'}</c>.</item> + <item>If P is a tuple pattern <c>{P_1, ..., P_k}</c>, then + Rep(P) = <c>{tuple,LINE,[Rep(P_1), ..., Rep(P_k)]}</c>.</item> + <item>If P is a nil pattern <c>[]</c>, then + Rep(P) = <c>{nil,LINE}</c>.</item> + <item>If P is a cons pattern <c>[P_h | P_t]</c>, then + Rep(P) = <c>{cons,LINE,Rep(P_h),Rep(P_t)}</c>.</item> + <item>If E is a binary pattern <c><<P_1:Size_1/TSL_1, ..., P_k:Size_k/TSL_k>></c>, then + Rep(E) = <c>{bin,LINE,[{bin_element,LINE,Rep(P_1),Rep(Size_1),Rep(TSL_1)}, ..., {bin_element,LINE,Rep(P_k),Rep(Size_k),Rep(TSL_k)}]}</c>. For Rep(TSL), see below. - An omitted <c><![CDATA[Size]]></c> is represented by <c><![CDATA[default]]></c>. An omitted <c><![CDATA[TSL]]></c> - (type specifier list) is represented by <c><![CDATA[default]]></c>.</item> - <item>If P is <c><![CDATA[P_1 Op P_2]]></c>, where <c><![CDATA[Op]]></c> is a binary operator (this - is either an occurrence of <c><![CDATA[++]]></c> applied to a literal string or character + An omitted <c>Size</c> is represented by <c>default</c>. An omitted <c>TSL</c> + (type specifier list) is represented by <c>default</c>.</item> + <item>If P is <c>P_1 Op P_2</c>, where <c>Op</c> is a binary operator (this + is either an occurrence of <c>++</c> applied to a literal string or character list, or an occurrence of an expression that can be evaluated to a number at compile time), - then Rep(P) = <c><![CDATA[{op,LINE,Op,Rep(P_1),Rep(P_2)}]]></c>.</item> - <item>If P is <c><![CDATA[Op P_0]]></c>, where <c><![CDATA[Op]]></c> is a unary operator (this is an + then Rep(P) = <c>{op,LINE,Op,Rep(P_1),Rep(P_2)}</c>.</item> + <item>If P is <c>Op P_0</c>, where <c>Op</c> is a unary operator (this is an occurrence of an expression that can be evaluated to a number at compile - time), then Rep(P) = <c><![CDATA[{op,LINE,Op,Rep(P_0)}]]></c>.</item> - <item>If P is a record pattern <c><![CDATA[#Name{Field_1=P_1, ..., Field_k=P_k}]]></c>, + time), then Rep(P) = <c>{op,LINE,Op,Rep(P_0)}</c>.</item> + <item>If P is a record pattern <c>#Name{Field_1=P_1, ..., Field_k=P_k}</c>, then Rep(P) = - <c><![CDATA[{record,LINE,Name, [{record_field,LINE,Rep(Field_1),Rep(P_1)}, ..., {record_field,LINE,Rep(Field_k),Rep(P_k)}]}]]></c>.</item> - <item>If P is <c><![CDATA[#Name.Field]]></c>, then - Rep(P) = <c><![CDATA[{record_index,LINE,Name,Rep(Field)}]]></c>.</item> - <item>If P is <c><![CDATA[( P_0 )]]></c>, then - Rep(P) = <c><![CDATA[Rep(P_0)]]></c>, - i.e., patterns cannot be distinguished from their bodies.</item> + <c>{record,LINE,Name,[{record_field,LINE,Rep(Field_1),Rep(P_1)}, ..., {record_field,LINE,Rep(Field_k),Rep(P_k)}]}</c>.</item> + <item>If P is <c>#Name.Field</c>, then + Rep(P) = <c>{record_index,LINE,Name,Rep(Field)}</c>.</item> + <item>If P is <c>( P_0 )</c>, then + Rep(P) = <c>Rep(P_0)</c>, + that is, patterns cannot be distinguished from their bodies.</item> </list> <p>Note that every pattern has the same source form as some expression, and is represented the same way as the corresponding expression.</p> @@ -339,180 +226,167 @@ <section> <title>Expressions</title> - <p>A body B is a sequence of expressions <c><![CDATA[E_1, ..., E_k]]></c>, and - Rep(B) = <c><![CDATA[[Rep(E_1), ..., Rep(E_k)]]]></c>.</p> + <p>A body B is a sequence of expressions <c>E_1, ..., E_k</c>, and + Rep(B) = <c>[Rep(E_1), ..., Rep(E_k)]</c>.</p> <p>An expression E is one of the following alternatives:</p> <list type="bulleted"> - <item>If P is an atomic literal <c><![CDATA[L]]></c>, then - Rep(P) = Rep(L).</item> - <item>If E is <c><![CDATA[P = E_0]]></c>, then - Rep(E) = <c><![CDATA[{match,LINE,Rep(P),Rep(E_0)}]]></c>.</item> - <item>If E is a variable <c><![CDATA[V]]></c>, then - Rep(E) = <c><![CDATA[{var,LINE,A}]]></c>, - where <c><![CDATA[A]]></c> is an atom with a printname consisting of the same - characters as <c><![CDATA[V]]></c>.</item> - <item>If E is a tuple skeleton <c><![CDATA[{E_1, ..., E_k}]]></c>, then - Rep(E) = <c><![CDATA[{tuple,LINE,[Rep(E_1), ..., Rep(E_k)]}]]></c>.</item> - <item>If E is <c><![CDATA[[]]]></c>, then - Rep(E) = <c><![CDATA[{nil,LINE}]]></c>.</item> - <item>If E is a cons skeleton <c><![CDATA[[E_h | E_t]]]></c>, then - Rep(E) = <c><![CDATA[{cons,LINE,Rep(E_h),Rep(E_t)}]]></c>.</item> - <item>If E is a binary constructor <c><![CDATA[<<V_1:Size_1/TSL_1, ..., V_k:Size_k/TSL_k>>]]></c>, then - Rep(E) = <c><![CDATA[{bin,LINE,[{bin_element,LINE,Rep(V_1),Rep(Size_1),Rep(TSL_1)}, ..., {bin_element,LINE,Rep(V_k),Rep(Size_k),Rep(TSL_k)}]}]]></c>. + <item>If P is an atomic literal <c>L</c>, then Rep(P) = Rep(L).</item> + <item>If E is <c>P = E_0</c>, then + Rep(E) = <c>{match,LINE,Rep(P),Rep(E_0)}</c>.</item> + <item>If E is a variable <c>V</c>, then Rep(E) = <c>{var,LINE,A}</c>, + where <c>A</c> is an atom with a printname consisting of the same + characters as <c>V</c>.</item> + <item>If E is a tuple skeleton <c>{E_1, ..., E_k}</c>, then + Rep(E) = <c>{tuple,LINE,[Rep(E_1), ..., Rep(E_k)]}</c>.</item> + <item>If E is <c>[]</c>, then + Rep(E) = <c>{nil,LINE}</c>.</item> + <item>If E is a cons skeleton <c>[E_h | E_t]</c>, then + Rep(E) = <c>{cons,LINE,Rep(E_h),Rep(E_t)}</c>.</item> + <item>If E is a binary constructor <c><<V_1:Size_1/TSL_1, ..., V_k:Size_k/TSL_k>></c>, then Rep(E) = + <c>{bin,LINE,[{bin_element,LINE,Rep(V_1),Rep(Size_1),Rep(TSL_1)}, ..., {bin_element,LINE,Rep(V_k),Rep(Size_k),Rep(TSL_k)}]}</c>. For Rep(TSL), see below. - An omitted <c><![CDATA[Size]]></c> is represented by <c><![CDATA[default]]></c>. An omitted <c><![CDATA[TSL]]></c> - (type specifier list) is represented by <c><![CDATA[default]]></c>.</item> - <item>If E is <c><![CDATA[E_1 Op E_2]]></c>, where <c><![CDATA[Op]]></c> is a binary operator, - then Rep(E) = <c><![CDATA[{op,LINE,Op,Rep(E_1),Rep(E_2)}]]></c>.</item> - <item>If E is <c><![CDATA[Op E_0]]></c>, where <c><![CDATA[Op]]></c> is a unary operator, then - Rep(E) = <c><![CDATA[{op,LINE,Op,Rep(E_0)}]]></c>.</item> - <item>If E is <c><![CDATA[#Name{Field_1=E_1, ..., Field_k=E_k}]]></c>, then - Rep(E) = - <c><![CDATA[{record,LINE,Name, [{record_field,LINE,Rep(Field_1),Rep(E_1)}, ..., {record_field,LINE,Rep(Field_k),Rep(E_k)}]}]]></c>.</item> - <item>If E is <c><![CDATA[E_0#Name{Field_1=E_1, ..., Field_k=E_k}]]></c>, then + An omitted <c>Size</c> is represented by <c>default</c>. An omitted <c>TSL</c> + (type specifier list) is represented by <c>default</c>.</item> + <item>If E is <c>E_1 Op E_2</c>, where <c>Op</c> is a binary operator, + then Rep(E) = <c>{op,LINE,Op,Rep(E_1),Rep(E_2)}</c>.</item> + <item>If E is <c>Op E_0</c>, where <c>Op</c> is a unary operator, then + Rep(E) = <c>{op,LINE,Op,Rep(E_0)}</c>.</item> + <item>If E is <c>#Name{Field_1=E_1, ..., Field_k=E_k}</c>, + then Rep(E) = + <c>{record,LINE,Name,[{record_field,LINE,Rep(Field_1),Rep(E_1)}, ..., {record_field,LINE,Rep(Field_k),Rep(E_k)}]}</c>.</item> + <item>If E is <c>E_0#Name{Field_1=E_1, ..., Field_k=E_k}</c>, then Rep(E) = - <c><![CDATA[{record,LINE,Rep(E_0),Name, [{record_field,LINE,Rep(Field_1),Rep(E_1)}, ..., {record_field,LINE,Rep(Field_k),Rep(E_k)}]}]]></c>.</item> - <item>If E is <c><![CDATA[#Name.Field]]></c>, then - Rep(E) = <c><![CDATA[{record_index,LINE,Name,Rep(Field)}]]></c>.</item> - <item>If E is <c><![CDATA[E_0#Name.Field]]></c>, then - Rep(E) = <c><![CDATA[{record_field,LINE,Rep(E_0),Name,Rep(Field)}]]></c>.</item> - <item>If E is <c><![CDATA[#{W_1, ..., W_k}]]></c> where each - <c><![CDATA[W_i]]></c> is a map assoc or exact field, then Rep(E) = - <c><![CDATA[{map,LINE,[Rep(W_1), ..., Rep(W_k)]}]]></c>. For Rep(W), see + <c>{record,LINE,Rep(E_0),Name,[{record_field,LINE,Rep(Field_1),Rep(E_1)}, ..., {record_field,LINE,Rep(Field_k),Rep(E_k)}]}</c>.</item> + <item>If E is <c>#Name.Field</c>, then + Rep(E) = <c>{record_index,LINE,Name,Rep(Field)}</c>.</item> + <item>If E is <c>E_0#Name.Field</c>, then + Rep(E) = <c>{record_field,LINE,Rep(E_0),Name,Rep(Field)}</c>.</item> + <item>If E is <c>#{W_1, ..., W_k}</c> where each + <c>W_i</c> is a map assoc or exact field, then Rep(E) = + <c>{map,LINE,[Rep(W_1), ..., Rep(W_k)]}</c>. For Rep(W), see below.</item> - <item>If E is <c><![CDATA[E_0#{W_1, ..., W_k}]]></c> where - <c><![CDATA[W_i]]></c> is a map assoc or exact field, then Rep(E) = - <c><![CDATA[{map,LINE,Rep(E_0),[Rep(W_1), ..., Rep(W_k)]}]]></c>. For - Rep(W), see below.</item> - <item>If E is <c><![CDATA[catch E_0]]></c>, then - Rep(E) = <c><![CDATA[{'catch',LINE,Rep(E_0)}]]></c>.</item> - <item>If E is <c><![CDATA[E_0(E_1, ..., E_k)]]></c>, then - Rep(E) = <c><![CDATA[{call,LINE,Rep(E_0),[Rep(E_1), ..., Rep(E_k)]}]]></c>.</item> - <item>If E is <c><![CDATA[E_m:E_0(E_1, ..., E_k)]]></c>, then - Rep(E) = - <c><![CDATA[{call,LINE,{remote,LINE,Rep(E_m),Rep(E_0)},[Rep(E_1), ..., Rep(E_k)]}]]></c>.</item> - <item>If E is a list comprehension <c><![CDATA[[E_0 || W_1, ..., W_k]]]></c>, - where each <c><![CDATA[W_i]]></c> is a generator or a filter, then - Rep(E) = <c><![CDATA[{lc,LINE,Rep(E_0),[Rep(W_1), ..., Rep(W_k)]}]]></c>. For Rep(W), see - below.</item> - <item>If E is a binary comprehension <c><![CDATA[<<E_0 || W_1, ..., W_k>>]]></c>, - where each <c><![CDATA[W_i]]></c> is a generator or a filter, then - Rep(E) = <c><![CDATA[{bc,LINE,Rep(E_0),[Rep(W_1), ..., Rep(W_k)]}]]></c>. For Rep(W), see + <item>If E is <c>E_0#{W_1, ..., W_k}</c> where + <c>W_i</c> is a map assoc or exact field, then Rep(E) = + <c>{map,LINE,Rep(E_0),[Rep(W_1), ..., Rep(W_k)]}</c>. + For Rep(W), see below.</item> + <item>If E is <c>catch E_0</c>, then + Rep(E) = <c>{'catch',LINE,Rep(E_0)}</c>.</item> + <item>If E is <c>E_0(E_1, ..., E_k)</c>, then + Rep(E) = <c>{call,LINE,Rep(E_0),[Rep(E_1), ..., Rep(E_k)]}</c>.</item> + <item>If E is <c>E_m:E_0(E_1, ..., E_k)</c>, then Rep(E) = + <c>{call,LINE,{remote,LINE,Rep(E_m),Rep(E_0)},[Rep(E_1), ..., Rep(E_k)]}</c>. + </item> + <item>If E is a list comprehension <c>[E_0 || W_1, ..., W_k]</c>, + where each <c>W_i</c> is a generator or a filter, then Rep(E) = + <c>{lc,LINE,Rep(E_0),[Rep(W_1), ..., Rep(W_k)]}</c>. For Rep(W), see below.</item> - <item>If E is <c><![CDATA[begin B end]]></c>, where <c><![CDATA[B]]></c> is a body, then - Rep(E) = <c><![CDATA[{block,LINE,Rep(B)}]]></c>.</item> - <item>If E is <c><![CDATA[if Ic_1 ; ... ; Ic_k end]]></c>, - where each <c><![CDATA[Ic_i]]></c> is an if clause then - Rep(E) = - <c><![CDATA[{'if',LINE,[Rep(Ic_1), ..., Rep(Ic_k)]}]]></c>.</item> - <item>If E is <c><![CDATA[case E_0 of Cc_1 ; ... ; Cc_k end]]></c>, - where <c><![CDATA[E_0]]></c> is an expression and each <c><![CDATA[Cc_i]]></c> is a - case clause then - Rep(E) = - <c><![CDATA[{'case',LINE,Rep(E_0),[Rep(Cc_1), ..., Rep(Cc_k)]}]]></c>.</item> - <item>If E is <c><![CDATA[try B catch Tc_1 ; ... ; Tc_k end]]></c>, - where <c><![CDATA[B]]></c> is a body and each <c><![CDATA[Tc_i]]></c> is a catch clause then - Rep(E) = - <c><![CDATA[{'try',LINE,Rep(B),[],[Rep(Tc_1), ..., Rep(Tc_k)],[]}]]></c>.</item> - <item>If E is <c><![CDATA[try B of Cc_1 ; ... ; Cc_k catch Tc_1 ; ... ; Tc_n end]]></c>, - where <c><![CDATA[B]]></c> is a body, - each <c><![CDATA[Cc_i]]></c> is a case clause and - each <c><![CDATA[Tc_j]]></c> is a catch clause then - Rep(E) = - <c><![CDATA[{'try',LINE,Rep(B),[Rep(Cc_1), ..., Rep(Cc_k)],[Rep(Tc_1), ..., Rep(Tc_n)],[]}]]></c>.</item> - <item>If E is <c><![CDATA[try B after A end]]></c>, - where <c><![CDATA[B]]></c> and <c><![CDATA[A]]></c> are bodies then - Rep(E) = - <c><![CDATA[{'try',LINE,Rep(B),[],[],Rep(A)}]]></c>.</item> - <item>If E is <c><![CDATA[try B of Cc_1 ; ... ; Cc_k after A end]]></c>, - where <c><![CDATA[B]]></c> and <c><![CDATA[A]]></c> are a bodies and - each <c><![CDATA[Cc_i]]></c> is a case clause then - Rep(E) = - <c><![CDATA[{'try',LINE,Rep(B),[Rep(Cc_1), ..., Rep(Cc_k)],[],Rep(A)}]]></c>.</item> - <item>If E is <c><![CDATA[try B catch Tc_1 ; ... ; Tc_k after A end]]></c>, - where <c><![CDATA[B]]></c> and <c><![CDATA[A]]></c> are bodies and - each <c><![CDATA[Tc_i]]></c> is a catch clause then - Rep(E) = - <c><![CDATA[{'try',LINE,Rep(B),[],[Rep(Tc_1), ..., Rep(Tc_k)],Rep(A)}]]></c>.</item> - <item>If E is <c><![CDATA[try B of Cc_1 ; ... ; Cc_k catch Tc_1 ; ... ; Tc_n after A end]]></c>, - where <c><![CDATA[B]]></c> and <c><![CDATA[A]]></c> are a bodies, - each <c><![CDATA[Cc_i]]></c> is a case clause and - each <c><![CDATA[Tc_j]]></c> is a catch clause then - Rep(E) = - <c><![CDATA[{'try',LINE,Rep(B),[Rep(Cc_1), ..., Rep(Cc_k)],[Rep(Tc_1), ..., Rep(Tc_n)],Rep(A)}]]></c>.</item> - <item>If E is <c><![CDATA[receive Cc_1 ; ... ; Cc_k end]]></c>, - where each <c><![CDATA[Cc_i]]></c> is a case clause then + <item>If E is a binary comprehension + <c><<E_0 || W_1, ..., W_k>></c>, + where each <c>W_i</c> is a generator or a filter, then + Rep(E) = <c>{bc,LINE,Rep(E_0),[Rep(W_1), ..., Rep(W_k)]}</c>. + For Rep(W), see below.</item> + <item>If E is <c>begin B end</c>, where <c>B</c> is a body, then + Rep(E) = <c>{block,LINE,Rep(B)}</c>.</item> + <item>If E is <c>if Ic_1 ; ... ; Ic_k end</c>, + where each <c>Ic_i</c> is an if clause then Rep(E) = + <c>{'if',LINE,[Rep(Ic_1), ..., Rep(Ic_k)]}</c>.</item> + <item>If E is <c>case E_0 of Cc_1 ; ... ; Cc_k end</c>, + where <c>E_0</c> is an expression and each <c>Cc_i</c> is a + case clause then Rep(E) = + <c>{'case',LINE,Rep(E_0),[Rep(Cc_1), ..., Rep(Cc_k)]}</c>.</item> + <item>If E is <c>try B catch Tc_1 ; ... ; Tc_k end</c>, + where <c>B</c> is a body and each <c>Tc_i</c> is a catch clause then Rep(E) = - <c><![CDATA[{'receive',LINE,[Rep(Cc_1), ..., Rep(Cc_k)]}]]></c>.</item> - <item>If E is <c><![CDATA[receive Cc_1 ; ... ; Cc_k after E_0 -> B_t end]]></c>, - where each <c><![CDATA[Cc_i]]></c> is a case clause, - <c><![CDATA[E_0]]></c> is an expression and <c><![CDATA[B_t]]></c> is a body, then + <c>{'try',LINE,Rep(B),[],[Rep(Tc_1), ..., Rep(Tc_k)],[]}</c>.</item> + <item>If E is <c>try B of Cc_1 ; ... ; Cc_k catch Tc_1 ; ... ; Tc_n end</c>, + where <c>B</c> is a body, + each <c>Cc_i</c> is a case clause and + each <c>Tc_j</c> is a catch clause then Rep(E) = + <c>{'try',LINE,Rep(B),[Rep(Cc_1), ..., Rep(Cc_k)],[Rep(Tc_1), ..., Rep(Tc_n)],[]}</c>.</item> + <item>If E is <c>try B after A end</c>, + where <c>B</c> and <c>A</c> are bodies then Rep(E) = + <c>{'try',LINE,Rep(B),[],[],Rep(A)}</c>.</item> + <item>If E is <c>try B of Cc_1 ; ... ; Cc_k after A end</c>, + where <c>B</c> and <c>A</c> are a bodies and + each <c>Cc_i</c> is a case clause then Rep(E) = + <c>{'try',LINE,Rep(B),[Rep(Cc_1), ..., Rep(Cc_k)],[],Rep(A)}</c>.</item> + <item>If E is <c>try B catch Tc_1 ; ... ; Tc_k after A end</c>, + where <c>B</c> and <c>A</c> are bodies and + each <c>Tc_i</c> is a catch clause then Rep(E) = + <c>{'try',LINE,Rep(B),[],[Rep(Tc_1), ..., Rep(Tc_k)],Rep(A)}</c>.</item> + <item>If E is <c>try B of Cc_1 ; ... ; Cc_k catch Tc_1 ; ... ; Tc_n after A end</c>, + where <c>B</c> and <c>A</c> are a bodies, + each <c>Cc_i</c> is a case clause and + each <c>Tc_j</c> is a catch clause then Rep(E) = - <c><![CDATA[{'receive',LINE,[Rep(Cc_1), ..., Rep(Cc_k)],Rep(E_0),Rep(B_t)}]]></c>.</item> - <item>If E is <c><![CDATA[fun Name / Arity]]></c>, then - Rep(E) = <c><![CDATA[{'fun',LINE,{function,Name,Arity}}]]></c>.</item> - <item>If E is <c><![CDATA[fun Module:Name/Arity]]></c>, then - Rep(E) = <c><![CDATA[{'fun',LINE,{function,Rep(Module),Rep(Name),Rep(Arity)}}]]></c>. - (Before the R15 release: Rep(E) = <c><![CDATA[{'fun',LINE,{function,Module,Name,Arity}}]]></c>.)</item> - <item>If E is <c><![CDATA[fun Fc_1 ; ... ; Fc_k end]]></c> - where each <c><![CDATA[Fc_i]]></c> is a function clause then Rep(E) = - <c><![CDATA[{'fun',LINE,{clauses,[Rep(Fc_1), ..., Rep(Fc_k)]}}]]></c>.</item> - <item>If E is <c><![CDATA[fun Name Fc_1 ; ... ; Name Fc_k end]]></c> - where <c><![CDATA[Name]]></c> is a variable and each - <c><![CDATA[Fc_i]]></c> is a function clause then Rep(E) = - <c><![CDATA[{named_fun,LINE,Name,[Rep(Fc_1), ..., Rep(Fc_k)]}]]></c>. + <c>{'try',LINE,Rep(B),[Rep(Cc_1), ..., Rep(Cc_k)],[Rep(Tc_1), ..., Rep(Tc_n)],Rep(A)}</c>.</item> + <item>If E is <c>receive Cc_1 ; ... ; Cc_k end</c>, + where each <c>Cc_i</c> is a case clause then Rep(E) = + <c>{'receive',LINE,[Rep(Cc_1), ..., Rep(Cc_k)]}</c>.</item> + <item>If E is <c>receive Cc_1 ; ... ; Cc_k after E_0 -> B_t end</c>, + where each <c>Cc_i</c> is a case clause, + <c>E_0</c> is an expression and <c>B_t</c> is a body, then Rep(E) = + <c>{'receive',LINE,[Rep(Cc_1), ..., Rep(Cc_k)],Rep(E_0),Rep(B_t)}</c>.</item> + <item>If E is <c>fun Name / Arity</c>, then + Rep(E) = <c>{'fun',LINE,{function,Name,Arity}}</c>.</item> + <item>If E is <c>fun Module:Name/Arity</c>, then Rep(E) = + <c>{'fun',LINE,{function,Rep(Module),Rep(Name),Rep(Arity)}}</c>. + (Before the R15 release: Rep(E) = + <c>{'fun',LINE,{function,Module,Name,Arity}}</c>.)</item> + <item>If E is <c>fun Fc_1 ; ... ; Fc_k end</c> + where each <c>Fc_i</c> is a function clause then Rep(E) = + <c>{'fun',LINE,{clauses,[Rep(Fc_1), ..., Rep(Fc_k)]}}</c>.</item> + <item>If E is <c>fun Name Fc_1 ; ... ; Name Fc_k end</c> + where <c>Name</c> is a variable and each + <c>Fc_i</c> is a function clause then Rep(E) = + <c>{named_fun,LINE,Name,[Rep(Fc_1), ..., Rep(Fc_k)]}</c>. </item> - <item>If E is <c><![CDATA[query [E_0 || W_1, ..., W_k] end]]></c>, - where each <c><![CDATA[W_i]]></c> is a generator or a filter, then - Rep(E) = <c><![CDATA[{'query',LINE,{lc,LINE,Rep(E_0),[Rep(W_1), ..., Rep(W_k)]}}]]></c>. - For Rep(W), see below.</item> - <item>If E is <c><![CDATA[E_0.Field]]></c>, a Mnesia record access - inside a query, then - Rep(E) = <c><![CDATA[{record_field,LINE,Rep(E_0),Rep(Field)}]]></c>.</item> - <item>If E is <c><![CDATA[( E_0 )]]></c>, then - Rep(E) = <c><![CDATA[Rep(E_0)]]></c>, - i.e., parenthesized expressions cannot be distinguished from their bodies.</item> + <item>If E is <c>( E_0 )</c>, then + Rep(E) = <c>Rep(E_0)</c>, that is, parenthesized + expressions cannot be distinguished from their bodies.</item> </list> <section> - <title>Generators and filters</title> - <p>When W is a generator or a filter (in the body of a list or binary comprehension), then:</p> + <title>Generators and Filters</title> + <p>When W is a generator or a filter (in the body of a list or + binary comprehension), then:</p> <list type="bulleted"> - <item>If W is a generator <c><![CDATA[P <- E]]></c>, where <c><![CDATA[P]]></c> is a pattern and <c><![CDATA[E]]></c> - is an expression, then - Rep(W) = <c><![CDATA[{generate,LINE,Rep(P),Rep(E)}]]></c>.</item> - <item>If W is a generator <c><![CDATA[P <= E]]></c>, where <c><![CDATA[P]]></c> is a pattern and <c><![CDATA[E]]></c> - is an expression, then - Rep(W) = <c><![CDATA[{b_generate,LINE,Rep(P),Rep(E)}]]></c>.</item> - <item>If W is a filter <c><![CDATA[E]]></c>, which is an expression, then - Rep(W) = <c><![CDATA[Rep(E)]]></c>.</item> + <item>If W is a generator <c>P <- E</c>, where <c>P</c> is + a pattern and <c>E</c> is an expression, then + Rep(W) = <c>{generate,LINE,Rep(P),Rep(E)}</c>.</item> + <item>If W is a generator <c>P <= E</c>, where <c>P</c> is + a pattern and <c>E</c> is an expression, then + Rep(W) = <c>{b_generate,LINE,Rep(P),Rep(E)}</c>.</item> + <item>If W is a filter <c>E</c>, which is an expression, then + Rep(W) = <c>Rep(E)</c>.</item> </list> </section> <section> - <title>Binary element type specifiers</title> + <title>Binary Element Type Specifiers</title> <p>A type specifier list TSL for a binary element is a sequence of type - specifiers <c><![CDATA[TS_1 - ... - TS_k]]></c>. - Rep(TSL) = <c><![CDATA[[Rep(TS_1), ..., Rep(TS_k)]]]></c>.</p> + specifiers <c>TS_1 - ... - TS_k</c>. + Rep(TSL) = <c>[Rep(TS_1), ..., Rep(TS_k)]</c>.</p> <p>When TS is a type specifier for a binary element, then:</p> <list type="bulleted"> - <item>If TS is an atom <c><![CDATA[A]]></c>, Rep(TS) = <c><![CDATA[A]]></c>.</item> - <item>If TS is a couple <c><![CDATA[A:Value]]></c> where <c><![CDATA[A]]></c> is an atom and <c><![CDATA[Value]]></c> - is an integer, Rep(TS) = <c><![CDATA[{A, Value}]]></c>.</item> + <item>If TS is an atom <c>A</c>, then Rep(TS) = <c>A</c>.</item> + <item>If TS is a couple <c>A:Value</c> where <c>A</c> is an atom + and <c>Value</c> is an integer, then Rep(TS) = + <c>{A,Value}</c>.</item> </list> </section> <section> - <title>Map assoc and exact fields</title> + <title>Map Assoc and Exact Fields</title> <p>When W is an assoc or exact field (in the body of a map), then:</p> <list type="bulleted"> - <item>If W is an assoc field <c><![CDATA[K => V]]></c>, where - <c><![CDATA[K]]></c> and <c><![CDATA[V]]></c> are both expressions, - then Rep(W) = <c><![CDATA[{map_field_assoc,LINE,Rep(K),Rep(V)}]]></c>. + <item>If W is an assoc field <c>K => V</c>, where + <c>K</c> and <c>V</c> are both expressions, + then Rep(W) = <c>{map_field_assoc,LINE,Rep(K),Rep(V)}</c>. </item> - <item>If W is an exact field <c><![CDATA[K := V]]></c>, where - <c><![CDATA[K]]></c> and <c><![CDATA[V]]></c> are both expressions, - then Rep(W) = <c><![CDATA[{map_field_exact,LINE,Rep(K),Rep(V)}]]></c>. + <item>If W is an exact field <c>K := V</c>, where + <c>K</c> and <c>V</c> are both expressions, + then Rep(W) = <c>{map_field_exact,LINE,Rep(K),Rep(V)}</c>. </item> </list> </section> @@ -520,112 +394,220 @@ <section> <title>Clauses</title> - <p>There are function clauses, if clauses, case clauses + <p>There are function clauses, if clauses, case clauses and catch clauses.</p> - <p>A clause <c><![CDATA[C]]></c> is one of the following alternatives:</p> + <p>A clause <c>C</c> is one of the following alternatives:</p> <list type="bulleted"> - <item>If C is a function clause <c><![CDATA[( Ps ) -> B]]></c> - where <c><![CDATA[Ps]]></c> is a pattern sequence and <c><![CDATA[B]]></c> is a body, then - Rep(C) = <c><![CDATA[{clause,LINE,Rep(Ps),[],Rep(B)}]]></c>.</item> - <item>If C is a function clause <c><![CDATA[( Ps ) when Gs -> B]]></c> - where <c><![CDATA[Ps]]></c> is a pattern sequence, - <c><![CDATA[Gs]]></c> is a guard sequence and <c><![CDATA[B]]></c> is a body, then - Rep(C) = <c><![CDATA[{clause,LINE,Rep(Ps),Rep(Gs),Rep(B)}]]></c>.</item> - <item>If C is an if clause <c><![CDATA[Gs -> B]]></c> - where <c><![CDATA[Gs]]></c> is a guard sequence and <c><![CDATA[B]]></c> is a body, then - Rep(C) = <c><![CDATA[{clause,LINE,[],Rep(Gs),Rep(B)}]]></c>.</item> - <item>If C is a case clause <c><![CDATA[P -> B]]></c> - where <c><![CDATA[P]]></c> is a pattern and <c><![CDATA[B]]></c> is a body, then - Rep(C) = <c><![CDATA[{clause,LINE,[Rep(P)],[],Rep(B)}]]></c>.</item> - <item>If C is a case clause <c><![CDATA[P when Gs -> B]]></c> - where <c><![CDATA[P]]></c> is a pattern, - <c><![CDATA[Gs]]></c> is a guard sequence and <c><![CDATA[B]]></c> is a body, then - Rep(C) = <c><![CDATA[{clause,LINE,[Rep(P)],Rep(Gs),Rep(B)}]]></c>.</item> - <item>If C is a catch clause <c><![CDATA[P -> B]]></c> - where <c><![CDATA[P]]></c> is a pattern and <c><![CDATA[B]]></c> is a body, then - Rep(C) = <c><![CDATA[{clause,LINE,[Rep({throw,P,_})],[],Rep(B)}]]></c>.</item> - <item>If C is a catch clause <c><![CDATA[X : P -> B]]></c> - where <c><![CDATA[X]]></c> is an atomic literal or a variable pattern, - <c><![CDATA[P]]></c> is a pattern and <c><![CDATA[B]]></c> is a body, then - Rep(C) = <c><![CDATA[{clause,LINE,[Rep({X,P,_})],[],Rep(B)}]]></c>.</item> - <item>If C is a catch clause <c><![CDATA[P when Gs -> B]]></c> - where <c><![CDATA[P]]></c> is a pattern, <c><![CDATA[Gs]]></c> is a guard sequence - and <c><![CDATA[B]]></c> is a body, then - Rep(C) = <c><![CDATA[{clause,LINE,[Rep({throw,P,_})],Rep(Gs),Rep(B)}]]></c>.</item> - <item>If C is a catch clause <c><![CDATA[X : P when Gs -> B]]></c> - where <c><![CDATA[X]]></c> is an atomic literal or a variable pattern, - <c><![CDATA[P]]></c> is a pattern, <c><![CDATA[Gs]]></c> is a guard sequence - and <c><![CDATA[B]]></c> is a body, then - Rep(C) = <c><![CDATA[{clause,LINE,[Rep({X,P,_})],Rep(Gs),Rep(B)}]]></c>.</item> + <item>If C is a function clause <c>( Ps ) -> B</c> + where <c>Ps</c> is a pattern sequence and <c>B</c> is a body, then + Rep(C) = <c>{clause,LINE,Rep(Ps),[],Rep(B)}</c>.</item> + <item>If C is a function clause <c>( Ps ) when Gs -> B</c> + where <c>Ps</c> is a pattern sequence, + <c>Gs</c> is a guard sequence and <c>B</c> is a body, then + Rep(C) = <c>{clause,LINE,Rep(Ps),Rep(Gs),Rep(B)}</c>.</item> + <item>If C is an if clause <c>Gs -> B</c> + where <c>Gs</c> is a guard sequence and <c>B</c> is a body, then + Rep(C) = <c>{clause,LINE,[],Rep(Gs),Rep(B)}</c>.</item> + <item>If C is a case clause <c>P -> B</c> + where <c>P</c> is a pattern and <c>B</c> is a body, then + Rep(C) = <c>{clause,LINE,[Rep(P)],[],Rep(B)}</c>.</item> + <item>If C is a case clause <c>P when Gs -> B</c> + where <c>P</c> is a pattern, + <c>Gs</c> is a guard sequence and <c>B</c> is a body, then + Rep(C) = <c>{clause,LINE,[Rep(P)],Rep(Gs),Rep(B)}</c>.</item> + <item>If C is a catch clause <c>P -> B</c> + where <c>P</c> is a pattern and <c>B</c> is a body, then + Rep(C) = <c>{clause,LINE,[Rep({throw,P,_})],[],Rep(B)}</c>.</item> + <item>If C is a catch clause <c>X : P -> B</c> + where <c>X</c> is an atomic literal or a variable pattern, + <c>P</c> is a pattern and <c>B</c> is a body, then + Rep(C) = <c>{clause,LINE,[Rep({X,P,_})],[],Rep(B)}</c>.</item> + <item>If C is a catch clause <c>P when Gs -> B</c> + where <c>P</c> is a pattern, <c>Gs</c> is a guard sequence + and <c>B</c> is a body, then + Rep(C) = <c>{clause,LINE,[Rep({throw,P,_})],Rep(Gs),Rep(B)}</c>.</item> + <item>If C is a catch clause <c>X : P when Gs -> B</c> + where <c>X</c> is an atomic literal or a variable pattern, + <c>P</c> is a pattern, <c>Gs</c> is a guard sequence + and <c>B</c> is a body, then + Rep(C) = <c>{clause,LINE,[Rep({X,P,_})],Rep(Gs),Rep(B)}</c>.</item> </list> </section> <section> <title>Guards</title> - <p>A guard sequence Gs is a sequence of guards <c><![CDATA[G_1; ...; G_k]]></c>, and - Rep(Gs) = <c><![CDATA[[Rep(G_1), ..., Rep(G_k)]]]></c>. If the guard sequence is - empty, Rep(Gs) = <c><![CDATA[[]]]></c>.</p> - <p>A guard G is a nonempty sequence of guard tests <c><![CDATA[Gt_1, ..., Gt_k]]></c>, and - Rep(G) = <c><![CDATA[[Rep(Gt_1), ..., Rep(Gt_k)]]]></c>.</p> - <p>A guard test <c><![CDATA[Gt]]></c> is one of the following alternatives:</p> + <p>A guard sequence Gs is a sequence of guards <c>G_1; ...; G_k</c>, and + Rep(Gs) = <c>[Rep(G_1), ..., Rep(G_k)]</c>. If the guard sequence is + empty, Rep(Gs) = <c>[]</c>.</p> + <p>A guard G is a nonempty sequence of guard tests + <c>Gt_1, ..., Gt_k</c>, and Rep(G) = + <c>[Rep(Gt_1), ..., Rep(Gt_k)]</c>.</p> + <p>A guard test <c>Gt</c> is one of the following alternatives:</p> <list type="bulleted"> <item>If Gt is an atomic literal L, then Rep(Gt) = Rep(L).</item> - <item>If Gt is a variable pattern <c><![CDATA[V]]></c>, then - Rep(Gt) = <c><![CDATA[{var,LINE,A}]]></c>, - where A is an atom with a printname consisting of the same characters as - <c><![CDATA[V]]></c>.</item> - <item>If Gt is a tuple skeleton <c><![CDATA[{Gt_1, ..., Gt_k}]]></c>, then - Rep(Gt) = <c><![CDATA[{tuple,LINE,[Rep(Gt_1), ..., Rep(Gt_k)]}]]></c>.</item> - <item>If Gt is <c><![CDATA[[]]]></c>, then - Rep(Gt) = <c><![CDATA[{nil,LINE}]]></c>.</item> - <item>If Gt is a cons skeleton <c><![CDATA[[Gt_h | Gt_t]]]></c>, then - Rep(Gt) = <c><![CDATA[{cons,LINE,Rep(Gt_h),Rep(Gt_t)}]]></c>.</item> - <item>If Gt is a binary constructor <c><![CDATA[<<Gt_1:Size_1/TSL_1, ..., Gt_k:Size_k/TSL_k>>]]></c>, then - Rep(Gt) = <c><![CDATA[{bin,LINE,[{bin_element,LINE,Rep(Gt_1),Rep(Size_1),Rep(TSL_1)}, ..., {bin_element,LINE,Rep(Gt_k),Rep(Size_k),Rep(TSL_k)}]}]]></c>. + <item>If Gt is a variable pattern <c>V</c>, then + Rep(Gt) = <c>{var,LINE,A}</c>, where A is an atom with + a printname consisting of the same characters as <c>V</c>.</item> + <item>If Gt is a tuple skeleton <c>{Gt_1, ..., Gt_k}</c>, then + Rep(Gt) = <c>{tuple,LINE,[Rep(Gt_1), ..., Rep(Gt_k)]}</c>.</item> + <item>If Gt is <c>[]</c>, then Rep(Gt) = <c>{nil,LINE}</c>.</item> + <item>If Gt is a cons skeleton <c>[Gt_h | Gt_t]</c>, then + Rep(Gt) = <c>{cons,LINE,Rep(Gt_h),Rep(Gt_t)}</c>.</item> + <item>If Gt is a binary constructor + <c><<Gt_1:Size_1/TSL_1, ..., Gt_k:Size_k/TSL_k>></c>, then + Rep(Gt) = <c>{bin,LINE,[{bin_element,LINE,Rep(Gt_1),Rep(Size_1),Rep(TSL_1)}, ..., {bin_element,LINE,Rep(Gt_k),Rep(Size_k),Rep(TSL_k)}]}</c>. For Rep(TSL), see above. - An omitted <c><![CDATA[Size]]></c> is represented by <c><![CDATA[default]]></c>. An omitted <c><![CDATA[TSL]]></c> - (type specifier list) is represented by <c><![CDATA[default]]></c>.</item> - <item>If Gt is <c><![CDATA[Gt_1 Op Gt_2]]></c>, where <c><![CDATA[Op]]></c> - is a binary operator, then Rep(Gt) = <c><![CDATA[{op,LINE,Op,Rep(Gt_1),Rep(Gt_2)}]]></c>.</item> - <item>If Gt is <c><![CDATA[Op Gt_0]]></c>, where <c><![CDATA[Op]]></c> is a unary operator, then - Rep(Gt) = <c><![CDATA[{op,LINE,Op,Rep(Gt_0)}]]></c>.</item> - <item>If Gt is <c><![CDATA[#Name{Field_1=Gt_1, ..., Field_k=Gt_k}]]></c>, then + An omitted <c>Size</c> is represented by <c>default</c>. + An omitted <c>TSL</c> (type specifier list) is represented + by <c>default</c>.</item> + <item>If Gt is <c>Gt_1 Op Gt_2</c>, where <c>Op</c> + is a binary operator, then Rep(Gt) = + <c>{op,LINE,Op,Rep(Gt_1),Rep(Gt_2)}</c>.</item> + <item>If Gt is <c>Op Gt_0</c>, where <c>Op</c> is a unary operator, then + Rep(Gt) = <c>{op,LINE,Op,Rep(Gt_0)}</c>.</item> + <item>If Gt is <c>#Name{Field_1=Gt_1, ..., Field_k=Gt_k}</c>, then Rep(E) = - <c><![CDATA[{record,LINE,Name, [{record_field,LINE,Rep(Field_1),Rep(Gt_1)}, ..., {record_field,LINE,Rep(Field_k),Rep(Gt_k)}]}]]></c>.</item> - <item>If Gt is <c><![CDATA[#Name.Field]]></c>, then - Rep(Gt) = <c><![CDATA[{record_index,LINE,Name,Rep(Field)}]]></c>.</item> - <item>If Gt is <c><![CDATA[Gt_0#Name.Field]]></c>, then - Rep(Gt) = <c><![CDATA[{record_field,LINE,Rep(Gt_0),Name,Rep(Field)}]]></c>.</item> - <item>If Gt is <c><![CDATA[A(Gt_1, ..., Gt_k)]]></c>, where <c><![CDATA[A]]></c> is an atom, then - Rep(Gt) = <c><![CDATA[{call,LINE,Rep(A),[Rep(Gt_1), ..., Rep(Gt_k)]}]]></c>.</item> - <item>If Gt is <c><![CDATA[A_m:A(Gt_1, ..., Gt_k)]]></c>, where <c><![CDATA[A_m]]></c> is - the atom <c><![CDATA[erlang]]></c> and <c><![CDATA[A]]></c> is an atom or an operator, then - Rep(Gt) = <c><![CDATA[{call,LINE,{remote,LINE,Rep(A_m),Rep(A)},[Rep(Gt_1), ..., Rep(Gt_k)]}]]></c>.</item> - <item>If Gt is <c><![CDATA[{A_m,A}(Gt_1, ..., Gt_k)]]></c>, where <c><![CDATA[A_m]]></c> is - the atom <c><![CDATA[erlang]]></c> and <c><![CDATA[A]]></c> is an atom or an operator, then - Rep(Gt) = <c><![CDATA[{call,LINE,Rep({A_m,A}),[Rep(Gt_1), ..., Rep(Gt_k)]}]]></c>.</item> - <item>If Gt is <c><![CDATA[( Gt_0 )]]></c>, then - Rep(Gt) = <c><![CDATA[Rep(Gt_0)]]></c>, - i.e., parenthesized guard tests cannot be distinguished from their bodies.</item> + <c>{record,LINE,Name,[{record_field,LINE,Rep(Field_1),Rep(Gt_1)}, ..., {record_field,LINE,Rep(Field_k),Rep(Gt_k)}]}</c>.</item> + <item>If Gt is <c>#Name.Field</c>, then + Rep(Gt) = <c>{record_index,LINE,Name,Rep(Field)}</c>.</item> + <item>If Gt is <c>Gt_0#Name.Field</c>, then + Rep(Gt) = <c>{record_field,LINE,Rep(Gt_0),Name,Rep(Field)}</c>.</item> + <item>If Gt is <c>A(Gt_1, ..., Gt_k)</c>, where <c>A</c> is an atom, then + Rep(Gt) = <c>{call,LINE,Rep(A),[Rep(Gt_1), ..., Rep(Gt_k)]}</c>.</item> + <item>If Gt is <c>A_m:A(Gt_1, ..., Gt_k)</c>, where <c>A_m</c> is + the atom <c>erlang</c> and <c>A</c> is an atom or an operator, then + Rep(Gt) = <c>{call,LINE,{remote,LINE,Rep(A_m),Rep(A)},[Rep(Gt_1), ..., Rep(Gt_k)]}</c>.</item> + <item>If Gt is <c>{A_m,A}(Gt_1, ..., Gt_k)</c>, where <c>A_m</c> is + the atom <c>erlang</c> and <c>A</c> is an atom or an operator, then + Rep(Gt) = <c>{call,LINE,Rep({A_m,A}),[Rep(Gt_1), ..., Rep(Gt_k)]}</c>. + </item> + <item>If Gt is <c>( Gt_0 )</c>, then + Rep(Gt) = <c>Rep(Gt_0)</c>, that is, parenthesized + guard tests cannot be distinguished from their bodies.</item> </list> <p>Note that every guard test has the same source form as some expression, and is represented the same way as the corresponding expression.</p> </section> <section> - <title>The abstract format after preprocessing</title> - <p>The compilation option <c><![CDATA[debug_info]]></c> can be given to the - compiler to have the abstract code stored in - the <c><![CDATA[abstract_code]]></c> chunk in the BEAM file + <title>Types</title> + <list type="bulleted"> + <item>If T is an annotated type <c>Anno :: Type</c>, + where <c>Anno</c> is a variable and + <c>Type</c> is a type, then Rep(T) = + <c>{ann_type,LINE,[Rep(Anno),Rep(Type)]}</c>.</item> + <item>If T is an atom or integer literal L, then Rep(T) = Rep(L). + </item> + <item>If T is <c>L Op R</c>, + where <c>Op</c> is a binary operator and <c>L</c> and <c>R</c> + are types (this is an occurrence of an expression that can be + evaluated to an integer at compile time), then + Rep(T) = <c>{op,LINE,Op,Rep(L),Rep(R)}</c>.</item> + <item>If T is <c>Op A</c>, where <c>Op</c> is a + unary operator and <c>A</c> is a type (this is an occurrence of + an expression that can be evaluated to an integer at compile time), + then Rep(T) = <c>{op,LINE,Op,Rep(A)}</c>.</item> + <item>If T is a bitstring type <c><<_:M,_:_*N>></c>, + where <c>M</c> and <c>N</c> are singleton integer types, then Rep(T) = + <c>{type,LINE,binary,[Rep(M),Rep(N)]}</c>.</item> + <item>If T is the empty list type <c>[]</c>, then Rep(T) = + <c>{type,Line,nil,[]}</c>.</item> + <item>If T is a fun type <c>fun()</c>, then Rep(T) = + <c>{type,LINE,'fun',[]}</c>.</item> + <item>If T is a fun type <c>fun((...) -> B)</c>, + where <c>B</c> is a type, then + Rep(T) = <c>{type,LINE,'fun',[{type,LINE,any},Rep(B)]}</c>. + </item> + <item>If T is a fun type <c>fun(Ft)</c>, where + <c>Ft</c> is a function type, + then Rep(T) = <c>Rep(Ft)</c>.</item> + <item>If T is an integer range type <c>L .. H</c>, + where <c>L</c> and <c>H</c> are singleton integer types, then + Rep(T) = <c>{type,LINE,range,[Rep(L),Rep(H)]}</c>.</item> + <item>If T is a map type <c>map()</c>, then Rep(T) = + <c>{type,LINE,map,any}</c>.</item> + <item>If T is a map type <c>#{P_1, ..., P_k}</c>, where each + <c>P_i</c> is a map pair type, then Rep(T) = + <c>{type,LINE,map,[Rep(P_1), ..., Rep(P_k)]}</c>.</item> + <item>If T is a map pair type <c>K => V</c>, where + <c>K</c> and <c>V</c> are types, then Rep(T) = + <c>{type,LINE,map_field_assoc,[Rep(K),Rep(V)]}</c>.</item> + <item>If T is a predefined (or built-in) type <c>N(A_1, ..., A_k)</c>, + where each <c>A_i</c> is a type, then Rep(T) = + <c>{type,LINE,N,[Rep(A_1), ..., Rep(A_k)]}</c>.</item> + <item>If T is a record type <c>#Name{F_1, ..., F_k}</c>, + where each <c>F_i</c> is a record field type, then Rep(T) = + <c>{type,LINE,record,[Rep(Name),Rep(F_1), ..., Rep(F_k)]}</c>. + </item> + <item>If T is a record field type <c>Name :: Type</c>, + where <c>Type</c> is a type, then Rep(T) = + <c>{type,LINE,field_type,[Rep(Name),Rep(Type)]}</c>.</item> + <item>If T is a remote type <c>M:N(A_1, ..., A_k)</c>, where + each <c>A_i</c> is a type, then Rep(T) = + <c>{remote_type,LINE,[Rep(M),Rep(N),[Rep(A_1), ..., Rep(A_k)]]}</c>. + </item> + <item>If T is a tuple type <c>tuple()</c>, then Rep(T) = + <c>{type,LINE,tuple,any}</c>.</item> + <item>If T is a tuple type <c>{A_1, ..., A_k}</c>, where + each <c>A_i</c> is a type, then Rep(T) = + <c>{type,LINE,tuple,[Rep(A_1), ..., Rep(A_k)]}</c>.</item> + <item>If T is a type union <c>T_1 | ... | T_k</c>, + where each <c>T_i</c> is a type, then Rep(T) = + <c>{type,LINE,union,[Rep(T_1), ..., Rep(T_k)]}</c>.</item> + <item>If T is a type variable <c>V</c>, then Rep(T) = + <c>{var,LINE,A}</c>, where <c>A</c> is an atom with a printname + consisting of the same characters as <c>V</c>. A type variable + is any variable except underscore (<c>_</c>).</item> + <item>If T is a user-defined type <c>N(A_1, ..., A_k)</c>, + where each <c>A_i</c> is a type, then Rep(T) = + <c>{user_type,LINE,N,[Rep(A_1), ..., Rep(A_k)]}</c>.</item> + <item>If T is <c>( T_0 )</c>, then Rep(T) = <c>Rep(T_0)</c>, + that is, parenthesized types cannot be distinguished from their + bodies.</item> + </list> + + <section> + <title>Function Types</title> + <list type="bulleted"> + <item>If Ft is a constrained function type <c>Ft_1 when Fc</c>, + where <c>Ft_1</c> is a function type and + <c>Fc</c> is a function constraint, then Rep(T) = + <c>{type,LINE,bounded_fun,[Rep(Ft_1),Rep(Fc)]}</c>.</item> + <item>If Ft is a function type <c>(A_1, ..., A_n) -> B</c>, + where each <c>A_i</c> and <c>B</c> are types, then + Rep(Ft) = <c>{type,LINE,'fun',[{type,LINE,product,[Rep(A_1), + ..., Rep(A_n)]},Rep(B)]}</c>.</item> + </list> + </section> + + <section> + <title>Function Constraints</title> + <p>A function constraint Fc is a nonempty sequence of constraints + <c>C_1, ..., C_k</c>, and + Rep(Fc) = <c>[Rep(C_1), ..., Rep(C_k)]</c>.</p> + <list type="bulleted"> + <item>If C is a constraint <c>is_subtype(V, T)</c> or <c>V :: T</c>, + where <c>V</c> is a type variable and <c>T</c> is a type, then + Rep(C) = <c>{type,LINE,constraint,[{atom,LINE,is_subtype},[Rep(V),Rep(T)]]}</c>. + </item> + </list> + </section> + </section> + + <section> + <title>The Abstract Format After Preprocessing</title> + <p>The compilation option <c>debug_info</c> can be given to the + compiler to have the abstract code stored in + the <c>abstract_code</c> chunk in the BEAM file (for debugging purposes).</p> - <p>In OTP R9C and later, the <c><![CDATA[abstract_code]]></c> chunk will + <p>In OTP R9C and later, the <c>abstract_code</c> chunk will contain</p> - <p><c><![CDATA[{raw_abstract_v1,AbstractCode}]]></c></p> - <p>where <c><![CDATA[AbstractCode]]></c> is the abstract code as described + <p><c>{raw_abstract_v1,AbstractCode}</c></p> + <p>where <c>AbstractCode</c> is the abstract code as described in this document.</p> <p>In releases of OTP prior to R9C, the abstract code after some more processing was stored in the BEAM file. The first element of the - tuple would be either <c><![CDATA[abstract_v1]]></c> (R7B) or <c><![CDATA[abstract_v2]]></c> + tuple would be either <c>abstract_v1</c> (R7B) or <c>abstract_v2</c> (R8B).</p> </section> </chapter> diff --git a/erts/doc/src/driver_entry.xml b/erts/doc/src/driver_entry.xml index 30772c68fe..bad20d6343 100644 --- a/erts/doc/src/driver_entry.xml +++ b/erts/doc/src/driver_entry.xml @@ -4,7 +4,7 @@ <cref> <header> <copyright> - <year>2001</year><year>2013</year> + <year>2001</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -126,7 +126,7 @@ <section> <title>DATA TYPES</title> <taglist> - <tag><b>ErlDrvEntry</b></tag> + <tag><em>ErlDrvEntry</em></tag> <item> <p/> <code type="none"> @@ -235,6 +235,7 @@ typedef struct erl_drv_entry { </item> <tag><marker id="ready_input"/>void (*ready_input)(ErlDrvData drv_data, ErlDrvEvent event)</tag> + <item/> <tag><marker id="ready_output"/>void (*ready_output)(ErlDrvData drv_data, ErlDrvEvent event)</tag> <item> <p>This is called when a driver event (given in the diff --git a/erts/doc/src/epmd.xml b/erts/doc/src/epmd.xml index 28fcc8f7af..7f61804bea 100644 --- a/erts/doc/src/epmd.xml +++ b/erts/doc/src/epmd.xml @@ -37,7 +37,7 @@ <comsummary> <p>Erlang Port Mapper Daemon</p> <taglist> - <tag><c><![CDATA[epmd [-d|-debug] [DbgExtra...] [-port No] [-daemon] [-relaxed_command_check]]]></c></tag> + <tag><c><![CDATA[epmd [-d|-debug] [DbgExtra...] [-address Addresses] [-port No] [-daemon] [-relaxed_command_check]]]></c></tag> <item> <p>Starts the port mapper daemon</p> </item> diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml index b0322b7d43..ed3e7e34c4 100644 --- a/erts/doc/src/erl.xml +++ b/erts/doc/src/erl.xml @@ -4,7 +4,7 @@ <comref> <header> <copyright> - <year>1996</year><year>2013</year> + <year>1996</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -138,7 +138,7 @@ see <seealso marker="kernel:app">app(4)</seealso> and <seealso marker="kernel:application">application(3)</seealso>.</p> </item> - <tag><marker id="args_file"><c><![CDATA[-args_file FileName]]></c></marker></tag> + <tag><marker id="args_file"/><c><![CDATA[-args_file FileName]]></c></tag> <item> <p>Command line arguments are read from the file <c><![CDATA[FileName]]></c>. The arguments read from the file replace the @@ -203,7 +203,7 @@ <seealso marker="kernel:app">app(4)</seealso> and <seealso marker="kernel:application">application(3)</seealso>.</p> </item> - <tag><marker id="connect_all"><c><![CDATA[-connect_all false]]></c></marker></tag> + <tag><marker id="connect_all"/><c><![CDATA[-connect_all false]]></c></tag> <item> <p>If this flag is present, <c><![CDATA[global]]></c> will not maintain a fully connected network of distributed Erlang nodes, and then @@ -288,7 +288,7 @@ <p>Makes <c><![CDATA[init]]></c> write some debug information while interpreting the boot script.</p> </item> - <tag><marker id="instr"><c><![CDATA[-instr]]></c>(emulator flag)</marker></tag> + <tag><marker id="instr"/><c><![CDATA[-instr]]></c>(emulator flag)</tag> <item> <p>Selects an instrumented Erlang runtime system (virtual machine) to run, instead of the ordinary one. When running an @@ -371,7 +371,7 @@ path, similar to <c><![CDATA[code:add_pathsa/1]]></c>. See <seealso marker="kernel:code">code(3)</seealso>. As an alternative to <c>-pa</c>, if several directories are - to be prepended to the code and the directories have a + to be prepended to the code path and the directories have a common parent directory, that parent directory could be specified in the <c>ERL_LIBS</c> environment variable. See <seealso marker="kernel:code">code(3)</seealso>.</p> @@ -382,6 +382,33 @@ similar to <c><![CDATA[code:add_pathsz/1]]></c>. See <seealso marker="kernel:code">code(3)</seealso>.</p> </item> + <tag><c><![CDATA[-path Dir1 Dir2 ...]]></c></tag> + <item> + <p>Replaces the path specified in the boot script. See + <seealso marker="sasl:script">script(4)</seealso>.</p> + </item> + <tag><c><![CDATA[-proto_dist Proto]]></c></tag> + <item> + <p>Specify a protocol for Erlang distribution.</p> + <taglist> + <tag><c>inet_tcp</c></tag> + <item> + <p>TCP over IPv4 (the default)</p> + </item> + <tag><c>inet_tls</c></tag> + <item> + <p>distribution over TLS/SSL</p> + </item> + <tag><c>inet6_tcp</c></tag> + <item> + <p>TCP over IPv6</p> + </item> + </taglist> + <p>For example, to start up IPv6 distributed nodes:</p> +<pre> +% <input>erl -name [email protected] -proto_dist inet6_tcp</input> +</pre> + </item> <tag><c><![CDATA[-remsh Node]]></c></tag> <item> <p>Starts Erlang with a remote shell connected to <c><![CDATA[Node]]></c>.</p> @@ -436,7 +463,7 @@ flag and those running with the <c><![CDATA[-name]]></c> flag, as node names must be unique in distributed Erlang systems.</p> </item> - <tag><marker id="smp"><c><![CDATA[-smp [enable|auto|disable]]]></c></marker></tag> + <tag><marker id="smp"/><c><![CDATA[-smp [enable|auto|disable]]]></c></tag> <item> <p><c>-smp enable</c> and <c>-smp</c> starts the Erlang runtime system with SMP support enabled. This may fail if no runtime @@ -462,7 +489,7 @@ <p><c><![CDATA[erl]]></c> invokes the code for the Erlang emulator (virtual machine), which supports the following flags:</p> <taglist> - <tag><marker id="async_thread_stack_size"><c><![CDATA[+a size]]></c></marker></tag> + <tag><marker id="async_thread_stack_size"/><c><![CDATA[+a size]]></c></tag> <item> <p>Suggested stack size, in kilowords, for threads in the async-thread pool. Valid range is 16-8192 kilowords. The @@ -477,7 +504,7 @@ suggestion, and it might even be ignored on some platforms.</p> </item> - <tag><marker id="async_thread_pool_size"><c><![CDATA[+A size]]></c></marker></tag> + <tag><marker id="async_thread_pool_size"/><c><![CDATA[+A size]]></c></tag> <item> <p>Sets the number of threads in async thread pool, valid range is 0-1024. If thread support is available, the default is 10.</p> @@ -496,7 +523,7 @@ <c><![CDATA[werl]]></c>, not <c><![CDATA[erl]]></c> (<c><![CDATA[oldshell]]></c>). Note also that <c><![CDATA[Ctrl-Break]]></c> is used instead of <c><![CDATA[Ctrl-C]]></c> on Windows.</p> </item> - <tag><marker id="+c"><c><![CDATA[+c true | false]]></c></marker></tag> + <tag><marker id="+c"/><c><![CDATA[+c true | false]]></c></tag> <item> <p>Enable or disable <seealso marker="time_correction#Time_Correction">time correction</seealso>:</p> @@ -512,7 +539,7 @@ This is interpreted as <c>+c false</c>. </p> </item> - <tag><marker id="+C_"><c><![CDATA[+C no_time_warp | single_time_warp | multi_time_warp]]></c></marker></tag> + <tag><marker id="+C_"/><c><![CDATA[+C no_time_warp | single_time_warp | multi_time_warp]]></c></tag> <item> <p>Set <seealso marker="time_correction#Time_Warp_Modes">time warp mode</seealso>: @@ -540,7 +567,7 @@ produce a crash dump. On Unix systems, sending an emulator process a SIGUSR1 signal will also force a crash dump.</p> </item> - <tag><marker id="+e"><c><![CDATA[+e Number]]></c></marker></tag> + <tag><marker id="+e"/><c><![CDATA[+e Number]]></c></tag> <item> <p>Set max number of ETS tables.</p> </item> @@ -625,7 +652,7 @@ information about the file names and line numbers. </p> </item> - <tag><marker id="erts_alloc"><c><![CDATA[+MFlag Value]]></c></marker></tag> + <tag><marker id="erts_alloc"/><c><![CDATA[+MFlag Value]]></c></tag> <item> <p>Memory allocator specific flags, see <seealso marker="erts_alloc">erts_alloc(3)</seealso> for @@ -664,10 +691,10 @@ debugging.</item> </taglist> </item> - <tag><marker id="+pc"/><marker id="printable_character_range"><c><![CDATA[+pc Range]]></c></marker></tag> + <tag><marker id="+pc"/><marker id="printable_character_range"/><c><![CDATA[+pc Range]]></c></tag> <item> <p>Sets the range of characters that the system will consider printable in heuristic detection of strings. This typically affects the shell, debugger and io:format functions (when ~tp is used in the format string).</p> - <p>Currently two values for the <c>Range</c> are supported: + <p>Currently two values for the <c>Range</c> are supported:</p> <taglist> <tag><c>latin1</c></tag> <item>The default. Only characters in the ISO-latin-1 range can be considered printable, which means @@ -682,11 +709,10 @@ example your font does not cover all Unicode characters.</item> </taglist> - </p> <p>Se also <seealso marker="stdlib:io#printable_range/0"> io:printable_range/0</seealso>.</p> </item> - <tag><marker id="+P"/><marker id="max_processes"><c><![CDATA[+P Number|legacy]]></c></marker></tag> + <tag><marker id="+P"/><marker id="max_processes"/><c><![CDATA[+P Number|legacy]]></c></tag> <item> <p>Sets the maximum number of simultaneously existing processes for this system if a <c>Number</c> is passed as value. Valid range for @@ -706,7 +732,7 @@ circumstances be extremely expensive. The legacy algoritm is deprecated, and the <c>legacy</c> option is scheduled for removal in OTP-R18.</p> </item> - <tag><marker id="+Q"/><marker id="max_ports"><c><![CDATA[+Q Number|legacy]]></c></marker></tag> + <tag><marker id="+Q"/><marker id="max_ports"/><c><![CDATA[+Q Number|legacy]]></c></tag> <item> <p>Sets the maximum number of simultaneously existing ports for this system if a Number is passed as value. Valid range for <c>Number</c> @@ -737,7 +763,7 @@ circumstances be extremely expensive. The legacy algoritm is deprecated, and the <c>legacy</c> option is scheduled for removal in OTP-R18.</p> </item> - <tag><marker id="compat_rel"><c><![CDATA[+R ReleaseNumber]]></c></marker></tag> + <tag><marker id="compat_rel"/><c><![CDATA[+R ReleaseNumber]]></c></tag> <item> <p>Sets the compatibility mode.</p> <p>The distribution mechanism is not backwards compatible by @@ -757,7 +783,7 @@ <item> <p>Force ets memory block to be moved on realloc.</p> </item> - <tag><marker id="+rg"><c><![CDATA[+rg ReaderGroupsLimit]]></c></marker></tag> + <tag><marker id="+rg"/><c><![CDATA[+rg ReaderGroupsLimit]]></c></tag> <item> <p>Limits the amount of reader groups used by read/write locks optimized for read operations in the Erlang runtime system. By @@ -775,7 +801,7 @@ schedulers to logical processors</seealso>, since the reader groups are distributed better between schedulers.</p> </item> - <tag><marker id="+S"><c><![CDATA[+S Schedulers:SchedulerOnline]]></c></marker></tag> + <tag><marker id="+S"/><c><![CDATA[+S Schedulers:SchedulerOnline]]></c></tag> <item> <p>Sets the number of scheduler threads to create and scheduler threads to set online when SMP support has been enabled. The maximum for @@ -800,7 +826,7 @@ SMP support enabled (see the <seealso marker="#smp">-smp</seealso> flag).</p> </item> - <tag><marker id="+SP"><c><![CDATA[+SP SchedulersPercentage:SchedulersOnlinePercentage]]></c></marker></tag> + <tag><marker id="+SP"/><c><![CDATA[+SP SchedulersPercentage:SchedulersOnlinePercentage]]></c></tag> <item> <p>Similar to <seealso marker="#+S">+S</seealso> but uses percentages to set the number of scheduler threads to create, based on logical processors configured, @@ -821,7 +847,7 @@ SMP support enabled (see the <seealso marker="#smp">-smp</seealso> flag).</p> </item> - <tag><marker id="+SDcpu"><c><![CDATA[+SDcpu DirtyCPUSchedulers:DirtyCPUSchedulersOnline]]></c></marker></tag> + <tag><marker id="+SDcpu"/><c><![CDATA[+SDcpu DirtyCPUSchedulers:DirtyCPUSchedulersOnline]]></c></tag> <item> <p>Sets the number of dirty CPU scheduler threads to create and dirty CPU scheduler threads to set online when threading support has been @@ -845,7 +871,7 @@ enabled (it's disabled by default). </p> </item> - <tag><marker id="+SDPcpu"><c><![CDATA[+SDPcpu DirtyCPUSchedulersPercentage:DirtyCPUSchedulersOnlinePercentage]]></c></marker></tag> + <tag><marker id="+SDPcpu"/><c><![CDATA[+SDPcpu DirtyCPUSchedulersPercentage:DirtyCPUSchedulersOnlinePercentage]]></c></tag> <item> <p>Similar to <seealso marker="#+SDcpu">+SDcpu</seealso> but uses percentages to set the number of dirty CPU scheduler threads to create and number of dirty CPU scheduler threads @@ -868,7 +894,7 @@ enabled (it's disabled by default). </p> </item> - <tag><marker id="+SDio"><c><![CDATA[+SDio IOSchedulers]]></c></marker></tag> + <tag><marker id="+SDio"/><c><![CDATA[+SDio IOSchedulers]]></c></tag> <item> <p>Sets the number of dirty I/O scheduler threads to create when threading support has been enabled. The valid range is 0-1024. By default, the number @@ -886,7 +912,7 @@ <item> <p>Scheduling specific flags.</p> <taglist> - <tag><marker id="+sbt"><c>+sbt BindType</c></marker></tag> + <tag><marker id="+sbt"/><c>+sbt BindType</c></tag> <item> <p>Set scheduler bind type.</p> <p>Schedulers can also be bound using the @@ -1010,7 +1036,7 @@ <seealso marker="erlang#system_info_scheduler_bindings">erlang:system_info(scheduler_bindings)</seealso>. </p> </item> - <tag><marker id="+sbwt"><c>+sbwt none|very_short|short|medium|long|very_long</c></marker></tag> + <tag><marker id="+sbwt"/><c>+sbwt none|very_short|short|medium|long|very_long</c></tag> <item> <p>Set scheduler busy wait threshold. Default is <c>medium</c>. The threshold determines how long schedulers should busy @@ -1020,7 +1046,7 @@ without prior notice. </p> </item> - <tag><marker id="+scl"><c>+scl true|false</c></marker></tag> + <tag><marker id="+scl"/><c>+scl true|false</c></tag> <item> <p>Enable or disable scheduler compaction of load. By default scheduler compaction of load is enabled. When enabled, load @@ -1037,7 +1063,7 @@ between schedulers. </p> </item> - <tag><marker id="+sct"><c>+sct CpuTopology</c></marker></tag> + <tag><marker id="+sct"/><c>+sct CpuTopology</c></tag> <item> <list type="bulleted"> <item><c><![CDATA[<Id> = integer(); when 0 =< <Id> =< 65535]]></c></item> @@ -1159,7 +1185,7 @@ <p>For more information, see <seealso marker="erlang#system_info_cpu_topology">erlang:system_info(cpu_topology)</seealso>.</p> </item> - <tag><marker id="+secio"><c>+secio true|false</c></marker></tag> + <tag><marker id="+secio"/><c>+secio true|false</c></tag> <item> <p>Enable or disable eager check I/O scheduling. The default is currently <c>true</c>. The default was changed from <c>false</c> @@ -1176,7 +1202,7 @@ <p><seealso marker="erlang#system_info_eager_check_io"><c>erlang:system_info(eager_check_io)</c></seealso> returns the value of this parameter used when starting the VM.</p> </item> - <tag><marker id="+sfwi"><c>+sfwi Interval</c></marker></tag> + <tag><marker id="+sfwi"/><c>+sfwi Interval</c></tag> <item> <p>Set scheduler forced wakeup interval. All run queues will be scanned each <c>Interval</c> milliseconds. While there are @@ -1185,12 +1211,12 @@ disables this feature, which also is the default. </p> <p>This feature has been introduced as a temporary workaround - for lengthy executing native code, and native code that do not + for long-executing native code, and native code that does not bump reductions properly in OTP. When these bugs have be fixed the <c>+sfwi</c> flag will be removed. </p> </item> - <tag><marker id="+stbt"><c>+stbt BindType</c></marker></tag> + <tag><marker id="+stbt"/><c>+stbt BindType</c></tag> <item> <p>Try to set scheduler bind type. The same as the <seealso marker="#+sbt">+sbt</seealso> flag with the exception of @@ -1198,7 +1224,7 @@ documentation of the <seealso marker="#+sbt">+sbt</seealso> flag. </p> </item> - <tag><marker id="+sub"><c>+sub true|false</c></marker></tag> + <tag><marker id="+sub"/><c>+sub true|false</c></tag> <item> <p>Enable or disable <seealso marker="erts:erlang#statistics_scheduler_wall_time">scheduler @@ -1211,7 +1237,7 @@ balance scheduler utilization between schedulers. That is, strive for equal scheduler utilization on all schedulers. <br/> <c>+sub true</c> is only supported on - systems where the runtime system detects and use a monotonically + systems where the runtime system detects and uses a monotonically increasing high resolution clock. On other systems, the runtime system will fail to start. <br/> <c>+sub true</c> implies @@ -1221,7 +1247,7 @@ utilization. </p> </item> - <tag><marker id="+swct"><c>+swct very_eager|eager|medium|lazy|very_lazy</c></marker></tag> + <tag><marker id="+swct"/><c>+swct very_eager|eager|medium|lazy|very_lazy</c></tag> <item> <p> Set scheduler wake cleanup threshold. Default is <c>medium</c>. @@ -1235,7 +1261,7 @@ <p><em>NOTE:</em> This flag may be removed or changed at any time without prior notice. </p> </item> - <tag><marker id="+sws"><c>+sws default|legacy</c></marker></tag> + <tag><marker id="+sws"/><c>+sws default|legacy</c></tag> <item> <p> Set scheduler wakeup strategy. Default strategy changed in erts-5.10/OTP-R16A. This strategy was previously known as <c>proposal</c> in OTP-R15. The <c>legacy</c> strategy was used as default from R13 up to and including R15. @@ -1243,7 +1269,7 @@ <p><em>NOTE:</em> This flag may be removed or changed at any time without prior notice. </p> </item> - <tag><marker id="+swt"><c>+swt very_low|low|medium|high|very_high</c></marker></tag> + <tag><marker id="+swt"/><c>+swt very_low|low|medium|high|very_high</c></tag> <item> <p>Set scheduler wakeup threshold. Default is <c>medium</c>. The threshold determines when to wake up sleeping schedulers @@ -1257,7 +1283,7 @@ without prior notice. </p> </item> - <tag><marker id="+spp"><c>+spp Bool</c></marker></tag> + <tag><marker id="+spp"/><c>+spp Bool</c></tag> <item> <p>Set default scheduler hint for port parallelism. If set to <c>true</c>, the VM will schedule port tasks when doing so will @@ -1273,7 +1299,7 @@ option to <seealso marker="erlang#open_port/2">open_port/2</seealso></p>. </item> - <tag><marker id="sched_thread_stack_size"><c><![CDATA[+sss size]]></c></marker></tag> + <tag><marker id="sched_thread_stack_size"/><c><![CDATA[+sss size]]></c></tag> <item> <p>Suggested stack size, in kilowords, for scheduler threads. Valid range is 4-8192 kilowords. The default stack size @@ -1281,11 +1307,11 @@ </item> </taglist> </item> - <tag><marker id="+t"><c><![CDATA[+t size]]></c></marker></tag> + <tag><marker id="+t"/><c><![CDATA[+t size]]></c></tag> <item> <p>Set the maximum number of atoms the VM can handle. Default is 1048576.</p> </item> - <tag><marker id="+T"><c><![CDATA[+T Level]]></c></marker></tag> + <tag><marker id="+T"/><c><![CDATA[+T Level]]></c></tag> <item> <p>Enables modified timing and sets the modified timing level. Currently valid range is 0-9. The timing of the runtime system @@ -1339,7 +1365,7 @@ <item> <p>Miscellaneous flags.</p> <taglist> - <tag><marker id="+zdbbl"><c>+zdbbl size</c></marker></tag> + <tag><marker id="+zdbbl"/><c>+zdbbl size</c></tag> <item> <p>Set the distribution buffer busy limit (<seealso marker="erlang#system_info_dist_buf_busy_limit">dist_buf_busy_limit</seealso>) @@ -1352,7 +1378,7 @@ give lower latency and higher throughput at the expense of higher memory usage.</p> </item> - <tag><marker id="+zdntgc"><c>+zdntgc time</c></marker></tag> + <tag><marker id="+zdntgc"/><c>+zdntgc time</c></tag> <item> <p>Set the delayed node table garbage collection time (<seealso marker="erlang#system_info_delayed_node_table_gc">delayed_node_table_gc</seealso>) @@ -1426,7 +1452,7 @@ </item> </taglist> </item> - <tag><marker id="ERL_AFLAGS"><c><![CDATA[ERL_AFLAGS]]></c></marker></tag> + <tag><marker id="ERL_AFLAGS"/><c><![CDATA[ERL_AFLAGS]]></c></tag> <item> <p>The content of this environment variable will be added to the beginning of the command line for <c><![CDATA[erl]]></c>.</p> @@ -1436,7 +1462,7 @@ the <c><![CDATA[-extra]]></c> section, i.e. the end of the command line following after an <c><![CDATA[-extra]]></c> flag.</p> </item> - <tag><marker id="ERL_ZFLAGS"><c><![CDATA[ERL_ZFLAGS]]></c></marker> and <marker id="ERL_FLAGS"><c><![CDATA[ERL_FLAGS]]></c></marker></tag> + <tag><marker id="ERL_ZFLAGS"/><c><![CDATA[ERL_ZFLAGS]]></c> and <marker id="ERL_FLAGS"/><c><![CDATA[ERL_FLAGS]]></c></tag> <item> <p>The content of these environment variables will be added to the end of the command line for <c><![CDATA[erl]]></c>.</p> diff --git a/erts/doc/src/erl_dist_protocol.xml b/erts/doc/src/erl_dist_protocol.xml index e1a58856f3..b435d5c9b4 100644 --- a/erts/doc/src/erl_dist_protocol.xml +++ b/erts/doc/src/erl_dist_protocol.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>2007</year> - <year>2013</year> + <year>2015</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> @@ -549,10 +549,10 @@ If Result > 0, the packet only consists of [119, Result]. --> </section> - <marker id="distribution_handshake"/> <section> <title>Distribution Handshake</title> <p> + <marker id="distribution_handshake"/> This section describes the distribution handshake protocol introduced in the OTP-R6 release of Erlang/OTP. This description was previously located in diff --git a/erts/doc/src/erl_driver.xml b/erts/doc/src/erl_driver.xml index 1f7fe0f961..34dc8af238 100644 --- a/erts/doc/src/erl_driver.xml +++ b/erts/doc/src/erl_driver.xml @@ -4,7 +4,7 @@ <cref> <header> <copyright> - <year>2001</year><year>2014</year> + <year>2001</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -223,7 +223,7 @@ asynchronous function calls, using a thread pool provided by Erlang. There is also a select call, that can be used for asynchronous drivers.</item> - <tag><marker id="multi_threading">Multi-threading</marker></tag> + <tag><marker id="multi_threading"/>Multi-threading</tag> <item> <p>A POSIX thread like API for multi-threading is provided. The Erlang driver thread API only provide a subset of the functionality @@ -297,7 +297,7 @@ <item><p>A driver can add and later remove drivers.</p></item> <tag>Monitoring processes</tag> <item><p>A driver can monitor a process that does not own a port.</p></item> - <tag><marker id="version_management">Version management</marker></tag> + <tag><marker id="version_management"/>Version management</tag> <item> <p>Version management is enabled for drivers that have set the <seealso marker="driver_entry#extended_marker">extended_marker</seealso> @@ -347,6 +347,16 @@ the driver does not handle sizes that overflow an <c>int</c> all will work as before.</p> </item> + <tag><marker id="time_measurement"/>Time Measurement</tag> + <item><p>Support for time measurement in drivers: + <list> + <item><seealso marker="#ErlDrvTime"><c>ErlDrvTime</c></seealso></item> + <item><seealso marker="#ErlDrvTimeUnit"><c>ErlDrvTimeUnit</c></seealso></item> + <item><seealso marker="#erl_drv_monotonic_time"><c>erl_drv_monotonic_time()</c></seealso></item> + <item><seealso marker="#erl_drv_time_offset"><c>erl_drv_time_offset()</c></seealso></item> + <item><seealso marker="#erl_drv_convert_time_unit"><c>erl_drv_convert_time_unit()</c></seealso></item> + </list></p> + </item> </taglist> </section> @@ -384,12 +394,12 @@ <item> <p> Rewrite driver callback - <c><seealso marker="driver_entry#control">control</seealso></c> + <seealso marker="driver_entry#control"><c>control</c></seealso> to use return type <c>ErlDrvSSizeT</c> instead of <c>int</c>. </p> <p> Rewrite driver callback - <c><seealso marker="driver_entry#call">call</seealso></c> + <seealso marker="driver_entry#call"><c>call</c></seealso> to use return type <c>ErlDrvSSizeT</c> instead of <c>int</c>. </p> <note> @@ -407,19 +417,19 @@ <item> <p> Driver callback - <c><seealso marker="driver_entry#output">output</seealso></c> + <seealso marker="driver_entry#output"><c>output</c></seealso> now gets <c>ErlDrvSizeT</c> as 3rd argument instead of previously <c>int</c>. </p> <p> Driver callback - <c><seealso marker="driver_entry#control">control</seealso></c> + <seealso marker="driver_entry#control"><c>control</c></seealso> now gets <c>ErlDrvSizeT</c> as 4th and 6th arguments instead of previously <c>int</c>. </p> <p> Driver callback - <c><seealso marker="driver_entry#call">call</seealso></c> + <seealso marker="driver_entry#call"><c>call</c></seealso> now gets <c>ErlDrvSizeT</c> as 4th and 6th arguments instead of previously <c>int</c>. </p> @@ -860,6 +870,24 @@ typedef struct ErlIOVec { <seealso marker="#erl_drv_tsd_get">erl_drv_tsd_get()</seealso>. </p> </item> + <tag><marker id="ErlDrvTime"/>ErlDrvTime</tag> + <item> + <p>A signed 64-bit integer type for representation of time.</p> + </item> + <tag><marker id="ErlDrvTimeUnit"/>ErlDrvTimeUnit</tag> + <item> + <p>An enumeration of time units supported by the driver API:</p> + <taglist> + <tag><c>ERL_DRV_SEC</c></tag> + <item><p>Seconds</p></item> + <tag><c>ERL_DRV_MSEC</c></tag> + <item><p>Milliseconds</p></item> + <tag><c>ERL_DRV_USEC</c></tag> + <item><p>Microseconds</p></item> + <tag><c>ERL_DRV_NSEC</c></tag> + <item><p>Nanoseconds</p></item> + </taglist> + </item> </taglist> </section> @@ -1023,6 +1051,11 @@ typedef struct ErlIOVec { <fsummary>Read a system timestamp</fsummary> <desc> <marker id="driver_get_now"></marker> + <warning><p><em>This function is deprecated! Do not use it!</em> + Use <seealso marker="#erl_drv_monotonic_time"><c>erl_drv_monotonic_time()</c></seealso> + (perhaps in combination with + <seealso marker="#erl_drv_time_offset"><c>erl_drv_time_offset()</c></seealso>) + instead.</p></warning> <p>This function reads a timestamp into the memory pointed to by the parameter <c>now</c>. See the description of <seealso marker="#ErlDrvNowData">ErlDrvNowData</seealso> for specification of its fields. </p> @@ -2811,7 +2844,7 @@ ERL_DRV_MAP int sz </func> <func> - <name><ret>int</ret><nametext>erl_drv_putenv(char *key, char *value)</nametext></name> + <name><ret>int</ret><nametext>erl_drv_putenv(const char *key, char *value)</nametext></name> <fsummary>Set the value of an environment variable</fsummary> <desc> <marker id="erl_drv_putenv"></marker> @@ -2840,7 +2873,7 @@ ERL_DRV_MAP int sz </desc> </func> <func> - <name><ret>int</ret><nametext>erl_drv_getenv(char *key, char *value, size_t *value_size)</nametext></name> + <name><ret>int</ret><nametext>erl_drv_getenv(const char *key, char *value, size_t *value_size)</nametext></name> <fsummary>Get the value of an environment variable</fsummary> <desc> <marker id="erl_drv_getenv"></marker> @@ -2997,6 +3030,86 @@ ERL_DRV_MAP int sz </desc> </func> + <func> + <name><ret>ErlDrvTime</ret><nametext>erl_drv_monotonic_time(ErlDrvTimeUnit time_unit)</nametext></name> + <fsummary>Get Erlang Monotonic Time</fsummary> + <desc> + <marker id="erl_drv_monotonic_time"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>time_unit</c></tag> + <item>Time unit of returned value.</item> + </taglist> + <p> + Returns + <seealso marker="time_correction#Erlang_Monotonic_Time">Erlang + monotonic time</seealso>. Note that it is not uncommon with + negative values. + </p> + <p>Returns <c>ERL_DRV_TIME_ERROR</c> if called with an invalid + time unit argument, or if called from a thread that is not a + scheduler thread.</p> + <p>See also:</p> + <list> + <item><seealso marker="#ErlDrvTime"><c>ErlDrvTime</c></seealso></item> + <item><seealso marker="#ErlDrvTimeUnit"><c>ErlDrvTimeUnit</c></seealso></item> + </list> + </desc> + </func> + + <func> + <name><ret>ErlDrvTime</ret><nametext>erl_drv_time_offset(ErlDrvTimeUnit time_unit)</nametext></name> + <fsummary>Get current Time Offset</fsummary> + <desc> + <marker id="erl_drv_time_offset"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>time_unit</c></tag> + <item>Time unit of returned value.</item> + </taglist> + <p>Returns the current time offset between + <seealso marker="time_correction#Erlang_Monotonic_Time">Erlang monotonic time</seealso> + and + <seealso marker="time_correction#Erlang_System_Time">Erlang system time</seealso> + converted into the <c>time_unit</c> passed as argument.</p> + <p>Returns <c>ERL_DRV_TIME_ERROR</c> if called with an invalid + time unit argument, or if called from a thread that is not a + scheduler thread.</p> + <p>See also:</p> + <list> + <item><seealso marker="#ErlDrvTime"><c>ErlDrvTime</c></seealso></item> + <item><seealso marker="#ErlDrvTimeUnit"><c>ErlDrvTimeUnit</c></seealso></item> + </list> + </desc> + </func> + + <func> + <name><ret>ErlDrvTime</ret><nametext>erl_drv_convert_time_unit(ErlDrvTime val, ErlDrvTimeUnit from, ErlDrvTimeUnit to)</nametext></name> + <fsummary>Convert time unit of a time value</fsummary> + <desc> + <marker id="erl_drv_convert_time_unit"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>val</c></tag> + <item>Value to convert time unit for.</item> + <tag><c>from</c></tag> + <item>Time unit of <c>val</c>.</item> + <tag><c>to</c></tag> + <item>Time unit of returned value.</item> + </taglist> + <p>Converts the <c>val</c> value of time unit <c>from</c> to + the corresponding value of time unit <c>to</c>. The result is + rounded using the floor function.</p> + <p>Returns <c>ERL_DRV_TIME_ERROR</c> if called with an invalid + time unit argument.</p> + <p>See also:</p> + <list> + <item><seealso marker="#ErlDrvTime"><c>ErlDrvTime</c></seealso></item> + <item><seealso marker="#ErlDrvTimeUnit"><c>ErlDrvTimeUnit</c></seealso></item> + </list> + </desc> + </func> + </funcs> <section> <title>SEE ALSO</title> diff --git a/erts/doc/src/erl_ext_dist.xml b/erts/doc/src/erl_ext_dist.xml index caf1e812c4..2ac974f497 100644 --- a/erts/doc/src/erl_ext_dist.xml +++ b/erts/doc/src/erl_ext_dist.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>2007</year> - <year>2014</year> + <year>2015</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> @@ -150,10 +150,10 @@ </note> </section> - <marker id="distribution_header"/> <section> <title>Distribution header</title> <p> + <marker id="distribution_header"/> As of erts version 5.7.2 the old atom cache protocol was dropped and a new one was introduced. This atom cache protocol introduced the distribution header. Nodes with erts versions diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml index 23c3d5fcee..420c9fea38 100644 --- a/erts/doc/src/erl_nif.xml +++ b/erts/doc/src/erl_nif.xml @@ -4,7 +4,7 @@ <cref> <header> <copyright> - <year>2001</year><year>2013</year> + <year>2001</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -317,6 +317,17 @@ ok libraries might however fail if deprecated features are used. </p></item> + <tag><marker id="time_measurement"/>Time Measurement</tag> + <item><p>Support for time measurement in NIF libraries: + <list> + <item><seealso marker="#ErlNifTime"><c>ErlNifTime</c></seealso></item> + <item><seealso marker="#ErlNifTimeUnit"><c>ErlNifTimeUnit</c></seealso></item> + <item><seealso marker="#enif_monotonic_time"><c>enif_monotonic_time()</c></seealso></item> + <item><seealso marker="#enif_time_offset"><c>enif_time_offset()</c></seealso></item> + <item><seealso marker="#enif_convert_time_unit"><c>enif_convert_time_unit()</c></seealso></item> + </list></p> + </item> + <tag>Long-running NIFs</tag> <item><p><marker id="dirty_nifs"/>Native functions <seealso marker="#lengthy_work"> @@ -560,6 +571,25 @@ typedef enum { <item><p>A native signed 64-bit integer type.</p></item> <tag><marker id="ErlNifUInt64"/>ErlNifUInt64</tag> <item><p>A native unsigned 64-bit integer type.</p></item> + + <tag><marker id="ErlNifTime"/>ErlNifTime</tag> + <item> + <p>A signed 64-bit integer type for representation of time.</p> + </item> + <tag><marker id="ErlNifTimeUnit"/>ErlNifTimeUnit</tag> + <item> + <p>An enumeration of time units supported by the NIF API:</p> + <taglist> + <tag><c>ERL_NIF_SEC</c></tag> + <item><p>Seconds</p></item> + <tag><c>ERL_NIF_MSEC</c></tag> + <item><p>Milliseconds</p></item> + <tag><c>ERL_NIF_USEC</c></tag> + <item><p>Microseconds</p></item> + <tag><c>ERL_NIF_NSEC</c></tag> + <item><p>Nanoseconds</p></item> + </taglist> + </item> </taglist> </section> @@ -791,6 +821,10 @@ typedef enum { and return true, or return false if <c>term</c> is not an unsigned integer or is outside the bounds of type <c>unsigned long</c>.</p></desc> </func> + <func><name><ret>int</ret><nametext>enif_getenv(const char* key, char* value, size_t *value_size)</nametext></name> + <fsummary>Get the value of an environment variable</fsummary> + <desc><p>Same as <seealso marker="erl_driver#erl_drv_getenv">erl_drv_getenv</seealso>.</p></desc> + </func> <func><name><ret>int</ret><nametext>enif_has_pending_exception(ErlNifEnv* env, ERL_NIF_TERM* reason)</nametext></name> <fsummary>Check if an exception has been raised</fsummary> <desc><p>Return true if a pending exception is associated @@ -833,9 +867,10 @@ typedef enum { <fsummary>Determine if a term is an empty list</fsummary> <desc><p>Return true if <c>term</c> is an empty list.</p></desc> </func> - <marker id="enif_is_exception"/><func><name><ret>int</ret><nametext>enif_is_exception(ErlNifEnv* env, ERL_NIF_TERM term)</nametext></name> + <func><name><ret>int</ret><nametext>enif_is_exception(ErlNifEnv* env, ERL_NIF_TERM term)</nametext></name> <fsummary>Determine if a term is an exception</fsummary> - <desc><p>Return true if <c>term</c> is an exception.</p></desc> + <desc><marker id="enif_is_exception"/> + <p>Return true if <c>term</c> is an exception.</p></desc> </func> <func><name><ret>int</ret><nametext>enif_is_map(ErlNifEnv* env, ERL_NIF_TERM term)</nametext></name> <fsummary>Determine if a term is a map</fsummary> @@ -1481,6 +1516,88 @@ enif_map_iterator_destroy(env, &iter); <desc><p>Same as <seealso marker="erl_driver#erl_drv_tsd_set">erl_drv_tsd_set</seealso>. </p></desc> </func> + + + <func> + <name><ret>ErlNifTime</ret><nametext>enif_monotonic_time(ErlNifTimeUnit time_unit)</nametext></name> + <fsummary>Get Erlang Monotonic Time</fsummary> + <desc> + <marker id="enif_monotonic_time"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>time_unit</c></tag> + <item>Time unit of returned value.</item> + </taglist> + <p> + Returns + <seealso marker="time_correction#Erlang_Monotonic_Time">Erlang + monotonic time</seealso>. Note that it is not uncommon with + negative values. + </p> + <p>Returns <c>ERL_NIF_TIME_ERROR</c> if called with an invalid + time unit argument, or if called from a thread that is not a + scheduler thread.</p> + <p>See also:</p> + <list> + <item><seealso marker="#ErlNifTime"><c>ErlNifTime</c></seealso></item> + <item><seealso marker="#ErlNifTimeUnit"><c>ErlNifTimeUnit</c></seealso></item> + </list> + </desc> + </func> + + <func> + <name><ret>ErlNifTime</ret><nametext>enif_time_offset(ErlNifTimeUnit time_unit)</nametext></name> + <fsummary>Get current Time Offset</fsummary> + <desc> + <marker id="enif_time_offset"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>time_unit</c></tag> + <item>Time unit of returned value.</item> + </taglist> + <p>Returns the current time offset between + <seealso marker="time_correction#Erlang_Monotonic_Time">Erlang monotonic time</seealso> + and + <seealso marker="time_correction#Erlang_System_Time">Erlang system time</seealso> + converted into the <c>time_unit</c> passed as argument.</p> + <p>Returns <c>ERL_NIF_TIME_ERROR</c> if called with an invalid + time unit argument, or if called from a thread that is not a + scheduler thread.</p> + <p>See also:</p> + <list> + <item><seealso marker="#ErlNifTime"><c>ErlNifTime</c></seealso></item> + <item><seealso marker="#ErlNifTimeUnit"><c>ErlNifTimeUnit</c></seealso></item> + </list> + </desc> + </func> + + <func> + <name><ret>ErlNifTime</ret><nametext>enif_convert_time_unit(ErlNifTime val, ErlNifTimeUnit from, ErlNifTimeUnit to)</nametext></name> + <fsummary>Convert time unit of a time value</fsummary> + <desc> + <marker id="enif_convert_time_unit"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>val</c></tag> + <item>Value to convert time unit for.</item> + <tag><c>from</c></tag> + <item>Time unit of <c>val</c>.</item> + <tag><c>to</c></tag> + <item>Time unit of returned value.</item> + </taglist> + <p>Converts the <c>val</c> value of time unit <c>from</c> to + the corresponding value of time unit <c>to</c>. The result is + rounded using the floor function.</p> + <p>Returns <c>ERL_NIF_TIME_ERROR</c> if called with an invalid + time unit argument.</p> + <p>See also:</p> + <list> + <item><seealso marker="#ErlNifTime"><c>ErlNifTime</c></seealso></item> + <item><seealso marker="#ErlNifTimeUnit"><c>ErlNifTimeUnit</c></seealso></item> + </list> + </desc> + </func> + </funcs> <section> <title>SEE ALSO</title> diff --git a/erts/doc/src/erl_prim_loader.xml b/erts/doc/src/erl_prim_loader.xml index d05f0d9aea..db4f132609 100644 --- a/erts/doc/src/erl_prim_loader.xml +++ b/erts/doc/src/erl_prim_loader.xml @@ -36,17 +36,11 @@ the system. The start script is also fetched with this low level loader.</p> <p><c>erl_prim_loader</c> knows about the environment and how to - fetch modules. The loader could, for example, fetch files using - the file system (with absolute file names as input), or a - database (where the binary format of a module is stored).</p> + fetch modules.</p> <p>The <c>-loader Loader</c> command line flag can be used to choose the method used by the <c>erl_prim_loader</c>. Two <c>Loader</c> methods are supported by the Erlang runtime system: - <c>efile</c> and <c>inet</c>. If another loader is required, then - it has to be implemented by the user. The <c>Loader</c> provided - by the user must fulfill the protocol defined below, and it is - started with the <c>erl_prim_loader</c> by evaluating - <c>open_port({spawn,Loader},[binary])</c>.</p> + <c>efile</c> and <c>inet</c>.</p> <warning><p>The support for loading of code from archive files is experimental. The sole purpose of releasing it before it is ready @@ -83,9 +77,6 @@ started on each of hosts given in <c><anno>Hosts</anno></c> in order to answer the requests. See <seealso marker="kernel:erl_boot_server">erl_boot_server(3)</seealso>.</p> - <p>If <c>-loader</c> is something else, the given port program - is started. The port program is supposed to follow - the protocol specified below.</p> </desc> </func> <func> @@ -175,22 +166,6 @@ </funcs> <section> - <title>Protocol</title> - <p>The following protocol must be followed if a user provided - loader port program is used. The <c>Loader</c> port program is - started with the command - <c>open_port({spawn,Loader},[binary])</c>. The protocol is as - follows:</p> - <pre> -Function Send Receive -------------------------------------------------------------- -get_file [102 | FileName] [121 | BinaryFile] (on success) - [122] (failure) - -stop eof terminate</pre> - </section> - - <section> <title>Command Line Flags</title> <p>The <c>erl_prim_loader</c> module interprets the following command line flags:</p> @@ -199,10 +174,8 @@ stop eof terminate</pre> <item> <p>Specifies the name of the loader used by <c>erl_prim_loader</c>. <c>Loader</c> can be <c>efile</c> - (use the local file system), or <c>inet</c> (load using - the <c>boot_server</c> on another Erlang node). If - <c>Loader</c> is user defined, the defined <c>Loader</c> port - program is started.</p> + (use the local file system) or <c>inet</c> (load using + the <c>boot_server</c> on another Erlang node).</p> <p>If the <c>-loader</c> flag is omitted, it defaults to <c>efile</c>.</p> </item> diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index 37f0aa289e..30e6751f41 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2013</year> + <year>1996</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -30,42 +30,43 @@ <file>erlang.xml</file> </header> <module>erlang</module> - <modulesummary>The Erlang BIFs</modulesummary> + <modulesummary>The Erlang BIFs.</modulesummary> <description> - <p>By convention, most built-in functions (BIFs) are seen as being - in the module <c>erlang</c>. A number of the BIFs are viewed more + <p>By convention, most Built-In Functions (BIFs) are seen as being + in this module. Some of the BIFs are viewed more or less as part of the Erlang programming language and are - <em>auto-imported</em>. Thus, it is not necessary to specify - the module name and both the calls <c>atom_to_list(Erlang)</c> and - <c>erlang:atom_to_list(Erlang)</c> are identical.</p> - <p>In the text, auto-imported BIFs are listed without module prefix. + <em>auto-imported</em>. Thus, it is not necessary to specify the + module name. For example, the calls <c>atom_to_list(Erlang)</c> + and <c>erlang:atom_to_list(Erlang)</c> are identical.</p> + <p>Auto-imported BIFs are listed without module prefix. BIFs listed with module prefix are not auto-imported.</p> - <p>BIFs may fail for a variety of reasons. All BIFs fail with + <p>BIFs can fail for various reasons. All BIFs fail with reason <c>badarg</c> if they are called with arguments of an - incorrect type. The other reasons that may make BIFs fail are - described in connection with the description of each individual - BIF.</p> - <p>Some BIFs may be used in guard tests, these are marked with + incorrect type. The other reasons are described in the + description of each individual BIF.</p> + <p>Some BIFs can be used in guard tests and are marked with "Allowed in guard tests".</p> </description> <datatypes> <datatype> - <name><marker id="type-ext_binary">ext_binary()</marker></name> + <name>ext_binary()</name> <desc> + <marker id="type-ext_binary"></marker> <p>A binary data object, structured according to the Erlang external term format.</p> </desc> </datatype> + <datatype> <name name="timestamp"></name> <desc><p>See <seealso marker="#timestamp/0">erlang:timestamp/0</seealso>.</p> </desc> </datatype> - <marker id="type_time_unit"/> <datatype> <name name="time_unit"></name> - <desc><p>Currently supported time unit representations:</p> + <desc><p><marker id="type_time_unit"/> + Supported time unit representations:</p> <taglist> <tag><c>PartsPerSecond :: integer() >= 1</c></tag> <item><p>Time unit expressed in parts per second. That is, @@ -92,11 +93,11 @@ used by the Erlang runtime system.</p> <p>The <c>native</c> time unit is determined at - runtime system start, and will remain the same until + runtime system start, and remains the same until the runtime system terminates. If a runtime system is stopped and then started again (even on the same machine), the <c>native</c> time unit of the new - runtime system instance may differ from the + runtime system instance can differ from the <c>native</c> time unit of the old runtime system instance.</p> @@ -105,8 +106,7 @@ seconds, native)</c>. The result equals the number of whole <c>native</c> time units per second. In case the number of <c>native</c> time units per second does - not add up to a whole number, the result will be - rounded downwards.</p> + not add up to a whole number, the result is rounded downwards.</p> <note> <p>The value of the <c>native</c> time unit gives @@ -120,7 +120,7 @@ but it gives absolutely no information at all about the <seealso marker="time_correction#Time_Accuracy">accuracy</seealso> of time values. The resolution of the <c>native</c> time - unit and the resolution of time values may differ + unit and the resolution of time values can differ significantly.</p> </note> </item> @@ -139,12 +139,15 @@ <func> <name name="abs" arity="1" clause_i="1"/> <name name="abs" arity="1" clause_i="2"/> - <type variable="Float" name_i="1"/> - <type variable="Int" name_i="2"/> - <fsummary>Arithmetical absolute value</fsummary> - <desc> - <p>Returns an integer or float which is the arithmetical - absolute value of <c><anno>Float</anno></c> or <c><anno>Int</anno></c>.</p> + <fsummary>Arithmetical absolute value.</fsummary> + <type> + <v>Float = float()</v> + <v>Int = integer()</v> + </type> + <desc> + <p>Returns an integer or float that is the arithmetical + absolute value of <c><anno>Float</anno></c> or + <c><anno>Int</anno></c>, for example:</p> <pre> > <input>abs(-3.33).</input> 3.33 @@ -153,206 +156,214 @@ <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="adler32" arity="1"/> - <fsummary>Compute adler32 checksum</fsummary> + <fsummary>Computes adler32 checksum.</fsummary> <desc> - <p>Computes and returns the adler32 checksum for <c><anno>Data</anno></c>.</p> + <p>Computes and returns the adler32 checksum for + <c><anno>Data</anno></c>.</p> </desc> </func> + <func> <name name="adler32" arity="2"/> - <fsummary>Compute adler32 checksum</fsummary> + <fsummary>Computes adler32 checksum.</fsummary> <desc> - <p>Continue computing the adler32 checksum by combining - the previous checksum, <c><anno>OldAdler</anno></c>, with the checksum of - <c><anno>Data</anno></c>.</p> - <p>The following code:</p> - <code> - X = erlang:adler32(Data1), - Y = erlang:adler32(X,Data2). - </code> - <p>- would assign the same value to <c>Y</c> as this would:</p> - <code> - Y = erlang:adler32([Data1,Data2]). - </code> + <p>Continues computing the adler32 checksum by combining + the previous checksum, <c><anno>OldAdler</anno></c>, with + the checksum of <c><anno>Data</anno></c>.</p> + <p>The following code:</p> + <code> + X = erlang:adler32(Data1), + Y = erlang:adler32(X,Data2).</code> + <p>assigns the same value to <c>Y</c> as this:</p> + <code> + Y = erlang:adler32([Data1,Data2]).</code> </desc> </func> + <func> <name name="adler32_combine" arity="3"/> - <fsummary>Combine two adler32 checksums</fsummary> - <desc> - <p>Combines two previously computed adler32 checksums. - This computation requires the size of the data object for - the second checksum to be known.</p> - <p>The following code:</p> - <code> - Y = erlang:adler32(Data1), - Z = erlang:adler32(Y,Data2). - </code> - <p>- would assign the same value to <c>Z</c> as this would:</p> - <code> - X = erlang:adler32(Data1), - Y = erlang:adler32(Data2), - Z = erlang:adler32_combine(X,Y,iolist_size(Data2)). - </code> + <fsummary>Combines two adler32 checksums.</fsummary> + <desc> + <p>Combines two previously computed adler32 checksums. + This computation requires the size of the data object for + the second checksum to be known.</p> + <p>The following code:</p> + <code> + Y = erlang:adler32(Data1), + Z = erlang:adler32(Y,Data2).</code> + <p>assigns the same value to <c>Z</c> as this:</p> + <code> + X = erlang:adler32(Data1), + Y = erlang:adler32(Data2), + Z = erlang:adler32_combine(X,Y,iolist_size(Data2)).</code> </desc> </func> + <func> <name name="append_element" arity="2"/> - <fsummary>Append an extra element to a tuple</fsummary> - <desc> - <p>Returns a new tuple which has one element more than - <c><anno>Tuple1</anno></c>, and contains the elements in <c><anno>Tuple1</anno></c> - followed by <c><anno>Term</anno></c> as the last element. Semantically - equivalent to - <c>list_to_tuple(tuple_to_list(<anno>Tuple1</anno>) ++ [<anno>Term</anno>])</c>, but much - faster.</p> + <fsummary>Appends an extra element to a tuple.</fsummary> + <desc> + <p>Returns a new tuple that has one element more than + <c><anno>Tuple1</anno></c>, and contains the elements in + <c><anno>Tuple1</anno></c> + followed by <c><anno>Term</anno></c> as the last element. + Semantically equivalent to + <c>list_to_tuple(tuple_to_list(<anno>Tuple1</anno>) ++ + [<anno>Term</anno>])</c>, but much faster.</p> + <p>Example:</p> <pre> > <input>erlang:append_element({one, two}, three).</input> {one,two,three}</pre> </desc> </func> + <func> <name name="apply" arity="2"/> - <fsummary>Apply a function to an argument list</fsummary> + <fsummary>Applies a function to an argument list.</fsummary> <desc> - <p>Call a fun, passing the elements in <c><anno>Args</anno></c> as - arguments.</p> - <p>Note: If the number of elements in the arguments are known at - compile-time, the call is better written as + <p>Calls a fun, passing the elements in <c><anno>Args</anno></c> + as arguments.</p> + <p>If the number of elements in the arguments are known at + compile time, the call is better written as <c><anno>Fun</anno>(Arg1, Arg2, ... ArgN)</c>.</p> <warning> <p>Earlier, <c><anno>Fun</anno></c> could also be given as <c>{Module, Function}</c>, equivalent to - <c>apply(Module, Function, Args)</c>. This usage is - deprecated and will stop working in a future release of - Erlang/OTP.</p> + <c>apply(Module, Function, Args)</c>. This use is + deprecated and will stop working in a future release.</p> </warning> </desc> </func> + <func> <name name="apply" arity="3"/> - <fsummary>Apply a function to an argument list</fsummary> + <fsummary>Applies a function to an argument list.</fsummary> <desc> <p>Returns the result of applying <c>Function</c> in - <c><anno>Module</anno></c> to <c><anno>Args</anno></c>. The applied function must + <c><anno>Module</anno></c> to <c><anno>Args</anno></c>. + The applied function must be exported from <c>Module</c>. The arity of the function is the length of <c>Args</c>.</p> + <p>Example:</p> <pre> > <input>apply(lists, reverse, [[a, b, c]]).</input> -[c,b,a]</pre> - <p><c>apply</c> can be used to evaluate BIFs by using - the module name <c>erlang</c>.</p> - <pre> +[c,b,a] > <input>apply(erlang, atom_to_list, ['Erlang']).</input> "Erlang"</pre> - <p>Note: If the number of arguments are known at compile-time, + <p>If the number of arguments are known at compile time, the call is better written as <c><anno>Module</anno>:<anno>Function</anno>(Arg1, Arg2, ..., ArgN)</c>.</p> <p>Failure: <c>error_handler:undefined_function/3</c> is called if the applied function is not exported. The error handler can be redefined (see <seealso marker="#process_flag/2">process_flag/2</seealso>). - If the <c>error_handler</c> is undefined, or if the user has + If <c>error_handler</c> is undefined, or if the user has redefined the default <c>error_handler</c> so the replacement module is undefined, an error with the reason <c>undef</c> is generated.</p> </desc> </func> + <func> <name name="atom_to_binary" arity="2"/> - <fsummary>Return the binary representation of an atom</fsummary> - <desc> - <p>Returns a binary which corresponds to the text - representation of <c><anno>Atom</anno></c>. If <c><anno>Encoding</anno></c> - is <c>latin1</c>, there will be one byte for each character - in the text representation. If <c><anno>Encoding</anno></c> is - <c>utf8</c> or - <c>unicode</c>, the characters will be encoded using UTF-8 - (meaning that characters from 16#80 up to 0xFF will be - encoded in two bytes).</p> - - <note><p>Currently, <c>atom_to_binary(<anno>Atom</anno>, latin1)</c> can - never fail because the text representation of an atom can only contain - characters from 0 to 16#FF. In a future release, the text representation - of atoms might be allowed to contain any Unicode character - and <c>atom_to_binary(<anno>Atom</anno>, latin1)</c> will fail if the - text representation for the <c><anno>Atom</anno></c> contains a Unicode - character greater than 16#FF.</p></note> - + <fsummary>Returns the binary representation of an atom.</fsummary> + <desc> + <p>Returns a binary corresponding to the text + representation of <c><anno>Atom</anno></c>. + If <c><anno>Encoding</anno></c> + is <c>latin1</c>, there is one byte for each character + in the text representation. If <c><anno>Encoding</anno></c> is + <c>utf8</c> or + <c>unicode</c>, the characters are encoded using UTF-8 + (that is, characters from 128 through 255 are + encoded in two bytes).</p> + <note><p><c>atom_to_binary(<anno>Atom</anno>, latin1)</c> never + fails because the text representation of an atom can only + contain characters from 0 through 255. In a future release, + the text representation + of atoms can be allowed to contain any Unicode character and + <c>atom_to_binary(<anno>Atom</anno>, latin1)</c> will then fail if the + text representation for <c><anno>Atom</anno></c> contains a Unicode + character greater than 255.</p></note> + <p>Example:</p> <pre> > <input>atom_to_binary('Erlang', latin1).</input> <<"Erlang">></pre> </desc> </func> + <func> <name name="atom_to_list" arity="1"/> - <fsummary>Text representation of an atom</fsummary> + <fsummary>Text representation of an atom.</fsummary> <desc> - <p>Returns a string which corresponds to the text - representation of <c><anno>Atom</anno></c>.</p> + <p>Returns a string corresponding to the text + representation of <c><anno>Atom</anno></c>, for example:</p> <pre> > <input>atom_to_list('Erlang').</input> "Erlang"</pre> </desc> </func> + <func> <name name="binary_part" arity="2"/> - <fsummary>Extracts a part of a binary</fsummary> + <fsummary>Extracts a part of a binary.</fsummary> <desc> - <p>Extracts the part of the binary described by <c><anno>PosLen</anno></c>.</p> - - <p>Negative length can be used to extract bytes at the end of a binary:</p> - + <p>Extracts the part of the binary described by + <c><anno>PosLen</anno></c>.</p> + <p>Negative length can be used to extract bytes at the end + of a binary, for example:</p> <code> 1> Bin = <<1,2,3,4,5,6,7,8,9,10>>. 2> binary_part(Bin,{byte_size(Bin), -5}). -<<6,7,8,9,10>> -</code> - - <p>If <c><anno>PosLen</anno></c> in any way references outside the binary, a <c>badarg</c> exception is raised.</p> - - <p><c><anno>Start</anno></c> is zero-based, i.e.:</p> +<<6,7,8,9,10>></code> + <p>Failure: <c>badarg</c> if <c><anno>PosLen</anno></c> in any way + references outside the binary.</p> + <p><c><anno>Start</anno></c> is zero-based, that is:</p> <code> 1> Bin = <<1,2,3>> 2> binary_part(Bin,{0,2}). -<<1,2>> -</code> - - <p>See the STDLIB module <c>binary</c> for details about the <c><anno>PosLen</anno></c> semantics.</p> - +<<1,2>></code> + <p>For details about the <c><anno>PosLen</anno></c> semantics, see the + <seealso marker="stdlib:binary">binary</seealso> + manual page in <c>STDLIB</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="binary_part" arity="3"/> - <fsummary>Extracts a part of a binary</fsummary> + <fsummary>Extracts a part of a binary.</fsummary> <desc> - <p>The same as <c>binary_part(<anno>Subject</anno>, {<anno>Start</anno>, <anno>Length</anno>})</c>.</p> - + <p>The same as <c>binary_part(<anno>Subject</anno>, + {<anno>Start</anno>, <anno>Length</anno>})</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="binary_to_atom" arity="2"/> - <fsummary>Convert from text representation to an atom</fsummary> + <fsummary>Converts from text representation to an atom.</fsummary> <desc> <p>Returns the atom whose text representation is - <c><anno>Binary</anno></c>. If <c><anno>Encoding</anno></c> is <c>latin1</c>, no - translation of bytes in the binary is done. If <c><anno>Encoding</anno></c> - is <c>utf8</c> or <c>unicode</c>, the binary must contain - valid UTF-8 sequences; furthermore, only Unicode characters up - to 0xFF are allowed.</p> - - <note><p><c>binary_to_atom(<anno>Binary</anno>, utf8)</c> will fail if - the binary contains Unicode characters greater than 16#FF. - In a future release, such Unicode characters might be allowed - and <c>binary_to_atom(<anno>Binary</anno>, utf8)</c> - will not fail in that case. For more information on Unicode support in atoms - see <seealso marker="erl_ext_dist#utf8_atoms">note on UTF-8 encoded atoms</seealso> - in the chapter about the external term format in the ERTS User's Guide.</p></note> - + <c><anno>Binary</anno></c>. + If <c><anno>Encoding</anno></c> is <c>latin1</c>, no + translation of bytes in the binary is done. + If <c><anno>Encoding</anno></c> + is <c>utf8</c> or <c>unicode</c>, the binary must contain + valid UTF-8 sequences. Only Unicode characters up + to 255 are allowed.</p> + <note><p><c>binary_to_atom(<anno>Binary</anno>, utf8)</c> fails if + the binary contains Unicode characters greater than 255. + In a future release, such Unicode characters can be allowed + and <c>binary_to_atom(<anno>Binary</anno>, utf8)</c> does then not fail. + For more information on Unicode support in atoms, see the + <seealso marker="erl_ext_dist#utf8_atoms">note on UTF-8 + encoded atoms</seealso> + in Section "External Term Format" in the User's Guide.</p></note> + <p>Examples:</p> <pre> > <input>binary_to_atom(<<"Erlang">>, latin1).</input> 'Erlang' @@ -362,20 +373,24 @@ called as binary_to_atom(<<208,128>>,utf8)</pre> </desc> </func> + <func> <name name="binary_to_existing_atom" arity="2"/> - <fsummary>Convert from text representation to an atom</fsummary> + <fsummary>Converts from text representation to an atom.</fsummary> <desc> - <p>Works like <seealso marker="#binary_to_atom/2">binary_to_atom/2</seealso>, - but the atom must already exist.</p> - <p>Failure: <c>badarg</c> if the atom does not already exist.</p> + <p>As + <seealso marker="#binary_to_atom/2">binary_to_atom/2</seealso>, + but the atom must exist.</p> + <p>Failure: <c>badarg</c> if the atom does not exist.</p> </desc> </func> + <func> <name name="binary_to_float" arity="1"/> - <fsummary>Convert from text representation to a float</fsummary> + <fsummary>Converts from text representation to a float.</fsummary> <desc> - <p>Returns the float whose text representation is <c><anno>Binary</anno></c>.</p> + <p>Returns the float whose text representation is + <c><anno>Binary</anno></c>, for example:</p> <pre> > <input>binary_to_float(<<"2.2017764e+0">>).</input> 2.2017764</pre> @@ -383,12 +398,13 @@ representation of a float.</p> </desc> </func> + <func> <name name="binary_to_integer" arity="1"/> - <fsummary>Convert from text representation to an integer</fsummary> + <fsummary>Converts from text representation to an integer.</fsummary> <desc> <p>Returns an integer whose text representation is - <c><anno>Binary</anno></c>.</p> + <c><anno>Binary</anno></c>, for example:</p> <pre> > <input>binary_to_integer(<<"123">>).</input> 123</pre> @@ -396,12 +412,13 @@ representation of an integer.</p> </desc> </func> + <func> <name name="binary_to_integer" arity="2"/> - <fsummary>Convert from text representation to an integer</fsummary> + <fsummary>Converts from text representation to an integer.</fsummary> <desc> <p>Returns an integer whose text representation in base - <c><anno>Base</anno></c> is <c><anno>Binary</anno></c>.</p> + <c><anno>Base</anno></c> is <c><anno>Binary</anno></c>, for example:</p> <pre> > <input>binary_to_integer(<<"3FF">>, 16).</input> 1023</pre> @@ -409,93 +426,101 @@ representation of an integer.</p> </desc> </func> + <func> <name name="binary_to_list" arity="1"/> - <fsummary>Convert a binary to a list</fsummary> + <fsummary>Converts a binary to a list.</fsummary> <desc> - <p>Returns a list of integers which correspond to the bytes of + <p>Returns a list of integers corresponding to the bytes of <c><anno>Binary</anno></c>.</p> </desc> </func> + <func> <name name="binary_to_list" arity="3"/> - <fsummary>Convert part of a binary to a list</fsummary> - <type_desc variable="Start">1..byte_size(<anno>Binary</anno>)</type_desc> + <fsummary>Converts part of a binary to a list.</fsummary> + <type_desc variable="Start">1..byte_size(<c><anno>Binary</anno></c>)</type_desc> <desc> <p>As <c>binary_to_list/1</c>, but returns a list of integers corresponding to the bytes from position <c><anno>Start</anno></c> to - position <c><anno>Stop</anno></c> in <c><anno>Binary</anno></c>. Positions in the + position <c><anno>Stop</anno></c> in <c><anno>Binary</anno></c>. + The positions in the binary are numbered starting from 1.</p> - - <note><p>This function's indexing style of using one-based indices for - binaries is deprecated. New code should use the functions in - the STDLIB module <c>binary</c> instead. They consequently - use the same (zero-based) style of indexing.</p></note> + <note><p>The one-based indexing for binaries used by + this function is deprecated. New code is to use + <seealso marker="stdlib:binary#bin_to_list/3">binary:bin_to_list/3</seealso> + in <c>STDLIB</c> instead. All functions in module + <c>binary</c> consistently use zero-based indexing.</p></note> </desc> </func> + <func> <name name="bitstring_to_list" arity="1"/> - <fsummary>Convert a bitstring to a list</fsummary> + <fsummary>Converts a bitstring to a list.</fsummary> <desc> - <p>Returns a list of integers which correspond to the bytes of - <c><anno>Bitstring</anno></c>. If the number of bits in the binary is not - divisible by 8, the last element of the list will be a bitstring - containing the remaining bits (1 up to 7 bits).</p> + <p>Returns a list of integers corresponding to the bytes of + <c><anno>Bitstring</anno></c>. If the number of bits in the binary + is not divisible by 8, the last element of the list is a bitstring + containing the remaining 1-7 bits.</p> </desc> </func> + <func> <name name="binary_to_term" arity="1"/> - <fsummary>Decode an Erlang external term format binary</fsummary> + <fsummary>Decodes an Erlang external term format binary.</fsummary> <desc> - <p>Returns an Erlang term which is the result of decoding - the binary object <c><anno>Binary</anno></c>, which must be encoded + <p>Returns an Erlang term that is the result of decoding + binary object <c><anno>Binary</anno></c>, which must be encoded according to the Erlang external term format.</p> - <warning> - <p>When decoding binaries from untrusted sources, consider using - <c>binary_to_term/2</c> to prevent denial of service attacks.</p> - </warning> - <p>See also - <seealso marker="#term_to_binary/1">term_to_binary/1</seealso> - and - <seealso marker="#binary_to_term/2">binary_to_term/2</seealso>.</p> + <warning><p>When decoding binaries from untrusted sources, + consider using <c>binary_to_term/2</c> to prevent Denial + of Service attacks.</p></warning> + <p>See also + <seealso marker="#term_to_binary/1">term_to_binary/1</seealso> + and + <seealso marker="#binary_to_term/2">binary_to_term/2</seealso>.</p> </desc> </func> + <func> <name name="binary_to_term" arity="2"/> - <fsummary>Decode an Erlang external term format binary</fsummary> + <fsummary>Decodes an Erlang external term format binary.</fsummary> <desc> <p>As <c>binary_to_term/1</c>, but takes options that affect decoding of the binary.</p> <taglist> <tag><c>safe</c></tag> <item> - <p>Use this option when receiving binaries from an untrusted + <p>Use this option when receiving binaries from an untrusted source.</p> - <p>When enabled, it prevents decoding data that may be used to - attack the Erlang system. In the event of receiving unsafe - data, decoding fails with a badarg error.</p> - <p>Currently, this prevents creation of new atoms directly, - creation of new atoms indirectly (as they are embedded in - certain structures like pids, refs, funs, etc.), and creation of - new external function references. None of those resources are - currently garbage collected, so unchecked creation of them can - exhaust available memory.</p> + <p>When enabled, it prevents decoding data that can be used to + attack the Erlang system. In the event of receiving unsafe + data, decoding fails with a <c>badarg</c> error.</p> + <p>This prevents creation of new atoms directly, + creation of new atoms indirectly (as they are embedded in + certain structures, such as process identifiers, + refs, and funs), and + creation of new external function references. + None of those resources are garbage collected, so unchecked + creation of them can exhaust available memory.</p> </item> </taglist> - <p>Failure: <c>badarg</c> if <c>safe</c> is specified and unsafe data - is decoded.</p> + <p>Failure: <c>badarg</c> if <c>safe</c> is specified and unsafe + data is decoded.</p> <p>See also <seealso marker="#term_to_binary/1">term_to_binary/1</seealso>, <seealso marker="#binary_to_term/1">binary_to_term/1</seealso>, - and <seealso marker="#list_to_existing_atom/1"> - list_to_existing_atom/1</seealso>.</p> + and + <seealso marker="#list_to_existing_atom/1">list_to_existing_atom/1</seealso>.</p> </desc> </func> + <func> <name name="bit_size" arity="1"/> - <fsummary>Return the size of a bitstring</fsummary> + <fsummary>Returns the size of a bitstring.</fsummary> <desc> - <p>Returns an integer which is the size in bits of <c><anno>Bitstring</anno></c>.</p> + <p>Returns an integer that is the size in bits of + <c><anno>Bitstring</anno></c>, for example:</p> <pre> > <input>bit_size(<<433:16,3:3>>).</input> 19 @@ -504,30 +529,34 @@ <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="bump_reductions" arity="1"/> - <fsummary>Increment the reduction counter</fsummary> + <fsummary>Increments the reduction counter.</fsummary> <desc> <p>This implementation-dependent function increments the reduction counter for the calling process. In the Beam emulator, the reduction counter is normally incremented by - one for each function and BIF call, and a context switch is - forced when the counter reaches the maximum number of reductions - for a process (2000 reductions in R12B).</p> + one for each function and BIF call. A context switch is + forced when the counter reaches the maximum number of + reductions for a process (2000 reductions in OTP R12B).</p> <warning> - <p>This BIF might be removed in a future version of the Beam + <p>This BIF can be removed in a future version of the Beam machine without prior warning. It is unlikely to be implemented in other Erlang implementations.</p> </warning> </desc> </func> + <func> <name name="byte_size" arity="1"/> - <fsummary>Return the size of a bitstring (or binary)</fsummary> + <fsummary>Returns the size of a bitstring (or binary).</fsummary> <desc> - <p>Returns an integer which is the number of bytes needed to contain - <c><anno>Bitstring</anno></c>. (That is, if the number of bits in <c><anno>Bitstring</anno></c> is not - divisible by 8, the resulting number of bytes will be rounded <em>up</em>.)</p> + <p>Returns an integer that is the number of bytes needed to + contain <c><anno>Bitstring</anno></c>. That is, if the number of bits + in <c><anno>Bitstring</anno></c> is not divisible by 8, the resulting + number of bytes is rounded <em>up</em>.</p> + <p>Examples:</p> <pre> > <input>byte_size(<<433:16,3:3>>).</input> 3 @@ -536,18 +565,19 @@ <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="cancel_timer" arity="2"/> - <fsummary>Cancel a timer</fsummary> + <fsummary>Cancels a timer.</fsummary> <desc> <p> - Cancels a timer that has been created by either + Cancels a timer that has been created by <seealso marker="#start_timer/4"><c>erlang:start_timer()</c></seealso>, or <seealso marker="#send_after/4"><c>erlang:send_after()</c></seealso>. <c><anno>TimerRef</anno></c> identifies the timer, and was returned by the BIF that created the timer. </p> - <p>Currently available <c><anno>Option</anno></c>s:</p> + <p>Available <c><anno>Option</anno></c>s:</p> <taglist> <tag><c>{async, Async}</c></tag> <item> @@ -556,7 +586,7 @@ defaults to <c>false</c> which will cause the cancellation to be performed synchronously. When <c>Async</c> is set to <c>true</c>, the cancel - operation will be performed asynchronously. That is, + operation is performed asynchronously. That is, <c>erlang:cancel_timer()</c> will send an asynchronous request for cancellation to the timer service that manages the timer, and then return <c>ok</c>. @@ -567,17 +597,17 @@ <p> Request information about the <c><anno>Result</anno></c> of the cancellation. <c>Info</c> defaults to <c>true</c> - which means that the <c><anno>Result</anno></c> will - be given. When <c>Info</c> is set to <c>false</c>, no + which means the <c><anno>Result</anno></c> is + given. When <c>Info</c> is set to <c>false</c>, no information about the result of the cancellation - will be given. When the operation is performed</p> + is given. When the operation is performed</p> <taglist> <tag>synchronously</tag> <item> <p> - If <c>Info</c> is <c>true</c>, the <c>Result</c> will + If <c>Info</c> is <c>true</c>, the <c>Result</c> is returned by <c>erlang:cancel_timer()</c>; otherwise, - <c>ok</c> will be returned. + <c>ok</c> is returned. </p> </item> <tag>asynchronously</tag> @@ -585,10 +615,10 @@ <p> If <c>Info</c> is <c>true</c>, a message on the form <c>{cancel_timer, <anno>TimerRef</anno>, - <anno>Result</anno>}</c> will be sent to the + <anno>Result</anno>}</c> is sent to the caller of <c>erlang:cancel_timer()</c> when the cancellation operation has been performed; otherwise, - no message will be sent. + no message is sent. </p> </item> </taglist> @@ -597,30 +627,30 @@ <p> More <c><anno>Option</anno></c>s may be added in the future. </p> + <p>If <c><anno>Result</anno></c> is an integer, it represents + the time in milli-seconds left until the canceled timer would + have expired.</p> <p> - When the <c><anno>Result</anno></c> equals <c>false</c>, a + If <c><anno>Result</anno></c> is <c>false</c>, a timer corresponding to <c><anno>TimerRef</anno></c> could not be found. This can be either because the timer had expired, already had been canceled, or because <c><anno>TimerRef</anno></c> - never has corresponded to a timer. If the timer has expired, - the timeout message has been sent, but it does not tell you - whether or not it has arrived at its destination yet. When the - <c><anno>Result</anno></c> is an integer, it represents the - time in milli-seconds left until the timer will expire. + never corresponded to a timer. Even if the timer had expired, + it does not tell you whether or not the timeout message has + arrived at its destination yet. </p> <note> <p> The timer service that manages the timer may be co-located with another scheduler than the scheduler that the calling process is executing on. If this is the case, communication - with the timer service will take much longer time than if it + with the timer service takes much longer time than if it is located locally. If the calling process is in critical path, and can do other things while waiting for the result of this operation, or is not interested in the result of - the operation, you want to use the <c>{async, true}</c> - option. If using the <c>{async, false}</c> option, the calling - process will be blocked until the operation has been - performed. + the operation, you want to use option <c>{async, true}</c>. + If using option <c>{async, false}</c>, the calling + process blocks until the operation has been performed. </p> </note> <p>See also @@ -632,7 +662,7 @@ </func> <func> <name name="cancel_timer" arity="1"/> - <fsummary>Cancel a timer</fsummary> + <fsummary>Cancels a timer.</fsummary> <desc> <p>Cancels a timer. The same as calling <seealso marker="#cancel_timer/2"><c>erlang:cancel_timer(TimerRef, @@ -641,103 +671,102 @@ </func> <func> <name name="check_old_code" arity="1"/> - <fsummary>Check if a module has old code</fsummary> + <fsummary>Checks if a module has old code.</fsummary> <desc> - <p>Returns <c>true</c> if the <c><anno>Module</anno></c> has old code, - and <c>false</c> otherwise.</p> + <p>Returns <c>true</c> if <c><anno>Module</anno></c> has old code, + otherwise <c>false</c>.</p> <p>See also <seealso marker="kernel:code">code(3)</seealso>.</p> </desc> </func> + <func> <name name="check_process_code" arity="2"/> - <fsummary>Check if a process is executing old code for a module</fsummary> + <fsummary>Checks if a process executes old code for a module.</fsummary> <desc> <p>The same as - <seealso marker="#check_process_code/3"><c>erlang:check_process_code(<anno>Pid</anno>, - <anno>Module</anno>, [])</c></seealso>.</p> + <seealso marker="#check_process_code/3"><c>erlang:check_process_code(<anno>Pid</anno>, <anno>Module</anno>, [])</c></seealso>.</p> </desc> </func> + <func> <name name="check_process_code" arity="3"/> - <fsummary>Check if a process is executing old code for a module</fsummary> + <fsummary>Checks if a process executes old code for a module.</fsummary> <desc> - <p>Check if the node local process identified by <c><anno>Pid</anno></c> - is executing old code for <c><anno>Module</anno></c>.</p> - <p>Currently available <c><anno>Option</anno>s</c>:</p> + <p>Checks if the node local process identified by <c><anno>Pid</anno></c> + executes old code for <c><anno>Module</anno></c>.</p> + <p>The available <c><anno>Option</anno></c>s are as follows:</p> <taglist> <tag><c>{allow_gc, boolean()}</c></tag> <item> - Determines if garbage collection is allowed when performing - the operation. If <c>{allow_gc, false}</c> is passed, and - a garbage collection is needed in order to determine the - result of the operation, the operation will be aborted - (see information on <c><anno>CheckResult</anno></c> below). - The default is to allow garbage collection, i.e., - <c>{allow_gc, true}</c>. + <p>Determines if garbage collection is allowed when performing + the operation. If <c>{allow_gc, false}</c> is passed, and + a garbage collection is needed to determine the + result of the operation, the operation is aborted (see + information on <c><anno>CheckResult</anno></c> in the following). + The default is to allow garbage collection, that is, + <c>{allow_gc, true}</c>.</p> </item> <tag><c>{async, RequestId}</c></tag> <item> - The <c>check_process_code/3</c> function will return - the value <c>async</c> immediately after the request - has been sent. When the request has been processed, the - process that called this function will be passed a - message on the form:<br/> - <c>{check_process_code, <anno>RequestId</anno>, <anno>CheckResult</anno>}</c>. + <p>The function <c>check_process_code/3</c> returns + the value <c>async</c> immediately after the request + has been sent. When the request has been processed, the + process that called this function is passed a + message on the form + <c>{check_process_code, <anno>RequestId</anno>, <anno>CheckResult</anno>}</c>.</p> </item> </taglist> - <p>If <c><anno>Pid</anno></c> equals <c>self()</c>, and - no <c>async</c> option has been passed, the operation will - be performed at once. In all other cases a request for - the operation will be sent to the process identified by - <c><anno>Pid</anno></c>, and will be handled when - appropriate. If no <c>async</c> option has been passed, - the caller will block until <c><anno>CheckResult</anno></c> - is available and can be returned.</p> - <p><c><anno>CheckResult</anno></c> informs about the result of - the request:</p> + <p>If <c><anno>Pid</anno></c> equals <c>self()</c>, and + no <c>async</c> option has been passed, the operation + is performed at once. Otherwise a request for + the operation is sent to the process identified by + <c><anno>Pid</anno></c>, and is handled when + appropriate. If no <c>async</c> option has been passed, + the caller blocks until <c><anno>CheckResult</anno></c> + is available and can be returned.</p> + <p><c><anno>CheckResult</anno></c> informs about the result of + the request as follows:</p> <taglist> <tag><c>true</c></tag> <item> - The process identified by <c><anno>Pid</anno></c> is - executing old code for <c><anno>Module</anno></c>. - That is, the current call of the process executes old - code for this module, or the process has references - to old code for this module, or the process contains - funs that references old code for this module. + <p>The process identified by <c><anno>Pid</anno></c> + executes old code for <c><anno>Module</anno></c>. + That is, the current call of the process executes old + code for this module, or the process has references + to old code for this module, or the process contains + funs that references old code for this module.</p> </item> <tag><c>false</c></tag> <item> - The process identified by <c><anno>Pid</anno></c> is - not executing old code for <c><anno>Module</anno></c>. + <p>The process identified by <c><anno>Pid</anno></c> does + not execute old code for <c><anno>Module</anno></c>.</p> </item> <tag><c>aborted</c></tag> <item> - The operation was aborted since the process needed to - be garbage collected in order to determine the result - of the operation, and the operation was requested - by passing the <c>{allow_gc, false}</c> option.</item> + <p>The operation was aborted, as the process needed to + be garbage collected to determine the operation result, + and the operation was requested + by passing option <c>{allow_gc, false}</c>.</p></item> </taglist> <p>See also <seealso marker="kernel:code">code(3)</seealso>.</p> <p>Failures:</p> <taglist> <tag><c>badarg</c></tag> - <item> - If <c><anno>Pid</anno></c> is not a node local process identifier. + <item>If <c><anno>Pid</anno></c> is not a node local process identifier. </item> <tag><c>badarg</c></tag> - <item> - If <c><anno>Module</anno></c> is not an atom. + <item>If <c><anno>Module</anno></c> is not an atom. </item> <tag><c>badarg</c></tag> - <item> - If <c><anno>OptionList</anno></c> is not a valid list of options. + <item>If <c><anno>OptionList</anno></c> is an invalid list of options. </item> </taglist> </desc> </func> + <func> <name name="convert_time_unit" arity="3"/> - <fsummary>Convert time unit of a time value</fsummary> + <fsummary>Converts time unit of a time value.</fsummary> <desc> <p>Converts the <c><anno>Time</anno></c> value of time unit <c><anno>FromUnit</anno></c> to the corresponding @@ -753,100 +782,102 @@ </func> <func> <name name="crc32" arity="1"/> - <fsummary>Compute crc32 (IEEE 802.3) checksum</fsummary> + <fsummary>Computes crc32 (IEEE 802.3) checksum.</fsummary> <desc> - <p>Computes and returns the crc32 (IEEE 802.3 style) checksum for <c><anno>Data</anno></c>.</p> + <p>Computes and returns the crc32 (IEEE 802.3 style) checksum + for <c><anno>Data</anno></c>.</p> </desc> </func> + <func> <name name="crc32" arity="2"/> - <fsummary>Compute crc32 (IEEE 802.3) checksum</fsummary> + <fsummary>Computes crc32 (IEEE 802.3) checksum.</fsummary> <desc> - <p>Continue computing the crc32 checksum by combining - the previous checksum, <c><anno>OldCrc</anno></c>, with the checksum of - <c><anno>Data</anno></c>.</p> - <p>The following code:</p> - <code> - X = erlang:crc32(Data1), - Y = erlang:crc32(X,Data2). - </code> - <p>- would assign the same value to <c>Y</c> as this would:</p> - <code> - Y = erlang:crc32([Data1,Data2]). - </code> + <p>Continues computing the crc32 checksum by combining + the previous checksum, <c><anno>OldCrc</anno></c>, with the checksum of + <c><anno>Data</anno></c>.</p> + <p>The following code:</p> + <code> + X = erlang:crc32(Data1), + Y = erlang:crc32(X,Data2).</code> + <p>assigns the same value to <c>Y</c> as this:</p> + <code> + Y = erlang:crc32([Data1,Data2]).</code> </desc> </func> + <func> <name name="crc32_combine" arity="3"/> - <fsummary>Combine two crc32 (IEEE 802.3) checksums</fsummary> - <desc> - <p>Combines two previously computed crc32 checksums. - This computation requires the size of the data object for - the second checksum to be known.</p> - <p>The following code:</p> + <fsummary>Combines two crc32 (IEEE 802.3) checksums.</fsummary> + <desc> + <p>Combines two previously computed crc32 checksums. + This computation requires the size of the data object for + the second checksum to be known.</p> + <p>The following code:</p> + <code> + Y = erlang:crc32(Data1), + Z = erlang:crc32(Y,Data2).</code> + <p>assigns the same value to <c>Z</c> as this:</p> <code> - Y = erlang:crc32(Data1), - Z = erlang:crc32(Y,Data2). - </code> - <p>- would assign the same value to <c>Z</c> as this would:</p> - <code> - X = erlang:crc32(Data1), - Y = erlang:crc32(Data2), - Z = erlang:crc32_combine(X,Y,iolist_size(Data2)). - </code> + X = erlang:crc32(Data1), + Y = erlang:crc32(Data2), + Z = erlang:crc32_combine(X,Y,iolist_size(Data2)).</code> </desc> </func> + <func> <name name="date" arity="0"/> - <fsummary>Current date</fsummary> + <fsummary>Current date.</fsummary> <desc> <p>Returns the current date as <c>{Year, Month, Day}</c>.</p> - <p>The time zone and daylight saving time correction depend on + <p>The time zone and Daylight Saving Time correction depend on the underlying OS.</p> + <p>Example:</p> <pre> > <input>date().</input> {1995,2,19}</pre> </desc> </func> + <func> <name name="decode_packet" arity="3"/> - <fsummary>Extracts a protocol packet from a binary</fsummary> + <fsummary>Extracts a protocol packet from a binary.</fsummary> <desc> - <p>Decodes the binary <c><anno>Bin</anno></c> according to the packet - protocol specified by <c><anno>Type</anno></c>. Very similar to the packet - handling done by sockets with the option {packet,<anno>Type</anno>}.</p> - <p>If an entire packet is contained in <c><anno>Bin</anno></c> it is + protocol specified by <c><anno>Type</anno></c>. Similar to the packet + handling done by sockets with option {packet,<anno>Type</anno>}.</p> + <p>If an entire packet is contained in <c><anno>Bin</anno></c>, it is returned together with the remainder of the binary as <c>{ok,<anno>Packet</anno>,<anno>Rest</anno>}</c>.</p> <p>If <c><anno>Bin</anno></c> does not contain the entire packet, - <c>{more,<anno>Length</anno>}</c> is returned. <c><anno>Length</anno></c> is either the - expected <em>total size</em> of the packet or <c>undefined</c> - if the expected packet size is not known. <c>decode_packet</c> + <c>{more,<anno>Length</anno>}</c> is returned. + <c><anno>Length</anno></c> is either the + expected <em>total size</em> of the packet, or <c>undefined</c> + if the expected packet size is unknown. <c>decode_packet</c> can then be called again with more data added.</p> - <p>If the packet does not conform to the protocol format + <p>If the packet does not conform to the protocol format, <c>{error,<anno>Reason</anno>}</c> is returned.</p> - <p>The following values of <c><anno>Type</anno></c> are valid:</p> + <p>The following <c>Type</c>s are valid:</p> <taglist> <tag><c>raw | 0</c></tag> <item> - <p>No packet handling is done. Entire binary is + <p>No packet handling is done. The entire binary is returned unless it is empty.</p> </item> <tag><c>1 | 2 | 4</c></tag> <item> <p>Packets consist of a header specifying the number of bytes in the packet, followed by that number of bytes. - The length of header can be one, two, or four bytes; + The length of the header can be one, two, or four bytes; the order of the bytes is big-endian. The header - will be stripped off when the packet is returned.</p> + is stripped off when the packet is returned.</p> </item> <tag><c>line</c></tag> <item> - <p>A packet is a line terminated with newline. The - newline character is included in the returned packet - unless the line was truncated according to the option - <c>line_length</c>.</p> + <p>A packet is a line terminated by a delimiter byte, + default is the latin1 newline character. The delimiter + byte is included in the returned packet unless the line + was truncated according to option <c>line_length</c>.</p> </item> <tag><c>asn1 | cdr | sunrm | fcgi | tpkt</c></tag> <item> @@ -864,41 +895,50 @@ <item> <p>The Hypertext Transfer Protocol. The packets are returned with the format according to - <c><anno>HttpPacket</anno></c> described above. A packet is either a - request, a response, a header or an end of header - mark. Invalid lines are returned as <c><anno>HttpError</anno></c>.</p> - <p>Recognized request methods and header fields are returned as atoms. - Others are returned as strings. Strings of unrecognized header fields - are formatted with only capital letters first and after hyphen characters - (like <c>"Sec-Websocket-Key"</c>).</p> - <p>The protocol type <c>http</c> should only be used for - the first line when a <c><anno>HttpRequest</anno></c> or a - <c><anno>HttpResponse</anno></c> is expected. The following calls - should use <c>httph</c> to get <c><anno>HttpHeader</anno></c>'s until - <c>http_eoh</c> is returned that marks the end of the + <c><anno>HttpPacket</anno></c> described earlier. + A packet is either a + request, a response, a header, or an end of header + mark. Invalid lines are returned as + <c><anno>HttpError</anno></c>.</p> + <p>Recognized request methods and header fields are returned + as atoms. Others are returned as strings. Strings of + unrecognized header fields are formatted with only + capital letters first and after hyphen characters, for + example, <c>"Sec-Websocket-Key"</c>.</p> + <p>The protocol type <c>http</c> is only to be used for + the first line when an <c><anno>HttpRequest</anno></c> or an + <c><anno>HttpResponse</anno></c> is expected. + The following calls are to use <c>httph</c> to get + <c><anno>HttpHeader</anno></c>s until + <c>http_eoh</c> is returned, which marks the end of the headers and the beginning of any following message body.</p> - <p>The variants <c>http_bin</c> and <c>httph_bin</c> will return + <p>The variants <c>http_bin</c> and <c>httph_bin</c> return strings (<c>HttpString</c>) as binaries instead of lists.</p> </item> </taglist> <p>The following options are available:</p> <taglist> <tag><c>{packet_size, integer() >= 0}</c></tag> - <item><p>Sets the max allowed size of the packet body. If - the packet header indicates that the length of the - packet is longer than the max allowed length, the packet - is considered invalid. Default is 0 which means no - size limit.</p> + <item><p>Sets the maximum allowed size of the packet body. + If the packet header indicates that the length of the + packet is longer than the maximum allowed length, the + packet is considered invalid. Default is 0, which means + no size limit.</p> </item> <tag><c>{line_length, integer() >= 0}</c></tag> - <item><p>For packet type <c>line</c>, truncate lines longer - than the indicated length.</p> - <p>Option <c>line_length</c> also applies to <c>http*</c> - packet types as an alias for option <c>packet_size</c> in the - case when <c>packet_size</c> itself is not set. This usage is - only intended for backward compatibility.</p> + <item><p>For packet type <c>line</c>, lines longer than + the indicated length are truncated.</p> + <p>Option <c>line_length</c> also applies to <c>http*</c> + packet types as an alias for option <c>packet_size</c> + if <c>packet_size</c> itself is not set. This use is + only intended for backward compatibility.</p> + </item> + <tag><c>{line_delimiter, 0 =< byte() =< 255}</c></tag> + <item><p>For packet type <c>line</c>, sets the delimiting byte. + Default is the latin1 character <c>$\n</c>.</p> </item> </taglist> + <p>Examples:</p> <pre> > <input>erlang:decode_packet(1,<<3,"abcd">>,[]).</input> {ok,<<"abc">>,<<"d">>} @@ -909,13 +949,11 @@ <func> <name name="delete_element" arity="2"/> - <fsummary>Delete element at index in a tuple</fsummary> + <fsummary>Deletes element at index in a tuple.</fsummary> <type_desc variable="Index">1..tuple_size(<anno>Tuple1</anno>)</type_desc> <desc> - <p> - Returns a new tuple with element at <c><anno>Index</anno></c> removed from - tuple <c><anno>Tuple1</anno></c>. - </p> + <p>Returns a new tuple with element at <c><anno>Index</anno></c> + removed from tuple <c><anno>Tuple1</anno></c>, for example:</p> <pre> > <input>erlang:delete_element(2, {one, two, three}).</input> {one,three}</pre> @@ -924,45 +962,49 @@ <func> <name name="delete_module" arity="1"/> - <fsummary>Make the current code for a module old</fsummary> + <fsummary>Makes the current code for a module old.</fsummary> <desc> - <p>Makes the current code for <c><anno>Module</anno></c> become old code, and - deletes all references for this module from the export table. + <p>Makes the current code for <c><anno>Module</anno></c> become old code, + and deletes all references for this module from the export table. Returns <c>undefined</c> if the module does not exist, otherwise <c>true</c>.</p> <warning> <p>This BIF is intended for the code server (see - <seealso marker="kernel:code">code(3)</seealso>) and should not be - used elsewhere.</p> + <seealso marker="kernel:code">code(3)</seealso>) and is not + to be used elsewhere.</p> </warning> - <p>Failure: <c>badarg</c> if there is already an old version of + <p>Failure: <c>badarg</c> if there already is an old version of <c>Module</c>.</p> </desc> </func> + <func> <name name="demonitor" arity="1"/> - <fsummary>Stop monitoring</fsummary> + <fsummary>Stops monitoring.</fsummary> <desc> - <p>If <c><anno>MonitorRef</anno></c> is a reference which the calling process - obtained by calling + <p>If <c><anno>MonitorRef</anno></c> is a reference that the + calling process obtained by calling <seealso marker="#monitor/2">monitor/2</seealso>, this monitoring is turned off. If the monitoring is already turned off, nothing happens.</p> - <p>Once <c>demonitor(<anno>MonitorRef</anno>)</c> has returned it is - guaranteed that no <c>{'DOWN', <anno>MonitorRef</anno>, _, _, _}</c> message - due to the monitor will be placed in the caller's message queue - in the future. A <c>{'DOWN', <anno>MonitorRef</anno>, _, _, _}</c> message - might have been placed in the caller's message queue prior to - the call, though. Therefore, in most cases, it is advisable + <p>Once <c>demonitor(<anno>MonitorRef</anno>)</c> has returned, it is + guaranteed that no <c>{'DOWN', + <anno>MonitorRef</anno>, _, _, _}</c> message, + because of the monitor, will be placed in the caller message queue + in the future. A <c>{'DOWN', + <anno>MonitorRef</anno>, _, _, _}</c> message + can have been placed in the caller message queue before + the call, though. It is therefore usually advisable to remove such a <c>'DOWN'</c> message from the message queue - after monitoring has been stopped. - <seealso marker="#demonitor/2">demonitor(<anno>MonitorRef</anno>, [flush])</seealso> can be used instead of + after monitoring has been stopped. + <seealso marker="#demonitor/2"><c>demonitor(<anno>MonitorRef</anno>, [flush])</c></seealso> + can be used instead of <c>demonitor(<anno>MonitorRef</anno>)</c> if this cleanup is wanted.</p> <note> - <p>Prior to OTP release R11B (erts version 5.5) <c>demonitor/1</c> - behaved completely asynchronous, i.e., the monitor was active + <p>Prior to OTP release R11B (ERTS version 5.5) <c>demonitor/1</c> + behaved completely asynchronously, i.e., the monitor was active until the "demonitor signal" reached the monitored entity. This - had one undesirable effect, though. You could never know when + had one undesirable effect. You could never know when you were guaranteed <em>not</em> to receive a <c>DOWN</c> message due to the monitor.</p> <p>Current behavior can be viewed as two combined operations: @@ -971,31 +1013,31 @@ </note> <p>Failure: It is an error if <c><anno>MonitorRef</anno></c> refers to a monitoring started by another process. Not all such cases are - cheap to check; if checking is cheap, the call fails with - <c>badarg</c> (for example if <c><anno>MonitorRef</anno></c> is a remote - reference).</p> + cheap to check. If checking is cheap, the call fails with + <c>badarg</c> for example, if <c><anno>MonitorRef</anno></c> is a + remote reference.</p> </desc> </func> + <func> <name name="demonitor" arity="2"/> - <fsummary>Stop monitoring</fsummary> + <fsummary>Stops monitoring.</fsummary> <desc> <p>The returned value is <c>true</c> unless <c>info</c> is part - of <c><anno>OptionList</anno></c>. - </p> + of <c><anno>OptionList</anno></c>.</p> <p><c>demonitor(<anno>MonitorRef</anno>, [])</c> is equivalent to - <seealso marker="#demonitor/1">demonitor(<anno>MonitorRef</anno>)</seealso>.</p> - <p>Currently the following <c><anno>Option</anno></c>s are valid:</p> + <seealso marker="#demonitor/1"><c>demonitor(<anno>MonitorRef</anno>)</c></seealso>.</p> + <p>The available <c><anno>Option</anno></c>s are as follows:</p> <taglist> <tag><c>flush</c></tag> <item> - <p>Remove (one) <c>{_, <anno>MonitorRef</anno>, _, _, _}</c> message, - if there is one, from the caller's message queue after + <p>Removes (one) <c>{_, + <anno>MonitorRef</anno>, _, _, _}</c> message, + if there is one, from the caller message queue after monitoring has been stopped.</p> <p>Calling <c>demonitor(<anno>MonitorRef</anno>, [flush])</c> is equivalent to the following, but more efficient:</p> <code type="none"> - demonitor(MonitorRef), receive {_, MonitorRef, _, _, _} -> @@ -1006,78 +1048,90 @@ </item> <tag><c>info</c></tag> <item> - <p>The returned value is one of the following:</p> - <taglist> - <tag><c>true</c></tag> - <item><p>The monitor was found and removed. In this case - no <c>'DOWN'</c> message due to this monitor have - been nor will be placed in the message queue - of the caller. - </p> - </item> - <tag><c>false</c></tag> - <item><p>The monitor was not found and could not be removed. - This probably because someone already has placed a - <c>'DOWN'</c> message corresponding to this monitor - in the caller's message queue. - </p> - </item> - </taglist> - <p>If the <c>info</c> option is combined with the <c>flush</c> - option, <c>false</c> will be returned if a flush was needed; - otherwise, <c>true</c>. - </p> + <p>The returned value is one of the following:</p> + <taglist> + <tag><c>true</c></tag> + <item>The monitor was found and removed. In this case, + no <c>'DOWN'</c> message corresponding to this + monitor has been delivered and will not be delivered. + </item> + <tag><c>false</c></tag> + <item>The monitor was not found and could not be removed. + This probably because someone already has placed a + <c>'DOWN'</c> message corresponding to this monitor + in the caller message queue. + </item> + </taglist> + <p>If option <c>info</c> is combined with option <c>flush</c>, + <c>false</c> is returned if a flush was needed, + otherwise <c>true</c>.</p> </item> </taglist> <note> - <p>More options may be added in the future.</p> + <p>More options can be added in a future release.</p> </note> - <p>Failure: <c>badarg</c> if <c><anno>OptionList</anno></c> is not a list, or - if <c><anno>Option</anno></c> is not a valid option, or the same failure as for - <seealso marker="#demonitor/1">demonitor/1</seealso></p> + <p>Failures:</p> + <taglist> + <tag><c>badarg</c></tag> + <item>If <c><anno>OptionList</anno></c> is not a list. + </item> + <tag><c>badarg</c></tag> + <item>If <c><anno>Option</anno></c> is an invalid option. + </item> + <tag><c>badarg</c></tag> + <item>The same failure as for + <seealso marker="#demonitor/1">demonitor/1</seealso>. + </item> + </taglist> </desc> </func> + <func> <name name="disconnect_node" arity="1"/> - <fsummary>Force the disconnection of a node</fsummary> + <fsummary>Forces the disconnection of a node.</fsummary> <desc> - <p>Forces the disconnection of a node. This will appear to - the node <c><anno>Node</anno></c> as if the local node has crashed. This - BIF is mainly used in the Erlang network authentication - protocols. Returns <c>true</c> if disconnection succeeds, + <p>Forces the disconnection of a node. This appears to + the node <c><anno>Node</anno></c> as if the local node has crashed. + This BIF is mainly used in the Erlang network authentication + protocols.</p> + <p>Returns <c>true</c> if disconnection succeeds, otherwise <c>false</c>. If the local node is not alive, - the function returns <c>ignored</c>.</p> + <c>ignored</c> is returned.</p> </desc> </func> + <func> <name name="display" arity="1"/> - <fsummary>Print a term on standard output</fsummary> + <fsummary>Prints a term on standard output.</fsummary> <desc> - <p>Prints a text representation of <c><anno>Term</anno></c> on the standard - output. On OSE the term is printed to the ramlog.</p> + <p>Prints a text representation of <c><anno>Term</anno></c> on the + standard output. On OSE, the term is printed to the ramlog.</p> <warning> <p>This BIF is intended for debugging only.</p> </warning> </desc> </func> + <func> <name name="element" arity="2"/> + <fsummary>Returns the Nth element of a tuple.</fsummary> <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc> - <fsummary>Get Nth element of a tuple</fsummary> <desc> <p>Returns the <c><anno>N</anno></c>th element (numbering from 1) of - <c><anno>Tuple</anno></c>.</p> + <c><anno>Tuple</anno></c>, for example:</p> <pre> > <input>element(2, {a, b, c}).</input> b</pre> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="erase" arity="0"/> - <fsummary>Return and delete the process dictionary</fsummary> + <fsummary>Returns and deletes the process dictionary.</fsummary> <desc> - <p>Returns the process dictionary and deletes it.</p> + <p>Returns the process dictionary and deletes it, for + example:</p> <pre> > <input>put(key1, {1, 2, 3}),</input> <input>put(key2, [a, b, c]),</input> @@ -1085,13 +1139,16 @@ b</pre> [{key1,{1,2,3}},{key2,[a,b,c]}]</pre> </desc> </func> + <func> <name name="erase" arity="1"/> - <fsummary>Return and delete a value from the process dictionary</fsummary> + <fsummary>Returns and deletes a value from the process dictionary.</fsummary> <desc> - <p>Returns the value <c><anno>Val</anno></c> associated with <c><anno>Key</anno></c> and - deletes it from the process dictionary. Returns - <c>undefined</c> if no value is associated with <c><anno>Key</anno></c>.</p> + <p>Returns the value <c><anno>Val</anno></c> associated with + <c><anno>Key</anno></c> and deletes it from the process dictionary. + Returns <c>undefined</c> if no value is associated with + <c><anno>Key</anno></c>.</p> + <p>Example:</p> <pre> > <input>put(key1, {merry, lambs, are, playing}),</input> <input>X = erase(key1),</input> @@ -1099,16 +1156,19 @@ b</pre> {{merry,lambs,are,playing},undefined}</pre> </desc> </func> + <func> <name name="error" arity="1"/> - <fsummary>Stop execution with a given reason</fsummary> + <fsummary>Stops execution with a given reason.</fsummary> <desc> <p>Stops the execution of the calling process with the reason - <c><anno>Reason</anno></c>, where <c><anno>Reason</anno></c> is any term. The actual - exit reason will be <c>{<anno>Reason</anno>, Where}</c>, where <c>Where</c> + <c><anno>Reason</anno></c>, where <c><anno>Reason</anno></c> + is any term. The exit reason is + <c>{<anno>Reason</anno>, Where}</c>, where <c>Where</c> is a list of the functions most recently called (the current function first). Since evaluating this function causes the process to terminate, it has no return value.</p> + <p>Example:</p> <pre> > <input>catch error(foobar).</input> {'EXIT',{foobar,[{erl_eval,do_apply,5}, @@ -1118,29 +1178,34 @@ b</pre> {shell,eval_loop,3}]}}</pre> </desc> </func> + <func> <name name="error" arity="2"/> - <fsummary>Stop execution with a given reason</fsummary> + <fsummary>Stops execution with a given reason.</fsummary> <desc> <p>Stops the execution of the calling process with the reason - <c><anno>Reason</anno></c>, where <c><anno>Reason</anno></c> is any term. The actual - exit reason will be <c>{<anno>Reason</anno>, Where}</c>, where <c>Where</c> + <c><anno>Reason</anno></c>, where <c><anno>Reason</anno></c> + is any term. The exit reason is + <c>{<anno>Reason</anno>, Where}</c>, where <c>Where</c> is a list of the functions most recently called (the current - function first). <c><anno>Args</anno></c> is expected to be the list of - arguments for the current function; in Beam it will be used - to provide the actual arguments for the current function in - the <c>Where</c> term. Since evaluating this function causes + function first). <c><anno>Args</anno></c> is expected to be the + list of arguments for the current function; in Beam it is used + to provide the arguments for the current function in + the term <c>Where</c>. Since evaluating this function causes the process to terminate, it has no return value.</p> </desc> </func> + <func> <name name="exit" arity="1"/> - <fsummary>Stop execution with a given reason</fsummary> + <fsummary>Stops execution with a given reason.</fsummary> <desc> - <p>Stops the execution of the calling process with the exit - reason <c><anno>Reason</anno></c>, where <c><anno>Reason</anno></c> is any term. Since + <p>Stops the execution of the calling process with exit reason + <c><anno>Reason</anno></c>, where <c><anno>Reason</anno></c> + is any term. Since evaluating this function causes the process to terminate, it has no return value.</p> + <p>Example:</p> <pre> > <input>exit(foobar).</input> ** exception exit: foobar @@ -1148,110 +1213,117 @@ b</pre> {'EXIT',foobar}</pre> </desc> </func> + <func> <name name="exit" arity="2"/> - <fsummary>Send an exit signal to a process or a port</fsummary> + <fsummary>Sends an exit signal to a process or a port.</fsummary> <desc> <p>Sends an exit signal with exit reason <c><anno>Reason</anno></c> to the process or port identified by <c><anno>Pid</anno></c>.</p> - <p>The following behavior apply if <c><anno>Reason</anno></c> is any term - except <c>normal</c> or <c>kill</c>:</p> - <p>If <c><anno>Pid</anno></c> is not trapping exits, <c><anno>Pid</anno></c> itself will - exit with exit reason <c><anno>Reason</anno></c>. If <c><anno>Pid</anno></c> is trapping - exits, the exit signal is transformed into a message - <c>{'EXIT', From, <anno>Reason</anno>}</c> and delivered to the message - queue of <c><anno>Pid</anno></c>. <c>From</c> is the pid of the process - which sent the exit signal. See also - <seealso marker="#process_flag/2">process_flag/2</seealso>.</p> - <p>If <c><anno>Reason</anno></c> is the atom <c>normal</c>, <c><anno>Pid</anno></c> will - not exit. If it is trapping exits, the exit signal is - transformed into a message <c>{'EXIT', From, normal}</c> - and delivered to its message queue.</p> - <p>If <c><anno>Reason</anno></c> is the atom <c>kill</c>, that is if - <c>exit(<anno>Pid</anno>, kill)</c> is called, an untrappable exit signal - is sent to <c><anno>Pid</anno></c> which will unconditionally exit with - exit reason <c>killed</c>.</p> + <p>The following behavior applies if <c><anno>Reason</anno></c> + is any term, except <c>normal</c> or <c>kill</c>:</p> + <list type="bulleted"> + <item>If <c><anno>Pid</anno></c> is not trapping exits, + <c><anno>Pid</anno></c> + itself exits with exit reason <c><anno>Reason</anno></c>. + </item> + <item>If <c><anno>Pid</anno></c> is trapping exits, the exit + signal is transformed into a message + <c>{'EXIT', From, <anno>Reason</anno>}</c> + and delivered to the message queue of <c><anno>Pid</anno></c>. + </item> + <item><c>From</c> is the process identifier of the process + that sent the exit signal. See also + <seealso marker="#process_flag/2">process_flag/2</seealso>. + </item> + </list> + <p>If <c><anno>Reason</anno></c> is the atom <c>normal</c>, + <c><anno>Pid</anno></c> + does not exit. If it is trapping exits, the exit signal is + transformed into a message <c>{'EXIT', From, normal}</c> + and delivered to its message queue.</p> + <p>If <c><anno>Reason</anno></c> is the atom <c>kill</c>, + that is, if <c>exit(<anno>Pid</anno>, kill)</c> is called, + an untrappable exit signal is sent to <c><anno>Pid</anno></c>, + which unconditionally exits with exit reason <c>killed</c>. + </p> </desc> </func> + <func> <name name="external_size" arity="1"/> - <fsummary>Calculate the maximum size for a term encoded in the Erlang - external term format</fsummary> + <fsummary>Calculates the maximum size for a term encoded in the Erlang external term format.</fsummary> <desc> <p>Calculates, without doing the encoding, the maximum byte size for a term encoded in the Erlang external term format. The following condition applies always:</p> - <p> <pre> > <input>Size1 = byte_size(term_to_binary(<anno>Term</anno>)),</input> > <input>Size2 = erlang:external_size(<anno>Term</anno>),</input> > <input>true = Size1 =< Size2.</input> -true - </pre> - </p> - <p>This is equivalent to a call to: <code>erlang:external_size(<anno>Term</anno>, []) - </code></p> +true</pre> + <p>This is equivalent to a call to:</p> +<code>erlang:external_size(<anno>Term</anno>, [])</code> </desc> </func> + <func> <name name="external_size" arity="2"/> - <fsummary>Calculate the maximum size for a term encoded in the Erlang - external term format</fsummary> + <fsummary>Calculates the maximum size for a term encoded in the Erlang external term format.</fsummary> <desc> <p>Calculates, without doing the encoding, the maximum byte size for a term encoded in the Erlang external term format. The following condition applies always:</p> - <p> <pre> > <input>Size1 = byte_size(term_to_binary(<anno>Term</anno>, <anno>Options</anno>)),</input> > <input>Size2 = erlang:external_size(<anno>Term</anno>, <anno>Options</anno>),</input> > <input>true = Size1 =< Size2.</input> -true - </pre> - </p> - <p>The option <c>{minor_version, <anno>Version</anno>}</c> specifies how floats - are encoded. See - <seealso marker="#term_to_binary/2">term_to_binary/2</seealso> for - a more detailed description. - </p> +true</pre> + <p>Option <c>{minor_version, <anno>Version</anno>}</c> specifies how + floats are encoded. For a detailed description, see + <seealso marker="#term_to_binary/2">term_to_binary/2</seealso>.</p> </desc> </func> + <func> <name name="float" arity="1"/> - <fsummary>Convert a number to a float</fsummary> + <fsummary>Converts a number to a float.</fsummary> <desc> - <p>Returns a float by converting <c><anno>Number</anno></c> to a float.</p> + <p>Returns a float by converting <c><anno>Number</anno></c> to a float, + for example:</p> <pre> > <input>float(55).</input> 55.0</pre> <p>Allowed in guard tests.</p> <note> - <p>Note that if used on the top-level in a guard, it will - test whether the argument is a floating point number; for - clarity, use + <p>If used on the top level in a guard, it tests whether the + argument is a floating point number; for clarity, use <seealso marker="#is_float/1">is_float/1</seealso> instead.</p> <p>When <c>float/1</c> is used in an expression in a guard, such as '<c>float(A) == 4.0</c>', it converts a number as - described above.</p> + described earlier.</p> </note> </desc> </func> + <func> <name name="float_to_binary" arity="1"/> - <fsummary>Text representation of a float</fsummary> + <fsummary>Text representation of a float.</fsummary> <desc> - <p>The same as <c>float_to_binary(<anno>Float</anno>,[{scientific,20}])</c>.</p> + <p>The same as + <c>float_to_binary(<anno>Float</anno>,[{scientific,20}])</c>.</p> </desc> </func> + <func> <name name="float_to_binary" arity="2"/> - <fsummary>Text representation of a float formatted using given options</fsummary> + <fsummary>Text representation of a float formatted using given options.</fsummary> <desc> - <p>Returns a binary which corresponds to the text + <p>Returns a binary corresponding to the text representation of <c><anno>Float</anno></c> using fixed decimal - point formatting. The <c><anno>Options</anno></c> behave in the same - way as <seealso marker="#float_to_list/2">float_to_list/2</seealso>. - </p> + point formatting. <c><anno>Options</anno></c> behaves in the same + way as <seealso marker="#float_to_list/2">float_to_list/2</seealso>.</p> + <p>Examples:</p> <pre> > <input>float_to_binary(7.12, [{decimals, 4}]).</input> <<"7.1200">> @@ -1259,31 +1331,42 @@ true <<"7.12">></pre> </desc> </func> + <func> <name name="float_to_list" arity="1"/> - <fsummary>Text representation of a float</fsummary> + <fsummary>Text representation of a float.</fsummary> <desc> - <p>The same as <c>float_to_list(<anno>Float</anno>,[{scientific,20}])</c>.</p> + <p>The same as + <c>float_to_list(<anno>Float</anno>,[{scientific,20}])</c>.</p> </desc> </func> + <func> <name name="float_to_list" arity="2"/> - <fsummary>Text representation of a float formatted using given options</fsummary> - <desc> - <p>Returns a string which corresponds to the text - representation of <c>Float</c> using fixed decimal point formatting. - When <c>decimals</c> option is specified - the returned value will contain at most <c>Decimals</c> number of - digits past the decimal point. If the number doesn't fit in the - internal static buffer of 256 bytes, the function throws <c>badarg</c>. - When <c>compact</c> option is provided - the trailing zeros at the end of the list are truncated (this option is - only meaningful together with the <c>decimals</c> option). When - <c>scientific</c> option is provided, the float will be formatted using - scientific notation with <c>Decimals</c> digits of precision. If - <c>Options</c> is <c>[]</c> the function behaves like - <c><seealso marker="#float_to_list/1">float_to_list/1</seealso></c>. - </p> + <fsummary>Text representation of a float formatted using given options.</fsummary> + <desc> + <p>Returns a string corresponding to the text representation + of <c>Float</c> using fixed decimal point formatting. The + options are as follows:</p> + <list type="bulleted"> + <item>If option <c>decimals</c> is specified, the returned value + contains at most <c>Decimals</c> number of digits past the + decimal point. If the number does not fit in the internal + static buffer of 256 bytes, the function throws <c>badarg</c>. + </item> + <item>If option <c>compact</c> is provided, the trailing zeros + at the end of the list are truncated. This option is only + meaningful together with option <c>decimals</c>. + </item> + <item>If option <c>scientific</c> is provided, the float is + formatted using scientific notation with <c>Decimals</c> + digits of precision. + </item> + <item>If <c>Options</c> is <c>[]</c>, the function behaves as + <seealso marker="#float_to_list/1">float_to_list/1</seealso>. + </item> + </list> + <p>Examples:</p> <pre> > <input>float_to_list(7.12, [{decimals, 4}]).</input> "7.1200" @@ -1291,36 +1374,40 @@ true "7.12"</pre> </desc> </func> + <func> <name name="fun_info" arity="1"/> - <fsummary>Information about a fun</fsummary> + <fsummary>Information about a fun.</fsummary> <desc> - <p>Returns a list containing information about the fun - <c><anno>Fun</anno></c>. Each element of the list is a tuple. The order of - the tuples is not defined, and more tuples may be added in a + <p>Returns a list with information about the fun + <c><anno>Fun</anno></c>. Each list element is a tuple. The order + of the tuples is undefined, and more tuples can be added in a future release.</p> <warning> <p>This BIF is mainly intended for debugging, but it can - occasionally be useful in library functions that might need - to verify, for instance, the arity of a fun.</p> + sometimes be useful in library functions that need + to verify, for example, the arity of a fun.</p> </warning> - <p>There are two types of funs with slightly different - semantics:</p> - <p>A fun created by <c>fun M:F/A</c> is called an - <em>external</em> fun. Calling it will always call the - function <c>F</c> with arity <c>A</c> in the latest code for - module <c>M</c>. Note that module <c>M</c> does not even need - to be loaded when the fun <c>fun M:F/A</c> is created.</p> - <p>All other funs are called <em>local</em>. When a local fun - is called, the same version of the code that created the fun - will be called (even if newer version of the module has been - loaded).</p> - <p>The following elements will always be present in the list + <p>Two types of funs have slightly different semantics:</p> + <list type="bulleted"> + <item>A fun created by <c>fun M:F/A</c> is called an + <em>external</em> fun. Calling it will always call the + function <c>F</c> with arity <c>A</c> in the latest code for + module <c>M</c>. Notice that module <c>M</c> does not even + need to be loaded when the fun <c>fun M:F/A</c> is created. + </item> + <item>All other funs are called <em>local</em>. When a local fun + is called, the same version of the code that created the fun + is called (even if a newer version of the module has been + loaded). + </item> + </list> + <p>The following elements are always present in the list for both local and external funs:</p> <taglist> <tag><c>{type, Type}</c></tag> <item> - <p><c>Type</c> is either <c>local</c> or <c>external</c>.</p> + <p><c>Type</c> is <c>local</c> or <c>external</c>.</p> </item> <tag><c>{module, Module}</c></tag> <item> @@ -1335,148 +1422,154 @@ true <p><c>Name</c> (an atom) is a function name.</p> <p>If <c>Fun</c> is a local fun, <c>Name</c> is the name of the local function that implements the fun. - (This name was generated by the compiler, and is generally + (This name was generated by the compiler, and is only of informational use. As it is a local function, it - is not possible to call it directly.) + cannot be called directly.) If no code is currently loaded for the fun, <c>[]</c> - will be returned instead of an atom.</p> + is returned instead of an atom.</p> <p>If <c>Fun</c> is an external fun, <c>Name</c> is the name of the exported function that the fun refers to.</p> </item> <tag><c>{arity, Arity}</c></tag> <item> <p><c>Arity</c> is the number of arguments that the fun - should be called with.</p> + is to be called with.</p> </item> <tag><c>{env, Env}</c></tag> <item> <p><c>Env</c> (a list) is the environment or free variables - for the fun. (For external funs, the returned list is - always empty.)</p> + for the fun. For external funs, the returned list is + always empty.</p> </item> </taglist> - <p>The following elements will only be present in the list if + <p>The following elements are only present in the list if <c>Fun</c> is local:</p> <taglist> <tag><c>{pid, Pid}</c></tag> <item> - <p><c>Pid</c> is the pid of the process that originally - created the fun.</p> + <p><c>Pid</c> is the process identifier of the process + that originally created the fun.</p> </item> <tag><c>{index, Index}</c></tag> <item> - <p><c>Index</c> (an integer) is an index into the module's + <p><c>Index</c> (an integer) is an index into the module fun table.</p> </item> <tag><c>{new_index, Index}</c></tag> <item> - <p><c>Index</c> (an integer) is an index into the module's + <p><c>Index</c> (an integer) is an index into the module fun table.</p> </item> <tag><c>{new_uniq, Uniq}</c></tag> <item> - <p><c>Uniq</c> (a binary) is a unique value for this fun. - It is calculated from the compiled code for the entire module.</p> + <p><c>Uniq</c> (a binary) is a unique value for this fun. It + is calculated from the compiled code for the entire module.</p> </item> <tag><c>{uniq, Uniq}</c></tag> <item> <p><c>Uniq</c> (an integer) is a unique value for this fun. - Starting in the R15 release, this integer is calculated from - the compiled code for the entire module. Before R15, this - integer was based on only the body of the fun. - </p> + As from OTP R15, this integer is calculated from the + compiled code for the entire module. Before OTP R15, this + integer was based on only the body of the fun.</p> </item> </taglist> </desc> </func> + <func> <name name="fun_info" arity="2"/> + <fsummary>Information about a fun.</fsummary> <type name="fun_info_item"/> - <fsummary>Information about a fun</fsummary> <desc> <p>Returns information about <c><anno>Fun</anno></c> as specified by - <c><anno>Item</anno></c>, in the form <c>{<anno>Item</anno>,<anno>Info</anno>}</c>.</p> + <c><anno>Item</anno></c>, in the form + <c>{<anno>Item</anno>,<anno>Info</anno>}</c>.</p> <p>For any fun, <c><anno>Item</anno></c> can be any of the atoms - <c>module</c>, <c>name</c>, <c>arity</c>, <c>env</c>, or <c>type</c>.</p> - <p>For a local fun, <c><anno>Item</anno></c> can also be any of the atoms - <c>index</c>, <c>new_index</c>, <c>new_uniq</c>, + <c>module</c>, <c>name</c>, <c>arity</c>, <c>env</c>, or + <c>type</c>.</p> + <p>For a local fun, <c><anno>Item</anno></c> can also be any of the + atoms <c>index</c>, <c>new_index</c>, <c>new_uniq</c>, <c>uniq</c>, and <c>pid</c>. For an external fun, the value of any of these items is always the atom <c>undefined</c>.</p> <p>See <seealso marker="#fun_info/1">erlang:fun_info/1</seealso>.</p> </desc> </func> + <func> <name name="fun_to_list" arity="1"/> - <fsummary>Text representation of a fun</fsummary> + <fsummary>Text representation of a fun.</fsummary> <desc> - <p>Returns a string which corresponds to the text + <p>Returns a string corresponding to the text representation of <c><anno>Fun</anno></c>.</p> </desc> </func> + <func> <name name="function_exported" arity="3"/> - <fsummary>Check if a function is exported and loaded</fsummary> + <fsummary>Checks if a function is exported and loaded.</fsummary> <desc> <p>Returns <c>true</c> if the module <c><anno>Module</anno></c> is loaded and contains an exported function <c><anno>Function</anno>/<anno>Arity</anno></c>, or if there is a BIF (a built-in function implemented in C) - with the given name; otherwise returns <c>false</c>.</p> + with the given name, otherwise returns <c>false</c>.</p> <note><p>This function used to return false for built-in functions before the 18.0 release.</p></note> </desc> </func> + <func> <name name="garbage_collect" arity="0"/> - <fsummary>Force an immediate garbage collection of the calling process</fsummary> + <fsummary>Forces an immediate garbage collection of the calling process.</fsummary> <desc> - <p>Forces an immediate garbage collection of the currently - executing process. The function should not be used, unless - it has been noticed -- or there are good reasons to suspect -- + <p>Forces an immediate garbage collection of the + executing process. The function is not to be used unless + it has been noticed (or there are good reasons to suspect) that the spontaneous garbage collection will occur too late - or not at all. Improper use may seriously degrade system - performance.</p> + or not at all.</p> + <warning> + <p>Improper use can seriously degrade system performance.</p> + </warning> </desc> </func> + <func> <name name="garbage_collect" arity="1"/> - <fsummary>Garbage collect a process</fsummary> + <fsummary>Garbage collects a process.</fsummary> <desc> <p>The same as <seealso marker="#garbage_collect/2"><c>garbage_collect(<anno>Pid</anno>, [])</c></seealso>.</p> </desc> </func> + <func> <name name="garbage_collect" arity="2"/> - <fsummary>Garbage collect a process</fsummary> + <fsummary>Garbage collects a process.</fsummary> <desc> - <p>Garbage collect the node local process identified by - <c><anno>Pid</anno></c>.</p> - <p>Currently available <c><anno>Option</anno></c>s:</p> + <p>Garbage collects the node local process identified by + <c><anno>Pid</anno></c>.</p> + <p>The available <c><anno>Option</anno></c>s are as follows:</p> <taglist> <tag><c>{async, RequestId}</c></tag> - <item> - The <c>garbage_collect/2</c> function will return + <item>The function <c>garbage_collect/2</c> returns the value <c>async</c> immediately after the request has been sent. When the request has been processed, the - process that called this function will be passed a - message on the form:<br/> - <c>{garbage_collect, <anno>RequestId</anno>, <anno>GCResult</anno>}</c>. - </item> + process that called this function is passed a message on + the form <c>{garbage_collect, + <anno>RequestId</anno>, <anno>GCResult</anno>}</c>. + </item> </taglist> <p>If <c><anno>Pid</anno></c> equals <c>self()</c>, and no <c>async</c> option has been passed, the garbage - collection will be performed at once, i.e. the same as - calling + collection is performed at once, that is, the same as calling <seealso marker="#garbage_collect/0">garbage_collect/0</seealso>. - In all other cases a request for garbage collection will - be sent to the process identified by <c><anno>Pid</anno></c>, + Otherwise a request for garbage collection + is sent to the process identified by <c><anno>Pid</anno></c>, and will be handled when appropriate. If no <c>async</c> - option has been passed, the caller will block until - <c><anno>GCResult</anno></c> is available and can be - returned.</p> + option has been passed, the caller blocks until + <c><anno>GCResult</anno></c> is available and can be returned.</p> <p><c><anno>GCResult</anno></c> informs about the result of - the garbage collection request:</p> + the garbage collection request as follows:</p> <taglist> <tag><c>true</c></tag> <item> @@ -1485,14 +1578,13 @@ true </item> <tag><c>false</c></tag> <item> - No garbage collection was performed. This since the + No garbage collection was performed, as the process identified by <c><anno>Pid</anno></c> terminated before the request could be satisfied. </item> </taglist> - <p>Note that the same caveats as for - <seealso marker="#garbage_collect/0">garbage_collect/0</seealso> - apply.</p> + <p>Notice that the same caveats apply as for + <seealso marker="#garbage_collect/0">garbage_collect/0</seealso>.</p> <p>Failures:</p> <taglist> <tag><c>badarg</c></tag> @@ -1501,17 +1593,18 @@ true </item> <tag><c>badarg</c></tag> <item> - If <c><anno>OptionList</anno></c> is not a valid list of options. + If <c><anno>OptionList</anno></c> is an invalid list of options. </item> </taglist> </desc> </func> + <func> <name name="get" arity="0"/> - <fsummary>Return the process dictionary</fsummary> + <fsummary>Returns the process dictionary.</fsummary> <desc> <p>Returns the process dictionary as a list of - <c>{<anno>Key</anno>, <anno>Val</anno>}</c> tuples.</p> + <c>{<anno>Key</anno>, <anno>Val</anno>}</c> tuples, for example:</p> <pre> > <input>put(key1, merry),</input> <input>put(key2, lambs),</input> @@ -1520,13 +1613,15 @@ true [{key1,merry},{key2,lambs},{key3,{are,playing}}]</pre> </desc> </func> + <func> <name name="get" arity="1"/> - <fsummary>Return a value from the process dictionary</fsummary> + <fsummary>Returns a value from the process dictionary.</fsummary> <desc> <p>Returns the value <c><anno>Val</anno></c> associated with <c><anno>Key</anno></c> in the process dictionary, or <c>undefined</c> if <c><anno>Key</anno></c> does not exist.</p> + <p>Example:</p> <pre> > <input>put(key1, merry),</input> <input>put(key2, lambs),</input> @@ -1535,14 +1630,16 @@ true {are,playing}</pre> </desc> </func> + <func> <name name="get_cookie" arity="0"/> - <fsummary>Get the magic cookie of the local node</fsummary> + <fsummary>Gets the magic cookie of the local node.</fsummary> <desc> - <p>Returns the magic cookie of the local node, if the node is - alive; otherwise the atom <c>nocookie</c>.</p> + <p>Returns the magic cookie of the local node if the node is + alive, otherwise the atom <c>nocookie</c>.</p> </desc> </func> + <func> <name name="get_keys" arity="0"/> <fsummary>Return a list of all keys from the process dictionary</fsummary> @@ -1558,10 +1655,10 @@ true </func> <func> <name name="get_keys" arity="1"/> - <fsummary>Return a list of keys from the process dictionary</fsummary> + <fsummary>Returns a list of keys from the process dictionary.</fsummary> <desc> - <p>Returns a list of keys which are associated with the value - <c><anno>Val</anno></c> in the process dictionary.</p> + <p>Returns a list of keys that are associated with the value + <c><anno>Val</anno></c> in the process dictionary, for example:</p> <pre> > <input>put(mary, {1, 2}),</input> <input>put(had, {1, 2}),</input> @@ -1573,40 +1670,40 @@ true [mary,had,a,little,lamb]</pre> </desc> </func> + <func> <name name="get_stacktrace" arity="0"/> - <fsummary>Get the call stack back-trace of the last exception</fsummary> + <fsummary>Gets the call stack back-trace of the last exception.</fsummary> <type name="stack_item"/> <desc> - <p>Get the call stack back-trace (<em>stacktrace</em>) of the last - exception in the calling process as a list of + <p>Gets the call stack back-trace (<em>stacktrace</em>) of the + last exception in the calling process as a list of <c>{<anno>Module</anno>,<anno>Function</anno>,<anno>Arity</anno>,<anno>Location</anno>}</c> tuples. - The <c><anno>Arity</anno></c> field in the first tuple may be the argument - list of that function call instead of an arity integer, + Field <c><anno>Arity</anno></c> in the first tuple can be the + argument list of that function call instead of an arity integer, depending on the exception.</p> <p>If there has not been any exceptions in a process, the stacktrace is <c>[]</c>. After a code change for the process, - the stacktrace may also be reset to [].</p> + the stacktrace can also be reset to <c>[]</c>.</p> <p>The stacktrace is the same data as the <c>catch</c> operator returns, for example:</p> <p><c>{'EXIT',{badarg,Stacktrace}} = catch abs(x)</c></p> - <p><c><anno>Location</anno></c> is a (possibly empty) list of two-tuples that - may indicate the location in the source code of the function. - The first element is an atom that describes the type of - information in the second element. Currently the following - items may occur:</p> + <p><c><anno>Location</anno></c> is a (possibly empty) list + of two-tuples that + can indicate the location in the source code of the function. + The first element is an atom describing the type of + information in the second element. The following + items can occur:</p> <taglist> <tag><c>file</c></tag> - <item> - <p>The second element of the tuple is a string (list of - characters) representing the filename of the source file - of the function.</p> + <item>The second element of the tuple is a string (list of + characters) representing the file name of the source file + of the function. </item> <tag><c>line</c></tag> - <item> - <p>The second element of the tuple is the line number + <item>The second element of the tuple is the line number (an integer greater than zero) in the source file - where the exception occurred or the function was called.</p> + where the exception occurred or the function was called. </item> </taglist> <p>See also @@ -1614,49 +1711,56 @@ true <seealso marker="#error/2">erlang:error/2</seealso>.</p> </desc> </func> + <func> <name name="group_leader" arity="0"/> - <fsummary>Get the group leader for the calling process</fsummary> + <fsummary>Gets the group leader for the calling process.</fsummary> <desc> - <p>Returns the pid of the group leader for the process which - evaluates the function.</p> + <p>Returns the process identifier of the group leader for the + process evaluating the function.</p> <p>Every process is a member of some process group and all - groups have a <em>group leader</em>. All IO from the group + groups have a <em>group leader</em>. All I/O from the group is channeled to the group leader. When a new process is spawned, it gets the same group leader as the spawning process. Initially, at system start-up, <c>init</c> is both its own group leader and the group leader of all processes.</p> </desc> </func> + <func> <name name="group_leader" arity="2"/> - <fsummary>Set the group leader for a process</fsummary> + <fsummary>Sets the group leader for a process.</fsummary> <desc> - <p>Sets the group leader of <c><anno>Pid</anno></c> to <c><anno>GroupLeader</anno></c>. - Typically, this is used when a processes started from a - certain shell should have another group leader than + <p>Sets the group leader of <c><anno>Pid</anno></c> + to <c><anno>GroupLeader</anno></c>. + Typically, this is used when a process started from a + certain shell is to have another group leader than <c>init</c>.</p> <p>See also <seealso marker="#group_leader/0">group_leader/0</seealso>.</p> </desc> </func> + <func> <name name="halt" arity="0"/> - <fsummary>Halt the Erlang runtime system and indicate normal exit to the calling environment</fsummary> + <fsummary>Halts the Erlang runtime system and indicates normal exit to the calling environment.</fsummary> <desc> <p>The same as <seealso marker="#halt/2"><c>halt(0, [])</c></seealso>.</p> + <p>Example:</p> <pre> > <input>halt().</input> os_prompt% </pre> </desc> </func> + <func> <name name="halt" arity="1"/> - <fsummary>Halt the Erlang runtime system</fsummary> + <fsummary>Halts the Erlang runtime system.</fsummary> <desc> <p>The same as <seealso marker="#halt/2"><c>halt(<anno>Status</anno>, [])</c></seealso>.</p> + <p>Example:</p> <pre> > <input>halt(17).</input> os_prompt% <input>echo $?</input> @@ -1664,178 +1768,189 @@ os_prompt% <input>echo $?</input> os_prompt% </pre> </desc> </func> + <func> <name name="halt" arity="2"/> - <fsummary>Halt the Erlang runtime system</fsummary> + <fsummary>Halts the Erlang runtime system.</fsummary> <desc> <p><c><anno>Status</anno></c> must be a non-negative integer, a string, or the atom <c>abort</c>. Halts the Erlang runtime system. Has no return value. - Depending on <c><anno>Status</anno></c>: - </p> + Depending on <c><anno>Status</anno></c>, the following occurs:</p> <taglist> <tag>integer()</tag> - <item>The runtime system exits with the integer value <c><anno>Status</anno></c> - as status code to the calling environment (operating system). + <item>The runtime system exits with integer value + <c><anno>Status</anno></c> + as status code to the calling environment (OS). </item> <tag>string()</tag> - <item>An erlang crash dump is produced with <c><anno>Status</anno></c> as slogan, - and then the runtime system exits with status code <c>1</c>. + <item>An Erlang crash dump is produced with <c><anno>Status</anno></c> + as slogan. Then the runtime system exits with status code <c>1</c>. </item> <tag><c>abort</c></tag> <item> The runtime system aborts producing a core dump, if that is - enabled in the operating system. + enabled in the OS. </item> </taglist> - <p>Note that on many platforms, only the status codes 0-255 are - supported by the operating system. - </p> - <p>For integer <c><anno>Status</anno></c> the Erlang runtime system closes all ports - and allows async threads to finish their operations before exiting. - To exit without such flushing use - <c><anno>Option</anno></c> as <c>{flush,false}</c>. - </p> - <p>For statuses <c>string()</c> and <c>abort</c> the <c>flush</c> - option is ignored and flushing is <em>not</em> done. - </p> + <note><p>On many platforms, the OS supports only status + codes 0-255. A too large status code will be truncated by clearing + the high bits.</p></note> + <p>For integer <c><anno>Status</anno></c>, the Erlang runtime system + closes all ports and allows async threads to finish their + operations before exiting. To exit without such flushing, use + <c><anno>Option</anno></c> as <c>{flush,false}</c>.</p> + <p>For statuses <c>string()</c> and <c>abort</c>, option + <c>flush</c> is ignored and flushing is <em>not</em> done.</p> </desc> </func> + <func> <name name="hash" arity="2"/> - <fsummary>Hash function (deprecated)</fsummary> + <fsummary>Hash function (deprecated).</fsummary> <desc> <p>Returns a hash value for <c><anno>Term</anno></c> within the range - <c>1..<anno>Range</anno></c>. The allowed range is 1..2^27-1.</p> + <c>1..<anno>Range</anno></c>. The maximum range is 1..2^27-1.</p> <warning> - <p>This BIF is deprecated as the hash value may differ on - different architectures. Also the hash values for integer - terms larger than 2^27 as well as large binaries are very + <p>This BIF is deprecated, as the hash value can differ on + different architectures. The hash values for integer + terms higher than 2^27 and large binaries are poor. The BIF is retained for backward compatibility - reasons (it may have been used to hash records into a file), - but all new code should use one of the BIFs + reasons (it can have been used to hash records into a file), + but all new code is to use one of the BIFs <c>erlang:phash/2</c> or <c>erlang:phash2/1,2</c> instead.</p> </warning> </desc> </func> + <func> <name name="hd" arity="1"/> - <fsummary>Head of a list</fsummary> + <fsummary>Head of a list.</fsummary> <desc> - <p>Returns the head of <c><anno>List</anno></c>, that is, the first element.</p> + <p>Returns the head of <c><anno>List</anno></c>, that is, + the first element, for example:</p> <pre> > <input>hd([1,2,3,4,5]).</input> 1</pre> <p>Allowed in guard tests.</p> - <p>Failure: <c>badarg</c> if <c><anno>List</anno></c> is the empty list [].</p> + <p>Failure: <c>badarg</c> if <c><anno>List</anno></c> is the empty + list <c>[]</c>.</p> </desc> </func> + <func> <name name="hibernate" arity="3"/> - <fsummary>Hibernate a process until a message is sent to it</fsummary> + <fsummary>Hibernates a process until a message is sent to it.</fsummary> <desc> <p>Puts the calling process into a wait state where its memory - allocation has been reduced as much as possible, which is + allocation has been reduced as much as possible. This is useful if the process does not expect to receive any messages - in the near future.</p> - <p>The process will be awaken when a message is sent to it, and - control will resume in <c><anno>Module</anno>:<anno>Function</anno></c> with - the arguments given by <c><anno>Args</anno></c> with the call stack - emptied, meaning that the process will terminate when that - function returns. Thus <c>erlang:hibernate/3</c> will never - return to its caller.</p> + soon.</p> + <p>The process is awaken when a message is sent to it, and control + resumes in <c><anno>Module</anno>:<anno>Function</anno></c> with + the arguments given by <c><anno>Args</anno></c> with the call + stack emptied, meaning that the process terminates when that + function returns. Thus <c>erlang:hibernate/3</c> never + returns to its caller.</p> <p>If the process has any message in its message queue, - the process will be awaken immediately in the same way as - described above.</p> + the process is awakened immediately in the same way as + described earlier.</p> <p>In more technical terms, what <c>erlang:hibernate/3</c> does - is the following. It discards the call stack for the process. - Then it garbage collects the process. After the garbage - collection, all live data is in one continuous heap. The heap + is the following. It discards the call stack for the process, + and then garbage collects the process. After this, + all live data is in one continuous heap. The heap is then shrunken to the exact same size as the live data - which it holds (even if that size is less than the minimum + that it holds (even if that size is less than the minimum heap size for the process).</p> <p>If the size of the live data in the process is less than the minimum heap size, the first garbage collection occurring - after the process has been awaken will ensure that the heap + after the process is awakened ensures that the heap size is changed to a size not smaller than the minimum heap size.</p> - <p>Note that emptying the call stack means that any surrounding - <c>catch</c> is removed and has to be re-inserted after + <p>Notice that emptying the call stack means that any surrounding + <c>catch</c> is removed and must be reinserted after hibernation. One effect of this is that processes started using <c>proc_lib</c> (also indirectly, such as - <c>gen_server</c> processes), should use + <c>gen_server</c> processes), are to use <seealso marker="stdlib:proc_lib#hibernate/3">proc_lib:hibernate/3</seealso> - instead to ensure that the exception handler continues to work + instead, to ensure that the exception handler continues to work when the process wakes up.</p> </desc> </func> <func> <name name="insert_element" arity="3"/> - <fsummary>Insert an element at index in a tuple</fsummary> + <fsummary>Inserts an element at index in a tuple.</fsummary> <type_desc variable="Index">1..tuple_size(<anno>Tuple1</anno>) + 1</type_desc> <desc> - <p> - Returns a new tuple with element <c><anno>Term</anno></c> insert at position - <c><anno>Index</anno></c> in tuple <c><anno>Tuple1</anno></c>. - All elements from position <c><anno>Index</anno></c> and upwards are subsequently - pushed one step higher in the new tuple <c><anno>Tuple2</anno></c>. - </p> + <p>Returns a new tuple with element <c><anno>Term</anno></c> + inserted at position + <c><anno>Index</anno></c> in tuple <c><anno>Tuple1</anno></c>. + All elements from position <c><anno>Index</anno></c> and upwards are + pushed one step higher in the new tuple <c><anno>Tuple2</anno></c>.</p> + <p>Example:</p> <pre> > <input>erlang:insert_element(2, {one, two, three}, new).</input> {one,new,two,three}</pre> </desc> </func> + <func> <name name="integer_to_binary" arity="1"/> - <fsummary>Text representation of an integer</fsummary> + <fsummary>Text representation of an integer.</fsummary> <desc> - <p>Returns a binary which corresponds to the text - representation of <c><anno>Integer</anno></c>.</p> + <p>Returns a binary corresponding to the text + representation of <c><anno>Integer</anno></c>, for example:</p> <pre> > <input>integer_to_binary(77).</input> <<"77">></pre> </desc> </func> + <func> <name name="integer_to_binary" arity="2"/> - <fsummary>Text representation of an integer</fsummary> + <fsummary>Text representation of an integer.</fsummary> <desc> - <p>Returns a binary which corresponds to the text - representation of <c><anno>Integer</anno></c> in base <c><anno>Base</anno></c>.</p> + <p>Returns a binary corresponding to the text + representation of <c><anno>Integer</anno></c> in base + <c><anno>Base</anno></c>, for example:</p> <pre> > <input>integer_to_binary(1023, 16).</input> <<"3FF">></pre> </desc> </func> + <func> <name name="integer_to_list" arity="1"/> - <fsummary>Text representation of an integer</fsummary> + <fsummary>Text representation of an integer.</fsummary> <desc> - <p>Returns a string which corresponds to the text - representation of <c><anno>Integer</anno></c>.</p> + <p>Returns a string corresponding to the text + representation of <c><anno>Integer</anno></c>, for example:</p> <pre> > <input>integer_to_list(77).</input> "77"</pre> </desc> </func> + <func> <name name="integer_to_list" arity="2"/> - <fsummary>Text representation of an integer</fsummary> + <fsummary>Text representation of an integer.</fsummary> <desc> - <p>Returns a string which corresponds to the text - representation of <c><anno>Integer</anno></c> in base <c><anno>Base</anno></c>.</p> + <p>Returns a string corresponding to the text + representation of <c><anno>Integer</anno></c> in base + <c><anno>Base</anno></c>, for example:</p> <pre> > <input>integer_to_list(1023, 16).</input> "3FF"</pre> </desc> </func> + <func> <name name="iolist_to_binary" arity="1"/> - <fsummary>Convert an iolist to a binary</fsummary> + <fsummary>Converts an iolist to a binary.</fsummary> <desc> - <p>Returns a binary which is made from the integers and - binaries in <c><anno>IoListOrBinary</anno></c>.</p> + <p>Returns a binary that is made from the integers and + binaries in <c><anno>IoListOrBinary</anno></c>, for example:</p> <pre> > <input>Bin1 = <<1,2,3>>.</input> <<1,2,3>> @@ -1847,278 +1962,311 @@ os_prompt% </pre> <<1,2,3,1,2,3,4,5,4,6>></pre> </desc> </func> + <func> <name name="iolist_size" arity="1"/> - <fsummary>Size of an iolist</fsummary> + <fsummary>Size of an iolist.</fsummary> <desc> - <p>Returns an integer which is the size in bytes - of the binary that would be the result of - <c>iolist_to_binary(<anno>Item</anno>)</c>.</p> + <p>Returns an integer that is the size in bytes + of the binary that would be the result of + <c>iolist_to_binary(<anno>Item</anno>)</c>, for example:</p> <pre> > <input>iolist_size([1,2|<<3,4>>]).</input> 4</pre> </desc> </func> + <func> <name name="is_alive" arity="0"/> - <fsummary>Check whether the local node is alive</fsummary> + <fsummary>Checks whether the local node is alive.</fsummary> <desc> - <p>Returns <c>true</c> if the local node is alive; that is, if - the node can be part of a distributed system. Otherwise, it - returns <c>false</c>.</p> + <p>Returns <c>true</c> if the local node is alive (that is, if + the node can be part of a distributed system), otherwise + <c>false</c>.</p> </desc> </func> + <func> <name name="is_atom" arity="1"/> - <fsummary>Check whether a term is an atom</fsummary> + <fsummary>Checks whether a term is an atom.</fsummary> <desc> - <p>Returns <c>true</c> if <c><anno>Term</anno></c> is an atom; - otherwise returns <c>false</c>.</p> + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is an atom, + otherwise <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="is_binary" arity="1"/> - <fsummary>Check whether a term is a binary</fsummary> + <fsummary>Checks whether a term is a binary.</fsummary> <desc> - <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a binary; - otherwise returns <c>false</c>.</p> - + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a binary, + otherwise <c>false</c>.</p> <p>A binary always contains a complete number of bytes.</p> - <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="is_bitstring" arity="1"/> - <fsummary>Check whether a term is a bitstring</fsummary> + <fsummary>Checks whether a term is a bitstring.</fsummary> <desc> - <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a bitstring (including a binary); - otherwise returns <c>false</c>.</p> - + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a + bitstring (including a binary), otherwise <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="is_boolean" arity="1"/> - <fsummary>Check whether a term is a boolean</fsummary> + <fsummary>Checks whether a term is a boolean.</fsummary> <desc> - <p>Returns <c>true</c> if <c><anno>Term</anno></c> is - either the atom <c>true</c> or the atom <c>false</c> - (i.e. a boolean); otherwise returns <c>false</c>.</p> + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is the + atom <c>true</c> or the atom <c>false</c> (that is, a boolean). + Otherwise returns <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="is_builtin" arity="3"/> - <fsummary>Check if a function is a BIF implemented in C</fsummary> + <fsummary>Checks if a function is a BIF implemented in C.</fsummary> <desc> - <p>Returns <c>true</c> if <c><anno>Module</anno>:<anno>Function</anno>/<anno>Arity</anno></c> is - a BIF implemented in C; otherwise returns <c>false</c>. - This BIF is useful for builders of cross reference tools.</p> + <p>This BIF is useful for builders of cross-reference tools.</p> + <p>Returns <c>true</c> if + <c><anno>Module</anno>:<anno>Function</anno>/<anno>Arity</anno></c> + is a BIF implemented in C, otherwise <c>false</c>.</p> </desc> </func> + <func> <name name="is_float" arity="1"/> - <fsummary>Check whether a term is a float</fsummary> + <fsummary>Checks whether a term is a float.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a floating point - number; otherwise returns <c>false</c>.</p> + number, otherwise <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="is_function" arity="1"/> - <fsummary>Check whether a term is a fun</fsummary> + <fsummary>Checks whether a term is a fun.</fsummary> <desc> - <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a fun; otherwise - returns <c>false</c>.</p> + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a fun, otherwise + <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="is_function" arity="2"/> - <fsummary>Check whether a term is a fun with a given arity</fsummary> + <fsummary>Checks whether a term is a fun with a given arity.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a fun that can be - applied with <c><anno>Arity</anno></c> number of arguments; otherwise - returns <c>false</c>.</p> + applied with <c><anno>Arity</anno></c> number of arguments, otherwise + <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="is_integer" arity="1"/> - <fsummary>Check whether a term is an integer</fsummary> + <fsummary>Checks whether a term is an integer.</fsummary> <desc> - <p>Returns <c>true</c> if <c><anno>Term</anno></c> is an integer; - otherwise returns <c>false</c>.</p> + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is an integer, + otherwise <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="is_list" arity="1"/> - <fsummary>Check whether a term is a list</fsummary> + <fsummary>Checks whether a term is a list.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a list with - zero or more elements; otherwise returns <c>false</c>.</p> + zero or more elements, otherwise <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="is_map" arity="1"/> - <fsummary>Check whether a term is a map</fsummary> + <fsummary>Checks whether a term is a map.</fsummary> <desc> - <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a map; - otherwise returns <c>false</c>.</p> + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a map, + otherwise <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="is_number" arity="1"/> - <fsummary>Check whether a term is a number</fsummary> + <fsummary>Checks whether a term is a number.</fsummary> <desc> - <p>Returns <c>true</c> if <c><anno>Term</anno></c> is either an integer or a - floating point number; otherwise returns <c>false</c>.</p> + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is an integer or a + floating point number. Otherwise returns <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="is_pid" arity="1"/> - <fsummary>Check whether a term is a pid</fsummary> + <fsummary>Checks whether a term is a process identifier.</fsummary> <desc> - <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a pid (process - identifier); otherwise returns <c>false</c>.</p> + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a process + identifier, otherwise <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="is_port" arity="1"/> - <fsummary>Check whether a term is a port</fsummary> + <fsummary>Checks whether a term is a port.</fsummary> <desc> - <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a port identifier; - otherwise returns <c>false</c>.</p> + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a port identifier, + otherwise <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="is_process_alive" arity="1"/> - <fsummary>Check whether a process is alive</fsummary> + <fsummary>Checks whether a process is alive.</fsummary> <desc> - <p> - <c><anno>Pid</anno></c> must refer to a process at the local node. - Returns <c>true</c> if the process exists and is alive, that - is, is not exiting and has not exited. Otherwise, returns + <p><c><anno>Pid</anno></c> must refer to a process at the local node.</p> + <p>Returns <c>true</c> if the process exists and is alive, that + is, is not exiting and has not exited. Otherwise returns <c>false</c>. </p> </desc> </func> + <func> <name name="is_record" arity="2"/> - <fsummary>Check whether a term appears to be a record</fsummary> + <fsummary>Checks whether a term appears to be a record.</fsummary> <desc> - <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a tuple and its first - element is <c><anno>RecordTag</anno></c>. Otherwise, returns <c>false</c>.</p> + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a tuple and its + first element is <c><anno>RecordTag</anno></c>. + Otherwise returns <c>false</c>.</p> <note> <p>Normally the compiler treats calls to <c>is_record/2</c> - specially. It emits code to verify that <c><anno>Term</anno></c> is a - tuple, that its first element is <c><anno>RecordTag</anno></c>, and that - the size is correct. However, if the <c><anno>RecordTag</anno></c> is - not a literal atom, the <c>is_record/2</c> BIF will be - called instead and the size of the tuple will not be - verified.</p> + specially. It emits code to verify that <c><anno>Term</anno></c> + is a tuple, that its first element is + <c><anno>RecordTag</anno></c>, and that the + size is correct. However, if <c><anno>RecordTag</anno></c> is + not a literal atom, the BIF <c>is_record/2</c> is called + instead and the size of the tuple is not verified.</p> </note> - <p>Allowed in guard tests, if <c><anno>RecordTag</anno></c> is a literal - atom.</p> + <p>Allowed in guard tests, if <c><anno>RecordTag</anno></c> is + a literal atom.</p> </desc> </func> + <func> <name name="is_record" arity="3"/> - <fsummary>Check whether a term appears to be a record</fsummary> - <desc> - <p><c><anno>RecordTag</anno></c> must be an atom. Returns <c>true</c> if - <c><anno>Term</anno></c> is a tuple, its first element is <c><anno>RecordTag</anno></c>, - and its size is <c><anno>Size</anno></c>. Otherwise, returns <c>false</c>.</p> - <p>Allowed in guard tests, provided that <c><anno>RecordTag</anno></c> is + <fsummary>Checks whether a term appears to be a record.</fsummary> + <desc> + <p><c><anno>RecordTag</anno></c> must be an atom.</p> + <p>Returns <c>true</c> if + <c><anno>Term</anno></c> is a tuple, + its first element is <c><anno>RecordTag</anno></c>, + and its size is <c><anno>Size</anno></c>. + Otherwise returns <c>false</c>.</p> + <p>Allowed in guard tests if <c><anno>RecordTag</anno></c> is a literal atom and <c>Size</c> is a literal integer.</p> <note> - <p>This BIF is documented for completeness. In most cases - <c>is_record/2</c> should be used.</p> + <p>This BIF is documented for completeness. Usually + <c>is_record/2</c> is to be used.</p> </note> </desc> </func> + <func> <name name="is_reference" arity="1"/> - <fsummary>Check whether a term is a reference</fsummary> + <fsummary>Checks whether a term is a reference.</fsummary> <desc> - <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a reference; - otherwise returns <c>false</c>.</p> + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a reference, + otherwise <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="is_tuple" arity="1"/> - <fsummary>Check whether a term is a tuple</fsummary> + <fsummary>Checks whether a term is a tuple.</fsummary> <desc> - <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a tuple; - otherwise returns <c>false</c>.</p> + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a tuple, + otherwise <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="length" arity="1"/> - <fsummary>Length of a list</fsummary> + <fsummary>Length of a list.</fsummary> <desc> - <p>Returns the length of <c><anno>List</anno></c>.</p> + <p>Returns the length of <c><anno>List</anno></c>, for example:</p> <pre> > <input>length([1,2,3,4,5,6,7,8,9]).</input> 9</pre> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="link" arity="1"/> - <fsummary>Create a link to another process (or port)</fsummary> + <fsummary>Creates a link to another process (or port).</fsummary> <desc> <p>Creates a link between the calling process and another - process (or port) <c><anno>PidOrPort</anno></c>, if there is not such a link + process (or port) <c><anno>PidOrPort</anno></c>, if there is + not such a link already. If a process attempts to create a link to itself, nothing is done. Returns <c>true</c>.</p> - <p>If <c><anno>PidOrPort</anno></c> does not exist, the behavior of the BIF depends - on if the calling process is trapping exits or not (see + <p>If <c><anno>PidOrPort</anno></c> does not exist, the behavior + of the BIF + depends on if the calling process is trapping exits or not (see <seealso marker="#process_flag/2">process_flag/2</seealso>):</p> <list type="bulleted"> <item>If the calling process is not trapping exits, and - checking <c><anno>PidOrPort</anno></c> is cheap -- that is, if <c><anno>PidOrPort</anno></c> is - local -- <c>link/1</c> fails with reason <c>noproc</c>.</item> + checking <c><anno>PidOrPort</anno></c> is cheap + (that is, if <c><anno>PidOrPort</anno></c> + is local), <c>link/1</c> fails with reason <c>noproc</c>.</item> <item>Otherwise, if the calling process is trapping exits, - and/or <c><anno>PidOrPort</anno></c> is remote, <c>link/1</c> returns - <c>true</c>, but an exit signal with reason <c>noproc</c> + and/or <c><anno>PidOrPort</anno></c> is remote, <c>link/1</c> + returns <c>true</c>, but an exit signal with reason <c>noproc</c> is sent to the calling process.</item> </list> </desc> </func> + <func> <name name="list_to_atom" arity="1"/> - <fsummary>Convert from text representation to an atom</fsummary> - <desc> - <p>Returns the atom whose text representation is <c><anno>String</anno></c>.</p> - <p><c><anno>String</anno></c> may only contain ISO-latin-1 - characters (i.e. numbers below 256) as the current - implementation does not allow unicode characters >= 256 in - atoms. For more information on Unicode support in atoms - see <seealso marker="erl_ext_dist#utf8_atoms">note on UTF-8 encoded atoms</seealso> - in the chapter about the external term format in the ERTS User's Guide.</p> + <fsummary>Converts from text representation to an atom.</fsummary> + <desc> + <p>Returns the atom whose text representation is + <c><anno>String</anno></c>.</p> + <p><c><anno>String</anno></c> can only contain ISO-latin-1 + characters (that is, + numbers less than 256) as the implementation does not + allow unicode characters equal to or above 256 in atoms. + For more information on Unicode support in atoms, see + <seealso marker="erl_ext_dist#utf8_atoms">note on UTF-8 + encoded atoms</seealso> + in Section "External Term Format" in the User's Guide.</p> + <p>Example:</p> <pre> > <input>list_to_atom("Erlang").</input> 'Erlang'</pre> </desc> </func> + <func> <name name="list_to_binary" arity="1"/> - <fsummary>Convert a list to a binary</fsummary> + <fsummary>Converts a list to a binary.</fsummary> <desc> - <p>Returns a binary which is made from the integers and - binaries in <c><anno>IoList</anno></c>.</p> + <p>Returns a binary that is made from the integers and + binaries in <c><anno>IoList</anno></c>, for example:</p> <pre> > <input>Bin1 = <<1,2,3>>.</input> <<1,2,3>> @@ -2130,40 +2278,46 @@ os_prompt% </pre> <<1,2,3,1,2,3,4,5,4,6>></pre> </desc> </func> + <func> <name name="list_to_bitstring" arity="1"/> + <fsummary>Converts a list to a bitstring.</fsummary> <type name="bitstring_list"/> - <fsummary>Convert a list to a bitstring</fsummary> <desc> - <p>Returns a bitstring which is made from the integers and - bitstrings in <c><anno>BitstringList</anno></c>. (The last tail in <c><anno>BitstringList</anno></c> - is allowed to be a bitstring.)</p> + <p>Returns a bitstring that is made from the integers and + bitstrings in <c><anno>BitstringList</anno></c>. (The last tail in + <c><anno>BitstringList</anno></c> is allowed to be a bitstring.)</p> + <p>Example:</p> <pre> > <input>Bin1 = <<1,2,3>>.</input> <<1,2,3>> > <input>Bin2 = <<4,5>>.</input> <<4,5>> -> <input>Bin3 = <<6,7:4,>>.</input> -<<6>> +> <input>Bin3 = <<6,7:4>>.</input> +<<6,7:4>> > <input>list_to_bitstring([Bin1,1,[2,3,Bin2],4|Bin3]).</input> -<<1,2,3,1,2,3,4,5,4,6,7:46>></pre> +<<1,2,3,1,2,3,4,5,4,6,7:4>></pre> </desc> </func> + <func> <name name="list_to_existing_atom" arity="1"/> - <fsummary>Convert from text representation to an atom</fsummary> + <fsummary>Converts from text representation to an atom.</fsummary> <desc> - <p>Returns the atom whose text representation is <c><anno>String</anno></c>, + <p>Returns the atom whose text representation is + <c><anno>String</anno></c>, but only if there already exists such atom.</p> <p>Failure: <c>badarg</c> if there does not already exist an atom whose text representation is <c><anno>String</anno></c>.</p> </desc> </func> + <func> <name name="list_to_float" arity="1"/> - <fsummary>Convert from text representation to a float</fsummary> + <fsummary>Converts from text representation to a float.</fsummary> <desc> - <p>Returns the float whose text representation is <c><anno>String</anno></c>.</p> + <p>Returns the float whose text representation is + <c><anno>String</anno></c>, for example:</p> <pre> > <input>list_to_float("2.2017764e+0").</input> 2.2017764</pre> @@ -2171,12 +2325,13 @@ os_prompt% </pre> representation of a float.</p> </desc> </func> + <func> <name name="list_to_integer" arity="1"/> - <fsummary>Convert from text representation to an integer</fsummary> + <fsummary>Converts from text representation to an integer.</fsummary> <desc> <p>Returns an integer whose text representation is - <c><anno>String</anno></c>.</p> + <c><anno>String</anno></c>, for example:</p> <pre> > <input>list_to_integer("123").</input> 123</pre> @@ -2184,12 +2339,14 @@ os_prompt% </pre> representation of an integer.</p> </desc> </func> + <func> <name name="list_to_integer" arity="2"/> - <fsummary>Convert from text representation to an integer</fsummary> + <fsummary>Converts from text representation to an integer.</fsummary> <desc> <p>Returns an integer whose text representation in base - <c><anno>Base</anno></c> is <c><anno>String</anno></c>.</p> + <c><anno>Base</anno></c> is <c><anno>String</anno></c>, + for example:</p> <pre> > <input>list_to_integer("3FF", 16).</input> 1023</pre> @@ -2197,47 +2354,52 @@ os_prompt% </pre> representation of an integer.</p> </desc> </func> + <func> <name name="list_to_pid" arity="1"/> - <fsummary>Convert from text representation to a pid</fsummary> + <fsummary>Converts from text representation to a pid.</fsummary> <desc> - <p>Returns a pid whose text representation is <c><anno>String</anno></c>.</p> - <warning> - <p>This BIF is intended for debugging and for use in - the Erlang operating system. It should not be used in - application programs.</p> - </warning> + <p>Returns a process identifier whose text representation is a + <c><anno>String</anno></c>, for example:</p> <pre> > <input>list_to_pid("<0.4.1>").</input> <0.4.1></pre> <p>Failure: <c>badarg</c> if <c><anno>String</anno></c> contains a bad - representation of a pid.</p> + representation of a process identifier.</p> + <warning> + <p>This BIF is intended for debugging and is not to be used + in application programs.</p> + </warning> </desc> </func> + <func> <name name="list_to_tuple" arity="1"/> - <fsummary>Convert a list to a tuple</fsummary> + <fsummary>Converts a list to a tuple.</fsummary> <desc> - <p>Returns a tuple which corresponds to <c><anno>List</anno></c>. <c><anno>List</anno></c> - can contain any Erlang terms.</p> + <p>Returns a tuple corresponding to <c><anno>List</anno></c>, + for example</p> <pre> > <input>list_to_tuple([share, ['Ericsson_B', 163]]).</input> {share, ['Ericsson_B', 163]}</pre> + <p><c><anno>List</anno></c> can contain any Erlang terms.</p> </desc> </func> + <func> <name name="load_module" arity="2"/> - <fsummary>Load object code for a module</fsummary> + <fsummary>Loads object code for a module.</fsummary> <desc> - <p>If <c><anno>Binary</anno></c> contains the object code for the module - <c><anno>Module</anno></c>, this BIF loads that object code. Also, if - the code for the module <c><anno>Module</anno></c> already exists, all + <p>If <c><anno>Binary</anno></c> contains the object code for module + <c><anno>Module</anno></c>, this BIF loads that object code. If + the code for module <c><anno>Module</anno></c> already exists, all export references are replaced so they point to the newly loaded code. The previously loaded code is kept in the system - as old code, as there may still be processes which are - executing that code. It returns either - <c>{module, <anno>Module</anno>}</c>, or <c>{error, <anno>Reason</anno>}</c> if loading - fails. <c><anno>Reason</anno></c> is one of the following:</p> + as old code, as there can still be processes executing + that code.</p> + <p>Returns either <c>{module, <anno>Module</anno>}</c>, or + <c>{error, <anno>Reason</anno>}</c> if loading fails. + <c><anno>Reason</anno></c> is any of the following:</p> <taglist> <tag><c>badfile</c></tag> <item> @@ -2247,118 +2409,122 @@ os_prompt% </pre> </item> <tag><c>not_purged</c></tag> <item> - <p><c><anno>Binary</anno></c> contains a module which cannot be loaded - because old code for this module already exists.</p> + <p><c><anno>Binary</anno></c> contains a module that cannot be + loaded because old code for this module already exists.</p> </item> </taglist> <warning> <p>This BIF is intended for the code server (see - <seealso marker="kernel:code">code(3)</seealso>) and should not be - used elsewhere.</p> + <seealso marker="kernel:code">code(3)</seealso>) + and is not to be used elsewhere.</p> </warning> </desc> </func> + <func> <name name="load_nif" arity="2"/> - <fsummary>Load NIF library</fsummary> + <fsummary>Loads NIF library.</fsummary> <desc> <note> - <p>In releases older than OTP R14B, NIFs were an - experimental feature. Versions of OTP older than R14B might + <p>Before OTP R14B, NIFs were an + experimental feature. Versions before OTP R14B can have different and possibly incompatible NIF semantics and - interfaces. For example, in R13B03 the return value on - failure was - <c>{error,Reason,Text}</c>.</p> + interfaces. For example, in OTP R13B03 the return value on + failure was <c>{error,Reason,Text}</c>.</p> </note> <p>Loads and links a dynamic library containing native - implemented functions (NIFs) for a module. <c><anno>Path</anno></c> is a - file path to the sharable object/dynamic library file minus - the OS-dependent file extension (.so for Unix and .dll for - Windows). See <seealso marker="erl_nif">erl_nif</seealso> - on how to implement a NIF library.</p> - <p><c><anno>LoadInfo</anno></c> can be any term. It will be passed on to + implemented functions (NIFs) for a module. <c><anno>Path</anno></c> + is a file path to the shareable object/dynamic library file minus + the OS-dependent file extension (<c>.so</c> for Unix and + <c>.dll</c> for Windows. For information on how to + implement a NIF library, see + <seealso marker="erl_nif">erl_nif</seealso>.</p> + <p><c><anno>LoadInfo</anno></c> can be any term. It is passed on to the library as part of the initialization. A good practice is to include a module version number to support future code upgrade scenarios.</p> <p>The call to <c>load_nif/2</c> must be made <em>directly</em> from the Erlang code of the module that the - NIF library belongs to.</p> - <p>It returns either <c>ok</c>, or <c>{error,{<anno>Reason</anno>,Text}}</c> - if loading fails. <c><anno>Reason</anno></c> is one of the atoms below, - while <c><anno>Text</anno></c> is a human readable string that may give - some more information about the failure.</p> + NIF library belongs to. It returns either <c>ok</c>, or + <c>{error,{<anno>Reason</anno>,Text}}</c> if loading fails. + <c><anno>Reason</anno></c> is one of the following atoms + while <c><anno>Text</anno></c> is a human readable string that + can give more information about the failure:</p> <taglist> <tag><c>load_failed</c></tag> - <item> - <p>The OS failed to load the NIF library.</p> + <item>The OS failed to load the NIF library. </item> <tag><c>bad_lib</c></tag> - <item> - <p>The library did not fulfil the requirements as a NIF - library of the calling module.</p> + <item>The library did not fulfill the requirements as a NIF + library of the calling module. </item> <tag><c>load | reload | upgrade</c></tag> - <item> - <p>The corresponding library callback was not successful.</p> + <item>The corresponding library callback was unsuccessful. </item> <tag><c>old_code</c></tag> - <item> - <p>The call to <c>load_nif/2</c> was made from the old - code of a module that has been upgraded. This is not - allowed.</p> + <item>The call to <c>load_nif/2</c> was made from the old + code of a module that has been upgraded; this is not + allowed. </item> </taglist> </desc> </func> + <func> <name name="loaded" arity="0"/> - <fsummary>List of all loaded modules</fsummary> + <fsummary>Lists all loaded modules.</fsummary> <desc> - <p>Returns a list of all loaded Erlang modules (current and/or + <p>Returns a list of all loaded Erlang modules (current and old code), including preloaded modules.</p> <p>See also <seealso marker="kernel:code">code(3)</seealso>.</p> </desc> </func> + <func> <name name="localtime" arity="0"/> - <fsummary>Current local date and time</fsummary> + <fsummary>Current local date and time.</fsummary> <desc> - <p>Returns the current local date and time - <c>{{Year, Month, Day}, {Hour, Minute, Second}}</c>.</p> - <p>The time zone and daylight saving time correction depend - on the underlying OS.</p> + <p>Returns the current local date and time, + <c>{{Year, Month, Day}, {Hour, Minute, Second}}</c>, + for example:</p> <pre> > <input>erlang:localtime().</input> {{1996,11,6},{14,45,17}}</pre> + <p>The time zone and Daylight Saving Time correction depend + on the underlying OS.</p> </desc> </func> + <func> <name name="localtime_to_universaltime" arity="1"/> - <fsummary>Convert from local to Universal Time Coordinated (UTC) date and time</fsummary> + <fsummary>Converts from local to Universal Time Coordinated (UTC) date and time.</fsummary> <desc> <p>Converts local date and time to Universal Time Coordinated - (UTC), if this is supported by the underlying OS. Otherwise, - no conversion is done and <c><anno>Localtime</anno></c> is returned.</p> + (UTC), if supported by the underlying OS. Otherwise + no conversion is done and <c><anno>Localtime</anno></c> + is returned.</p> + <p>Example:</p> <pre> > <input>erlang:localtime_to_universaltime({{1996,11,6},{14,45,17}}).</input> {{1996,11,6},{13,45,17}}</pre> - <p>Failure: <c>badarg</c> if <c><anno>Localtime</anno></c> does not denote - a valid date and time.</p> + <p>Failure: <c>badarg</c> if <c><anno>Localtime</anno></c> denotes an + invalid date and time.</p> </desc> </func> + <func> <name name="localtime_to_universaltime" arity="2"/> - <fsummary>Convert from local to Universal Time Coordinated (UTC) date and time</fsummary> + <fsummary>Converts from local to Universal Time Coordinated (UTC) date and time.</fsummary> <desc> <p>Converts local date and time to Universal Time Coordinated - (UTC) just like <c>erlang:localtime_to_universaltime/1</c>, - but the caller decides if daylight saving time is active or - not.</p> - <p>If <c><anno>IsDst</anno> == true</c> the <c><anno>Localtime</anno></c> is during - daylight saving time, if <c><anno>IsDst</anno> == false</c> it is not, - and if <c><anno>IsDst</anno> == undefined</c> the underlying OS may + (UTC) as <c>erlang:localtime_to_universaltime/1</c>, + but the caller decides if Daylight Saving Time is active.</p> + <p>If <c><anno>IsDst</anno> == true</c>, <c><anno>Localtime</anno></c> is + during Daylight Saving Time, if <c><anno>IsDst</anno> == false</c> it is + not. If <c><anno>IsDst</anno> == undefined</c>, the underlying OS can guess, which is the same as calling <c>erlang:localtime_to_universaltime(<anno>Localtime</anno>)</c>.</p> + <p>Examples:</p> <pre> > <input>erlang:localtime_to_universaltime({{1996,11,6},{14,45,17}}, true).</input> {{1996,11,6},{12,45,17}} @@ -2366,15 +2532,16 @@ os_prompt% </pre> {{1996,11,6},{13,45,17}} > <input>erlang:localtime_to_universaltime({{1996,11,6},{14,45,17}}, undefined).</input> {{1996,11,6},{13,45,17}}</pre> - <p>Failure: <c>badarg</c> if <c><anno>Localtime</anno></c> does not denote - a valid date and time.</p> + <p>Failure: <c>badarg</c> if <c><anno>Localtime</anno></c> denotes an + invalid date and time.</p> </desc> </func> + <func> <name name="make_ref" arity="0"/> - <fsummary>Return a unique reference</fsummary> + <fsummary>Returns a unique reference.</fsummary> <desc> - <p>Return a <seealso marker="doc/efficiency_guide:advanced#unique_references">unique + <p>Returns a <seealso marker="doc/efficiency_guide:advanced#unique_references">unique reference</seealso>. The reference is unique among connected nodes.</p> <warning><p>Known issue: When a node is restarted multiple @@ -2383,200 +2550,209 @@ os_prompt% </pre> created on an older node with the same node name.</p></warning> </desc> </func> + <func> <name name="make_tuple" arity="2"/> - <fsummary>Create a new tuple of a given arity</fsummary> + <fsummary>Creates a new tuple of a given arity.</fsummary> <desc> - <p>Returns a new tuple of the given <c><anno>Arity</anno></c>, where all - elements are <c><anno>InitialValue</anno></c>.</p> + <p>Creates a new tuple of the given <c><anno>Arity</anno></c>, where all + elements are <c><anno>InitialValue</anno></c>, for example:</p> <pre> > <input>erlang:make_tuple(4, []).</input> {[],[],[],[]}</pre> </desc> </func> + <func> <name name="make_tuple" arity="3"/> - <fsummary>Create a new tuple with given arity and contents</fsummary> - <desc> - <p><c>erlang:make_tuple</c> first creates a tuple of size <c><anno>Arity</anno></c> - where each element has the value <c><anno>DefaultValue</anno></c>. It then fills - in values from <c><anno>InitList</anno></c>. Each list element in <c><anno>InitList</anno></c> - must be a two-tuple where the first element is a position in the - newly created tuple and the second element is any term. If a position - occurs more than once in the list, the term corresponding to - last occurrence will be used.</p> + <fsummary>Creates a new tuple with given arity and contents.</fsummary> + <desc> + <p>Creates a tuple of size <c><anno>Arity</anno></c>, where each element + has value <c><anno>DefaultValue</anno></c>, and then fills in + values from <c><anno>InitList</anno></c>. + Each list element in <c><anno>InitList</anno></c> + must be a two-tuple, where the first element is a position in the + newly created tuple and the second element is any term. If a + position occurs more than once in the list, the term corresponding + to the last occurrence is used.</p> + <p>Example:</p> <pre> > <input>erlang:make_tuple(5, [], [{2,ignored},{5,zz},{2,aa}]).</input> {{[],aa,[],[],zz}</pre> </desc> </func> + <func> <name name="map_size" arity="1"/> - <fsummary>Return the size of a map</fsummary> + <fsummary>Returns the size of a map.</fsummary> <desc> - <p>Returns an integer which is the number of key-value pairs in <c><anno>Map</anno></c>.</p> + <p>Returns an integer, which is the number of key-value pairs + in <c><anno>Map</anno></c>, for example:</p> <pre> > <input>map_size(#{a=>1, b=>2, c=>3}).</input> 3</pre> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="max" arity="2"/> - <fsummary>Return the largest of two term</fsummary> + <fsummary>Returns the largest of two terms.</fsummary> <desc> - <p>Return the largest of <c><anno>Term1</anno></c> and <c><anno>Term2</anno></c>; - if the terms compare equal, <c><anno>Term1</anno></c> will be returned.</p> + <p>Returns the largest of <c><anno>Term1</anno></c> and + <c><anno>Term2</anno></c>. + If the terms are equal, <c><anno>Term1</anno></c> is returned.</p> </desc> </func> + <func> <name name="md5" arity="1"/> - <fsummary>Compute an MD5 message digest</fsummary> + <fsummary>Computes an MD5 message digest.</fsummary> <desc> - <p>Computes an <c>MD5</c> message digest from <c><anno>Data</anno></c>, where - the length of the digest is 128 bits (16 bytes). <c><anno>Data</anno></c> + <p>Computes an MD5 message digest from <c><anno>Data</anno></c>, where + the length of the digest is 128 bits (16 bytes). + <c><anno>Data</anno></c> is a binary or a list of small integers and binaries.</p> - <p>See The MD5 Message Digest Algorithm (RFC 1321) for more - information about MD5.</p> - <warning><p>The MD5 Message Digest Algorithm is <em>not</em> considered - safe for code-signing or software integrity purposes.</p></warning> + <p>For more information about MD5, see RFC 1321 - The + MD5 Message-Digest Algorithm.</p> + <warning><p>The MD5 Message-Digest Algorithm is <em>not</em> considered + safe for code-signing or software-integrity purposes.</p></warning> </desc> </func> + <func> <name name="md5_final" arity="1"/> - <fsummary>Finish the update of an MD5 context and return the computed MD5 message digest</fsummary> + <fsummary>Finishes the update of an MD5 context and returns the computed MD5 message digest.</fsummary> <desc> <p>Finishes the update of an MD5 <c><anno>Context</anno></c> and returns the computed <c>MD5</c> message digest.</p> </desc> </func> + <func> <name name="md5_init" arity="0"/> - <fsummary>Create an MD5 context</fsummary> + <fsummary>Creates an MD5 context.</fsummary> <desc> <p>Creates an MD5 context, to be used in subsequent calls to <c>md5_update/2</c>.</p> </desc> </func> + <func> <name name="md5_update" arity="2"/> - <fsummary>Update an MD5 context with data, and return a new context</fsummary> + <fsummary>Updates an MD5 context with data and returns a new context.</fsummary> <desc> - <p>Updates an MD5 <c><anno>Context</anno></c> with <c><anno>Data</anno></c>, and returns - a <c><anno>NewContext</anno></c>.</p> + <p>Updates an MD5 <c><anno>Context</anno></c> with + <c><anno>Data</anno></c> and returns a + <c><anno>NewContext</anno></c>.</p> </desc> </func> + <func> <name name="memory" arity="0"/> + <fsummary>Information about dynamically allocated memory.</fsummary> <type name="memory_type"/> - <fsummary>Information about dynamically allocated memory</fsummary> - <desc> - <p>Returns a list containing information about memory - dynamically allocated by the Erlang emulator. Each element of - the list is a tuple <c>{Type, Size}</c>. The first element - <c><anno>Type</anno></c>is an atom describing memory type. The second - element <c><anno>Size</anno></c>is memory size in bytes. A description of - each memory type follows:</p> + <desc> + <p>Returns a list with information about memory + dynamically allocated by the Erlang emulator. Each list + element is a tuple <c>{Type, Size}</c>. The first element + <c><anno>Type</anno></c> is an atom describing memory type. The second + element <c><anno>Size</anno></c> is the memory size in bytes.</p> + <p>The memory types are as follows:</p> <taglist> <tag><c>total</c></tag> <item> - <p>The total amount of memory currently allocated, which is - the same as the sum of memory size for <c>processes</c> + <p>The total amount of memory currently allocated. This is + the same as the sum of the memory size for <c>processes</c> and <c>system</c>.</p> </item> <tag><c>processes</c></tag> <item> - <p>The total amount of memory currently allocated by + <p>The total amount of memory currently allocated for the Erlang processes.</p> </item> <tag><c>processes_used</c></tag> <item> <p>The total amount of memory currently used by the Erlang - processes.</p> - <p>This memory is part of the memory presented as + processes. This is part of the memory presented as <c>processes</c> memory.</p> </item> <tag><c>system</c></tag> <item> - <p>The total amount of memory currently allocated by + <p>The total amount of memory currently allocated for the emulator that is not directly related to any Erlang - process.</p> - <p>Memory presented as <c>processes</c> is not included in - this memory.</p> + process. Memory presented as <c>processes</c> is not + included in this memory.</p> </item> <tag><c>atom</c></tag> <item> - <p>The total amount of memory currently allocated for atoms.</p> - <p>This memory is part of the memory presented as + <p>The total amount of memory currently allocated for atoms. + This memory is part of the memory presented as <c>system</c> memory.</p> </item> <tag><c>atom_used</c></tag> <item> - <p>The total amount of memory currently used for atoms.</p> - <p>This memory is part of the memory presented as + <p>The total amount of memory currently used for atoms. + This memory is part of the memory presented as <c>atom</c> memory.</p> </item> <tag><c>binary</c></tag> <item> <p>The total amount of memory currently allocated for - binaries.</p> - <p>This memory is part of the memory presented as - <c>system</c> memory.</p> + binaries. This memory is part of the memory presented + as <c>system</c> memory.</p> </item> <tag><c>code</c></tag> <item> <p>The total amount of memory currently allocated for - Erlang code.</p> - <p>This memory is part of the memory presented as - <c>system</c> memory.</p> + Erlang code. This memory is part of the memory presented + as <c>system</c> memory.</p> </item> <tag><c>ets</c></tag> <item> <p>The total amount of memory currently allocated for ets - tables.</p> - <p>This memory is part of the memory presented as + tables. This memory is part of the memory presented as <c>system</c> memory.</p> </item> <tag><c>low</c></tag> <item> - <p>Only on 64-bit halfword emulator.</p> - <p>The total amount of memory allocated in low memory areas - that are restricted to less than 4 Gb even though - the system may have more physical memory.</p> - <p>May be removed in future releases of halfword emulator.</p> + <p>Only on 64-bit halfword emulator. + The total amount of memory allocated in low memory areas + that are restricted to less than 4 GB, although + the system can have more memory.</p> + <p>Can be removed in a future release of the halfword + emulator.</p> </item> <tag><c>maximum</c></tag> <item> <p>The maximum total amount of memory allocated since - the emulator was started.</p> - <p>This tuple is only present when the emulator is run with - instrumentation.</p> + the emulator was started. This tuple is only present + when the emulator is run with instrumentation.</p> <p>For information on how to run the emulator with - instrumentation see + instrumentation, see <seealso marker="tools:instrument">instrument(3)</seealso> and/or <seealso marker="erts:erl">erl(1)</seealso>.</p> </item> </taglist> <note> <p>The <c>system</c> value is not complete. Some allocated - memory that should be part of the <c>system</c> value are - not.</p> + memory that is to be part of this value is not.</p> <p>When the emulator is run with instrumentation, the <c>system</c> value is more accurate, but memory - directly allocated by <c>malloc</c> (and friends) are still + directly allocated for <c>malloc</c> (and friends) is still not part of the <c>system</c> value. Direct calls to - <c>malloc</c> are only done from OS specific runtime - libraries and perhaps from user implemented Erlang drivers + <c>malloc</c> are only done from OS-specific runtime + libraries and perhaps from user-implemented Erlang drivers that do not use the memory allocation functions in the driver interface.</p> - <p>Since the <c>total</c> value is the sum of <c>processes</c> - and <c>system</c> the error in <c>system</c> will propagate + <p>As the <c>total</c> value is the sum of <c>processes</c> + and <c>system</c>, the error in <c>system</c> propagates to the <c>total</c> value.</p> <p>The different amounts of memory that are summed are - <em>not</em> gathered atomically which also introduce + <em>not</em> gathered atomically, which introduces an error in the result.</p> </note> - <p>The different values has the following relation to each + <p>The different values have the following relation to each other. Values beginning with an uppercase letter is not part of the result.</p> <code type="none"> @@ -2584,69 +2760,62 @@ os_prompt% </pre> processes = processes_used + ProcessesNotUsed system = atom + binary + code + ets + OtherSystem atom = atom_used + AtomNotUsed - RealTotal = processes + RealSystem RealSystem = system + MissedSystem</code> - <p>More tuples in the returned list may be added in the future.</p> + <p>More tuples in the returned list can be added in a + future release.</p> <note> <p>The <c>total</c> value is supposed to be the total amount of memory dynamically allocated by the emulator. Shared libraries, the code of the emulator itself, and - the emulator stack(s) are not supposed to be included. That + the emulator stacks are not supposed to be included. That is, the <c>total</c> value is <em>not</em> supposed to be - equal to the total size of all pages mapped to the emulator. - Furthermore, due to fragmentation and pre-reservation of - memory areas, the size of the memory segments which contain - the dynamically allocated memory blocks can be substantially + equal to the total size of all pages mapped to the emulator.</p> + <p>Furthermore, because of fragmentation and prereservation of + memory areas, the size of the memory segments containing + the dynamically allocated memory blocks can be much larger than the total size of the dynamically allocated memory blocks.</p> </note> <note> - <p> - Since erts version 5.6.4 <c>erlang:memory/0</c> requires that + <p>As from <c>ERTS</c> 5.6.4, <c>erlang:memory/0</c> requires that all <seealso marker="erts:erts_alloc">erts_alloc(3)</seealso> - allocators are enabled (default behaviour). - </p> + allocators are enabled (default behavior).</p> </note> - <p>Failure:</p> - <taglist> - <tag><c>notsup</c></tag> - <item> - If an <seealso marker="erts:erts_alloc">erts_alloc(3)</seealso> - allocator has been disabled. - </item> - </taglist> + <p>Failure: <c>notsup</c> if an + <seealso marker="erts:erts_alloc">erts_alloc(3)</seealso> + allocator has been disabled.</p> </desc> </func> + <func> <name name="memory" arity="1" clause_i="1"/> <name name="memory" arity="1" clause_i="2"/> + <fsummary>Information about dynamically allocated memory.</fsummary> <type name="memory_type"/> - <fsummary>Information about dynamically allocated memory</fsummary> <desc> <p>Returns the memory size in bytes allocated for memory of type <c><anno>Type</anno></c>. The argument can also be given as a list of <c>memory_type()</c> atoms, in which case a corresponding list of <c>{memory_type(), Size :: integer >= 0}</c> tuples is returned.</p> <note> - <p> - Since erts version 5.6.4 <c>erlang:memory/1</c> requires that + <p>As from <c>ERTS</c> version 5.6.4, + <c>erlang:memory/1</c> requires that all <seealso marker="erts:erts_alloc">erts_alloc(3)</seealso> - allocators are enabled (default behaviour). - </p> + allocators are enabled (default behavior).</p> </note> <p>Failures:</p> <taglist> <tag><c>badarg</c></tag> <item> - If <c><anno>Type</anno></c> is not one of the memory types listed in the - documentation of + If <c><anno>Type</anno></c> is not one of the memory types + listed in the description of <seealso marker="#memory/0">erlang:memory/0</seealso>. </item> <tag><c>badarg</c></tag> <item> - If <c>maximum</c> is passed as <c><anno>Type</anno></c> and the emulator - is not run in instrumented mode. + If <c>maximum</c> is passed as <c><anno>Type</anno></c> and + the emulator is not run in instrumented mode. </item> <tag><c>notsup</c></tag> <item> @@ -2658,35 +2827,39 @@ os_prompt% </pre> <seealso marker="#memory/0">erlang:memory/0</seealso>.</p> </desc> </func> + <func> <name name="min" arity="2"/> - <fsummary>Return the smallest of two term</fsummary> + <fsummary>Returns the smallest of two terms.</fsummary> <desc> - <p>Return the smallest of <c><anno>Term1</anno></c> and <c><anno>Term2</anno></c>; - if the terms compare equal, <c><anno>Term1</anno></c> will be returned.</p> + <p>Returns the smallest of <c><anno>Term1</anno></c> and + <c><anno>Term2</anno></c>. + If the terms are equal, <c><anno>Term1</anno></c> is returned.</p> </desc> </func> + <func> <name name="module_loaded" arity="1"/> - <fsummary>Check if a module is loaded</fsummary> + <fsummary>Checks if a module is loaded.</fsummary> <desc> - <p>Returns <c>true</c> if the module <c><anno>Module</anno></c> is loaded, - otherwise returns <c>false</c>. It does not attempt to load + <p>Returns <c>true</c> if the module <c><anno>Module</anno></c> + is loaded, otherwise <c>false</c>. It does not attempt to load the module.</p> <warning> <p>This BIF is intended for the code server (see - <seealso marker="kernel:code">code(3)</seealso>) and should not be + <seealso marker="kernel:code">code(3)</seealso>) and is not to be used elsewhere.</p> </warning> </desc> </func> + <func> <name name="monitor" arity="2" clause_i="1"/> <name name="monitor" arity="2" clause_i="2"/> + <fsummary>Starts monitoring.</fsummary> <type name="registered_name"/> <type name="registered_process_identifier"/> <type name="monitor_process_identifier"/> - <fsummary>Start monitoring</fsummary> <desc> <p>Send a monitor request of type <c><anno>Type</anno></c> to the entity identified by <c><anno>Item</anno></c>. The caller of @@ -2694,15 +2867,15 @@ os_prompt% </pre> following format if the monitored state is changed:</p> <code type="none">{Tag, <anno>MonitorRef</anno>, <anno>Type</anno>, Object, Info}</code> <note><p>The monitor request is an asynchronous signal. That is, it - takes time before the signal reach its destination.</p></note> - <p>Currently valid <c><anno>Type</anno></c>s:</p> + takes time before the signal reaches its destination.</p></note> + <p>Valid <c><anno>Type</anno></c>s:</p> <taglist> <tag><marker id="monitor_process"/><c>process</c></tag> <item> <p>Monitor the existence of the process identified by - <c><anno>Item</anno></c>. Currently valid + <c><anno>Item</anno></c>. Valid <c><anno>Item</anno></c>s in combination with the - <c>process <anno>Type</anno></c>:</p> + <c>process <anno>Type</anno></c> can be any of the following:</p> <taglist> <tag><c>pid()</c></tag> <item> @@ -2721,10 +2894,10 @@ os_prompt% </pre> will become monitored.</p> </item> </taglist> - <note><p>When a process is monitored by registered name, the - process that has the registered name at the time when the + <note><p>When a registered name is used, the + process that has the registered name when the monitor request reach its destination will be monitored. - The monitor will not be effected, if the registered name is + The monitor is not effected if the registered name is unregistered, or unregistered and later registered on another process.</p></note> <p>The monitor is triggered either when the monitored process @@ -2732,22 +2905,22 @@ os_prompt% </pre> lost. In the case the connection to it is lost, we do not know if it still exist or not. After this type of monitor has been triggered, the monitor is automatically removed.</p> - <p>When the monitor is triggered a <c>'DOWN'</c> message will - be sent to the monitoring process. A <c>'DOWN'</c> message has + <p>When the monitor is triggered a <c>'DOWN'</c> message is + sent to the monitoring process. A <c>'DOWN'</c> message has the following pattern:</p> <code type="none">{'DOWN', MonitorRef, Type, Object, Info}</code> - <p>where <c>MonitorRef</c> and <c>Type</c> are the same as - described above, and:</p> + <p>Here <c>MonitorRef</c> and <c>Type</c> are the same as + described earlier, and:</p> <taglist> <tag><c>Object</c></tag> <item> <p>equals:</p> <taglist> <tag><c><anno>Item</anno></c></tag> - <item>If <c><anno>Item</anno></c> was specified by a - pid.</item> + <item>If <c><anno>Item</anno></c> is specified by a + process identifier.</item> <tag><c>{RegisteredName, Node}</c></tag> - <item>If <c><anno>Item</anno></c> was specified as + <item>If <c><anno>Item</anno></c> is specified as <c>RegisteredName</c>, or <c>{RegisteredName, Node}</c> where <c>Node</c> corresponds to the node that the monitored process resides on.</item> @@ -2760,26 +2933,26 @@ os_prompt% </pre> connection to the node where the monitored process resides).</p></item> </taglist> - <p>The monitoring is turned off either when the <c>'DOWN'</c> - message is sent, or when + <p>The monitoring is turned off when the <c>'DOWN'</c> + message is sent or when <seealso marker="#demonitor/1">demonitor/1</seealso> is called.</p> <p>If an attempt is made to monitor a process on an older node - (where remote process monitoring is not implemented or one + (where remote process monitoring is not implemented or where remote process monitoring by registered name is not implemented), the call fails with <c>badarg</c>.</p> <note> - <p>The format of the <c>'DOWN'</c> message changed in the 5.2 - version of the emulator (OTP release R9B) for monitor - <em>by registered name</em>. The <c>Object</c> element of + <p>The format of the <c>'DOWN'</c> message changed in ERTS + version 5.2 (OTP R9B) for monitoring + <em>by registered name</em>. Element <c>Object</c> of the <c>'DOWN'</c> message could in earlier versions - sometimes be the pid of the monitored process and sometimes - be the registered name. Now the <c>Object</c> element is + sometimes be the process identifier of the monitored process and sometimes + be the registered name. Now element <c>Object</c> is always a tuple consisting of the registered name and - the node name. Processes on new nodes (emulator version 5.2 - or greater) will always get <c>'DOWN'</c> messages on + the node name. Processes on new nodes (ERTS version 5.2 + or higher) always get <c>'DOWN'</c> messages on the new format even if they are monitoring processes on old - nodes. Processes on old nodes will always get <c>'DOWN'</c> + nodes. Processes on old nodes always get <c>'DOWN'</c> messages on the old format.</p> </note> </item> @@ -2807,8 +2980,8 @@ os_prompt% </pre> <seealso marker="time_correction#Single_Time_Warp_Mode">single time warp mode</seealso> is used. When a change from preliminary to final time offset is made, the monitor will be triggered once - regardless of whether the time offset value was changed due to - the finalization or not.</p> + regardless of whether the time offset value was actually changed + or not.</p> <p>If the runtime system is in <seealso marker="time_correction#Multi_Time_Warp_Mode">multi @@ -2836,7 +3009,7 @@ os_prompt% </pre> <p>When the <c>'CHANGE'</c> message has been received you are guaranteed not to retrieve the old time offset when calling <seealso marker="#time_offset/0"><c>erlang:time_offset()</c></seealso>. - Note that you may observe the change of the time offset + Note that you can observe the change of the time offset when calling <c>erlang:time_offset()</c> before you get the <c>'CHANGE'</c> message.</p> @@ -2844,67 +3017,71 @@ os_prompt% </pre> </taglist> <p>Making several calls to <c>monitor/2</c> for the same <c><anno>Item</anno></c> and/or <c><anno>Type</anno></c> is not - an error; it results in many, completely independent, - monitorings.</p> + an error; it results in as many independent monitoring instances.</p> <p>The monitor functionality is expected to be extended. That is, other <c><anno>Type</anno></c>s and <c><anno>Item</anno></c>s - are expected to be supported in the future.</p> + are expected to be supported in a future release.</p> <note> - <p>If/when <c>monitor/2</c> is extended, other - possible values for <c>Tag</c>, <c>Object</c>, and + <p>If or when <c>monitor/2</c> is extended, other + possible values for <c>Tag</c>, <c>Object</c> and <c>Info</c> in the monitor message will be introduced.</p> </note> </desc> </func> + <func> <name name="monitor_node" arity="2"/> - <fsummary>Monitor the status of a node</fsummary> + <fsummary>Monitors the status of a node.</fsummary> <desc> - <p>Monitors the status of the node <c><anno>Node</anno></c>. If <c><anno>Flag</anno></c> - is <c>true</c>, monitoring is turned on; if <c><anno>Flag</anno></c> is - <c>false</c>, monitoring is turned off.</p> + <p>Monitors the status of the node <c><anno>Node</anno></c>. + If <c><anno>Flag</anno></c> + is <c>true</c>, monitoring is turned on. If <c><anno>Flag</anno></c> + is <c>false</c>, monitoring is turned off.</p> <p>Making several calls to <c>monitor_node(Node, true)</c> for - the same <c><anno>Node</anno></c> is not an error; it results in as many, - completely independent, monitorings.</p> + the same <c><anno>Node</anno></c> is not an error; it results + in as many independent monitoring instances.</p> <p>If <c><anno>Node</anno></c> fails or does not exist, the message <c>{nodedown, Node}</c> is delivered to the process. If a process has made two calls to <c>monitor_node(Node, true)</c> - and <c><anno>Node</anno></c> terminates, two <c>nodedown</c> messages are - delivered to the process. If there is no connection to - <c><anno>Node</anno></c>, there will be an attempt to create one. If this - fails, a <c>nodedown</c> message is delivered.</p> + and <c><anno>Node</anno></c> terminates, two <c>nodedown</c> messages + are delivered to the process. If there is no connection to + <c><anno>Node</anno></c>, an attempt is made to create one. + If this fails, a <c>nodedown</c> message is delivered.</p> <p>Nodes connected through hidden connections can be monitored - as any other node.</p> + as any other nodes.</p> <p>Failure: <c>badarg</c> if the local node is not alive.</p> </desc> </func> + <func> <name name="monitor_node" arity="3"/> - <fsummary>Monitor the status of a node</fsummary> + <fsummary>Monitors the status of a node.</fsummary> <desc> - <p>Behaves as <c>monitor_node/2</c> except that it allows an + <p>Behaves as + <seealso marker="#monitor_node/2">monitor_node/2</seealso> + except that it allows an extra option to be given, namely <c>allow_passive_connect</c>. - The option allows the BIF to wait the normal net connection - timeout for the <em>monitored node</em> to connect itself, + This option allows the BIF to wait the normal network connection + time-out for the <em>monitored node</em> to connect itself, even if it cannot be actively connected from this node - (i.e. it is blocked). The state where this might be useful can - only be achieved by using the kernel option - <c>dist_auto_connect once</c>. If that kernel option is not - used, the <c>allow_passive_connect</c> option has no - effect.</p> + (that is, it is blocked). The state where this can be useful + can only be achieved by using the <c>Kernel</c> option + <c>dist_auto_connect once</c>. If that option is not + used, option <c>allow_passive_connect</c> has no effect.</p> <note> - <p>The <c>allow_passive_connect</c> option is used + <p>Option <c>allow_passive_connect</c> is used internally and is seldom needed in applications where the - network topology and the kernel options in effect is known in - advance.</p> + network topology and the <c>Kernel</c> options in effect + are known in advance.</p> </note> <p>Failure: <c>badarg</c> if the local node is not alive or the option list is malformed.</p> </desc> </func> + <func> <name name="monotonic_time" arity="0"/> - <fsummary>Current Erlang monotonic time</fsummary> + <fsummary>Current Erlang monotonic time.</fsummary> <desc> <p>Returns the current <seealso marker="time_correction#Erlang_Monotonic_Time">Erlang @@ -2917,7 +3094,7 @@ os_prompt% </pre> <seealso marker="time_correction#Monotonically_Increasing">monotonically increasing</seealso> time, but <em>not</em> a <seealso marker="time_correction#Strictly_Monotonically_Increasing">strictly monotonically increasing</seealso> time. That is, consecutive calls to - <c>erlang:monotonic_time/0</c> may produce the same result.</p> + <c>erlang:monotonic_time/0</c> can produce the same result.</p> <p>Different runtime system instances will use different unspecified points in time as base for their Erlang monotonic clocks. @@ -2925,9 +3102,9 @@ os_prompt% </pre> different runtime system instances. Different runtime system instances may also place this unspecified point in time different relative runtime system start. It may be placed in the future (time at start - will be a negative value), the past (time at start will be a - positive value), or the runtime system start (time at start will - be zero). The monotonic time as of runtime system start can be + is a negative value), the past (time at start is a + positive value), or the runtime system start (time at start is + zero). The monotonic time at runtime system start can be retrieved by calling <seealso marker="#system_info_start_time"><c>erlang:system_info(start_time)</c></seealso>.</p></note> </desc> @@ -2949,61 +3126,68 @@ os_prompt% </pre> </func> <func> <name name="nif_error" arity="1"/> - <fsummary>Stop execution with a given reason</fsummary> + <fsummary>Stops execution with a given reason.</fsummary> <desc> <p>Works exactly like - <seealso marker="#error/1">erlang:error/1</seealso>, - but Dialyzer thinks that this BIF will return an arbitrary term. - When used in a stub function for a NIF to generate an - exception when the NIF library is not loaded, Dialyzer - will not generate false warnings.</p> + <seealso marker="#error/1">erlang:error/1</seealso>, but + <c>Dialyzer</c> thinks that this BIF will return an arbitrary + term. When used in a stub function for a NIF to generate an + exception when the NIF library is not loaded, <c>Dialyzer</c> + does not generate false warnings.</p> </desc> </func> + <func> <name name="nif_error" arity="2"/> - <fsummary>Stop execution with a given reason</fsummary> + <fsummary>Stops execution with a given reason.</fsummary> <desc> <p>Works exactly like - <seealso marker="#error/2">erlang:error/2</seealso>, - but Dialyzer thinks that this BIF will return an arbitrary term. - When used in a stub function for a NIF to generate an - exception when the NIF library is not loaded, Dialyzer - will not generate false warnings.</p> + <seealso marker="#error/2">erlang:error/2</seealso>, but + <c>Dialyzer</c> thinks that this BIF will return an arbitrary + term. When used in a stub function for a NIF to generate an + exception when the NIF library is not loaded, <c>Dialyzer</c> + does not generate false warnings.</p> </desc> </func> + <func> <name name="node" arity="0"/> - <fsummary>Name of the local node</fsummary> + <fsummary>Name of the local node.</fsummary> <desc> <p>Returns the name of the local node. If the node is not alive, <c>nonode@nohost</c> is returned instead.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="node" arity="1"/> - <fsummary>At which node is a pid, port or reference located</fsummary> + <fsummary>At which node a pid, port, or reference originates.</fsummary> <desc> - <p>Returns the node where <c><anno>Arg</anno></c> is located. <c><anno>Arg</anno></c> can - be a pid, a reference, or a port. If the local node is not + <p>Returns the node where <c><anno>Arg</anno></c> originates. + <c><anno>Arg</anno></c> can + be a process identifier, a reference, or a port. + If the local node is not alive, <c>nonode@nohost</c> is returned.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="nodes" arity="0"/> - <fsummary>All visible nodes in the system</fsummary> + <fsummary>All visible nodes in the system.</fsummary> <desc> - <p>Returns a list of all visible nodes in the system, excluding + <p>Returns a list of all visible nodes in the system, except the local node. Same as <c>nodes(visible)</c>.</p> </desc> </func> + <func> <name name="nodes" arity="1"/> - <fsummary>All nodes of a certain type in the system</fsummary> + <fsummary>All nodes of a certain type in the system.</fsummary> <desc> - <p>Returns a list of nodes according to argument given. - The result returned when the argument is a list, is the list + <p>Returns a list of nodes according to the argument given. + The returned result when the argument is a list, is the list of nodes satisfying the disjunction(s) of the list elements.</p> <p><c><anno>NodeType</anno></c> can be any of the following:</p> <taglist> @@ -3025,22 +3209,26 @@ os_prompt% </pre> </item> <tag><c>known</c></tag> <item> - <p>Nodes which are known to this node, i.e., connected, - previously connected, etc.</p> + <p>Nodes that are known to this node. That is, connected + nodes and nodes referred to by process identifiers, port + identifiers and references located on this node. + The set of known nodes is garbage collected. Notice that + this garbage collection can be delayed. For more + information, see + <seealso marker="erlang#system_info_delayed_node_table_gc">delayed_node_table_gc</seealso>. + </p> </item> </taglist> <p>Some equalities: <c>[node()] = nodes(this)</c>, <c>nodes(connected) = nodes([visible, hidden])</c>, and <c>nodes() = nodes(visible)</c>.</p> - <p>If the local node is not alive, - <c>nodes(this) == nodes(known) == [nonode@nohost]</c>, for - any other <c><anno>Arg</anno></c> the empty list [] is returned.</p> </desc> </func> + <func> <name name="now" arity="0"/> + <fsummary>Elapsed time since 00:00 GMT.</fsummary> <type name="timestamp"/> - <fsummary>Elapsed time since 00:00 GMT</fsummary> <desc> <warning><p><em>This function is deprecated! Do not use it!</em> See the users guide chapter @@ -3050,107 +3238,101 @@ os_prompt% </pre> section for information on what to use instead of <c>erlang:now/0</c>. </p></warning> <p>Returns the tuple <c>{MegaSecs, Secs, MicroSecs}</c> which is - the elapsed time since 00:00 GMT, January 1, 1970 (zero hour) + the elapsed time since 00:00 GMT, January 1, 1970 (zero hour), on the assumption that the underlying OS supports this. - Otherwise, some other point in time is chosen. It is also - guaranteed that subsequent calls to this BIF returns + Otherwise some other point in time is chosen. It is also + guaranteed that subsequent calls to this BIF return continuously increasing values. Hence, the return value from - <c>now()</c> can be used to generate unique time-stamps, - and if it is called in a tight loop on a fast machine + <c>now()</c> can be used to generate unique time-stamps. + If it is called in a tight loop on a fast machine, the time of the node can become skewed.</p> - <p>It can only be used to check the local time of day if - the time-zone info of the underlying operating system is + <p>Can only be used to check the local time of day if + the time-zone information of the underlying OS is properly configured.</p> </desc> </func> + <func> <name name="open_port" arity="2"/> - <fsummary>Open a port</fsummary> + <fsummary>Opens a port.</fsummary> <desc> <p>Returns a port identifier as the result of opening a new Erlang port. A port can be seen as an external Erlang - process. - </p> + process.</p> <p>The name of the executable as well as the arguments - given in <c>cd</c>, <c>env</c>, <c>args</c> and <c>arg0</c> is subject to - Unicode file name translation if the system is running + given in <c>cd</c>, <c>env</c>, <c>args</c>, and <c>arg0</c> are + subject to Unicode file name translation if the system is running in Unicode file name mode. To avoid - translation or force i.e. UTF-8, supply the executable + translation or to force, for example UTF-8, supply the executable and/or arguments as a binary in the correct - encoding. See the <seealso - marker="kernel:file">file</seealso> module, the - <seealso marker="kernel:file#native_name_encoding/0"> - file:native_name_encoding/0</seealso> function and the - <seealso marker="stdlib:unicode_usage">stdlib users guide - </seealso> for details.</p> - - <note><p>The characters in the name (if given as a list) - can only be > 255 if the Erlang VM is started in - Unicode file name translation mode, otherwise the name + encoding. For details, see the module + <seealso marker="kernel:file">file</seealso>, the function + <seealso marker="kernel:file#native_name_encoding/0">file:native_name_encoding/0</seealso>, and the + <seealso marker="stdlib:unicode_usage">STDLIB </seealso> + User's Guide.</p> + <note><p>The characters in the name (if given as a list) can + only be higher than 255 if the Erlang Virtual Machine is started + in Unicode file name translation mode. Otherwise the name of the executable is limited to the ISO-latin-1 character set.</p></note> - - <p><c><anno>PortName</anno></c> is one of the following:</p> + <p><c><anno>PortName</anno></c> can be any of the following:</p> <taglist> <tag><c>{spawn, <anno>Command</anno>}</c></tag> <item> - <p>Starts an external program. <c><anno>Command</anno></c> is the name - of the external program which will be run. <c><anno>Command</anno></c> + <p>Starts an external program. <c><anno>Command</anno></c> + is the name of the external program to be run. + <c><anno>Command</anno></c> runs outside the Erlang work space unless an Erlang - driver with the name <c><anno>Command</anno></c> is found. If found, - that driver will be started. A driver runs in the Erlang - workspace, which means that it is linked with the Erlang + driver with the name <c><anno>Command</anno></c> is found. + If found, that driver is started. A driver runs in the Erlang + work space, which means that it is linked with the Erlang runtime system.</p> <p>When starting external programs on Solaris, the system call <c>vfork</c> is used in preference to <c>fork</c> for performance reasons, although it has a history of - being less robust. If there are problems with using - <c>vfork</c>, setting the environment variable - <c>ERL_NO_VFORK</c> to any value will cause <c>fork</c> + being less robust. If there are problems using + <c>vfork</c>, setting environment variable + <c>ERL_NO_VFORK</c> to any value causes <c>fork</c> to be used instead.</p> - - <p>For external programs, the <c>PATH</c> is searched + <p>For external programs, <c>PATH</c> is searched (or an equivalent method is used to find programs, - depending on operating system). This is done by invoking - the shell on certain platforms. The first space - separated token of the command will be considered as the + depending on OS). This is done by invoking + the shell on certain platforms. The first space-separated + token of the command is considered as the name of the executable (or driver). This (among other things) makes this option unsuitable for running - programs having spaces in file or directory names. Use - {spawn_executable, <anno>Command</anno>} instead if spaces in executable - file names is desired.</p> + programs having spaces in file names or directory names. + If spaces in executable file names are desired, use + <c>{spawn_executable, <anno>Command</anno>}</c> instead.</p> </item> <tag><c>{spawn_driver, <anno>Command</anno>}</c></tag> <item> <p>Works like <c>{spawn, <anno>Command</anno>}</c>, but demands the - first (space separated) token of the command to be the name of a + first (space-separated) token of the command to be the name of a loaded driver. If no driver with that name is loaded, a <c>badarg</c> error is raised.</p> </item> <tag><c>{spawn_executable, <anno>FileName</anno>}</c></tag> <item> - <p>Works like <c>{spawn, <anno>FileName</anno>}</c>, but only runs - external executables. The <c><anno>FileName</anno></c> in its whole - is used as the name of the executable, including any - spaces. If arguments are to be passed, the - <c>args</c> and <c>arg0</c> <c><anno>PortSettings</anno></c> can be used.</p> - - <p>The shell is not usually invoked to start the - program, it's executed directly. Neither is the - <c>PATH</c> (or equivalent) searched. To find a program - in the PATH to execute, use <seealso - marker="kernel:os#find_executable/1">os:find_executable/1</seealso>.</p> + external executables. <c><anno>FileName</anno></c> in its whole + is used as the name of the executable, including any spaces. + If arguments are to be passed, the <c><anno>PortSettings</anno></c> + <c>args</c> and <c>arg0</c> can be used.</p> + <p>The shell is usually not invoked to start the + program, it is executed directly. <c>PATH</c> (or + equivalent) is not searched. To find a program + in <c>PATH</c> to execute, use + <seealso marker="kernel:os#find_executable/1">os:find_executable/1</seealso>.</p> <p>Only if a shell script or <c>.bat</c> file is - executed, the appropriate command interpreter will - implicitly be invoked, but there will still be no - command argument expansion or implicit PATH search.</p> - - <p>If the <c><anno>FileName</anno></c> cannot be run, an error - exception, with the posix error code as the reason, is - raised. The error reason may differ between operating - systems. Typically the error <c>enoent</c> is raised - when one tries to run a program that is not found and + executed, the appropriate command interpreter is + invoked implicitly, but there is still no + command argument expansion or implicit <c>PATH</c> search.</p> + <p>If <c><anno>FileName</anno></c> cannot be run, an error + exception is raised, with the POSIX error code as the reason. + The error reason can differ between OSs. + Typically the error <c>enoent</c> is raised when an + attempt is made to run a program that is not found and <c>eacces</c> is raised when the given file is not executable.</p> </item> @@ -3160,19 +3342,18 @@ os_prompt% </pre> file descriptors used by Erlang. The file descriptor <c><anno>In</anno></c> can be used for standard input, and the file descriptor <c><anno>Out</anno></c> for standard output. It is only - used for various servers in the Erlang operating system - (<c>shell</c> and <c>user</c>). Hence, its use is very - limited.</p> + used for various servers in the Erlang OS (<c>shell</c> + and <c>user</c>). Hence, its use is limited.</p> </item> </taglist> <p><c><anno>PortSettings</anno></c> is a list of settings for the port. - Valid settings are:</p> + The valid settings are as follows:</p> <taglist> <tag><c>{packet, <anno>N</anno>}</c></tag> <item> <p>Messages are preceded by their length, sent in <c><anno>N</anno></c> - bytes, with the most significant byte first. Valid values - for <c>N</c> are 1, 2, or 4.</p> + bytes, with the most significant byte first. The valid values + for <c>N</c> are 1, 2, and 4.</p> </item> <tag><c>stream</c></tag> <item> @@ -3183,116 +3364,108 @@ os_prompt% </pre> <tag><c>{line, <anno>L</anno>}</c></tag> <item> <p>Messages are delivered on a per line basis. Each line - (delimited by the OS-dependent newline sequence) is - delivered in one single message. The message data format - is <c>{Flag, Line}</c>, where <c>Flag</c> is either - <c>eol</c> or <c>noeol</c> and <c>Line</c> is the actual - data delivered (without the newline sequence).</p> + (delimited by the OS-dependent new line sequence) is + delivered in a single message. The message data format + is <c>{Flag, Line}</c>, where <c>Flag</c> is + <c>eol</c> or <c>noeol</c>, and <c>Line</c> is the + data delivered (without the new line sequence).</p> <p><c><anno>L</anno></c> specifies the maximum line length in bytes. - Lines longer than this will be delivered in more than one - message, with the <c>Flag</c> set to <c>noeol</c> for all + Lines longer than this are delivered in more than one + message, with <c>Flag</c> set to <c>noeol</c> for all but the last message. If end of file is encountered - anywhere else than immediately following a newline - sequence, the last line will also be delivered with - the <c>Flag</c> set to <c>noeol</c>. In all other cases, + anywhere else than immediately following a new line + sequence, the last line is also delivered with + <c>Flag</c> set to <c>noeol</c>. Otherwise lines are delivered with <c>Flag</c> set to <c>eol</c>.</p> - <p>The <c>{packet, <anno>N</anno>}</c> and <c>{line, <anno>L</anno>}</c> settings are - mutually exclusive.</p> + <p>The <c>{packet, <anno>N</anno>}</c> and <c>{line, + <anno>L</anno>}</c> settings are mutually exclusive.</p> </item> <tag><c>{cd, <anno>Dir</anno>}</c></tag> <item> - <p>This is only valid for <c>{spawn, <anno>Command</anno>}</c> and - <c>{spawn_executable, <anno>FileName</anno>}</c>. + <p>Only valid for <c>{spawn, <anno>Command</anno>}</c> and + <c>{spawn_executable, <anno>FileName</anno>}</c>. The external program starts using <c><anno>Dir</anno></c> as its - working directory. <c><anno>Dir</anno></c> must be a string. - </p> + working directory. <c><anno>Dir</anno></c> must be a string.</p> </item> <tag><c>{env, <anno>Env</anno>}</c></tag> <item> - <p>This is only valid for <c>{spawn, <anno>Command</anno>}</c> and + <p>Only valid for <c>{spawn, <anno>Command</anno>}</c> and <c>{spawn_executable, <anno>FileName</anno>}</c>. The environment of the started process is extended using the environment specifications in <c><anno>Env</anno></c>.</p> - <p><c><anno>Env</anno></c> should be a list of tuples <c>{<anno>Name</anno>, <anno>Val</anno>}</c>, - where <c><anno>Name</anno></c> is the name of an environment variable, - and <c><anno>Val</anno></c> is the value it is to have in the spawned - port process. Both <c><anno>Name</anno></c> and <c><anno>Val</anno></c> must be - strings. The one exception is <c><anno>Val</anno></c> being the atom + <p><c><anno>Env</anno></c> is to be a list of tuples + <c>{<anno>Name</anno>, <anno>Val</anno>}</c>, + where <c><anno>Name</anno></c> is the name of an + environment variable, and <c><anno>Val</anno></c> is the + value it is to have in the spawned + port process. Both <c><anno>Name</anno></c> and + <c><anno>Val</anno></c> must be strings. The one + exception is <c><anno>Val</anno></c> being the atom <c>false</c> (in analogy with <c>os:getenv/1</c>), which - removes the environment variable. - </p> + removes the environment variable.</p> </item> <tag><c>{args, [ string() | binary() ]}</c></tag> <item> - - <p>This option is only valid for <c>{spawn_executable, <anno>FileName</anno>}</c> + <p>Only valid for <c>{spawn_executable, <anno>FileName</anno>}</c> and specifies arguments to the executable. Each argument is given as a separate string and (on Unix) eventually ends up as one element each in the argument vector. On - other platforms, similar behavior is mimicked.</p> - - <p>The arguments are not expanded by the shell prior to - being supplied to the executable, most notably this - means that file wildcard expansion will not happen. Use - <seealso - marker="stdlib:filelib#wildcard/1">filelib:wildcard/1</seealso> - to expand wildcards for the arguments. Note that even if + other platforms, a similar behavior is mimicked.</p> + <p>The arguments are not expanded by the shell before + being supplied to the executable. Most notably this + means that file wild card expansion does not happen. + To expand wild cards for the arguments, use + <seealso marker="stdlib:filelib#wildcard/1">filelib:wildcard/1</seealso>. + Notice that even if the program is a Unix shell script, meaning that the - shell will ultimately be invoked, wildcard expansion - will not happen and the script will be provided with the - untouched arguments. On Windows®, wildcard expansion - is always up to the program itself, why this isn't an - issue.</p> - - <p>Note also that the actual executable name (a.k.a. <c>argv[0]</c>) - should not be given in this list. The proper executable name will - automatically be used as argv[0] where applicable.</p> - - <p>If one, for any reason, wants to explicitly set the - program name in the argument vector, the <c>arg0</c> - option can be used.</p> - + shell ultimately is invoked, wild card expansion + does not happen, and the script is provided with the + untouched arguments. On Windows, wild card expansion + is always up to the program itself, therefore this is + not an issue issue.</p> + <p>The executable name (also known as <c>argv[0]</c>) + is not to be given in this list. The proper executable name + is automatically used as argv[0], where applicable.</p> + <p>If you explicitly want to set the + program name in the argument vector, option <c>arg0</c> + can be used.</p> </item> <tag><c>{arg0, string() | binary()}</c></tag> <item> - - <p>This option is only valid for <c>{spawn_executable, <anno>FileName</anno>}</c> + <p>Only valid for <c>{spawn_executable, <anno>FileName</anno>}</c> and explicitly specifies the program name argument when - running an executable. This might in some circumstances, - on some operating systems, be desirable. How the program - responds to this is highly system dependent and no specific + running an executable. This can in some circumstances, + on some OSs, be desirable. How the program + responds to this is highly system-dependent and no specific effect is guaranteed.</p> - </item> - <tag><c>exit_status</c></tag> <item> - <p>This is only valid for <c>{spawn, <anno>Command</anno>}</c> where - <c><anno>Command</anno></c> refers to an external program, and for - <c>{spawn_executable, <anno>FileName</anno>}</c>.</p> + <p>Only valid for <c>{spawn, <anno>Command</anno>}</c>, where + <c><anno>Command</anno></c> refers to an external program, and + for <c>{spawn_executable, <anno>FileName</anno>}</c>.</p> <p>When the external process connected to the port exits, a message of the form <c>{Port,{exit_status,Status}}</c> is sent to the connected process, where <c>Status</c> is the exit status of the external process. If the program - aborts, on Unix the same convention is used as the shells - do (i.e., 128+signal).</p> - <p>If the <c>eof</c> option has been given as well, - the <c>eof</c> message and the <c>exit_status</c> message - appear in an unspecified order.</p> - <p>If the port program closes its stdout without exiting, - the <c>exit_status</c> option will not work.</p> + aborts on Unix, the same convention is used as the shells + do (that is, 128+signal).</p> + <p>If option <c>eof</c> is also given, the messages <c>eof</c> + and <c>exit_status</c> appear in an unspecified order.</p> + <p>If the port program closes its <c>stdout</c> without exiting, + option <c>exit_status</c> does not work.</p> </item> <tag><c>use_stdio</c></tag> <item> - <p>This is only valid for <c>{spawn, <anno>Command</anno>}</c> and + <p>Only valid for <c>{spawn, <anno>Command</anno>}</c> and <c>{spawn_executable, <anno>FileName</anno>}</c>. It allows the standard input and output (file descriptors 0 - and 1) of the spawned (UNIX) process for communication + and 1) of the spawned (Unix) process for communication with Erlang.</p> </item> <tag><c>nouse_stdio</c></tag> <item> - <p>The opposite of <c>use_stdio</c>. Uses file descriptors + <p>The opposite of <c>use_stdio</c>. It uses file descriptors 3 and 4 for communication with Erlang.</p> </item> <tag><c>stderr_to_stdout</c></tag> @@ -3304,14 +3477,15 @@ os_prompt% </pre> </item> <tag><c>overlapped_io</c></tag> <item> - <p>Affects ports to external programs on Windows® only. - The standard input and standard output handles of the port program - will, if this option is supplied, be opened with the flag - FILE_FLAG_OVERLAPPED, so that the port program can (and has to) do + <p>Affects ports to external programs on Windows only. The + standard input and standard output handles of the port program + are, if this option is supplied, opened with flag + <c>FILE_FLAG_OVERLAPPED</c>, so that the port program can + (and must) do overlapped I/O on its standard handles. This is not normally the case for simple port programs, but an option of value for the - experienced Windows programmer. <em>On all other platforms, this - option is silently discarded</em>.</p> + experienced Windows programmer. <em>On all other platforms, this + option is silently discarded.</em></p> </item> <tag><c>in</c></tag> <item> @@ -3323,345 +3497,354 @@ os_prompt% </pre> </item> <tag><c>binary</c></tag> <item> - <p>All IO from the port are binary data objects as opposed + <p>All I/O from the port is binary data objects as opposed to lists of bytes.</p> </item> <tag><c>eof</c></tag> <item> - <p>The port will not be closed at the end of the file and - produce an exit signal. Instead, it will remain open and - a <c>{Port, eof}</c> message will be sent to the process + <p>The port is not closed at the end of the file and does not + produce an exit signal. Instead, it remains open and + a <c>{Port, eof}</c> message is sent to the process holding the port.</p> </item> <tag><c>hide</c></tag> <item> - <p>When running on Windows, suppress creation of a new + <p>When running on Windows, suppresses creation of a new console window when spawning the port program. (This option has no effect on other platforms.)</p> </item> - <tag><marker id="open_port_parallelism"><c>{parallelism, Boolean}</c></marker></tag> + <tag><c>{parallelism, Boolean}</c></tag> <item> - <p>Set scheduler hint for port parallelism. If set to <c>true</c>, - the VM will schedule port tasks when doing so will improve - parallelism in the system. If set to <c>false</c>, the VM will - try to perform port tasks immediately, improving latency at the - expense of parallelism. The default can be set on system startup - by passing the - <seealso marker="erl#+spp">+spp</seealso> command line argument - to <seealso marker="erl">erl(1)</seealso>. - </p> + <marker id="open_port_parallelism"></marker> + <p>Sets scheduler hint for port parallelism. If set to + <c>true</c>, the Virtual Machine schedules port tasks; + when doing so, it improves parallelism in the system. If set + to <c>false</c>, the Virtual Machine tries to + perform port tasks immediately, improving latency at the + expense of parallelism. The default can be set at system startup + by passing command-line argument + <seealso marker="erl#+spp">+spp</seealso> to <c>erl(1)</c>.</p> </item> </taglist> - <p>The default is <c>stream</c> for all types of port and + <p>Default is <c>stream</c> for all port types and <c>use_stdio</c> for spawned ports.</p> <p>Failure: If the port cannot be opened, the exit reason is - <c>badarg</c>, <c>system_limit</c>, or the Posix error code which - most closely describes the error, or <c>einval</c> if no Posix code - is appropriate:</p> + <c>badarg</c>, <c>system_limit</c>, or the POSIX error code that + most closely describes the error, or <c>einval</c> if no POSIX + code is appropriate:</p> <taglist> <tag><c>badarg</c></tag> - <item> - <p>Bad input arguments to <c>open_port</c>.</p> + <item>Bad input arguments to <c>open_port</c>. </item> <tag><c>system_limit</c></tag> - <item> - <p>All available ports in the Erlang emulator are in use.</p> + <item>All available ports in the Erlang emulator are in use. </item> <tag><c>enomem</c></tag> - <item> - <p>There was not enough memory to create the port.</p> + <item>Not enough memory to create the port. </item> <tag><c>eagain</c></tag> - <item> - <p>There are no more available operating system processes.</p> + <item>No more available OS processes. </item> <tag><c>enametoolong</c></tag> - <item> - <p>The external command given was too long.</p> + <item>Too long external command. </item> <tag><c>emfile</c></tag> - <item> - <p>There are no more available file descriptors (for the operating system process - that the Erlang emulator runs in).</p> + <item>No more available file descriptors (for the + OS process that the Erlang emulator runs in). </item> <tag><c>enfile</c></tag> - <item> - <p>The file table is full (for the entire operating system).</p> + <item>Full file table (for the entire OS). </item> <tag><c>eacces</c></tag> - <item> - <p>The <c>Command</c> given in <c>{spawn_executable, Command}</c> does not point out an executable file.</p> + <item><c>Command</c> given in <c>{spawn_executable, Command}</c> + does not point out an executable file. </item> <tag><c>enoent</c></tag> - <item> - <p>The <c><anno>FileName</anno></c> given in <c>{spawn_executable, <anno>FileName</anno>}</c> does not point out an existing file.</p> + <item><c><anno>FileName</anno></c> given in + <c>{spawn_executable, <anno>FileName</anno>}</c> + does not point out an existing file. </item> </taglist> <p>During use of a port opened using <c>{spawn, Name}</c>, - <c>{spawn_driver, Name}</c> or <c>{spawn_executable, Name}</c>, + <c>{spawn_driver, Name}</c>, or <c>{spawn_executable, Name}</c>, errors arising when sending messages to it are reported to the owning process using signals of the form - <c>{'EXIT', Port, PosixCode}</c>. See <c>file(3)</c> for - possible values of <c>PosixCode</c>.</p> + <c>{'EXIT', Port, PosixCode}</c>. For the possible values of + <c>PosixCode</c>, see the + <seealso marker="kernel:file">file(3)</seealso> + manual page in <c>Kernel</c>.</p> <p>The maximum number of ports that can be open at the same - time can be configured by passing the - <seealso marker="erl#max_ports"><c>+Q</c></seealso> - command line flag to - <seealso marker="erl"><c>erl(1)</c></seealso>.</p> + time can be configured by passing command-line flag + <seealso marker="erl#max_ports"><c>+Q</c></seealso> to + <c>erl(1)</c>.</p> </desc> </func> + <func> <name name="phash" arity="2"/> + <fsummary>Portable hash function.</fsummary> <type_desc variable="Range">Range = 1..2^32, Hash = 1..Range</type_desc> - <fsummary>Portable hash function</fsummary> <desc> - <p>Portable hash function that will give the same hash for + <p>Portable hash function that gives the same hash for the same Erlang term regardless of machine architecture and - ERTS version (the BIF was introduced in ERTS 4.9.1.1). Range - can be between 1 and 2^32, the function returns a hash value - for <c><anno>Term</anno></c> within the range <c>1..<anno>Range</anno></c>.</p> - <p>This BIF could be used instead of the old deprecated - <c>erlang:hash/2</c> BIF, as it calculates better hashes for - all data-types, but consider using <c>phash2/1,2</c> instead.</p> + <c>ERTS</c> version (the BIF was introduced in <c>ERTS</c> 4.9.1.1). + The function returns a hash value for + <c><anno>Term</anno></c> within the range + <c>1..<anno>Range</anno></c>. The maximum value for + <c><anno>Range</anno></c> is 2^32.</p> + <p>This BIF can be used instead of the old deprecated BIF + <c>erlang:hash/2</c>, as it calculates better hashes for + all data types, but consider using <c>phash2/1,2</c> instead.</p> </desc> </func> + <func> <name name="phash2" arity="1"/> <name name="phash2" arity="2"/> + <fsummary>Portable hash function.</fsummary> <type_desc variable="Range">1..2^32</type_desc> <type_desc variable="Hash">0..Range-1</type_desc> - <fsummary>Portable hash function</fsummary> <desc> - <p>Portable hash function that will give the same hash for + <p>Portable hash function that gives the same hash for the same Erlang term regardless of machine architecture and - ERTS version (the BIF was introduced in ERTS 5.2). Range can - be between 1 and 2^32, the function returns a hash value for - <c><anno>Term</anno></c> within the range <c>0..<anno>Range</anno>-1</c>. When called - without the <c><anno>Range</anno></c> argument, a value in the range - <c>0..2^27-1</c> is returned.</p> - <p>This BIF should always be used for hashing terms. It + <c>ERTS</c> version (the BIF was introduced in <c>ERTS</c> 5.2). + The function returns a hash value for + <c><anno>Term</anno></c> within the range + <c>0..<anno>Range</anno>-1</c>. The maximum value for + <c><anno>Range</anno></c> is 2^32. When without argument + <c><anno>Range</anno></c>, a value in the range + 0..2^27-1 is returned.</p> + <p>This BIF is always to be used for hashing terms. It distributes small integers better than <c>phash/2</c>, and it is faster for bignums and binaries.</p> - <p>Note that the range <c>0..<anno>Range</anno>-1</c> is different from - the range of <c>phash/2</c> (<c>1..<anno>Range</anno></c>).</p> + <p>Notice that the range <c>0..<anno>Range</anno>-1</c> is + different from the range of <c>phash/2</c>, which is + <c>1..<anno>Range</anno></c>.</p> </desc> </func> + <func> <name name="pid_to_list" arity="1"/> - <fsummary>Text representation of a pid</fsummary> + <fsummary>Text representation of a pid.</fsummary> <desc> - <p>Returns a string which corresponds to the text + <p>Returns a string corresponding to the text representation of <c><anno>Pid</anno></c>.</p> <warning> - <p>This BIF is intended for debugging and for use in - the Erlang operating system. It should not be used in - application programs.</p> + <p>This BIF is intended for debugging and is not to be used + in application programs.</p> </warning> </desc> </func> + <func> <name name="port_close" arity="1"/> - <fsummary>Close an open port</fsummary> + <fsummary>Closes an open port.</fsummary> <desc> <p>Closes an open port. Roughly the same as - <c><anno>Port</anno> ! {self(), close}</c> except for the error behaviour - (see below), being synchronous, and that the port does - <em>not</em> reply with <c>{Port, closed}</c>. Any process may + <c><anno>Port</anno> ! {self(), close}</c> except for the error behavior + (see the following), being synchronous, and that the port does + <em>not</em> reply with <c>{Port, closed}</c>. Any process can close a port with <c>port_close/1</c>, not only the port owner (the connected process). If the calling process is linked to - port identified by <c><anno>Port</anno></c>, an exit signal due - to that link will be received by the process prior to the return - from <c>port_close/1</c>.</p> - <p>For comparison: <c><anno>Port</anno> ! {self(), close}</c> fails with - <c>badarg</c> if <c><anno>Port</anno></c> cannot be sent to (i.e., - <c><anno>Port</anno></c> refers neither to a port nor to a process). If - <c><anno>Port</anno></c> is a closed port nothing happens. If <c><anno>Port</anno></c> + the port identified by <c><anno>Port</anno></c>, the exit + signal from the port is guaranteed to be delivered before + <c>port_close/1</c> returns.</p> + <p>For comparison: <c><anno>Port</anno> ! {self(), close}</c> + only fails with <c>badarg</c> if <c><anno>Port</anno></c> does + not refer to a port or a process. If <c><anno>Port</anno></c> + is a closed port, nothing happens. If <c><anno>Port</anno></c> is an open port and the calling process is the port owner, - the port replies with <c>{Port, closed}</c> when all buffers - have been flushed and the port really closes, but if - the calling process is not the port owner the <em>port owner</em> fails with <c>badsig</c>.</p> - - <p>Note that any process can close a port using - <c><anno>Port</anno> ! {PortOwner, close}</c> just as if it itself was + the port replies with <c>{Port, closed}</c> when all buffers + have been flushed and the port really closes. If the calling + process is not the port owner, the <em>port owner</em> fails + with <c>badsig</c>.</p> + <p>Notice that any process can close a port using + <c><anno>Port</anno> ! {PortOwner, close}</c> as if it itself was the port owner, but the reply always goes to the port owner.</p> - <p>As of OTP-R16 <c><anno>Port</anno> ! {PortOwner, close}</c> is truly - asynchronous. Note that this operation has always been + <p>As from OTP R16, <c><anno>Port</anno> ! {PortOwner, close}</c> is truly + asynchronous. Notice that this operation has always been documented as an asynchronous operation, while the underlying implementation has been synchronous. <c>port_close/1</c> is - however still fully synchronous. This due to its error + however still fully synchronous. This because of its error behavior.</p> - <p>Failure:</p> - <taglist> - <tag><c>badarg</c></tag> - <item> - If <c><anno>Port</anno></c> is not an identifier of an open - port, or the registered name of an open port. If the calling - process was linked to the previously open port identified by - <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to this exception. - </item> - </taglist> + <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not an identifier + of an open port, or the registered name of an open port. + If the calling process was previously linked to the closed + port, identified by <c><anno>Port</anno></c>, the exit + signal from the port is guaranteed to be delivered before + this <c>badarg</c> exception occurs.</p> </desc> </func> + <func> <name name="port_command" arity="2"/> - <fsummary>Send data to a port</fsummary> + <fsummary>Sends data to a port.</fsummary> <desc> <p>Sends data to a port. Same as - <c><anno>Port</anno> ! {PortOwner, {command, Data}}</c> except for the error - behaviour and being synchronous (see below). Any process may - send data to a port with <c>port_command/2</c>, not only the + <c><anno>Port</anno> ! {PortOwner, {command, Data}}</c> except + for the error + behavior and being synchronous (see the following). Any process + can send data to a port with <c>port_command/2</c>, not only the port owner (the connected process).</p> <p>For comparison: <c><anno>Port</anno> ! {PortOwner, {command, Data}}</c> - fails with <c>badarg</c> if <c><anno>Port</anno></c> cannot be sent to - (i.e., <c><anno>Port</anno></c> refers neither to a port nor to a process). - If <c><anno>Port</anno></c> is a closed port the data message disappears + only fails with <c>badarg</c> if <c><anno>Port</anno></c> + does not refer to a port or a process. If + <c><anno>Port</anno></c> is a closed port, the data message + disappears without a sound. If <c><anno>Port</anno></c> is open and the calling process is not the port owner, the <em>port owner</em> fails with <c>badsig</c>. The port owner fails with <c>badsig</c> - also if <c><anno>Data</anno></c> is not a valid IO list.</p> - <p>Note that any process can send to a port using - <c><anno>Port</anno> ! {PortOwner, {command, <anno>Data</anno>}}</c> just as if it - itself was the port owner.</p> - <p>If the port is busy, the calling process will be suspended - until the port is not busy anymore.</p> - <p>As of OTP-R16 <c><anno>Port</anno> ! {PortOwner, {command, Data}}</c> is - truly asynchronous. Note that this operation has always been + also if <c><anno>Data</anno></c> is an invalid I/O list.</p> + <p>Notice that any process can send to a port using + <c><anno>Port</anno> ! {PortOwner, {command, <anno>Data</anno>}}</c> + as if it itself was the port owner.</p> + <p>If the port is busy, the calling process is suspended + until the port is not busy any more.</p> + <p>As from OTP-R16, <c><anno>Port</anno> ! {PortOwner, {command, Data}}</c> + is truly asynchronous. Notice that this operation has always been documented as an asynchronous operation, while the underlying implementation has been synchronous. <c>port_command/2</c> is - however still fully synchronous. This due to its error + however still fully synchronous. This because of its error behavior.</p> <p>Failures:</p> <taglist> <tag><c>badarg</c></tag> <item> If <c><anno>Port</anno></c> is not an identifier of an open - port, or the registered name of an open port. If the calling - process was linked to the previously open port identified by - <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to this exception. + port, or the registered name of an open port. If the + calling process was previously linked to the closed port, + identified by <c><anno>Port</anno></c>, the exit signal + from the port is guaranteed to be delivered before this + <c>badarg</c> exception occurs. </item> <tag><c>badarg</c></tag> <item> - If <c><anno>Data</anno></c> is not a valid io list. + If <c><anno>Data</anno></c> is an invalid I/O list. </item> </taglist> </desc> </func> + <func> <name name="port_command" arity="3"/> - <fsummary>Send data to a port</fsummary> + <fsummary>Sends data to a port.</fsummary> <desc> <p>Sends data to a port. <c>port_command(Port, Data, [])</c> equals <c>port_command(Port, Data)</c>.</p> - <p>If the port command is aborted <c>false</c> is returned; - otherwise, <c>true</c> is returned.</p> - <p>If the port is busy, the calling process will be suspended - until the port is not busy anymore.</p> - <p>Currently the following <c><anno>Option</anno></c>s are valid:</p> + <p>If the port command is aborted, <c>false</c> is returned, + otherwise <c>true</c>.</p> + <p>If the port is busy, the calling process is suspended + until the port is not busy any more.</p> + <p>The following <c><anno>Option</anno></c>s are valid:</p> <taglist> <tag><c>force</c></tag> - <item>The calling process will not be suspended if the port is - busy; instead, the port command is forced through. The - call will fail with a <c>notsup</c> exception if the + <item>The calling process is not suspended if the port is + busy, instead the port command is forced through. The + call fails with a <c>notsup</c> exception if the driver of the port does not support this. For more - information see the - <seealso marker="driver_entry#driver_flags"><![CDATA[ERL_DRV_FLAG_SOFT_BUSY]]></seealso> - driver flag. + information, see driver flag + <seealso marker="driver_entry#driver_flags"><![CDATA[ERL_DRV_FLAG_SOFT_BUSY]]></seealso>. </item> <tag><c>nosuspend</c></tag> - <item>The calling process will not be suspended if the port is - busy; instead, the port command is aborted and + <item>The calling process is not suspended if the port is + busy, instead the port command is aborted and <c>false</c> is returned. </item> </taglist> <note> - <p>More options may be added in the future.</p> + <p>More options can be added in a future release.</p> </note> <p>Failures:</p> <taglist> <tag><c>badarg</c></tag> <item> If <c><anno>Port</anno></c> is not an identifier of an open - port, or the registered name of an open port. If the calling - process was linked to the previously open port identified by - <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to this exception. + port, or the registered name of an open port. If the + calling process was previously linked to the closed port, + identified by <c><anno>Port</anno></c>, the exit signal + from the port is guaranteed to be delivered before this + <c>badarg</c> exception occurs. </item> <tag><c>badarg</c></tag> <item> - If <c><anno>Data</anno></c> is not a valid io list. + If <c><anno>Data</anno></c> is an invalid I/O list. </item> <tag><c>badarg</c></tag> <item> - If <c><anno>OptionList</anno></c> is not a valid option list. + If <c><anno>OptionList</anno></c> is an invalid option list. </item> <tag><c>notsup</c></tag> <item> - If the <c>force</c> option has been passed, but the + If option <c>force</c> has been passed, but the driver of the port does not allow forcing through a busy port. </item> </taglist> </desc> </func> + <func> <name name="port_connect" arity="2"/> - <fsummary>Set the owner of a port</fsummary> + <fsummary>Sets the owner of a port.</fsummary> <desc> <p>Sets the port owner (the connected port) to <c><anno>Pid</anno></c>. - Roughly the same as <c><anno>Port</anno> ! {Owner, {connect, <anno>Pid</anno>}}</c> + Roughly the same as + <c><anno>Port</anno> ! {Owner, {connect, <anno>Pid</anno>}}</c> except for the following:</p> <list type="bulleted"> <item> - <p>The error behavior differs, see below.</p> + <p>The error behavior differs, see the following.</p> </item> <item> <p>The port does <em>not</em> reply with <c>{Port,connected}</c>.</p> </item> <item> - <p><c>port_connect/1</c> is synchronous, see below.</p> + <p><c>port_connect/1</c> is synchronous, see the following.</p> </item> <item> <p>The new port owner gets linked to the port.</p> </item> </list> - <p>The old port owner stays linked to the port and have to call - <c>unlink(Port)</c> if this is not desired. Any process may + <p>The old port owner stays linked to the port and must call + <c>unlink(Port)</c> if this is not desired. Any process can set the port owner to be any process with <c>port_connect/2</c>.</p> - <p>For comparison: <c><anno>Port</anno> ! {self(), {connect, <anno>Pid</anno>}}</c> fails - with <c>badarg</c> if <c><anno>Port</anno></c> cannot be sent to (i.e., - <c><anno>Port</anno></c> refers neither to a port nor to a process). If - <c><anno>Port</anno></c> is a closed port nothing happens. If <c><anno>Port</anno></c> + <p>For comparison: + <c><anno>Port</anno> ! {self(), {connect, <anno>Pid</anno>}}</c> + only fails with <c>badarg</c> if <c><anno>Port</anno></c> + does not refer to a port or a process. If + <c><anno>Port</anno></c> is a closed port, nothing happens. + If <c><anno>Port</anno></c> is an open port and the calling process is the port owner, the port replies with <c>{Port, connected}</c> to the old - port owner. Note that the old port owner is still linked to - the port, and that the new is not. If <c><anno>Port</anno></c> is an open + port owner. Notice that the old port owner is still linked to + the port, while the new is not. If <c><anno>Port</anno></c> is an open port and the calling process is not the port owner, the <em>port owner</em> fails with <c>badsig</c>. The port owner fails with <c>badsig</c> also if <c><anno>Pid</anno></c> is not an - existing local pid.</p> - <p>Note that any process can set the port owner using - <c><anno>Port</anno> ! {PortOwner, {connect, <anno>Pid</anno>}}</c> just as if it - itself was the port owner, but the reply always goes to + existing local process identifier.</p> + <p>Notice that any process can set the port owner using + <c><anno>Port</anno> ! {PortOwner, {connect, <anno>Pid</anno>}}</c> + as if it itself was the port owner, but the reply always goes to the port owner.</p> - <p>As of OTP-R16 <c><anno>Port</anno> ! {PortOwner, {connect, <anno>Pid</anno>}}</c> is - truly asynchronous. Note that this operation has always been + <p>As from OTP-R16, + <c><anno>Port</anno> ! {PortOwner, {connect, <anno>Pid</anno>}}</c> is + truly asynchronous. Notice that this operation has always been documented as an asynchronous operation, while the underlying implementation has been synchronous. <c>port_connect/2</c> is - however still fully synchronous. This due to its error + however still fully synchronous. This because of its error behavior.</p> <p>Failures:</p> <taglist> <tag><c>badarg</c></tag> <item> - If <c><anno>Port</anno></c> is not an identifier of an open - port, or the registered name of an open port. If the calling - process was linked to the previously open port identified by - <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to this exception. + If <c><anno>Port</anno></c> is not an identifier of an open port, or + the registered name of an open port. If the calling + process was previously linked to the closed port, + identified by <c><anno>Port</anno></c>, the exit signal + from the port is guaranteed to be delivered before this + <c>badarg</c> exception occurs. </item> <tag><c>badarg</c></tag> <item>If process identified by <c>Pid</c> is not an existing @@ -3669,53 +3852,75 @@ os_prompt% </pre> </taglist> </desc> </func> + <func> <name name="port_control" arity="3"/> - <fsummary>Perform a synchronous control operation on a port</fsummary> + <fsummary>Performs a synchronous control operation on a port.</fsummary> <desc> <p>Performs a synchronous control operation on a port. - The meaning of <c><anno>Operation</anno></c> and <c><anno>Data</anno></c> depends on - the port, i.e., on the port driver. Not all port drivers + The meaning of <c><anno>Operation</anno></c> and + <c><anno>Data</anno></c> depends on + the port, that is, on the port driver. Not all port drivers support this control feature.</p> - <p>Returns: a list of integers in the range 0 through 255, or a + <p>Returns a list of integers in the range 0..255, or a binary, depending on the port driver. The meaning of the returned data also depends on the port driver.</p> - <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not an open port or - the registered name of an open port, if <c><anno>Operation</anno></c> - cannot fit in a 32-bit integer, if the port driver does not - support synchronous control operations, or if the port driver - so decides for any reason (probably something wrong with - <c><anno>Operation</anno></c> or <c><anno>Data</anno></c>).</p> + <p>Failures:</p> + <taglist> + <tag><c>badarg</c></tag> + <item> + If <c><anno>Port</anno></c> is not an open port or the registered + name of an open port. + </item> + <tag><c>badarg</c></tag> + <item> + If <c><anno>Operation</anno></c> cannot fit in a 32-bit integer. + </item> + <tag><c>badarg</c></tag> + <item> + If the port driver does not support synchronous control + operations. + </item> + <tag><c>badarg</c></tag> + <item> + If the port driver so decides for any reason (probably + something wrong with <c><anno>Operation</anno></c> or + <c><anno>Data</anno></c>). + </item> + </taglist> </desc> </func> + <func> <name name="port_call" arity="3"/> - <fsummary>Synchronous call to a port with term data</fsummary> + <fsummary>Performs a synchronous call to a port with term data.</fsummary> <desc> <p>Performs a synchronous call to a port. The meaning of - <c><anno>Operation</anno></c> and <c><anno>Data</anno></c> depends on the port, i.e., + <c><anno>Operation</anno></c> and <c><anno>Data</anno></c> + depends on the port, that is, on the port driver. Not all port drivers support this feature.</p> - <p><c><anno>Port</anno></c> is a port identifier, referring to a driver.</p> + <p><c><anno>Port</anno></c> is a port identifier, + referring to a driver.</p> <p><c><anno>Operation</anno></c> is an integer, which is passed on to the driver.</p> - <p><c><anno>Data</anno></c> is any Erlang term. This data is converted to - binary term format and sent to the port.</p> - <p>Returns: a term from the driver. The meaning of the returned + <p><c><anno>Data</anno></c> is any Erlang term. This data is converted + to binary term format and sent to the port.</p> + <p>Returns a term from the driver. The meaning of the returned data also depends on the port driver.</p> <p>Failures:</p> <taglist> <tag><c>badarg</c></tag> <item> - If <c><anno>Port</anno></c> is not an identifier of an open - port, or the registered name of an open port. If the calling - process was linked to the previously open port identified by - <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to this exception. + If <c><anno>Port</anno></c> is not an identifier of an open port, + or the registered name of an open port. If the calling + process was previously linked to the closed port, + identified by <c><anno>Port</anno></c>, the exit signal + from the port is guaranteed to be delivered before this + <c>badarg</c> exception occurs. </item> <tag><c>badarg</c></tag> <item> - If <c><anno>Operation</anno></c> does not fit in a - 32-bit integer. + If <c><anno>Operation</anno></c> does not fit in a 32-bit integer. </item> <tag><c>badarg</c></tag> <item> @@ -3725,171 +3930,183 @@ os_prompt% </pre> <tag><c>badarg</c></tag> <item> If the port driver so decides for any reason (probably - something wrong with <c><anno>Operation</anno></c>, or - <c><anno>Data</anno></c>). + something wrong with <c><anno>Operation</anno></c> + or <c><anno>Data</anno></c>). </item> </taglist> </desc> </func> + <func> <name name="port_info" arity="1"/> - <fsummary>Information about a port</fsummary> + <fsummary>Information about a port.</fsummary> <desc> <p>Returns a list containing tuples with information about - the <c><anno>Port</anno></c>, or <c>undefined</c> if the port is not open. - The order of the tuples is not defined, nor are all the - tuples mandatory. - If <c>undefined</c> is returned and the calling process - was linked to a previously open port identified by - <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to the return from - <c>port_info/1</c>.</p> - <p>Currently the result will containt information about the - following <c>Item</c>s: <c>registered_name</c> (if the port has - a registered name), <c>id</c>, <c>connected</c>, <c>links</c>, - <c>name</c>, <c>input</c>, and <c>output</c>. For more information - about the different <c>Item</c>s, see + <c><anno>Port</anno></c>, or <c>undefined</c> if the port is not open. + The order of the tuples is undefined, and all the + tuples are not mandatory. + If the port is closed and the calling process + was previously linked to the port, the exit signal from the + port is guaranteed to be delivered before <c>port_info/1</c> + returns <c>undefined</c>.</p> + <p>The result contains information about the following + <c>Item</c>s:</p> + <list type="bulleted"> + <item><c>registered_name</c> (if the port has a registered + name)</item> + <item><c>id</c></item> + <item><c>connected</c></item> + <item><c>links</c></item> + <item><c>name</c></item> + <item><c>input</c></item> + <item><c>output</c></item> + </list> + <p>For more information about the different <c>Item</c>s, see <seealso marker="#port_info/2">port_info/2</seealso>.</p> <p>Failure: <c>badarg</c> if <c>Port</c> is not a local port identifier, or an atom.</p> </desc> </func> + <func> <name name="port_info" arity="2" clause_i="1"/> - <fsummary>Information about the connected process of a port</fsummary> + <fsummary>Information about the connected process of a port.</fsummary> <desc> <p><c><anno>Pid</anno></c> is the process identifier of the process connected to the port.</p> <p>If the port identified by <c><anno>Port</anno></c> is not open, - <c>undefined</c> is returned. If <c>undefined</c> is returned and - the calling process was linked to a previously open port identified - by <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to the return from - <c>port_info/2</c>.</p> + <c>undefined</c> is returned. If the port is closed and the + calling process was previously linked to the port, the exit + signal from the port is guaranteed to be delivered before + <c>port_info/2</c> returns <c>undefined</c>.</p> <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local port identifier, or an atom.</p> </desc> </func> + <func> <name name="port_info" arity="2" clause_i="2"/> - <fsummary>Information about the internal index of a port</fsummary> + <fsummary>Information about the internal index of a port.</fsummary> <desc> <p><c><anno>Index</anno></c> is the internal index of the port. This - index may be used to separate ports.</p> + index can be used to separate ports.</p> <p>If the port identified by <c><anno>Port</anno></c> is not open, - <c>undefined</c> is returned. If <c>undefined</c> is returned and - the calling process was linked to a previously open port identified - by <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to the return from - <c>port_info/2</c>.</p> + <c>undefined</c> is returned. If the port is closed and the + calling process was previously linked to the port, the exit + signal from the port is guaranteed to be delivered before + <c>port_info/2</c> returns <c>undefined</c>.</p> <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local port identifier, or an atom.</p> </desc> </func> + <func> <name name="port_info" arity="2" clause_i="3"/> - <fsummary>Information about the input of a port</fsummary> + <fsummary>Information about the input of a port.</fsummary> <desc> <p><c><anno>Bytes</anno></c> is the total number of bytes read from the port.</p> <p>If the port identified by <c><anno>Port</anno></c> is not open, - <c>undefined</c> is returned. If <c>undefined</c> is returned and - the calling process was linked to a previously open port identified - by <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to the return from - <c>port_info/2</c>.</p> + <c>undefined</c> is returned. If the port is closed and the + calling process was previously linked to the port, the exit + signal from the port is guaranteed to be delivered before + <c>port_info/2</c> returns <c>undefined</c>.</p> <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local port identifier, or an atom.</p> </desc> </func> + <func> <name name="port_info" arity="2" clause_i="4"/> - <fsummary>Information about the links of a port</fsummary> + <fsummary>Information about the links of a port.</fsummary> <desc> <p><c><anno>Pids</anno></c> is a list of the process identifiers of the processes that the port is linked to.</p> <p>If the port identified by <c><anno>Port</anno></c> is not open, - <c>undefined</c> is returned. If <c>undefined</c> is returned and - the calling process was linked to a previously open port identified - by <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to the return from - <c>port_info/2</c>.</p> + <c>undefined</c> is returned. If the port is closed and the + calling process was previously linked to the port, the exit + signal from the port is guaranteed to be delivered before + <c>port_info/2</c> returns <c>undefined</c>.</p> <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local port identifier, or an atom.</p> </desc> </func> + <func> <name name="port_info" arity="2" clause_i="5"/> - <fsummary>Information about the locking of a port</fsummary> + <fsummary>Information about the locking of a port.</fsummary> <desc> - <p><c><anno>Locking</anno></c> is currently either <c>false</c> - (emulator without SMP support), <c>port_level</c> (port specific - locking), or <c>driver_level</c> (driver specific locking). Note - that these results are highly implementation specific and might - change in the future.</p> + <p><c><anno>Locking</anno></c> is one of the following:</p> + <list type="bulleted"> + <item><c>false</c> (emulator without SMP support)</item> + <item><c>port_level</c> (port-specific locking)</item> + <item><c>driver_level</c> (driver-specific locking)</item> + </list> + <p>Notice that these results are highly implementation-specific + and can change in a future release.</p> <p>If the port identified by <c><anno>Port</anno></c> is not open, - <c>undefined</c> is returned. If <c>undefined</c> is returned and - the calling process was linked to a previously open port identified - by <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to the return from - <c>port_info/2</c>.</p> + <c>undefined</c> is returned. If the port is closed and the + calling process was previously linked to the port, the exit + signal from the port is guaranteed to be delivered before + <c>port_info/2</c> returns <c>undefined</c>.</p> <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local port identifier, or an atom.</p> </desc> </func> + <func> <name name="port_info" arity="2" clause_i="6"/> - <fsummary>Information about the memory size of a port</fsummary> + <fsummary>Information about the memory size of a port.</fsummary> <desc> - <p><c><anno>Bytes</anno></c> is the total amount of memory, - in bytes, allocated for this port by the runtime system. Note - that the port itself might have allocated memory which is not + <p><c><anno>Bytes</anno></c> is the total number of + bytes allocated for this port by the runtime system. The + port itself can have allocated memory that is not included in <c><anno>Bytes</anno></c>.</p> <p>If the port identified by <c><anno>Port</anno></c> is not open, - <c>undefined</c> is returned. If <c>undefined</c> is returned and - the calling process was linked to a previously open port identified - by <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to the return from - <c>port_info/2</c>.</p> + <c>undefined</c> is returned. If the port is closed and the + calling process was previously linked to the port, the exit + signal from the port is guaranteed to be delivered before + <c>port_info/2</c> returns <c>undefined</c>.</p> <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local port identifier, or an atom.</p> </desc> </func> + <func> <name name="port_info" arity="2" clause_i="7"/> - <fsummary>Information about the monitors of a port</fsummary> + <fsummary>Information about the monitors of a port.</fsummary> <desc> <p><c><anno>Monitors</anno></c> represent processes that this port - is monitoring.</p> + monitors.</p> <p>If the port identified by <c><anno>Port</anno></c> is not open, - <c>undefined</c> is returned. If <c>undefined</c> is returned and - the calling process was linked to a previously open port identified - by <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to the return from - <c>port_info/2</c>.</p> + <c>undefined</c> is returned. If the port is closed and the + calling process was previously linked to the port, the exit + signal from the port is guaranteed to be delivered before + <c>port_info/2</c> returns <c>undefined</c>.</p> <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local port identifier, or an atom.</p> </desc> </func> + <func> <name name="port_info" arity="2" clause_i="8"/> - <fsummary>Information about the name of a port</fsummary> + <fsummary>Information about the name of a port.</fsummary> <desc> <p><c><anno>Name</anno></c> is the command name set by <seealso marker="#open_port/2">open_port/2</seealso>.</p> <p>If the port identified by <c><anno>Port</anno></c> is not open, - <c>undefined</c> is returned. If <c>undefined</c> is returned and - the calling process was linked to a previously open port identified - by <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to the return from - <c>port_info/2</c>.</p> + <c>undefined</c> is returned. If the port is closed and the + calling process was previously linked to the port, the exit + signal from the port is guaranteed to be delivered before + <c>port_info/2</c> returns <c>undefined</c>.</p> <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local port identifier, or an atom.</p> </desc> </func> + <func> <name name="port_info" arity="2" clause_i="9"/> - <fsummary>Information about the OS pid of a port</fsummary> + <fsummary>Information about the OS pid of a port.</fsummary> <desc> <p><c><anno>OsPid</anno></c> is the process identifier (or equivalent) of an OS process created with @@ -3897,432 +4114,464 @@ os_prompt% </pre> Command}, Options)</seealso>. If the port is not the result of spawning an OS process, the value is <c>undefined</c>.</p> <p>If the port identified by <c><anno>Port</anno></c> is not open, - <c>undefined</c> is returned. If <c>undefined</c> is returned and - the calling process was linked to a previously open port identified - by <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to the return from - <c>port_info/2</c>.</p> + <c>undefined</c> is returned. If the port is closed and the + calling process was previously linked to the port, the exit + signal from the port is guaranteed to be delivered before + <c>port_info/2</c> returns <c>undefined</c>.</p> <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local port identifier, or an atom.</p> </desc> </func> + <func> <name name="port_info" arity="2" clause_i="10"/> - <fsummary>Information about the output of a port</fsummary> + <fsummary>Information about the output of a port.</fsummary> <desc> <p><c><anno>Bytes</anno></c> is the total number of bytes written - to the port from Erlang processes using either + to the port from Erlang processes using <seealso marker="#port_command/2">port_command/2</seealso>, <seealso marker="#port_command/3">port_command/3</seealso>, - or <c><anno>Port</anno> ! {Owner, {command, Data}</c>. - </p> + or <c><anno>Port</anno> ! {Owner, {command, Data}</c>.</p> <p>If the port identified by <c><anno>Port</anno></c> is not open, - <c>undefined</c> is returned. If <c>undefined</c> is returned and - the calling process was linked to a previously open port identified - by <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to the return from - <c>port_info/2</c>.</p> + <c>undefined</c> is returned. If the port is closed and the + calling process was previously linked to the port, the exit + signal from the port is guaranteed to be delivered before + <c>port_info/2</c> returns <c>undefined</c>.</p> <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local port identifier, or an atom.</p> </desc> </func> + <func> <name name="port_info" arity="2" clause_i="11"/> - <fsummary>Information about the parallelism hint of a port</fsummary> + <fsummary>Information about the parallelism hint of a port.</fsummary> <desc> <p><c><anno>Boolean</anno></c> corresponds to the port parallelism - hint being used by this port. For more information see - the <seealso marker="#open_port_parallelism">parallelism</seealso> - option of <seealso marker="#open_port/2">open_port/2</seealso>.</p> + hint being used by this port. For more information, see option + <seealso marker="#open_port_parallelism">parallelism</seealso> + of <seealso marker="#open_port/2">open_port/2</seealso>.</p> </desc> </func> + <func> <name name="port_info" arity="2" clause_i="12"/> - <fsummary>Information about the queue size of a port</fsummary> + <fsummary>Information about the queue size of a port.</fsummary> <desc> - <p><c><anno>Bytes</anno></c> is the total amount of data, - in bytes, queued by the port using the ERTS driver queue + <p><c><anno>Bytes</anno></c> is the total number + of bytes queued by the port using the <c>ERTS</c> driver queue implementation.</p> <p>If the port identified by <c><anno>Port</anno></c> is not open, - <c>undefined</c> is returned. If <c>undefined</c> is returned and - the calling process was linked to a previously open port identified - by <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to the return from - <c>port_info/2</c>.</p> + <c>undefined</c> is returned. If the port is closed and the + calling process was previously linked to the port, the exit + signal from the port is guaranteed to be delivered before + <c>port_info/2</c> returns <c>undefined</c>.</p> <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local port identifier, or an atom.</p> </desc> </func> + <func> <name name="port_info" arity="2" clause_i="13"/> - <fsummary>Information about the registered name of a port</fsummary> + <fsummary>Information about the registered name of a port.</fsummary> <desc> <p><c><anno>RegisteredName</anno></c> is the registered name of the port. If the port has no registered name, <c>[]</c> is returned.</p> <p>If the port identified by <c><anno>Port</anno></c> is not open, - <c>undefined</c> is returned. If <c>undefined</c> is returned and - the calling process was linked to a previously open port identified - by <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to the return from - <c>port_info/2</c>.</p> + <c>undefined</c> is returned. If the port is closed and the + calling process was previously linked to the port, the exit + signal from the port is guaranteed to be delivered before + <c>port_info/2</c> returns <c>undefined</c>.</p> <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local port identifier, or an atom.</p> </desc> </func> + <func> <name name="port_to_list" arity="1"/> - <fsummary>Text representation of a port identifier</fsummary> + <fsummary>Text representation of a port identifier.</fsummary> <desc> - <p>Returns a string which corresponds to the text + <p>Returns a string corresponding to the text representation of the port identifier <c><anno>Port</anno></c>.</p> <warning> - <p>This BIF is intended for debugging and for use in - the Erlang operating system. It should not be used in - application programs.</p> + <p>This BIF is intended for debugging. It is not to be used + in application programs.</p> </warning> </desc> </func> + <func> <name name="ports" arity="0"/> - <fsummary>All open ports</fsummary> + <fsummary>Lists all existing ports.</fsummary> <desc> <p>Returns a list of port identifiers corresponding to all the - ports currently existing on the local node.</p> - - <p>Note that a port that is exiting, exists but is not open.</p> + ports existing on the local node.</p> + <p>Notice that an exiting port exists, but is not open.</p> </desc> </func> + <func> <name name="pre_loaded" arity="0"/> - <fsummary>List of all pre-loaded modules</fsummary> + <fsummary>Lists all pre-loaded modules.</fsummary> <desc> - <p>Returns a list of Erlang modules which are pre-loaded in + <p>Returns a list of Erlang modules that are preloaded in the system. As all loading of code is done through the file system, the file system must have been loaded previously. - Hence, at least the module <c>init</c> must be pre-loaded.</p> + Hence, at least the module <c>init</c> must be preloaded.</p> </desc> </func> + <func> <name name="process_display" arity="2"/> - <fsummary>Write information about a local process on standard error</fsummary> + <fsummary>Writes information about a local process on standard error.</fsummary> <desc> <p>Writes information about the local process <c><anno>Pid</anno></c> on - standard error. The currently allowed value for the atom + standard error. The only allowed value for the atom <c><anno>Type</anno></c> is <c>backtrace</c>, which shows the contents of the call stack, including information about the call chain, with the current function printed first. The format of the output is not further defined.</p> </desc> </func> + <func> <name name="process_flag" arity="2" clause_i="1"/> - <fsummary>Set process flag trap_exit for the calling process</fsummary> + <fsummary>Sets process flag <c>trap_exit</c> for the calling process.</fsummary> <desc> <p>When <c>trap_exit</c> is set to <c>true</c>, exit signals - arriving to a process are converted to <c>{'EXIT', From, Reason}</c> messages, which can be received as ordinary + arriving to a process are converted to <c>{'EXIT', From, Reason}</c> + messages, which can be received as ordinary messages. If <c>trap_exit</c> is set to <c>false</c>, the process exits if it receives an exit signal other than <c>normal</c> and the exit signal is propagated to its - linked processes. Application processes should normally - not trap exits.</p> + linked processes. Application processes are normally + not to trap exits.</p> <p>Returns the old value of the flag.</p> <p>See also <seealso marker="#exit/2">exit/2</seealso>.</p> </desc> </func> + <func> <name name="process_flag" arity="2" clause_i="2"/> - <fsummary>Set process flag error_handler for the calling process</fsummary> + <fsummary>Sets process flag <c>error_handler</c> for the calling process.</fsummary> <desc> - <p>This is used by a process to redefine the error handler + <p>Used by a process to redefine the error handler for undefined function calls and undefined registered - processes. Inexperienced users should not use this flag - since code auto-loading is dependent on the correct + processes. Inexperienced users are not to use this flag, + as code auto-loading depends on the correct operation of the error handling module.</p> <p>Returns the old value of the flag.</p> </desc> </func> + <func> <name name="process_flag" arity="2" clause_i="3"/> - <fsummary>Set process flag min_heap_size for the calling process</fsummary> + <fsummary>Sets process flag <c>min_heap_size</c> for the calling process.</fsummary> <desc> - <p>This changes the minimum heap size for the calling - process.</p> + <p>Changes the minimum heap size for the calling process.</p> <p>Returns the old value of the flag.</p> </desc> </func> + <func> <name name="process_flag" arity="2" clause_i="4"/> - <fsummary>Set process flag min_bin_vheap_size for the calling process</fsummary> + <fsummary>Sets process flag <c>min_bin_vheap_size</c> for the calling process.</fsummary> <desc> - <p>This changes the minimum binary virtual heap size for the calling + <p>Changes the minimum binary virtual heap size for the calling process.</p> - <p>Returns the old value of the flag.</p> </desc> + <p>Returns the old value of the flag.</p> + </desc> </func> + <func> <name name="process_flag" arity="2" clause_i="5"/> + <fsummary>Sets process flag <c>priority</c> for the calling process.</fsummary> <type name="priority_level"/> - <fsummary>Set process flag priority for the calling process</fsummary> <desc> <p><marker id="process_flag_priority"></marker> - This sets the process priority. <c><anno>Level</anno></c> is an atom. - There are currently four priority levels: <c>low</c>, - <c>normal</c>, <c>high</c>, and <c>max</c>. The default - priority level is <c>normal</c>. <em>NOTE</em>: The - <c>max</c> priority level is reserved for internal use in - the Erlang runtime system, and should <em>not</em> be used - by others. - </p> - <p>Internally in each priority level processes are scheduled - in a round robin fashion. - </p> + Sets the process priority. <c><anno>Level</anno></c> is an atom. + There are four priority levels: <c>low</c>, + <c>normal</c>, <c>high</c>, and <c>max</c>. Default + is <c>normal</c>.</p> + <note> + <p>Priority level <c>max</c> is reserved for internal use in + the Erlang runtime system, and is <em>not</em> to be used + by others.</p> + </note> + <p>Internally in each priority level, processes are scheduled + in a round robin fashion.</p> <p>Execution of processes on priority <c>normal</c> and - priority <c>low</c> will be interleaved. Processes on - priority <c>low</c> will be selected for execution less - frequently than processes on priority <c>normal</c>. - </p> - <p>When there are runnable processes on priority <c>high</c> - no processes on priority <c>low</c>, or <c>normal</c> will - be selected for execution. Note, however, that this does - <em>not</em> mean that no processes on priority <c>low</c>, - or <c>normal</c> will be able to run when there are - processes on priority <c>high</c> running. On the runtime - system with SMP support there might be more processes running - in parallel than processes on priority <c>high</c>, i.e., - a <c>low</c>, and a <c>high</c> priority process might - execute at the same time. - </p> - <p>When there are runnable processes on priority <c>max</c> + <c>low</c> are interleaved. Processes on priority + <c>low</c> are selected for execution less + frequently than processes on priority <c>normal</c>.</p> + <p>When there are runnable processes on priority <c>high</c>, + no processes on priority <c>low</c> or <c>normal</c> are + selected for execution. Notice however, that this does + <em>not</em> mean that no processes on priority <c>low</c> + or <c>normal</c> can run when there are processes + running on priority <c>high</c>. On the runtime + system with SMP support, more processes can be running + in parallel than processes on priority <c>high</c>, that is, + a <c>low</c> and a <c>high</c> priority process can + execute at the same time.</p> + <p>When there are runnable processes on priority <c>max</c>, no processes on priority <c>low</c>, <c>normal</c>, or - <c>high</c> will be selected for execution. As with the - <c>high</c> priority, processes on lower priorities might - execute in parallel with processes on priority <c>max</c>. - </p> + <c>high</c> are selected for execution. As with priority + <c>high</c>, processes on lower priorities can + execute in parallel with processes on priority <c>max</c>.</p> <p>Scheduling is preemptive. Regardless of priority, a process - is preempted when it has consumed more than a certain amount + is preempted when it has consumed more than a certain number of reductions since the last time it was selected for - execution. - </p> - <p><em>NOTE</em>: You should not depend on the scheduling + execution.</p> + <note> + <p>Do not depend on the scheduling to remain exactly as it is today. Scheduling, at least on - the runtime system with SMP support, is very likely to be - modified in the future in order to better utilize available - processor cores. - </p> - <p>There is currently <em>no</em> automatic mechanism for - avoiding priority inversion, such as priority inheritance, - or priority ceilings. When using priorities you have - to take this into account and handle such scenarios by - yourself. - </p> + the runtime system with SMP support, is likely to be + changed in a future release to use available + processor cores better.</p> + </note> + <p>There is <em>no</em> automatic mechanism for + avoiding priority inversion, such as priority inheritance + or priority ceilings. When using priorities, + take this into account and handle such scenarios by + yourself.</p> <p>Making calls from a <c>high</c> priority process into code - that you don't have control over may cause the <c>high</c> - priority process to wait for a processes with lower - priority, i.e., effectively decreasing the priority of the + that you have no control over can cause the <c>high</c> + priority process to wait for a process with lower + priority. That is, effectively decreasing the priority of the <c>high</c> priority process during the call. Even if this - isn't the case with one version of the code that you don't - have under your control, it might be the case in a future - version of it. This might, for example, happen if a - <c>high</c> priority process triggers code loading, since - the code server runs on priority <c>normal</c>. - </p> + is not the case with one version of the code that you have no + control over, it can be the case in a future + version of it. This can, for example, occur if a + <c>high</c> priority process triggers code loading, as + the code server runs on priority <c>normal</c>.</p> <p>Other priorities than <c>normal</c> are normally not needed. - When other priorities are used, they need to be used - with care, especially the <c>high</c> priority <em>must</em> - be used with care. A process on <c>high</c> priority should - only perform work for short periods of time. Busy looping for - long periods of time in a <c>high</c> priority process will - most likely cause problems, since there are important servers - in OTP running on priority <c>normal</c>. - </p> + When other priorities are used, use them with care, + <em>especially</em> priority <c>high</c>. A + process on priority <c>high</c> is only + to perform work for short periods. Busy looping for + long periods in a <c>high</c> priority process does + most likely cause problems, as important OTP servers + run on priority <c>normal</c>.</p> <p>Returns the old value of the flag.</p> </desc> </func> + <func> <name name="process_flag" arity="2" clause_i="6"/> - <fsummary>Set process flag save_calls for the calling process</fsummary> + <fsummary>Sets process flag <c>save_calls</c> for the calling process.</fsummary> <desc> <p><c><anno>N</anno></c> must be an integer in the interval 0..10000. - If <c><anno>N</anno></c> > 0, call saving is made active for the - process, which means that information about the <c><anno>N</anno></c> - most recent global function calls, BIF calls, sends and + If <c><anno>N</anno></c> is greater than 0, call saving is made + active for the + process. This means that information about the <c><anno>N</anno></c> + most recent global function calls, BIF calls, sends, and receives made by the process are saved in a list, which can be retrieved with <c>process_info(Pid, last_calls)</c>. A global function call is one in which the module of the function is explicitly mentioned. Only a fixed amount of information - is saved: a tuple <c>{Module, Function, Arity}</c> for - function calls, and the mere atoms <c>send</c>, - <c>'receive'</c> and <c>timeout</c> for sends and receives - (<c>'receive'</c> when a message is received and - <c>timeout</c> when a receive times out). If <c>N</c> = 0, + is saved, as follows:</p> + <list type="bulleted"> + <item>A tuple <c>{Module, Function, Arity}</c> for + function calls</item> + <item> The atoms <c>send</c>, <c>'receive'</c>, and + <c>timeout</c> for sends and receives (<c>'receive'</c> + when a message is received and <c>timeout</c> when a + receive times out)</item> + </list> + <p>If <c>N</c> = 0, call saving is disabled for the process, which is the default. Whenever the size of the call saving list is set, its contents are reset.</p> <p>Returns the old value of the flag.</p> </desc> </func> + <func> <name name="process_flag" arity="2" clause_i="7"/> - <fsummary>Set process flag sensitive for the calling process</fsummary> + <fsummary>Sets process flag <c>sensitive</c> for the calling process.</fsummary> <desc> - <p>Set or clear the <c>sensitive</c> flag for the current process. + <p>Sets or clears flag <c>sensitive</c> for the current process. When a process has been marked as sensitive by calling - <c>process_flag(sensitive, true)</c>, features in the run-time - system that can be used for examining the data and/or inner working + <c>process_flag(sensitive, true)</c>, features in the runtime + system that can be used for examining the data or inner working of the process are silently disabled.</p> <p>Features that are disabled include (but are not limited to) the following:</p> - <p>Tracing: Trace flags can still be set for the process, but no - trace messages of any kind will be generated. - (If the <c>sensitive</c> flag is turned off, trace messages will - again be generated if there are any trace flags set.)</p> - <p>Sequential tracing: The sequential trace token will be propagated - as usual, but no sequential trace messages will be generated.</p> - <p><c>process_info/1,2</c> cannot be used to read out the message - queue or the process dictionary (both will be returned as empty lists).</p> + <list type="bulleted"> + <item>Tracing: Trace flags can still be set for the process, + but no trace messages of any kind are generated. (If flag + <c>sensitive</c> is turned off, trace messages are again + generated if any trace flags are set.)</item> + <item>Sequential tracing: The sequential trace token is + propagated as usual, but no sequential trace messages are + generated.</item> + </list> + <p><c>process_info/1,2</c> cannot be used to read out the + message queue or the process dictionary (both are returned + as empty lists).</p> <p>Stack back-traces cannot be displayed for the process.</p> <p>In crash dumps, the stack, messages, and the process dictionary - will be omitted.</p> + are omitted.</p> <p>If <c>{save_calls,N}</c> has been set for the process, no - function calls will be saved to the call saving list. - (The call saving list will not be cleared; furthermore, send, receive, - and timeout events will still be added to the list.)</p> + function calls are saved to the call saving list. + (The call saving list is not cleared. Furthermore, send, receive, + and timeout events are still added to the list.)</p> <p>Returns the old value of the flag.</p> </desc> </func> + <func> <name name="process_flag" arity="3"/> - <fsummary>Set process flags for a process</fsummary> + <fsummary>Sets process flags for a process.</fsummary> <desc> - <p>Sets certain flags for the process <c><anno>Pid</anno></c>, in the same - manner as + <p>Sets certain flags for the process <c><anno>Pid</anno></c>, + in the same manner as <seealso marker="#process_flag/2">process_flag/2</seealso>. - Returns the old value of the flag. The allowed values for + Returns the old value of the flag. The valid values for <c><anno>Flag</anno></c> are only a subset of those allowed in - <c>process_flag/2</c>, namely: <c>save_calls</c>.</p> - <p>Failure: <c>badarg</c> if <c><anno>Pid</anno></c> is not a local process.</p> + <c>process_flag/2</c>, namely <c>save_calls</c>.</p> + <p>Failure: <c>badarg</c> if <c><anno>Pid</anno></c> + is not a local process.</p> </desc> </func> + <func> <name name="process_info" arity="1"/> + <fsummary>Information about a process.</fsummary> <type name="process_info_result_item"/> <type name="priority_level"/> <type name="stack_item"/> - <fsummary>Information about a process</fsummary> <desc> <p>Returns a list containing <c><anno>InfoTuple</anno></c>s with miscellaneous information about the process identified by - <c>Pid</c>, or <c>undefined</c> if the process is not alive. - </p> - <p> - The order of the <c><anno>InfoTuple</anno></c>s is not defined, nor - are all the <c><anno>InfoTuple</anno></c>s mandatory. The <c><anno>InfoTuple</anno></c>s - part of the result may be changed without prior notice. - Currently <c><anno>InfoTuple</anno></c>s with the following items - are part of the result: - <c>current_function</c>, <c>initial_call</c>, <c>status</c>, - <c>message_queue_len</c>, <c>messages</c>, <c>links</c>, - <c>dictionary</c>, <c>trap_exit</c>, <c>error_handler</c>, - <c>priority</c>, <c>group_leader</c>, <c>total_heap_size</c>, - <c>heap_size</c>, <c>stack_size</c>, <c>reductions</c>, and - <c>garbage_collection</c>. - If the process identified by <c><anno>Pid</anno></c> has a registered name - also an <c><anno>InfoTuple</anno></c> with the item <c>registered_name</c> - will appear. - </p> - <p>See <seealso marker="#process_info/2">process_info/2</seealso> - for information about specific <c><anno>InfoTuple</anno></c>s.</p> + <c>Pid</c>, or <c>undefined</c> if the process is not alive.</p> + <p>The order of the <c><anno>InfoTuple</anno></c>s is undefined and + all <c><anno>InfoTuple</anno></c>s are not mandatory. + The <c><anno>InfoTuple</anno></c>s + part of the result can be changed without prior notice.</p> + <p>The <c><anno>InfoTuple</anno></c>s with the following items + are part of the result:</p> + <list type="bulleted"> + <item><c>current_function</c></item> + <item><c>initial_call</c></item> + <item><c>status</c></item> + <item><c>message_queue_len</c></item> + <item><c>messages</c></item> + <item><c>links</c></item> + <item><c>dictionary</c></item> + <item><c>trap_exit</c></item> + <item><c>error_handler</c></item> + <item><c>priority</c></item> + <item><c>group_leader</c></item> + <item><c>total_heap_size</c></item> + <item><c>heap_size</c></item> + <item><c>stack_size</c></item> + <item><c>reductions</c></item> + <item><c>garbage_collection</c></item> + </list> + <p>If the process identified by <c><anno>Pid</anno></c> has a + registered name, + also an <c><anno>InfoTuple</anno></c> with item <c>registered_name</c> + appears.</p> + <p>For information about specific <c><anno>InfoTuple</anno></c>s, see + <seealso marker="#process_info/2">process_info/2</seealso>.</p> <warning> - <p>This BIF is intended for <em>debugging only</em>, use - <seealso marker="#process_info/2">process_info/2</seealso> - for all other purposes. - </p> + <p>This BIF is intended for <em>debugging only</em>. For + all other purposes, use + <seealso marker="#process_info/2">process_info/2</seealso>.</p> </warning> - <p>Failure: <c>badarg</c> if <c>Pid</c> is not a local process.</p> + <p>Failure: <c>badarg</c> if <c><anno>Pid</anno></c> is not a + local process.</p> </desc> </func> + <func> <name name="process_info" arity="2" clause_i="1"/> <name name="process_info" arity="2" clause_i="2"/> + <fsummary>Information about a process.</fsummary> <type name="process_info_item"/> <type name="process_info_result_item"/> <type name="stack_item"/> <type name="priority_level"/> - <fsummary>Information about a process</fsummary> <desc> - <p>Returns information about the process identified by <c><anno>Pid</anno></c> - as specified by the <c><anno>Item</anno></c> or the <c><anno>ItemList</anno></c>, or <c>undefined</c> if the - process is not alive. - </p> - <p>If the process is alive and a single <c><anno>Item</anno></c> is given, - the returned value is the corresponding - <c><anno>InfoTuple</anno></c> unless <c>Item =:= registered_name</c> - and the process has no registered name. In this case - <c>[]</c> is returned. This strange behavior is due to - historical reasons, and is kept for backward compatibility. - </p> - <p>If an <c>ItemList</c> is given, the result is an - <c><anno>InfoTupleList</anno></c>. The <c><anno>InfoTuple</anno></c>s in the - <c><anno>InfoTupleList</anno></c> will appear with the corresponding - <c><anno>Item</anno></c>s in the same order as the <c><anno>Item</anno></c>s appeared - in the <c><anno>ItemList</anno></c>. Valid <c><anno>Item</anno></c>s may appear multiple - times in the <c><anno>ItemList</anno></c>. - </p> - <note><p>If <c>registered_name</c> is part of an <c><anno>ItemList</anno></c> + <p>Returns information about the process identified by + <c><anno>Pid</anno></c>, as specified by + <c><anno>Item</anno></c> or <c><anno>ItemList</anno></c>. + Returns <c>undefined</c> if the process is not alive.</p> + <p>If the process is alive and a single <c><anno>Item</anno></c> + is given, the returned value is the corresponding + <c><anno>InfoTuple</anno></c>, unless <c>Item =:= registered_name</c> + and the process has no registered name. In this case, + <c>[]</c> is returned. This strange behavior is because of + historical reasons, and is kept for backward compatibility.</p> + <p>If <c><anno>ItemList</anno></c> is given, the result is + <c><anno>InfoTupleList</anno></c>. + The <c><anno>InfoTuple</anno></c>s in + <c><anno>InfoTupleList</anno></c> appear with the corresponding + <c><anno>Item</anno></c>s in the same order as the + <c><anno>Item</anno></c>s appeared + in <c><anno>ItemList</anno></c>. Valid <c><anno>Item</anno></c>s can + appear multiple times in <c><anno>ItemList</anno></c>.</p> + <note><p>If <c>registered_name</c> is part of <c><anno>ItemList</anno></c> and the process has no name registered a - <c>{registered_name, []}</c> <c><anno>InfoTuple</anno></c> <em>will</em> - appear in the resulting <c><anno>InfoTupleList</anno></c>. This - behavior is different than when a single - <c>Item =:= registered_name</c> is given, and than when - <c>process_info/1</c> is used. - </p></note> - <p>Currently the following <c><anno>InfoTuple</anno></c>s with corresponding + <c>{registered_name, []}</c>, <c><anno>InfoTuple</anno></c> + <em>will</em> appear in the resulting + <c><anno>InfoTupleList</anno></c>. This + behavior is different when a single + <c>Item =:= registered_name</c> is given, and when + <c>process_info/1</c> is used.</p> + </note> + <p>The following <c><anno>InfoTuple</anno></c>s with corresponding <c><anno>Item</anno></c>s are valid:</p> <taglist> <tag><c>{backtrace, <anno>Bin</anno>}</c></tag> <item> - <p>The binary <c><anno>Bin</anno></c> contains the same information as - the output from + <p>Binary <c><anno>Bin</anno></c> contains the same information + as the output from <c>erlang:process_display(<anno>Pid</anno>, backtrace)</c>. Use <c>binary_to_list/1</c> to obtain the string of characters from the binary.</p> </item> <tag><c>{binary, <anno>BinInfo</anno>}</c></tag> <item> - <p><c><anno>BinInfo</anno></c> is a list containing miscellaneous information - about binaries currently being referred to by this process. - This <c><anno>InfoTuple</anno></c> may be changed or removed without prior - notice.</p> + <p><c><anno>BinInfo</anno></c> is a list containing miscellaneous + information about binaries currently being referred to by this + process. This <c><anno>InfoTuple</anno></c> can be changed or + removed without prior notice.</p> </item> <tag><c>{catchlevel, <anno>CatchLevel</anno>}</c></tag> <item> <p><c><anno>CatchLevel</anno></c> is the number of currently active - catches in this process. This <c><anno>InfoTuple</anno></c> may be + catches in this process. This <c><anno>InfoTuple</anno></c> can be changed or removed without prior notice.</p> </item> - <tag><c>{current_function, {<anno>Module</anno>, <anno>Function</anno>, <anno>Arity</anno>}}</c></tag> + <tag><c>{current_function, {<anno>Module</anno>, + <anno>Function</anno>, Arity}}</c></tag> <item> - <p><c><anno>Module</anno></c>, <c><anno>Function</anno></c>, <c><anno>Arity</anno></c> is + <p><c><anno>Module</anno></c>, <c><anno>Function</anno></c>, + <c><anno>Arity</anno></c> is the current function call of the process.</p> </item> - <tag><c>{current_location, {<anno>Module</anno>, <anno>Function</anno>, <anno>Arity</anno>, <anno>Location</anno>}}</c></tag> + <tag><c>{current_location, {<anno>Module</anno>, + <anno>Function</anno>, <anno>Arity</anno>, + <anno>Location</anno>}}</c></tag> <item> - <p><c><anno>Module</anno></c>, <c><anno>Function</anno></c>, <c><anno>Arity</anno></c> is + <p><c><anno>Module</anno></c>, <c><anno>Function</anno></c>, + <c><anno>Arity</anno></c> is the current function call of the process. - <c><anno>Location</anno></c> is a list of two-tuples that describes the - location in the source code. - </p> + <c><anno>Location</anno></c> is a list of two-tuples describing the + location in the source code.</p> </item> <tag><c>{current_stacktrace, <anno>Stack</anno>}</c></tag> <item> - <p>Return the current call stack back-trace (<em>stacktrace</em>) + <p>Returns the current call stack back-trace (<em>stacktrace</em>) of the process. The stack has the same format as returned by - <seealso marker="#get_stacktrace/0">erlang:get_stacktrace/0</seealso>. - </p> + <seealso marker="#get_stacktrace/0">erlang:get_stacktrace/0</seealso>.</p> </item> <tag><c>{dictionary, <anno>Dictionary</anno>}</c></tag> <item> - <p><c><anno>Dictionary</anno></c> is the dictionary of the process.</p> + <p><c><anno>Dictionary</anno></c> is the process dictionary.</p> </item> <tag><c>{error_handler, <anno>Module</anno>}</c></tag> <item> @@ -4331,34 +4580,36 @@ os_prompt% </pre> </item> <tag><c>{garbage_collection, <anno>GCInfo</anno>}</c></tag> <item> - <p><c><anno>GCInfo</anno></c> is a list which contains miscellaneous + <p><c><anno>GCInfo</anno></c> is a list containing miscellaneous information about garbage collection for this process. - The content of <c><anno>GCInfo</anno></c> may be changed without + The content of <c><anno>GCInfo</anno></c> can be changed without prior notice.</p> </item> <tag><c>{group_leader, <anno>GroupLeader</anno>}</c></tag> <item> - <p><c><anno>GroupLeader</anno></c> is group leader for the IO of + <p><c><anno>GroupLeader</anno></c> is group leader for the I/O of the process.</p> </item> <tag><c>{heap_size, <anno>Size</anno>}</c></tag> <item> - <p><c><anno>Size</anno></c> is the size in words of youngest heap generation - of the process. This generation currently include the stack - of the process. This information is highly implementation - dependent, and may change if the implementation change. - </p> + <p><c><anno>Size</anno></c> is the size in words of the youngest heap + generation of the process. This generation includes + the process stack. This information is highly + implementation-dependent, and can change if the + implementation changes.</p> </item> - <tag><c>{initial_call, {Module, Function, Arity}}</c></tag> + <tag><c>{initial_call, {<anno>Module</anno>, <anno>Function</anno>, + <anno>Arity</anno>}}</c></tag> <item> - <p><c>Module</c>, <c>Function</c>, <c>Arity</c> is + <p><c><anno>Module</anno></c>, <c><anno>Function</anno></c>, + <c><anno>Arity</anno></c> is the initial function call with which the process was spawned.</p> </item> <tag><c>{links, <anno>PidsAndPorts</anno>}</c></tag> <item> - <p><c><anno>PidsAndPorts</anno></c> is a list of pids and - port identifiers, with processes or ports to which the process + <p><c><anno>PidsAndPorts</anno></c> is a list of process identifiers + and port identifiers, with processes or ports to which the process has a link.</p> </item> <tag><c>{last_calls, false|Calls}</c></tag> @@ -4372,14 +4623,14 @@ os_prompt% </pre> <tag><c>{memory, <anno>Size</anno>}</c></tag> <item> <p><c><anno>Size</anno></c> is the size in bytes of the process. This - includes call stack, heap and internal structures.</p> + includes call stack, heap, and internal structures.</p> </item> <tag><c>{message_queue_len, <anno>MessageQueueLen</anno>}</c></tag> <item> <p><c><anno>MessageQueueLen</anno></c> is the number of messages currently in the message queue of the process. This is the length of the list <c><anno>MessageQueue</anno></c> returned as - the info item <c>messages</c> (see below).</p> + the information item <c>messages</c> (see the following).</p> </item> <tag><c>{messages, <anno>MessageQueue</anno>}</c></tag> <item> @@ -4388,31 +4639,35 @@ os_prompt% </pre> </item> <tag><c>{min_heap_size, <anno>MinHeapSize</anno>}</c></tag> <item> - <p><c><anno>MinHeapSize</anno></c> is the minimum heap size for the process.</p> + <p><c><anno>MinHeapSize</anno></c> is the minimum heap size + for the process.</p> </item> <tag><c>{min_bin_vheap_size, <anno>MinBinVHeapSize</anno>}</c></tag> <item> - <p><c><anno>MinBinVHeapSize</anno></c> is the minimum binary virtual heap size for the process.</p> + <p><c><anno>MinBinVHeapSize</anno></c> is the minimum binary virtual + heap size for the process.</p> </item> <tag><c>{monitored_by, <anno>Pids</anno>}</c></tag> <item> - <p>A list of pids that are monitoring the process (with + <p>A list of process identifiers monitoring the process (with <c>monitor/2</c>).</p> </item> <tag><c>{monitors, <anno>Monitors</anno>}</c></tag> <item> <p>A list of monitors (started by <c>monitor/2</c>) that are active for the process. For a local process - monitor or a remote process monitor by pid, the list item - is <c>{process, <anno>Pid</anno>}</c>, and for a remote process + monitor or a remote process monitor by a process + identifier, the list item is <c>{process, <anno>Pid</anno>}</c>. + For a remote process monitor by name, the list item is <c>{process, {<anno>RegName</anno>, <anno>Node</anno>}}</c>.</p> </item> - <tag><c>{priority, Level}</c></tag> + <tag><c>{priority, <anno>Level</anno>}</c></tag> <item> <p><c><anno>Level</anno></c> is the current priority level for - the process. For more information on priorities see - <seealso marker="#process_flag_priority">process_flag(priority, Level)</seealso>.</p> + the process. For more information on priorities, see + <seealso marker="#process_flag_priority">process_flag(priority, + Level)</seealso>.</p> </item> <tag><c>{reductions, <anno>Number</anno>}</c></tag> <item> @@ -4427,166 +4682,201 @@ os_prompt% </pre> </item> <tag><c>{sequential_trace_token, [] | <anno>SequentialTraceToken</anno>}</c></tag> <item> - <p><c><anno>SequentialTraceToken</anno></c> the sequential trace token for - the process. This <c><anno>InfoTuple</anno></c> may be changed or removed - without prior notice.</p> + <p><c><anno>SequentialTraceToken</anno></c> is the sequential trace + token for the process. This <c><anno>InfoTuple</anno></c> can be + changed or removed without prior notice.</p> </item> <tag><c>{stack_size, <anno>Size</anno>}</c></tag> <item> - <p><c><anno>Size</anno></c> is the stack size of the process in words.</p> + <p><c><anno>Size</anno></c> is the stack size, in words, + of the process.</p> </item> <tag><c>{status, <anno>Status</anno>}</c></tag> <item> - <p><c><anno>Status</anno></c> is the status of the process. <c><anno>Status</anno></c> - is <c>exiting</c>, <c>garbage_collecting</c>, - <c>waiting</c> (for a message), <c>running</c>, - <c>runnable</c> (ready to run, but another process is - running), or <c>suspended</c> (suspended on a "busy" port - or by the <c>erlang:suspend_process/[1,2]</c> BIF).</p> + <p><c><anno>Status</anno></c> is the status of the process and is one + of the following:</p> + <list type="bulleted"> + <item><c>exiting</c></item> + <item><c>garbage_collecting</c></item> + <item><c>waiting</c> (for a message)</item> + <item><c>running</c></item> + <item><c>runnable</c> (ready to run, but another process is + running)</item> + <item><c>suspended</c> (suspended on a "busy" port + or by the BIF <c>erlang:suspend_process/[1,2]</c>)</item> + </list> </item> <tag><c>{suspending, <anno>SuspendeeList</anno>}</c></tag> <item> - <p><c><anno>SuspendeeList</anno></c> is a list of <c>{<anno>Suspendee</anno>, - <anno>ActiveSuspendCount</anno>, <anno>OutstandingSuspendCount</anno>}</c> tuples. - <c><anno>Suspendee</anno></c> is the pid of a process that have been or is to - be suspended by the process identified by <c><anno>Pid</anno></c> via the - <seealso marker="#suspend_process/2">erlang:suspend_process/2</seealso> - BIF, or the - <seealso marker="#suspend_process/1">erlang:suspend_process/1</seealso> - BIF. <c><anno>ActiveSuspendCount</anno></c> is the number of times the - <c><anno>Suspendee</anno></c> has been suspended by <c><anno>Pid</anno></c>. + <p><c><anno>SuspendeeList</anno></c> is a list of + <c>{<anno>Suspendee</anno>, <anno>ActiveSuspendCount</anno>, + <anno>OutstandingSuspendCount</anno>}</c> tuples. + <c><anno>Suspendee</anno></c> is the process identifier of a + process that has been, or is to be, + suspended by the process identified by <c><anno>Pid</anno></c> + through one of the following BIFs:</p> + <list type="bulleted"> + <item> + <seealso marker="#suspend_process/2">erlang:suspend_process/2</seealso> + </item> + <item> + <seealso marker="#suspend_process/1">erlang:suspend_process/1</seealso> + </item> + </list> + <p><c><anno>ActiveSuspendCount</anno></c> is the number of + times <c><anno>Suspendee</anno></c> has been suspended by + <c><anno>Pid</anno></c>. <c><anno>OutstandingSuspendCount</anno></c> is the number of not yet - completed suspend requests sent by <c><anno>Pid</anno></c>. That is, - if <c><anno>ActiveSuspendCount</anno> =/= 0</c>, <c><anno>Suspendee</anno></c> is - currently in the suspended state, and if - <c><anno>OutstandingSuspendCount</anno> =/= 0</c> the <c>asynchronous</c> - option of <c>erlang:suspend_process/2</c> has been used and - the suspendee has not yet been suspended by <c><anno>Pid</anno></c>. - Note that the <c><anno>ActiveSuspendCount</anno></c> and - <c><anno>OutstandingSuspendCount</anno></c> are not the total suspend count - on <c><anno>Suspendee</anno></c>, only the parts contributed by <c>Pid</c>. - </p> + completed suspend requests sent by <c><anno>Pid</anno></c>, that is:</p> + <list type="bulleted"> + <item>If <c><anno>ActiveSuspendCount</anno> =/= 0</c>, + <c><anno>Suspendee</anno></c> is + currently in the suspended state. + </item> + <item>If <c><anno>OutstandingSuspendCount</anno> =/= 0</c>, option + <c>asynchronous</c> of <c>erlang:suspend_process/2</c> + has been used and the suspendee has not yet been + suspended by <c><anno>Pid</anno></c>. + </item> + </list> + <p>Notice that <c><anno>ActiveSuspendCount</anno></c> and + <c><anno>OutstandingSuspendCount</anno></c> are not the + total suspend count on <c><anno>Suspendee</anno></c>, + only the parts contributed by <c><anno>Pid</anno></c>.</p> </item> <tag><c>{total_heap_size, <anno>Size</anno>}</c></tag> <item> - <p><c><anno>Size</anno></c> is the total size in words of all heap - fragments of the process. This currently include the stack - of the process. - </p> + <p><c><anno>Size</anno></c> is the total size, in words, of all heap + fragments of the process. This includes the process stack.</p> </item> <tag><c>{trace, <anno>InternalTraceFlags</anno>}</c></tag> <item> - <p><c><anno>InternalTraceFlags</anno></c> is an integer representing - internal trace flag for this process. This <c><anno>InfoTuple</anno></c> - may be changed or removed without prior notice.</p> + <p><c><anno>InternalTraceFlags</anno></c> is an integer + representing the internal trace flag for this process. + This <c><anno>InfoTuple</anno></c> + can be changed or removed without prior notice.</p> </item> <tag><c>{trap_exit, <anno>Boolean</anno>}</c></tag> <item> - <p><c><anno>Boolean</anno></c> is <c>true</c> if the process is trapping - exits, otherwise it is <c>false</c>.</p> + <p><c><anno>Boolean</anno></c> is <c>true</c> if the process + is trapping exits, otherwise <c>false</c>.</p> </item> </taglist> - <p>Note however, that not all implementations support every one - of the above <c><anno>Item</anno></c>s.</p> - <p>Failure: <c>badarg</c> if <c><anno>Pid</anno></c> is not a local process, - or if <c><anno>Item</anno></c> is not a valid <c><anno>Item</anno></c>.</p> + <p>Notice that not all implementations support all + these <c><anno>Item</anno></c>s.</p> + <p>Failures:</p> + <taglist> + <tag><c>badarg</c></tag> + <item>If <c><anno>Pid</anno></c> is not a local process.</item> + <tag><c>badarg</c></tag> + <item>If <c><anno>Item</anno></c> is an invalid item.</item> + </taglist> </desc> </func> + <func> <name name="processes" arity="0"/> - <fsummary>All processes</fsummary> + <fsummary>All processes.</fsummary> <desc> <p>Returns a list of process identifiers corresponding to - all the processes currently existing on the local node. - </p> - <p>Note that a process that is exiting, exists but is not alive, i.e., - <c>is_process_alive/1</c> will return <c>false</c> for a process - that is exiting, but its process identifier will be part - of the result returned from <c>processes/0</c>. - </p> + all the processes currently existing on the local node.</p> + <p>Notice that an exiting process exists, but is not alive. + That is, <c>is_process_alive/1</c> returns <c>false</c> + for an exiting process, but its process identifier is part + of the result returned from <c>processes/0</c>.</p> + <p>Example:</p> <pre> > <input>processes().</input> [<0.0.0>,<0.2.0>,<0.4.0>,<0.5.0>,<0.7.0>,<0.8.0>]</pre> </desc> </func> + <func> <name name="purge_module" arity="1"/> - <fsummary>Remove old code for a module</fsummary> + <fsummary>Removes old code for a module.</fsummary> <desc> - <p>Removes old code for <c><anno>Module</anno></c>. Before this BIF is used, - <c>erlang:check_process_code/2</c> should be called to check - that no processes are executing old code in the module.</p> + <p>Removes old code for <c><anno>Module</anno></c>. + Before this BIF is used, + <c>erlang:check_process_code/2</c> is to be called to check + that no processes execute old code in the module.</p> <warning> <p>This BIF is intended for the code server (see - <seealso marker="kernel:code">code(3)</seealso>) and should not be - used elsewhere.</p> + <seealso marker="kernel:code">code(3)</seealso>) + and is not to be used elsewhere.</p> </warning> <p>Failure: <c>badarg</c> if there is no old code for <c><anno>Module</anno></c>.</p> </desc> </func> + <func> <name name="put" arity="2"/> - <fsummary>Add a new value to the process dictionary</fsummary> - <desc> - <p>Adds a new <c><anno>Key</anno></c> to the process dictionary, associated - with the value <c><anno>Val</anno></c>, and returns <c>undefined</c>. If - <c><anno>Key</anno></c> already exists, the old value is deleted and - replaced by <c><anno>Val</anno></c> and the function returns the old value.</p> - <note> - <p>The values stored when <c>put</c> is evaluated within - the scope of a <c>catch</c> will not be retracted if a - <c>throw</c> is evaluated, or if an error occurs.</p> - </note> + <fsummary>Adds a new value to the process dictionary.</fsummary> + <desc> + <p>Adds a new <c><anno>Key</anno></c> to the process dictionary, + associated with the value <c><anno>Val</anno></c>, and returns + <c>undefined</c>. If <c><anno>Key</anno></c> exists, the old + value is deleted and replaced by <c><anno>Val</anno></c>, and + the function returns the old value.</p> + <p>Example:</p> <pre> > <input>X = put(name, walrus), Y = put(name, carpenter),</input> <input>Z = get(name),</input> <input>{X, Y, Z}.</input> {undefined,walrus,carpenter}</pre> + <note> + <p>The values stored when <c>put</c> is evaluated within + the scope of a <c>catch</c> are not retracted if a + <c>throw</c> is evaluated, or if an error occurs.</p> + </note> </desc> </func> + <func> <name name="raise" arity="3"/> + <fsummary>Stops execution with an exception of given class, reason, and call stack backtrace.</fsummary> <type name="raise_stacktrace"/> - <fsummary>Stop execution with an exception of given class, reason and call stack backtrace</fsummary> <desc> <p>Stops the execution of the calling process with an - exception of given class, reason and call stack backtrace + exception of given class, reason, and call stack backtrace (<em>stacktrace</em>).</p> <warning> - <p>This BIF is intended for debugging and for use in - the Erlang operating system. In general, it should - be avoided in applications, unless you know - very well what you are doing.</p> + <p>This BIF is intended for debugging. Avoid to use it in applications, + unless you really know what you are doing.</p> </warning> - <p><c><anno>Class</anno></c> is one of <c>error</c>, <c>exit</c> or - <c>throw</c>, so if it were not for the stacktrace - <c>erlang:raise(<anno>Class</anno>, <anno>Reason</anno>, <anno>Stacktrace</anno>)</c> is - equivalent to <c>erlang:<anno>Class</anno>(<anno>Reason</anno>)</c>. - <c><anno>Reason</anno></c> is any term and <c><anno>Stacktrace</anno></c> is a list as - returned from <c>get_stacktrace()</c>, that is a list of - 4-tuples <c>{Module, Function, Arity | Args, - Location}</c> where <c>Module</c> and <c>Function</c> - are atoms and the third element is an integer arity or an - argument list. The stacktrace may also contain <c>{Fun, - Args, Location}</c> tuples where - <c>Fun</c> is a local fun and <c>Args</c> is an argument list.</p> - <p>The <c>Location</c> element at the end is optional. + <p><c><anno>Class</anno></c> is <c>error</c>, <c>exit</c>, or + <c>throw</c>. So, if it were not for the stacktrace, + <c>erlang:raise(<anno>Class</anno>, <anno>Reason</anno>, + <anno>Stacktrace</anno>)</c> is + equivalent to <c>erlang:<anno>Class</anno>(<anno>Reason</anno>)</c>.</p> + <p><c><anno>Reason</anno></c> is any term. + <c><anno>Stacktrace</anno></c> is a list as + returned from <c>get_stacktrace()</c>, that is, a list of + four-tuples <c>{Module, Function, Arity | Args, + Location}</c>, where <c>Module</c> and <c>Function</c> + are atoms, and the third element is an integer arity or an + argument list. The stacktrace can also contain <c>{Fun, + Args, Location}</c> tuples, where <c>Fun</c> is a local + fun and <c>Args</c> is an argument list.</p> + <p>Element <c>Location</c> at the end is optional. Omitting it is equivalent to specifying an empty list.</p> <p>The stacktrace is used as the exception stacktrace for the - calling process; it will be truncated to the current + calling process; it is truncated to the current maximum stacktrace depth.</p> - <p>Because evaluating this function causes the process to - terminate, it has no return value - unless the arguments are - invalid, in which case the function <em>returns the error reason</em>, that is <c>badarg</c>. If you want to be - really sure not to return you can call - <c>error(erlang:raise(<anno>Class</anno>, <anno>Reason</anno>, <anno>Stacktrace</anno>))</c> + <p>Since evaluating this function causes the process to + terminate, it has no return value unless the arguments are + invalid, in which case the function <em>returns the error + reason</em> <c>badarg</c>. If you want to be + sure not to return, you can call + <c>error(erlang:raise(<anno>Class</anno>, <anno>Reason</anno>, + <anno>Stacktrace</anno>))</c> and hope to distinguish exceptions later.</p> </desc> </func> + <func> <name name="read_timer" arity="2"/> - <fsummary>Read the state of a timer</fsummary> + <fsummary>Reads the state of a timer.</fsummary> <desc> <p> Read the state of a timer that has been created by either @@ -4595,7 +4885,7 @@ os_prompt% </pre> <c><anno>TimerRef</anno></c> identifies the timer, and was returned by the BIF that created the timer. </p> - <p>Currently available <c><anno>Option</anno>s</c>:</p> + <p>Available <c><anno>Option</anno>s</c>:</p> <taglist> <tag><c>{async, Async}</c></tag> <item> @@ -4603,12 +4893,12 @@ os_prompt% </pre> Asynchronous request for state information. <c>Async</c> defaults to <c>false</c> which will cause the operation to be performed synchronously. In this case, the <c>Result</c> - will be returned by <c>erlang:read_timer()</c>. When - <c>Async</c> is set to <c>true</c>, <c>erlang:read_timer()</c> - will send an asynchronous request for the state information - to the timer service that manages the timer, and then return + is returned by <c>erlang:read_timer()</c>. When + <c>Async</c> is <c>true</c>, <c>erlang:read_timer()</c> + sends an asynchronous request for the state information + to the timer service that manages the timer, and then returns <c>ok</c>. A message on the format <c>{read_timer, - <anno>TimerRef</anno>, <anno>Result</anno>}</c> will be + <anno>TimerRef</anno>, <anno>Result</anno>}</c> is sent to the caller of <c>erlang:read_timer()</c> when the operation has been processed. </p> @@ -4618,26 +4908,27 @@ os_prompt% </pre> More <c><anno>Option</anno></c>s may be added in the future. </p> <p> - When the <c><anno>Result</anno></c> equals <c>false</c>, a + If <c><anno>Result</anno></c> is an integer, it represents the + time in milli-seconds left until the timer expires.</p> + <p> + If <c><anno>Result</anno></c> is <c>false</c>, a timer corresponding to <c><anno>TimerRef</anno></c> could not - be found. This can be either because the timer had expired, - had been canceled, or because <c><anno>TimerRef</anno></c> - never has corresponded to a timer. If the timer has expired, - the timeout message has been sent, but it does not tell you - whether or not it has arrived at its destination yet. When the - <c><anno>Result</anno></c> is an integer, it represents the - time in milli-seconds left until the timer will expire. + be found. This can be because the timer had expired, + it had been canceled, or because <c><anno>TimerRef</anno></c> + never has corresponded to a timer. Even if the timer has expired, + it does not tell you whether or not the timeout message has + arrived at its destination yet. </p> <note> <p> The timer service that manages the timer may be co-located with another scheduler than the scheduler that the calling process is executing on. If this is the case, communication - with the timer service will take much longer time than if it + with the timer service takes much longer time than if it is located locally. If the calling process is in critical path, and can do other things while waiting for the result - of this operation you want to use the <c>{async, true}</c> - option. If using the <c>{async, false}</c> option, the calling + of this operation, you want to use option <c>{async, true}</c>. + If using option <c>{async, false}</c>, the calling process will be blocked until the operation has been performed. </p> @@ -4651,70 +4942,86 @@ os_prompt% </pre> </func> <func> <name name="read_timer" arity="1"/> - <fsummary>Read the state of a timer</fsummary> + <fsummary>Reads the state of a timer.</fsummary> <desc> <p>Read the state of a timer. The same as calling <seealso marker="#read_timer/2"><c>erlang:read_timer(TimerRef, [])</c></seealso>.</p> </desc> </func> + <func> <name name="ref_to_list" arity="1"/> - <fsummary>Text representation of a reference</fsummary> + <fsummary>Text representation of a reference.</fsummary> <desc> - <p>Returns a string which corresponds to the text + <p>Returns a string corresponding to the text representation of <c><anno>Ref</anno></c>.</p> <warning> - <p>This BIF is intended for debugging and for use in - the Erlang operating system. It should not be used in - application programs.</p> + <p>This BIF is intended for debugging and is not to be used + in application programs.</p> </warning> </desc> </func> + <func> <name name="register" arity="2"/> - <fsummary>Register a name for a pid (or port)</fsummary> + <fsummary>Registers a name for a pid (or port).</fsummary> <desc> - <p>Associates the name <c><anno>RegName</anno></c> with a pid or a port - identifier. <c><anno>RegName</anno></c>, which must be an atom, can be used - instead of the pid / port identifier in the send operator + <p>Associates the name <c><anno>RegName</anno></c> with a process + identifier (pid) or a port identifier. + <c><anno>RegName</anno></c>, which must be an atom, can be used + instead of the pid or port identifier in send operator (<c><anno>RegName</anno> ! Message</c>).</p> + <p>Example:</p> <pre> > <input>register(db, Pid).</input> true</pre> - <p>Failure: <c>badarg</c> if <c><anno>PidOrPort</anno></c> is not an existing, - local process or port, if <c><anno>RegName</anno></c> is already in use, - if the process or port is already registered (already has a - name), or if <c><anno>RegName</anno></c> is the atom <c>undefined</c>.</p> + <p>Failures:</p> + <taglist> + <tag><c>badarg</c></tag> + <item>If <c><anno>PidOrPort</anno></c> is not an existing local + process or port.</item> + <tag><c>badarg</c></tag> + <item>If <c><anno>RegName</anno></c> is already in use.</item> + <tag><c>badarg</c></tag> + <item>If the process or port is already registered + (already has a name).</item> + <tag><c>badarg</c></tag> + <item>If <c><anno>RegName</anno></c> is the atom + <c>undefined</c>.</item> + </taglist> </desc> </func> + <func> <name name="registered" arity="0"/> - <fsummary>All registered names</fsummary> + <fsummary>All registered names.</fsummary> <desc> - <p>Returns a list of names which have been registered using - <seealso marker="#register/2">register/2</seealso>.</p> + <p>Returns a list of names that have been registered using + <seealso marker="#register/2">register/2</seealso>, for + example:</p> <pre> > <input>registered().</input> [code_server, file_server, init, user, my_db]</pre> </desc> </func> + <func> <name name="resume_process" arity="1"/> - <fsummary>Resume a suspended process</fsummary> + <fsummary>Resumes a suspended process.</fsummary> <desc> <p>Decreases the suspend count on the process identified by - <c><anno>Suspendee</anno></c>. <c><anno>Suspendee</anno></c> should previously have been - suspended via - <seealso marker="#suspend_process/2">erlang:suspend_process/2</seealso>, + <c><anno>Suspendee</anno></c>. <c><anno>Suspendee</anno></c> + is previously to have been suspended through + <seealso marker="#suspend_process/2">erlang:suspend_process/2</seealso> or <seealso marker="#suspend_process/1">erlang:suspend_process/1</seealso> - by the process calling <c>erlang:resume_process(<anno>Suspendee</anno>)</c>. When - the suspend count on <c><anno>Suspendee</anno></c> reach zero, <c><anno>Suspendee</anno></c> - will be resumed, i.e., the state of the <c>Suspendee</c> is changed - from suspended into the state <c><anno>Suspendee</anno></c> was in before it was - suspended. - </p> + by the process calling + <c>erlang:resume_process(<anno>Suspendee</anno>)</c>. When the + suspend count on <c><anno>Suspendee</anno></c> reaches zero, + <c><anno>Suspendee</anno></c> is resumed, that is, its state + is changed from suspended into the state it had before it was + suspended.</p> <warning> <p>This BIF is intended for debugging only.</p> </warning> @@ -4722,7 +5029,7 @@ true</pre> <taglist> <tag><c>badarg</c></tag> <item> - If <c><anno>Suspendee</anno></c> isn't a process identifier. + If <c><anno>Suspendee</anno></c> is not a process identifier. </item> <tag><c>badarg</c></tag> <item> @@ -4732,58 +5039,65 @@ true</pre> </item> <tag><c>badarg</c></tag> <item> - If the process identified by <c><anno>Suspendee</anno></c> is not alive. + If the process identified by <c><anno>Suspendee</anno></c> + is not alive. </item> </taglist> </desc> </func> + <func> <name name="round" arity="1"/> - <fsummary>Return an integer by rounding a number</fsummary> + <fsummary>Returns an integer by rounding a number.</fsummary> <desc> - <p>Returns an integer by rounding <c><anno>Number</anno></c>.</p> + <p>Returns an integer by rounding <c><anno>Number</anno></c>, + for example:</p> <pre> -> <input>round(5.5).</input> +<input>round(5.5).</input> 6</pre> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="self" arity="0"/> - <fsummary>Pid of the calling process</fsummary> + <fsummary>Returns pid of the calling process.</fsummary> <desc> - <p>Returns the pid (process identifier) of the calling process.</p> + <p>Returns the process identifier of the calling process, for + example:</p> <pre> > <input>self().</input> <0.26.0></pre> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="send" arity="2"/> - <fsummary>Send a message</fsummary> + <fsummary>Sends a message.</fsummary> <type name="dst"/> <desc> - <p>Sends a message and returns <c><anno>Msg</anno></c>. This is the same as - <c><anno>Dest</anno> ! <anno>Msg</anno></c>.</p> - <p><c><anno>Dest</anno></c> may be a remote or local pid, a (local) port, a - locally registered name, or a tuple <c>{<anno>RegName</anno>, <anno>Node</anno>}</c> + <p>Sends a message and returns <c><anno>Msg</anno></c>. This + is the same as <c><anno>Dest</anno> ! <anno>Msg</anno></c>.</p> + <p><c><anno>Dest</anno></c> can be a remote or local process identifier, + a (local) port, a locally registered name, or a tuple + <c>{<anno>RegName</anno>, <anno>Node</anno>}</c> for a registered name at another node.</p> </desc> </func> + <func> <name name="send" arity="3"/> + <fsummary>Sends a message conditionally.</fsummary> <type name="dst"/> - <fsummary>Send a message conditionally</fsummary> - <desc> - <p>Sends a message and returns <c>ok</c>, or does not send - the message but returns something else (see below). Otherwise - the same as - <seealso marker="#send/2">erlang:send/2</seealso>. See - also - <seealso marker="#send_nosuspend/2">erlang:send_nosuspend/2,3</seealso>. - for more detailed explanation and warnings.</p> - <p>The possible options are:</p> + <desc> + <p>Either sends a message and returns <c>ok</c>, or does not send + the message but returns something else (see the following). + Otherwise the same as + <seealso marker="#send/2">erlang:send/2</seealso>. + For more detailed explanation and warnings, see + <seealso marker="#send_nosuspend/2">erlang:send_nosuspend/2,3</seealso>.</p> + <p>The options are as follows:</p> <taglist> <tag><c>nosuspend</c></tag> <item> @@ -4793,314 +5107,366 @@ true</pre> <tag><c>noconnect</c></tag> <item> <p>If the destination node would have to be auto-connected - before doing the send, <c>noconnect</c> is returned + to do the send, <c>noconnect</c> is returned instead.</p> </item> </taglist> <warning> - <p>As with <c>erlang:send_nosuspend/2,3</c>: Use with extreme - care!</p> + <p>As with <c>erlang:send_nosuspend/2,3</c>: use with extreme + care.</p> </warning> </desc> </func> + <func> <name name="send_after" arity="4"/> <fsummary>Start a timer</fsummary> <desc> <p> Starts a timer. When the timer expires, the message - <c><anno>Msg</anno></c> will be sent to the process - identified by <c><anno>Dest</anno></c>. Appart from - the format of the message sent to - <c><anno>Dest</anno></c> when the timer expires + <c><anno>Msg</anno></c> is sent to the process + identified by <c><anno>Dest</anno></c>. Apart from + the format of the timeout message, <c>erlang:send_after/4</c> works exactly as <seealso marker="#start_timer/4"><c>erlang:start_timer/4</c></seealso>.</p> </desc> </func> <func> <name name="send_after" arity="3"/> - <fsummary>Start a timer</fsummary> + <fsummary>Starts a timer.</fsummary> <desc> <p>Starts a timer. The same as calling <seealso marker="#send_after/4"><c>erlang:send_after(<anno>Time</anno>, <anno>Dest</anno>, <anno>Msg</anno>, [])</c></seealso>.</p> </desc> </func> + <func> <name name="send_nosuspend" arity="2"/> - <fsummary>Try to send a message without ever blocking</fsummary> + <fsummary>Tries to send a message without ever blocking.</fsummary> <type name="dst"/> <desc> <p>The same as - <seealso marker="#send/3">erlang:send(<anno>Dest</anno>, <anno>Msg</anno>, [nosuspend])</seealso>, but returns <c>true</c> if + <seealso marker="#send/3">erlang:send(<anno>Dest</anno>, + <anno>Msg</anno>, [nosuspend])</seealso>, + but returns <c>true</c> if the message was sent and <c>false</c> if the message was not sent because the sender would have had to be suspended.</p> - <p>This function is intended for send operations towards an + <p>This function is intended for send operations to an unreliable remote node without ever blocking the sending (Erlang) process. If the connection to the remote node (usually not a real Erlang node, but a node written in C or - Java) is overloaded, this function <em>will not send the message</em> but return <c>false</c> instead.</p> - <p>The same happens, if <c><anno>Dest</anno></c> refers to a local port that - is busy. For all other destinations (allowed for the ordinary - send operator <c>'!'</c>) this function sends the message and + Java) is overloaded, this function <em>does not send the message</em> + and returns <c>false</c>.</p> + <p>The same occurs if <c><anno>Dest</anno></c> refers to a local port + that is busy. For all other destinations (allowed for the ordinary + send operator <c>'!'</c>), this function sends the message and returns <c>true</c>.</p> - <p>This function is only to be used in very rare circumstances + <p>This function is only to be used in rare circumstances where a process communicates with Erlang nodes that can - disappear without any trace causing the TCP buffers and - the drivers queue to be over-full before the node will actually - be shut down (due to tick timeouts) by <c>net_kernel</c>. The - normal reaction to take when this happens is some kind of + disappear without any trace, causing the TCP buffers and + the drivers queue to be over-full before the node is + shut down (because of tick time-outs) by <c>net_kernel</c>. + The normal reaction to take when this occurs is some kind of premature shutdown of the other node.</p> - <p>Note that ignoring the return value from this function would - result in <em>unreliable</em> message passing, which is + <p>Notice that ignoring the return value from this function would + result in an <em>unreliable</em> message passing, which is contradictory to the Erlang programming model. The message is <em>not</em> sent if this function returns <c>false</c>.</p> - <p>Note also that in many systems, transient states of + <p>In many systems, transient states of overloaded queues are normal. The fact that this function - returns <c>false</c> does not in any way mean that the other + returns <c>false</c> does not mean that the other node is guaranteed to be non-responsive, it could be a - temporary overload. Also a return value of <c>true</c> does - only mean that the message could be sent on the (TCP) channel - without blocking, the message is not guaranteed to have - arrived at the remote node. Also in the case of a disconnected + temporary overload. Also, a return value of <c>true</c> does + only mean that the message can be sent on the (TCP) channel + without blocking, the message is not guaranteed to + arrive at the remote node. For a disconnected non-responsive node, the return value is <c>true</c> (mimics - the behaviour of the <c>!</c> operator). The expected - behaviour as well as the actions to take when the function - returns <c>false</c> are application and hardware specific.</p> + the behavior of operator <c>!</c>). The expected + behavior and the actions to take when the function + returns <c>false</c> are application- and hardware-specific.</p> <warning> - <p>Use with extreme care!</p> + <p>Use with extreme care.</p> </warning> </desc> </func> + <func> <name name="send_nosuspend" arity="3"/> - <fsummary>Try to send a message without ever blocking</fsummary> + <fsummary>Tries to send a message without ever blocking.</fsummary> <type name="dst"/> <desc> <p>The same as - <seealso marker="#send/3">erlang:send(<anno>Dest</anno>, <anno>Msg</anno>, [nosuspend | <anno>Options</anno>])</seealso>, - but with boolean return value.</p> + <seealso marker="#send/3">erlang:send(<anno>Dest</anno>, + <anno>Msg</anno>, [nosuspend | <anno>Options</anno>])</seealso>, + but with a Boolean return value.</p> <p>This function behaves like - <seealso marker="#send_nosuspend/2">erlang:send_nosuspend/2)</seealso>, - but takes a third parameter, a list of options. The only - currently implemented option is <c>noconnect</c>. The option - <c>noconnect</c> makes the function return <c>false</c> if + <seealso marker="#send_nosuspend/2">erlang:send_nosuspend/2</seealso>, + but takes a third parameter, a list of options. + The only option is <c>noconnect</c>, which + makes the function return <c>false</c> if the remote node is not currently reachable by the local - node. The normal behaviour is to try to connect to the node, - which may stall the process for a shorter period. The use of - the <c>noconnect</c> option makes it possible to be - absolutely sure not to get even the slightest delay when + node. The normal behavior is to try to connect to the node, + which can stall the process during a short period. The use of + option <c>noconnect</c> makes it possible to be + sure not to get the slightest delay when sending to a remote process. This is especially useful when - communicating with nodes who expect to always be - the connecting part (i.e. nodes written in C or Java).</p> + communicating with nodes that expect to always be + the connecting part (that is, nodes written in C or Java).</p> <p>Whenever the function returns <c>false</c> (either when a suspend would occur or when <c>noconnect</c> was specified and the node was not already connected), the message is guaranteed <em>not</em> to have been sent.</p> <warning> - <p>Use with extreme care!</p> + <p>Use with extreme care.</p> </warning> </desc> </func> + <func> <name name="set_cookie" arity="2"/> - <fsummary>Set the magic cookie of a node</fsummary> + <fsummary>Sets the magic cookie of a node.</fsummary> <desc> <p>Sets the magic cookie of <c><anno>Node</anno></c> to the atom - <c><anno>Cookie</anno></c>. If <c><anno>Node</anno></c> is the local node, the function + <c><anno>Cookie</anno></c>. If <c><anno>Node</anno></c> is the + local node, the function also sets the cookie of all other unknown nodes to - <c><anno>Cookie</anno></c> (see - <seealso marker="doc/reference_manual:distributed">Distributed Erlang</seealso> in the Erlang Reference Manual).</p> + <c><anno>Cookie</anno></c> (see Section + <seealso marker="doc/reference_manual:distributed">Distributed Erlang</seealso> + in the Erlang Reference Manual in System Documentation).</p> <p>Failure: <c>function_clause</c> if the local node is not alive.</p> </desc> </func> + <func> <name name="setelement" arity="3"/> - <type_desc variable="Index">1..tuple_size(<anno>Tuple1</anno>)</type_desc> - <fsummary>Set Nth element of a tuple</fsummary> + <fsummary>Sets the Nth element of a tuple.</fsummary> + <type_desc variable="Index">1..tuple_size(<anno>Tuple1</anno></type_desc> <desc> - <p>Returns a tuple which is a copy of the argument <c><anno>Tuple1</anno></c> - with the element given by the integer argument <c><anno>Index</anno></c> + <p>Returns a tuple that is a copy of argument + <c><anno>Tuple1</anno></c> + with the element given by integer argument + <c><anno>Index</anno></c> (the first element is the element with index 1) replaced by - the argument <c><anno>Value</anno></c>.</p> + argument <c><anno>Value</anno></c>, for example:</p> <pre> > <input>setelement(2, {10, green, bottles}, red).</input> {10,red,bottles}</pre> </desc> </func> + <func> <name name="size" arity="1"/> - <fsummary>Size of a tuple or binary</fsummary> + <fsummary>Size of a tuple or binary.</fsummary> <desc> - <p>Returns an integer which is the size of the argument - <c><anno>Item</anno></c>, which must be either a tuple or a binary.</p> + <p>Returns the number of elements in a tuple or the number of + bytes in a binary or bitstring, for example:</p> <pre> > <input>size({morni, mulle, bwange}).</input> -3</pre> +3 +> <input>size(<<11, 22, 33>>).</input> +3 +</pre> + <p>For bitstrings the number of whole bytes is returned. That is, if the number of bits + in the bitstring is not divisible by 8, the resulting + number of bytes is rounded <em>down</em>.</p> <p>Allowed in guard tests.</p> + <p>See also + <seealso marker="#tuple_size/1"><c>tuple_size/1</c></seealso>, + <seealso marker="#byte_size/1"><c>byte_size/1</c></seealso> + and + <seealso marker="#bit_size/1"><c>bit_size/1</c></seealso>.</p> </desc> </func> + <func> <name name="spawn" arity="1"/> - <fsummary>Create a new process with a fun as entry point</fsummary> + <fsummary>Creates a new process with a fun as entry point.</fsummary> <desc> - <p>Returns the pid of a new process started by the application - of <c><anno>Fun</anno></c> to the empty list <c>[]</c>. Otherwise works - like <seealso marker="#spawn/3">spawn/3</seealso>.</p> + <p>Returns the process identifier of a new process started by the + application of <c><anno>Fun</anno></c> to the empty list + <c>[]</c>. Otherwise + works like <seealso marker="#spawn/3">spawn/3</seealso>.</p> </desc> </func> + <func> <name name="spawn" arity="2"/> - <fsummary>Create a new process with a fun as entry point on a given node</fsummary> + <fsummary>Creates a new process with a fun as entry point on a given node.</fsummary> <desc> - <p>Returns the pid of a new process started by the application - of <c><anno>Fun</anno></c> to the empty list <c>[]</c> on <c><anno>Node</anno></c>. If - <c><anno>Node</anno></c> does not exist, a useless pid is returned. - Otherwise works like + <p>Returns the process identifier of a new process started + by the application of <c><anno>Fun</anno></c> to the + empty list <c>[]</c> on <c><anno>Node</anno></c>. If + <c><anno>Node</anno></c> does not exist, a useless pid is + returned. Otherwise works like <seealso marker="#spawn/3">spawn/3</seealso>.</p> </desc> </func> + <func> <name name="spawn" arity="3"/> - <fsummary>Create a new process with a function as entry point</fsummary> - <desc> - <p>Returns the pid of a new process started by the application - of <c><anno>Module</anno>:<anno>Function</anno></c> to <c><anno>Args</anno></c>. The new process - created will be placed in the system scheduler queue and be - run some time later.</p> - <p><c>error_handler:undefined_function(<anno>Module</anno>, <anno>Function</anno>, <anno>Args</anno>)</c> is evaluated by the new process if - <c><anno>Module</anno>:<anno>Function</anno>/Arity</c> does not exist (where - <c>Arity</c> is the length of <c><anno>Args</anno></c>). The error handler + <fsummary>Creates a new process with a function as entry point.</fsummary> + <desc> + <p>Returns the process identifier of a new process started by + the application of <c><anno>Module</anno>:<anno>Function</anno></c> + to <c><anno>Args</anno></c>.</p> + <p><c>error_handler:undefined_function(<anno>Module</anno>, + <anno>Function</anno>, <anno>Args</anno>)</c> + is evaluated by the new process if + <c><anno>Module</anno>:<anno>Function</anno>/Arity</c> + does not exist (where <c>Arity</c> is the length of + <c><anno>Args</anno></c>). The error handler can be redefined (see <seealso marker="#process_flag/2">process_flag/2</seealso>). If <c>error_handler</c> is undefined, or the user has - redefined the default <c>error_handler</c> its replacement is - undefined, a failure with the reason <c>undef</c> will occur.</p> + redefined the default <c>error_handler</c> and its replacement is + undefined, a failure with reason <c>undef</c> occurs.</p> + <p>Example:</p> <pre> > <input>spawn(speed, regulator, [high_speed, thin_cut]).</input> <0.13.1></pre> </desc> </func> + <func> <name name="spawn" arity="4"/> - <fsummary>Create a new process with a function as entry point on a given node</fsummary> + <fsummary>Creates a new process with a function as entry point on a given node.</fsummary> <desc> - <p>Returns the pid of a new process started by the application - of <c><anno>Module</anno>:<anno>Function</anno></c> to <c><anno>Args</anno></c> on <c>Node</c>. If - <c><anno>Node</anno></c> does not exists, a useless pid is returned. + <p>Returns the process identifier (pid) of a new process started + by the application + of <c><anno>Module</anno>:<anno>Function</anno></c> + to <c><anno>Args</anno></c> on <c><anno>Node</anno></c>. If + <c><anno>Node</anno></c> does not exist, a useless pid is returned. Otherwise works like <seealso marker="#spawn/3">spawn/3</seealso>.</p> </desc> </func> + <func> <name name="spawn_link" arity="1"/> - <fsummary>Create and link to a new process with a fun as entry point</fsummary> + <fsummary>Creates and links to a new process with a fun as entry point.</fsummary> <desc> - <p>Returns the pid of a new process started by the application - of <c><anno>Fun</anno></c> to the empty list []. A link is created between + <p>Returns the process identifier of a new process started by + the application of <c><anno>Fun</anno></c> to the empty list + <c>[]</c>. A link is created between the calling process and the new process, atomically. Otherwise works like <seealso marker="#spawn/3">spawn/3</seealso>.</p> </desc> </func> + <func> <name name="spawn_link" arity="2"/> - <fsummary>Create and link to a new process with a fun as entry point on a specified node</fsummary> + <fsummary>Creates and links to a new process with a fun as entry point on a specified node.</fsummary> <desc> - <p>Returns the pid of a new process started by the application - of <c><anno>Fun</anno></c> to the empty list [] on <c><anno>Node</anno></c>. A link is + <p>Returns the process identifier (pid) of a new process started + by the application of <c><anno>Fun</anno></c> to the empty + list <c>[]</c> on <c><anno>Node</anno></c>. A link is created between the calling process and the new process, - atomically. If <c><anno>Node</anno></c> does not exist, a useless pid is - returned (and due to the link, an exit signal with exit - reason <c>noconnection</c> will be received). Otherwise works - like <seealso marker="#spawn/3">spawn/3</seealso>.</p> + atomically. If <c><anno>Node</anno></c> does not exist, + a useless pid is returned and an exit signal with + reason <c>noconnection</c> is sent to the calling + process. Otherwise works like <seealso marker="#spawn/3">spawn/3</seealso>.</p> </desc> </func> + <func> <name name="spawn_link" arity="3"/> - <fsummary>Create and link to a new process with a function as entry point</fsummary> + <fsummary>Creates and links to a new process with a function as entry point.</fsummary> <desc> - <p>Returns the pid of a new process started by the application - of <c><anno>Module</anno>:<anno>Function</anno></c> to <c><anno>Args</anno></c>. A link is created + <p>Returns the process identifier of a new process started by + the application of <c><anno>Module</anno>:<anno>Function</anno></c> + to <c><anno>Args</anno></c>. A link is created between the calling process and the new process, atomically. Otherwise works like <seealso marker="#spawn/3">spawn/3</seealso>.</p> </desc> </func> + <func> <name name="spawn_link" arity="4"/> - <fsummary>Create and link to a new process with a function as entry point on a given node</fsummary> + <fsummary>Creates and links to a new process with a function as entry point on a given node.</fsummary> <desc> - <p>Returns the pid of a new process started by the application - of <c><anno>Module</anno>:<anno>Function</anno></c> to <c><anno>Args</anno></c> on <c>Node</c>. A + <p>Returns the process identifier (pid) of a new process + started by the application + of <c><anno>Module</anno>:<anno>Function</anno></c> + to <c><anno>Args</anno></c> on <c><anno>Node</anno></c>. A link is created between the calling process and the new - process, atomically. If <c><anno>Node</anno></c> does not exist, a useless - pid is returned (and due to the link, an exit signal with exit - reason <c>noconnection</c> will be received). Otherwise works - like <seealso marker="#spawn/3">spawn/3</seealso>.</p> + process, atomically. If <c><anno>Node</anno></c> does + not exist, a useless pid is returned and an exit signal with + reason <c>noconnection</c> is sent to the calling + process. Otherwise works like <seealso marker="#spawn/3">spawn/3</seealso>.</p> </desc> </func> + <func> <name name="spawn_monitor" arity="1"/> - <fsummary>Create and monitor a new process with a fun as entry point</fsummary> + <fsummary>Creates and monitors a new process with a fun as entry point.</fsummary> <desc> - <p>Returns the pid of a new process started by the application - of <c><anno>Fun</anno></c> to the empty list [] and reference for a monitor - created to the new process. + <p>Returns the process identifier of a new process, started by + the application of <c><anno>Fun</anno></c> to the empty list + <c>[]</c>, + and a reference for a monitor created to the new process. Otherwise works like <seealso marker="#spawn/3">spawn/3</seealso>.</p> </desc> </func> + <func> <name name="spawn_monitor" arity="3"/> - <fsummary>Create and monitor a new process with a function as entry point</fsummary> + <fsummary>Creates and monitors a new process with a function as entry point.</fsummary> <desc> <p>A new process is started by the application - of <c><anno>Module</anno>:<anno>Function</anno></c> to <c><anno>Args</anno></c>, and the process is - monitored at the same time. Returns the pid and a reference - for the monitor. - Otherwise works like + of <c><anno>Module</anno>:<anno>Function</anno></c> + to <c><anno>Args</anno></c>. The process is + monitored at the same time. Returns the process identifier + and a reference for the monitor. Otherwise works like <seealso marker="#spawn/3">spawn/3</seealso>.</p> </desc> </func> + <func> <name name="spawn_opt" arity="2"/> - <type name="priority_level" /> - <fsummary>Create a new process with a fun as entry point</fsummary> + <fsummary>Creates a new process with a fun as entry point.</fsummary> + <type name="priority_level"/> <desc> - <p>Returns the pid of a new process started by the application - of <c><anno>Fun</anno></c> to the empty list <c>[]</c>. Otherwise - works like + <p>Returns the process identifier (pid) of a new process + started by the application of <c><anno>Fun</anno></c> + to the empty list <c>[]</c>. Otherwise works like <seealso marker="#spawn_opt/4">spawn_opt/4</seealso>.</p> - <p>If the option <c>monitor</c> is given, the newly created - process will be monitored and both the pid and reference for - the monitor will be returned.</p> + <p>If option <c>monitor</c> is given, the newly created + process is monitored, and both the pid and reference for + the monitor is returned.</p> </desc> </func> + <func> <name name="spawn_opt" arity="3"/> - <type name="priority_level" /> - <fsummary>Create a new process with a fun as entry point on a given node</fsummary> + <fsummary>Creates a new process with a fun as entry point on a given node.</fsummary> + <type name="priority_level"/> <desc> - <p>Returns the pid of a new process started by the application - of <c><anno>Fun</anno></c> to the empty list <c>[]</c> on <c><anno>Node</anno></c>. If - <c><anno>Node</anno></c> does not exist, a useless pid is returned. - Otherwise works like + <p>Returns the process identifier (pid) of a new process started + by the application of <c><anno>Fun</anno></c> to the + empty list <c>[]</c> on <c><anno>Node</anno></c>. If + <c><anno>Node</anno></c> does not exist, a useless pid is + returned. Otherwise works like <seealso marker="#spawn_opt/4">spawn_opt/4</seealso>.</p> </desc> </func> + <func> <name name="spawn_opt" arity="4"/> - <type name="priority_level" /> - <fsummary>Create a new process with a function as entry point</fsummary> + <fsummary>Creates a new process with a function as entry point.</fsummary> + <type name="priority_level"/> <desc> - <p>Works exactly like + <p>Works as <seealso marker="#spawn/3">spawn/3</seealso>, except that an extra option list is given when creating the process.</p> - <p>If the option <c>monitor</c> is given, the newly created - process will be monitored and both the pid and reference for - the monitor will be returned.</p> + <p>If option <c>monitor</c> is given, the newly created + process is monitored, and both the pid and reference for + the monitor is returned.</p> + <p>The options are as follows:</p> <taglist> <tag><c>link</c></tag> <item> @@ -5109,112 +5475,123 @@ true</pre> </item> <tag><c>monitor</c></tag> <item> - <p>Monitor the new process (just like + <p>Monitors the new process (like <seealso marker="#monitor/2">monitor/2</seealso> does).</p> </item> - <tag><c>{priority, <anno>Level</anno>}</c></tag> + <tag><c>{priority, <anno>Level</anno></c></tag> <item> <p>Sets the priority of the new process. Equivalent to executing - <seealso marker="#process_flag_priority">process_flag(priority, <anno>Level</anno>)</seealso> in the start function of the new process, - except that the priority will be set before the process is - selected for execution for the first time. For more information - on priorities see - <seealso marker="#process_flag_priority">process_flag(priority, Level)</seealso>.</p> + <seealso marker="#process_flag_priority">process_flag(priority, + <anno>Level</anno>)</seealso> + in the start function of the new process, + except that the priority is set before the process is + selected for execution for the first time. For more + information on priorities, see + <seealso marker="#process_flag_priority">process_flag(priority, + <anno>Level</anno>)</seealso>.</p> </item> <tag><c>{fullsweep_after, <anno>Number</anno>}</c></tag> <item> - <p>This option is only useful for performance tuning. - In general, you should not use this option unless you - know that there is problem with execution times and/or - memory consumption, and you should measure to make sure - that the option improved matters. - </p> + <p>Useful only for performance tuning. Do not use this + option unless you + know that there is problem with execution times or + memory consumption, and ensure + that the option improves matters.</p> <p>The Erlang runtime system uses a generational garbage collection scheme, using an "old heap" for data that has survived at least one garbage collection. When there is no more room on the old heap, a fullsweep garbage - collection will be done.</p> - <p>The <c>fullsweep_after</c> option makes it possible to + collection is done.</p> + <p>Option <c>fullsweep_after</c> makes it possible to specify the maximum number of generational collections - before forcing a fullsweep even if there is still room on - the old heap. Setting the number to zero effectively - disables the general collection algorithm, meaning that + before forcing a fullsweep, even if there is room on + the old heap. Setting the number to zero + disables the general collection algorithm, that is, all live data is copied at every garbage collection.</p> - <p>Here are a few cases when it could be useful to change - <c>fullsweep_after</c>. Firstly, if binaries that are no - longer used should be thrown away as soon as possible. - (Set <c><anno>Number</anno></c> to zero.) Secondly, a process that - mostly have short-lived data will be fullsweeped seldom - or never, meaning that the old heap will contain mostly - garbage. To ensure a fullsweep once in a while, set - <c><anno>Number</anno></c> to a suitable value such as 10 or 20. - Thirdly, in embedded systems with limited amount of RAM - and no virtual memory, one might want to preserve memory - by setting <c><anno>Number</anno></c> to zero. (The value may be set - globally, see - <seealso marker="#system_flag/2">erlang:system_flag/2</seealso>.)</p> + <p>A few cases when it can be useful to change + <c>fullsweep_after</c>:</p> + <list type="bulleted"> + <item>If binaries that are no longer used are to be + thrown away as soon as possible. (Set + <c><anno>Number</anno></c> to zero.) + </item> + <item>A process that mostly have short-lived data is + fullsweeped seldom or never, that is, the old heap + contains mostly garbage. To ensure a fullsweep + occasionally, set <c><anno>Number</anno></c> to a + suitable value, such as 10 or 20. + </item> + <item>In embedded systems with a limited amount of RAM + and no virtual memory, you might want to preserve memory + by setting <c><anno>Number</anno></c> to zero. + (The value can be set globally, see + <seealso marker="#system_flag/2">erlang:system_flag/2</seealso>.) + </item> + </list> </item> <tag><c>{min_heap_size, <anno>Size</anno>}</c></tag> <item> - <p>This option is only useful for performance tuning. - In general, you should not use this option unless you - know that there is problem with execution times and/or - memory consumption, and you should measure to make sure - that the option improved matters. - </p> - <p>Gives a minimum heap size in words. Setting this value - higher than the system default might speed up some + <p>Useful only for performance tuning. Do not use this + option unless you know that there is problem with + execution times or memory consumption, and + ensure that the option improves matters.</p> + <p>Gives a minimum heap size, in words. Setting this value + higher than the system default can speed up some processes because less garbage collection is done. - Setting too high value, however, might waste memory and - slow down the system due to worse data locality. - Therefore, it is recommended to use this option only for + However, setting a too high value can waste memory and + slow down the system because of worse data locality. + Therefore, use this option only for fine-tuning an application and to measure the execution time with various <c><anno>Size</anno></c> values.</p> </item> <tag><c>{min_bin_vheap_size, <anno>VSize</anno>}</c></tag> <item> - <p>This option is only useful for performance tuning. - In general, you should not use this option unless you - know that there is problem with execution times and/or - memory consumption, and you should measure to make sure - that the option improved matters. - </p> - <p>Gives a minimum binary virtual heap size in words. Setting this value - higher than the system default might speed up some + <p>Useful only for performance tuning. Do not use this + option unless you know that there is problem with + execution times or memory consumption, and + ensure that the option improves matters.</p> + <p>Gives a minimum binary virtual heap size, in words. + Setting this value + higher than the system default can speed up some processes because less garbage collection is done. - Setting too high value, however, might waste memory. - Therefore, it is recommended to use this option only for + However, setting a too high value can waste memory. + Therefore, use this option only for fine-tuning an application and to measure the execution time with various <c><anno>VSize</anno></c> values.</p> </item> - </taglist> </desc> </func> + <func> <name name="spawn_opt" arity="5"/> - <type name="priority_level" /> - <fsummary>Create a new process with a function as entry point on a given node</fsummary> + <fsummary>Creates a new process with a function as entry point on a given node.</fsummary> + <type name="priority_level"/> <desc> - <p>Returns the pid of a new process started by the application - of <c><anno>Module</anno>:<anno>Function</anno></c> to <c><anno>Args</anno></c> on <c>Node</c>. If + <p>Returns the process identifier (pid) of a new process started + by the application + of <c><anno>Module</anno>:<anno>Function</anno></c> to + <c><anno>Args</anno></c> on <c><anno>Node</anno></c>. If <c><anno>Node</anno></c> does not exist, a useless pid is returned. Otherwise works like <seealso marker="#spawn_opt/4">spawn_opt/4</seealso>.</p> - <note><p>The <c>monitor</c> option is currently not supported by + <note><p>Option <c>monitor</c> is not supported by <c>spawn_opt/5</c>.</p></note> </desc> </func> + <func> <name name="split_binary" arity="2"/> + <fsummary>Splits a binary into two.</fsummary> <type_desc variable="Pos">0..byte_size(Bin)</type_desc> - <fsummary>Split a binary into two</fsummary> <desc> - <p>Returns a tuple containing the binaries which are the result - of splitting <c><anno>Bin</anno></c> into two parts at position <c><anno>Pos</anno></c>. + <p>Returns a tuple containing the binaries that are the result + of splitting <c><anno>Bin</anno></c> into two parts at + position <c><anno>Pos</anno></c>. This is not a destructive operation. After the operation, - there will be three binaries altogether.</p> + there are three binaries altogether.</p> + <p>Example:</p> <pre> > <input>B = list_to_binary("0123456789").</input> <<"0123456789">> @@ -5228,31 +5605,35 @@ true</pre> 7</pre> </desc> </func> + <func> <name name="start_timer" arity="4"/> - <fsummary>Start a timer</fsummary> + <fsummary>Starts a timer.</fsummary> <desc> <p> Starts a timer. When the timer expires, the message <c>{timeout, <anno>TimerRef</anno>, <anno>Msg</anno>}</c> - will be sent to the process identified by + is sent to the process identified by <c><anno>Dest</anno></c>. </p> - <p>Currently available <c><anno>Option</anno></c>s:</p> + <p>Available <c><anno>Option</anno></c>s:</p> <taglist> - <tag><c>{abs, Abs}</c></tag> + <tag><c>{abs, false}</c></tag> <item> <p> - Absolute <c><anno>Time</anno></c> value. <c>Abs</c> - defaults to <c>false</c> which means that the - <c><anno>Time</anno></c> value will be interpreted - as a time in milli-seconds relative current + This is the default. It means the + <c><anno>Time</anno></c> value is interpreted + as a time in milli-seconds <em>relative</em> current <seealso marker="time_correction#Erlang_Monotonic_Time">Erlang - monotonic time</seealso>. When <c>Abs</c> is set to - <c>true</c>, the <c><anno>Time</anno></c> value will - be interpreted as an absolute Erlang monotonic time of - milli-seconds - <seealso marker="#type_time_unit">time unit</seealso>. + monotonic time</seealso>. + </p> + </item> + <tag><c>{abs, true}</c></tag> + <item> + <p> + Absolute <c><anno>Time</anno></c> value. The + <c><anno>Time</anno></c> value is interpreted as an + absolute Erlang monotonic time in milli-seconds. </p> </item> </taglist> @@ -5260,7 +5641,7 @@ true</pre> More <c><anno>Option</anno></c>s may be added in the future. </p> <p> - The absolute point in time that the timer is set to expire on + The absolute point in time, the timer is set to expire on, has to be in the interval <c>[</c><seealso marker="#system_info_start_time"><c>erlang:system_info(start_time)</c></seealso><c>, </c><seealso marker="#system_info_end_time"><c>erlang:system_info(end_time)</c></seealso><c>]</c>. @@ -5268,21 +5649,21 @@ true</pre> is not allowed to be negative. </p> <p> - If <c><anno>Dest</anno></c> is a <c>pid()</c>, it has to + If <c><anno>Dest</anno></c> is a <c>pid()</c>, it must be a <c>pid()</c> of a process created on the current runtime system instance. This process may or may not have terminated. If <c><anno>Dest</anno></c> is an - <c>atom()</c>, it will be interpreted as the name of a + <c>atom()</c>, it is interpreted as the name of a locally registered process. The process referred to by the name is looked up at the time of timer expiration. No error is given if the name does not refer to a process. </p> <p> - If <c><anno>Dest</anno></c> is a <c>pid()</c>, the timer will - be automatically canceled if the process referred to by the - <c>pid()</c> is not alive, or when the process exits. This - feature was introduced in erts version 5.4.11. Note that - timers will not be automatically canceled when + If <c><anno>Dest</anno></c> is a <c>pid()</c>, the timer is + automatically canceled if the process referred to by the + <c>pid()</c> is not alive, or if the process exits. This + feature was introduced in ERTS version 5.4.11. Notice that + timers are not automatically canceled when <c><anno>Dest</anno></c> is an <c>atom()</c>. </p> <p>See also @@ -5290,141 +5671,203 @@ true</pre> <seealso marker="#cancel_timer/2"><c>erlang:cancel_timer/2</c></seealso>, and <seealso marker="#read_timer/2"><c>erlang:read_timer/2</c></seealso>.</p> - <p>Failure: <c>badarg</c> if the arguments does not satisfy - the requirements specified above.</p> + <p>Failure: <c>badarg</c> if the arguments do not satisfy + the requirements specified here.</p> </desc> </func> + <func> <name name="start_timer" arity="3"/> - <fsummary>Start a timer</fsummary> + <fsummary>Starts a timer.</fsummary> <desc> <p>Starts a timer. The same as calling <seealso marker="#start_timer/4"><c>erlang:start_timer(<anno>Time</anno>, <anno>Dest</anno>, <anno>Msg</anno>, [])</c></seealso>.</p> </desc> </func> + <func> <name name="statistics" arity="1" clause_i="1"/> - <fsummary>Information about context switches</fsummary> - <desc> - <p><c><anno>ContextSwitches</anno></c> is the total number of context - switches since the system started.</p> + <fsummary>Information about active processes and ports.</fsummary> + <desc><marker id="statistics_active_tasks"></marker> + <p> + Returns a list where each element represents the amount + of active processes and ports on each run queue and its + associated scheduler. That is, the number of processes and + ports that are ready to run, or are currently running. The + element location in the list corresponds to the scheduler + and its run queue. The first element corresponds to scheduler + number 1 and so on. The information is <em>not</em> gathered + atomically. That is, the result is not necessarily a + consistent snapshot of the state, but instead quite + efficiently gathered. See also, + <seealso marker="#statistics_total_active_tasks"><c>statistics(total_active_tasks)</c></seealso>, + <seealso marker="#statistics_run_queue_lengths"><c>statistics(run_queue_lengths)</c></seealso>, and + <seealso marker="#statistics_total_run_queue_lengths"><c>statistics(total_run_queue_lengths)</c></seealso>. + </p> </desc> </func> + <func> <name name="statistics" arity="1" clause_i="2"/> - <fsummary>Information about exact reductions</fsummary> + <fsummary>Information about context switches.</fsummary> <desc> - <marker id="statistics_exact_reductions"></marker> - <note><p><c>statistics(exact_reductions)</c> is - a more expensive operation than - <seealso marker="#statistics_reductions">statistics(reductions)</seealso> - especially on an Erlang machine with SMP support.</p> - </note> + <p>Returns the total number of context switches since the + system started.</p> </desc> </func> + <func> <name name="statistics" arity="1" clause_i="3"/> - <fsummary>Information about garbage collection</fsummary> + <fsummary>Information about exact reductions.</fsummary> <desc> - <p>This information may not be valid for all implementations.</p> - <pre> -> <input>statistics(garbage_collection).</input> -{85,23961,0} -</pre> + <marker id="statistics_exact_reductions"></marker> + <p>Returns the number of exact reductions.</p> + <note><p><c>statistics(exact_reductions)</c> is + a more expensive operation than + <seealso marker="#statistics_reductions">statistics(reductions)</seealso>, + especially on an Erlang machine with SMP support.</p> + </note> </desc> </func> + <func> <name name="statistics" arity="1" clause_i="4"/> - <fsummary>Information about io</fsummary> + <fsummary>Information about garbage collection.</fsummary> <desc> - <p><c><anno>Input</anno></c> is the total number of bytes received - through ports, and <c><anno>Output</anno></c> is the total number of - bytes output to ports.</p> + <p>Returns information about garbage collection, for example:</p> + <pre> +> <input>statistics(garbage_collection).</input> +{85,23961,0}</pre> + <p>This information can be invalid for some implementations.</p> </desc> </func> + <func> <name name="statistics" arity="1" clause_i="5"/> - <fsummary>Information about reductions</fsummary> + <fsummary>Information about I/O.</fsummary> <desc> - <marker id="statistics_reductions"></marker> - <note> - <p>Since erts-5.5 (OTP release R11B) - this value does not include reductions performed in current - time slices of currently scheduled processes. If an - exact value is wanted, use - <seealso marker="#statistics_exact_reductions">statistics(exact_reductions)</seealso>.</p> - </note> - <pre> -> <input>statistics(reductions).</input> -{2046,11} -</pre> + <p>Returns <c><anno>Input</anno></c>, + which is the total number of bytes + received through ports, and <c><anno>Output</anno></c>, + which is the total number of bytes output to ports.</p> </desc> </func> + <func> <name name="statistics" arity="1" clause_i="6"/> - <fsummary>Information about the run-queue</fsummary> + <fsummary>Information about reductions.</fsummary> <desc> - <p>Returns the total length of the run queues, that is, the number - of processes that are ready to run on all available run queues.</p> + <marker id="statistics_reductions"></marker> + <p>Returns information about reductions, for example:</p> + <pre> +> <input>statistics(reductions).</input> +{2046,11}</pre> + <note><p>As from <c>ERTS</c> 5.5 (OTP R11B), + this value does not include reductions performed in current + time slices of currently scheduled processes. If an + exact value is wanted, use + <seealso marker="#statistics_exact_reductions">statistics(exact_reductions)</seealso>.</p> + </note> </desc> </func> + <func> <name name="statistics" arity="1" clause_i="7"/> - <fsummary>Information about run-time</fsummary> - <desc> - <p>Note that the run-time is the sum of the run-time for all - threads in the Erlang run-time system and may therefore be greater - than the wall-clock time. The time is returned in milliseconds.</p> - <pre> -> <input>statistics(runtime).</input> -{1690,1620} -</pre> + <fsummary>Information about the run-queues.</fsummary> + <desc><marker id="statistics_run_queue"></marker> + <p> + Returns the total length of the run-queues. That is, the number + of processes and ports that are ready to run on all available + run-queues. The information is gathered atomically. That + is, the result is a consistent snapshot of the state, but + this operation is much more expensive compared to + <seealso marker="#statistics_total_run_queue_lengths"><c>statistics(total_run_queue_lengths)</c></seealso>. + This especially when a large amount of schedulers is used. + </p> </desc> </func> + <func> <name name="statistics" arity="1" clause_i="8"/> - <fsummary>Information about each schedulers work time</fsummary> - <desc> - <marker id="statistics_scheduler_wall_time"></marker> - <p> - Returns a list of tuples with <c>{<anno>SchedulerId</anno>, - <anno>ActiveTime</anno>, <anno>TotalTime</anno>}</c>, where - <c>SchedulerId</c> is an integer id of the scheduler, <c>ActiveTime</c> is - the duration the scheduler has been busy, <c>TotalTime</c> is the total time duration since - <seealso marker="#system_flag_scheduler_wall_time">scheduler_wall_time</seealso> - activation. The time unit is not defined and may be subject to change - between releases, operating systems and system restarts. - <c>scheduler_wall_time</c> should only be used to calculate relative - values for scheduler-utilization. <c>ActiveTime</c> can never exceed <c>TotalTime</c>. - </p> - - <p>The definition of a busy scheduler is when it is not idle or not - scheduling (selecting) a process or port, meaning; executing process - code, executing linked-in-driver or NIF code, executing - built-in-functions or any other runtime handling, garbage collecting - or handling any other memory management. Note, a scheduler may also be - busy even if the operating system has scheduled out the scheduler - thread. - </p> + <fsummary>Information about the run-queue lengths.</fsummary> + <desc><marker id="statistics_run_queue_lengths"></marker> + <p> + Returns a list where each element represents the amount + of processes and ports ready to run for each run queue. The + element location in the list corresponds to the run queue + of a scheduler. The first element corresponds to the run + queue of scheduler number 1 and so on. The information is + <em>not</em> gathered atomically. That is, the result is + not necessarily a consistent snapshot of the state, but + instead quite efficiently gathered. See also, + <seealso marker="#statistics_total_run_queue_lengths"><c>statistics(total_run_queue_lengths)</c></seealso>, + <seealso marker="#statistics_active_tasks"><c>statistics(active_tasks)</c></seealso>, and + <seealso marker="#statistics_total_active_tasks"><c>statistics(total_active_tasks)</c></seealso>. + </p> + </desc> + </func> - <p> - Returns <c>undefined</c> if the system flag - <seealso marker="#system_flag_scheduler_wall_time">scheduler_wall_time</seealso> - is turned off. - </p> + <func> + <name name="statistics" arity="1" clause_i="9"/> + <fsummary>Information about runtime.</fsummary> + <desc> + <p>Returns information about runtime, in milliseconds.</p> + <p>This is the sum of the runtime for all threads + in the Erlang runtime system and can therefore be greater + than the wall clock time.</p> + <p>Example:</p> + <pre> +> <input>statistics(runtime).</input> +{1690,1620}</pre> + </desc> + </func> - <p>The list of scheduler information is unsorted and may appear in different order - between calls. - </p> - <p>Using <c>scheduler_wall_time</c> to calculate scheduler utilization.</p> + <func> + <name name="statistics" arity="1" clause_i="10"/> + <fsummary>Information about each schedulers work time.</fsummary> + <desc> + <marker id="statistics_scheduler_wall_time"></marker> + <p>Returns a list of tuples with + <c>{<anno>SchedulerId</anno>, <anno>ActiveTime</anno>, + <anno>TotalTime</anno>}</c>, where + <c><anno>SchedulerId</anno></c> is an integer ID of the scheduler, + <c><anno>ActiveTime</anno></c> is + the duration the scheduler has been busy, and + <c><anno>TotalTime</anno></c> is the total time duration since + <seealso marker="#system_flag_scheduler_wall_time">scheduler_wall_time</seealso> + activation. The time unit is undefined and can be subject + to change between releases, OSs, and system restarts. + <c>scheduler_wall_time</c> is only to be used to + calculate relative values for scheduler-utilization. + <c><anno>ActiveTime</anno></c> can never exceed + <c><anno>TotalTime</anno></c>.</p> + <p>The definition of a busy scheduler is when it is not idle + and is not scheduling (selecting) a process or port, + that is:</p> + <list type="bulleted"> + <item>Executing process code</item> + <item>Executing linked-in-driver or NIF code</item> + <item>Executing built-in-functions, or any other runtime + handling</item> + <item>Garbage collecting</item> + <item>Handling any other memory management</item> + </list> + <p>Notice that a scheduler can also be busy even if the + OS has scheduled out the scheduler thread.</p> + <p>Returns <c>undefined</c> if system flag + <seealso marker="#system_flag_scheduler_wall_time">scheduler_wall_time</seealso> + is turned off.</p> + <p>The list of scheduler information is unsorted and can + appear in different order between calls.</p> + <p>Using <c>scheduler_wall_time</c> to calculate scheduler-utilization:</p> <pre> > <input>erlang:system_flag(scheduler_wall_time, true).</input> false > <input>Ts0 = lists:sort(erlang:statistics(scheduler_wall_time)), ok.</input> -ok -</pre> - <p>Some time later we will take another snapshot and calculate scheduler-utilization per scheduler.</p> +ok</pre> + <p>Some time later the user takes another snapshot and calculates + scheduler-utilization per scheduler, for example:</p> <pre> > <input>Ts1 = lists:sort(erlang:statistics(scheduler_wall_time)), ok.</input> ok @@ -5437,86 +5880,127 @@ ok {5,0.9717956667018103}, {6,0.9739235846420741}, {7,0.973237033077876}, - {8,0.9741297293248656}] -</pre> - <p>Using the same snapshots to calculate a total scheduler-utilization.</p> + {8,0.9741297293248656}]</pre> + <p>Using the same snapshots to calculate a total scheduler-utilization:</p> <pre> > <input>{A, T} = lists:foldl(fun({{_, A0, T0}, {_, A1, T1}}, {Ai,Ti}) -> {Ai + (A1 - A0), Ti + (T1 - T0)} end, {0, 0}, lists:zip(Ts0,Ts1)), A/T.</input> -0.9769136803764825 -</pre> +0.9769136803764825</pre> <note> - <p><c>scheduler_wall_time</c> is by default disabled. Use <c>erlang:system_flag(scheduler_wall_time, true)</c> to enable it. </p> + <p><c>scheduler_wall_time</c> is by default disabled. To + enable it, use + <c>erlang:system_flag(scheduler_wall_time, true)</c>.</p> </note> </desc> </func> + <func> - <name name="statistics" arity="1" clause_i="9"/> - <fsummary>Information about wall-clock</fsummary> + <name name="statistics" arity="1" clause_i="11"/> + <fsummary>Information about active processes and ports.</fsummary> + <desc><marker id="statistics_total_active_tasks"></marker> + <p> + Returns the total amount of active processes and ports in + the system. That is, the number of processes and ports that + are ready to run, or are currently running. The information + is <em>not</em> gathered atomically. That is, the result + is not necessarily a consistent snapshot of the state, but + instead quite efficiently gathered. See also, + <seealso marker="#statistics_active_tasks"><c>statistics(active_tasks)</c></seealso>, + <seealso marker="#statistics_run_queue_lengths"><c>statistics(run_queue_lengths)</c></seealso>, and + <seealso marker="#statistics_total_run_queue_lengths"><c>statistics(total_run_queue_lengths)</c></seealso>. + </p> + </desc> + </func> + + <func> + <name name="statistics" arity="1" clause_i="12"/> + <fsummary>Information about the run-queue lengths.</fsummary> + <desc><marker id="statistics_total_run_queue_lengths"></marker> + <p> + Returns the total length of the run-queues. That is, the number + of processes and ports that are ready to run on all available + run-queues. The information is <em>not</em> gathered atomically. + That is, the result is not necessarily a consistent snapshot of + the state, but much more efficiently gathered compared to + <seealso marker="#statistics_run_queue"><c>statistics(run_queue)</c></seealso>. + See also, + <seealso marker="#statistics_run_queue_lengths"><c>statistics(run_queue_lengths)</c></seealso>, + <seealso marker="#statistics_total_active_tasks"><c>statistics(total_active_tasks)</c></seealso>, and + <seealso marker="#statistics_active_tasks"><c>statistics(active_tasks)</c></seealso>. + </p> + </desc> + </func> + + <func> + <name name="statistics" arity="1" clause_i="13"/> + <fsummary>Information about wall clock.</fsummary> <desc> - <p><c>wall_clock</c> can be used in the same manner as + <p>Returns information about wall clock. <c>wall_clock</c> can + be used in the same manner as <c>runtime</c>, except that real time is measured as opposed to runtime or CPU time.</p> </desc> </func> + <func> <name name="suspend_process" arity="2"/> - <fsummary>Suspend a process</fsummary> + <fsummary>Suspends a process.</fsummary> <desc> <p>Increases the suspend count on the process identified by - <c><anno>Suspendee</anno></c> and puts it in the suspended state if it isn't - already in the suspended state. A suspended process will not be - scheduled for execution until the process has been resumed. - </p> - + <c><anno>Suspendee</anno></c> and puts it in the suspended + state if it is not + already in that state. A suspended process will not be + scheduled for execution until the process has been resumed.</p> <p>A process can be suspended by multiple processes and can be suspended multiple times by a single process. A suspended - process will not leave the suspended state until its suspend - count reach zero. The suspend count of <c><anno>Suspendee</anno></c> - is decreased when + process does not leave the suspended state until its suspend + count reaches zero. The suspend count of + <c><anno>Suspendee</anno></c> is decreased when <seealso marker="#resume_process/1">erlang:resume_process(<anno>Suspendee</anno>)</seealso> is called by the same process that called - <c>erlang:suspend_process(<anno>Suspendee</anno>)</c>. All increased suspend - counts on other processes acquired by a process will automatically be + <c>erlang:suspend_process(<anno>Suspendee</anno>)</c>. + All increased suspend + counts on other processes acquired by a process are automatically decreased when the process terminates.</p> - - <p>Currently the following options (<c><anno>Opt</anno></c>s) are available:</p> + <p>The options (<c><anno>Opt</anno></c>s) are as follows:</p> <taglist> <tag><c>asynchronous</c></tag> <item> A suspend request is sent to the process identified by - <c><anno>Suspendee</anno></c>. <c><anno>Suspendee</anno></c> will eventually suspend - unless it is resumed before it was able to suspend. The caller - of <c>erlang:suspend_process/2</c> will return immediately, - regardless of whether the <c><anno>Suspendee</anno></c> has suspended yet - or not. Note that the point in time when the <c><anno>Suspendee</anno></c> - will actually suspend cannot be deduced from other events - in the system. The only guarantee given is that the - <c><anno>Suspendee</anno></c> will <em>eventually</em> suspend (unless it - is resumed). If the <c>asynchronous</c> option has <em>not</em> - been passed, the caller of <c>erlang:suspend_process/2</c> will - be blocked until the <c><anno>Suspendee</anno></c> has actually suspended. + <c><anno>Suspendee</anno></c>. <c><anno>Suspendee</anno></c> + eventually suspends + unless it is resumed before it could suspend. The caller + of <c>erlang:suspend_process/2</c> returns immediately, + regardless of whether <c><anno>Suspendee</anno></c> has + suspended yet or not. The point in time when + <c><anno>Suspendee</anno></c> suspends cannot be deduced + from other events in the system. It is only guaranteed that + <c><anno>Suspendee</anno></c> <em>eventually</em> suspends + (unless it + is resumed). If option <c>asynchronous</c> has <em>not</em> + been passed, the caller of <c>erlang:suspend_process/2</c> is + blocked until <c><anno>Suspendee</anno></c> has suspended. </item> <tag><c>unless_suspending</c></tag> <item> - The process identified by <c><anno>Suspendee</anno></c> will be suspended - unless the calling process already is suspending the - <c><anno>Suspendee</anno></c>. If <c>unless_suspending</c> is combined - with the <c>asynchronous</c> option, a suspend request will be - sent unless the calling process already is suspending the - <c><anno>Suspendee</anno></c> or if a suspend request already has been sent - and is in transit. If the calling process already is suspending - the <c><anno>Suspendee</anno></c>, or if combined with the <c>asynchronous</c> - option and a send request already is in transit, - <c>false</c> is returned and the suspend count on <c><anno>Suspendee</anno></c> - will remain unchanged. + The process identified by <c><anno>Suspendee</anno></c> is + suspended unless the calling process already is suspending + <c><anno>Suspendee</anno></c>. + If <c>unless_suspending</c> is combined + with option <c>asynchronous</c>, a suspend request is + sent unless the calling process already is suspending + <c><anno>Suspendee</anno></c> or if a suspend request + already has been sent and is in transit. If the calling + process already is suspending <c><anno>Suspendee</anno></c>, + or if combined with option <c>asynchronous</c> + and a send request already is in transit, + <c>false</c> is returned and the suspend count on + <c><anno>Suspendee</anno></c> remains unchanged. </item> </taglist> - <p>If the suspend count on the process identified by - <c><anno>Suspendee</anno></c> was increased, <c>true</c> is returned; otherwise, - <c>false</c> is returned.</p> - + <c><anno>Suspendee</anno></c> is increased, <c>true</c> + is returned, otherwise <c>false</c>.</p> <warning> <p>This BIF is intended for debugging only.</p> </warning> @@ -5524,310 +6008,322 @@ ok <taglist> <tag><c>badarg</c></tag> <item> - If <c><anno>Suspendee</anno></c> isn't a process identifier. + If <c><anno>Suspendee</anno></c> is not a process identifier. </item> <tag><c>badarg</c></tag> <item> - If the process identified by <c><anno>Suspendee</anno></c> is same the process as - the process calling <c>erlang:suspend_process/2</c>. + If the process identified by <c><anno>Suspendee</anno></c> + is the same process + as the process calling <c>erlang:suspend_process/2</c>. </item> <tag><c>badarg</c></tag> <item> - If the process identified by <c><anno>Suspendee</anno></c> is not alive. + If the process identified by <c><anno>Suspendee</anno></c> + is not alive. </item> <tag><c>badarg</c></tag> <item> - If the process identified by <c><anno>Suspendee</anno></c> resides on another node. + If the process identified by <c><anno>Suspendee</anno></c> + resides on another node. </item> <tag><c>badarg</c></tag> <item> - If <c><anno>OptList</anno></c> isn't a proper list of valid <c><anno>Opt</anno></c>s. + If <c><anno>OptList</anno></c> is not a proper list of valid + <c><anno>Opt</anno></c>s. </item> <tag><c>system_limit</c></tag> <item> - If the process identified by <c><anno>Suspendee</anno></c> has been suspended more - times by the calling process than can be represented by the - currently used internal data structures. The current system limit - is larger than 2 000 000 000 suspends, and it will never be less - than that. + If the process identified by <c><anno>Suspendee</anno></c> + has been suspended + more times by the calling process than can be represented by the + currently used internal data structures. The system limit is + higher than 2,000,000,000 suspends and will never be lower. </item> </taglist> </desc> </func> + <func> <name name="suspend_process" arity="1"/> - <fsummary>Suspend a process</fsummary> + <fsummary>Suspends a process.</fsummary> <desc> - <p>Suspends the process identified by <c><anno>Suspendee</anno></c>. The - same as calling - <seealso marker="#suspend_process/2">erlang:suspend_process(<anno>Suspendee</anno>, [])</seealso>. For more information see the documentation of <seealso marker="#suspend_process/2">erlang:suspend_process/2</seealso>. - </p> + <p>Suspends the process identified by + <c><anno>Suspendee</anno></c>. The same as calling + <seealso marker="#suspend_process/2">erlang:suspend_process(<anno>Suspendee</anno>, + [])</seealso>.</p> <warning> <p>This BIF is intended for debugging only.</p> </warning> </desc> </func> + <func> <name name="system_flag" arity="2" clause_i="1"/> - <fsummary>Set system flag backtrace_depth</fsummary> + <fsummary>Sets system flag <c>backtrace_depth</c>.</fsummary> <desc> <p>Sets the maximum depth of call stack back-traces in the exit reason element of <c>'EXIT'</c> tuples.</p> <p>Returns the old value of the flag.</p> </desc> </func> + <func> <name name="system_flag" arity="2" clause_i="2"/> + <fsummary>Sets system flag <c>cpu_topology</c>.</fsummary> <type name="cpu_topology"/> <type name="level_entry"/> <type name="level_tag"/> <type name="sub_level"/> <type name="info_list"/> - <fsummary>Set system flag cpu_topology</fsummary> <desc> <warning> <p><marker id="system_flag_cpu_topology"></marker> - This argument is <em>deprecated</em> and - scheduled for removal in erts-5.10/OTP-R16. Instead of using - this argument you are advised to use the <c>erl</c> command - line argument <seealso marker="erts:erl#+sct">+sct</seealso>. - When this argument has been removed a final CPU topology to use - will be determined at emulator boot time.</p> + This argument is <em>deprecated</em> and scheduled for + removal in <c>ERTS</c> 5.10/OTP R16. Instead of using this + argument, use command-line argument + <seealso marker="erts:erl#+sct">+sct</seealso> in + <c>erl(1)</c>.</p> + <p>When this argument is removed, a final CPU topology + to use is determined at emulator boot time.</p> </warning> - <p>Sets the user defined <c><anno>CpuTopology</anno></c>. The user defined - CPU topology will override any automatically detected - CPU topology. By passing <c>undefined</c> as <c><anno>CpuTopology</anno></c> - the system will revert back to the CPU topology automatically + <p>Sets the user-defined <c><anno>CpuTopology</anno></c>. + The user-defined + CPU topology overrides any automatically detected + CPU topology. By passing <c>undefined</c> as + <c><anno>CpuTopology</anno></c>, + the system reverts to the CPU topology automatically detected. The returned value equals the value returned from <c>erlang:system_info(cpu_topology)</c> before the - change was made. - </p> + change was made.</p> <p>Returns the old value of the flag.</p> <p>The CPU topology is used when binding schedulers to logical processors. If schedulers are already bound when the CPU - topology is changed, the schedulers will be sent a request - to rebind according to the new CPU topology. - </p> - <p>The user defined CPU topology can also be set by passing - the <seealso marker="erts:erl#+sct">+sct</seealso> command - line argument to <c>erl</c>. - </p> - <p>For information on the <c><anno>CpuTopology</anno></c> type - and more, see the documentation of - <seealso marker="#system_info_cpu_topology">erlang:system_info(cpu_topology)</seealso>, - and the <c>erl</c> <seealso marker="erts:erl#+sct">+sct</seealso> - and <seealso marker="erts:erl#+sbt">+sbt</seealso> - command line flags. - </p> + topology is changed, the schedulers are sent a request + to rebind according to the new CPU topology.</p> + <p>The user-defined CPU topology can also be set by passing + command-line argument + <seealso marker="erts:erl#+sct">+sct</seealso> to + <c>erl(1)</c>.</p> + <p>For information on type <c><anno>CpuTopology</anno></c> + and more, see + <seealso marker="#system_info_cpu_topology">erlang:system_info(cpu_topology)</seealso> + as well as the command-line flags + <seealso marker="erts:erl#+sct">+sct</seealso> and + <seealso marker="erts:erl#+sbt">+sbt</seealso> in + <c>erl(1)</c>.</p> </desc> </func> + <func> <name name="system_flag" arity="2" clause_i="3"/> - <fsummary>Set system flag dirty CPU schedulers online</fsummary> + <fsummary>Sets <c>system_flag_dirty_cpu_schedulers_online</c>.</fsummary> <desc> <p><marker id="system_flag_dirty_cpu_schedulers_online"></marker> - Sets the amount of dirty CPU schedulers online. Valid range is - <![CDATA[1 <= DirtyCPUSchedulersOnline <= N]]> where <c>N</c> is the - lesser of the return values of <c>erlang:system_info(dirty_cpu_schedulers)</c> and - <c>erlang:system_info(schedulers_online)</c>. - </p> + Sets the number of dirty CPU schedulers online. Range is + <![CDATA[1 <= DirtyCPUSchedulersOnline <= N]]>, where <c>N</c> + is the smallest of the return values of + <c>erlang:system_info(dirty_cpu_schedulers)</c> and + <c>erlang:system_info(schedulers_online)</c>.</p> <p>Returns the old value of the flag.</p> - <p>Note that the number of dirty CPU schedulers online may change if the number of - schedulers online changes. For example, if there are 12 schedulers and all are - online, and 6 dirty CPU schedulers, all online as well, and <c>system_flag/2</c> - is used to set the number of schedulers online to 6, then the number of dirty - CPU schedulers online is automatically decreased by half as well, down to 3. - Similarly, the number of dirty CPU schedulers online increases proportionally - to increases in the number of schedulers online.</p> - <p><em>Note that the dirty schedulers functionality is experimental</em>, and - that you have to enable support for dirty schedulers when building OTP in order - to try out the functionality.</p> - <p>For more information see + <p>The number of dirty CPU schedulers online can change if the + number of schedulers online changes. For example, if 12 + schedulers and 6 dirty CPU schedulers are online, and + <c>system_flag/2</c> is used to set the number of + schedulers online to 6, then the number of dirty CPU + schedulers online is automatically decreased by half as well, + down to 3. Similarly, the number of dirty CPU schedulers + online increases proportionally to increases in the number of + schedulers online.</p> + <note><p>The dirty schedulers functionality is experimental. + Enable support for dirty schedulers when building OTP to + try out the functionality.</p> + </note> + <p>For more information, see <seealso marker="#system_info_dirty_cpu_schedulers">erlang:system_info(dirty_cpu_schedulers)</seealso> and - <seealso marker="#system_info_dirty_cpu_schedulers_online">erlang:system_info(dirty_cpu_schedulers_online)</seealso>. - </p> + <seealso marker="#system_info_dirty_cpu_schedulers_online">erlang:system_info(dirty_cpu_schedulers_online)</seealso>.</p> </desc> </func> + <func> <name name="system_flag" arity="2" clause_i="4"/> - <fsummary>Set system flag fullsweep_after</fsummary> + <fsummary>Sets system flag <c>fullsweep_after</c>.</fsummary> <desc> - <p><c><anno>Number</anno></c> is a non-negative integer which indicates + <p>Sets system flag <c>fullsweep_after</c>. + <c><anno>Number</anno></c> is a non-negative integer indicating how many times generational garbage collections can be done without forcing a fullsweep collection. The value - applies to new processes; processes already running are + applies to new processes, while processes already running are not affected.</p> <p>Returns the old value of the flag.</p> <p>In low-memory systems (especially without virtual - memory), setting the value to 0 can help to conserve + memory), setting the value to <c>0</c> can help to conserve memory.</p> - <p>An alternative way to set this value is through the - (operating system) environment variable - <c>ERL_FULLSWEEP_AFTER</c>.</p> + <p>This value can also be set through (OS) + environment variable <c>ERL_FULLSWEEP_AFTER</c>.</p> </desc> </func> + <func> <name name="system_flag" arity="2" clause_i="5"/> - <fsummary>Set system flag min_heap_size</fsummary> - <desc> - <p>Sets the default minimum heap size for processes. The - size is given in words. The new <c>min_heap_size</c> only - effects processes spawned after the change of - <c>min_heap_size</c> has been made. - The <c>min_heap_size</c> can be set for individual - processes by use of + <fsummary>Sets system flag <c>min_heap_size</c>.</fsummary> + <desc> + <p>Sets the default minimum heap size for processes. The size + is given in words. The new <c>min_heap_size</c> effects + only processes spawned after the change of + <c>min_heap_size</c> has been made. <c>min_heap_size</c> + can be set for individual processes by using <seealso marker="#spawn_opt/4">spawn_opt/N</seealso> or - <seealso marker="#process_flag/2">process_flag/2</seealso>. </p> + <seealso marker="#process_flag/2">process_flag/2</seealso>.</p> <p>Returns the old value of the flag.</p> </desc> </func> + <func> <name name="system_flag" arity="2" clause_i="6"/> - <fsummary>Set system flag min_bin_vheap_size</fsummary> + <fsummary>Sets system flag <c>min_bin_vheap_size</c>.</fsummary> <desc> - <p>Sets the default minimum binary virtual heap size for processes. The - size is given in words. The new <c>min_bin_vhheap_size</c> only - effects processes spawned after the change of + <p>Sets the default minimum binary virtual heap size for + processes. The size is given in words. + The new <c>min_bin_vhheap_size</c> effects only + processes spawned after the change of <c>min_bin_vhheap_size</c> has been made. - The <c>min_bin_vheap_size</c> can be set for individual - processes by use of + <c>min_bin_vheap_size</c> can be set for individual + processes by using <seealso marker="#spawn_opt/4">spawn_opt/N</seealso> or - <seealso marker="#process_flag/2">process_flag/2</seealso>. </p> + <seealso marker="#process_flag/2">process_flag/2</seealso>.</p> <p>Returns the old value of the flag.</p> </desc> </func> + <func> <name name="system_flag" arity="2" clause_i="7"/> - <fsummary>Set system flag multi_scheduling</fsummary> + <fsummary>Sets system flag <c>multi_scheduling</c>.</fsummary> <desc> <p><marker id="system_flag_multi_scheduling"></marker> If multi-scheduling is enabled, more than one scheduler thread is used by the emulator. Multi-scheduling can be - blocked. When multi-scheduling has been blocked, only - one scheduler thread will schedule Erlang processes.</p> - <p>If <c><anno>BlockState</anno> =:= block</c>, multi-scheduling will - be blocked. If <c><anno>BlockState</anno> =:= unblock</c> and no-one - else is blocking multi-scheduling and this process has - only blocked one time, multi-scheduling will be unblocked. - One process can block multi-scheduling multiple times. - If a process has blocked multiple times, it has to + blocked. When multi-scheduling is blocked, only + one scheduler thread schedules Erlang processes.</p> + <p>If <c><anno>BlockState</anno> =:= block</c>, multi-scheduling is + blocked. If <c><anno>BlockState</anno> =:= unblock</c> and no one + else blocks multi-scheduling, and this process has + blocked only once, multi-scheduling is unblocked.</p> + <p>One process can block multi-scheduling multiple times. + If a process has blocked multiple times, it must unblock exactly as many times as it has blocked before it has released its multi-scheduling block. If a process that - has blocked multi-scheduling exits, it will release its + has blocked multi-scheduling exits, it releases its blocking of multi-scheduling.</p> <p>The return values are <c>disabled</c>, <c>blocked</c>, or <c>enabled</c>. The returned value describes the state just after the call to <c>erlang:system_flag(multi_scheduling, <anno>BlockState</anno>)</c> - has been made. The return values are described in the - documentation of <seealso marker="#system_info_multi_scheduling">erlang:system_info(multi_scheduling)</seealso>.</p> - <p><em>NOTE</em>: Blocking of multi-scheduling should normally - not be needed. If you feel that you need to - block multi-scheduling, think through the - problem at least a couple of times again. - Blocking multi-scheduling should only be used - as a last resort since it will most likely be - a <em>very inefficient</em> way to solve the - problem.</p> - <p>See also <seealso marker="#system_info_multi_scheduling">erlang:system_info(multi_scheduling)</seealso>, + has been made. For information about the return values, see + <seealso marker="#system_info_multi_scheduling">erlang:system_info(multi_scheduling)</seealso>.</p> + <note><p>Blocking of multi-scheduling is normally not needed. + If you feel that you need to block multi-scheduling, + consider it a few more times again. Blocking multi-scheduling + is only to be used as a last resort, as it is most likely + a <em>very inefficient</em> way to solve the problem.</p> + </note> + <p>See also + <seealso marker="#system_info_multi_scheduling">erlang:system_info(multi_scheduling)</seealso>, <seealso marker="#system_info_multi_scheduling_blockers">erlang:system_info(multi_scheduling_blockers)</seealso>, and <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso>.</p> </desc> </func> + <func> <name name="system_flag" arity="2" clause_i="8"/> + <fsummary>Sets system flag <c>scheduler_bind_type</c>.</fsummary> <type name="scheduler_bind_type"/> - <fsummary>Set system flag scheduler_bind_type</fsummary> <desc> <warning> <p><marker id="system_flag_scheduler_bind_type"></marker> - This argument is <em>deprecated</em> and - scheduled for removal in erts-5.10/OTP-R16. Instead of using - this argument you are advised to use the <c>erl</c> command - line argument <seealso marker="erts:erl#+sbt">+sbt</seealso>. - When this argument has been removed a final scheduler bind type - to use will be determined at emulator boot time.</p> + This argument is <em>deprecated</em> and scheduled for + removal in <c>ERTS</c> 5.10/OTP R16. Instead of using this + argument, use command-line argument + <seealso marker="erts:erl#+sbt">+sbt</seealso> in <c>erl(1)</c>. + When this argument is removed, a final scheduler bind + type to use is determined at emulator boot time.</p> </warning> <p>Controls if and how schedulers are bound to logical processors.</p> - <p>When <c>erlang:system_flag(scheduler_bind_type, <anno>How</anno>)</c> is - called, an asynchronous signal is sent to all schedulers - online which causes them to try to bind or unbind as requested. - <em>NOTE:</em> If a scheduler fails to bind, this - will often be silently ignored. This since it isn't always - possible to verify valid logical processor identifiers. If - an error is reported, it will be reported to the - <c>error_logger</c>. If you want to verify that the - schedulers actually have bound as requested, call - <seealso marker="#system_info_scheduler_bindings">erlang:system_info(scheduler_bindings)</seealso>. - </p> - <p>Schedulers can currently only be bound on newer Linux, + <p>When <c>erlang:system_flag(scheduler_bind_type, <anno>How</anno>)</c> + is called, an asynchronous signal is sent to all schedulers + online, causing them to try to bind or unbind as requested.</p> + <note><p>If a scheduler fails to bind, this is often silently + ignored, as it is not always possible to verify valid + logical processor identifiers. If an error is reported, + it is reported to <c>error_logger</c>. To verify that the + schedulers have bound as requested, call + <seealso marker="#system_info_scheduler_bindings">erlang:system_info(scheduler_bindings)</seealso>.</p> + </note> + <p>Schedulers can be bound on newer Linux, Solaris, FreeBSD, and Windows systems, but more systems will be - supported in the future. - </p> + supported in future releases.</p> <p>In order for the runtime system to be able to bind schedulers, - the CPU topology needs to be known. If the runtime system fails - to automatically detect the CPU topology, it can be defined. + the CPU topology must be known. If the runtime system fails + to detect the CPU topology automatically, it can be defined. For more information on how to define the CPU topology, see - the <c>erl</c> <seealso marker="erts:erl#+sct">+sct</seealso> command - line flag. - </p> - <p>The runtime system will by default <em>not</em> bind schedulers - to logical processors. - </p> - <p><em>NOTE:</em> If the Erlang runtime system is the only - operating system process that binds threads to logical processors, - this improves the performance of the runtime system. However, - if other operating system processes (as for example another Erlang - runtime system) also bind threads to logical processors, there - might be a performance penalty instead. In some cases this - performance penalty might be severe. If this is the case, you - are advised to not bind the schedulers.</p> - <p>Schedulers can be bound in different ways. The <c><anno>How</anno></c> - argument determines how schedulers are bound. <c><anno>How</anno></c> can - currently be one of:</p> + command-line flag <seealso marker="erts:erl#+sct">+sct</seealso> + in <c>erl(1)</c>.</p> + <p>The runtime system does by default <em>not</em> bind schedulers + to logical processors.</p> + <note><p>If the Erlang runtime system is the only OS + process binding threads to logical processors, this + improves the performance of the runtime system. However, + if other OS processes (for example, another Erlang + runtime system) also bind threads to logical processors, + there can be a performance penalty instead. Sometimes this + performance penalty can be severe. If so, it is recommended + to not bind the schedulers.</p> + </note> + <p>Schedulers can be bound in different ways. Argument + <c><anno>How</anno></c> determines how schedulers are + bound and can be any of the following:</p> <taglist> <tag><c>unbound</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt u</seealso>. + <item><p>Same as command-line argument + <seealso marker="erts:erl#+sbt">+sbt u</seealso> in <c>erl(1)</c>. </p></item> <tag><c>no_spread</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt ns</seealso>. + <item><p>Same as command-line argument + <seealso marker="erts:erl#+sbt">+sbt ns</seealso> in <c>erl(1)</c>. </p></item> <tag><c>thread_spread</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt ts</seealso>. + <item><p>Same as command-line argument + <seealso marker="erts:erl#+sbt">+sbt ts</seealso> in <c>erl(1)</c>. </p></item> <tag><c>processor_spread</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt ps</seealso>. + <item><p>Same as command-line argument + <seealso marker="erts:erl#+sbt">+sbt ps</seealso> in <c>erl(1)</c>. </p></item> <tag><c>spread</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt s</seealso>. + <item><p>Same as command-line argument + <seealso marker="erts:erl#+sbt">+sbt s</seealso> in <c>erl(1)</c>. </p></item> <tag><c>no_node_thread_spread</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt nnts</seealso>. + <item><p>Same as command-line argument + <seealso marker="erts:erl#+sbt">+sbt nnts</seealso> in <c>erl(1)</c>. </p></item> <tag><c>no_node_processor_spread</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt nnps</seealso>. + <item><p>Same as command-line argument + <seealso marker="erts:erl#+sbt">+sbt nnps</seealso> in <c>erl(1)</c>. </p></item> <tag><c>thread_no_node_processor_spread</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt tnnps</seealso>. + <item><p>Same as command-line argument + <seealso marker="erts:erl#+sbt">+sbt tnnps</seealso> in <c>erl(1)</c>. </p></item> <tag><c>default_bind</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt db</seealso>. + <item><p>Same as command-line argument + <seealso marker="erts:erl#+sbt">+sbt db</seealso> in <c>erl(1)</c>. </p></item> </taglist> - <p>The value returned equals <c><anno>How</anno></c> before the - <c>scheduler_bind_type</c> flag was changed.</p> - <p>Failure:</p> + <p>The returned value equals <c><anno>How</anno></c> before flag + <c>scheduler_bind_type</c> was changed.</p> + <p>Failures:</p> <taglist> <tag><c>notsup</c></tag> <item> @@ -5835,168 +6331,171 @@ ok </item> <tag><c>badarg</c></tag> <item> - <p>If <c>How</c> isn't one of the documented alternatives.</p> + <p>If <c><anno>How</anno></c> is not one of the documented + alternatives.</p> </item> <tag><c>badarg</c></tag> <item> - <p>If no CPU topology information is available.</p> + <p>If CPU topology information is unavailable.</p> </item> </taglist> <p>The scheduler bind type can also be set by passing - the <seealso marker="erts:erl#+sbt">+sbt</seealso> command - line argument to <c>erl</c>. - </p> + command-line argument + <seealso marker="erts:erl#+sbt">+sbt</seealso> to <c>erl(1)</c>.</p> <p>For more information, see <seealso marker="#system_info_scheduler_bind_type">erlang:system_info(scheduler_bind_type)</seealso>, <seealso marker="#system_info_scheduler_bindings">erlang:system_info(scheduler_bindings)</seealso>, - the <c>erl</c> <seealso marker="erts:erl#+sbt">+sbt</seealso> - and <seealso marker="erts:erl#+sct">+sct</seealso> command line - flags. - </p> + as well as command-line flags + <seealso marker="erts:erl#+sbt">+sbt</seealso> + and <seealso marker="erts:erl#+sct">+sct</seealso> + in <c>erl(1)</c>.</p> </desc> </func> + <func> <name name="system_flag" arity="2" clause_i="9"/> - <fsummary>Set system flag scheduler_wall_time</fsummary> + <fsummary>Sets system flag <c>scheduler_wall_time</c>.</fsummary> <desc><p><marker id="system_flag_scheduler_wall_time"></marker> - Turns on/off scheduler wall time measurements. </p> - <p>For more information see, - <seealso marker="#statistics_scheduler_wall_time">erlang:statistics(scheduler_wall_time)</seealso>. - </p> + Turns on or off scheduler wall time measurements.</p> + <p>For more information, see + <seealso marker="#statistics_scheduler_wall_time">erlang:statistics(scheduler_wall_time)</seealso>.</p> </desc> </func> + <func> <name name="system_flag" arity="2" clause_i="10"/> - <fsummary>Set system flag schedulers_online</fsummary> + <fsummary>Sets system flag <c>schedulers_online</c>.</fsummary> <desc> <p><marker id="system_flag_schedulers_online"></marker> - Sets the amount of schedulers online. Valid range is - <![CDATA[1 <= SchedulersOnline <= erlang:system_info(schedulers)]]>. - </p> + Sets the number of schedulers online. Range is + <![CDATA[1 <= SchedulersOnline <= erlang:system_info(schedulers)]]>.</p> <p>Returns the old value of the flag.</p> - <p>Note that if the emulator was built with support for <seealso - marker="#system_flag_dirty_cpu_schedulers_online">dirty schedulers</seealso>, - changing the number of schedulers online can also change the number of dirty - CPU schedulers online. For example, if there are 12 schedulers and all are - online, and 6 dirty CPU schedulers, all online as well, and <c>system_flag/2</c> - is used to set the number of schedulers online to 6, then the number of dirty - CPU schedulers online is automatically decreased by half as well, down to 3. - Similarly, the number of dirty CPU schedulers online increases proportionally - to increases in the number of schedulers online.</p> - <p>For more information see, - <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso>, + <p>If the emulator was built with support for + <seealso marker="#system_flag_dirty_cpu_schedulers_online">dirty schedulers</seealso>, + changing the number of schedulers online can also change the + number of dirty CPU schedulers online. For example, if 12 + schedulers and 6 dirty CPU schedulers are online, and + <c>system_flag/2</c> is used to set the number of schedulers + online to 6, then the number of dirty CPU schedulers online + is automatically decreased by half as well, down to 3. + Similarly, the number of dirty CPU schedulers online increases + proportionally to increases in the number of schedulers online.</p> + <p>For more information, see + <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso> and - <seealso marker="#system_info_schedulers_online">erlang:system_info(schedulers_online)</seealso>. - </p> + <seealso marker="#system_info_schedulers_online">erlang:system_info(schedulers_online)</seealso>.</p> </desc> </func> + <func> <name name="system_flag" arity="2" clause_i="11"/> - <fsummary>Set system flag trace_control_word</fsummary> + <fsummary>Sets system flag <c>trace_control_word</c>.</fsummary> <desc> - <p>Sets the value of the node's trace control word to - <c><anno>TCW</anno></c>. <c><anno>TCW</anno></c> should be an unsigned integer. For - more information see documentation of the + <p>Sets the value of the node trace control word to + <c><anno>TCW</anno></c>, which is to be an unsigned integer. + For more information, see the function <seealso marker="erts:match_spec#set_tcw">set_tcw</seealso> - function in the match specification documentation in the - ERTS User's Guide.</p> + in Section "Match Specifications in Erlang" in the + User's Guide.</p> <p>Returns the old value of the flag.</p> </desc> </func> - <marker id="system_flag_time_offset"/> + <func> <name name="system_flag" arity="2" clause_i="12"/> <fsummary>Finalize the Time Offset</fsummary> <desc> - <p>Finalizes the <seealso marker="#time_offset/0">time offset</seealso> - when the <seealso marker="time_correction#Single_Time_Warp_Mode">single - time warp mode</seealso> is being used. If another time warp mode than - the "single time warp mode" is used, the time offset state will be left - unchanged.</p> - <p>Returns the old state identifier. That is, if:</p> + <p><marker id="system_flag_time_offset"></marker> + Finalizes the <seealso marker="#time_offset/0">time offset</seealso> + when <seealso marker="time_correction#Single_Time_Warp_Mode">single + time warp mode</seealso> is used. If another time warp mode + is used, the time offset state is left unchanged.</p> + <p>Returns the old state identifier. That is:</p> <list> - <item><p><c>preliminary</c> is returned, finalization was + <item><p>If <c>preliminary</c> is returned, finalization was performed and the time offset is now final.</p></item> - <item><p><c>final</c> is returned, the time offset was - already in the final state. This either due to another + <item><p>If <c>final</c> is returned, the time offset was + already in the final state. This either because another <c>erlang:system_flag(time_offset, finalize)</c> call, or - due to the - <seealso marker="time_correction#No_Time_Warp_Mode">no - time warp mode</seealso> being used.</p></item> + because <seealso marker="time_correction#No_Time_Warp_Mode">no + time warp mode</seealso> is used.</p></item> - <item><p><c>volatile</c> is returned, the time offset - cannot be finalized due to the + <item><p>If <c>volatile</c> is returned, the time offset + cannot be finalized because <seealso marker="time_correction#Multi_Time_Warp_Mode">multi - time warp mode</seealso> being used.</p></item> + time warp mode</seealso> is used.</p></item> </list> </desc> </func> + <func> <name name="system_info" arity="1" clause_i="1"/> <name name="system_info" arity="1" clause_i="2"/> <name name="system_info" arity="1" clause_i="3"/> <name name="system_info" arity="1" clause_i="4"/> <name name="system_info" arity="1" clause_i="5"/> + <fsummary>Information about the system allocators.</fsummary> <type variable="Allocator" name_i="2"/> <type variable="Version" name_i="2"/> <type variable="Features" name_i="2"/> <type variable="Settings" name_i="2"/> <type variable="Alloc" name_i="3"/> - <fsummary>Information about the allocators of the system</fsummary> <desc> - <p> - Returns various information about the - <marker id="system_info_allocator_tags">allocators</marker> of the + <marker id="system_info_allocator_tags"></marker> + <p>Returns various information about the allocators of the current system (emulator) as specified by <c><anno>Item</anno></c>:</p> + <marker id="system_info_allocated_areas"></marker> <taglist> - <tag><marker id="system_info_allocated_areas"><c>allocated_areas</c></marker></tag> + <tag><c>allocated_areas</c></tag> <item> <p>Returns a list of tuples with information about miscellaneous allocated memory areas.</p> - <p>Each tuple contains an atom describing type of memory as - first element and amount of allocated memory in bytes as - second element. In those cases when there is information - present about allocated and used memory, a third element - is present. This third element contains the amount of + <p>Each tuple contains an atom describing the type of + memory as first element and the amount of allocated + memory in bytes as second element. When information + about allocated and used memory is present, also a + third element is present, containing the amount of used memory in bytes.</p> <p><c>erlang:system_info(allocated_areas)</c> is intended - for debugging, and the content is highly implementation - dependent. The content of the results will therefore - change when needed without prior notice.</p> - <p><em>Note:</em> The sum of these values is <em>not</em> + for debugging, and the content is highly + implementation-dependent. The content of the results + therefore changes when needed without prior notice.</p> + <p>Notice that the sum of these values is <em>not</em> the total amount of memory allocated by the emulator. Some values are part of other values, and some memory - areas are not part of the result. If you are interested - in the total amount of memory allocated by the emulator - see <seealso marker="#memory/0">erlang:memory/0,1</seealso>.</p> + areas are not part of the result. For information about + the total amount of memory allocated by the emulator, see + <seealso marker="#memory/0">erlang:memory/0,1</seealso>.</p> </item> - <tag><marker id="system_info_allocator"><c>allocator</c></marker></tag> + <tag><c>allocator</c></tag> <item> - <p>Returns <c>{<anno>Allocator</anno>, <anno>Version</anno>, <anno>Features</anno>, <anno>Settings</anno>}.</c></p> - <p>Explanation:</p> + <marker id="system_info_allocator"></marker> + <p>Returns <c>{<anno>Allocator</anno>, <anno>Version</anno>, + <anno>Features</anno>, <anno>Settings</anno></c>, where:</p> <list type="bulleted"> <item> - <p><c><anno>Allocator</anno></c> corresponds to the <c>malloc()</c> - implementation used. If <c><anno>Allocator</anno></c> equals + <p><c><anno>Allocator</anno></c> corresponds to the + <c>malloc()</c> implementation used. If + <c><anno>Allocator</anno></c> equals <c>undefined</c>, the <c>malloc()</c> implementation - used could not be identified. Currently - <c>glibc</c> can be identified.</p> + used cannot be identified. <c>glibc</c> can be + identified.</p> </item> <item> - <p><c><anno>Version</anno></c> is a list of integers (but not a - string) representing the version of + <p><c><anno>Version</anno></c> is a list of integers + (but not a string) representing the version of the <c>malloc()</c> implementation used.</p> </item> <item> - <p><c><anno>Features</anno></c> is a list of atoms representing - allocation features used.</p> + <p><c><anno>Features</anno></c> is a list of atoms + representing the allocation features used.</p> </item> <item> - <p><c><anno>Settings</anno></c> is a list of subsystems, their - configurable parameters, and used values. Settings - may differ between different combinations of + <p><c><anno>Settings</anno></c> is a list of subsystems, + their configurable parameters, and used values. Settings + can differ between different combinations of platforms, allocators, and allocation features. Memory sizes are given in bytes.</p> </item> @@ -6004,165 +6503,169 @@ ok <p>See also "System Flags Effecting erts_alloc" in <seealso marker="erts:erts_alloc#flags">erts_alloc(3)</seealso>.</p> </item> - <tag><marker id="system_info_alloc_util_allocators"><c>alloc_util_allocators</c></marker></tag> + <tag><c>alloc_util_allocators</c></tag> <item> - <p>Returns a list of the names of all allocators - using the ERTS internal <c>alloc_util</c> framework - as atoms. For more information see the - <seealso marker="erts:erts_alloc#alloc_util">"the - alloc_util framework" section in the - erts_alloc(3)</seealso> documentation. - </p> + <marker id="system_info_alloc_util_allocators"></marker> + <p>Returns a list of the names of all allocators using + the <c>ERTS</c> internal <c>alloc_util</c> framework + as atoms. For more information, see Section + <seealso marker="erts:erts_alloc#alloc_util">"The + alloc_util framework" in erts_alloc(3)</seealso>.</p> </item> - <tag><marker id="system_info_allocator_tuple"><c>{allocator, <anno>Alloc</anno>}</c></marker></tag> + <tag><c>{allocator, <anno>Alloc</anno>}</c></tag> <item> + <marker id="system_info_allocator_tuple"></marker> <p>Returns information about the specified allocator. - As of erts version 5.6.1 the return value is a list - of <c>{instance, InstanceNo, InstanceInfo}</c> tuples + As from <c>ERTS</c> 5.6.1, the return value is a list + of <c>{instance, InstanceNo, InstanceInfo}</c> tuples, where <c>InstanceInfo</c> contains information about - a specific instance of the allocator. As of erts version - 5.10.4 the returned list when calling + a specific instance of the allocator. As from + <c>ERTS</c> 5.10.4, the returned list when calling <c>erlang:system_info({allocator, mseg_alloc})</c> also - include an <c>{erts_mmap, _}</c> tuple as one element - in the list. - If <c><anno>Alloc</anno></c> is not a recognized allocator, - <c>undefined</c> is returned. If <c><anno>Alloc</anno></c> is disabled, + includes an <c>{erts_mmap, _}</c> tuple as one element + in the list. If <c><anno>Alloc</anno></c> is not a + recognized allocator, <c>undefined</c> is returned. + If <c><anno>Alloc</anno></c> is disabled, <c>false</c> is returned.</p> - <p><em>Note:</em> The information returned is highly - implementation dependent and may be changed, or removed + <p>Notice that the information returned is highly + implementation-dependent and can be changed or removed at any time without prior notice. It was initially intended as a tool when developing new allocators, but - since it might be of interest for others it has been + as it can be of interest for others it has been briefly documented.</p> <p>The recognized allocators are listed in <seealso marker="erts:erts_alloc">erts_alloc(3)</seealso>. After reading the <c>erts_alloc(3)</c> documentation, the returned information - should more or less speak for itself. But it can be worth + more or less speaks for itself, but it can be worth explaining some things. Call counts are presented by two - values. The first value is giga calls, and the second - value is calls. <c>mbcs</c>, and <c>sbcs</c> are - abbreviations for, respectively, multi-block carriers, and - single-block carriers. Sizes are presented in bytes. When - it is not a size that is presented, it is the amount of - something. Sizes and amounts are often presented by three - values, the first is current value, the second is maximum - value since the last call to - <c>erlang:system_info({allocator, Alloc})</c>, and - the third is maximum value since the emulator was started. - If only one value is present, it is the current value. + values, the first value is giga calls, and the second + value is calls. <c>mbcs</c> and <c>sbcs</c> denote + multi-block carriers, and single-block carriers, + respectively. Sizes are presented in bytes. When a + size is not presented, it is the amount of something. + Sizes and amounts are often presented by three values:</p> + <list type="bulleted"> + <item>The first is the current value.</item> + <item>The second is the maximum value since the last call + to <c>erlang:system_info({allocator, Alloc})</c>.</item> + <item>The third is the maximum value since the emulator + was started.</item> + </list> + <p>If only one value is present, it is the current value. <c>fix_alloc</c> memory block types are presented by two - values. The first value is memory pool size and - the second value used memory size.</p> + values. The first value is the memory pool size and + the second value is the used memory size.</p> </item> - <tag><marker id="system_info_allocator_sizes"><c>{allocator_sizes, <anno>Alloc</anno>}</c></marker></tag> + <tag><c>{allocator_sizes, <anno>Alloc</anno>}</c></tag> <item> + <marker id="system_info_allocator_sizes"></marker> <p>Returns various size information for the specified allocator. The information returned is a subset of the information returned by - <seealso marker="#system_info_allocator_tuple">erlang:system_info({allocator, <anno>Alloc</anno>})</seealso>. + <seealso marker="#system_info_allocator_tuple"><c>erlang:system_info({allocator, <anno>Alloc</anno>})</c></seealso>. </p> </item> </taglist> </desc> </func> + <func> <name name="system_info" arity="1" clause_i="10"/> <name name="system_info" arity="1" clause_i="11"/> + <fsummary>Information about the CPU topology of the system.</fsummary> <type name="cpu_topology"/> <type name="level_entry"/> <type_desc name="cpu_topology"> - <marker id="system_info_cpu_topology"></marker> All <c><anno>LevelEntry</anno></c>s of a list must contain the same <c><anno>LevelTag</anno></c>, except on the top level where both <c>node</c> and - <c>processor</c> <c><anno>LevelTag</anno></c>s may co-exist. + <c>processor</c> <c><anno>LevelTag</anno></c>s can coexist. </type_desc> <type_desc name="level_entry"> - <c>{<anno>LevelTag</anno>, <anno>SubLevel</anno>} == {<anno>LevelTag</anno>, [], <anno>SubLevel</anno>}</c> + <c>{<anno>LevelTag</anno>, + <anno>SubLevel</anno>} == {<anno>LevelTag</anno>, [], + <anno>SubLevel</anno>}</c> </type_desc> <type name="level_tag"/> <type_desc name="level_tag"> - More <c><anno>LevelTag</anno></c>s may be introduced in the future. + More <c><anno>LevelTag</anno></c>s can be introduced in a + future release. </type_desc> <type name="sub_level"/> <type name="info_list"/> <type_desc name="info_list"> - The <c>info_list()</c> may be extended in the future. + The <c>info_list()</c> can be extended in a future release. </type_desc> - <fsummary>Information about the CPU topology of the system</fsummary> <desc> - <p>Returns various information about the - <marker id="system_info_cpu_topology_tags">CPU topology</marker> - of the current system - (emulator) as specified by <c><anno>Item</anno></c>:</p> + <marker id="system_info_cpu_topology_tags"></marker> + <marker id="system_info_cpu_topology"></marker> + <p>Returns various information about the CPU topology of + the current system (emulator) as specified by + <c><anno>Item</anno></c>:</p> <taglist> <tag><c>cpu_topology</c></tag> <item> - <p>Returns the <c><anno>CpuTopology</anno></c> which currently is used by the - emulator. The CPU topology is used when binding schedulers + <p>Returns the <c><anno>CpuTopology</anno></c> currently used by + the emulator. The CPU topology is used when binding schedulers to logical processors. The CPU topology used is the - <seealso marker="erlang#system_info_cpu_topology_defined">user - defined CPU topology</seealso> if such exists; otherwise, the - <seealso marker="erlang#system_info_cpu_topology_detected">automatically - detected CPU topology</seealso> if such exists. If no CPU topology + <seealso marker="erlang#system_info_cpu_topology_defined">user-defined CPU topology</seealso>, + if such exists, otherwise the + <seealso marker="erlang#system_info_cpu_topology_detected">automatically detected CPU topology</seealso>, + if such exists. If no CPU topology exists, <c>undefined</c> is returned.</p> - <p><c>node</c> refers to NUMA (non-uniform memory access) - nodes, and <c>thread</c> refers to hardware threads - (e.g. Intels hyper-threads).</p> - <p>A level in the <c><anno>CpuTopology</anno></c> term can be omitted if - only one entry exists and the <c><anno>InfoList</anno></c> is empty. - </p> + <p><c>node</c> refers to Non-Uniform Memory Access (NUMA) + nodes. <c>thread</c> refers to hardware threads + (for example, Intel hyper-threads).</p> + <p>A level in term <c><anno>CpuTopology</anno></c> can be + omitted if only one entry exists and + <c><anno>InfoList</anno></c> is empty.</p> <p><c>thread</c> can only be a sub level to <c>core</c>. - <c>core</c> can be a sub level to either <c>processor</c> - or <c>node</c>. <c>processor</c> can either be on the + <c>core</c> can be a sub level to <c>processor</c> + or <c>node</c>. <c>processor</c> can be on the top level or a sub level to <c>node</c>. <c>node</c> - can either be on the top level or a sub level to + can be on the top level or a sub level to <c>processor</c>. That is, NUMA nodes can be processor internal or processor external. A CPU topology can consist of a mix of processor internal and external - NUMA nodes, as long as each logical CPU belongs to one - and only one NUMA node. Cache hierarchy is not part of - the <c><anno>CpuTopology</anno></c> type yet, but will be in the - future. Other things may also make it into the CPU - topology in the future. In other words, expect the - <c><anno>CpuTopology</anno></c> type to change. - </p> - </item> - <tag><marker id="system_info_cpu_topology_defined"><c>{cpu_topology, defined}</c></marker></tag> - <item> - <p>Returns the user defined <c><anno>CpuTopology</anno></c>. For more - information see the documentation of - the <c>erl</c> <seealso marker="erts:erl#+sct">+sct</seealso> command - line flag, and the documentation of the - <seealso marker="#system_info_cpu_topology">cpu_topology</seealso> - argument. - </p> - </item> - <tag><marker id="system_info_cpu_topology_detected"><c>{cpu_topology, detected}</c></marker></tag> - <item> - <p>Returns the automatically detected <c><anno>CpuTopology</anno></c>. The - emulator currently only detects the CPU topology on some newer - Linux, Solaris, FreeBSD, and Windows systems. On Windows system with - more than 32 logical processors the CPU topology is not detected. - </p> - <p>For more information see the documentation of the - <seealso marker="#system_info_cpu_topology">cpu_topology</seealso> - argument. - </p> + NUMA nodes, as long as each logical CPU belongs to + <em>one</em> NUMA node. Cache hierarchy is not part of + the <c><anno>CpuTopology</anno></c> type, but will be in a + future release. Other things can also make it into the CPU + topology in a future release. In other words, expect the + <c><anno>CpuTopology</anno></c> type to change.</p> + </item> + <tag><c>{cpu_topology, defined}</c></tag> + <item> + <marker id="system_info_cpu_topology_defined"></marker> + <p>Returns the user-defined <c><anno>CpuTopology</anno></c>. + For more information, see command-line flag + <seealso marker="erts:erl#+sct">+sct</seealso> in + <c>erl(1)</c> and argument + <seealso marker="#system_info_cpu_topology">cpu_topology</seealso>.</p> + </item> + <tag><c>{cpu_topology, detected}</c></tag> + <item> + <marker id="system_info_cpu_topology_detected"></marker> + <p>Returns the automatically detected + <c><anno>CpuTopology</anno>y</c>. The + emulator detects the CPU topology on some newer + Linux, Solaris, FreeBSD, and Windows systems. + On Windows system with more than 32 logical processors, + the CPU topology is not detected.</p> + <p>For more information, see argument + <seealso marker="#system_info_cpu_topology">cpu_topology</seealso>.</p> </item> <tag><c>{cpu_topology, used}</c></tag> <item> - <p>Returns the <c><anno>CpuTopology</anno></c> which is used by the - emulator. For more information see the - documentation of the - <seealso marker="#system_info_cpu_topology">cpu_topology</seealso> - argument. - </p> + <p>Returns <c><anno>CpuTopology</anno></c> used by the emulator. + For more information, see argument + <seealso marker="#system_info_cpu_topology">cpu_topology</seealso>.</p> </item> </taglist> </desc> </func> + <func> <name name="system_info" arity="1" clause_i="6"/> <name name="system_info" arity="1" clause_i="7"/> @@ -6224,7 +6727,7 @@ ok <name name="system_info" arity="1" clause_i="65"/> <name name="system_info" arity="1" clause_i="66"/> <name name="system_info" arity="1" clause_i="67"/> - <fsummary>Information about the system</fsummary> + <fsummary>Information about the system.</fsummary> <desc> <p>Returns various information about the current system (emulator) as specified by <c><anno>Item</anno></c>:</p> @@ -6241,8 +6744,7 @@ ok Other possible return values are <c>debug</c>, <c>purify</c>, <c>quantify</c>, <c>purecov</c>, <c>gcov</c>, <c>valgrind</c>, <c>gprof</c>, and <c>lcnt</c>. Possible return values - may be added and/or removed at any time without prior notice. - </p> + can be added or removed at any time without prior notice.</p> </item> <tag><c>c_compiler_used</c></tag> <item> @@ -6250,26 +6752,25 @@ ok compiling the runtime system. The first element is an atom describing the name of the compiler, or <c>undefined</c> if unknown. The second element is a term describing the - version of the compiler, or <c>undefined</c> if unknown. - </p> + version of the compiler, or <c>undefined</c> if unknown.</p> </item> <tag><c>check_io</c></tag> <item> <p>Returns a list containing miscellaneous information - regarding the emulators internal I/O checking. Note, - the content of the returned list may vary between - platforms and over time. The only thing guaranteed is + about the emulators internal I/O checking. Notice that + the content of the returned list can vary between + platforms and over time. It is only guaranteed that a list is returned.</p> </item> <tag><c>compat_rel</c></tag> <item> <p>Returns the compatibility mode of the local node as an integer. The integer returned represents the - Erlang/OTP release which the current emulator has been + Erlang/OTP release that the current emulator has been set to be backward compatible with. The compatibility - mode can be configured at startup by using the command - line flag <c>+R</c>, see - <seealso marker="erts:erl#compat_rel">erl(1)</seealso>.</p> + mode can be configured at startup by using command-line flag + <seealso marker="erts:erl#compat_rel">+R</seealso> in + <c>erl(1)</c>.</p> </item> <tag><c>cpu_topology</c></tag> <item> @@ -6282,144 +6783,150 @@ ok creation of a node is stored in process identifiers, port identifiers, and references. This makes it (to some extent) possible to distinguish between identifiers from - different incarnations of a node. Currently valid - creations are integers in the range 1..3, but this may - (probably will) change in the future. If the node is not - alive, 0 is returned.</p> + different incarnations of a node. The valid + creations are integers in the range 1..3, but this will + probably change in a future release. If the node is not + alive, <c>0</c> is returned.</p> </item> <tag><c>debug_compiled</c></tag> <item> <p>Returns <c>true</c> if the emulator has been debug - compiled; otherwise, <c>false</c>. - </p> + compiled, otherwise <c>false</c>.</p> </item> - <tag><marker id="system_info_delayed_node_table_gc"><c>delayed_node_table_gc</c></marker></tag> + <tag><c>delayed_node_table_gc</c></tag> <item> - <p>Returns the amount of time in seconds that garbage collection - of an entry in a node table will be delayed. This limit can be set - on startup by passing the - <seealso marker="erts:erl#+zdntgc">+zdntgc</seealso> command line - flag to <c>erl</c>. For more information see the documentation of the + <marker id="system_info_delayed_node_table_gc"></marker> + <p>Returns the amount of time in seconds garbage collection + of an entry in a node table is delayed. This limit can be set + on startup by passing the command line flag + <seealso marker="erts:erl#+zdntgc">+zdntgc</seealso> + to <c>erl</c>. For more information see the documentation of the command line flag.</p> </item> - <tag><marker id="system_info_dirty_cpu_schedulers"><c>dirty_cpu_schedulers</c></marker></tag> + <tag><c>dirty_cpu_schedulers</c></tag> <item> + <marker id="system_info_dirty_cpu_schedulers"></marker> <p>Returns the number of dirty CPU scheduler threads used by the emulator. Dirty CPU schedulers execute CPU-bound - native functions such as NIFs, linked-in driver code, and BIFs - that cannot be managed cleanly by the emulator's normal schedulers. - </p> - <p>The number of dirty CPU scheduler threads is determined at emulator - boot time and cannot be changed after that. The number of dirty CPU - scheduler threads online can however be changed at any time. The number of - dirty CPU schedulers can be set on startup by passing - the <seealso marker="erts:erl#+SDcpu">+SDcpu</seealso> or - <seealso marker="erts:erl#+SDPcpu">+SDPcpu</seealso> command line flags, - see <seealso marker="erts:erl#+SDcpu">erl(1)</seealso>. - </p> - <p><em>Note that the dirty schedulers functionality is experimental</em>, and - that you have to enable support for dirty schedulers when building OTP in - order to try out the functionality.</p> - <p>See also <seealso marker="#system_flag_dirty_cpu_schedulers_online">erlang:system_flag(dirty_cpu_schedulers_online, DirtyCPUSchedulersOnline)</seealso>, + native functions, such as NIFs, linked-in driver code, + and BIFs that cannot be managed cleanly by the normal + emulator schedulers.</p> + <p>The number of dirty CPU scheduler threads is determined + at emulator boot time and cannot be changed after that. + However, the number of dirty CPU scheduler threads online + can be changed at any time. The number of dirty CPU + schedulers can be set at startup by passing + command-line flag + <seealso marker="erts:erl#+SDcpu">+SDcpu</seealso> or + <seealso marker="erts:erl#+SDPcpu">+SDPcpu</seealso> in + <c>erl(1)</c>.</p> + <p>Notice that the dirty schedulers functionality is + experimental. Enable support for dirty schedulers when + building OTP to try out the functionality.</p> + <p>See also + <seealso marker="#system_flag_dirty_cpu_schedulers_online">erlang:system_flag(dirty_cpu_schedulers_online, DirtyCPUSchedulersOnline)</seealso>, <seealso marker="#system_info_dirty_cpu_schedulers_online">erlang:system_info(dirty_cpu_schedulers_online)</seealso>, <seealso marker="#system_info_dirty_io_schedulers">erlang:system_info(dirty_io_schedulers)</seealso>, <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso>, <seealso marker="#system_info_schedulers_online">erlang:system_info(schedulers_online)</seealso>, and <seealso marker="#system_flag_schedulers_online">erlang:system_flag(schedulers_online, SchedulersOnline)</seealso>.</p> </item> - <tag><marker id="system_info_dirty_cpu_schedulers_online"><c>dirty_cpu_schedulers_online</c></marker></tag> - <item> - <p>Returns the number of dirty CPU schedulers online. The return value - satisfies the following relationship: - <c><![CDATA[1 <= DirtyCPUSchedulersOnline <= N]]></c>, where <c>N</c> is - the lesser of the return values of <c>erlang:system_info(dirty_cpu_schedulers)</c> and - <c>erlang:system_info(schedulers_online)</c>. - </p> - <p>The number of dirty CPU schedulers online can be set on startup by passing - the <seealso marker="erts:erl#+SDcpu">+SDcpu</seealso> command line flag, see - <seealso marker="erts:erl#+SDcpu">erl(1)</seealso>. - </p> - <p><em>Note that the dirty schedulers functionality is experimental</em>, and - that you have to enable support for dirty schedulers when building OTP in - order to try out the functionality.</p> + <tag><c>dirty_cpu_schedulers_online</c></tag> + <item> + <marker id="system_info_dirty_cpu_schedulers_online"></marker> + <p>Returns the number of dirty CPU schedulers online. + The return value satisfies + <c><![CDATA[1 <= DirtyCPUSchedulersOnline <= N]]></c>, + where <c>N</c> is the smallest of the return values of + <c>erlang:system_info(dirty_cpu_schedulers)</c> and + <c>erlang:system_info(schedulers_online)</c>.</p> + <p>The number of dirty CPU schedulers online can be set at + startup by passing command-line flag + <seealso marker="erts:erl#+SDcpu">+SDcpu</seealso> in + <c>erl(1)</c>.</p> + <p>Notice that the dirty schedulers functionality is + experimental. Enable support for dirty schedulers when + building OTP to try out the functionality.</p> <p>For more information, see <seealso marker="#system_info_dirty_cpu_schedulers">erlang:system_info(dirty_cpu_schedulers)</seealso>, <seealso marker="#system_info_dirty_io_schedulers">erlang:system_info(dirty_io_schedulers)</seealso>, <seealso marker="#system_info_schedulers_online">erlang:system_info(schedulers_online)</seealso>, and - <seealso marker="#system_flag_dirty_cpu_schedulers_online">erlang:system_flag(dirty_cpu_schedulers_online, DirtyCPUSchedulersOnline)</seealso>. - </p> - </item> - <tag><marker id="system_info_dirty_io_schedulers"><c>dirty_io_schedulers</c></marker></tag> - <item> - <p>Returns the number of dirty I/O schedulers as an integer. Dirty I/O schedulers - execute I/O-bound native functions such as NIFs and linked-in driver code that - cannot be managed cleanly by the emulator's normal schedulers. - </p> - <p>This value can be set on startup by passing - the <seealso marker="erts:erl#+SDio">+SDio</seealso> command line flag, see - <seealso marker="erts:erl#+SDio">erl(1)</seealso>. - </p> - <p><em>Note that the dirty schedulers functionality is experimental</em>, and - that you have to enable support for dirty schedulers when building OTP in - order to try out the functionality.</p> + <seealso marker="#system_flag_dirty_cpu_schedulers_online">erlang:system_flag(dirty_cpu_schedulers_online, DirtyCPUSchedulersOnline)</seealso>.</p> + </item> + <tag><c>dirty_io_schedulers</c></tag> + <item> + <marker id="system_info_dirty_io_schedulers"></marker> + <p>Returns the number of dirty I/O schedulers as an integer. + Dirty I/O schedulers execute I/O-bound native functions, + such as NIFs and linked-in driver code, which cannot be + managed cleanly by the normal emulator schedulers.</p> + <p>This value can be set at startup by passing command-line + argument <seealso marker="erts:erl#+SDio">+SDio</seealso> + in <c>erl(1)</c>.</p> + <p>Notice that the dirty schedulers functionality is + experimental. Enable support for dirty schedulers when + building OTP to try out the functionality.</p> <p>For more information, see <seealso marker="#system_info_dirty_cpu_schedulers">erlang:system_info(dirty_cpu_schedulers)</seealso>, <seealso marker="#system_info_dirty_cpu_schedulers_online">erlang:system_info(dirty_cpu_schedulers_online)</seealso>, and - <seealso marker="#system_flag_dirty_cpu_schedulers_online">erlang:system_flag(dirty_cpu_schedulers_online, DirtyCPUSchedulersOnline)</seealso>. - </p> + <seealso marker="#system_flag_dirty_cpu_schedulers_online">erlang:system_flag(dirty_cpu_schedulers_online, DirtyCPUSchedulersOnline)</seealso>.</p> </item> <tag><c>dist</c></tag> <item> <p>Returns a binary containing a string of distribution information formatted as in Erlang crash dumps. For more - information see the <seealso marker="erts:crash_dump">"How to interpret the Erlang crash dumps"</seealso> - chapter in the ERTS User's Guide.</p> + information, see Section + <seealso marker="erts:crash_dump">"How to interpret the Erlang crash dumps"</seealso> + in the User's Guide.</p> </item> - <tag><marker id="system_info_dist_buf_busy_limit"><c>dist_buf_busy_limit</c></marker></tag> + <tag><c>dist_buf_busy_limit</c></tag> <item> + <marker id="system_info_dist_buf_busy_limit"></marker> <p>Returns the value of the distribution buffer busy limit - in bytes. This limit can be set on startup by passing the - <seealso marker="erts:erl#+zdbbl">+zdbbl</seealso> command line - flag to <c>erl</c>.</p> + in bytes. This limit can be set at startup by passing + command-line flag + <seealso marker="erts:erl#+zdbbl">+zdbbl</seealso> + to <c>erl</c>.</p> </item> <tag><c>dist_ctrl</c></tag> <item> <p>Returns a list of tuples - <c>{Node, ControllingEntity}</c>, one entry for each - connected remote node. The <c><anno>Node</anno></c> is the name of the - node and the <c><anno>ControllingEntity</anno></c> is the port or pid - responsible for the communication to that node. More - specifically, the <c><anno>ControllingEntity</anno></c> for nodes - connected via TCP/IP (the normal case) is the socket - actually used in communication with the specific node.</p> + <c>{<anno>Node</anno>, <anno>ControllingEntity</anno>}</c>, + one entry for each connected remote node. + <c><anno>Node</anno></c> is the node name + and <c><anno>ControllingEntity</anno></c> is the port or process + identifier responsible for the communication to that node. + More specifically, <c><anno>ControllingEntity</anno></c> for + nodes connected through TCP/IP (the normal case) is the socket + used in communication with the specific node.</p> </item> <tag><c>driver_version</c></tag> <item> - <p>Returns a string containing the erlang driver version - used by the runtime system. It will be on the form + <p>Returns a string containing the Erlang driver version + used by the runtime system. It has the form <seealso marker="erts:erl_driver#version_management">"<major ver>.<minor ver>"</seealso>.</p> </item> <tag><c>dynamic_trace</c></tag> <item> <p>Returns an atom describing the dynamic trace framework - compiled into the virtual machine. It can currently be either - <c>dtrace</c>, <c>systemtap</c> or <c>none</c>. For a - commercial or standard build, this is always <c>none</c>, - the other return values indicate a custom configuration - (e.g. <c>./configure --with-dynamic-trace=dtrace</c>). See - the <seealso marker="runtime_tools:dyntrace">dyntrace - </seealso> manual page and the + compiled into the virtual machine. It can be + <c>dtrace</c>, <c>systemtap</c>, or <c>none</c>. For a + commercial or standard build, it is always <c>none</c>. + The other return values indicate a custom configuration + (for example, <c>./configure --with-dynamic-trace=dtrace</c>). + For more information about dynamic tracing, see the + <seealso marker="runtime_tools:dyntrace">dyntrace</seealso> + manual page and the <c>README.dtrace</c>/<c>README.systemtap</c> files in the - Erlang source code top directory for more information - about dynamic tracing.</p> + Erlang source code top directory.</p> </item> <tag><c>dynamic_trace_probes</c></tag> <item> - <p>Returns a <c>boolean()</c> indicating if dynamic trace probes - (either dtrace or systemtap) are built into the - emulator. This can only be <c>true</c> if the virtual - machine was built for dynamic tracing - (i.e. <c>system_info(dynamic_trace)</c> returns + <p>Returns a <c>boolean()</c> indicating if dynamic trace + probes (<c>dtrace</c> or <c>systemtap</c>) are built into + the emulator. This can only be <c>true</c> if the Virtual + Machine was built for dynamic tracing (that is, + <c>system_info(dynamic_trace)</c> returns <c>dtrace</c> or <c>systemtap</c>).</p> </item> <tag><marker id="system_info_end_time"/><c>end_time</c></tag> @@ -6433,42 +6940,43 @@ ok <tag><c>elib_malloc</c></tag> <item> <p>This option will be removed in a future release. - The return value will always be <c>false</c> since - the elib_malloc allocator has been removed.</p> + The return value will always be <c>false</c>, as the + <c>elib_malloc</c> allocator has been removed.</p> </item> - <tag><marker id="system_info_eager_check_io"><c>eager_check_io</c></marker></tag> + <tag><marker id="system_info_eager_check_io"/><c>eager_check_io</c></tag> <item> <p> - Returns the value of the <c>erl</c> - <seealso marker="erl#+secio">+secio</seealso> command line - flag which is either <c>true</c> or <c>false</c>. See the + Returns the value of the <c>erl</c> command line flag + <seealso marker="erl#+secio">+secio</seealso> + which is either <c>true</c> or <c>false</c>. See the documentation of the command line flag for information about the different values. </p> </item> <tag><c>ets_limit</c></tag> <item> - <p>Returns the maximum number of ETS tables allowed. This limit - can be increased on startup by passing the <seealso - marker="erts:erl#+e">+e</seealso> command line flag to - <c>erl</c> or by setting the environment variable - <c>ERL_MAX_ETS_TABLES</c> before starting the Erlang runtime - system.</p> + <p>Returns the maximum number of ETS tables allowed. This + limit can be increased at startup by passing + command-line flag + <seealso marker="erts:erl#+e">+e</seealso> to + <c>erl(1)</c> or by setting environment variable + <c>ERL_MAX_ETS_TABLES</c> before starting the Erlang + runtime system.</p> </item> <tag><c>fullsweep_after</c></tag> <item> - <p>Returns <c>{fullsweep_after, integer() >= 0}</c> which is the - <c>fullsweep_after</c> garbage collection setting used - by default. For more information see - <c>garbage_collection</c> described below.</p> + <p>Returns <c>{fullsweep_after, integer() >= 0}</c>, which is + the <c>fullsweep_after</c> garbage collection setting used + by default. For more information, see + <c>garbage_collection</c> described in the following.</p> </item> <tag><c>garbage_collection</c></tag> <item> <p>Returns a list describing the default garbage collection settings. A process spawned on the local node by a - <c>spawn</c> or <c>spawn_link</c> will use these + <c>spawn</c> or <c>spawn_link</c> uses these garbage collection settings. The default settings can be - changed by use of + changed by using <seealso marker="#system_flag/2">system_flag/2</seealso>. <seealso marker="#spawn_opt/4">spawn_opt/4</seealso> can spawn a process that does not use the default @@ -6482,8 +6990,8 @@ ok </item> <tag><c>heap_type</c></tag> <item> - <p>Returns the heap type used by the current emulator. - Currently only the following heap type exists:</p> + <p>Returns the heap type used by the current emulator. One + heap type exists:</p> <taglist> <tag><c>private</c></tag> <item> @@ -6498,51 +7006,51 @@ ok <item> <p>Returns a binary containing a string of miscellaneous system information formatted as in Erlang crash dumps. - For more information see the - <seealso marker="erts:crash_dump">"How to interpret the Erlang crash dumps"</seealso> chapter in the ERTS - User's Guide.</p> + For more information, see Section + <seealso marker="erts:crash_dump">"How to interpret the Erlang crash dumps"</seealso> + in the User's Guide.</p> </item> <tag><c>kernel_poll</c></tag> <item> <p>Returns <c>true</c> if the emulator uses some kind of - kernel-poll implementation; otherwise, <c>false</c>.</p> + kernel-poll implementation, otherwise <c>false</c>.</p> </item> <tag><c>loaded</c></tag> <item> <p>Returns a binary containing a string of loaded module information formatted as in Erlang crash dumps. For more - information see the <seealso marker="erts:crash_dump">"How to interpret the Erlang crash dumps"</seealso> chapter - in the ERTS User's Guide.</p> + information, see Section + <seealso marker="erts:crash_dump">"How to interpret the Erlang crash dumps"</seealso> + in the User's Guide.</p> </item> - <tag><marker id="logical_processors"><c>logical_processors</c></marker></tag> + <tag><c>logical_processors</c></tag> <item> + <marker id="logical_processors"></marker> <p>Returns the detected number of logical processors configured - on the system. The return value is either an integer, or - the atom <c>unknown</c> if the emulator wasn't able to - detect logical processors configured. - </p> + in the system. The return value is either an integer, or + the atom <c>unknown</c> if the emulator cannot + detect the configured logical processors.</p> </item> - <tag><marker id="logical_processors_available"><c>logical_processors_available</c></marker></tag> + <tag><c>logical_processors_available</c></tag> <item> - <p>Returns the detected number of logical processors available to - the Erlang runtime system. The return value is either an - integer, or the atom <c>unknown</c> if the emulator wasn't - able to detect logical processors available. The number - of logical processors available is less than or equal to - the number of <seealso marker="#logical_processors_online">logical - processors online</seealso>. - </p> + <marker id="logical_processors_available"></marker> + <p>Returns the detected number of logical processors available + to the Erlang runtime system. The return value is either an + integer, or the atom <c>unknown</c> if the emulator + cannot detect the available logical processors. The number + of available logical processors is less than or equal to + the number of + <seealso marker="#logical_processors_online">logical processors online</seealso>.</p> </item> - <tag><marker id="logical_processors_online"><c>logical_processors_online</c></marker></tag> + <tag><c>logical_processors_online</c></tag> <item> + <marker id="logical_processors_online"></marker> <p>Returns the detected number of logical processors online on the system. The return value is either an integer, - or the atom <c>unknown</c> if the emulator wasn't able to + or the atom <c>unknown</c> if the emulator cannot detect logical processors online. The number of logical processors online is less than or equal to the number of - <seealso marker="#logical_processors">logical processors - configured</seealso>. - </p> + <seealso marker="#logical_processors">logical processors configured</seealso>.</p> </item> <tag><c>machine</c></tag> <item> @@ -6550,27 +7058,30 @@ ok </item> <tag><c>min_heap_size</c></tag> <item> - <p>Returns <c>{min_heap_size, <anno>MinHeapSize</anno>}</c> where <c><anno>MinHeapSize</anno></c> is the current system wide - minimum heap size for spawned processes.</p> + <p>Returns <c>{min_heap_size, <anno>MinHeapSize</anno>}</c>, + where <c><anno>MinHeapSize</anno></c> is the current + system-wide minimum heap size for spawned processes.</p> </item> <tag><c>min_bin_vheap_size</c></tag> <item> - <p>Returns <c>{min_bin_vheap_size, <anno>MinBinVHeapSize</anno>}</c> where <c><anno>MinBinVHeapSize</anno></c> is the current system wide + <p>Returns <c>{min_bin_vheap_size, + <anno>MinBinVHeapSize</anno>}</c>, where + <c><anno>MinBinVHeapSize</anno></c> is the current system-wide minimum binary virtual heap size for spawned processes.</p> </item> <tag><c>modified_timing_level</c></tag> <item> - <p>Returns the modified timing level (an integer) if - modified timing has been enabled; otherwise, - <c>undefined</c>. See the <c>+T</c> command line flag - in the documentation of the - <seealso marker="erts:erl#+T">erl(1)</seealso> - command for more information on modified timing.</p> + <p>Returns the modified timing-level (an integer) if + modified timing is enabled, otherwise, <c>undefined</c>. + For more information about modified timing, see + command-line flag + <seealso marker="erts:erl#+T">+T</seealso> + in <c>erl(1)</c></p> </item> - <tag><marker id="system_info_multi_scheduling"><c>multi_scheduling</c></marker></tag> + <tag><c>multi_scheduling</c></tag> <item> - <p>Returns <c>disabled</c>, <c>blocked</c>, or <c>enabled</c>. - A description of the return values:</p> + <marker id="system_info_multi_scheduling"></marker> + <p>Returns <c>disabled</c>, <c>blocked</c>, or <c>enabled</c>:</p> <taglist> <tag><c>disabled</c></tag> <item> @@ -6581,93 +7092,99 @@ ok <tag><c>blocked</c></tag> <item> <p>The emulator has more than one scheduler thread, - but all scheduler threads but one have been blocked, - i.e., only one scheduler thread will schedule - Erlang processes and execute Erlang code.</p> + but all scheduler threads except one are blocked, + that is, only one scheduler thread schedules + Erlang processes and executes Erlang code.</p> </item> <tag><c>enabled</c></tag> <item> <p>The emulator has more than one scheduler thread, - and no scheduler threads have been blocked, i.e., - all available scheduler threads will schedule + and no scheduler threads are blocked, that is, + all available scheduler threads schedule Erlang processes and execute Erlang code.</p> </item> </taglist> - <p>See also <seealso marker="#system_flag_multi_scheduling">erlang:system_flag(multi_scheduling, BlockState)</seealso>, - <seealso marker="#system_info_multi_scheduling_blockers">erlang:system_info(multi_scheduling_blockers)</seealso>, and + <p>See also + <seealso marker="#system_flag_multi_scheduling">erlang:system_flag(multi_scheduling, BlockState)</seealso>, + <seealso marker="#system_info_multi_scheduling_blockers">erlang:system_info(multi_scheduling_blockers)</seealso>, + and <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso>.</p> </item> - <tag><marker id="system_info_multi_scheduling_blockers"><c>multi_scheduling_blockers</c></marker></tag> + <tag><c>multi_scheduling_blockers</c></tag> <item> - <p>Returns a list of <c><anno>PID</anno></c>s when multi-scheduling - is blocked; otherwise, the empty list. The <c><anno>PID</anno></c>s - in the list is <c><anno>PID</anno></c>s of the processes currently - blocking multi-scheduling. A <c><anno>PID</anno></c> will only be - present once in the list, even if the corresponding + <marker id="system_info_multi_scheduling_blockers"></marker> + <p>Returns a list of <c><anno>Pid</anno></c>s when + multi-scheduling is blocked, otherwise the empty list is + returned. The <c><anno>Pid</anno></c>s in the list + represent all the processes currently + blocking multi-scheduling. A <c><anno>Pid</anno></c> occurs + only once in the list, even if the corresponding process has blocked multiple times.</p> - <p>See also <seealso marker="#system_flag_multi_scheduling">erlang:system_flag(multi_scheduling, BlockState)</seealso>, - <seealso marker="#system_info_multi_scheduling">erlang:system_info(multi_scheduling)</seealso>, and + <p>See also + <seealso marker="#system_flag_multi_scheduling">erlang:system_flag(multi_scheduling, BlockState)</seealso>, + <seealso marker="#system_info_multi_scheduling">erlang:system_info(multi_scheduling)</seealso>, + and <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso>.</p> </item> <tag><c>nif_version</c></tag> <item> - <p>Returns a string containing the erlang NIF version - used by the runtime system. It will be on the form "<major ver>.<minor ver>".</p> + <p>Returns a string containing the version of the Erlang NIF interface + used by the runtime system. It is on the form + "<major ver>.<minor ver>".</p> </item> - <tag><marker id="system_info_otp_release"><c>otp_release</c></marker></tag> + <tag><c>otp_release</c></tag> <item> + <marker id="system_info_otp_release"></marker> <p>Returns a string containing the OTP release number of the - OTP release that the currently executing ERTS application is + OTP release that the currently executing <c>ERTS</c> application is part of.</p> - <p>As of OTP release 17, the OTP release number corresponds to - the major OTP version number. There is no - <c>erlang:system_info()</c> argument giving the exact OTP - version. This since the exact OTP version in the general case - is hard to determine. For more information see - <seealso marker="doc/system_principles:versions">the - documentation of versions in the system principles - guide</seealso>.</p> + <p>As from OTP 17, the OTP release number corresponds to + the major OTP version number. No + <c>erlang:system_info()</c> argument gives the exact OTP + version. This is because the exact OTP version in the general case + is difficult to determine. For more information, see the description + of versions in <seealso marker="doc/system_principles:versions"> + System principles</seealso> in System Documentation.</p> </item> - <tag><marker id="system_info_os_monotonic_time_source"><c>os_monotonic_time_source</c></marker></tag> + <tag><marker id="system_info_os_monotonic_time_source"/><c>os_monotonic_time_source</c></tag> <item> <p>Returns a list containing information about the source of <seealso marker="erts:time_correction#OS_Monotonic_Time">OS monotonic time</seealso> that is used by the runtime system.</p> - <p>In case <c>[]</c> is returned, no OS monotonic time is + <p>If <c>[]</c> is returned, no OS monotonic time is available. The list contains two-tuples with <c>Key</c>s as first element, and <c>Value</c>s as second element. The - order if these tuples is undefined. Currently the following - tuples may be part of the list, but more tuples may be + order of these tuples is undefined. The following + tuples can be part of the list, but more tuples can be introduced in the future:</p> <taglist> <tag><c>{function, Function}</c></tag> - <item><p><c>Function</c> is the name of the funcion + <item><p><c>Function</c> is the name of the function used. This tuple always exist if OS monotonic time is available to the runtime system.</p></item> <tag><c>{clock_id, ClockId}</c></tag> <item><p>This tuple only exist if <c>Function</c> can be used with different clocks. <c>ClockId</c> - corresponds to the clock identifer used when calling + corresponds to the clock identifier used when calling <c>Function</c>.</p></item> <tag><c>{resolution, OsMonotonicTimeResolution}</c></tag> <item><p>Highest possible <seealso marker="time_correction#Time_Resolution">resolution</seealso> of current OS monotonic time source as parts per - second. If no resolution information can be retreived - from the OS, <c>OsMonotonicTimeResolution</c> will be + second. If no resolution information can be retrieved + from the OS, <c>OsMonotonicTimeResolution</c> is set to the resolution of the time unit of <c>Function</c>s return value. That is, the actual - resolution may be lower than + resolution can be lower than <c>OsMonotonicTimeResolution</c>. Also note that the resolution does not say anything about the <seealso marker="time_correction#Time_Accuracy">accuracy</seealso>, - and that the + and whether the <seealso marker="time_correction#Time_Precision">precision</seealso> - might not align with the resolution. You do, - however, know that the precision won't be - better than + do align with the resolution. You do, + however, know that the precision is not better than <c>OsMonotonicTimeResolution</c>.</p></item> <tag><c>{extended, Extended}</c></tag> @@ -6692,15 +7209,15 @@ ok <seealso marker="#type_time_unit">time unit</seealso>.</p></item> </taglist> </item> - <tag><marker id="system_info_os_system_time_source"><c>os_system_time_source</c></marker></tag> + <tag><marker id="system_info_os_system_time_source"/><c>os_system_time_source</c></tag> <item> <p>Returns a list containing information about the source of <seealso marker="erts:time_correction#OS_System_Time">OS system time</seealso> that is used by the runtime system.</p> <p>The list contains two-tuples with <c>Key</c>s as first element, and <c>Value</c>s as second element. The - order if these tuples is undefined. Currently the following - tuples may be part of the list, but more tuples may be + order if these tuples is undefined. The following + tuples can be part of the list, but more tuples can be introduced in the future:</p> <taglist> <tag><c>{function, Function}</c></tag> @@ -6710,26 +7227,25 @@ ok <tag><c>{clock_id, ClockId}</c></tag> <item><p>This tuple only exist if <c>Function</c> can be used with different clocks. <c>ClockId</c> - corresponds to the clock identifer used when calling + corresponds to the clock identifier used when calling <c>Function</c>.</p></item> <tag><c>{resolution, OsSystemTimeResolution}</c></tag> <item><p>Highest possible <seealso marker="time_correction#Time_Resolution">resolution</seealso> of current OS system time source as parts per - second. If no resolution information can be retreived - from the OS, <c>OsSystemTimeResolution</c> will be + second. If no resolution information can be retrieved + from the OS, <c>OsSystemTimeResolution</c> is set to the resolution of the time unit of <c>Function</c>s return value. That is, the actual resolution may be lower than <c>OsSystemTimeResolution</c>. Also note that the resolution does not say anything about the <seealso marker="time_correction#Time_Accuracy">accuracy</seealso>, - and that the + and whether the <seealso marker="time_correction#Time_Precision">precision</seealso> - might not align with the resolution. You do, - however, know that the precision won't be - better than + do align with the resolution. You do, + however, know that the precision is not better than <c>OsSystemTimeResolution</c>.</p></item> <tag><c>{parallel, Parallel}</c></tag> @@ -6745,130 +7261,136 @@ ok <seealso marker="#type_time_unit">time unit</seealso>.</p></item> </taglist> </item> - <tag><marker id="system_info_port_parallelism"><c>port_parallelism</c></marker></tag> - <item><p>Returns the default port parallelism scheduling hint used. - For more information see the - <seealso marker="erl#+spp">+spp</seealso> command line argument - of <seealso marker="erl">erl(1)</seealso>.</p></item> + <tag><c>port_parallelism</c></tag> + <item> + <marker id="system_info_port_parallelism"></marker> + <p>Returns the default port parallelism scheduling hint used. + For more information, see command-line argument + <seealso marker="erl#+spp">+spp</seealso> in <c>erl(1)</c>.</p></item> <tag><marker id="system_info_port_count"/><c>port_count</c></tag> <item> - <p>Returns the number of ports currently existing at - the local node as an integer. The same value as - <c>length(erlang:ports())</c> returns, but more efficient.</p> + <p>Returns the number of ports currently existing at the + local node. The value is given as an integer. This is + the same value as returned by + <c>length(erlang:ports())</c>, but more efficient.</p> </item> - <tag><marker id="system_info_port_limit"><c>port_limit</c></marker></tag> + <tag><c>port_limit</c></tag> <item> + <marker id="system_info_port_limit"></marker> <p>Returns the maximum number of simultaneously existing - ports at the local node as an integer. This limit - can be configured at startup by using the - <seealso marker="erl#+Q">+Q</seealso> - command line flag of - <seealso marker="erl">erl(1)</seealso>.</p> + ports at the local node as an integer. This limit can be + configured at startup by using command-line flag + <seealso marker="erl#+Q">+Q</seealso> in <c>erl(1)</c>.</p> </item> <tag><marker id="system_info_process_count"/><c>process_count</c></tag> <item> - <p>Returns the number of processes currently existing at - the local node as an integer. The same value as - <c>length(processes())</c> returns, but more efficient.</p> + <p>Returns the number of processes currently existing at the + local node. The value is given as an integer. This is + the same value as returned by + <c>length(processes())</c>, but more efficient.</p> </item> - <tag><marker id="system_info_process_limit"><c>process_limit</c></marker></tag> + <tag><c>process_limit</c></tag> <item> + <marker id="system_info_process_limit"></marker> <p>Returns the maximum number of simultaneously existing - processes at the local node as an integer. This limit - can be configured at startup by using the - <seealso marker="erl#+P">+P</seealso> - command line flag of - <seealso marker="erl">erl(1)</seealso>.</p> + processes at the local node. The value is given as an + integer. This limit can be configured at startup by using + command-line flag <seealso marker="erl#+P">+P</seealso> + in <c>erl(1)</c>.</p> </item> <tag><c>procs</c></tag> <item> <p>Returns a binary containing a string of process and port information formatted as in Erlang crash dumps. For more - information see the <seealso marker="erts:crash_dump">"How to interpret the Erlang crash dumps"</seealso> chapter - in the ERTS User's Guide.</p> + information, see Section + <seealso marker="erts:crash_dump">"How to interpret the Erlang crash dumps"</seealso> + in the User's Guide.</p> </item> - <tag><marker id="system_info_scheduler_bind_type"><c>scheduler_bind_type</c></marker></tag> + <tag><c>scheduler_bind_type</c></tag> <item> - <p>Returns information on how user has requested + <marker id="system_info_scheduler_bind_type"></marker> + <p>Returns information about how the user has requested schedulers to be bound or not bound.</p> - <p><em>NOTE:</em> Even though user has requested - schedulers to be bound, they might have silently failed - to bind. In order to inspect actual scheduler bindings call - <seealso marker="#system_info_scheduler_bindings">erlang:system_info(scheduler_bindings)</seealso>. - </p> - <p>For more information, see - the <c>erl</c> <seealso marker="erts:erl#+sbt">+sbt</seealso> - command line argument, and - <seealso marker="#system_info_scheduler_bindings">erlang:system_info(scheduler_bindings)</seealso>. - </p> - </item> - <tag><marker id="system_info_scheduler_bindings"><c>scheduler_bindings</c></marker></tag> - <item> - <p>Returns information on currently used scheduler + <p>Notice that even though a user has requested + schedulers to be bound, they can silently have failed + to bind. To inspect the scheduler bindings, call + <seealso marker="#system_info_scheduler_bindings">erlang:system_info(scheduler_bindings)</seealso>.</p> + <p>For more information, see command-line argument + <seealso marker="erts:erl#+sbt">+sbt</seealso> + in <c>erl(1)</c> and + <seealso marker="#system_info_scheduler_bindings">erlang:system_info(scheduler_bindings)</seealso>.</p> + </item> + <tag><c>scheduler_bindings</c></tag> + <item> + <marker id="system_info_scheduler_bindings"></marker> + <p>Returns information about the currently used scheduler bindings.</p> <p>A tuple of a size equal to - <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso> is returned. The elements of the tuple are integers + <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso> + is returned. The tuple elements are integers or the atom <c>unbound</c>. Logical processor identifiers are represented as integers. The <c>N</c>th element of the tuple equals the current binding for the scheduler with the scheduler identifier equal to - <c>N</c>. E.g., if the schedulers have been bound, + <c>N</c>. For example, if the schedulers are bound, <c>element(erlang:system_info(scheduler_id), - erlang:system_info(scheduler_bindings))</c> will return + erlang:system_info(scheduler_bindings))</c> returns the identifier of the logical processor that the calling - process is executing on. - </p> - <p>Note that only schedulers online can be bound to logical + process is executing on.</p> + <p>Notice that only schedulers online can be bound to logical processors.</p> - <p>For more information, see - the <c>erl</c> <seealso marker="erts:erl#+sbt">+sbt</seealso> - command line argument, + <p>For more information, see command-line argument + <seealso marker="erts:erl#+sbt">+sbt</seealso> + in <c>erl(1)</c> and <seealso marker="#system_info_schedulers_online">erlang:system_info(schedulers_online)</seealso>. </p> </item> - <tag><marker id="system_info_scheduler_id"><c>scheduler_id</c></marker></tag> + <tag><c>scheduler_id</c></tag> <item> - <p>Returns the scheduler id (<c>SchedulerId</c>) of the + <marker id="system_info_scheduler_id"></marker> + <p>Returns the scheduler ID (<c>SchedulerId</c>) of the scheduler thread that the calling process is executing - on. <c><anno>SchedulerId</anno></c> is a positive integer; where - <c><![CDATA[1 <= SchedulerId <= erlang:system_info(schedulers)]]></c>. See also + on. <c><anno>SchedulerId</anno></c> is a positive integer, + where + <c><![CDATA[1 <= SchedulerId <= erlang:system_info(schedulers)]]></c>. + See also <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso>.</p> </item> - <tag><marker id="system_info_schedulers"><c>schedulers</c></marker></tag> + <tag><c>schedulers</c></tag> <item> + <marker id="system_info_schedulers"></marker> <p>Returns the number of scheduler threads used by the emulator. Scheduler threads online schedules Erlang processes and Erlang ports, and execute Erlang code - and Erlang linked in driver code.</p> + and Erlang linked-in driver code.</p> <p>The number of scheduler threads is determined at - emulator boot time and cannot be changed after - that. The amount of schedulers online can - however be changed at any time.</p> - <p>See also <seealso marker="#system_flag_schedulers_online">erlang:system_flag(schedulers_online, SchedulersOnline)</seealso>, + emulator boot time and cannot be changed later. + However, the number of schedulers online can + be changed at any time.</p> + <p>See also + <seealso marker="#system_flag_schedulers_online">erlang:system_flag(schedulers_online, SchedulersOnline)</seealso>, <seealso marker="#system_info_schedulers_online">erlang:system_info(schedulers_online)</seealso>, <seealso marker="#system_info_scheduler_id">erlang:system_info(scheduler_id)</seealso>, <seealso marker="#system_flag_multi_scheduling">erlang:system_flag(multi_scheduling, BlockState)</seealso>, - <seealso marker="#system_info_multi_scheduling">erlang:system_info(multi_scheduling)</seealso>, and - and <seealso marker="#system_info_multi_scheduling_blockers">erlang:system_info(multi_scheduling_blockers)</seealso>.</p> + <seealso marker="#system_info_multi_scheduling">erlang:system_info(multi_scheduling)</seealso>, + and + <seealso marker="#system_info_multi_scheduling_blockers">erlang:system_info(multi_scheduling_blockers)</seealso>.</p> </item> - <tag><marker id="system_info_schedulers_online"><c>schedulers_online</c></marker></tag> + <tag><c>schedulers_online</c></tag> <item> - <p>Returns the amount of schedulers online. The scheduler - identifiers of schedulers online satisfy the following - relationship: - <c><![CDATA[1 <= SchedulerId <= erlang:system_info(schedulers_online)]]></c>. - </p> + <marker id="system_info_schedulers_online"></marker> + <p>Returns the number of schedulers online. The scheduler + identifiers of schedulers online satisfy the relationship + <c><![CDATA[1 <= SchedulerId <= erlang:system_info(schedulers_online)]]></c>.</p> <p>For more information, see - <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso>, + <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso> and - <seealso marker="#system_flag_schedulers_online">erlang:system_flag(schedulers_online, SchedulersOnline)</seealso>. - </p> <name name="system_info" arity="1" clause_i="49"/> - + <seealso marker="#system_flag_schedulers_online">erlang:system_flag(schedulers_online, SchedulersOnline)</seealso>.</p> </item> <tag><c>smp_support</c></tag> <item> <p>Returns <c>true</c> if the emulator has been compiled - with smp support; otherwise, <c>false</c>.</p> + with SMP support, otherwise <c>false</c> is returned.</p> </item> <tag><marker id="system_info_start_time"/><c>start_time</c></tag> <item><p>The <seealso marker="#monotonic_time/0">Erlang monotonic @@ -6880,7 +7402,7 @@ ok <tag><c>system_version</c></tag> <item> <p>Returns a string containing version number and - some important properties such as the number of schedulers.</p> + some important properties, such as the number of schedulers.</p> </item> <tag><c>system_architecture</c></tag> <item> @@ -6890,23 +7412,28 @@ ok <tag><c>threads</c></tag> <item> <p>Returns <c>true</c> if the emulator has been compiled - with thread support; otherwise, <c>false</c> is - returned.</p> + with thread support, otherwise <c>false</c> is returned.</p> </item> - <tag><marker id="system_info_thread_pool_size"><c>thread_pool_size</c></marker></tag> + <tag><c>thread_pool_size</c></tag> <item> + <marker id="system_info_thread_pool_size"></marker> <p>Returns the number of async threads in the async thread pool used for asynchronous driver calls - (<seealso marker="erts:erl_driver#driver_async">driver_async()</seealso>) - as an integer.</p> + (<seealso marker="erts:erl_driver#driver_async">driver_async()</seealso>). + The value is given as an integer.</p> </item> - <tag><marker id="system_info_time_correction"/><c>time_correction</c></tag> - <item><p>Returns a boolean value indicating whether + + <tag><c>time_correction</c></tag> + <item> + <marker id="system_info_time_correction"></marker> + <p>Returns a boolean value indicating whether <seealso marker="time_correction#Time_Correction">time correction</seealso> is enabled or not. </p></item> - <tag><marker id="system_info_time_offset"/><c>time_offset</c></tag> - <item><p>Returns the state of the time offset:</p> + <tag><c>time_offset</c></tag> + <item> + <marker id="system_info_time_offset"></marker> + <p>Returns the state of the time offset:</p> <taglist> <tag><c>preliminary</c></tag> <item><p>The time offset is preliminary, and will be changed @@ -6916,19 +7443,18 @@ ok time warp mode</seealso>.</p></item> <tag><c>final</c></tag> - <item><p>The time offset is final. This - either due to the use of the + <item><p>The time offset is final. This either because <seealso marker="time_correction#No_Time_Warp_Mode">no - time warp mode</seealso>, or due to the time offset having - been finalized when using the + time warp mode</seealso> is used, or because the time + offset have been finalized when <seealso marker="time_correction#Single_Time_Warp_Mode">single - time warp mode</seealso>.</p></item> + time warp mode</seealso> is used.</p></item> <tag><c>volatile</c></tag> - <item><p>The time offset is volatile. That is, it may - change at any time. This due to the + <item><p>The time offset is volatile. That is, it can + change at any time. This is because <seealso marker="time_correction#Multi_Time_Warp_Mode">multi - time warp mode</seealso> being used.</p></item> + time warp mode</seealso> is used.</p></item> </taglist> </item> <tag><marker id="system_info_time_warp_mode"/><c>time_warp_mode</c></tag> @@ -6938,19 +7464,20 @@ ok <taglist> <tag><c>no_time_warp</c></tag> <item><p>The <seealso marker="time_correction#No_Time_Warp_Mode">no - time warp mode</seealso> is being used.</p></item> + time warp mode</seealso> is used.</p></item> <tag><c>single_time_warp</c></tag> <item><p>The <seealso marker="time_correction#Single_Time_Warp_Mode">single - time warp mode</seealso> is being used.</p></item> + time warp mode</seealso> is used.</p></item> <tag><c>multi_time_warp</c></tag> <item><p>The <seealso marker="time_correction#Multi_Time_Warp_Mode">multi - time warp mode</seealso> is being used.</p></item> + time warp mode</seealso> is used.</p></item> </taglist> </item> - <tag><marker id="system_info_tolerant_timeofday"><c>tolerant_timeofday</c></marker></tag> + <tag><c>tolerant_timeofday</c></tag> <item> + <marker id="system_info_tolerant_timeofday"></marker> <p>Returns whether a pre erts-7.0 backwards compatible compensation for sudden changes of system time is <c>enabled</c> or <c>disabled</c>. Such compensation is <c>enabled</c> when the @@ -6961,90 +7488,92 @@ ok </item> <tag><c>trace_control_word</c></tag> <item> - <p>Returns the value of the node's trace control word. - For more information see documentation of the function - <c>get_tcw</c> in "Match Specifications in Erlang", - <seealso marker="erts:match_spec#get_tcw">ERTS User's Guide</seealso>.</p> + <p>Returns the value of the node trace control word. For + more information, see function <c>get_tcw</c> in Section + <seealso marker="erts:match_spec#get_tcw">Match Specifications in Erlang</seealso> in the User's Guide.</p> </item> - <tag><marker id="update_cpu_info"><c>update_cpu_info</c></marker></tag> + <tag><c>update_cpu_info</c></tag> <item> - <p>The runtime system rereads the CPU information available and - updates its internally stored information about the - <seealso marker="#system_info_cpu_topology_detected">detected CPU - topology</seealso> and the amount of logical processors + <marker id="update_cpu_info"></marker> + <p>The runtime system rereads the CPU information available + and updates its internally stored information about the + <seealso marker="#system_info_cpu_topology_detected">detected + CPU topology</seealso> and the number of logical processors <seealso marker="#logical_processors">configured</seealso>, <seealso marker="#logical_processors_online">online</seealso>, and - <seealso marker="#logical_processors_available">available</seealso>. - If the CPU information has changed since the last time it was read, - the atom <c>changed</c> is returned; otherwise, the atom - <c>unchanged</c> is returned. If the CPU information has changed + <seealso marker="#logical_processors_available">available</seealso>.</p> + <p>If the CPU information has changed since the last time + it was read, the atom <c>changed</c> is returned, otherwise + the atom <c>unchanged</c>. If the CPU information has changed, you probably want to - <seealso marker="#system_flag_schedulers_online">adjust the amount - of schedulers online</seealso>. You typically want to have as - many schedulers online as - <seealso marker="#logical_processors_available">logical processors - available</seealso>. - </p> + <seealso marker="#system_flag_schedulers_online">adjust the + number of schedulers online</seealso>. You typically want + to have as many schedulers online as + <seealso marker="#logical_processors_available">logical + processors available</seealso>.</p> </item> - <tag><marker id="system_info_version"><c>version</c></marker></tag> + <tag><c>version</c></tag> <item> + <marker id="system_info_version"></marker> <p>Returns a string containing the version number of the emulator.</p> </item> <tag><c>wordsize</c></tag> <item> - <p>Same as <c>{wordsize, internal}.</c></p> + <p>Same as <c>{wordsize, internal}</c>.</p> </item> <tag><c>{wordsize, internal}</c></tag> <item> <p>Returns the size of Erlang term words in bytes as an - integer, i.e. on a 32-bit architecture 4 is returned, - and on a pure 64-bit architecture 8 is returned. On a + integer, that is, 4 is returned on a 32-bit architecture, + and 8 is returned on a pure 64-bit architecture. On a halfword 64-bit emulator, 4 is returned, as the Erlang - terms are stored using a virtual wordsize of half the - system's wordsize.</p> + terms are stored using a virtual word size of half the + system word size.</p> </item> <tag><c>{wordsize, external}</c></tag> <item> - <p>Returns the true wordsize of the emulator, i.e. the size - of a pointer, in bytes as an integer. On a pure 32-bit - architecture 4 is returned, on both a halfword and pure + <p>Returns the true word size of the emulator, that is, + the size of a pointer. The value is given in bytes + as an integer. On a pure 32-bit architecture, 4 is + returned. On both a half word and on a pure 64-bit architecture, 8 is returned.</p> </item> </taglist> <note> - <p>The <c>scheduler</c> argument has changed name to - <c>scheduler_id</c>. This in order to avoid mixup with - the <c>schedulers</c> argument. The <c>scheduler</c> - argument was introduced in ERTS version 5.5 and renamed - in ERTS version 5.5.1.</p> + <p>Argument <c>scheduler</c> has changed name to + <c>scheduler_id</c> to avoid mix up with argument + <c>schedulers</c>. Argument <c>scheduler</c> was + introduced in <c>ERTS</c> 5.5 and renamed in + <c>ERTS</c> 5.5.1.</p> </note> </desc> </func> <func> <name name="system_monitor" arity="0"/> + <fsummary>Current system performance monitoring settings.</fsummary> <type name="system_monitor_option"/> - <fsummary>Current system performance monitoring settings</fsummary> <desc> <p>Returns the current system monitoring settings set by <seealso marker="#system_monitor/2">erlang:system_monitor/2</seealso> - as <c>{<anno>MonitorPid</anno>, <anno>Options</anno>}</c>, or <c>undefined</c> if there - are no settings. The order of the options may be different + as <c>{<anno>MonitorPid</anno>, <anno>Options</anno>}</c>, + or <c>undefined</c> if there + are no settings. The order of the options can be different from the one that was set.</p> </desc> </func> <func> <name name="system_monitor" arity="1"/> + <fsummary>Sets or clears system performance monitoring options.</fsummary> <type name="system_monitor_option"/> - <fsummary>Set or clear system performance monitoring options</fsummary> <desc> - <p>When called with the argument <c>undefined</c>, all + <p>When called with argument <c>undefined</c>, all system performance monitoring settings are cleared.</p> - <p>Calling the function with <c>{<anno>MonitorPid</anno>, <anno>Options</anno>}</c> as - argument, is the same as calling - <seealso marker="#system_monitor/2">erlang:system_monitor(<anno>MonitorPid</anno>, <anno>Options</anno>)</seealso>.</p> + <p>Calling the function with <c>{<anno>MonitorPid</anno>, + <anno>Options</anno>}</c> as argument is the same as calling + <seealso marker="#system_monitor/2"><c>erlang:system_monitor(<anno>MonitorPid</anno>, <anno>Options</anno>)</c></seealso>.</p> <p>Returns the previous system monitor settings just like <seealso marker="#system_monitor/0">erlang:system_monitor/0</seealso>.</p> </desc> @@ -7052,102 +7581,101 @@ ok <func> <name name="system_monitor" arity="2"/> + <fsummary>Sets system performance monitoring options.</fsummary> <type name="system_monitor_option"/> - <fsummary>Set system performance monitoring options</fsummary> <desc> - <p>Sets system performance monitoring options. <c><anno>MonitorPid</anno></c> - is a local pid that will receive system monitor messages, and - the second argument is a list of monitoring options:</p> + <p>Sets the system performance monitoring options. + <c><anno>MonitorPid</anno></c> is a local process identifier (pid) + receiving system monitor messages. The + second argument is a list of monitoring options:</p> <taglist> <tag><c>{long_gc, Time}</c></tag> <item> <p>If a garbage collection in the system takes at least - <c>Time</c> wallclock milliseconds, a message + <c>Time</c> wall clock milliseconds, a message <c>{monitor, GcPid, long_gc, Info}</c> is sent to - <c><anno>MonitorPid</anno></c>. <c>GcPid</c> is the pid that was - garbage collected and <c>Info</c> is a list of two-element - tuples describing the result of the garbage collection. - One of the tuples is <c>{timeout, GcTime}</c> where - <c>GcTime</c> is the actual time for the garbage + <c><anno>MonitorPid</anno></c>. <c>GcPid</c> is the pid that + was garbage collected. <c>Info</c> is a list of two-element + tuples describing the result of the garbage collection.</p> + <p>One of the tuples is <c>{timeout, GcTime}</c>, where + <c>GcTime</c> is the time for the garbage collection in milliseconds. The other tuples are - tagged with <c>heap_size</c>, <c>heap_block_size</c>, - <c>stack_size</c>, <c>mbuf_size</c>, <c>old_heap_size</c>, - and <c>old_heap_block_size</c>. These tuples are - explained in the documentation of the - <seealso marker="#gc_start">gc_start</seealso> - trace message (see - <seealso marker="#trace/3">erlang:trace/3</seealso>). - New tuples may be added, and the order of the tuples in - the <c>Info</c> list may be changed at any time without prior - notice. - </p> + tagged with <c>heap_size</c>, <c>heap_block_size</c> + <c>stack_size</c>, <c>mbuf_size</c>, <c>old_heap_size</c>, + and <c>old_heap_block_size</c>. These tuples are + explained in the description of trace message + <seealso marker="#gc_start">gc_start</seealso> (see + <seealso marker="#trace/3">erlang:trace/3</seealso>). + New tuples can be added, and the order of the tuples in + the <c>Info</c> list can be changed at any time without + prior notice.</p> </item> <tag><c>{long_schedule, Time}</c></tag> <item> - <p>If a process or port in the system runs uninterrupted + <p>If a process or port in the system runs uninterrupted for at least <c>Time</c> wall clock milliseconds, a message <c>{monitor, PidOrPort, long_schedule, Info}</c> is sent to <c>MonitorPid</c>. <c>PidOrPort</c> is the - process or port that was running and <c>Info</c> is a - list of two-element tuples describing the event. In case - of a <c>pid()</c>, the tuples <c>{timeout, Millis}</c>, - <c>{in, Location}</c> and <c>{out, Location}</c> will be + process or port that was running. <c>Info</c> is a + list of two-element tuples describing the event.</p> + <p>If a <c>pid()</c>, the tuples <c>{timeout, Millis}</c>, + <c>{in, Location}</c>, and <c>{out, Location}</c> are present, where <c>Location</c> is either an MFA (<c>{Module, Function, Arity}</c>) describing the function where the process was scheduled in/out, or the - atom <c>undefined</c>. In case of a <c>port()</c>, the + atom <c>undefined</c>.</p> + <p>If a <c>port()</c>, the tuples <c>{timeout, Millis}</c> and <c>{port_op,Op}</c> - will be present. <c>Op</c> will be one of <c>proc_sig</c>, + are present. <c>Op</c> is one of <c>proc_sig</c>, <c>timeout</c>, <c>input</c>, <c>output</c>, - <c>event</c> or <c>dist_cmd</c>, depending on which - driver callback was executing. <c>proc_sig</c> is an - internal operation and should never appear, while the + <c>event</c>, or <c>dist_cmd</c>, depending on which + driver callback was executing.</p> + <p><c>proc_sig</c> is an + internal operation and is never to appear, while the others represent the corresponding driver callbacks <c>timeout</c>, <c>ready_input</c>, <c>ready_output</c>, - <c>event</c> and finally <c>outputv</c> (when the port - is used by distribution). The <c>Millis</c> value in - the <c>timeout</c> tuple will tell you the actual - uninterrupted execution time of the process or port, - which will always be <c>>=</c> the <c>Time</c> value - supplied when starting the trace. New tuples may be - added to the <c>Info</c> list in the future, and the - order of the tuples in the list may be changed at any - time without prior notice. - </p> - <p>This can be used to detect problems with NIF's or - drivers that take too long to execute. Generally, 1 ms - is considered a good maximum time for a driver callback - or a NIF. However, a time sharing system should usually - consider everything below 100 ms as "possible" and - fairly "normal". Schedule times above that might however - indicate swapping or a NIF/driver that is - misbehaving. Misbehaving NIF's and drivers could cause - bad resource utilization and bad overall performance of - the system.</p> + <c>event</c>, and <c>outputv</c> (when the port + is used by distribution). Value <c>Millis</c> in + the <c>timeout</c> tuple informs about the + uninterrupted execution time of the process or port, which + always is equal to or higher than the <c>Time</c> value + supplied when starting the trace. New tuples can be + added to the <c>Info</c> list in a future release. The + order of the tuples in the list can be changed at any + time without prior notice.</p> + <p>This can be used to detect problems with NIFs or + drivers that take too long to execute. 1 ms is + considered a good maximum time for a driver callback + or a NIF. However, a time-sharing system is usually to + consider everything below 100 ms as "possible" and + fairly "normal". However, longer schedule times can + indicate swapping or a misbehaving NIF/driver. + Misbehaving NIFs and drivers can cause bad resource + utilization and bad overall system performance.</p> </item> <tag><c>{large_heap, Size}</c></tag> <item> <p>If a garbage collection in the system results in the allocated size of a heap being at least <c>Size</c> words, a message <c>{monitor, GcPid, large_heap, Info}</c> - is sent to <c><anno>MonitorPid</anno></c>. <c>GcPid</c> and <c>Info</c> - are the same as for <c>long_gc</c> above, except that - the tuple tagged with <c>timeout</c> is not present. - <em>Note</em>: As of erts version 5.6 the monitor message - is sent if the sum of the sizes of all memory blocks allocated - for all heap generations is equal to or larger than <c>Size</c>. - Previously the monitor message was sent if the memory block - allocated for the youngest generation was equal to or larger - than <c>Size</c>. - </p> + is sent to <c><anno>MonitorPid</anno></c>. + <c>GcPid</c> and <c>Info</c> + are the same as for <c>long_gc</c> earlier, except that + the tuple tagged with <c>timeout</c> is not present.</p> + <p>As of <c>ERTS</c> 5.6, the monitor message is sent + if the sum of the sizes of all memory blocks allocated + for all heap generations is equal to or higher than <c>Size</c>. + Previously the monitor message was sent if the memory block + allocated for the youngest generation was equal to or higher + than <c>Size</c>.</p> </item> <tag><c>busy_port</c></tag> <item> <p>If a process in the system gets suspended because it sends to a busy port, a message <c>{monitor, SusPid, busy_port, Port}</c> is sent to - <c><anno>MonitorPid</anno></c>. <c>SusPid</c> is the pid that got - suspended when sending to <c>Port</c>.</p> + <c><anno>MonitorPid</anno></c>. <c>SusPid</c> is the pid + that got suspended when sending to <c>Port</c>.</p> </item> <tag><c>busy_dist_port</c></tag> <item> @@ -7155,8 +7683,8 @@ ok sends to a process on a remote node whose inter-node communication was handled by a busy port, a message <c>{monitor, SusPid, busy_dist_port, Port}</c> is sent to - <c><anno>MonitorPid</anno></c>. <c>SusPid</c> is the pid that got - suspended when sending through the inter-node + <c><anno>MonitorPid</anno></c>. <c>SusPid</c> is the pid + that got suspended when sending through the inter-node communication port <c>Port</c>.</p> </item> </taglist> @@ -7165,74 +7693,103 @@ ok <note> <p>If a monitoring process gets so large that it itself starts to cause system monitor messages when garbage - collecting, the messages will enlarge the process's + collecting, the messages enlarge the process message queue and probably make the problem worse.</p> <p>Keep the monitoring process neat and do not set the system monitor limits too tight.</p> </note> - <p>Failure: <c>badarg</c> if <c><anno>MonitorPid</anno></c> does not exist or is not a local process.</p> + <p>Failures:</p> + <taglist> + <tag><c>badarg</c></tag> + <item>If <c><anno>MonitorPid</anno></c> does not exist.</item> + <tag><c>badarg</c></tag> + <item>If <c><anno>MonitorPid</anno></c> is not a local process.</item> + </taglist> </desc> </func> <func> <name name="system_profile" arity="0"/> + <fsummary>Current system profiling settings.</fsummary> <type name="system_profile_option"/> - <fsummary>Current system profiling settings</fsummary> <desc> <p>Returns the current system profiling settings set by <seealso marker="#system_profile/2">erlang:system_profile/2</seealso> - as <c>{<anno>ProfilerPid</anno>, <anno>Options</anno>}</c>, or <c>undefined</c> if there - are no settings. The order of the options may be different + as <c>{<anno>ProfilerPid</anno>, <anno>Options</anno>}</c>, + or <c>undefined</c> if there + are no settings. The order of the options can be different from the one that was set.</p> </desc> </func> <func> <name name="system_profile" arity="2"/> + <fsummary>Current system profiling settings.</fsummary> <type name="system_profile_option"/> - <fsummary>Current system profiling settings</fsummary> <desc> <p>Sets system profiler options. <c><anno>ProfilerPid</anno></c> - is a local pid or port that will receive profiling messages. The - receiver is excluded from all profiling. + is a local process identifier (pid) or port receiving profiling + messages. The receiver is excluded from all profiling. The second argument is a list of profiling options:</p> <taglist> <tag><c>exclusive</c></tag> <item> - <p> - If a synchronous call to a port from a process is done, the + <p>If a synchronous call to a port from a process is done, the calling process is considered not runnable during the call runtime to the port. The calling process is notified as - <c>inactive</c> and subsequently <c>active</c> when the port - callback returns. - </p> + <c>inactive</c>, and later <c>active</c> when the port + callback returns.</p> + </item> + <tag><c>monotonic_timestamp</c></tag> + <item> + <p>Timestamps in profile messages will use + <seealso marker="time_correction#Erlang_Monotonic_Time">Erlang + monotonic time</seealso>. The time-stamp (Ts) has the same + format and value as produced by + <c>erlang:monotonic_time(nano_seconds)</c>.</p> </item> <tag><c>runnable_procs</c></tag> <item> - <p>If a process is put into or removed from the run queue a message, - <c>{profile, Pid, State, Mfa, Ts}</c>, is sent to - <c><anno>ProfilerPid</anno></c>. Running processes that is reinserted into the - run queue after having been preemptively scheduled out will not trigger this - message. - </p> + <p>If a process is put into or removed from the run queue, a + message, <c>{profile, Pid, State, Mfa, Ts}</c>, is sent to + <c><anno>ProfilerPid</anno></c>. Running processes that + are reinserted into the run queue after having been + preempted do not trigger this message.</p> </item> <tag><c>runnable_ports</c></tag> <item> - <p>If a port is put into or removed from the run queue a message, - <c>{profile, Port, State, 0, Ts}</c>, is sent to - <c><anno>ProfilerPid</anno></c>. - </p> + <p>If a port is put into or removed from the run queue, a + message, <c>{profile, Port, State, 0, Ts}</c>, is sent to + <c><anno>ProfilerPid</anno></c>.</p> </item> <tag><c>scheduler</c></tag> <item> - <p>If a scheduler is put to sleep or awoken a message, - <c>{profile, scheduler, Id, State, NoScheds, Ts}</c>, is sent - to <c><anno>ProfilerPid</anno></c>. - </p> + <p>If a scheduler is put to sleep or awoken, a message, + <c>{profile, scheduler, Id, State, NoScheds, Ts}</c>, is + sent to <c><anno>ProfilerPid</anno></c>.</p> + </item> + <tag><c>strict_monotonic_timestamp</c></tag> + <item> + <p>Timestamps in profile messages will consisting of + <seealso marker="time_correction#Erlang_Monotonic_Time">Erlang + monotonic time</seealso> and a monotonically increasing + integer. The time-stamp (Ts) has the same format and value + as produced by <c>{erlang:monotonic_time(nano_seconds), + erlang:unique_integer([monotonic])}</c>.</p> + </item> + <tag><c>timestamp</c></tag> + <item> + <p>Timestamps in profile messages will include a + time-stamp (Ts) that has the same form as returned by + <c>erlang:now()</c>. This is also the default if no + timestamp flag is given. If <c>cpu_timestamp</c> has + been enabled via <c>erlang:trace/3</c>, this will also + effect the timestamp produced in profiling messages + when <c>timestamp</c> flag is enabled.</p> </item> </taglist> - <note><p><c>erlang:system_profile</c> is considered experimental and - its behaviour may change in the future.</p> + <note><p><c>erlang:system_profile</c> is considered experimental + and its behavior can change in a future release.</p> </note> </desc> </func> @@ -7276,11 +7833,12 @@ ok </func> <func> <name name="term_to_binary" arity="1"/> - <fsummary>Encode a term to an Erlang external term format binary</fsummary> + <fsummary>Encodes a term to an Erlang external term format binary.</fsummary> <desc> - <p>Returns a binary data object which is the result of encoding - <c><anno>Term</anno></c> according to the Erlang external term format.</p> - <p>This can be used for a variety of purposes, for example + <p>Returns a binary data object that is the result of encoding + <c><anno>Term</anno></c> according to the Erlang external + term format.</p> + <p>This can be used for various purposes, for example, writing a term to a file in an efficient way, or sending an Erlang term to some type of communications channel not supported by distributed Erlang.</p> @@ -7288,67 +7846,81 @@ ok <seealso marker="#binary_to_term/1">binary_to_term/1</seealso>.</p> </desc> </func> + <func> <name name="term_to_binary" arity="2"/> - <fsummary>Encode a term to en Erlang external term format binary</fsummary> - <desc> - <p>Returns a binary data object which is the result of encoding - <c><anno>Term</anno></c> according to the Erlang external term format.</p> - <p>If the option <c>compressed</c> is provided, the external - term format will be compressed. The compressed format is - automatically recognized by <c>binary_to_term/1</c> in R7B and later.</p> - <p>It is also possible to specify a compression level by giving - the option <c>{compressed, <anno>Level</anno>}</c>, where <c><anno>Level</anno></c> is an - integer from 0 through 9. <c>0</c> means that no compression - will be done (it is the same as not giving any <c>compressed</c> option); - <c>1</c> will take the least time but may not compress as well as - the higher levels; <c>9</c> will take the most time and may produce - a smaller result. Note the "mays" in the preceding sentence; depending - on the input term, level 9 compression may or may not produce a smaller - result than level 1 compression.</p> - <p>Currently, <c>compressed</c> gives the same result as - <c>{compressed, 6}</c>.</p> - <p>The option <c>{minor_version, <anno>Version</anno>}</c> can be use to control - some details of the encoding. This option was - introduced in R11B-4. Currently, the allowed values for <c><anno>Version</anno></c> - are <c>0</c> and <c>1</c>.</p> - <p><c>{minor_version, 1}</c> is since 17.0 the default, it forces any floats in - the term to be encoded - in a more space-efficient and exact way (namely in the 64-bit IEEE format, - rather than converted to a textual representation). <c>binary_to_term/1</c> - in R11B-4 and later is able decode this representation.</p> - <p><c>{minor_version, 0}</c> meaning that floats - will be encoded using a textual representation; this option is useful if - you want to ensure that releases prior to R11B-4 can decode resulting + <fsummary>Encodes a term to en Erlang external term format binary.</fsummary> + <desc> + <p>Returns a binary data object that is the result of encoding + <c><anno>Term</anno></c> according to the Erlang external + term format.</p> + <p>If option <c>compressed</c> is provided, the external term + format is compressed. The compressed format is automatically + recognized by <c>binary_to_term/1</c> as from Erlang R7B.</p> + <p>A compression level can be specified by giving option + <c>{compressed, <anno>Level</anno>}</c>. + <c><anno>Level</anno></c> is an integer + with range 0..9, where:</p> + <list type="bulleted"> + <item><c>0</c> - No compression is done (it is the same as + giving no <c>compressed</c> option).</item> + <item><c>1</c> - Takes least time but may not compress + as well as the higher levels.</item> + <item><c>6</c> - Default level when option <c>compressed</c> + is provided.</item> + <item><c>9</c> - Takes most time and tries to produce a smaller + result. Notice "tries" in the preceding sentence; depending + on the input term, level 9 compression either does or does + not produce a smaller result than level 1 compression.</item> + </list> + <p>Option <c>{minor_version, <anno>Version</anno>}</c> + can be used to control + some encoding details. This option was introduced in OTP R11B-4. + The valid values for <c><anno>Version</anno></c> are + <c>0</c> and <c>1</c>.</p> + <p>As from OTP 17.0, <c>{minor_version, 1}</c> is the default. It + forces any floats in the term to be encoded in a more + space-efficient and exact way (namely in the 64-bit IEEE format, + rather than converted to a textual representation).</p> + <p>As from OTP R11B-4, <c>binary_to_term/1</c> can decode this + representation.</p> + <p><c>{minor_version, 0}</c> means that floats are encoded + using a textual representation. This option is useful to + ensure that releases before OTP R11B-4 can decode resulting binary.</p> <p>See also <seealso marker="#binary_to_term/1">binary_to_term/1</seealso>.</p> </desc> </func> + <func> <name name="throw" arity="1"/> - <fsummary>Throw an exception</fsummary> + <fsummary>Throws an exception.</fsummary> <desc> <p>A non-local return from a function. If evaluated within a - <c>catch</c>, <c>catch</c> will return the value <c><anno>Any</anno></c>.</p> + <c>catch</c>, <c>catch</c> returns value <c><anno>Any</anno></c>.</p> + <p>Example:</p> <pre> > <input>catch throw({hello, there}).</input> {hello,there}</pre> <p>Failure: <c>nocatch</c> if not evaluated within a catch.</p> </desc> </func> + <func> <name name="time" arity="0"/> - <fsummary>Current time</fsummary> + <fsummary>Current time.</fsummary> <desc> <p>Returns the current time as <c>{Hour, Minute, Second}</c>.</p> - <p>The time zone and daylight saving time correction depend on + <p>The time zone and Daylight Saving Time correction depend on the underlying OS.</p> + <p>Example:</p> <pre> > <input>time().</input> {9,42,44}</pre> </desc> </func> + <func> <name name="time_offset" arity="0"/> <fsummary>Current time offset</fsummary> @@ -7399,14 +7971,14 @@ ok </func> <func> <name name="timestamp" arity="0"/> - <type name="timestamp"/> <fsummary>Current Erlang System time</fsummary> + <type name="timestamp"/> <desc> <p>Returns current <seealso marker="time_correction#Erlang_System_Time">Erlang system time</seealso> on the format <c>{MegaSecs, Secs, MicroSecs}</c>. This format is - the same that <seealso marker="kernel:os#timestamp/0"><c>os:timestamp/0</c></seealso> - and the now deprecated <seealso marker="#now/0"><c>erlang:now/0</c></seealso> + the same as <seealso marker="kernel:os#timestamp/0"><c>os:timestamp/0</c></seealso> + and the deprecated <seealso marker="#now/0"><c>erlang:now/0</c></seealso> uses. The reason for the existence of <c>erlang:timestamp()</c> is purely to simplify usage for existing code that assumes this timestamp format. Current Erlang system time can more efficiently be retrieved in @@ -7420,9 +7992,9 @@ timestamp() -> Secs = ErlangSystemTime div 1000000 - MegaSecs*1000000, MicroSecs = ErlangSystemTime rem 1000000, {MegaSecs, Secs, MicroSecs}.</code> - <p>It however use a native implementation which does - not build garbage on the heap and with slightly better - performance.</p> + <p>It, however, uses a native implementation which does + not build garbage on the heap and with slightly better + performance.</p> <note><p>This time is <em>not</em> a monotonically increasing time in the general case. For more information, see the documentation of @@ -7433,186 +8005,213 @@ timestamp() -> </func> <func> <name name="tl" arity="1"/> - <fsummary>Tail of a list</fsummary> + <fsummary>Tail of a list.</fsummary> <desc> - <p>Returns the tail of <c><anno>List</anno></c>, that is, the list minus - the first element.</p> + <p>Returns the tail of <c><anno>List</anno></c>, that is, + the list minus the first element, for example:</p> <pre> > <input>tl([geesties, guilies, beasties]).</input> [guilies, beasties]</pre> <p>Allowed in guard tests.</p> - <p>Failure: <c>badarg</c> if <c><anno>List</anno></c> is the empty list [].</p> + <p>Failure: <c>badarg</c> if <c><anno>List</anno></c> + is the empty list <c>[]</c>.</p> </desc> </func> + <func> <name name="trace" arity="3"/> + <fsummary>Sets trace flags for a process or processes.</fsummary> <type name="trace_flag"/> - <fsummary>Set trace flags for a process or processes</fsummary> <desc> <p>Turns on (if <c><anno>How</anno> == true</c>) or off (if - <c><anno>How</anno> == false</c>) the trace flags in <c><anno>FlagList</anno></c> for - the process or processes represented by <c><anno>PidSpec</anno></c>.</p> - <p><c><anno>PidSpec</anno></c> is either a pid for a local process, or one of - the following atoms:</p> + <c><anno>How</anno> == false</c>) the trace flags in + <c><anno>FlagList</anno></c> for + the process or processes represented by + <c><anno>PidSpec</anno></c>.</p> + <p><c><anno>PidSpec</anno></c> is either a process identifier + (pid) for a local process, or one of the following atoms:</p> <taglist> <tag><c>existing</c></tag> <item> - <p>All processes currently existing.</p> + <p>All currently existing processes.</p> </item> <tag><c>new</c></tag> <item> - <p>All processes that will be created in the future.</p> + <p>All processes that are created in the future.</p> </item> <tag><c>all</c></tag> <item> <p>All currently existing processes and all processes that - will be created in the future.</p> + are created in the future.</p> </item> </taglist> - <p><c><anno>FlagList</anno></c> can contain any number of the following - flags (the "message tags" refers to the list of messages - following below):</p> + <p><c><anno>FlagList</anno></c> can contain any number of the + following flags (the "message tags" refers to the list of + <seealso marker="#trace_3_trace_messages">trace messages</seealso>):</p> <taglist> <tag><c>all</c></tag> <item> - <p>Set all trace flags except <c>{tracer, Tracer}</c> and - <c>cpu_timestamp</c> that are in their nature different + <p>Sets all trace flags except <c>{tracer, Tracer}</c> and + <c>cpu_timestamp</c>, which are in their nature different than the others.</p> </item> <tag><c>send</c></tag> <item> - <p>Trace sending of messages.</p> - <p>Message tags: <c>send</c>, + <p>Traces sending of messages.</p> + <p>Message tags: <c>send</c> and <c>send_to_non_existing_process</c>.</p> </item> <tag><c>'receive'</c></tag> <item> - <p>Trace receiving of messages.</p> + <p>Traces receiving of messages.</p> <p>Message tags: <c>'receive'</c>.</p> </item> <tag><c>procs</c></tag> <item> - <p>Trace process related events.</p> + <p>Traces process-related events.</p> <p>Message tags: <c>spawn</c>, <c>exit</c>, <c>register</c>, <c>unregister</c>, <c>link</c>, - <c>unlink</c>, <c>getting_linked</c>, + <c>unlink</c>, <c>getting_linked</c>, and <c>getting_unlinked</c>.</p> </item> <tag><c>call</c></tag> <item> - <p>Trace certain function calls. Specify which function + <p>Traces certain function calls. Specify which function calls to trace by calling <seealso marker="#trace_pattern/3">erlang:trace_pattern/3</seealso>.</p> - <p>Message tags: <c>call</c>, <c>return_from</c>.</p> + <p>Message tags: <c>call</c> and <c>return_from</c>.</p> </item> <tag><c>silent</c></tag> <item> - <p>Used in conjunction with the <c>call</c> trace flag. - The <c>call</c>, <c>return_from</c> and <c>return_to</c> - trace messages are inhibited if this flag is set, - but if there are match specs they are executed as normal.</p> + <p>Used with the <c>call</c> trace flag. + The <c>call</c>, <c>return_from</c>, and <c>return_to</c> + trace messages are inhibited if this flag is set, but they + are executed as normal if there are match specifications.</p> <p>Silent mode is inhibited by executing <c>erlang:trace(_, false, [silent|_])</c>, - or by a match spec executing the <c>{silent, false}</c> - function.</p> + or by a match specification executing the function + <c>{silent, false}</c>.</p> <p>The <c>silent</c> trace flag facilitates setting up a trace on many or even all processes in the system. - Then the interesting trace can be activated and - deactivated using the <c>{silent,Bool}</c> - match spec function, giving a high degree - of control of which functions with which - arguments that triggers the trace.</p> - <p>Message tags: <c>call</c>, <c>return_from</c>, + The trace can then be activated and deactivated using the match + specification function <c>{silent,Bool}</c>, giving + a high degree of control of which functions with which + arguments that trigger the trace.</p> + <p>Message tags: <c>call</c>, <c>return_from</c>, and <c>return_to</c>. Or rather, the absence of.</p> </item> <tag><c>return_to</c></tag> <item> - <p>Used in conjunction with the <c>call</c> trace flag. - Trace the actual return from a traced function back to + <p>Used with the <c>call</c> trace flag. + Traces the return from a traced function back to its caller. Only works for functions traced with - the <c>local</c> option to + option <c>local</c> to <seealso marker="#trace_pattern/3">erlang:trace_pattern/3</seealso>.</p> <p>The semantics is that a trace message is sent when a - call traced function actually returns, that is, when a - chain of tail recursive calls is ended. There will be - only one trace message sent per chain of tail recursive - calls, why the properties of tail recursiveness for + call traced function returns, that is, when a + chain of tail recursive calls ends. Only one trace + message is sent per chain of tail recursive calls, + so the properties of tail recursiveness for function calls are kept while tracing with this flag. Using <c>call</c> and <c>return_to</c> trace together makes it possible to know exactly in which function a process executes at any time.</p> <p>To get trace messages containing return values from - functions, use the <c>{return_trace}</c> match_spec - action instead.</p> + functions, use the <c>{return_trace}</c> match + specification action instead.</p> <p>Message tags: <c>return_to</c>.</p> </item> <tag><c>running</c></tag> <item> - <p>Trace scheduling of processes.</p> - <p>Message tags: <c>in</c>, and <c>out</c>.</p> + <p>Traces scheduling of processes.</p> + <p>Message tags: <c>in</c> and <c>out</c>.</p> </item> <tag><c>exiting</c></tag> <item> - <p>Trace scheduling of an exiting processes.</p> + <p>Traces scheduling of exiting processes.</p> <p>Message tags: <c>in_exiting</c>, <c>out_exiting</c>, and <c>out_exited</c>.</p> </item> <tag><c>garbage_collection</c></tag> <item> - <p>Trace garbage collections of processes.</p> - <p>Message tags: <c>gc_start</c>, <c>gc_end</c>.</p> + <p>Traces garbage collections of processes.</p> + <p>Message tags: <c>gc_start</c> and <c>gc_end</c>.</p> </item> <tag><c>timestamp</c></tag> <item> - <p>Include a time stamp in all trace messages. The time - stamp (Ts) is of the same form as returned by + <p>Includes a time-stamp in all trace messages. The + time-stamp (Ts) has the same form as returned by <c>erlang:now()</c>.</p> </item> <tag><c>cpu_timestamp</c></tag> <item> <p>A global trace flag for the Erlang node that makes all - trace timestamps be in CPU time, not wallclock. It is - only allowed with <c>PidSpec==all</c>. If the host - machine operating system does not support high resolution + trace time-stamps using the <c>timestamp</c> flag to be + in CPU time, not wall clock time. That is, <c>cpu_timestamp</c> + will not be used if <c>monotonic_timestamp</c>, or + <c>strict_monotonic_timestamp</c> is enabled. + Only allowed with <c>PidSpec==all</c>. If the host + machine OS does not support high-resolution CPU time measurements, <c>trace/3</c> exits with - <c>badarg</c>. Note that most operating systems do + <c>badarg</c>. Notice that most OS do not synchronize this value across cores, so be prepared that time might seem to go backwards when using this option.</p> </item> + <tag><c>monotonic_timestamp</c></tag> + <item> + <p>Includes an + <seealso marker="time_correction#Erlang_Monotonic_Time">Erlang + monotonic time</seealso> time-stamp in all trace messages. The + time-stamp (Ts) has the same format and value as produced by + <c>erlang:monotonic_time(nano_seconds)</c>. This flag overrides + the <c>cpu_timestamp</c> flag.</p> + </item> + <tag><c>strict_monotonic_timestamp</c></tag> + <item> + <p>Includes an timestamp consisting of + <seealso marker="time_correction#Erlang_Monotonic_Time">Erlang + monotonic time</seealso> and a monotonically increasing + integer in all trace messages. The time-stamp (Ts) has the + same format and value as produced by + <c>{erlang:monotonic_time(nano_seconds), + erlang:unique_integer([monotonic])}</c>. This flag overrides + the <c>cpu_timestamp</c> flag.</p> + </item> <tag><c>arity</c></tag> <item> - <p>Used in conjunction with the <c>call</c> trace flag. - <c>{M, F, Arity}</c> will be specified instead of + <p>Used with the <c>call</c> trace flag. + <c>{M, F, Arity}</c> is specified instead of <c>{M, F, Args}</c> in call trace messages.</p> </item> <tag><c>set_on_spawn</c></tag> <item> <p>Makes any process created by a traced process inherit - its trace flags, including the <c>set_on_spawn</c> flag.</p> + its trace flags, including flag <c>set_on_spawn</c>.</p> </item> <tag><c>set_on_first_spawn</c></tag> <item> <p>Makes the first process created by a traced process - inherit its trace flags, excluding - the <c>set_on_first_spawn</c> flag.</p> + inherit its trace flags, excluding flag + <c>set_on_first_spawn</c>.</p> </item> <tag><c>set_on_link</c></tag> <item> <p>Makes any process linked by a traced process inherit its - trace flags, including the <c>set_on_link</c> flag.</p> + trace flags, including flag <c>set_on_link</c>.</p> </item> <tag><c>set_on_first_link</c></tag> <item> <p>Makes the first process linked to by a traced process - inherit its trace flags, excluding - the <c>set_on_first_link</c> flag.</p> + inherit its trace flags, excluding flag + <c>set_on_first_link</c>.</p> </item> <tag><c>{tracer, Tracer}</c></tag> <item> - <p>Specify where to send the trace messages. <c>Tracer</c> - must be the pid of a local process or the port identifier + <p>Specifies where to send the trace messages. <c>Tracer</c> + must be the process identifier of a local process + or the port identifier of a local port. If this flag is not given, trace - messages will be sent to the process that called + messages are sent to the process that called <c>erlang:trace/3</c>.</p> </item> </taglist> @@ -7620,27 +8219,34 @@ timestamp() -> <c>set_on_link</c> is the same as having <c>set_on_first_link</c> alone. Likewise for <c>set_on_spawn</c> and <c>set_on_first_spawn</c>.</p> - <p>If the <c>timestamp</c> flag is not given, the tracing - process will receive the trace messages described below. - <c>Pid</c> is the pid of the traced process in which - the traced event has occurred. The third element of the tuple - is the message tag.</p> - <p>If the <c>timestamp</c> flag is given, the first element of - the tuple will be <c>trace_ts</c> instead and the timestamp - is added last in the tuple.</p> + <p>The tracing process receives the <em>trace messages</em> described + in the following list. <c>Pid</c> is the process identifier of the + traced process in which the traced event has occurred. The + third tuple element is the message tag.</p> + <p>If flag <c>timestamp</c>, <c>strict_monotonic_timestamp</c>, or + <c>monotonic_timestamp</c> is given, the first tuple + element is <c>trace_ts</c> instead, and the time-stamp + is added as an extra element last in the message tuple. If + multiple timestamp flags are passed, <c>timestamp</c> has + precedence over <c>strict_monotonic_timestamp</c> which + in turn has precedence over <c>monotonic_timestamp</c>. All + timestamp flags are remembered, so if two are passed + and the one with highest precedence later is disabled + the other one will become active.</p> + <marker id="trace_3_trace_messages"></marker> <taglist> <tag><c>{trace, Pid, 'receive', Msg}</c></tag> <item> - <p>When <c>Pid</c> receives the message <c>Msg</c>.</p> + <p>When <c>Pid</c> receives message <c>Msg</c>.</p> </item> <tag><c>{trace, Pid, send, Msg, To}</c></tag> <item> - <p>When <c>Pid</c> sends the message <c>Msg</c> to - the process <c>To</c>.</p> + <p>When <c>Pid</c> sends message <c>Msg</c> to + process <c>To</c>.</p> </item> <tag><c>{trace, Pid, send_to_non_existing_process, Msg, To}</c></tag> <item> - <p>When <c>Pid</c> sends the message <c>Msg</c> to + <p>When <c>Pid</c> sends message <c>Msg</c> to the non-existing process <c>To</c>.</p> </item> <tag><c>{trace, Pid, call, {M, F, Args}}</c></tag> @@ -7648,7 +8254,7 @@ timestamp() -> <p>When <c>Pid</c> calls a traced function. The return values of calls are never supplied, only the call and its arguments.</p> - <p>Note that the trace flag <c>arity</c> can be used to + <p>Trace flag <c>arity</c> can be used to change the contents of this message, so that <c>Arity</c> is specified instead of <c>Args</c>.</p> </item> @@ -7656,35 +8262,34 @@ timestamp() -> <item> <p>When <c>Pid</c> returns <em>to</em> the specified function. This trace message is sent if both - the <c>call</c> and the <c>return_to</c> flags are set, + the flags <c>call</c> and <c>return_to</c> are set, and the function is set to be traced on <em>local</em> function calls. The message is only sent when returning - from a chain of tail recursive function calls where at + from a chain of tail recursive function calls, where at least one call generated a <c>call</c> trace message - (that is, the functions match specification matched and + (that is, the functions match specification matched, and <c>{message, false}</c> was not an action).</p> </item> <tag><c>{trace, Pid, return_from, {M, F, Arity}, ReturnValue}</c></tag> <item> <p>When <c>Pid</c> returns <em>from</em> the specified - function. This trace message is sent if the <c>call</c> - flag is set, and the function has a match specification + function. This trace message is sent if flag <c>call</c> + is set, and the function has a match specification with a <c>return_trace</c> or <c>exception_trace</c> action.</p> </item> <tag><c>{trace, Pid, exception_from, {M, F, Arity}, {Class, Value}}</c></tag> <item> <p>When <c>Pid</c> exits <em>from</em> the specified - function due to an exception. This trace message is sent - if the <c>call</c> flag is set, and the function has + function because of an exception. This trace message is + sent if flag <c>call</c> is set, and the function has a match specification with an <c>exception_trace</c> action.</p> </item> <tag><c>{trace, Pid, spawn, Pid2, {M, F, Args}}</c></tag> <item> <p>When <c>Pid</c> spawns a new process <c>Pid2</c> with the specified function call as entry point.</p> - <p>Note that <c>Args</c> is supposed to be the argument - list, but may be any term in the case of an erroneous - spawn.</p> + <p><c>Args</c> is supposed to be the argument list, + but can be any term if the spawn is erroneous.</p> </item> <tag><c>{trace, Pid, exit, Reason}</c></tag> <item> @@ -7714,148 +8319,158 @@ timestamp() -> <tag><c>{trace, Pid, unregister, RegName}</c></tag> <item> <p>When <c>Pid</c> gets the name <c>RegName</c> unregistered. - Note that this is done automatically when a registered + This is done automatically when a registered process exits.</p> </item> <tag><c>{trace, Pid, in, {M, F, Arity} | 0}</c></tag> <item> - <p>When <c>Pid</c> is scheduled to run. The process will - run in function <c>{M, F, Arity}</c>. On some rare - occasions the current function cannot be determined, then - the last element <c>Arity</c> is 0.</p> + <p>When <c>Pid</c> is scheduled to run. The process + runs in function <c>{M, F, Arity}</c>. On some rare + occasions, the current function cannot be determined, + then the last element is <c>0</c>.</p> </item> <tag><c>{trace, Pid, out, {M, F, Arity} | 0}</c></tag> <item> <p>When <c>Pid</c> is scheduled out. The process was - running in function {M, F, Arity}. On some rare occasions + running in function {M, F, Arity}. On some rare occasions, the current function cannot be determined, then the last - element <c>Arity</c> is 0.</p> + element is <c>0</c>.</p> </item> - <tag><marker id="gc_start"><c>{trace, Pid, gc_start, Info}</c></marker></tag> + <tag><c>{trace, Pid, gc_start, Info}</c></tag> <item> + <marker id="gc_start"></marker> <p>Sent when garbage collection is about to be started. <c>Info</c> is a list of two-element tuples, where the first element is a key, and the second is the value. - You should not depend on the tuples have any defined - order. Currently, the following keys are defined:</p> + Do not depend on any order of the tuples. + The following keys are defined:</p> <taglist> <tag><c>heap_size</c></tag> <item>The size of the used part of the heap.</item> <tag><c>heap_block_size</c></tag> <item>The size of the memory block used for storing - the heap and the stack.</item> + the heap and the stack.</item> <tag><c>old_heap_size</c></tag> <item>The size of the used part of the old heap.</item> <tag><c>old_heap_block_size</c></tag> <item>The size of the memory block used for storing - the old heap.</item> + the old heap.</item> <tag><c>stack_size</c></tag> - <item>The actual size of the stack.</item> + <item>The size of the stack.</item> <tag><c>recent_size</c></tag> <item>The size of the data that survived the previous garbage - collection.</item> + collection.</item> <tag><c>mbuf_size</c></tag> <item>The combined size of message buffers associated with - the process.</item> - + the process.</item> <tag><c>bin_vheap_size</c></tag> - <item>The total size of unique off-heap binaries referenced from the process heap.</item> + <item>The total size of unique off-heap binaries referenced + from the process heap.</item> <tag><c>bin_vheap_block_size</c></tag> - <item>The total size of binaries, in words, allowed in the virtual - heap in the process before doing a garbage collection. </item> + <item>The total size of binaries allowed in the virtual + heap in the process before doing a garbage collection.</item> <tag><c>bin_old_vheap_size</c></tag> - <item>The total size of unique off-heap binaries referenced from the process old heap.</item> - <tag><c>bin_vheap_block_size</c></tag> - <item>The total size of binaries, in words, allowed in the virtual - old heap in the process before doing a garbage collection. </item> - - + <item>The total size of unique off-heap binaries referenced + from the process old heap.</item> + <tag><c>bin_old_vheap_block_size</c></tag> + <item>The total size of binaries allowed in the virtual + old heap in the process before doing a garbage collection.</item> </taglist> <p>All sizes are in words.</p> </item> <tag><c>{trace, Pid, gc_end, Info}</c></tag> <item> <p>Sent when garbage collection is finished. <c>Info</c> - contains the same kind of list as in the <c>gc_start</c> - message, but the sizes reflect the new sizes after + contains the same kind of list as in message <c>gc_start</c>, + but the sizes reflect the new sizes after garbage collection.</p> </item> </taglist> - <p>If the tracing process dies, the flags will be silently + <p>If the tracing process dies, the flags are silently removed.</p> - <p>Only one process can trace a particular process. For this - reason, attempts to trace an already traced process will fail.</p> + <p>Only one process can trace a particular process. Therefore, + attempts to trace an already traced process fail.</p> <p>Returns: A number indicating the number of processes that - matched <c><anno>PidSpec</anno></c>. If <c><anno>PidSpec</anno></c> is a pid, - the return value will be <c>1</c>. If <c><anno>PidSpec</anno></c> is - <c>all</c> or <c>existing</c> the return value will be + matched <c><anno>PidSpec</anno></c>. + If <c><anno>PidSpec</anno></c> is a process + identifier, the return value is <c>1</c>. + If <c><anno>PidSpec</anno></c> + is <c>all</c> or <c>existing</c>, the return value is the number of processes running, excluding tracer processes. - If <c><anno>PidSpec</anno></c> is <c>new</c>, the return value will be + If <c><anno>PidSpec</anno></c> is <c>new</c>, the return value is <c>0</c>.</p> - <p>Failure: If specified arguments are not supported. For - example <c>cpu_timestamp</c> is not supported on all - platforms.</p> + <p>Failure: <c>badarg</c> if the specified arguments are + not supported. For example, <c>cpu_timestamp</c> is not + supported on all platforms.</p> </desc> </func> + <func> <name name="trace_delivered" arity="1"/> - <fsummary>Notification when trace has been delivered</fsummary> + <fsummary>Notification when trace has been delivered.</fsummary> <desc> <p>The delivery of trace messages is dislocated on the time-line - compared to other events in the system. If you know that the - <c><anno>Tracee</anno></c> has passed some specific point in its execution, + compared to other events in the system. If you know that + <c><anno>Tracee</anno></c> has passed some specific point + in its execution, and you want to know when at least all trace messages - corresponding to events up to this point have reached the tracer - you can use <c>erlang:trace_delivered(<anno>Tracee</anno>)</c>. A + corresponding to events up to this point have reached the + tracer, use <c>erlang:trace_delivered(<anno>Tracee</anno>)</c>. A <c>{trace_delivered, <anno>Tracee</anno>, <anno>Ref</anno>}</c> message is sent to the caller of <c>erlang:trace_delivered(<anno>Tracee</anno>)</c> when it - is guaranteed that all trace messages have been delivered to - the tracer up to the point that the <c><anno>Tracee</anno></c> had reached + is guaranteed that all trace messages are delivered to + the tracer up to the point that <c><anno>Tracee</anno></c> reached at the time of the call to <c>erlang:trace_delivered(<anno>Tracee</anno>)</c>.</p> - <p>Note that the <c>trace_delivered</c> message does <em>not</em> - imply that trace messages have been delivered; instead, it implies - that all trace messages that <em>should</em> be delivered have - been delivered. It is not an error if <c><anno>Tracee</anno></c> isn't, and - hasn't been traced by someone, but if this is the case, - <em>no</em> trace messages will have been delivered when the + <p>Notice that message <c>trace_delivered</c> does <em>not</em> + imply that trace messages have been delivered. + Instead it implies that all trace messages that + <em>are to be delivered</em> have been delivered. + It is not an error if <c><anno>Tracee</anno></c> is not, and + has not been traced by someone, but if this is the case, + <em>no</em> trace messages have been delivered when the <c>trace_delivered</c> message arrives.</p> - <p>Note that <c><anno>Tracee</anno></c> has to refer to a process currently, + <p>Notice that that <c><anno>Tracee</anno></c> must refer + to a process currently, or previously existing on the same node as the caller of <c>erlang:trace_delivered(<anno>Tracee</anno>)</c> resides on. - The special <c><anno>Tracee</anno></c> atom <c>all</c> denotes all processes + The special <c><anno>Tracee</anno></c> atom <c>all</c> + denotes all processes that currently are traced in the node.</p> - <p>An example: Process <c>A</c> is <c><anno>Tracee</anno></c>, port <c>B</c> is - tracer, and process <c>C</c> is the port owner of <c>B</c>. - <c>C</c> wants to close <c>B</c> when <c>A</c> exits. <c>C</c> - can ensure that the trace isn't truncated by calling - <c>erlang:trace_delivered(A)</c> when <c>A</c> exits and wait - for the <c>{trace_delivered, A, <anno>Ref</anno>}</c> message before closing - <c>B</c>.</p> - <p>Failure: <c>badarg</c> if <c><anno>Tracee</anno></c> does not refer to a + <p>Example: Process <c>A</c> is <c><anno>Tracee</anno></c>, + port <c>B</c> is tracer, and process <c>C</c> is the port + owner of <c>B</c>. <c>C</c> wants to close <c>B</c> when + <c>A</c> exits. To ensure that the trace is not truncated, + <c>C</c> can call <c>erlang:trace_delivered(A)</c>, when + <c>A</c> exits, and wait for message <c>{trace_delivered, A, + <anno>Ref</anno>}</c> before closing <c>B</c>.</p> + <p>Failure: <c>badarg</c> if <c><anno>Tracee</anno></c> + does not refer to a process (dead or alive) on the same node as the caller of <c>erlang:trace_delivered(<anno>Tracee</anno>)</c> resides on.</p> </desc> </func> + <func> <name name="trace_info" arity="2"/> + <fsummary>Trace information about a process or function.</fsummary> <type name="trace_info_return"/> <type name="trace_info_item_result"/> <type name="trace_info_flag"/> <type name="trace_match_spec"/> - <fsummary>Trace information about a process or function</fsummary> <desc> <p>Returns trace information about a process or function.</p> - <p>To get information about a process, <c><anno>PidOrFunc</anno></c> should - be a pid or the atom <c>new</c>. The atom <c>new</c> means - that the default trace state for processes to be created will - be returned. <c><anno>Item</anno></c> must have one of the following - values:</p> + <p>To get information about a process, + <c><anno>PidOrFunc</anno></c> is to + be a process identifier (pid) or the atom <c>new</c>. + The atom <c>new</c> means that the default trace state for + processes to be created is returned.</p> + <p>The following <c>Item</c>s are valid:</p> <taglist> <tag><c>flags</c></tag> <item> - <p>Return a list of atoms indicating what kind of traces is - enabled for the process. The list will be empty if no + <p>Returns a list of atoms indicating what kind of traces is + enabled for the process. The list is empty if no traces are enabled, and one or more of the followings atoms if traces are enabled: <c>send</c>, <c>'receive'</c>, <c>set_on_spawn</c>, <c>call</c>, @@ -7866,337 +8481,354 @@ timestamp() -> </item> <tag><c>tracer</c></tag> <item> - <p>Return the identifier for process or port tracing this + <p>Returns the identifier for process or port tracing this process. If this process is not being traced, the return - value will be <c>[]</c>.</p> + value is <c>[]</c>.</p> </item> </taglist> - <p>To get information about a function, <c>PidOrFunc</c> should - be a three-element tuple: <c>{Module, Function, Arity}</c> or - the atom <c>on_load</c>. No wildcards are allowed. Returns - <c>undefined</c> if the function does not exist or - <c>false</c> if the function is not traced at all. <c>Item</c> - must have one of the following values:</p> + <p>To get information about a function, <c>PidOrFunc</c> is to + be the three-element tuple <c>{Module, Function, Arity}</c> or + the atom <c>on_load</c>. No wild cards are allowed. Returns + <c>undefined</c> if the function does not exist, or + <c>false</c> if the function is not traced.</p> + <p>The following <c>Item</c>s are valid::</p> <taglist> <tag><c>traced</c></tag> <item> - <p>Return <c>global</c> if this function is traced on + <p>Returns <c>global</c> if this function is traced on global function calls, <c>local</c> if this function is - traced on local function calls (i.e local and global - function calls), and <c>false</c> if neither local nor - global function calls are traced.</p> + traced on local function calls (that is, local and global + function calls), and <c>false</c> if local or + global function calls are not traced.</p> </item> <tag><c>match_spec</c></tag> <item> - <p>Return the match specification for this function, if it + <p>Returns the match specification for this function, if it has one. If the function is locally or globally traced but has no match specification defined, the returned value is <c>[]</c>.</p> </item> <tag><c>meta</c></tag> <item> - <p>Return the meta trace tracer process or port for this - function, if it has one. If the function is not meta - traced the returned value is <c>false</c>, and if - the function is meta traced but has once detected that - the tracer proc is invalid, the returned value is [].</p> + <p>Returns the meta-trace tracer process or port for this + function, if it has one. If the function is not + meta-traced, the returned value is <c>false</c>. If + the function is meta-traced but has once detected that + the tracer process is invalid, the returned value is [].</p> </item> <tag><c>meta_match_spec</c></tag> <item> - <p>Return the meta trace match specification for this - function, if it has one. If the function is meta traced + <p>Returns the meta-trace match specification for this + function, if it has one. If the function is meta-traced but has no match specification defined, the returned value is <c>[]</c>.</p> </item> <tag><c>call_count</c></tag> <item> - <p>Return the call count value for this function or + <p>Returns the call count value for this function or <c>true</c> for the pseudo function <c>on_load</c> if call - count tracing is active. Return <c>false</c> otherwise. + count tracing is active. Otherwise <c>false</c> is returned. See also <seealso marker="#trace_pattern/3">erlang:trace_pattern/3</seealso>.</p> </item> <tag><c>call_time</c></tag> <item> - <p>Return the call time values for this function or + <p>Returns the call time values for this function or <c>true</c> for the pseudo function <c>on_load</c> if call - time tracing is active. Returns <c>false</c> otherwise. + time tracing is active. Otherwise <c>false</c> is returned. The call time values returned, <c>[{Pid, Count, S, Us}]</c>, - is a list of each process that has executed the function and its specific counters. - See also + is a list of each process that executed the function + and its specific counters. See also <seealso marker="#trace_pattern/3">erlang:trace_pattern/3</seealso>.</p> </item> <tag><c>all</c></tag> <item> - <p>Return a list containing the <c>{<anno>Item</anno>, Value}</c> tuples - for all other items, or return <c>false</c> if no tracing + <p>Returns a list containing the + <c>{<anno>Item</anno>, Value}</c> tuples + for all other items, or returns <c>false</c> if no tracing is active for this function.</p> </item> </taglist> - <p>The actual return value will be <c>{<anno>Item</anno>, Value}</c>, where - <c>Value</c> is the requested information as described above. + <p>The return value is <c>{<anno>Item</anno>, Value}</c>, where + <c>Value</c> is the requested information as described earlier. If a pid for a dead process was given, or the name of a - non-existing function, <c>Value</c> will be <c>undefined</c>.</p> - <p>If <c><anno>PidOrFunc</anno></c> is the <c>on_load</c>, the information + non-existing function, <c>Value</c> is <c>undefined</c>.</p> + <p>If <c><anno>PidOrFunc</anno></c> is <c>on_load</c>, the information returned refers to the default value for code that will be loaded.</p> </desc> </func> + <func> <name name="trace_pattern" arity="2" clause_i="1"/> + <fsummary>Sets trace patterns for global call tracing.</fsummary> <type name="trace_pattern_mfa"/> <type name="trace_match_spec"/> - <fsummary>Set trace patterns for global call tracing</fsummary> <desc> <p>The same as <seealso marker="#trace_pattern/3">erlang:trace_pattern(MFA, MatchSpec, [])</seealso>, retained for backward compatibility.</p> </desc> </func> + <func> <name name="trace_pattern" arity="3"/> + <fsummary>Sets trace patterns for tracing of function calls.</fsummary> <type name="trace_pattern_mfa"/> <type name="trace_match_spec"/> <type name="trace_pattern_flag"/> - <fsummary>Set trace patterns for tracing of function calls</fsummary> <desc> - <p>This BIF is used to enable or disable call tracing for - exported functions. It must be combined with + <p>Enables or disables call tracing for + one or more functions. Must be combined with <seealso marker="#trace/3">erlang:trace/3</seealso> to set the <c>call</c> trace flag for one or more processes.</p> - <p>Conceptually, call tracing works like this: Inside - the Erlang virtual machine there is a set of processes to be - traced and a set of functions to be traced. Tracing will be - enabled on the intersection of the set. That is, if a process - included in the traced process set calls a function included - in the traced function set, the trace action will be taken. - Otherwise, nothing will happen.</p> - <p>Use - <seealso marker="#trace/3">erlang:trace/3</seealso> to - add or remove one or more processes to the set of traced - processes. Use <c>erlang:trace_pattern/2</c> to add or remove - exported functions to the set of traced functions.</p> - <p>The <c>erlang:trace_pattern/3</c> BIF can also add match - specifications to an exported function. A match specification - comprises a pattern that the arguments to the function must - match, a guard expression which must evaluate to <c>true</c> + <p>Conceptually, call tracing works as follows. Inside + the Erlang Virtual Machine, a set of processes and + a set of functions are to be traced. If a traced process + calls a traced function, the trace action is taken. + Otherwise, nothing happens.</p> + <p>To add or remove one or more processes to the set of traced + processes, use + <seealso marker="#trace/3">erlang:trace/3</seealso>.</p> + <p>To add or remove functions to the set of traced + functions, use <c>erlang:trace_pattern/3</c>.</p> + <p>The BIF <c>erlang:trace_pattern/3</c> can also add match + specifications to a function. A match specification + comprises a pattern that the function arguments must + match, a guard expression that must evaluate to <c>true</c>, and an action to be performed. The default action is to send a trace message. If the pattern does not match or the guard - fails, the action will not be executed.</p> - <p>The <c><anno>MFA</anno></c> argument should be a tuple like - <c>{Module, Function, Arity}</c> or the atom <c>on_load</c> - (described below). It can be the module, function, and arity - for an exported function (or a BIF in any module). - The <c>'_'</c> atom can be used to mean any of that kind. - Wildcards can be used in any of the following ways:</p> + fails, the action is not executed.</p> + <p>Argument <c><anno>MFA</anno></c> is to be a tuple, such as + <c>{Module, Function, Arity}</c>, or the atom <c>on_load</c> + (described in the following). It can be the module, function, + and arity for a function (or a BIF in any module). + The atom <c>'_'</c> can be used as a wild card in any of the + following ways:</p> <taglist> <tag><c>{Module,Function,'_'}</c></tag> <item> - <p>All exported functions of any arity named <c>Function</c> + <p>All functions of any arity named <c>Function</c> in module <c>Module</c>.</p> </item> <tag><c>{Module,'_','_'}</c></tag> <item> - <p>All exported functions in module <c>Module</c>.</p> + <p>All functions in module <c>Module</c>.</p> </item> <tag><c>{'_','_','_'}</c></tag> <item> - <p>All exported functions in all loaded modules.</p> + <p>All functions in all loaded modules.</p> </item> </taglist> <p>Other combinations, such as <c>{Module,'_',Arity}</c>, are - not allowed. Local functions will match wildcards only if - the <c>local</c> option is in the <c><anno>FlagList</anno></c>.</p> - <p>If the <c><anno>MFA</anno></c> argument is the atom <c>on_load</c>, - the match specification and flag list will be used on all + not allowed. Local functions match wild cards only if + option <c>local</c> is in <c><anno>FlagList</anno></c>.</p> + <p>If argument <c><anno>MFA</anno></c> is the atom <c>on_load</c>, + the match specification and flag list are used on all modules that are newly loaded.</p> - <p>The <c><anno>MatchSpec</anno></c> argument can take any of the following - forms:</p> + <p>Argument <c><anno>MatchSpec</anno></c> can take the + following forms:</p> <taglist> <tag><c>false</c></tag> <item> - <p>Disable tracing for the matching function(s). Any match - specification will be removed.</p> + <p>Disables tracing for the matching functions. + Any match specification is removed.</p> </item> <tag><c>true</c></tag> <item> - <p>Enable tracing for the matching function(s).</p> + <p>Enables tracing for the matching functions.</p> </item> <tag><c><anno>MatchSpecList</anno></c></tag> <item> <p>A list of match specifications. An empty list is - equivalent to <c>true</c>. See the ERTS User's Guide - for a description of match specifications.</p> + equivalent to <c>true</c>. For a description of match + specifications, see the User's Guide.</p> </item> <tag><c>restart</c></tag> <item> - <p>For the <c><anno>FlagList</anno></c> option <c>call_count</c> and <c>call_time</c>: - restart the existing counters. The behaviour is undefined + <p>For the <c><anno>FlagList</anno></c> options <c>call_count</c> + and <c>call_time</c>: restarts + the existing counters. The behavior is undefined for other <c><anno>FlagList</anno></c> options.</p> </item> <tag><c>pause</c></tag> <item> - <p>For the <c><anno>FlagList</anno></c> option <c>call_count</c> and <c>call_time</c>: pause - the existing counters. The behaviour is undefined for - other <c>FlagList</c> options.</p> + <p>For the <c><anno>FlagList</anno></c> options + <c>call_count</c> and <c>call_time</c>: pauses + the existing counters. The behavior is undefined for + other <c><anno>FlagList</anno></c> options.</p> </item> </taglist> - <p>The <c><anno>FlagList</anno></c> parameter is a list of options. - The following options are allowed:</p> + <p>Parameter <c><anno>FlagList</anno></c> is a list of options. + The following are the valid options:</p> <taglist> <tag><c>global</c></tag> <item> - <p>Turn on or off call tracing for global function calls + <p>Turns on or off call tracing for global function calls (that is, calls specifying the module explicitly). Only - exported functions will match and only global calls will - generate trace messages. This is the default.</p> + exported functions match and only global calls + generate trace messages. <em>This is the default</em>.</p> </item> <tag><c>local</c></tag> <item> - <p>Turn on or off call tracing for all types of function - calls. Trace messages will be sent whenever any of + <p>Turns on or off call tracing for all types of function + calls. Trace messages are sent whenever any of the specified functions are called, regardless of how they - are called. If the <c>return_to</c> flag is set for - the process, a <c>return_to</c> message will also be sent + are called. If flag <c>return_to</c> is set for + the process, a <c>return_to</c> message is also sent when this function returns to its caller.</p> </item> <tag><c>meta | {meta, <anno>Pid</anno>}</c></tag> <item> - <p>Turn on or off meta tracing for all types of function - calls. Trace messages will be sent to the tracer process + <p>Turns on or off meta-tracing for all types of function + calls. Trace messages are sent to the tracer process or port <c><anno>Pid</anno></c> whenever any of the specified functions are called, regardless of how they are called. - If no <c><anno>Pid</anno></c> is specified, <c>self()</c> is used as a - default tracer process.</p> - <p>Meta tracing traces all processes and does not care + If no <c><anno>Pid</anno></c> is specified, + <c>self()</c> is used as a default tracer process.</p> + <p>Meta-tracing traces all processes and does not care about the process trace flags set by <c>trace/3</c>, the trace flags are instead fixed to <c>[call, timestamp]</c>.</p> - <p>The match spec function <c>{return_trace}</c> works with - meta trace and send its trace message to the same tracer - process.</p> + <p>The match specification function <c>{return_trace}</c> + works with meta-trace and sends its trace message to the + same tracer process.</p> </item> <tag><c>call_count</c></tag> <item> <p>Starts (<c><anno>MatchSpec</anno> == true</c>) or stops - (<c><anno>MatchSpec</anno> == false</c>) call count tracing for all - types of function calls. For every function a counter is + (<c><anno>MatchSpec</anno> == false</c>) + call count tracing for all + types of function calls. For every function, a counter is incremented when the function is called, in any process. No process trace flags need to be activated.</p> <p>If call count tracing is started while already running, - the count is restarted from zero. Running counters can be - paused with <c><anno>MatchSpec</anno> == pause</c>. Paused and running - counters can be restarted from zero with + the count is restarted from zero. To pause running + counters, use <c><anno>MatchSpec</anno> == pause</c>. + Paused and running counters can be restarted from zero with <c><anno>MatchSpec</anno> == restart</c>.</p> - <p>The counter value can be read with + <p>To read the counter value, use <seealso marker="#trace_info/2">erlang:trace_info/2</seealso>.</p> </item> <tag><c>call_time</c></tag> <item> <p>Starts (<c><anno>MatchSpec</anno> == true</c>) or stops - (<c><anno>MatchSpec</anno> == false</c>) call time tracing for all - types of function calls. For every function a counter is - incremented when the function is called. Time spent in the function - is accumulated in two other counters, seconds and micro-seconds. + (<c><anno>MatchSpec</anno> == false</c>) call time + tracing for all + types of function calls. For every function, a counter is + incremented when the function is called. + Time spent in the function is accumulated in + two other counters, seconds and microseconds. The counters are stored for each call traced process.</p> <p>If call time tracing is started while already running, - the count and time is restarted from zero. Running counters can be - paused with <c><anno>MatchSpec</anno> == pause</c>. Paused and running - counters can be restarted from zero with + the count and time is restarted from zero. To pause + running counters, use <c><anno>MatchSpec</anno> == pause</c>. + Paused and running counters can be restarted from zero with <c><anno>MatchSpec</anno> == restart</c>.</p> - <p>The counter value can be read with + <p>To read the counter value, use <seealso marker="#trace_info/2">erlang:trace_info/2</seealso>.</p> </item> - </taglist> - <p>The <c>global</c> and <c>local</c> options are mutually - exclusive and <c>global</c> is the default (if no options are - specified). The <c>call_count</c> and <c>meta</c> options - perform a kind of local tracing, and can also not be combined - with <c>global</c>. A function can be either globally or + <p>The options <c>global</c> and <c>local</c> are mutually + exclusive, and <c>global</c> is the default (if no options are + specified). The options <c>call_count</c> and <c>meta</c> + perform a kind of local tracing, and cannot be combined + with <c>global</c>. A function can be globally or locally traced. If global tracing is specified for a - specified set of functions; local, meta, call time and call count - tracing for the matching set of local functions will be - disabled, and vice versa.</p> + set of functions, then local, meta, call time, and call count + tracing for the matching set of local functions is + disabled, and conversely.</p> <p>When disabling trace, the option must match the type of trace - that is set on the function, so that local tracing must be - disabled with the <c>local</c> option and global tracing with - the <c>global</c> option (or no option at all), and so forth.</p> - <p>There is no way to directly change part of a match - specification list. If a function has a match specification, - you can replace it with a completely new one. If you need to - change an existing match specification, use the + set on the function. That is, local tracing must be + disabled with option <c>local</c> and global tracing with + option <c>global</c> (or no option), and so forth.</p> + <p>Part of a match specification list cannot be changed directly. + If a function has a match specification, it can be replaced + with a new one. To change an existing match specification, + use the BIF <seealso marker="#trace_info/2">erlang:trace_info/2</seealso> - BIF to retrieve the existing match specification.</p> - <p>Returns the number of exported functions that matched - the <c><anno>MFA</anno></c> argument. This will be zero if none matched at - all.</p> + to retrieve the existing match specification.</p> + <p>Returns the number of functions matching + argument <c><anno>MFA</anno></c>. This is zero if none matched.</p> </desc> </func> + <func> <name name="trunc" arity="1"/> - <fsummary>Return an integer by the truncating a number</fsummary> + <fsummary>Returns an integer by truncating a number</fsummary> <desc> - <p>Returns an integer by the truncating <c><anno>Number</anno></c>.</p> + <p>Returns an integer by truncating <c><anno>Number</anno></c>, + for example:</p> <pre> > <input>trunc(5.5).</input> 5</pre> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="tuple_size" arity="1"/> - <fsummary>Return the size of a tuple</fsummary> + <fsummary>Returns the size of a tuple.</fsummary> <desc> - <p>Returns an integer which is the number of elements in <c><anno>Tuple</anno></c>.</p> + <p>Returns an integer that is the number of elements in + <c><anno>Tuple</anno></c>, for example:</p> <pre> > <input>tuple_size({morni, mulle, bwange}).</input> 3</pre> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="tuple_to_list" arity="1"/> - <fsummary>Convert a tuple to a list</fsummary> + <fsummary>Converts a tuple to a list.</fsummary> <desc> - <p>Returns a list which corresponds to <c><anno>Tuple</anno></c>. - <c><anno>Tuple</anno></c> may contain any Erlang terms.</p> + <p>Returns a list corresponding to <c><anno>Tuple</anno></c>. + <c><anno>Tuple</anno></c> can contain any Erlang terms.</p> + <p>Example:</p> <pre> > <input>tuple_to_list({share, {'Ericsson_B', 163}}).</input> [share,{'Ericsson_B',163}]</pre> </desc> </func> + <func> <name name="universaltime" arity="0"/> - <fsummary>Current date and time according to Universal Time Coordinated (UTC)</fsummary> + <fsummary>Current date and time according to Universal Time Coordinated (UTC).</fsummary> <desc> <p>Returns the current date and time according to Universal - Time Coordinated (UTC), also called GMT, in the form + Time Coordinated (UTC) in the form <c>{{Year, Month, Day}, {Hour, Minute, Second}}</c> if - supported by the underlying operating system. If not, - <c>erlang:universaltime()</c> is equivalent to + supported by the underlying OS. + Otherwise <c>erlang:universaltime()</c> is equivalent to <c>erlang:localtime()</c>.</p> + <p>Example:</p> <pre> > <input>erlang:universaltime().</input> {{1996,11,6},{14,18,43}}</pre> </desc> </func> + <func> <name name="universaltime_to_localtime" arity="1"/> - <fsummary>Convert from Universal Time Coordinated (UTC) to local date and time</fsummary> + <fsummary>Converts from Universal Time Coordinated (UTC) to local date and time.</fsummary> <desc> <p>Converts Universal Time Coordinated (UTC) date and time to - local date and time, if this is supported by the underlying - OS. Otherwise, no conversion is done, and + local date and time in the form + <c>{{Year, Month, Day}, {Hour, Minute, Second}}</c> if + supported by the underlying OS. + Otherwise no conversion is done, and <c><anno>Universaltime</anno></c> is returned.</p> + <p>Example:</p> <pre> > <input>erlang:universaltime_to_localtime({{1996,11,6},{14,18,43}}).</input> {{1996,11,7},{15,18,43}}</pre> - <p>Failure: <c>badarg</c> if <c>Universaltime</c> does not denote - a valid date and time.</p> + <p>Failure: <c>badarg</c> if <c>Universaltime</c> denotes + an invalid date and time.</p> </desc> </func> + <func> <name name="unique_integer" arity="0"/> <fsummary>Get a unique integer value</fsummary> @@ -8221,23 +8853,23 @@ timestamp() -> Each integer value can of course be constructed by other means.</p> - <p>By default, i.e. when <c>[]</c> is passed as + <p>By default, when <c>[]</c> is passed as <c><anno>ModifierList</anno></c>, both negative and - positive integers will be returned. This is order - to be able to utilize the range of integers that do - not need to be heap allocated as much as possible. + positive integers can be returned. This in order + to utilize the range of integers that do + not need heap memory allocation as much as possible. By default the returned integers are also only - guaranteed to be unique, i.e., any integer returned - may be either smaller, or larger than previously + guaranteed to be unique, that is, any returned integer + can be smaller or larger than previously returned integers.</p> - <p>Currently valid <c><anno>Modifier</anno></c>s:</p> + <p>Valid <c><anno>Modifier</anno></c>s:</p> <taglist> <tag>positive</tag> <item><p>Return only positive integers.</p> <p>Note that by passing the <c>positive</c> modifier - you will get heap allocated integers (big-nums) + you will get heap allocated integers (bignums) quicker.</p> </item> @@ -8249,7 +8881,7 @@ timestamp() -> returned will always be larger than previously returned integers on the current runtime system instance.</p> - <p>These values can be used when ordering events + <p>These values can be used to determine order between events on the runtime system instance. That is, if both <c>X = erlang:unique_integer([monotonic])</c> and <c>Y = erlang:unique_integer([monotonic])</c> are @@ -8259,21 +8891,21 @@ timestamp() -> before <c>Y</c>.</p> <warning><p>Strictly monotonically increasing values are inherently quite expensive to generate and scales - poorly. This since the values needs to be - synchronized. That is, do not pass the <c>monotonic</c> + poorly. This is because the values need to be + synchronized between cpu cores. That is, do not pass the <c>monotonic</c> modifier unless you really need strictly monotonically increasing values.</p></warning> </item> </taglist> - <p>All currently valid <c><anno>Modifier</anno></c>s + <p>All valid <c><anno>Modifier</anno></c>s can be combined. Repeated (valid) <c><anno>Modifier</anno></c>s in the <c>ModifierList</c> are ignored.</p> <note><p>Note that the set of integers returned by - <c>unique_integer/1</c> using diffrent sets of + <c>unique_integer/1</c> using different sets of <c><anno>Modifier</anno></c>s <em>will overlap</em>. For example, by calling <c>unique_integer([monotonic])</c>, and <c>unique_integer([positive, monotonic])</c> @@ -8293,25 +8925,30 @@ timestamp() -> </func> <func> <name name="unlink" arity="1"/> - <fsummary>Remove a link, if there is one, to another process or port</fsummary> + <fsummary>Removes a link to another process or port.</fsummary> <desc> <p>Removes the link, if there is one, between the calling - process and the process or port referred to by <c><anno>Id</anno></c>.</p> + process and the process or port referred to by + <c><anno>Id</anno></c>.</p> <p>Returns <c>true</c> and does not fail, even if there is no - link to <c><anno>Id</anno></c>, or if <c><anno>Id</anno></c> does not exist.</p> - <p>Once <c>unlink(<anno>Id</anno>)</c> has returned it is guaranteed that + link to <c><anno>Id</anno></c>, or if <c><anno>Id</anno></c> + does not exist.</p> + <p>Once <c>unlink(<anno>Id</anno>)</c> has returned, + it is guaranteed that the link between the caller and the entity referred to by - <c><anno>Id</anno></c> has no effect on the caller in the future (unless - the link is setup again). If caller is trapping exits, an - <c>{'EXIT', <anno>Id</anno>, _}</c> message due to the link might have - been placed in the caller's message queue prior to the call, - though. Note, the <c>{'EXIT', <anno>Id</anno>, _}</c> message can be the - result of the link, but can also be the result of <c><anno>Id</anno></c> - calling <c>exit/2</c>. Therefore, it <em>may</em> be - appropriate to cleanup the message queue when trapping exits - after the call to <c>unlink(<anno>Id</anno>)</c>, as follow:</p> + <c><anno>Id</anno></c> has no effect on the caller + in the future (unless + the link is setup again). If the caller is trapping exits, an + <c>{'EXIT', <anno>Id</anno>, _}</c> message from the link + can have been placed in the caller's message queue before + the call.</p> + <p>Notice that the <c>{'EXIT', <anno>Id</anno>, _}</c> + message can be the + result of the link, but can also be the result of <c>Id</c> + calling <c>exit/2</c>. Therefore, it <em>can</em> be + appropriate to clean up the message queue when trapping exits + after the call to <c>unlink(<anno>Id</anno>)</c>, as follows:</p> <code type="none"> - unlink(Id), receive {'EXIT', Id, _} -> @@ -8320,23 +8957,25 @@ timestamp() -> true end</code> <note> - <p>Prior to OTP release R11B (erts version 5.5) <c>unlink/1</c> - behaved completely asynchronous, i.e., the link was active + <p>Prior to OTP release R11B (ERTS version 5.5) <c>unlink/1</c> + behaved completely asynchronously, i.e., the link was active until the "unlink signal" reached the linked entity. This - had one undesirable effect, though. You could never know when + had an undesirable effect, as you could never know when you were guaranteed <em>not</em> to be effected by the link.</p> - <p>Current behavior can be viewed as two combined operations: + <p>The current behavior can be viewed as two combined operations: asynchronously send an "unlink signal" to the linked entity and ignore any future results of the link.</p> </note> </desc> </func> + <func> <name name="unregister" arity="1"/> - <fsummary>Remove the registered name for a process (or port)</fsummary> + <fsummary>Removes the registered name for a process (or port).</fsummary> <desc> - <p>Removes the registered name <c><anno>RegName</anno></c>, associated with a - pid or a port identifier.</p> + <p>Removes the registered name <c><anno>RegName</anno></c> + associated with a + process identifier or a port identifier, for example:</p> <pre> > <input>unregister(db).</input> true</pre> @@ -8345,31 +8984,34 @@ true</pre> name.</p> </desc> </func> + <func> <name name="whereis" arity="1"/> - <fsummary>Get the pid (or port) with a given registered name</fsummary> + <fsummary>Gets the pid (or port) with a given registered name.</fsummary> <desc> - <p>Returns the pid or port identifier with the registered name - <c>RegName</c>. Returns <c>undefined</c> if the name is not - registered.</p> + <p>Returns the process identifier or port identifier with + the registered name <c>RegName</c>. Returns <c>undefined</c> + if the name is not registered.</p> + <p>Example:</p> <pre> > <input>whereis(db).</input> <0.43.0></pre> </desc> </func> + <func> <name name="yield" arity="0"/> - <fsummary>Let other processes get a chance to execute</fsummary> + <fsummary>Lets other processes get a chance to execute.</fsummary> <desc> - <p>Voluntarily let other processes (if any) get a chance to + <p>Voluntarily lets other processes (if any) get a chance to execute. Using <c>erlang:yield()</c> is similar to <c>receive after 1 -> ok end</c>, except that <c>yield()</c> is faster.</p> <warning><p>There is seldom or never any need to use this BIF, - especially in the SMP-emulator as other processes will have a - chance to run in another scheduler thread anyway. - Using this BIF without a thorough grasp of how the scheduler - works may cause performance degradation.</p></warning> + especially in the SMP emulator, as other processes have a + chance to run in another scheduler thread anyway. + Using this BIF without a thorough grasp of how the scheduler + works can cause performance degradation.</p></warning> </desc> </func> </funcs> diff --git a/erts/doc/src/erts_alloc.xml b/erts/doc/src/erts_alloc.xml index 376cae4a95..15b78ffa10 100644 --- a/erts/doc/src/erts_alloc.xml +++ b/erts/doc/src/erts_alloc.xml @@ -4,7 +4,7 @@ <cref> <header> <copyright> - <year>2002</year><year>2014</year> + <year>2002</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -260,19 +260,19 @@ <p>The following flags are available for configuration of <c>mseg_alloc</c>:</p> <taglist> - <tag><marker id="MMamcbf"><c><![CDATA[+MMamcbf <size>]]></c></marker></tag> + <tag><marker id="MMamcbf"/><c><![CDATA[+MMamcbf <size>]]></c></tag> <item> Absolute max cache bad fit (in kilobytes). A segment in the memory segment cache is not reused if its size exceeds the requested size with more than the value of this parameter. Default value is 4096. </item> - <tag><marker id="MMrmcbf"><c><![CDATA[+MMrmcbf <ratio>]]></c></marker></tag> + <tag><marker id="MMrmcbf"/><c><![CDATA[+MMrmcbf <ratio>]]></c></tag> <item> Relative max cache bad fit (in percent). A segment in the memory segment cache is not reused if its size exceeds the requested size with more than relative max cache bad fit percent of the requested size. Default value is 20.</item> - <tag><marker id="MMsco"><c><![CDATA[+MMsco true|false]]></c></marker></tag> + <tag><marker id="MMsco"/><c><![CDATA[+MMsco true|false]]></c></tag> <item> Set <seealso marker="#MMscs">super carrier</seealso> only flag. This flag defaults to <c>true</c>. When a super carrier is used and this @@ -292,7 +292,7 @@ disabled on halfword heap systems. This flag will be ignored on halfword heap systems. </item> - <tag><marker id="MMscrfsd"><c><![CDATA[+MMscrfsd <amount>]]></c></marker></tag> + <tag><marker id="MMscrfsd"/><c><![CDATA[+MMscrfsd <amount>]]></c></tag> <item> Set <seealso marker="#MMscs">super carrier</seealso> reserved free segment descriptors. This parameter defaults to <c>65536</c>. @@ -305,7 +305,7 @@ <c>erts_mmap</c> tuple part of the result from calling <seealso marker="erts:erlang#system_info_allocator_tuple">erlang:system_info({allocator, mseg_alloc})</seealso>. </item> - <tag><marker id="MMscrpm"><c><![CDATA[+MMscrpm true|false]]></c></marker></tag> + <tag><marker id="MMscrpm"/><c><![CDATA[+MMscrpm true|false]]></c></tag> <item> Set <seealso marker="#MMscs">super carrier</seealso> reserve physical memory flag. This flag defaults to <c>true</c>. When this flag is @@ -328,7 +328,7 @@ disabled on halfword heap systems. This flag will be ignored on halfword heap systems. </item> - <tag><marker id="MMscs"><c><![CDATA[+MMscs <size in MB>]]></c></marker></tag> + <tag><marker id="MMscs"/><c><![CDATA[+MMscs <size in MB>]]></c></tag> <item> Set super carrier size (in MB). The super carrier size defaults to zero; i.e, the super carrier is by default disabled. The super @@ -343,7 +343,7 @@ disabled on halfword heap systems. This flag will be ignored on halfword heap systems. </item> - <tag><marker id="MMmcs"><c><![CDATA[+MMmcs <amount>]]></c></marker></tag> + <tag><marker id="MMmcs"/><c><![CDATA[+MMmcs <amount>]]></c></tag> <item> Max cached segments. The maximum number of memory segments stored in the memory segment cache. Valid range is @@ -352,15 +352,15 @@ <p>The following flags are available for configuration of <c>sys_alloc</c>:</p> <taglist> - <tag><marker id="MYe"><c>+MYe true</c></marker></tag> + <tag><marker id="MYe"/><c>+MYe true</c></tag> <item> Enable <c>sys_alloc</c>. Note: <c>sys_alloc</c> cannot be disabled.</item> - <tag><marker id="MYm"><c>+MYm libc</c></marker></tag> + <tag><marker id="MYm"/><c>+MYm libc</c></tag> <item> <c>malloc</c> library to use. Currently only <c>libc</c> is available. <c>libc</c> enables the standard <c>libc</c> malloc implementation. By default <c>libc</c> is used.</item> - <tag><marker id="MYtt"><c><![CDATA[+MYtt <size>]]></c></marker></tag> + <tag><marker id="MYtt"/><c><![CDATA[+MYtt <size>]]></c></tag> <item> Trim threshold size (in kilobytes). This is the maximum amount of free memory at the top of the heap (allocated by @@ -372,7 +372,7 @@ trim threshold is 128. <em>Note:</em> This flag will only have any effect when the emulator has been linked with the GNU C library, and uses its <c>malloc</c> implementation.</item> - <tag><marker id="MYtp"><c><![CDATA[+MYtp <size>]]></c></marker></tag> + <tag><marker id="MYtp"/><c><![CDATA[+MYtp <size>]]></c></tag> <item> Top pad size (in kilobytes). This is the amount of extra memory that will be allocated by <c>malloc</c> when @@ -390,7 +390,7 @@ subsystem identifier, only the specific allocator identified will be effected:</p> <taglist> - <tag><marker id="M_acul"><c><![CDATA[+M<S>acul <utilization>|de]]></c></marker></tag> + <tag><marker id="M_acul"/><c><![CDATA[+M<S>acul <utilization>|de]]></c></tag> <item> Abandon carrier utilization limit. A valid <c><![CDATA[<utilization>]]></c> is an integer in the range @@ -422,7 +422,7 @@ allocators based on the <c>alloc_util</c> framework with the exception of <c>temp_alloc</c> (which would be pointless). </item> - <tag><marker id="M_as"><c><![CDATA[+M<S>as bf|aobf|aoff|aoffcbf|aoffcaobf|gf|af]]></c></marker></tag> + <tag><marker id="M_as"/><c><![CDATA[+M<S>as bf|aobf|aoff|aoffcbf|aoffcaobf|gf|af]]></c></tag> <item> Allocation strategy. Valid strategies are <c>bf</c> (best fit), <c>aobf</c> (address order best fit), <c>aoff</c> (address order first fit), @@ -430,7 +430,7 @@ <c>aoffcaobf</c> (address order first fit carrier address order best fit), <c>gf</c> (good fit), and <c>af</c> (a fit). See <seealso marker="#strategy">the description of allocation strategies</seealso> in "the <c>alloc_util</c> framework" section.</item> - <tag><marker id="M_asbcst"><c><![CDATA[+M<S>asbcst <size>]]></c></marker></tag> + <tag><marker id="M_asbcst"/><c><![CDATA[+M<S>asbcst <size>]]></c></tag> <item> Absolute singleblock carrier shrink threshold (in kilobytes). When a block located in an @@ -438,23 +438,23 @@ will be left unchanged if the amount of unused memory is less than this threshold; otherwise, the carrier will be shrunk. See also <seealso marker="#M_rsbcst">rsbcst</seealso>.</item> - <tag><marker id="M_e"><c><![CDATA[+M<S>e true|false]]></c></marker></tag> + <tag><marker id="M_e"/><c><![CDATA[+M<S>e true|false]]></c></tag> <item> Enable allocator <c><![CDATA[<S>]]></c>.</item> - <tag><marker id="M_lmbcs"><c><![CDATA[+M<S>lmbcs <size>]]></c></marker></tag> + <tag><marker id="M_lmbcs"/><c><![CDATA[+M<S>lmbcs <size>]]></c></tag> <item> Largest (<c>mseg_alloc</c>) multiblock carrier size (in kilobytes). See <seealso marker="#mseg_mbc_sizes">the description on how sizes for mseg_alloc multiblock carriers are decided</seealso> in "the <c>alloc_util</c> framework" section. On 32-bit Unix style OS this limit can not be set higher than 128 megabyte.</item> - <tag><marker id="M_mbcgs"><c><![CDATA[+M<S>mbcgs <ratio>]]></c></marker></tag> + <tag><marker id="M_mbcgs"/><c><![CDATA[+M<S>mbcgs <ratio>]]></c></tag> <item> (<c>mseg_alloc</c>) multiblock carrier growth stages. See <seealso marker="#mseg_mbc_sizes">the description on how sizes for mseg_alloc multiblock carriers are decided</seealso> in "the <c>alloc_util</c> framework" section.</item> - <tag><marker id="M_mbsd"><c><![CDATA[+M<S>mbsd <depth>]]></c></marker></tag> + <tag><marker id="M_mbsd"/><c><![CDATA[+M<S>mbsd <depth>]]></c></tag> <item> Max block search depth. This flag has effect only if the good fit strategy has been selected for allocator @@ -464,40 +464,40 @@ search depth sets a limit on the maximum number of blocks to inspect in a free list during a search for suitable block satisfying the request.</item> - <tag><marker id="M_mmbcs"><c><![CDATA[+M<S>mmbcs <size>]]></c></marker></tag> + <tag><marker id="M_mmbcs"/><c><![CDATA[+M<S>mmbcs <size>]]></c></tag> <item> Main multiblock carrier size. Sets the size of the main multiblock carrier for allocator <c><![CDATA[<S>]]></c>. The main multiblock carrier is allocated via <c><![CDATA[sys_alloc]]></c> and is never deallocated.</item> - <tag><marker id="M_mmmbc"><c><![CDATA[+M<S>mmmbc <amount>]]></c></marker></tag> + <tag><marker id="M_mmmbc"/><c><![CDATA[+M<S>mmmbc <amount>]]></c></tag> <item> Max <c>mseg_alloc</c> multiblock carriers. Maximum number of multiblock carriers allocated via <c>mseg_alloc</c> by allocator <c><![CDATA[<S>]]></c>. When this limit has been reached, new multiblock carriers will be allocated via <c>sys_alloc</c>.</item> - <tag><marker id="M_mmsbc"><c><![CDATA[+M<S>mmsbc <amount>]]></c></marker></tag> + <tag><marker id="M_mmsbc"/><c><![CDATA[+M<S>mmsbc <amount>]]></c></tag> <item> Max <c>mseg_alloc</c> singleblock carriers. Maximum number of singleblock carriers allocated via <c>mseg_alloc</c> by allocator <c><![CDATA[<S>]]></c>. When this limit has been reached, new singleblock carriers will be allocated via <c>sys_alloc</c>.</item> - <tag><marker id="M_ramv"><c><![CDATA[+M<S>ramv <bool>]]></c></marker></tag> + <tag><marker id="M_ramv"/><c><![CDATA[+M<S>ramv <bool>]]></c></tag> <item> Realloc always moves. When enabled, reallocate operations will more or less be translated into an allocate, copy, free sequence. This often reduce memory fragmentation, but costs performance. </item> - <tag><marker id="M_rmbcmt"><c><![CDATA[+M<S>rmbcmt <ratio>]]></c></marker></tag> + <tag><marker id="M_rmbcmt"/><c><![CDATA[+M<S>rmbcmt <ratio>]]></c></tag> <item> Relative multiblock carrier move threshold (in percent). When a block located in a multiblock carrier is shrunk, the block will be moved if the ratio of the size of the returned memory compared to the previous size is more than this threshold; otherwise, the block will be shrunk at current location.</item> - <tag><marker id="M_rsbcmt"><c><![CDATA[+M<S>rsbcmt <ratio>]]></c></marker></tag> + <tag><marker id="M_rsbcmt"/><c><![CDATA[+M<S>rsbcmt <ratio>]]></c></tag> <item> Relative singleblock carrier move threshold (in percent). When a block located in a singleblock carrier is shrunk to @@ -506,7 +506,7 @@ the block will be left unchanged in the singleblock carrier if the ratio of unused memory is less than this threshold; otherwise, it will be moved into a multiblock carrier. </item> - <tag><marker id="M_rsbcst"><c><![CDATA[+M<S>rsbcst <ratio>]]></c></marker></tag> + <tag><marker id="M_rsbcst"/><c><![CDATA[+M<S>rsbcst <ratio>]]></c></tag> <item> Relative singleblock carrier shrink threshold (in percent). When a block located in an <c>mseg_alloc</c> @@ -514,20 +514,20 @@ unchanged if the ratio of unused memory is less than this threshold; otherwise, the carrier will be shrunk. See also <seealso marker="#M_asbcst">asbcst</seealso>.</item> - <tag><marker id="M_sbct"><c><![CDATA[+M<S>sbct <size>]]></c></marker></tag> + <tag><marker id="M_sbct"/><c><![CDATA[+M<S>sbct <size>]]></c></tag> <item> Singleblock carrier threshold. Blocks larger than this threshold will be placed in singleblock carriers. Blocks smaller than this threshold will be placed in multiblock carriers. On 32-bit Unix style OS this threshold can not be set higher than 8 megabytes.</item> - <tag><marker id="M_smbcs"><c><![CDATA[+M<S>smbcs <size>]]></c></marker></tag> + <tag><marker id="M_smbcs"/><c><![CDATA[+M<S>smbcs <size>]]></c></tag> <item> Smallest (<c>mseg_alloc</c>) multiblock carrier size (in kilobytes). See <seealso marker="#mseg_mbc_sizes">the description on how sizes for mseg_alloc multiblock carriers are decided</seealso> in "the <c>alloc_util</c> framework" section.</item> - <tag><marker id="M_t"><c><![CDATA[+M<S>t true|false]]></c></marker></tag> + <tag><marker id="M_t"/><c><![CDATA[+M<S>t true|false]]></c></tag> <item> <p>Multiple, thread specific instances of the allocator. This option will only have any effect on the runtime system @@ -544,20 +544,20 @@ <c>alloc_util</c>, i.e. all allocators based on <c>alloc_util</c> will be effected:</p> <taglist> - <tag><marker id="Muycs"><c><![CDATA[+Muycs <size>]]></c></marker></tag> + <tag><marker id="Muycs"/><c><![CDATA[+Muycs <size>]]></c></tag> <item> <c>sys_alloc</c> carrier size. Carriers allocated via <c>sys_alloc</c> will be allocated in sizes which are multiples of the <c>sys_alloc</c> carrier size. This is not true for main multiblock carriers and carriers allocated during a memory shortage, though.</item> - <tag><marker id="Mummc"><c><![CDATA[+Mummc <amount>]]></c></marker></tag> + <tag><marker id="Mummc"/><c><![CDATA[+Mummc <amount>]]></c></tag> <item> Max <c>mseg_alloc</c> carriers. Maximum number of carriers placed in separate memory segments. When this limit has been reached, new carriers will be placed in memory retrieved from <c>sys_alloc</c>.</item> - <tag><marker id="Musac"><c><![CDATA[+Musac <bool>]]></c></marker></tag> + <tag><marker id="Musac"/><c><![CDATA[+Musac <bool>]]></c></tag> <item> Allow <c>sys_alloc</c> carriers. By default <c>true</c>. If set to <c>false</c>, <c>sys_alloc</c> carriers will never be @@ -565,19 +565,19 @@ </taglist> <p>Instrumentation flags:</p> <taglist> - <tag><marker id="Mim"><c>+Mim true|false</c></marker></tag> + <tag><marker id="Mim"/><c>+Mim true|false</c></tag> <item> A map over current allocations is kept by the emulator. The allocation map can be retrieved via the <c>instrument</c> module. <c>+Mim true</c> implies <c>+Mis true</c>. <c>+Mim true</c> is the same as <seealso marker="erl#instr">-instr</seealso>.</item> - <tag><marker id="Mis"><c>+Mis true|false</c></marker></tag> + <tag><marker id="Mis"/><c>+Mis true|false</c></tag> <item> Status over allocated memory is kept by the emulator. The allocation status can be retrieved via the <c>instrument</c> module.</item> - <tag><marker id="Mit"><c>+Mit X</c></marker></tag> + <tag><marker id="Mit"/><c>+Mit X</c></tag> <item> Reserved for future use. Do <em>not</em> use this flag.</item> </taglist> @@ -587,7 +587,7 @@ </note> <p>Other flags:</p> <taglist> - <tag><marker id="Mea"><c>+Mea min|max|r9c|r10b|r11b|config</c></marker></tag> + <tag><marker id="Mea"/><c>+Mea min|max|r9c|r10b|r11b|config</c></tag> <item> <taglist> <tag><c>min</c></tag> @@ -617,7 +617,7 @@ </item> </taglist> </item> - <tag><marker id="Mlpm"><c>+Mlpm all|no</c></marker></tag> + <tag><marker id="Mlpm"/><c>+Mlpm all|no</c></tag> <item>Lock physical memory. The default value is <c>no</c>, i.e., no physical memory will be locked. If set to <c>all</c>, all memory mappings made by the runtime system, will be locked into diff --git a/erts/doc/src/escript.xml b/erts/doc/src/escript.xml index 46110333f9..f12f76890c 100644 --- a/erts/doc/src/escript.xml +++ b/erts/doc/src/escript.xml @@ -4,7 +4,7 @@ <comref> <header> <copyright> - <year>2007</year><year>2014</year> + <year>2007</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -96,8 +96,8 @@ $ <input>escript factorial 5</input> </pre> <note><p> The encoding specified by the above mentioned comment applies to the script itself. The encoding of the - I/O-server, however, has to be set explicitly like this: -<code>io:setopts([{encoding, unicode}])</code></p> + I/O-server, however, has to be set explicitly like this:</p> +<code>io:setopts([{encoding, unicode}])</code> <p>The default encoding of the I/O-server for <c>standard_io</c> is <c>latin1</c> since the script runs in a non-interactive terminal diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml index 2d96ed6105..baf4e82b4f 100644 --- a/erts/doc/src/notes.xml +++ b/erts/doc/src/notes.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2004</year><year>2013</year> + <year>2004</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -31,6 +31,646 @@ </header> <p>This document describes the changes made to the ERTS application.</p> + +<section><title>Erts 7.3.1.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix scheduler deadlock bug in <c>ets:update_counter/4</c> + when key is not found and inserting the default object + causes the table to grow.</p> + <p> + Own Id: OTP-13731 Aux Id: ERL-188 </p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 7.3.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + <c>process_info(Pid, last_calls)</c> did not work for + <c>Pid /= self()</c>.</p> + <p> + Own Id: OTP-13418</p> + </item> + <item> + <p> + Make sure to create a crash dump when running out of + memory. This was accidentally removed in the erts-7.3 + release.</p> + <p> + Own Id: OTP-13419</p> + </item> + <item> + <p> + Schedulers could be woken by a premature timeout on + Linux. This premature wakeup was however harmless.</p> + <p> + Own Id: OTP-13420</p> + </item> + <item> + <p> + A process communicating with a port via one of the + <c>erlang:port_*</c> BIFs could potentially end up in an + inconsistent state if the port terminated during the + communication. When this occurred the process could later + block in a <c>receive</c> even though it had messages + matching in its message queue.</p> + <p> + This bug was introduced in erts version 5.10 (OTP R16A).</p> + <p> + Own Id: OTP-13424 Aux Id: OTP-10336 </p> + </item> + <item> + <p> + The reference count of a process structure could under + rare circumstances be erroneously managed. When this + happened invalid memory accesses occurred.</p> + <p> + Own Id: OTP-13446</p> + </item> + <item> + <p> + Fix race between <c>process_flag(trap_exit,true)</c> and + a received exit signal.</p> + <p> + A process could terminate due to exit signal even though + <c>process_flag(trap_exit,true)</c> had returned. A very + specific timing between call to <c>process_flag/2</c> and + exit signal from another scheduler was required for this + to happen.</p> + <p> + Own Id: OTP-13452</p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 7.3</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The '-path' flag to 'erl' has been documented. This flag + replaces the path specified in the boot script. It has + always existed, but was earlier only documented in SASL + (script).</p> + <p> + Own Id: OTP-13060</p> + </item> + <item> + <p> + The <c>call_time</c> tracing functionality internally + used a time based on OS system time in order to measure + call time which could cause erroneous results if OS + system time was changed during tracing.</p> + <p> + This functionality now use Erlang monotonic time in order + to measure time. Besides fixing the erroneous results due + to OS system time being used, the results are often also + better since Erlang monotonic time often has better + accuracy and precision.</p> + <p> + Own Id: OTP-13216</p> + </item> + <item> + <p> + Fix behaviour of -delay_write command line switch of + epmd, which is used for debugging - in some cases epmd + was sleeping twice the requested amount of time.</p> + <p> + Own Id: OTP-13220</p> + </item> + <item> + <p> + Fix race between timeout and exit signal that could cause + a process to ignore the exit signal and continue + execution. Bug exist since OTP 18.0.</p> + <p> + Own Id: OTP-13245</p> + </item> + <item> + <p> + Fix bug in <c>erlang:halt/1,2</c> for large exit status + values, causing either <c>badarg</c> (on 32-bit) or exit + with a crash dump and/or core dump (on 64-bit). Make + <c>erlang:halt/1,2</c> tolerate any non negative integer + as exit status and truncate high order bits if the OS + does not support it.</p> + <p> + Own Id: OTP-13251 Aux Id: ERL-49 </p> + </item> + <item> + <p> + <seealso + marker="kernel:gen_tcp#accept/2"><c>gen_tcp:accept/2</c></seealso> + was not <seealso + marker="erts:time_correction#Time_Warp_Safe_Code">time + warp safe</seealso>. This since it used the same time as + returned by <seealso + marker="erts:erlang#now/0"><c>erlang:now/0</c></seealso> + when calculating timeout. This has now been fixed.</p> + <p> + Own Id: OTP-13254 Aux Id: OTP-11997, OTP-13222 </p> + </item> + <item> + <p> + Fix faulty error handling when writing to a compressed + file.</p> + <p> + Own Id: OTP-13270</p> + </item> + <item> + <p> + Fix sendfile usage for large files on FreeBSD</p> + <p> + Own Id: OTP-13271</p> + </item> + <item> + <p> + Fix bug that could cause + <c>process_info(P,current_location)</c> to crash emulator + for hipe compiled modules.</p> + <p> + Own Id: OTP-13282 Aux Id: ERL-79 </p> + </item> + <item> + <p> + Out of memory errors have been changed to cause an exit + instead of abort.</p> + <p> + Own Id: OTP-13292</p> + </item> + <item> + <p> + When calling <c>garbage_collect/[1,2]</c> or + <c>check_process_code/[2,3]</c> from a process with a + higher priority than the priority of the process operated + on, the run queues could end up in an inconsistent state. + This bug has now been fixed.</p> + <p> + Own Id: OTP-13298 Aux Id: OTP-11388 </p> + </item> + <item> + <p> + A workaround for an issue with older gcc versions (less + than 5) and inline assembly on 32-bit x86 caused an + emulator crash when it had been compiled with a newer gcc + version. An improved <c>configure</c> test, run when + building OTP, now detects whether the workaround should + be used or not.</p> + <p> + Own Id: OTP-13326 Aux Id: ERL-80 </p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>Introduced new statistics functionality in order to + more efficiently retrieve information about run able and + active processes and ports. For more information see:</p> + <list> <item><seealso + marker="erlang#statistics_total_run_queue_lengths"><c>statistics(total_run_queue_lengths)</c></seealso></item> + <item><seealso + marker="erlang#statistics_run_queue_lengths"><c>statistics(run_queue_lengths)</c></seealso></item> + <item><seealso + marker="erlang#statistics_total_active_tasks"><c>statistics(total_active_tasks)</c></seealso></item> + <item><seealso + marker="erlang#statistics_active_tasks"><c>statistics(active_tasks)</c></seealso></item> + </list> + <p> + Own Id: OTP-13201</p> + </item> + <item> + <p> + Time warp safety improvements.</p> + <p> + Introduced the options <c>monotonic_timestamp</c>, and + <c>strict_monotonic_timestamp</c> to the trace, + sequential trace, and system profile functionality. This + since the already existing <c>timestamp</c> option is not + time warp safe.</p> + <p> + Introduced the option <c>safe_fixed_monotonic_time</c> to + <c>ets:info/2</c> and <c>dets:info/2</c>. This since the + already existing <c>safe_fixed</c> option is not time + warp safe.</p> + <p> + Own Id: OTP-13222 Aux Id: OTP-11997 </p> + </item> + <item> + <p> + Fix a register race where down nodes goes undetected in + epmd</p> + <p> + Own Id: OTP-13301</p> + </item> + <item> + <p> + Improved the gcc inline assembly implementing double word + atomic compare and exchange on x86/x86_64 so that it also + can be used when compiling with clang.</p> + <p> + Own Id: OTP-13336</p> + </item> + <item> + <p> + An optimization preventing a long wait for a scheduler + thread looking up information about a process executing + on another scheduler thread had unintentionally been lost + in erts-5.10 (OTP R16A). This optimization has now been + reintroduced.</p> + <p> + Own Id: OTP-13365 Aux Id: OTP-9892 </p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 7.2.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Revert "Fix erroneous splitting of emulator path"</p> + <p> + Own Id: OTP-13202</p> + </item> + <item> + <p> + Fix HiPE enabled emulator for FreeBSD.</p> + <p> + Own Id: OTP-13204 Aux Id: pr926 </p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 7.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Small documentation fixes</p> + <p> + Own Id: OTP-13017</p> + </item> + <item> + <p> + Fix memory corruption bug caused by disabling + distribution and then re-enable distribution with a node + name that has previously been used by a remote node.</p> + <p> + Own Id: OTP-13076 Aux Id: seq12959 </p> + </item> + <item> + <p> + Renamed variables with name bool as Visual Studio 2015 + now treats this is a keyword.</p> + <p> + Own Id: OTP-13079</p> + </item> + <item> + <p><c>erl_prim_loader</c> has not supported custom + loaders for several releases. In the documentation for + <c>erl_prim_loader</c>, all references to custom loaders + have now been removed.</p> + <p> + Own Id: OTP-13102</p> + </item> + <item> + <p> + Fixed compilation of erts together with libc versions + that do not define __uint32_t.</p> + <p> + Own Id: OTP-13105</p> + </item> + <item> + <p> + erl -make now returns non-zero exit codes on failure</p> + <p> + Own Id: OTP-13107</p> + </item> + <item> + <p> + Fix crash on init:restart in embedded mode caused by + on_load handler process not being relaunched leading to + load failure for modules such as crypto and asn1rt_nif + that need it to be present for correct NIF loading.</p> + <p> + Own Id: OTP-13115</p> + </item> + <item> + <p> + Fix maps decode in erlang:binary_to_term/1</p> + <p>Decoding a term with a large (HAMT) map in an small + (FLAT) map could cause a critical error if the external + format was not produced by beam.</p> + <p> + Own Id: OTP-13125</p> + </item> + <item> + <p> + Fix very rare bug in GC when big maps with a lot of hash + collisions from a remote node are waiting in inner + message queue.</p> + <p> + Own Id: OTP-13146</p> + </item> + <item> + <p> + Fixed a bug that could cause a crash dump to become + almost empty.</p> + <p> + Own Id: OTP-13150</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> Updated the xmllint target to just check the xml + files with real documentation content.<br/> Corrected + some errors and added some missing target in the DTD's. + </p> + <p> + Own Id: OTP-13026</p> + </item> + <item> + <p> + Add function enif_getenv to read OS environment variables + in a portable way from NIFs.</p> + <p> + Own Id: OTP-13147</p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 7.1</title> + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix bug in ETS that could cause stray objects marked for + deletion to occasionally be missed by the cleanup done by + <c>safe_fixtable(_,false)</c>.</p> + <p> + Own Id: OTP-12870</p> + </item> + <item> + <p> + Fixed VM crash that could occur if a trace port was + linked to a process, and the trace port terminated + abnormally while handling a trace message. This bug has + always existed in the runtime system with SMP support.</p> + <p> + Own Id: OTP-12901</p> + </item> + <item> + <p> + Instead of aborting, the vm now creates a crash dump when + a system process is terminated.</p> + <p> + Own Id: OTP-12934</p> + </item> + <item> + <p> + Fixed a rare emulator dead lock that occurred when + erlang:process_flag(priority,...) was called by a process + that was also scheduled for an internal system activity.</p> + <p> + Own Id: OTP-12943</p> + </item> + <item> + <p> + The runtime system on various posix platforms (except for + Linux and Solaris) could crash when large amounts of + file-descriptors were in use.</p> + <p> + Own Id: OTP-12954</p> + </item> + <item> + <p> + A beam file compiled by hipe for an incompatible runtime + system was sometimes not rejected by the loader, which + could lead to vm crash. This fix will also allow the same + hipe compiler to be used by both normal and debug-built + vm.</p> + <p> + Own Id: OTP-12962</p> + </item> + <item> + <p> + Fix bug in <c>maps:merge/2</c> when called by hipe + compiled code that could cause vm crash. Bug exists since + erts-7.0 (OTP 18.0).</p> + <p> + Own Id: OTP-12965</p> + </item> + <item> + <p> + When tracing with <c>process_dump</c> option, the VM + could abort if there was an ongoing binary match + somewhere in the call stack of the traced process.</p> + <p> + Own Id: OTP-12968</p> + </item> + <item> + <p> + Fixed possible output deadlock in tty driver when hitting + "CTRL-C" in a non-smp emulator shell on unix.</p> + <p> + Own Id: OTP-12987 Aux Id: Seq12947 </p> + </item> + <item> + <p> + Fix <c>binary_to_integer</c> to throw badarg for "+" and + "-" similar to <c>list_to_integer</c>.</p> + <p> + Own Id: OTP-12988</p> + </item> + <item> + <p> + Suppress warning of unused argument when using macro + enif_make_pid.</p> + <p> + Own Id: OTP-12989</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Changed default clock source used for OS system time on + MacOS X to <c>gettimeofday()</c> in order to improve + performance. The system can be configured during build to + use the previously used higher resolution clock source by + passing the switch <seealso + marker="doc/installation_guide:INSTALL#Advanced-configuration-and-build-of-ErlangOTP_Configuring"><c>--with-clock-resolution=high</c></seealso> + when configuring the build.</p> + <p> + Own Id: OTP-12945 Aux Id: OTP-12892 </p> + </item> + <item> + <p> + Added the <c>configure</c> option <seealso + marker="doc/installation_guide:INSTALL#Advanced-configuration-and-build-of-ErlangOTP_Configuring"><c>--disable-saved-compile-time</c></seealso> + which disables saving of compile date and time in the + emulator binary.</p> + <p> + Own Id: OTP-12971</p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 7.0.3</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fixed a binary memory leak when printing to shell using + the tty driver (i.e. not -oldshell).</p> + <p> + Own Id: OTP-12941</p> + </item> + <item> + <p> + Fix a bug where the standard error port sometimes crashes + with eagain as the reason.</p> + <p> + Own Id: OTP-12942</p> + </item> + <item> + <p> + When tracing with <c>process_dump</c> option, the VM + could abort if there was an ongoing binary match + somewhere in the call stack of the traced process./</p> + <p> + Own Id: OTP-12968</p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 7.0.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + A process could end up in an inconsistent half exited + state in the runtime system without SMP support. This + could occur if the processes was traced by a port that it + also was linked to, and the port terminated abnormally + while handling a trace message for the process.</p> + <p> + This bug has always existed in the runtime system without + SMP support, but never in the runtime system with SMP + support.</p> + <p> + Own Id: OTP-12889 Aux Id: seq12885 </p> + </item> + <item> + <p> + Removed unnecessary copying of data when retrieving + corrected Erlang monotonic time.</p> + <p> + Own Id: OTP-12894</p> + </item> + <item> + <p> + Changed default OS monotonic clock source chosen at build + time. This in order to improve performance. The behavior + will now on most systems be that (both OS and Erlang) + monotonic time stops when the system is suspended.</p> + <p> + If you prefer that monotonic time elapse during suspend + of the machine, you can pass the command line argument + <c>--enable-prefer-elapsed-monotonic-time-during-suspend</c> + to <c>configure</c> when building Erlang/OTP. The + configuration stage will try to find such a clock source, + but might not be able to find it. Note that there might + be a performance penalty associated with such a clock + source.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-12895</p> + </item> + <item> + <p> + <c>erlang:system_info(end_time)</c> returned a faulty + value on 32-bit architectures.</p> + <p> + Own Id: OTP-12896</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + The <c>configure</c> command line argument + <c>--enable-gettimeofday-as-os-system-time</c> has been + added which force usage of <c>gettimeofday()</c> for OS + system time. This will improve performance of + <c>os:system_time()</c> and <c>os:timestamp()</c> on + MacOS X, at the expense of worse accuracy, resolution and + precision of Erlang monotonic time, Erlang system time, + and OS system time.</p> + <p> + Own Id: OTP-12892</p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 7.0.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix a rare hanging of the VM seen to happen just after + emulator start. Bug exists since R14.</p> + <p> + Own Id: OTP-12859 Aux Id: seq12882 </p> + </item> + </list> + </section> + +</section> + <section><title>Erts 7.0</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -462,19 +1102,20 @@ </item> <item> <p> - Use persistent hashmaps for large Maps <p>Maps will use a + Use persistent hashmaps for large Maps</p> + <p>Maps will use a persistent hashmap implementation when the number of pairs in a Map becomes sufficiently large. The change will occur when a Map reaches 33 pairs in size but this - limit might change in the future.</p></p> - <p>The most significant impact for the user by this + limit might change in the future.</p> + <p>The most significant impact for the user by this change is speed, and to a lesser degree memory consumption and introspection of Maps. Memory consumption size is probalistic but lesser than <c>gb_trees</c> or <c>dict</c> for instance. Any other impacts will be transparent for the user except for the following changes.</p> - <p>Semantics of Maps have changed in two incompatible + <p>Semantics of Maps have changed in two incompatible ways compared to the experimental implementation in OTP 17:</p> <list> <item>Hashing of maps is done different by <c>erlang:phash2/1,2</c>, <c>erlang:phash/1</c> and @@ -734,6 +1375,42 @@ </section> +<section><title>Erts 6.4.1.5</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fixed a bug that could cause a crash dump to become + almost empty.</p> + <p> + Own Id: OTP-13150</p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 6.4.1.4</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The 'raw' socket option could not be used multiple times + in one call to any e.g gen_tcp function because only one + of the occurrences were used. This bug has been fixed, + and also a small bug concerning propagating error codes + from within inet:setopts/2.</p> + <p> + Own Id: OTP-11482 Aux Id: seq12872 </p> + </item> + </list> + </section> + +</section> + + <section><title>Erts 6.4.1</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -1122,7 +1799,7 @@ <p> Improved support for atomic memory operations provided by the <url - href="https://github.com/ivmai/libatomic_ops/"><c>libatomic_ops</c></url> + href="https://github.com/ivmai/libatomic_ops/">libatomic_ops</url> library. Most importantly support for use of native double word atomics when implemented by <c>libatomic_ops</c> (for example, implemented for ARM).</p> @@ -2089,22 +2766,28 @@ <p> EEP43: New data type - Maps</p> <p> - With Maps you may for instance: <taglist> <item><c>M0 = - #{ a => 1, b => 2}, % create - associations</c></item> <item><c>M1 = M0#{ a := 10 }, % - update values</c></item> <item><c>M2 = M1#{ "hi" => - "hello"}, % add new associations</c></item> <item><c>#{ - "hi" := V1, a := V2, b := V3} = M2. % match keys with - values</c></item> </taglist></p> + With Maps you may for instance:</p> + <taglist> + <tag/> <item><c>M0 = #{ a => 1, b => 2}, % create + associations</c></item> + <tag/><item><c>M1 = M0#{ a := 10 }, % update values</c></item> + <tag/><item><c>M2 = M1#{ "hi" => + "hello"}, % add new associations</c></item> + <tag/><item><c>#{ "hi" := V1, a := V2, b := V3} = M2. + % match keys with values</c></item> + </taglist> <p> For information on how to use Maps please see Map Expressions in the <seealso marker="doc/reference_manual:expressions#map_expressions"> Reference Manual</seealso>.</p> <p> The current implementation is without the following - features: <taglist> <item>No variable keys</item> - <item>No single value access</item> <item>No map - comprehensions</item> </taglist></p> + features:</p> + <taglist> + <tag/><item>No variable keys</item> + <tag/><item>No single value access</item> + <tag/><item>No map comprehensions</item> + </taglist> <p> Note that Maps is <em>experimental</em> during OTP 17.0.</p> <p> @@ -4264,8 +4947,7 @@ <p> Fix erl_prim_loader errors in handling of primary archive. The following errors have been corrected:</p> - <p> - <list> <item> If primary archive was named "xxx", then a + <list> <item> If primary archive was named "xxx", then a file in the same directory named "xxxyyy" would be interpreted as a file named "yyy" inside the archive. </item> <item> erl_prim_loader did not correctly create @@ -4280,7 +4962,8 @@ erl_prim_loader:list_dir/1 would sometimes return an empty string inside the file list. This was a virtual element representing the top directory of the archive. - This has been removed. </item> </list></p> + This has been removed. </item> + </list> <p> Thanks to Tuncer Ayaz and Shunichi Shinohara for reporting and co-authoring corrections.</p> @@ -6723,12 +7406,12 @@ Own Id: OTP-8726 Aux Id: seq11617 </p> </item> <item> - <p>Fix libm linking with --as-needed flag + <p>Fix libm linking with --as-needed flag</p> <p> When building with "--as-needed" linker flags on Linux the build will fail. This has now been fixed.</p> <p> - (Thanks to Christian Faulhammer)</p></p> + (Thanks to Christian Faulhammer)</p> <p> Own Id: OTP-8728</p> </item> diff --git a/erts/doc/src/time_correction.xml b/erts/doc/src/time_correction.xml index aed38fbb92..236fe679cb 100644 --- a/erts/doc/src/time_correction.xml +++ b/erts/doc/src/time_correction.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>1999</year><year>2014</year> + <year>1999</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -35,31 +35,35 @@ <section> <title>New Extended Time Functionality</title> - <note><p>As of OTP 18 (ERTS version 7.0) the time functionality of - Erlang has been extended. This both includes a + <note><p>As of OTP 18 (<c>ERTS</c> version 7.0) the time functionality of + Erlang has been extended. This includes a <seealso marker="#The_New_Time_API">new API</seealso> - for time, as well as + for time and <seealso marker="#Time_Warp_Modes">time warp - modes</seealso> which alters the behavior of the system when + modes</seealso> that alter the system behavior when system time changes.</p> + <p>The <seealso marker="#No_Time_Warp_Mode">default time warp mode</seealso> has the same behavior as before, and the - old API will still work, so you are not required to change + old API still works. Thus, you are not required to change anything unless you want to. However, <em>you are strongly encouraged to use the new API</em> instead of the old API based on <seealso marker="erlang#now/0"><c>erlang:now/0</c></seealso>. - <c>erlang:now/0</c> has been deprecated since it is and forever - will be a scalability bottleneck. By using the new API you will + <c>erlang:now/0</c> is deprecated, as it is and + will be a scalability bottleneck.</p> + + <p>By using the new API, you automatically get scalability and performance improvements. This - will also enable you to use the - <seealso marker="#Multi_Time_Warp_Mode">multi time warp mode</seealso> - which improves accuracy, and precision of time measurements.</p></note> + also enables you to use the + <seealso marker="#Multi_Time_Warp_Mode">multi-time warp mode</seealso> + that improves accuracy and precision of time measurements.</p> + </note> </section> <section> - <title>Some Terminology</title> - <p>In order to make it easier to understand this document we first - define some terminology. This is a mixture of our own terminology + <title>Terminology</title> + <p>To make it easier to understand this section, some terms + are defined. This is a mix of our own terminology (Erlang/OS system time, Erlang/OS monotonic time, time warp) and globally accepted terminology.</p> @@ -67,7 +71,7 @@ <section> <title>Monotonically Increasing</title> <p>In a monotonically increasing sequence of values, all values - that have a predecessor are either larger than, or equal to its + that have a predecessor are either larger than or equal to its predecessor.</p> </section> @@ -82,19 +86,19 @@ <marker id="UT1"/> <section> <title>UT1</title> - <p>Universal Time. Based on the rotation of the earth. Conceptually - mean solar time at 0° longitude.</p> + <p>Universal Time. UT1 is based on the rotation of the earth + and conceptually means solar time at 0° longitude.</p> </section> <marker id="UTC"/> <section> <title>UTC</title> - <p>Coordinated Universal Time. UTC almost align with - <seealso marker="#UT1">UT1</seealso>, however, UTC uses the - SI definition of a second which is not exactly of the same length + <p>Coordinated Universal Time. UTC almost aligns with + <seealso marker="#UT1">UT1</seealso>. However, UTC uses the + SI definition of a second, which has not exactly the same length as the second used by UT1. This means that UTC slowly drifts from - UT1. In order to keep UTC relatively in sync with UT1, leap seconds - are inserted, and potentially also deleted. That is, an UTC day may + UT1. To keep UTC relatively in sync with UT1, leap seconds + are inserted, and potentially also deleted. That is, an UTC day can be 86400, 86401, or 86399 seconds long.</p> </section> @@ -104,14 +108,15 @@ <p>Time since <url href="http://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap03.html#tag_21_03_00_17">Epoch</url>. Epoch is defined to be 00:00:00 <seealso marker="#UTC">UTC</seealso>, - January 1, 1970. + 1970-01-01. <url href="http://pubs.opengroup.org/onlinepubs/009604499/basedefs/xbd_chap04.html#tag_04_14">A day in POSIX time</url> is defined to be exactly 86400 seconds long. Strangely enough - Epoch is defined to be a time in UTC, and UTC have another + Epoch is defined to be a time in UTC, and UTC has another definition of how long a day is. Quoting the Open Group - <url href="http://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap04.html#tag_21_04_15">"POSIX time is therefore not necessarily UTC, despite its appearance"</url>. The effect of this is that when an UTC leap second is + <url href="http://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap04.html#tag_21_04_15">"POSIX time is therefore not necessarily UTC, despite its appearance"</url>. + The effect of this is that when an UTC leap second is inserted, POSIX time either stops for a second, or repeats the - last second. If an UTC leap second would be deleted (has never + last second. If an UTC leap second would be deleted (which has not happened yet), POSIX time would make a one second leap forward.</p> </section> @@ -125,11 +130,11 @@ <marker id="Time_Precision"/> <section> <title>Time Precision</title> - <p>The shortest time interval that can be be distinguished + <p>The shortest time interval that can be distinguished repeatedly and reliably when reading time values. Precision is limited by the <seealso marker="#Time_Resolution">resolution</seealso>, but - resolution and precision might differ significantly.</p> + resolution and precision can differ significantly.</p> </section> <marker id="Time_Accuracy"/> @@ -143,21 +148,23 @@ <title>Time Warp</title> <p>A time warp is a leap forwards or backwards in time. That is, the difference of time values taken before and after the - time warp will not correspond to the actual elapsed time.</p> + time warp does not correspond to the actual elapsed time.</p> </section> <marker id="OS_System_Time"/> <section> <title>OS System Time</title> <p>The operating systems view of - <seealso marker="#POSIX_Time">POSIX time</seealso>. It can be - retrieved by calling + <seealso marker="#POSIX_Time">POSIX time</seealso>. To + retrieve it, call <seealso marker="kernel:os#system_time/0"><c>os:system_time()</c></seealso>. This may or may not be an accurate view of POSIX time. This time may typically be adjusted both backwards and forwards without limitation. That is, <seealso marker="#Time_Warp">time warps</seealso> - may be observed. You can get information about the Erlang runtime - system's source of OS system time by calling + may be observed.</p> + + <p>To get information about the Erlang runtime + system's source of OS system time, call <seealso marker="erlang#system_info_os_system_time_source"><c>erlang:system_info(os_system_time_source)</c></seealso>.</p> </section> @@ -165,15 +172,17 @@ <section> <title>OS Monotonic Time</title> <p>A monotonically increasing time provided by the operating - system. This time does not leap and have a relatively steady + system. This time does not leap and has a relatively steady frequency although not completely correct. However, it is not - uncommon that the OS monotonic time stops if the system is - suspended. This time typically increase since some + uncommon that OS monotonic time stops if the system is + suspended. This time typically increases since some unspecified point in time that is not connected to - <seealso marker="#OS_System_Time">OS system time</seealso>. Note - that this type of time is not necessarily provided by all - operating systems. You can get information about the Erlang - runtime system's source of OS monotonic time by calling + <seealso marker="#OS_System_Time">OS system time</seealso>. + This type of time is not necessarily provided by all + operating systems.</p> + + <p>To get information about the Erlang + runtime system's source of OS monotonic time, call <seealso marker="erlang#system_info_os_monotonic_time_source"><c>erlang:system_info(os_monotonic_time_source)</c></seealso>.</p> </section> @@ -181,14 +190,17 @@ <section> <title>Erlang System Time</title> <p>The Erlang runtime systems view of - <seealso marker="#POSIX_Time">POSIX time</seealso>. It can be - retrieved by calling - <seealso marker="erlang#system_time/0"><c>erlang:system_time()</c></seealso>. - This time may or may not be an accurate view of POSIX time, and may + <seealso marker="#POSIX_Time">POSIX time</seealso>. To + retrieve it, call + <seealso marker="erlang#system_time/0"><c>erlang:system_time()</c></seealso>.</p> + + <p>This time may or may not be an accurate view of POSIX time, + and may or may not align with <seealso marker="#OS_System_Time">OS system time</seealso>. The runtime system works towards aligning the two - system times. Depending on <seealso marker="#Time_Warp_Modes">time - warp mode</seealso> used, this may be achieved by letting the Erlang + system times. Depending on the + <seealso marker="#Time_Warp_Modes">time warp mode</seealso> used, + this can be achieved by letting Erlang system time perform a <seealso marker="#Time_Warp">time warp</seealso>.</p> </section> @@ -197,35 +209,43 @@ <section> <title>Erlang Monotonic Time</title> <p>A monotonically increasing time provided by the - Erlang runtime system. The Erlang monotonic time increase since - some unspecified point in time. It can be retrieved by calling + Erlang runtime system. Erlang monotonic time increases since + some unspecified point in time. To retrieve it, call <seealso marker="erlang#monotonic_time/0"><c>erlang:monotonic_time()</c></seealso>. - The - <seealso marker="#Time_Accuracy">accuracy</seealso>, and + </p> + + <p>The <seealso marker="#Time_Accuracy">accuracy</seealso> and <seealso marker="#Time_Precision">precision</seealso> of Erlang - monotonic time heavily depends on the accuracy and precision of - <seealso marker="#OS_Monotonic_Time">OS monotonic time</seealso>, - the accuracy and precision of - <seealso marker="#OS_System_Time">OS system time</seealso> as well - as on the - <seealso marker="#Time_Warp_Modes">time warp mode</seealso> - used. On a system that is lacking OS monotonic time, the Erlang - monotonic time can only guarantee monotonicity and can more or less - not give any other guarantees. The frequency adjustments made to - the Erlang monotonic time depends on the time warp mode - used.</p> - - <p>Internally in the runtime system the Erlang monotonic + monotonic time heavily depends on the following:</p> + + <list type="bulleted"> + <item>Accuracy and precision of + <seealso marker="#OS_Monotonic_Time">OS monotonic time</seealso> + </item> + <item>Accuracy and precision of + <seealso marker="#OS_System_Time">OS system time</seealso> + </item> + <item><seealso marker="#Time_Warp_Modes">time warp mode</seealso> used + </item> + </list> + + <p>On a system without OS monotonic time, Erlang monotonic + time guarantees monotonicity, but cannot give + other guarantees. The frequency adjustments made to + Erlang monotonic time depend on the time warp mode used.</p> + + <p>Internally in the runtime system, Erlang monotonic time is the "time engine" that is used for more or less - everything that has anything to do with time. All timers + everything that has anything to do with time. All timers, regardless of it is a <c>receive ... after</c> timer, BIF timer, - or a timer in the <c>timer</c> module are triggered + or a timer in the <c>timer</c> module, are triggered relative Erlang monotonic time. Even <seealso marker="#Erlang_System_Time">Erlang system time</seealso> is based on Erlang monotonic time. By adding current Erlang monotonic time with current time - offset you get current Erlang system time. Current time - offset can be retrieved by calling + offset, you get current Erlang system time.</p> + + <p>To retrieve current time offset, call <seealso marker="erlang#time_offset/0"><c>erlang:time_offset/0</c></seealso>. </p> </section> @@ -234,176 +254,169 @@ <section> <title>Introduction</title> - <p>Time is vital to an Erlang program and, more importantly, <em>correct</em> time is vital to an Erlang program. As Erlang is a language with - soft real time properties and we have the possibility to express - time in our programs, the Virtual Machine and the language has to be - very careful about what is considered a correct point in time and in + soft real-time properties and we can express + time in our programs, the Virtual Machine and the language must be + careful about what is considered a correct time and in how time functions behave.</p> - <p>In the beginning, Erlang was constructed assuming that the wall + <p>When Erlang was designed, it was assumed that the wall clock time in the system showed a monotonic time moving forward at - exactly the same pace as the definition of time. That more or less - meant that an atomic clock (or better) was expected to be attached + exactly the same pace as the definition of time. This more or less meant + that an atomic clock (or better time source) was expected to be attached to your hardware and that the hardware was then expected to be - locked away from any human (or unearthly) tinkering for all - eternity. While this might be a compelling thought, it's simply - never the case.</p> - - <p>A "normal" modern computer can not keep time. Not on itself and - not unless you actually have a chip level atomic clock wired to - it. Time, as perceived by your computer, will normally need to be - corrected. Hence the NTP protocol that together with the ntpd - process will do it's best to keep your computers time in sync with - the "real" time in the universe. Between NTP corrections, usually a + locked away from any human tinkering forever. While this can be a + compelling thought, it is simply never the case.</p> + + <p>A "normal" modern computer cannot keep time, not on itself and + not unless you have a chip-level atomic clock wired to it. Time, + as perceived by your computer, must normally be corrected. Hence + the Network Time Protocol (NTP) protocol, together with the <c>ntpd</c> + process, does its best to keep your computer time in sync with + the correct time. Between NTP corrections, usually a less potent time-keeper than an atomic clock is used.</p> - <p>But NTP is not fail safe. The NTP server can be unavailable, the - ntp.conf can be wrongly configured or your computer may from time to - time be disconnected from the internet. Furthermore you can have a - user (or even system administrator) on your system that thinks the - right way to handle daylight saving time is to adjust the clock one - hour two times a year (a tip, that is not the right way to do - it...). To further complicate things, this user fetched your - software from the internet and has never ever thought about what's - the correct time as perceived by a computer. The user simply does - not care about keeping the wall clock in sync with the rest of the - universe. The user expects your program to have omnipotent knowledge + <p>However, NTP is not fail-safe. The NTP server can be unavailable, + <c>ntp.conf</c> can be wrongly configured, or your computer may + sometimes be disconnected from Internet. Furthermore, you can have a + user (or even system administrator) who thinks the correct + way to handle Daylight Saving Time is to adjust the clock one + hour two times a year (which is the incorrect way to do it). + To complicate things further, this user fetched your + software from Internet and has not considered what + the correct time is as perceived by a computer. The user does + not care about keeping the wall clock in sync with the correct + time. The user expects your program to have unlimited knowledge about the time.</p> <p>Most programmers also expect time to be reliable, at least until - they realize that the wall clock time on their workstation is of by - a minute. Then they simply set it to the correct time, maybe or - maybe not in a smooth way. Most probably not in a smooth way.</p> + they realize that the wall clock time on their workstation is off by + a minute. Then they set it to the correct time, but most probably + not in a smooth way.</p> - <p>The amount of problems that arise when you expect the wall clock - time on the system to always be correct may be immense. Therefore Erlang + <p>The number of problems that arise when you always expect the wall clock + time on the system to be correct can be immense. Erlang therefore introduced the "corrected estimate of time", or the "time - correction" many years ago. The time correction relies on the fact + correction", many years ago. The time correction relies on the fact that most operating systems have some kind of monotonic clock, - either a real time extension or some built in "tick counter" that is - independent of the wall clock settings. This counter may have - microsecond resolution or much less, but generally it has a drift - that is not to be ignored.</p> - + either a real-time extension or some built-in "tick counter" that is + independent of the wall clock settings. This counter can have + microsecond resolution or much less, but it has a drift that cannot + be ignored.</p> </section> - <marker id="Time_Correction"/> <section> + <marker id="Time_Correction"/> <title>Time Correction</title> <p>If time correction is enabled, the Erlang runtime system - will make use of both + makes use of both <seealso marker="#OS_System_Time">OS system time</seealso> and <seealso marker="#OS_Monotonic_Time">OS monotonic time</seealso>, - in order to make adjustments of the frequency of the Erlang - monotonic clock. Time correction will ensure that + to adjust the frequency of the Erlang + monotonic clock. Time correction ensures that <seealso marker="#Erlang_Monotonic_Time">Erlang monotonic time</seealso> - will not warp, and that the frequency is relatively accurate. - The type of adjustments made to the frequency depends on the - time warp mode used. This will be discussed in more details in - the <seealso marker="#Time_Warp_Modes">time warp modes</seealso> - section below.</p> - - <p>By default time correction will be enabled if support for - it on the specific platform exist. Support for it includes - both an OS monotonic time provided by the OS, and an - implementation in the Erlang runtime system utilizing the - OS monotonic time. You can check if your system has support - for OS monotonic time by calling - <seealso marker="erlang#system_info_os_monotonic_time_source"><c>erlang:system_info(os_monotonic_time_source)</c></seealso>, - and you can check if time correction is enabled on your - system by calling + does not warp and that the frequency is relatively accurate. + The type of frequency adjustments depends on the time warp mode used. + Section <seealso marker="#Time_Warp_Modes">Time Warp Modes</seealso> + provides more details.</p> + + <p>By default time correction is enabled if support for + it exists on the specific platform. Support for it includes + both OS monotonic time, provided by the OS, and an + implementation in the Erlang runtime system using + OS monotonic time. To check if your system has support + for OS monotonic time, call + <seealso marker="erlang#system_info_os_monotonic_time_source"><c>erlang:system_info(os_monotonic_time_source)</c></seealso>. + To check if time correction is enabled on your system, call <seealso marker="erlang#system_info_time_correction"><c>erlang:system_info(time_correction)</c></seealso>.</p> - <p>Time correction is enabled or disabled by passing the + <p>To enable or disable time correction, pass command-line argument <seealso marker="erl#+c"><c>+c [true|false]</c></seealso> - command line argument to <c>erl</c>.</p> + to <c>erl</c>.</p> <p>If time correction is disabled, Erlang monotonic time - may warp forwards, it may stop and even freeze for extended - periods of time, and there are no guarantees that the frequency + may warp forwards or stop, or even freeze for extended + periods of time. There are then no guarantees that the frequency of the Erlang monotonic clock is accurate or stable.</p> <p><em>You typically never want to disable time correction</em>. - Previously there was a performance penalty associated with time - correction, but nowadays it is most often the other way around. - By disabling time correction you are likely to get bad scalability, + Previously a performance penalty was associated with time + correction, but nowadays it is usually the other way around. + If time correction is disabled, you probably get bad scalability, bad performance, and bad time measurements.</p> </section> - - <marker id="Time_Warp_Safe_Code"/> <section> + <marker id="Time_Warp_Safe_Code"/> <title>Time Warp Safe Code</title> - <p>Time warp safe code is code that is able to handle + <p>Time warp safe code can handle a <seealso marker="#Time_Warp">time warp</seealso> of - <seealso marker="#Erlang_System_Time">Erlang system time</seealso>. - </p> + <seealso marker="#Erlang_System_Time">Erlang system time</seealso>.</p> <p><seealso marker="erlang#now/0"><c>erlang:now/0</c></seealso> - behaves very bad when Erlang system time warps. When Erlang - system time do a time warp backwards, the values returned - from <c>erlang:now/0</c> will freeze (if you disregard the - micro second increments made due to the actual call) until - OS system time reach the point of the last value returned by - <c>erlang:now/0</c>. This freeze might continue for very - long periods of time. It might take years, decades, - and even longer than this until the freeze stops.</p> + behaves bad when Erlang system time warps. When Erlang + system time does a time warp backwards, the values returned + from <c>erlang:now/0</c> freeze (if you disregard the + microsecond increments made because of the actual call) until + OS system time reaches the point of the last value returned by + <c>erlang:now/0</c>. This freeze can continue for a long time. It + can take years, decades, and even longer until the freeze stops.</p> <p>All uses of <c>erlang:now/0</c> are not necessarily time warp unsafe. If you do not use it to get time, it - will be time warp safe. However <em>all uses of + is time warp safe. However, <em>all uses of <c>erlang:now/0</c> are suboptimal</em> from a performance and scalability perspective. So you really want to replace - the usage of it with other functionality. For examples - of how to replace the usage of <c>erlang:now/0</c>, - see the <seealso marker="#Dos_and_Donts">Dos and Donts</seealso> - section.</p> + the use of it with other functionality. For examples + of how to replace the use of <c>erlang:now/0</c>, see Section + <seealso marker="#Dos_and_Donts">How to Work with the New + API</seealso>.</p> </section> - <marker id="Time_Warp_Modes"/> <section> <title>Time Warp Modes</title> - + <marker id="Time_Warp_Modes"/> <p>Current <seealso marker="#Erlang_System_Time">Erlang system time</seealso> is determined by adding current <seealso marker="erlang#monotonic_time/0">Erlang monotonic time</seealso> with current <seealso marker="erlang#time_offset/0">time offset</seealso>. The time offset is managed differently depending on which time - warp mode you use. The time warp mode is set by passing the + warp mode you use.</p> + + <p>To set the time warp mode, pass command-line argument <seealso marker="erl#+C_"><c>+C [no_time_warp|single_time_warp|multi_time_warp]</c></seealso> - command line argument to <c>erl</c>.</p> + to <c>erl</c>.</p> <marker id="No_Time_Warp_Mode"/> <section> <title>No Time Warp Mode</title> <p>The time offset is determined at runtime system start - and will after this not change. This is the default behavior. - Not because it is the best mode (which it isn't). It is + and does not change later. This is the default behavior, but + not because it is the best mode (which it is not). It is default <em>only</em> because this is how the runtime system - always has behaved up until ERTS version 7.0, and you have to - ensure that your Erlang code that may execute during a time + behaved until <c>ERTS</c> 7.0. + Ensure that your Erlang code that may execute during a time warp is <seealso marker="#Time_Warp_Safe_Code">time warp - safe</seealso> before you can enable other modes.</p> + safe</seealso> before enabling other modes.</p> - <p>Since the time offset is not allowed to change, time - correction needs to adjust the frequency of the Erlang - monotonic clock in order to smoothly align Erlang system - time with OS system time. A big downside of this approach + <p>As the time offset is not allowed to change, time + correction must adjust the frequency of the Erlang + monotonic clock to align Erlang system time with OS + system time smoothly. A significant downside of this approach is that we on purpose will use a faulty frequency on the Erlang monotonic clock if adjustments are needed. This - error may be as big as 1%. This error will show up in all + error can be as large as 1%. This error will show up in all time measurements in the runtime system.</p> - <p>If time correction is not enabled, the Erlang monotonic - time will freeze when the OS system time leap backwards. - The freeze of the monotonic time will continue until - OS system time catch up. The freeze may continue for - a very long time. When OS system time leaps forwards, - Erlang monotonic time will also leap forward.</p> + <p>If time correction is not enabled, Erlang monotonic + time freezes when OS system time leaps backwards. + The freeze of monotonic time continues until + OS system time catches up. The freeze can continue for + a long time. When OS system time leaps forwards, + Erlang monotonic time also leaps forward.</p> </section> <marker id="Single_Time_Warp_Mode"/> @@ -411,26 +424,27 @@ <title>Single Time Warp Mode</title> <p>This mode is more or less a backwards compatibility mode as of its introduction.</p> + <p>On an embedded system it is not uncommon that the system - has no power supply at all, not even a battery, when it is - shut off. The system clock on such a system will typically - be way off when the system boots. If the + has no power supply, not even a battery, when it is + shut off. The system clock on such a system is typically + way off when the system boots. If <seealso marker="#No_Time_Warp_Mode">no time warp mode</seealso> is used, and the Erlang runtime system is started before - the OS system time has been corrected, the Erlang system - time may be wrong for a very long time, even centuries or - more.</p> - <p>If you for some reason need to use Erlang code that - is not + OS system time has been corrected, Erlang system time + can be wrong for a long time, centuries or even longer.</p> + + <p>If you need to use Erlang code that is not <seealso marker="#Time_Warp_Safe_Code">time warp safe</seealso>, - and you need to start the Erlang runtime system before the OS + and you need to start the Erlang runtime system before OS system time has been corrected, you may want to use the single - time warp mode. Note that there are limitations to when you can + time warp mode.</p> + + <note><p>There are limitations to when you can execute time warp unsafe code using this mode. If it is possible - to only utilize time warp safe code, it is <em>much</em> better - to use the <seealso marker="#Multi_Time_Warp_Mode">multi time - warp mode</seealso> instead. - </p> + to use time warp safe code only, it is <em>much</em> better + to use the <seealso marker="#Multi_Time_Warp_Mode">multi-time + warp mode</seealso> instead.</p></note> <p>Using the single time warp mode, the time offset is handled in two phases:</p> @@ -438,158 +452,150 @@ <taglist> <tag>Preliminary Phase</tag> <item> - <p>The preliminary phase starts when the runtime + <p>This phase starts when the runtime system starts. A preliminary time offset based on - current OS system time is determined. This offset will - from now on be fixed during the whole preliminary phase.</p> + current OS system time is determined. This offset is from + now on to be fixed during the whole preliminary phase.</p> <p>If time correction is enabled, adjustments to the - Erlang monotonic clock will be made to keep its - frequency as correct as possible, but <em>no</em> - adjustments will be made trying to align Erlang system - time and OS system time. That is, during the preliminary - Erlang system time and OS system time might diverge - from each other, and no attempt to prevent this will - be made.</p> + Erlang monotonic clock are made to keep its + frequency as correct as possible. However, <em>no</em> + adjustments are made trying to align Erlang system + time and OS system time. That is, during the preliminary phase + Erlang system time and OS system time can diverge + from each other, and no attempt is made to prevent this.</p> <p>If time correction is disabled, changes in OS system - time will effect the monotonic clock the same way as + time affects the monotonic clock the same way as when the <seealso marker="#No_Time_Warp_Mode">no time warp mode</seealso> is used.</p> </item> <tag>Final Phase</tag> <item> - - <p>The final phase begin when the user finalize the time + <p>This phase begins when the user finalizes the time offset by calling <seealso marker="erlang#system_flag_time_offset"><c>erlang:system_flag(time_offset, finalize)</c></seealso>. - The finalization can only be performed once. - </p> + The finalization can only be performed once.</p> <p>During finalization, the time offset is adjusted and - fixated so that current Erlang system time align with - current OS system time. Since the time offset may - change during the finalization, the Erlang system time - may do a time warp at this point. The time offset will - from now on be fixed until the runtime system terminates. + fixated so that current Erlang system time aligns with + current OS system time. As the time offset can + change during the finalization, Erlang system time + can do a time warp at this point. The time offset is + from now on fixed until the runtime system terminates. If time correction has been enabled, the time - correction will from now on also make adjustments - in order to align Erlang system time with OS system - time. When the system is in the final phase it behaves + correction from now on also makes adjustments + to align Erlang system time with OS system + time. When the system is in the final phase, it behaves exactly as in the <seealso marker="#No_Time_Warp_Mode">no time warp mode</seealso>.</p> - </item> </taglist> - <p>In order for this to work properly there are two - requirements that the user needs to ensure are - satisfied:</p> + <p>In order for this to work properly, the user must ensure + that the following two requirements are satisfied:</p> <taglist> <tag>Forward Time Warp</tag> <item><p>The time warp made when finalizing the time offset can only be done forwards without encountering problems. - This implies that the user has to ensure that the OS + This implies that the user must ensure that OS system time is set to a time earlier or equal to actual - POSIX time before starting the Erlang runtime system. If - you are not completely sure the OS system time is correct, + POSIX time before starting the Erlang runtime system.</p> + + <p>If you are not sure that OS system time is correct, set it to a time that is guaranteed to be earlier than actual POSIX time before starting the Erlang runtime - system just to be safe.</p></item> + system, just to be safe.</p> + </item> <tag>Finalize Correct OS System Time</tag> - <item><p>The OS system time needs to be correct when the - the user finalizes the time offset.</p></item> + <item><p>OS system time must be correct when + the user finalizes the time offset.</p> + </item> </taglist> <p>If these requirements are not fulfilled, the system - may behave very bad. - </p> - - <p>Assuming that the requirements above are fulfilled, - time correction is enabled, and that the OS system time - is adjusted using some time adjustment protocol like NTP - or similar, only small adjustments of the Erlang monotonic - time should be needed in order to keep system times - aligned after finilization. As long as the system is not - suspended, the largest adjustments needed should be for + may behave very bad.</p> + + <p>Assuming that these requirements are fulfilled, + time correction is enabled, and that OS system time + is adjusted using a time adjustment protocol such as NTP, + only small adjustments of Erlang monotonic + time are needed to keep system times + aligned after finalization. As long as the system is not + suspended, the largest adjustments needed are for inserted (or deleted) leap seconds.</p> - <warning><p>In order to be able to use this mode you have - to ensure that all Erlang code that will execute in - both phases are + <warning><p>To use this mode, ensure that + all Erlang code that will execute in both phases are <seealso marker="#Time_Warp_Safe_Code">time warp safe</seealso>.</p> - <p>Code that only execute in the final phase does not have + <p>Code executing only in the final phase does not have to be able to cope with the time warp.</p></warning> - </section> <marker id="Multi_Time_Warp_Mode"/> <section> - <title>Multi Time Warp Mode</title> - - <p><em>Multi time warp mode in combination with time - correction is the preferred configuration</em>. This since, - on almost all platforms, the Erlang runtime system will have - better performance, will scale better, will behave better, - and since the accuracy, and precision of time measurements - will be better. Only Erlang runtime systems executing on - ancient platforms will benefit from another configuration.</p> + <title>Multi-Time Warp Mode</title> + <p><em>Multi-time warp mode in combination with time + correction is the preferred configuration</em>. This as + the Erlang runtime system have better performance, scale + better, and behave better on almost all platforms. In + addition, the accuracy and precision of time measurements + are better. Only Erlang runtime systems executing on + ancient platforms benefit from another configuration.</p> <p>The time offset may change at any time without limitations. That is, Erlang system time may perform time warps both - forwards and backwards at <em>any</em> time. Since we align - the Erlang system time with the OS system time by changing + forwards and backwards at <em>any</em> time. As we align + Erlang system time with OS system time by changing the time offset, we can enable a time correction that tries to adjust the frequency of the Erlang monotonic clock to be as - correct as possible. This will make time measurements using - the Erlang monotonic time more accurate and precise.</p> + correct as possible. This makes time measurements using + Erlang monotonic time more accurate and precise.</p> <p>If time correction is disabled, Erlang monotonic time - will leap forward if OS system time leaps forward. If the - OS system time leaps backwards, Erlang monotonic time will - stop briefly but it does not freeze for extended periods - of time. This since the time offset is changed in order to + leaps forward if OS system time leaps forward. If + OS system time leaps backwards, Erlang monotonic time + stops briefly, but it does not freeze for extended periods + of time. This as the time offset is changed to align Erlang system time with OS system time.</p> - <warning><p>In order to be able to use this mode you have - to ensure that all Erlang code that will execute on the - runtime system is + <warning><p>To use this mode, ensure that all + Erlang code that will execute on the runtime system is <seealso marker="#Time_Warp_Safe_Code">time warp safe</seealso>.</p></warning> </section> </section> - <marker id="The_New_Time_API"/> <section> - <title>The New Time API</title> - + <title>New Time API</title> + <marker id="The_New_Time_API"/> <p>The old time API is based on <seealso marker="erlang#now/0"><c>erlang:now/0</c></seealso>. - The major issue with <c>erlang:now/0</c> is that it was - intended to be used for so many unrelated things. This - tied these unrelated operations together and unnecessarily - caused performance, scalability as well as accuracy, and - precision issues for operations that do not need to have - such issues. The new API spreads different functionality - over multiple functions in order to improve on this.</p> - - <p>In order to be backwards compatible <c>erlang:now/0</c> will - remain as is, but <em>you are strongly discouraged from using - it</em>. A lot of uses of <c>erlang:now/0</c> will also - prevent you from using the new - <seealso marker="#Multi_Time_Warp_Mode">multi time warp - mode</seealso> which is an important part of this + <c>erlang:now/0</c> was intended to be used for many unrelated + things. This tied these unrelated operations together and + caused issues with performance, scalability, accuracy, and + precision for operations that did not need to have + such issues. To improve this, the new API spreads different + functionality over multiple functions.</p> + + <p>To be backwards compatible, <c>erlang:now/0</c> + remains as is, but <em>you are strongly discouraged from using + it</em>. Many use cases of <c>erlang:now/0</c> + prevents you from using the new + <seealso marker="#Multi_Time_Warp_Mode">multi-time warp + mode</seealso>, which is an important part of this new time functionality improvement.</p> <p>Some of the new BIFs on some systems, perhaps surprisingly, - return negative integer values on a newly started run time - system. This is not a bug, but a memory usage optimization.</p> + return negative integer values on a newly started runtime + system. This is not a bug, but a memory use optimization.</p> + + <p>The new API consists of the following new BIFs:</p> - <p>The new API consists of a number of new BIFs:</p> <list> <item><p><seealso marker="erlang#convert_time_unit/3"><c>erlang:convert_time_unit/3</c></seealso></p></item> <item><p><seealso marker="erlang#monotonic_time/0"><c>erlang:monotonic_time/0</c></seealso></p></item> @@ -604,7 +610,9 @@ <item><p><seealso marker="kernel:os#system_time/0"><c>os:system_time/0</c></seealso></p></item> <item><p><seealso marker="kernel:os#system_time/1"><c>os:system_time/1</c></seealso></p></item> </list> - <p>and a number of extensions of existing BIFs:</p> + + <p>The new API also consists of extensions of the following existing BIFs:</p> + <list> <item><p><seealso marker="erlang#monitor/2"><c>erlang:monitor(time_offset, clock_service)</c></seealso></p></item> <item><p><seealso marker="erlang#system_flag_time_offset"><c>erlang:system_flag(time_offset, finalize)</c></seealso></p></item> @@ -619,102 +627,99 @@ <marker id="The_New_Erlang_Monotonic_Time"/> <section> - <title>The New Erlang Monotonic Time</title> - <p>The Erlang monotonic time as such is new as of ERTS - version 7.0. It has been introduced in order to be able - to detach time measurements such as elapsed time from - calender time. It is very common that one is interested - in measuring elapsed time or specifying a time relative - to another point in time without having any need to know - what the involved times are in UTC or any other - globally defined time scale. By introducing a time scale - that has a local definition of where it starts, it is - possible to manage time that do not concern calender - time on that time scale. Erlang monotonic time use - such a time scale with a locally defined start.</p> - - <p>The introduction of Erlang monotonic time gives us - the possibility to adjust the two Erlang times (Erlang + <title>New Erlang Monotonic Time</title> + <p>Erlang monotonic time as such is new as of <c>ERTS</c> 7.0. + It is introduced to detach time measurements, such as elapsed + time from calendar time. In many use cases there is a need to + measure elapsed time or specify a time relative to another point + in time without the need to know the involved times in UTC or + any other globally defined time scale. By introducing a time + scale with a local definition of where it starts, time that do + not concern calendar time can be managed on that time + scale. Erlang monotonic time uses such a time scale with a + locally defined start.</p> + + <p>The introduction of Erlang monotonic time allows + us to adjust the two Erlang times (Erlang monotonic time and Erlang system time) separately. By - doing this, accuracy of elapsed time does not have to + doing this, the accuracy of elapsed time does not have to suffer just because the system time happened to be wrong at some point in time. Separate adjustments of the two times are only performed in the time warp modes, and only fully separated in the - <seealso marker="#Multi_Time_Warp_Mode">multi - time warp mode</seealso>. All other modes than the - multi time warp mode are there for backwards - compatibility reasons, and when using these the - accuracy of Erlang monotonic time suffer since + <seealso marker="#Multi_Time_Warp_Mode">multi-time + warp mode</seealso>. All other modes than the + multi-time warp mode are for backwards + compatibility reasons. When using these modes, the + accuracy of Erlang monotonic time suffer, as the adjustments of Erlang monotonic time in these - modes are more or less tied to the Erlang system - time.</p> + modes are more or less tied to Erlang system time.</p> <p>The adjustment of system time could have been made smother than using a time warp approach, but we think - that would be a bad choice. Since we are able to - express and measure time that aren't connected to - calender time by the use of Erlang monotonic time, it + that would be a bad choice. As we can + express and measure time that is not connected to + calendar time by the use of Erlang monotonic time, it is better to expose the change in Erlang system time - immediately. This since it makes it possible for the - Erlang applications executing on the system to react - on the change in system time as soon as possible. This - is also more or less exactly how most OSes handle this + immediately. This as the Erlang applications + executing on the system can react on the change in + system time as soon as possible. This is also more or + less exactly how most operating systems handle this (OS monotonic time and OS system time). By adjusting - system time smoothly we would just hide the fact that + system time smoothly, we would just hide the fact that system time changed and make it harder for the Erlang applications to react to the change in a sensible way.</p> - <p>In order to be able to react to a change in Erlang - system time you have to be able to detect that it + <p>To be able to react to a change in Erlang + system time, you must be able to detect that it happened. The change in Erlang system time occurs when current time offset is changed. We have therefore - introduced the possibility to monitor the time offset - using - <seealso marker="erlang#monitor/2"><c>erlang:monitor(time_offset, clock_service)</c></seealso>. A process monitoring the time - offset will be sent a message on the following format + introduced the possibility to monitor the time offset using + <seealso marker="erlang#monitor/2"><c>erlang:monitor(time_offset, clock_service)</c></seealso>. + A process monitoring the time + offset is sent a message on the following format when the time offset is changed:</p> + <code type="none">{'CHANGE', MonitorReference, time_offset, clock_service, NewTimeOffset}</code> </section> <marker id="Unique_Values"/> <section> <title>Unique Values</title> - <p>Besides reporting time <c>erlang:now/0</c> also - produce unique and strictly monotonically increasing - values. In order to detach this functionality from - time measurements we have introduced + <p>Besides reporting time, <c>erlang:now/0</c> also + produces unique and strictly monotonically increasing + values. To detach this functionality from + time measurements, we have introduced <seealso marker="erlang#unique_integer/1"><c>erlang:unique_integer()</c></seealso>. </p> </section> <marker id="Dos_and_Donts"/> <section> - <title>Dos and Don'ts</title> + <title>How to Work with the New API</title> <p>Previously <c>erlang:now/0</c> was the only option for doing - quite a lot of things. We will look at a few different things - <c>erlang:now/0</c> could be used for, and how you want to do - this using the new API:</p> + many things. This section deals with some things that + <c>erlang:now/0</c> can be used for, and how you are to + these using the new API.</p> <marker id="Dos_and_Donts_Retrieve_Erlang_System_Time"/> <section> <title>Retrieve Erlang System Time</title> <dont> <p> - use <c>erlang:now/0</c> in order to retrieve current Erlang - system time. + Use <c>erlang:now/0</c> to retrieve current Erlang system time. </p> </dont> <do> <p> - use + Use <seealso marker="erlang#system_time/1"><c>erlang:system_time/1</c></seealso> - in order to retrieve current Erlang system time on the + to retrieve current Erlang system time on the <seealso marker="erlang#type_time_unit">time unit</seealso> of your choice.</p> <p>If you want the same format as returned by <c>erlang:now/0</c>, use <seealso marker="erlang#timestamp/0"><c>erlang:timestamp/0</c></seealso>. - </p> + </p> </do> </section> @@ -723,26 +728,27 @@ <title>Measure Elapsed Time</title> <dont> <p> - take timestamps with <c>erlang:now/0</c> and calculate + Take timestamps with <c>erlang:now/0</c> and calculate the difference in time with <seealso marker="stdlib:timer#now_diff/2"><c>timer:now_diff/2</c></seealso>. </p> </dont> <do> <p> - take timestamps with + Take timestamps with <seealso marker="erlang#monotonic_time/0"><c>erlang:monotonic_time/0</c></seealso> and calculate the time difference using ordinary subtraction. The result will be in <c>native</c> <seealso marker="erlang#type_time_unit">time unit</seealso>. If you want to convert the - result to another time unit you can do this using + result to another time unit, you can use <seealso marker="erlang#convert_time_unit/3"><c>erlang:convert_time_unit/3</c></seealso>. </p> - <p>Another easier way of doing this is to use + + <p>An easier way to do this is to use <seealso marker="erlang#monotonic_time/1"><c>erlang:monotonic_time/1</c></seealso> - with desired time unit. However, you may lose accuracy, - and precision this way. + with the desired time unit. However, you can then lose accuracy + and precision. </p> </do> </section> @@ -752,16 +758,16 @@ <title>Determine Order of Events</title> <dont> <p> - determine the order of events by saving a timestamp - with <c>erlang:now/0</c> when the event happens. + Determine the order of events by saving a timestamp + with <c>erlang:now/0</c> when the event occurs. </p> </dont> <do> <p> - determine the order of events by saving the integer + Determine the order of events by saving the integer returned by <seealso marker="erlang#unique_integer/1"><c>erlang:unique_integer([monotonic])</c></seealso> - when the event happens. These integers will be strictly + when the event occurs. These integers will be strictly monotonically ordered on current runtime system instance corresponding to creation time. </p> @@ -770,40 +776,43 @@ <marker id="Dos_and_Donts_Determine_Order_of_Events_With_Time_of_the_Event"/> <section> - <title>Determine Order of Events With Time of the Event</title> + <title>Determine Order of Events with Time of the Event</title> <dont> <p> - determine the order of events by saving a timestamp - with <c>erlang:now/0</c> when the event happens. + Determine the order of events by saving a timestamp + with <c>erlang:now/0</c> when the event occurs. </p> </dont> <do> <p> - determine the order of events by saving a tuple - containing + Determine the order of events by saving a tuple containing <seealso marker="erlang#monotonic_time/0">monotonic time</seealso> and a <seealso marker="erlang#unique_integer/1">strictly - monotonically increasing integer</seealso> like this:</p> + monotonically increasing integer</seealso> as follows:</p> + <code type="none"> Time = erlang:monotonic_time(), UMI = erlang:unique_integer([monotonic]), EventTag = {Time, UMI}</code> + <p>These tuples will be strictly monotonically ordered - on the current runtime system instance according to - creation time. Note that it is important that the + on current runtime system instance according to + creation time. It is important that the monotonic time is in the first element (the most significant element when comparing 2-tuples). Using the monotonic time in the tuples, you can calculate time between events.</p> - <p>If you are interested in the Erlang system time at the - time when the event occurred you can also save the time + + <p>If you are interested in Erlang system time at the + time when the event occurred, you can also save the time offset before or after saving the events using <seealso marker="erlang#time_offset/0"><c>erlang:time_offset/0</c></seealso>. Erlang monotonic time added with the time offset corresponds to Erlang system time.</p> + <p>If you are executing in a mode where time offset - may change and you want to be able to get the actual - Erlang system time when the event occurred you can + can change, and you want to get the actual + Erlang system time when the event occurred, you can save the time offset as a third element in the tuple (the least significant element when comparing 3-tuples).</p> </do> @@ -814,16 +823,15 @@ EventTag = {Time, UMI}</code> <title>Create a Unique Name</title> <dont> <p> - use the values returned from <c>erlang:now/0</c> - in order to create a name unique on the current - runtime system instance. + Use the values returned from <c>erlang:now/0</c> + to create a name unique on the current runtime system instance. </p> </dont> <do> <p> - use the value returned from + Use the value returned from <seealso marker="erlang#unique_integer/0"><c>erlang:unique_integer/0</c></seealso> - in order to create a name unique on the current runtime system + to create a name unique on the current runtime system instance. If you only want positive integers, you can use <seealso marker="erlang#unique_integer/1"><c>erlang:unique_integer([positive])</c></seealso>. </p> @@ -832,49 +840,63 @@ EventTag = {Time, UMI}</code> <marker id="Dos_and_Donts_Seed_Random_Number_Generation_With_a_Unique_Value"/> <section> - <title>Seed Random Number Generation With a Unique Value</title> + <title>Seed Random Number Generation with a Unique Value</title> <dont> <p> - seed random number generation using <c>erlang:now()</c>. + Seed random number generation using <c>erlang:now()</c>. </p> </dont> <do> <p> - seed random number generation using a combination of + Seed random number generation using a combination of <seealso marker="erlang#monotonic_time/0"><c>erlang:monotonic_time()</c></seealso>, <seealso marker="erlang#time_offset/0"><c>erlang:time_offset()</c></seealso>, - <seealso marker="erlang#unique_integer/0"><c>erlang:unique_integer()</c></seealso>, and other functionality. + <seealso marker="erlang#unique_integer/0"><c>erlang:unique_integer()</c></seealso>, + and other functionality. </p> </do> </section> - <p>To sum this section up: <em>Don't use <c>erlang:now/0</c>!</em></p> + <p>To sum up this section: <em>Do not use <c>erlang:now/0</c>.</em></p> </section> </section> - <marker id="Supporting_Both_New_and_Old_OTP_Releases"/> <section> - <title>Supporting Both New and Old OTP Releases</title> - <p>Your code may be required to be able to run on a variety + <marker id="Supporting_Both_New_and_Old_OTP_Releases"/> + <title>Support of Both New and Old OTP Releases</title> + <p>It can be required that your code must run on a variety of OTP installations of different OTP releases. If so, you - can not just use the new API out of the box, since it will + cannot use the new API out of the box, as it will not be available on old pre OTP 18 releases. The solution - is <em>not</em> to avoid using the new API, since your - code then won't be able to benefit from the scalability - and accuracy improvements made. Instead you want to use the + is <em>not</em> to avoid using the new API, as your + code then would not benefit from the scalability + and accuracy improvements made. Instead, use the new API when available, and fall back on <c>erlang:now/0</c> - when it is not available. Fortunately almost all of the new - API can easily be implemented using existing primitives - (except for - <seealso marker="erlang#system_info_start_time"><c>erlang:system_info(start_time)</c></seealso>, - <seealso marker="erlang#system_info_end_time"><c>erlang:system_info(end_time)</c></seealso>, - <seealso marker="erlang#system_info_os_monotonic_time_source"><c>erlang:system_info(os_monotonic_time_source)</c></seealso>, and - <seealso marker="erlang#system_info_os_system_time_source"><c>erlang:system_info(os_system_time_source)</c></seealso>). - By wrapping the API with functions that fall back on - <c>erlang:now/0</c> when the new API is not available, - and using these wrappers instead of using the API directly - the problem is solved. These wrappers can for example + when the new API is unavailable.</p> + + <p>Fortunately most of the new API can easily be + implemented using existing primitives, except for:</p> + + <list type="bulleted"> + <item> + <seealso marker="erlang#system_info_start_time"><c>erlang:system_info(start_time)</c></seealso> + </item> + <item> + <seealso marker="erlang#system_info_end_time"><c>erlang:system_info(end_time)</c></seealso> + </item> + <item> + <seealso marker="erlang#system_info_os_monotonic_time_source"><c>erlang:system_info(os_monotonic_time_source)</c></seealso> + </item> + <item> + <seealso marker="erlang#system_info_os_system_time_source"><c>erlang:system_info(os_system_time_source)</c></seealso>) + </item> + </list> + + <p>By wrapping the API with functions that fall back on + <c>erlang:now/0</c> when the new API is unavailable, + and using these wrappers instead of using the API directly, + the problem is solved. These wrappers can, for example, be implemented as in - <url href="time_compat.erl"><c>$ERL_TOP/erts/example/time_compat.erl</c></url>.</p> + <url href="time_compat.erl">$ERL_TOP/erts/example/time_compat.erl</url>.</p> </section> </chapter> diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names index f9a2f3e33e..cb6d294a41 100644 --- a/erts/emulator/beam/atom.names +++ b/erts/emulator/beam/atom.names @@ -71,6 +71,7 @@ atom absoluteURI atom ac atom accessor atom active +atom active_tasks atom all atom all_but_first atom all_names @@ -268,6 +269,7 @@ atom getenv atom gather_gc_info_result atom gather_io_bytes atom gather_sched_wall_time_result +atom gather_system_check_result atom getting_linked atom getting_unlinked atom global @@ -321,6 +323,7 @@ atom ldflags atom Le='=<' atom lf atom line +atom line_delimiter atom line_length atom linked_in_driver atom links @@ -368,6 +371,7 @@ atom monitor atom monitor_nodes atom monitors atom monotonic +atom monotonic_timestamp atom more atom multi_scheduling atom multiline @@ -511,6 +515,7 @@ atom return_from atom return_to atom return_trace atom run_queue +atom run_queue_lengths atom runnable atom runnable_ports atom runnable_procs @@ -556,6 +561,7 @@ atom static atom stderr_to_stdout atom stop atom stream +atom strict_monotonic_timestamp atom sunrm atom suspend atom suspended @@ -578,7 +584,9 @@ atom timeout_value atom Times='*' atom timestamp atom total +atom total_active_tasks atom total_heap_size +atom total_run_queue_lengths atom tpkt atom trace trace_ts traced atom trace_control_word diff --git a/erts/emulator/beam/beam_bp.c b/erts/emulator/beam/beam_bp.c index 016d0aaa32..9860968687 100644 --- a/erts/emulator/beam/beam_bp.c +++ b/erts/emulator/beam/beam_bp.c @@ -75,6 +75,16 @@ extern BeamInstr beam_return_time_trace[1]; /* OpCode(i_return_time_trace) */ erts_smp_atomic32_t erts_active_bp_index; erts_smp_atomic32_t erts_staging_bp_index; +/* + * Inlined helpers + */ + +static ERTS_INLINE ErtsMonotonicTime +get_mtime(Process *c_p) +{ + return erts_get_monotonic_time(ERTS_PROC_GET_SCHDATA(c_p)); +} + /* ************************************************************************* ** Local prototypes */ @@ -97,9 +107,6 @@ static int clear_function_break(BeamInstr *pc, Uint break_flags); static BpDataTime* get_time_break(BeamInstr *pc); static GenericBpData* check_break(BeamInstr *pc, Uint break_flags); -static void bp_time_diff(bp_data_time_item_t *item, - process_breakpoint_time_t *pbt, - Uint ms, Uint s, Uint us); static void bp_meta_unref(BpMetaPid* bmp); static void bp_count_unref(BpCount* bcp); @@ -110,13 +117,8 @@ static void uninstall_breakpoint(BeamInstr* pc); /* bp_hash */ #define BP_TIME_ADD(pi0, pi1) \ do { \ - Uint r; \ (pi0)->count += (pi1)->count; \ - (pi0)->s_time += (pi1)->s_time; \ - (pi0)->us_time += (pi1)->us_time; \ - r = (pi0)->us_time / 1000000; \ - (pi0)->s_time += r; \ - (pi0)->us_time = (pi0)->us_time % 1000000; \ + (pi0)->time += (pi1)->time; \ } while(0) static void bp_hash_init(bp_time_hash_t *hash, Uint n); @@ -948,7 +950,7 @@ do_call_trace(Process* c_p, BeamInstr* I, Eterm* reg, void erts_trace_time_call(Process* c_p, BeamInstr* I, BpDataTime* bdt) { - Uint ms,s,us; + ErtsMonotonicTime time; process_breakpoint_time_t *pbt = NULL; bp_data_time_item_t sitem, *item = NULL; bp_time_hash_t *h = NULL; @@ -961,7 +963,7 @@ erts_trace_time_call(Process* c_p, BeamInstr* I, BpDataTime* bdt) * from the process psd */ pbt = ERTS_PROC_GET_CALL_TIME(c_p); - get_sys_now(&ms, &s, &us); + time = get_mtime(c_p); /* get pbt * timestamp = t0 @@ -976,7 +978,7 @@ erts_trace_time_call(Process* c_p, BeamInstr* I, BpDataTime* bdt) } else { ASSERT(pbt->pc); /* add time to previous code */ - bp_time_diff(&sitem, pbt, ms, s, us); + sitem.time = time - pbt->time; sitem.pid = c_p->common.id; sitem.count = 0; @@ -1002,8 +1004,7 @@ erts_trace_time_call(Process* c_p, BeamInstr* I, BpDataTime* bdt) /* Add count to this code */ sitem.pid = c_p->common.id; sitem.count = 1; - sitem.s_time = 0; - sitem.us_time = 0; + sitem.time = 0; /* this breakpoint */ ASSERT(bdt); @@ -1020,15 +1021,13 @@ erts_trace_time_call(Process* c_p, BeamInstr* I, BpDataTime* bdt) } pbt->pc = I; - pbt->ms = ms; - pbt->s = s; - pbt->us = us; + pbt->time = time; } void erts_trace_time_return(Process *p, BeamInstr *pc) { - Uint ms,s,us; + ErtsMonotonicTime time; process_breakpoint_time_t *pbt = NULL; bp_data_time_item_t sitem, *item = NULL; bp_time_hash_t *h = NULL; @@ -1041,7 +1040,7 @@ erts_trace_time_return(Process *p, BeamInstr *pc) * from the process psd */ pbt = ERTS_PROC_GET_CALL_TIME(p); - get_sys_now(&ms,&s,&us); + time = get_mtime(p); /* get pbt * lookup bdt from code @@ -1057,7 +1056,7 @@ erts_trace_time_return(Process *p, BeamInstr *pc) */ ASSERT(pbt->pc); - bp_time_diff(&sitem, pbt, ms, s, us); + sitem.time = time - pbt->time; sitem.pid = p->common.id; sitem.count = 0; @@ -1080,9 +1079,7 @@ erts_trace_time_return(Process *p, BeamInstr *pc) } pbt->pc = pc; - pbt->ms = ms; - pbt->s = s; - pbt->us = us; + pbt->time = time; } } @@ -1183,10 +1180,14 @@ int erts_is_time_break(Process *p, BeamInstr *pc, Eterm *retval) { for(ix = 0; ix < hash.n; ix++) { item = &(hash.item[ix]); if (item->pid != NIL) { + ErtsMonotonicTime sec, usec; + usec = ERTS_MONOTONIC_TO_USEC(item->time); + sec = usec / 1000000; + usec = usec - sec*1000000; t = TUPLE4(hp, item->pid, make_small(item->count), - make_small(item->s_time), - make_small(item->us_time)); + make_small((Uint) sec), + make_small((Uint) usec)); hp += 5; *retval = CONS(hp, t, *retval); hp += 2; } @@ -1266,8 +1267,7 @@ static void bp_hash_rehash(bp_time_hash_t *hash, Uint n) { } item[hval].pid = hash->item[ix].pid; item[hval].count = hash->item[ix].count; - item[hval].s_time = hash->item[ix].s_time; - item[hval].us_time = hash->item[ix].us_time; + item[hval].time = hash->item[ix].time; } } @@ -1315,8 +1315,7 @@ static ERTS_INLINE bp_data_time_item_t * bp_hash_put(bp_time_hash_t *hash, bp_da item = &(hash->item[hval]); item->pid = sitem->pid; - item->s_time = sitem->s_time; - item->us_time = sitem->us_time; + item->time = sitem->time; item->count = sitem->count; hash->used++; @@ -1330,41 +1329,7 @@ static void bp_hash_delete(bp_time_hash_t *hash) { hash->item = NULL; } -static void bp_time_diff(bp_data_time_item_t *item, /* out */ - process_breakpoint_time_t *pbt, /* in */ - Uint ms, Uint s, Uint us) { - int ds,dus; -#ifdef DEBUG - int dms; - - - dms = ms - pbt->ms; -#endif - ds = s - pbt->s; - dus = us - pbt->us; - - /* get_sys_now may return zero difftime, - * this is ok. - */ - -#ifdef DEBUG - ASSERT(dms >= 0 || ds >= 0 || dus >= 0); -#endif - - if (dus < 0) { - dus += 1000000; - ds -= 1; - } - if (ds < 0) { - ds += 1000000; - } - - item->s_time = ds; - item->us_time = dus; -} - void erts_schedule_time_break(Process *p, Uint schedule) { - Uint ms, s, us; process_breakpoint_time_t *pbt = NULL; bp_data_time_item_t sitem, *item = NULL; bp_time_hash_t *h = NULL; @@ -1387,8 +1352,7 @@ void erts_schedule_time_break(Process *p, Uint schedule) { pbdt = get_time_break(pbt->pc); if (pbdt) { - get_sys_now(&ms,&s,&us); - bp_time_diff(&sitem, pbt, ms, s, us); + sitem.time = get_mtime(p) - pbt->time; sitem.pid = p->common.id; sitem.count = 0; @@ -1410,10 +1374,7 @@ void erts_schedule_time_break(Process *p, Uint schedule) { * timestamp it and remove the previous * timestamp in the psd. */ - get_sys_now(&ms,&s,&us); - pbt->ms = ms; - pbt->s = s; - pbt->us = us; + pbt->time = get_mtime(p); break; default : ASSERT(0); diff --git a/erts/emulator/beam/beam_bp.h b/erts/emulator/beam/beam_bp.h index 97d0539ac7..2b89d6fc71 100644 --- a/erts/emulator/beam/beam_bp.h +++ b/erts/emulator/beam/beam_bp.h @@ -29,8 +29,7 @@ typedef struct { Eterm pid; Sint count; - Uint s_time; - Uint us_time; + ErtsMonotonicTime time; } bp_data_time_item_t; typedef struct { @@ -46,9 +45,7 @@ typedef struct bp_data_time { /* Call time */ } BpDataTime; typedef struct { - Uint ms; - Uint s; - Uint us; + ErtsMonotonicTime time; BeamInstr *pc; } process_breakpoint_time_t; /* used within psd */ diff --git a/erts/emulator/beam/beam_catches.c b/erts/emulator/beam/beam_catches.c index c1fd17c65d..7a1f4901aa 100644 --- a/erts/emulator/beam/beam_catches.c +++ b/erts/emulator/beam/beam_catches.c @@ -143,7 +143,7 @@ BeamInstr *beam_catches_car(unsigned i) struct bc_pool* p = &bccix[erts_active_code_ix()]; if (i >= p->tabsize ) { - erl_exit(1, "beam_catches_delmod: index %#x is out of range\r\n", i); + erts_exit(ERTS_ERROR_EXIT, "beam_catches_delmod: index %#x is out of range\r\n", i); } return p->beam_catches[i].cp; } @@ -157,10 +157,10 @@ void beam_catches_delmod(unsigned head, BeamInstr *code, unsigned code_bytes, ASSERT((code_ix == erts_active_code_ix()) != bccix[erts_staging_code_ix()].is_staging); for(i = head; i != (unsigned)-1;) { if (i >= p->tabsize) { - erl_exit(1, "beam_catches_delmod: index %#x is out of range\r\n", i); + erts_exit(ERTS_ERROR_EXIT, "beam_catches_delmod: index %#x is out of range\r\n", i); } if( (char*)p->beam_catches[i].cp - (char*)code >= code_bytes ) { - erl_exit(1, + erts_exit(ERTS_ERROR_EXIT, "beam_catches_delmod: item %#x has cp %p which is not " "in module's range [%p,%p[\r\n", i, p->beam_catches[i].cp, code, ((char*)code + code_bytes)); diff --git a/erts/emulator/beam/beam_debug.c b/erts/emulator/beam/beam_debug.c index c756de8c8e..90985e4f53 100644 --- a/erts/emulator/beam/beam_debug.c +++ b/erts/emulator/beam/beam_debug.c @@ -79,7 +79,7 @@ erts_debug_breakpoint_2(BIF_ALIST_2) { Process* p = BIF_P; Eterm MFA = BIF_ARG_1; - Eterm bool = BIF_ARG_2; + Eterm boolean = BIF_ARG_2; Eterm* tp; Eterm mfa[3]; int i; @@ -87,7 +87,7 @@ erts_debug_breakpoint_2(BIF_ALIST_2) Eterm res; BpFunctions f; - if (bool != am_true && bool != am_false) + if (boolean != am_true && boolean != am_false) goto error; if (is_not_tuple(MFA)) { @@ -124,7 +124,7 @@ erts_debug_breakpoint_2(BIF_ALIST_2) erts_smp_thr_progress_block(); erts_bp_match_functions(&f, mfa, specified); - if (bool == am_true) { + if (boolean == am_true) { erts_set_debug_break(&f); erts_install_breakpoints(&f); erts_commit_staged_bp(); @@ -298,8 +298,8 @@ erts_debug_disassemble_1(BIF_ALIST_1) (void) erts_bld_uword(NULL, &hsz, (BeamInstr) code_ptr); hp = HAlloc(p, hsz); addr = erts_bld_uword(&hp, NULL, (BeamInstr) code_ptr); - ASSERT(is_atom(funcinfo[0])); - ASSERT(is_atom(funcinfo[1])); + ASSERT(is_atom(funcinfo[0]) || funcinfo[0] == NIL); + ASSERT(is_atom(funcinfo[1]) || funcinfo[1] == NIL); mfa = TUPLE3(hp, (Eterm) funcinfo[0], (Eterm) funcinfo[1], make_small((Eterm) funcinfo[2])); hp += 4; return TUPLE3(hp, addr, bin, mfa); @@ -669,7 +669,6 @@ print_op(int to, void *to_arg, int op, int size, BeamInstr* addr) case op_new_map_dII: case op_update_map_assoc_jsdII: case op_update_map_exact_jsdII: - case op_i_get_map_elements_fsI: { int n = unpacked[-1]; @@ -693,6 +692,32 @@ print_op(int to, void *to_arg, int op, int size, BeamInstr* addr) } } break; + case op_i_get_map_elements_fsI: + { + int n = unpacked[-1]; + + while (n > 0) { + if (n % 3 == 1) { + erts_print(to, to_arg, " %X", ap[0]); + } else if (!is_header(ap[0])) { + erts_print(to, to_arg, " %T", (Eterm) ap[0]); + } else { + switch ((ap[0] >> 2) & 0x03) { + case R_REG_DEF: + erts_print(to, to_arg, " x(0)"); + break; + case X_REG_DEF: + erts_print(to, to_arg, " x(%d)", ap[0] >> 4); + break; + case Y_REG_DEF: + erts_print(to, to_arg, " y(%d)", ap[0] >> 4); + break; + } + } + ap++, size++, n--; + } + } + break; } erts_print(to, to_arg, "\n"); diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index 8b409e139b..3a15287555 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -2163,10 +2163,29 @@ void process_main(void) OpCase(wait_f): wait2: { +#ifndef ERTS_SMP + if (ERTS_PROC_IS_EXITING(c_p)) { + /* + * I non smp case: + * + * Currently executing process might be sent an exit + * signal if it is traced by a port that it also is + * linked to, and the port terminates during the + * trace. In this case we do *not* want to clear + * the active flag, which will make the process hang + * in limbo forever. + */ + SWAPOUT; + goto do_schedule; + } +#endif c_p->i = (BeamInstr *) Arg(0); /* L1 */ SWAPOUT; c_p->arity = 0; - erts_smp_atomic32_read_band_relb(&c_p->state, ~ERTS_PSFLG_ACTIVE); + + if (!ERTS_PTMR_IS_TIMED_OUT(c_p)) + erts_smp_atomic32_read_band_relb(&c_p->state, + ~ERTS_PSFLG_ACTIVE); ASSERT(!ERTS_PROC_IS_EXITING(c_p)); erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE); c_p->current = NULL; @@ -4053,7 +4072,7 @@ do { \ tmp_arg1 += Arg1; store_bs_add_result: - if (MY_IS_SSMALL((Sint) tmp_arg1)) { + if (tmp_arg1 <= MAX_SMALL) { tmp_arg1 = make_small(tmp_arg1); } else { /* @@ -5002,7 +5021,7 @@ do { \ #ifdef NO_FPE_SIGNALS OpCase(fclearerror): OpCase(i_fcheckerror): - erl_exit(1, "fclearerror/i_fcheckerror without fpe signals (beam_emu)"); + erts_exit(ERTS_ERROR_EXIT, "fclearerror/i_fcheckerror without fpe signals (beam_emu)"); # define ERTS_NO_FPE_CHECK_INIT ERTS_FP_CHECK_INIT # define ERTS_NO_FPE_ERROR ERTS_FP_ERROR #else @@ -5160,7 +5179,7 @@ do { \ I = handle_error(c_p, I, reg, NULL); goto post_error_handling; default: - erl_exit(1, "hipe_mode_switch: result %u\n", c_p->def_arg_reg[3]); + erts_exit(ERTS_ERROR_EXIT, "hipe_mode_switch: result %u\n", c_p->def_arg_reg[3]); } } OpCase(hipe_call_count): { @@ -5240,7 +5259,7 @@ do { \ OpCase(label_L): OpCase(on_load): OpCase(line_I): - erl_exit(1, "meta op\n"); + erts_exit(ERTS_ERROR_EXIT, "meta op\n"); /* * One-time initialization of Beam emulator. @@ -5294,7 +5313,7 @@ do { \ } #ifdef NO_JUMP_TABLE default: - erl_exit(1, "unexpected op code %d\n",Go); + erts_exit(ERTS_ERROR_EXIT, "unexpected op code %d\n",Go); } #endif return; /* Never executed */ @@ -5339,7 +5358,7 @@ translate_gc_bif(void* gcf) } else if (gcf == erts_gc_binary_part_3) { return binary_part_3; } else { - erl_exit(1, "bad gc bif"); + erts_exit(ERTS_ERROR_EXIT, "bad gc bif"); } } @@ -5404,7 +5423,7 @@ handle_error(Process* c_p, BeamInstr* pc, Eterm* reg, BifFunction bf) Eterm* hp; Eterm Value = c_p->fvalue; Eterm Args = am_true; - c_p->i = pc; /* In case we call erl_exit(). */ + c_p->i = pc; /* In case we call erts_exit(). */ ASSERT(c_p->freason != TRAP); /* Should have been handled earlier. */ @@ -5468,7 +5487,7 @@ handle_error(Process* c_p, BeamInstr* pc, Eterm* reg, BifFunction bf) c_p->cp = 0; /* To avoid keeping stale references. */ return new_pc; } - if (c_p->catches > 0) erl_exit(1, "Catch not found"); + if (c_p->catches > 0) erts_exit(ERTS_ERROR_EXIT, "Catch not found"); } ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p); terminate_proc(c_p, Value); @@ -6219,6 +6238,23 @@ erts_hibernate(Process* c_p, Eterm module, Eterm function, Eterm args, Eterm* re int arity; Eterm tmp; +#ifndef ERTS_SMP + if (ERTS_PROC_IS_EXITING(c_p)) { + /* + * I non smp case: + * + * Currently executing process might be sent an exit + * signal if it is traced by a port that it also is + * linked to, and the port terminates during the + * trace. In this case we do *not* want to clear + * the active flag, which will make the process hang + * in limbo forever. Get out of here and terminate + * the process... + */ + return -1; + } +#endif + if (is_not_atom(module) || is_not_atom(function)) { /* * No need to test args here -- done below. @@ -6295,7 +6331,16 @@ erts_hibernate(Process* c_p, Eterm module, Eterm function, Eterm args, Eterm* re ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); PROCESS_MAIN_CHK_LOCKS(c_p); erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MSGQ|ERTS_PROC_LOCK_STATUS); -#ifdef ERTS_SMP +#ifndef ERTS_SMP + if (ERTS_PROC_IS_EXITING(c_p)) { + /* + * See comment in the begining of the function... + * + * This second test is needed since gc might be traced. + */ + return -1; + } +#else /* ERTS_SMP */ ERTS_SMP_MSGQ_MV_INQ2PRIVQ(c_p); if (!c_p->msg.len) #endif diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index b70e5b9a2d..a6dce2d1d2 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -6249,6 +6249,7 @@ erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info) code[MI_LITERALS_END] = 0; code[MI_LITERALS_OFF_HEAP] = 0; code[MI_ON_LOAD_FUNCTION_PTR] = 0; + code[MI_LINE_TABLE] = 0; code[MI_MD5_PTR] = 0; ci = MI_FUNCTIONS + n + 1; diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index 4e3a1cef69..095df36a43 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -616,7 +616,7 @@ erts_queue_monitor_message(Process *p, } static BIF_RETTYPE -local_pid_monitor(Process *p, Eterm target, Eterm mon_ref, int bool) +local_pid_monitor(Process *p, Eterm target, Eterm mon_ref, int boolean) { BIF_RETTYPE ret; Process *rp; @@ -634,7 +634,7 @@ local_pid_monitor(Process *p, Eterm target, Eterm mon_ref, int bool) if (!rp) { erts_smp_proc_unlock(p, ERTS_PROC_LOCK_LINK); p_locks &= ~ERTS_PROC_LOCK_LINK; - if (bool) + if (boolean) ret = am_false; else erts_queue_monitor_message(p, &p_locks, @@ -643,7 +643,7 @@ local_pid_monitor(Process *p, Eterm target, Eterm mon_ref, int bool) else { ASSERT(rp != p); - if (bool) + if (boolean) ret = am_true; erts_add_monitor(&ERTS_P_MONITORS(p), MON_ORIGIN, mon_ref, target, NIL); @@ -1605,14 +1605,17 @@ BIF_RETTYPE process_flag_2(BIF_ALIST_2) * true. For more info, see implementation of * erts_send_exit_signal(). */ + erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCKS_XSIG_SEND); if (trap_exit) state = erts_smp_atomic32_read_bor_mb(&BIF_P->state, ERTS_PSFLG_TRAP_EXIT); else state = erts_smp_atomic32_read_band_mb(&BIF_P->state, ~ERTS_PSFLG_TRAP_EXIT); + erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCKS_XSIG_SEND); + #ifdef ERTS_SMP - if (ERTS_PROC_PENDING_EXIT(BIF_P)) { + if (state & ERTS_PSFLG_PENDING_EXIT) { erts_handle_pending_exit(BIF_P, ERTS_PROC_LOCK_MAIN); ERTS_BIF_EXITED(BIF_P); } @@ -2216,7 +2219,7 @@ BIF_RETTYPE send_3(BIF_ALIST_3) erts_dsend_export_trap_context(p, ctx)); break; default: - erl_exit(ERTS_ABORT_EXIT, "send_3 invalid result %d\n", (int)result); + erts_exit(ERTS_ABORT_EXIT, "send_3 invalid result %d\n", (int)result); break; } @@ -2260,7 +2263,7 @@ static BIF_RETTYPE dsend_continue_trap_1(BIF_ALIST_1) BIF_TRAP1(&dsend_continue_trap_export, BIF_P, BIF_ARG_1); } default: - erl_exit(ERTS_ABORT_EXIT, "dsend_continue_trap invalid result %d\n", (int)result); + erts_exit(ERTS_ABORT_EXIT, "dsend_continue_trap invalid result %d\n", (int)result); break; } ASSERT(! "Can not arrive here"); @@ -2332,7 +2335,7 @@ Eterm erl_send(Process *p, Eterm to, Eterm msg) erts_dsend_export_trap_context(p, ctx)); break; default: - erl_exit(ERTS_ABORT_EXIT, "invalid send result %d\n", (int)result); + erts_exit(ERTS_ABORT_EXIT, "invalid send result %d\n", (int)result); break; } @@ -3883,7 +3886,7 @@ BIF_RETTYPE erts_debug_display_1(BIF_ALIST_1) erts_dsprintf_buf_t *dsbufp = erts_create_tmp_dsbuf(64); pres = erts_dsprintf(dsbufp, "%.*T\n", INT_MAX, BIF_ARG_1); if (pres < 0) - erl_exit(1, "Failed to convert term to string: %d (%s)\n", + erts_exit(ERTS_ERROR_EXIT, "Failed to convert term to string: %d (%s)\n", -pres, erl_errno_id(-pres)); hp = HAlloc(BIF_P, 2*dsbufp->str_len); /* we need length * 2 heap words */ res = buf_to_intlist(&hp, dsbufp->str, dsbufp->str_len, NIL); @@ -3905,7 +3908,7 @@ BIF_RETTYPE display_string_1(BIF_ALIST_1) } str = (char *) erts_alloc(ERTS_ALC_T_TMP, sizeof(char)*(len + 1)); if (intlist_to_buf(string, str, len) != len) - erl_exit(1, "%s:%d: Internal error\n", __FILE__, __LINE__); + erts_exit(ERTS_ERROR_EXIT, "%s:%d: Internal error\n", __FILE__, __LINE__); str[len] = '\0'; erts_fprintf(stderr, "%s", str); erts_free(ERTS_ALC_T_TMP, (void *) str); @@ -3925,7 +3928,7 @@ BIF_RETTYPE display_nl_0(BIF_ALIST_0) BIF_RETTYPE halt_0(BIF_ALIST_0) { VERBOSE(DEBUG_SYSTEM,("System halted by BIF halt()\n")); - erl_halt(0); + erts_halt(0); ERTS_BIF_YIELD1(bif_export[BIF_halt_1], BIF_P, am_undefined); } @@ -3938,17 +3941,18 @@ static char halt_msg[HALT_MSG_SIZE]; /* ARGSUSED */ BIF_RETTYPE halt_1(BIF_ALIST_1) { - Sint code; + Uint code; - if (is_small(BIF_ARG_1) && (code = signed_val(BIF_ARG_1)) >= 0) { + if (term_to_Uint_mask(BIF_ARG_1, &code)) { + int pos_int_code = (int) (code & INT_MAX); VERBOSE(DEBUG_SYSTEM,("System halted by BIF halt(%T)\n", BIF_ARG_1)); - erl_halt((int)(- code)); + erts_halt(pos_int_code); ERTS_BIF_YIELD1(bif_export[BIF_halt_1], BIF_P, am_undefined); } else if (ERTS_IS_ATOM_STR("abort", BIF_ARG_1)) { VERBOSE(DEBUG_SYSTEM,("System halted by BIF halt(%T)\n", BIF_ARG_1)); erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erl_exit(ERTS_ABORT_EXIT, ""); + erts_exit(ERTS_ABORT_EXIT, ""); } else if (is_string(BIF_ARG_1) || BIF_ARG_1 == NIL) { int i; @@ -3959,11 +3963,11 @@ BIF_RETTYPE halt_1(BIF_ALIST_1) halt_msg[i] = '\0'; VERBOSE(DEBUG_SYSTEM,("System halted by BIF halt(%T)\n", BIF_ARG_1)); erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erl_exit(ERTS_DUMP_EXIT, "%s\n", halt_msg); + erts_exit(ERTS_DUMP_EXIT, "%s\n", halt_msg); } else goto error; - return NIL; /* Pedantic (lint does not know about erl_exit) */ + return NIL; /* Pedantic (lint does not know about erts_exit) */ error: BIF_ERROR(BIF_P, BADARG); } @@ -3974,7 +3978,7 @@ BIF_RETTYPE halt_1(BIF_ALIST_1) /* ARGSUSED */ BIF_RETTYPE halt_2(BIF_ALIST_2) { - Sint code; + Uint code; Eterm optlist = BIF_ARG_2; int flush = 1; @@ -4001,23 +4005,24 @@ BIF_RETTYPE halt_2(BIF_ALIST_2) if (is_not_nil(optlist)) goto error; - if (is_small(BIF_ARG_1) && (code = signed_val(BIF_ARG_1)) >= 0) { + if (term_to_Uint_mask(BIF_ARG_1, &code)) { + int pos_int_code = (int) (code & INT_MAX); VERBOSE(DEBUG_SYSTEM, ("System halted by BIF halt(%T, %T)\n", BIF_ARG_1, BIF_ARG_2)); if (flush) { - erl_halt((int)(- code)); + erts_halt(pos_int_code); ERTS_BIF_YIELD1(bif_export[BIF_halt_1], BIF_P, am_undefined); } else { erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erl_exit((int)(- code), ""); + erts_exit(pos_int_code, ""); } } else if (ERTS_IS_ATOM_STR("abort", BIF_ARG_1)) { VERBOSE(DEBUG_SYSTEM, ("System halted by BIF halt(%T, %T)\n", BIF_ARG_1, BIF_ARG_2)); erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erl_exit(ERTS_ABORT_EXIT, ""); + erts_exit(ERTS_ABORT_EXIT, ""); } else if (is_string(BIF_ARG_1) || BIF_ARG_1 == NIL) { int i; @@ -4029,11 +4034,11 @@ BIF_RETTYPE halt_2(BIF_ALIST_2) VERBOSE(DEBUG_SYSTEM, ("System halted by BIF halt(%T, %T)\n", BIF_ARG_1, BIF_ARG_2)); erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erl_exit(ERTS_DUMP_EXIT, "%s\n", halt_msg); + erts_exit(ERTS_DUMP_EXIT, "%s\n", halt_msg); } else goto error; - return NIL; /* Pedantic (lint does not know about erl_exit) */ + return NIL; /* Pedantic (lint does not know about erts_exit) */ error: BIF_ERROR(BIF_P, BADARG); } @@ -4089,7 +4094,7 @@ term2list_dsprintf(Process *p, Eterm term) erts_dsprintf_buf_t *dsbufp = erts_create_tmp_dsbuf(64); pres = erts_dsprintf(dsbufp, "%T", term); if (pres < 0) - erl_exit(1, "Failed to convert term to list: %d (%s)\n", + erts_exit(ERTS_ERROR_EXIT, "Failed to convert term to list: %d (%s)\n", -pres, erl_errno_id(-pres)); hp = HAlloc(p, 2*dsbufp->str_len); /* we need length * 2 heap words */ res = buf_to_intlist(&hp, dsbufp->str, dsbufp->str_len, NIL); @@ -4231,6 +4236,7 @@ BIF_RETTYPE list_to_pid_1(BIF_ALIST_1) goto bad; enp = erts_find_or_insert_node(dep->sysname, dep->creation); + ASSERT(enp != erts_this_node); etp = (ExternalThing *) HAlloc(BIF_P, EXTERNAL_THING_HEAD_SIZE + 1); etp->header = make_external_pid_header(1); diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab index 4f0656d174..3177d5dae7 100644 --- a/erts/emulator/beam/bif.tab +++ b/erts/emulator/beam/bif.tab @@ -174,6 +174,8 @@ bif erts_internal:time_unit/0 bif erts_internal:is_system_process/1 +bif erts_internal:system_check/1 + # inet_db support bif erlang:port_set_data/2 bif erlang:port_get_data/1 diff --git a/erts/emulator/beam/big.c b/erts/emulator/beam/big.c index 044bf6a34e..87d3be2b0f 100644 --- a/erts/emulator/beam/big.c +++ b/erts/emulator/beam/big.c @@ -2028,6 +2028,32 @@ term_to_Uint(Eterm term, Uint *up) } } +/* same as term_to_Uint() + but also accept larger bignums by masking + */ +int +term_to_Uint_mask(Eterm term, Uint *up) +{ + if (is_small(term)) { + Sint i = signed_val(term); + if (i < 0) { + *up = BADARG; + return 0; + } + *up = (Uint) i; + return 1; + } else if (is_big(term) && !big_sign(term)) { + ErtsDigit* xr = big_v(term); + + ERTS_CT_ASSERT(sizeof(ErtsDigit) == sizeof(Uint)); + *up = (Uint)*xr; /* just pick first word */ + return 1; + } else { + *up = BADARG; + return 0; + } +} + int term_to_UWord(Eterm term, UWord *up) { @@ -2618,6 +2644,9 @@ Eterm erts_chars_to_integer(Process *BIF_P, char *bytes, size--; } + if (size == 0) + goto bytebuf_to_integer_1_error; + if (size < SMALL_DIGITS && base <= 10) { /* * * Take shortcut if we know that all chars are '0' < b < '9' and diff --git a/erts/emulator/beam/big.h b/erts/emulator/beam/big.h index 4aa9724ae3..3c1f1e6b23 100644 --- a/erts/emulator/beam/big.h +++ b/erts/emulator/beam/big.h @@ -161,6 +161,7 @@ Eterm bytes_to_big(byte*, dsize_t, int, Eterm*); byte* big_to_bytes(Eterm, byte*); int term_to_Uint(Eterm, Uint*); +int term_to_Uint_mask(Eterm, Uint*); int term_to_UWord(Eterm, UWord*); int term_to_Sint(Eterm, Sint*); #if HAVE_INT64 diff --git a/erts/emulator/beam/binary.c b/erts/emulator/beam/binary.c index e670fbf31c..247c8f1122 100644 --- a/erts/emulator/beam/binary.c +++ b/erts/emulator/beam/binary.c @@ -47,7 +47,7 @@ erts_init_binary(void) if ((((UWord) &((Binary *) 0)->orig_bytes[0]) % ((UWord) 8)) != 0) { /* I assume that any compiler should be able to optimize this away. If not, this test is not very expensive... */ - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Internal error: Address of orig_bytes[0] of a Binary" " is *not* 8-byte aligned\n"); } diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c index 64c8bc5e58..0ddf7f4e6d 100644 --- a/erts/emulator/beam/break.c +++ b/erts/emulator/beam/break.c @@ -104,7 +104,7 @@ process_killer(void) erts_printf("(k)ill (n)ext (r)eturn:\n"); while(1) { if ((j = sys_get_key(0)) <= 0) - erl_exit(0, ""); + erts_exit(0, ""); switch(j) { case 'k': { ErtsProcLocks rp_locks = ERTS_PROC_LOCKS_XSIG_SEND; @@ -493,7 +493,7 @@ do_break(void) halt immediately if break is called */ mode = erts_read_env("ERL_CONSOLE_MODE"); if (mode && strcmp(mode, "window") != 0) - erl_exit(0, ""); + erts_exit(0, ""); erts_free_read_env(mode); #endif /* __WIN32__ */ @@ -503,7 +503,7 @@ do_break(void) while (1) { if ((i = sys_get_key(0)) <= 0) - erl_exit(0, ""); + erts_exit(0, ""); switch (i) { case 'q': case 'a': @@ -513,9 +513,9 @@ do_break(void) * The usual reason for a read error is Ctrl-C. Treat this as * 'a' to avoid infinite loop. */ - erl_exit(0, ""); + erts_exit(0, ""); case 'A': /* Halt generating crash dump */ - erl_exit(1, "Crash dump requested by user"); + erts_exit(ERTS_ERROR_EXIT, "Crash dump requested by user"); case 'c': return; case 'p': @@ -536,7 +536,9 @@ do_break(void) erts_printf("Erlang (%s) emulator version " ERLANG_VERSION "\n", EMULATOR); +#if ERTS_SAVED_COMPILE_TIME erts_printf("Compiled on " ERLANG_COMPILE_DATE "\n"); +#endif return; case 'd': distribution_info(ERTS_PRINT_STDOUT, NULL); @@ -774,14 +776,16 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args) } erts_fdprintf(fd, "System version: "); erts_print_system_version(fd, NULL, NULL); +#if ERTS_SAVED_COMPILE_TIME erts_fdprintf(fd, "%s\n", "Compiled: " ERLANG_COMPILE_DATE); +#endif erts_fdprintf(fd, "Taints: "); erts_print_nif_taints(fd, NULL); erts_fdprintf(fd, "Atoms: %d\n", atom_table_size()); #ifdef USE_THREADS - /* We want to note which thread it was that called erl_exit */ + /* We want to note which thread it was that called erts_exit */ if (erts_get_scheduler_data()) { erts_fdprintf(fd, "Calling Thread: scheduler:%d\n", erts_get_scheduler_data()->no); diff --git a/erts/emulator/beam/copy.c b/erts/emulator/beam/copy.c index 8849dadd00..64be43edb4 100644 --- a/erts/emulator/beam/copy.c +++ b/erts/emulator/beam/copy.c @@ -59,7 +59,7 @@ copy_object(Eterm obj, Process* to) res = copy_struct(obj, size, &hp, &to->off_heap); #ifdef DEBUG if (eq(obj, res) == 0) { - erl_exit(ERTS_ABORT_EXIT, "copy not equal to source\n"); + erts_exit(ERTS_ABORT_EXIT, "copy not equal to source\n"); } #endif return res; @@ -171,7 +171,7 @@ Uint size_object(Eterm obj) } break; default: - erl_exit(ERTS_ABORT_EXIT, "size_object: bad hashmap type %d\n", MAP_HEADER_TYPE(hdr)); + erts_exit(ERTS_ABORT_EXIT, "size_object: bad hashmap type %d\n", MAP_HEADER_TYPE(hdr)); } break; case SUB_BINARY_SUBTAG: @@ -202,7 +202,7 @@ Uint size_object(Eterm obj) } break; case BIN_MATCHSTATE_SUBTAG: - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "size_object: matchstate term not allowed"); default: sum += thing_arityval(hdr) + 1; @@ -219,7 +219,7 @@ Uint size_object(Eterm obj) obj = ESTACK_POP(s); break; default: - erl_exit(ERTS_ABORT_EXIT, "size_object: bad tag for %#x\n", obj); + erts_exit(ERTS_ABORT_EXIT, "size_object: bad tag for %#x\n", obj); } } } @@ -272,7 +272,7 @@ Eterm copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap) goto L_copy_list; case TAG_PRIMARY_BOXED: argp = &res; goto L_copy_boxed; default: - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%s, line %d: Internal error in copy_struct: 0x%08x\n", __FILE__, __LINE__,obj); } @@ -331,7 +331,7 @@ Eterm copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap) case TAG_PRIMARY_IMMED1: *tailp = obj; goto L_copy; case TAG_PRIMARY_BOXED: argp = tailp; goto L_copy_boxed; default: - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%s, line %d: Internal error in copy_struct: 0x%08x\n", __FILE__, __LINE__,obj); } @@ -512,11 +512,11 @@ Eterm copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap) *argp = make_hashmap_rel(tp, dst_base); break; default: - erl_exit(ERTS_ABORT_EXIT, "copy_struct: bad hashmap type %d\n", MAP_HEADER_TYPE(hdr)); + erts_exit(ERTS_ABORT_EXIT, "copy_struct: bad hashmap type %d\n", MAP_HEADER_TYPE(hdr)); } break; case BIN_MATCHSTATE_SUBTAG: - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "copy_struct: matchstate term not allowed"); default: i = thing_arityval(hdr)+1; @@ -540,13 +540,13 @@ Eterm copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap) #ifdef DEBUG if (htop != hbot) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Internal error in copy_struct() when copying %T:" " htop=%p != hbot=%p (sz=%beu)\n", org_obj, htop, hbot, org_sz); #else if (htop > hbot) { - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Internal error in copy_struct(): htop, hbot overrun\n"); } #endif diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c index 23897a49ae..787241b960 100644 --- a/erts/emulator/beam/dist.c +++ b/erts/emulator/beam/dist.c @@ -45,6 +45,8 @@ #include "erl_thr_progress.h" #include "dtrace-wrapper.h" +#define DIST_CTL_DEFAULT_SIZE 64 + /* Turn this on to get printouts of all distribution messages * which go on the line */ @@ -66,9 +68,13 @@ static void bw(byte *buf, ErlDrvSizeT sz) static void dist_msg_dbg(ErtsDistExternal *edep, char *what, byte *buf, int sz) { + ErtsHeapFactory factory; + DeclareTmpHeapNoproc(ctl_default,DIST_CTL_DEFAULT_SIZE); + Eterm* ctl = ctl_default; byte *extp = edep->extp; Eterm msg; - Sint size = erts_decode_dist_ext_size(edep); + Sint ctl_len; + Sint size = ctl_len = erts_decode_dist_ext_size(edep); if (size < 0) { erts_fprintf(stderr, "DIST MSG DEBUG: erts_decode_dist_ext_size(%s) failed:\n", @@ -76,10 +82,9 @@ dist_msg_dbg(ErtsDistExternal *edep, char *what, byte *buf, int sz) bw(buf, sz); } else { - Eterm *hp; ErlHeapFragment *mbuf = new_message_buffer(size); - hp = mbuf->mem; - msg = erts_decode_dist_ext(&hp, &mbuf->off_heap, edep); + erts_factory_static_init(&factory, ctl, ctl_len, &mbuf->off_heap); + msg = erts_decode_dist_ext(&factory, edep); if (is_value(msg)) erts_fprintf(stderr, " %s: %T\n", what, msg); else { @@ -1136,7 +1141,6 @@ int erts_net_message(Port *prt, byte *buf, ErlDrvSizeT len) { -#define DIST_CTL_DEFAULT_SIZE 64 ErtsDistExternal ede; byte *t; Sint ctl_len; @@ -1149,7 +1153,6 @@ int erts_net_message(Port *prt, Process* rp; DeclareTmpHeapNoproc(ctl_default,DIST_CTL_DEFAULT_SIZE); Eterm* ctl = ctl_default; - ErlOffHeap off_heap; ErtsHeapFactory factory; Eterm* hp; Sint type; @@ -1164,9 +1167,6 @@ int erts_net_message(Port *prt, #endif UseTmpHeapNoproc(DIST_CTL_DEFAULT_SIZE); - /* Thanks to Luke Gorrie */ - off_heap.first = NULL; - off_heap.overhead = 0; ERTS_SMP_CHK_NO_PROC_LOCKS; @@ -1227,15 +1227,15 @@ int erts_net_message(Port *prt, } hp = ctl; - erts_factory_static_init(&factory, ctl, ctl_len, &off_heap); + erts_factory_tmp_init(&factory, ctl, ctl_len, ERTS_ALC_T_DCTRL_BUF); arg = erts_decode_dist_ext(&factory, &ede); if (is_non_value(arg)) { #ifdef ERTS_DIST_MSG_DBG - erts_fprintf(stderr, "DIST MSG DEBUG: erts_dist_ext_size(CTL) failed:\n"); + erts_fprintf(stderr, "DIST MSG DEBUG: erts_decode_dist_ext(CTL) failed:\n"); bw(buf, orig_len); #endif PURIFY_MSG("data error"); - goto data_error; + goto decode_error; } ctl_len = t - buf; @@ -1715,7 +1715,7 @@ int erts_net_message(Port *prt, goto invalid_message; } - erts_cleanup_offheap(&off_heap); + erts_factory_close(&factory); if (ctl != ctl_default) { erts_free(ERTS_ALC_T_DCTRL_BUF, (void *) ctl); } @@ -1728,12 +1728,13 @@ int erts_net_message(Port *prt, erts_dsprintf(dsbufp, "Invalid distribution message: %.200T", arg); erts_send_error_to_logger_nogl(dsbufp); } - data_error: +decode_error: PURIFY_MSG("data error"); - erts_cleanup_offheap(&off_heap); + erts_factory_close(&factory); if (ctl != ctl_default) { erts_free(ERTS_ALC_T_DCTRL_BUF, (void *) ctl); } +data_error: UnUseTmpHeapNoproc(DIST_CTL_DEFAULT_SIZE); erts_deliver_port_exit(prt, dep->cid, am_killed, 0); ERTS_SMP_CHK_NO_PROC_LOCKS; @@ -1790,8 +1791,8 @@ erts_dsig_send(ErtsDSigData *dsdp, struct erts_dsig_send_context* ctx) #ifdef ERTS_DIST_MSG_DBG erts_fprintf(stderr, ">>%s CTL: %T\n", ctx->pass_through_size ? "P" : " ", ctx->ctl); - if (is_value(msg)) - erts_fprintf(stderr, " MSG: %T\n", msg); + if (is_value(ctx->msg)) + erts_fprintf(stderr, " MSG: %T\n", ctx->msg); #endif ctx->data_size = ctx->pass_through_size; @@ -1958,7 +1959,7 @@ erts_dsig_send(ErtsDSigData *dsdp, struct erts_dsig_send_context* ctx) goto done; } default: - erl_exit(ERTS_ABORT_EXIT, "dsig_send invalid phase (%d)\n", (int)ctx->phase); + erts_exit(ERTS_ABORT_EXIT, "dsig_send invalid phase (%d)\n", (int)ctx->phase); } } @@ -1979,7 +1980,7 @@ dist_port_command(Port *prt, ErtsDistOutputBuf *obuf) ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)); if (size > (Uint) INT_MAX) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Absurdly large distribution output data buffer " "(%beu bytes) passed.\n", size); @@ -2019,7 +2020,7 @@ dist_port_commandv(Port *prt, ErtsDistOutputBuf *obuf) ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)); if (size > (Uint) INT_MAX) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Absurdly large distribution output data buffer " "(%beu bytes) passed.\n", size); @@ -2572,7 +2573,9 @@ int distribution_info(int to, void *arg) /* Called by break handler */ } for (dep = erts_not_connected_dist_entries; dep; dep = dep->next) { - info_dist_entry(to, arg, dep, 0, 0); + if (dep != erts_this_dist_entry) { + info_dist_entry(to, arg, dep, 0, 0); + } } return(0); @@ -2650,13 +2653,8 @@ BIF_RETTYPE setnode_2(BIF_ALIST_2) if (!net_kernel) goto error; - /* By setting dist_entry==erts_this_dist_entry and DISTRIBUTION on - net_kernel do_net_exist will be called when net_kernel - is terminated !! */ - (void) ERTS_PROC_SET_DIST_ENTRY(net_kernel, - ERTS_PROC_LOCK_MAIN, - erts_this_dist_entry); - erts_refc_inc(&erts_this_dist_entry->refc, 2); + /* By setting F_DISTRIBUTION on net_kernel, + * do_net_exist will be called when net_kernel is terminated !! */ net_kernel->flags |= F_DISTRIBUTION; if (net_kernel != BIF_P) @@ -3017,11 +3015,11 @@ BIF_RETTYPE nodes_1(BIF_ALIST_1) erts_smp_rwmtx_rlock(&erts_dist_table_rwmtx); - ASSERT(erts_no_of_not_connected_dist_entries >= 0); + ASSERT(erts_no_of_not_connected_dist_entries > 0); ASSERT(erts_no_of_hidden_dist_entries >= 0); ASSERT(erts_no_of_visible_dist_entries >= 0); if(not_connected) - length += erts_no_of_not_connected_dist_entries; + length += (erts_no_of_not_connected_dist_entries - 1); if(hidden) length += erts_no_of_hidden_dist_entries; if(visible) @@ -3043,8 +3041,10 @@ BIF_RETTYPE nodes_1(BIF_ALIST_1) #endif if(not_connected) for(dep = erts_not_connected_dist_entries; dep; dep = dep->next) { - result = CONS(hp, dep->sysname, result); - hp += 2; + if (dep != erts_this_dist_entry) { + result = CONS(hp, dep->sysname, result); + hp += 2; + } } if(hidden) for(dep = erts_hidden_dist_entries; dep; dep = dep->next) { @@ -3382,7 +3382,7 @@ send_nodes_mon_msgs(Process *c_p, Eterm what, Eterm node, Eterm type, Eterm reas continue; break; default: - erl_exit(ERTS_ABORT_EXIT, "Bad node type found\n"); + erts_exit(ERTS_ABORT_EXIT, "Bad node type found\n"); } } @@ -3691,7 +3691,7 @@ erts_processes_monitoring_nodes(Process *c_p) case ERTS_NODES_MON_OPT_TYPES: type = am_all; break; case ERTS_NODES_MON_OPT_TYPE_VISIBLE: type = am_visible; break; case ERTS_NODES_MON_OPT_TYPE_HIDDEN: type = am_hidden; break; - default: erl_exit(ERTS_ABORT_EXIT, "Bad node type found\n"); + default: erts_exit(ERTS_ABORT_EXIT, "Bad node type found\n"); } olist = erts_bld_cons(hpp, szp, erts_bld_tuple(hpp, szp, 2, diff --git a/erts/emulator/beam/erl_afit_alloc.c b/erts/emulator/beam/erl_afit_alloc.c index 47dafa53c0..4b0541c10e 100644 --- a/erts/emulator/beam/erl_afit_alloc.c +++ b/erts/emulator/beam/erl_afit_alloc.c @@ -241,7 +241,7 @@ info_options(Allctr_t *allctr, if (hpp || szp) { if (!atoms_initialized) - erl_exit(1, "%s:%d: Internal error: Atoms not initialized", + erts_exit(ERTS_ERROR_EXIT, "%s:%d: Internal error: Atoms not initialized", __FILE__, __LINE__);; res = NIL; diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c index 55c164bf11..5f8cd2bbf7 100644 --- a/erts/emulator/beam/erl_alloc.c +++ b/erts/emulator/beam/erl_alloc.c @@ -134,6 +134,7 @@ static ErtsAllocatorState_t binary_alloc_state; static ErtsAllocatorState_t ets_alloc_state; static ErtsAllocatorState_t driver_alloc_state; static ErtsAllocatorState_t fix_alloc_state; +static ErtsAllocatorState_t test_alloc_state; typedef struct { erts_smp_atomic32_t refc; @@ -233,6 +234,7 @@ typedef struct { struct au_init std_low_alloc; struct au_init ll_low_alloc; #endif + struct au_init test_alloc; } erts_alc_hndl_args_init_t; #define ERTS_AU_INIT__ {0, 0, 1, GOODFIT, DEFAULT_ALLCTR_INIT, {1,1,1,1}} @@ -432,6 +434,33 @@ set_default_fix_alloc_opts(struct au_init *ip, ip->init.util.acul = ERTS_ALC_DEFAULT_ACUL; } +static void +set_default_test_alloc_opts(struct au_init *ip) +{ + SET_DEFAULT_ALLOC_OPTS(ip); + ip->enable = 0; /* Disabled by default */ + ip->thr_spec = -1 * erts_no_schedulers; + ip->atype = AOFIRSTFIT; + ip->init.aoff.flavor = AOFF_BF; + ip->init.util.name_prefix = "test_"; + ip->init.util.alloc_no = ERTS_ALC_A_TEST; + ip->init.util.mmbcs = 0; /* Main carrier size */ + ip->init.util.ts = ERTS_ALC_MTA_TEST; + ip->init.util.acul = ERTS_ALC_DEFAULT_ACUL; + + /* Use a constant minimal MBC size */ +#if ERTS_SA_MB_CARRIERS + ip->init.util.smbcs = ERTS_SACRR_UNIT_SZ; + ip->init.util.lmbcs = ERTS_SACRR_UNIT_SZ; + ip->init.util.sbct = ERTS_SACRR_UNIT_SZ; +#else + ip->init.util.smbcs = 1 << 12; + ip->init.util.lmbcs = 1 << 12; + ip->init.util.sbct = 1 << 12; +#endif +} + + #ifdef ERTS_SMP static void @@ -613,6 +642,7 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop) set_default_driver_alloc_opts(&init.driver_alloc); set_default_fix_alloc_opts(&init.fix_alloc, fix_type_sizes); + set_default_test_alloc_opts(&init.test_alloc); if (argc && argv) handle_args(argc, argv, &init); @@ -623,11 +653,11 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop) if (mlockall(MCL_CURRENT|MCL_FUTURE) != 0) { int err = errno; char *errstr = err ? strerror(err) : "unknown"; - erl_exit(-1, "Failed to lock physical memory: %s (%d)\n", + erts_exit(1, "Failed to lock physical memory: %s (%d)\n", errstr, err); } #else - erl_exit(-1, "Failed to lock physical memory: Not supported\n"); + erts_exit(1, "Failed to lock physical memory: Not supported\n"); #endif } @@ -772,16 +802,17 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop) set_au_allocator(ERTS_ALC_A_ETS, &init.ets_alloc, ncpu); set_au_allocator(ERTS_ALC_A_DRIVER, &init.driver_alloc, ncpu); set_au_allocator(ERTS_ALC_A_FIXED_SIZE, &init.fix_alloc, ncpu); + set_au_allocator(ERTS_ALC_A_TEST, &init.test_alloc, ncpu); for (i = ERTS_ALC_A_MIN; i <= ERTS_ALC_A_MAX; i++) { if (!erts_allctrs[i].alloc) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Missing alloc function for %s\n", ERTS_ALC_A2AD(i)); if (!erts_allctrs[i].realloc) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Missing realloc function for %s\n", ERTS_ALC_A2AD(i)); if (!erts_allctrs[i].free) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Missing free function for %s\n", ERTS_ALC_A2AD(i)); } @@ -833,6 +864,10 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop) &init.fix_alloc, &fix_alloc_state); + start_au_allocator(ERTS_ALC_A_TEST, + &init.test_alloc, + &test_alloc_state); + erts_mtrace_install_wrapper_functions(); extra_block_size += erts_instr_init(init.instr.stat, init.instr.map); @@ -855,7 +890,7 @@ erts_alloc_late_init(void) static void * erts_realloc_fixed_size(ErtsAlcType_t type, void *extra, void *p, Uint size) { - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Attempt to reallocate a block of the fixed size type %s\n", ERTS_ALC_T2TD(type)); } @@ -977,7 +1012,7 @@ start_au_allocator(ErtsAlcType_t alctr_n, * tspec->size) + ERTS_CACHE_LINE_SIZE - 1)); if (!states) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Failed to allocate allocator states for %salloc\n", init->init.util.name_prefix); tspec->allctr = (Allctr_t **) states; @@ -1005,7 +1040,7 @@ start_au_allocator(ErtsAlcType_t alctr_n, (tot_fix_list_size + ERTS_CACHE_LINE_SIZE - 1)); if (!fix_lists) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Failed to allocate fix lists for %salloc\n", init->init.util.name_prefix); @@ -1079,7 +1114,7 @@ start_au_allocator(ErtsAlcType_t alctr_n, } if (!as) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Failed to start %salloc\n", init->init.util.name_prefix); ASSERT(as == (void *) as0); @@ -1418,6 +1453,7 @@ handle_args(int *argc, char **argv, erts_alc_hndl_args_init_t *init) &init->fix_alloc, &init->sl_alloc, &init->temp_alloc + /* test_alloc not affected by +Mea??? or +Mu??? */ }; int aui_sz = (int) sizeof(aui)/sizeof(aui[0]); char *arg; @@ -1508,6 +1544,9 @@ handle_args(int *argc, char **argv, erts_alc_hndl_args_init_t *init) case 'T': handle_au_arg(&init->temp_alloc, &argv[i][3], argv, &i, 0); break; + case 'Z': + handle_au_arg(&init->test_alloc, &argv[i][3], argv, &i, 0); + break; case 'Y': { /* sys_alloc */ if (has_prefix("tt", param+2)) { /* set trim threshold */ @@ -1870,7 +1909,7 @@ erts_alc_fatal_error(int error, int func, ErtsAlcType_t n, ...) case ERTS_ALC_O_FREE: op_str = "free"; break; default: op_str = "UNKNOWN"; break; } - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%s: %s operation not supported (memory type: \"%s\")\n", allctr_str, op_str, t_str); break; @@ -1884,18 +1923,18 @@ erts_alc_fatal_error(int error, int func, ErtsAlcType_t n, ...) va_start(argp, n); size = va_arg(argp, Uint); va_end(argp); - erl_exit(1, + erts_exit(ERTS_DUMP_EXIT, "%s: Cannot %s %lu bytes of memory (of type \"%s\").\n", allctr_str, op, size, t_str); break; } case ERTS_ALC_E_NOALLCTR: - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "erts_alloc: Unknown allocator type: %d\n", ERTS_ALC_T2A(ERTS_ALC_N2T(n))); break; default: - erl_exit(ERTS_ABORT_EXIT, "erts_alloc: Unknown error: %d\n", error); + erts_exit(ERTS_ABORT_EXIT, "erts_alloc: Unknown error: %d\n", error); break; } } @@ -2222,11 +2261,12 @@ erts_memory(int *print_to_p, void *print_to_arg, void *proc, Eterm earg) return am_badarg; } - /* All alloc_util allocators *have* to be enabled */ + /* All alloc_util allocators *have* to be enabled, except test_alloc */ for (ai = ERTS_ALC_A_MIN; ai <= ERTS_ALC_A_MAX; ai++) { switch (ai) { case ERTS_ALC_A_SYSTEM: + case ERTS_ALC_A_TEST: break; default: if (!erts_allctrs_info[ai].enabled @@ -2267,6 +2307,8 @@ erts_memory(int *print_to_p, void *print_to_arg, void *proc, Eterm earg) * contain any allocated memory. */ continue; + case ERTS_ALC_A_TEST: + continue; case ERTS_ALC_A_EHEAP: save = &size.processes; break; @@ -2675,14 +2717,17 @@ erts_alloc_util_allocators(void *proc) /* * Currently all allocators except sys_alloc are * alloc_util allocators. + * Also hide test_alloc which is disabled by default + * and only intended for our own testing. */ - sz = ((ERTS_ALC_A_MAX + 1 - ERTS_ALC_A_MIN) - 1)*2; + sz = ((ERTS_ALC_A_MAX + 1 - ERTS_ALC_A_MIN) - 2)*2; ASSERT(sz > 0); hp = HAlloc((Process *) proc, sz); res = NIL; for (i = ERTS_ALC_A_MAX; i >= ERTS_ALC_A_MIN; i--) { switch (i) { case ERTS_ALC_A_SYSTEM: + case ERTS_ALC_A_TEST: break; default: { char *alc_str = (char *) ERTS_ALC_A2AD(i); @@ -3144,7 +3189,7 @@ reply_alloc_info(void *vair) make_small(0), ainfo); } else { - erl_exit(ERTS_ABORT_EXIT, "%s:%d: internal error\n", + erts_exit(ERTS_ABORT_EXIT, "%s:%d: internal error\n", __FILE__, __LINE__); } } @@ -3381,7 +3426,7 @@ void *safe_realloc(void *ptr, Uint sz) * Keep alloc_SUITE_data/allocator_test.h updated if changes are made * * to erts_alc_test() * \* */ -#define ERTS_ALC_TEST_ABORT erl_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error\n") +#define ERTS_ALC_TEST_ABORT erts_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error\n") UWord erts_alc_test(UWord op, UWord a1, UWord a2, UWord a3) { @@ -3566,6 +3611,41 @@ UWord erts_alc_test(UWord op, UWord a1, UWord a2, UWord a3) #else case 0xf13: return (UWord) 0; #endif + case 0xf14: return (UWord) erts_alloc(ERTS_ALC_T_TEST, (Uint)a1); + + case 0xf15: erts_free(ERTS_ALC_T_TEST, (void*)a1); return 0; + + case 0xf16: { + Uint extra_hdr_sz = UNIT_CEILING((Uint)a1); + ErtsAllocatorThrSpec_t* ts = &erts_allctr_thr_spec[ERTS_ALC_A_TEST]; + Uint offset = ts->allctr[0]->mbc_header_size; + void* orig_creating_mbc = ts->allctr[0]->creating_mbc; + void* orig_destroying_mbc = ts->allctr[0]->destroying_mbc; + void* new_creating_mbc = *(void**)a2; /* inout arg */ + void* new_destroying_mbc = *(void**)a3; /* inout arg */ + int i; + + for (i=0; i < ts->size; i++) { + Allctr_t* ap = ts->allctr[i]; + if (ap->mbc_header_size != offset + || ap->creating_mbc != orig_creating_mbc + || ap->destroying_mbc != orig_destroying_mbc + || ap->mbc_list.first != NULL) + return -1; + } + for (i=0; i < ts->size; i++) { + ts->allctr[i]->mbc_header_size += extra_hdr_sz; + ts->allctr[i]->creating_mbc = new_creating_mbc; + ts->allctr[i]->destroying_mbc = new_destroying_mbc; + } + *(void**)a2 = orig_creating_mbc; + *(void**)a3 = orig_destroying_mbc; + return offset; + } + case 0xf17: { + ErtsAllocatorThrSpec_t* ts = &erts_allctr_thr_spec[ERTS_ALC_A_TEST]; + return ts->allctr[0]->largest_mbc_size; + } default: break; } @@ -3808,7 +3888,7 @@ check_memory_fence(void *ptr, Uint *size, ErtsAlcType_t n, int func) found_type = GET_TYPE_OF_PATTERN(pre_pattern); if (pre_pattern != MK_PATTERN(n)) { if ((FIXED_FENCE_PATTERN_MASK & pre_pattern) != FIXED_FENCE_PATTERN) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "ERROR: Fence at beginning of memory block (p=0x%u) " "clobbered.\n", (UWord) ptr); @@ -3825,12 +3905,12 @@ check_memory_fence(void *ptr, Uint *size, ErtsAlcType_t n, int func) char *op_str; if ((FIXED_FENCE_PATTERN_MASK & post_pattern) != FIXED_FENCE_PATTERN) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "ERROR: Fence at end of memory block (p=0x%u, sz=%u) " "clobbered.\n", (UWord) ptr, (UWord) sz); if (found_type != GET_TYPE_OF_PATTERN(post_pattern)) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "ERROR: Fence around memory block (p=0x%u, sz=%u) " "clobbered.\n", (UWord) ptr, (UWord) sz); @@ -3853,7 +3933,7 @@ check_memory_fence(void *ptr, Uint *size, ErtsAlcType_t n, int func) default: op_str = "???"; break; } - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "ERROR: Memory block (p=0x%u, sz=%u) allocated as type \"%s\"," " but %s as type \"%s\".\n", (UWord) ptr, (UWord) sz, ftype, op_str, otype); diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types index b1d511ab78..7738531142 100644 --- a/erts/emulator/beam/erl_alloc.types +++ b/erts/emulator/beam/erl_alloc.types @@ -112,7 +112,7 @@ allocator STANDARD_LOW false std_low_alloc allocator BINARY true binary_alloc allocator DRIVER true driver_alloc - +allocator TEST true test_alloc # --- Class declarations ----------------------------------------------------- # @@ -369,6 +369,7 @@ type AINFO_REQ STANDARD_LOW SYSTEM alloc_info_request type SCHED_WTIME_REQ STANDARD_LOW SYSTEM sched_wall_time_request type GC_INFO_REQ STANDARD_LOW SYSTEM gc_info_request type PORT_DATA_HEAP STANDARD_LOW SYSTEM port_data_heap +type SYS_CHECK_REQ STANDARD_LOW SYSTEM system_check_request +else # "fullword" @@ -389,6 +390,7 @@ type AINFO_REQ SHORT_LIVED SYSTEM alloc_info_request type SCHED_WTIME_REQ SHORT_LIVED SYSTEM sched_wall_time_request type GC_INFO_REQ SHORT_LIVED SYSTEM gc_info_request type PORT_DATA_HEAP STANDARD SYSTEM port_data_heap +type SYS_CHECK_REQ SHORT_LIVED SYSTEM system_check_request +endif @@ -456,4 +458,7 @@ type CON_VPRINTF_BUF TEMPORARY SYSTEM con_vprintf_buf +endif +# This type should only be used for test +type TEST TEST SYSTEM testing + # ---------------------------------------------------------------------------- diff --git a/erts/emulator/beam/erl_alloc_util.c b/erts/emulator/beam/erl_alloc_util.c index 236ee35d18..d9eaa7b32c 100644 --- a/erts/emulator/beam/erl_alloc_util.c +++ b/erts/emulator/beam/erl_alloc_util.c @@ -1437,6 +1437,16 @@ erts_alcu_fix_alloc_shrink(Allctr_t *allctr, erts_aint32_t flgs) static void dealloc_carrier(Allctr_t *allctr, Carrier_t *crr, int superaligned); +static ERTS_INLINE void +dealloc_mbc(Allctr_t *allctr, Carrier_t *crr) +{ + ASSERT(IS_MB_CARRIER(crr)); + if (allctr->destroying_mbc) + allctr->destroying_mbc(allctr, crr); + + dealloc_carrier(allctr, crr, 1); +} + #ifdef ERTS_SMP static ERTS_INLINE Allctr_t* @@ -3149,7 +3159,7 @@ cpool_fetch(Allctr_t *allctr, UWord size) cpool_entrance = sentinel; cpdp = cpool_aint2cpd(cpool_read(&cpool_entrance->prev)); if (cpdp == sentinel) - return NULL; + goto check_dc_list; } has_passed_sentinel = 0; @@ -3160,18 +3170,18 @@ cpool_fetch(Allctr_t *allctr, UWord size) if (cpool_entrance == sentinel) { cpdp = cpool_aint2cpd(cpool_read(&cpdp->prev)); if (cpdp == sentinel) - return NULL; + break; } i = 0; /* Last one to inspect */ } else if (cpdp == sentinel) { if (has_passed_sentinel) { /* We been here before. cpool_entrance must have been removed */ - return NULL; + break; } cpdp = cpool_aint2cpd(cpool_read(&cpdp->prev)); if (cpdp == sentinel) - return NULL; + break; has_passed_sentinel = 1; } crr = (Carrier_t *)(((char *)cpdp) - offsetof(Carrier_t, cpool)); @@ -3195,10 +3205,12 @@ cpool_fetch(Allctr_t *allctr, UWord size) return NULL; } +check_dc_list: /* Last; check our own pending dealloc carrier list... */ crr = allctr->cpool.dc_list.last; while (crr) { if (erts_atomic_read_nob(&crr->cpool.max_size) >= size) { + Block_t* blk; unlink_carrier(&allctr->cpool.dc_list, crr); #ifdef ERTS_ALC_CPOOL_DEBUG ERTS_ALC_CPOOL_ASSERT(erts_smp_atomic_xchg_nob(&crr->allctr, @@ -3207,6 +3219,9 @@ cpool_fetch(Allctr_t *allctr, UWord size) #else erts_smp_atomic_set_nob(&crr->allctr, ((erts_aint_t) allctr)); #endif + blk = MBC_TO_FIRST_BLK(allctr, crr); + ASSERT(FBLK_TO_MBC(blk) == crr); + allctr->link_free_block(allctr, blk); return crr; } crr = crr->prev; @@ -3237,7 +3252,7 @@ check_pending_dealloc_carrier(Allctr_t *allctr, dcrr = crr; crr = crr->next; - dealloc_carrier(allctr, dcrr, 1); + dealloc_mbc(allctr, dcrr); i++; } while (crr && i < ERTS_ALC_MAX_DEALLOC_CARRIER); @@ -3268,18 +3283,20 @@ static void schedule_dealloc_carrier(Allctr_t *allctr, Carrier_t *crr) { Allctr_t *orig_allctr; + Block_t *blk; int check_pending_dealloc; erts_aint_t max_size; + ASSERT(IS_MB_CARRIER(crr)); + if (!ERTS_ALC_IS_CPOOL_ENABLED(allctr)) { - dealloc_carrier(allctr, crr, 1); + dealloc_mbc(allctr, crr); return; } orig_allctr = crr->cpool.orig_allctr; if (allctr != orig_allctr) { - Block_t *blk = MBC_TO_FIRST_BLK(allctr, crr); int cinit = orig_allctr->dd.ix - allctr->dd.ix; /* @@ -3296,6 +3313,7 @@ schedule_dealloc_carrier(Allctr_t *allctr, Carrier_t *crr) * since the block is an mbc block that is free and last * in the carrier. */ + blk = MBC_TO_FIRST_BLK(allctr, crr); ERTS_ALC_CPOOL_ASSERT(IS_FREE_LAST_MBC_BLK(blk)); ERTS_ALC_CPOOL_ASSERT(IS_MBC_FIRST_ABLK(allctr, blk)); @@ -3315,11 +3333,13 @@ schedule_dealloc_carrier(Allctr_t *allctr, Carrier_t *crr) if (crr->cpool.thr_prgr == ERTS_THR_PRGR_INVALID || erts_thr_progress_has_reached(crr->cpool.thr_prgr)) { - dealloc_carrier(allctr, crr, 1); + dealloc_mbc(allctr, crr); return; } - max_size = (erts_aint_t) allctr->largest_fblk_in_mbc(allctr, crr); + blk = MBC_TO_FIRST_BLK(allctr, crr); + ASSERT(IS_FREE_LAST_MBC_BLK(blk)); + max_size = (erts_aint_t) MBC_FBLK_SZ(blk); erts_atomic_set_nob(&crr->cpool.max_size, max_size); crr->next = NULL; @@ -3894,9 +3914,6 @@ destroy_carrier(Allctr_t *allctr, Block_t *blk, Carrier_t **busy_pcrr_pp) } #endif - if (allctr->destroying_mbc) - (*allctr->destroying_mbc)(allctr, crr); - #ifdef ERTS_SMP if (busy_pcrr_pp && *busy_pcrr_pp) { ERTS_ALC_CPOOL_ASSERT(*busy_pcrr_pp == crr); @@ -3920,12 +3937,15 @@ destroy_carrier(Allctr_t *allctr, Block_t *blk, Carrier_t **busy_pcrr_pp) else #endif STAT_SYS_ALLOC_MBC_FREE(allctr, crr_sz); + + if (allctr->remove_mbc) + allctr->remove_mbc(allctr, crr); } #ifdef ERTS_SMP schedule_dealloc_carrier(allctr, crr); #else - dealloc_carrier(allctr, crr, 1); + dealloc_mbc(allctr, crr); #endif } } @@ -4498,7 +4518,7 @@ make_name_atoms(Allctr_t *allctr) size_t prefix_len = strlen(allctr->name_prefix); if (prefix_len > MAX_ATOM_CHARACTERS + sizeof(realloc) - 1) - erl_exit(1,"Too long allocator name: %salloc\n",allctr->name_prefix); + erts_exit(ERTS_ERROR_EXIT,"Too long allocator name: %salloc\n",allctr->name_prefix); memcpy((void *) buf, (void *) allctr->name_prefix, prefix_len); @@ -5700,7 +5720,7 @@ erts_alcu_start(Allctr_t *allctr, AllctrInit_t *init) /* erts_alcu_start assumes that allctr has been zeroed */ if (((UWord)allctr & ERTS_CRR_ALCTR_FLG_MASK) != 0) { - erl_exit(ERTS_ABORT_EXIT, "%s:%d:erts_alcu_start: Alignment error\n", + erts_exit(ERTS_ABORT_EXIT, "%s:%d:erts_alcu_start: Alignment error\n", __FILE__, __LINE__); } @@ -5884,7 +5904,7 @@ erts_alcu_start(Allctr_t *allctr, AllctrInit_t *init) if (allctr->thread_safe) erts_mtx_destroy(&allctr->mutex); #endif - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Failed to create main carrier for %salloc\n", init->name_prefix); } @@ -6029,7 +6049,7 @@ erts_alcu_test(UWord op, UWord a1, UWord a2) case 0x019: return (UWord) PREV_BLK((Block_t *) a1); case 0x01a: return (UWord) IS_MBC_FIRST_BLK((Allctr_t*)a1, (Block_t *) a2); case 0x01b: return (UWord) sizeof(Unit_t); - case 0x01c: return (unsigned long) BLK_TO_MBC((Block_t*) a1); + case 0x01c: return (UWord) BLK_TO_MBC((Block_t*) a1); case 0x01d: ((Allctr_t*) a1)->add_mbc((Allctr_t*)a1, (Carrier_t*)a2); break; case 0x01e: ((Allctr_t*) a1)->remove_mbc((Allctr_t*)a1, (Carrier_t*)a2); break; #ifdef ERTS_SMP @@ -6054,6 +6074,16 @@ erts_alcu_test(UWord op, UWord a1, UWord a2) case 0x023: return (UWord) 0; case 0x024: return (UWord) 0; #endif + case 0x025: /* UMEM2BLK_TEST*/ +#ifdef DEBUG +# ifdef HARD_DEBUG + return (UWord)UMEM2BLK(a1-3*sizeof(UWord)); +# else + return (UWord)UMEM2BLK(a1-2*sizeof(UWord)); +# endif +#else + return (UWord)UMEM2BLK(a1); +#endif default: ASSERT(0); return ~((UWord) 0); } @@ -6090,7 +6120,7 @@ erts_alcu_verify_unused(Allctr_t *allctr) if (no) { UWord sz = allctr->sbcs.blocks.curr.size; sz += allctr->mbcs.blocks.curr.size; - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%salloc() used when expected to be unused!\n" "Total amount of blocks allocated: %bpu\n" "Total amount of bytes allocated: %bpu\n", diff --git a/erts/emulator/beam/erl_alloc_util.h b/erts/emulator/beam/erl_alloc_util.h index df1f0aa65a..f4a2ae7ff3 100644 --- a/erts/emulator/beam/erl_alloc_util.h +++ b/erts/emulator/beam/erl_alloc_util.h @@ -277,7 +277,7 @@ typedef struct ErtsDoubleLink_t_ { typedef struct { erts_atomic_t next; erts_atomic_t prev; - Allctr_t *orig_allctr; + Allctr_t *orig_allctr; /* read-only while carrier is alive */ ErtsThrPrgrVal thr_prgr; erts_atomic_t max_size; UWord abandon_limit; diff --git a/erts/emulator/beam/erl_ao_firstfit_alloc.c b/erts/emulator/beam/erl_ao_firstfit_alloc.c index 7c2a5c3323..5cd067ff54 100644 --- a/erts/emulator/beam/erl_ao_firstfit_alloc.c +++ b/erts/emulator/beam/erl_ao_firstfit_alloc.c @@ -209,7 +209,9 @@ static Block_t* aoff_get_free_block(Allctr_t *, Uint, Block_t *, Uint); static void aoff_link_free_block(Allctr_t *, Block_t*); static void aoff_unlink_free_block(Allctr_t *allctr, Block_t *del); static void aoff_creating_mbc(Allctr_t*, Carrier_t*); +#ifdef DEBUG static void aoff_destroying_mbc(Allctr_t*, Carrier_t*); +#endif static void aoff_add_mbc(Allctr_t*, Carrier_t*); static void aoff_remove_mbc(Allctr_t*, Carrier_t*); static UWord aoff_largest_fblk_in_mbc(Allctr_t*, Carrier_t*); @@ -271,7 +273,11 @@ erts_aoffalc_start(AOFFAllctr_t *alc, allctr->get_next_mbc_size = NULL; allctr->creating_mbc = aoff_creating_mbc; +#ifdef DEBUG allctr->destroying_mbc = aoff_destroying_mbc; +#else + allctr->destroying_mbc = NULL; +#endif allctr->add_mbc = aoff_add_mbc; allctr->remove_mbc = aoff_remove_mbc; allctr->largest_fblk_in_mbc = aoff_largest_fblk_in_mbc; @@ -885,17 +891,18 @@ static void aoff_creating_mbc(Allctr_t *allctr, Carrier_t *carrier) HARD_CHECK_TREE(NULL, 0, *root, 0); } +#define IS_CRR_IN_TREE(CRR,ROOT) \ + ((CRR)->rbt_node.parent || (ROOT) == &(CRR)->rbt_node) + +#ifdef DEBUG static void aoff_destroying_mbc(Allctr_t *allctr, Carrier_t *carrier) { AOFFAllctr_t *alc = (AOFFAllctr_t *) allctr; AOFF_Carrier_t *crr = (AOFF_Carrier_t*) carrier; - AOFF_RBTree_t *root = alc->mbc_root; - if (crr->rbt_node.parent || &crr->rbt_node == root) { - aoff_remove_mbc(allctr, carrier); - } - /*else already removed */ + ASSERT(!IS_CRR_IN_TREE(crr, alc->mbc_root)); } +#endif static void aoff_add_mbc(Allctr_t *allctr, Carrier_t *carrier) { @@ -903,6 +910,7 @@ static void aoff_add_mbc(Allctr_t *allctr, Carrier_t *carrier) AOFF_Carrier_t *crr = (AOFF_Carrier_t*) carrier; AOFF_RBTree_t **root = &alc->mbc_root; + ASSERT(!IS_CRR_IN_TREE(crr, *root)); HARD_CHECK_TREE(NULL, 0, *root, 0); /* Link carrier in address order tree @@ -919,6 +927,10 @@ static void aoff_remove_mbc(Allctr_t *allctr, Carrier_t *carrier) AOFF_RBTree_t **root = &alc->mbc_root; ASSERT(allctr == ERTS_ALC_CARRIER_TO_ALLCTR(carrier)); + + if (!IS_CRR_IN_TREE(crr,*root)) + return; + HARD_CHECK_TREE(NULL, 0, *root, 0); rbt_delete(root, &crr->rbt_node); @@ -1023,7 +1035,7 @@ info_options(Allctr_t *allctr, if (hpp || szp) { if (!atoms_initialized) - erl_exit(1, "%s:%d: Internal error: Atoms not initialized", + erts_exit(ERTS_ERROR_EXIT, "%s:%d: Internal error: Atoms not initialized", __FILE__, __LINE__);; res = NIL; diff --git a/erts/emulator/beam/erl_bestfit_alloc.c b/erts/emulator/beam/erl_bestfit_alloc.c index fb853b65ab..f39a18ac88 100644 --- a/erts/emulator/beam/erl_bestfit_alloc.c +++ b/erts/emulator/beam/erl_bestfit_alloc.c @@ -940,7 +940,7 @@ info_options(Allctr_t *allctr, if (hpp || szp) { if (!atoms_initialized) - erl_exit(1, "%s:%d: Internal error: Atoms not initialized", + erts_exit(ERTS_ERROR_EXIT, "%s:%d: Internal error: Atoms not initialized", __FILE__, __LINE__);; res = NIL; diff --git a/erts/emulator/beam/erl_bif_ddll.c b/erts/emulator/beam/erl_bif_ddll.c index 28bec6325c..f4ef59993a 100644 --- a/erts/emulator/beam/erl_bif_ddll.c +++ b/erts/emulator/beam/erl_bif_ddll.c @@ -1309,7 +1309,7 @@ static Eterm notify_when_loaded(Process *p, Eterm name_term, char *name, ErtsPro case ERL_DE_FORCE_RELOAD: break; default: - erl_exit(1,"Internal error, unknown state %u in dynamic driver.", drv->handle->status); + erts_exit(ERTS_ERROR_EXIT,"Internal error, unknown state %u in dynamic driver.", drv->handle->status); } p->flags |= F_USING_DDLL; r = add_monitor(p, drv->handle, ERL_DE_PROC_AWAIT_LOAD); diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c index b44382cde8..ac7a70c642 100644 --- a/erts/emulator/beam/erl_bif_info.c +++ b/erts/emulator/beam/erl_bif_info.c @@ -65,6 +65,7 @@ static Export* gather_io_bytes_trap = NULL; static Export *gather_sched_wall_time_res_trap; static Export *gather_gc_info_res_trap; +static Export *gather_system_check_res_trap; #define DECL_AM(S) Eterm AM_ ## S = am_atom_put(#S, sizeof(#S) - 1) @@ -914,7 +915,7 @@ BIF_RETTYPE process_info_1(BIF_ALIST_1) case ERTS_PI_FAIL_TYPE_AWAIT_EXIT: ERTS_BIF_AWAIT_X_DATA_TRAP(BIF_P, BIF_ARG_1, am_undefined); default: - erl_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error", __FILE__, __LINE__); + erts_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error", __FILE__, __LINE__); } } @@ -954,7 +955,7 @@ BIF_RETTYPE process_info_2(BIF_ALIST_2) case ERTS_PI_FAIL_TYPE_AWAIT_EXIT: ERTS_BIF_AWAIT_X_DATA_TRAP(BIF_P, BIF_ARG_1, am_undefined); default: - erl_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error", + erts_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error", __FILE__, __LINE__); } } @@ -1533,7 +1534,7 @@ process_info_aux(Process *BIF_P, } case am_last_calls: { - struct saved_calls *scb = ERTS_PROC_GET_SAVED_CALLS_BUF(BIF_P); + struct saved_calls *scb = ERTS_PROC_GET_SAVED_CALLS_BUF(rp); if (!scb) { hp = HAlloc(BIF_P, 3); res = am_false; @@ -1759,7 +1760,7 @@ info_1_tuple(Process* BIF_P, /* Pointer to current process. */ return res; buf = (char *) erts_alloc(ERTS_ALC_T_TMP, len+1); if (intlist_to_buf(*tp, buf, len) != len) - erl_exit(1, "%s:%d: Internal error\n", __FILE__, __LINE__); + erts_exit(ERTS_ERROR_EXIT, "%s:%d: Internal error\n", __FILE__, __LINE__); buf[len] = '\0'; res = erts_instr_dump_memory_map(buf) ? am_true : am_false; erts_free(ERTS_ALC_T_TMP, (void *) buf); @@ -1778,7 +1779,7 @@ info_1_tuple(Process* BIF_P, /* Pointer to current process. */ return res; buf = (char *) erts_alloc(ERTS_ALC_T_TMP, len+1); if (intlist_to_buf(tp[1], buf, len) != len) - erl_exit(1, "%s:%d: Internal error\n", __FILE__, __LINE__); + erts_exit(ERTS_ERROR_EXIT, "%s:%d: Internal error\n", __FILE__, __LINE__); buf[len] = '\0'; res = erts_instr_dump_stat(buf, 1) ? am_true : am_false; erts_free(ERTS_ALC_T_TMP, (void *) buf); @@ -3234,6 +3235,39 @@ BIF_RETTYPE statistics_1(BIF_ALIST_1) if (is_non_value(res)) BIF_RET(am_undefined); BIF_TRAP1(gather_sched_wall_time_res_trap, BIF_P, res); + } else if (BIF_ARG_1 == am_total_active_tasks + || BIF_ARG_1 == am_total_run_queue_lengths) { + Uint no = erts_run_queues_len(NULL, 0, BIF_ARG_1 == am_total_active_tasks); + if (IS_USMALL(0, no)) + res = make_small(no); + else { + Eterm *hp = HAlloc(BIF_P, BIG_UINT_HEAP_SIZE); + res = uint_to_big(no, hp); + } + BIF_RET(res); + } else if (BIF_ARG_1 == am_active_tasks + || BIF_ARG_1 == am_run_queue_lengths) { + Eterm res, *hp, **hpp; + Uint sz, *szp; + int no_qs = erts_no_run_queues; + Uint *qszs = erts_alloc(ERTS_ALC_T_TMP,sizeof(Uint)*no_qs*2); + (void) erts_run_queues_len(qszs, 0, BIF_ARG_1 == am_active_tasks); + sz = 0; + szp = &sz; + hpp = NULL; + while (1) { + int i; + for (i = 0; i < no_qs; i++) + qszs[no_qs+i] = erts_bld_uint(hpp, szp, qszs[i]); + res = erts_bld_list(hpp, szp, no_qs, &qszs[no_qs]); + if (hpp) { + erts_free(ERTS_ALC_T_TMP, qszs); + BIF_RET(res); + } + hp = HAlloc(BIF_P, sz); + szp = NULL; + hpp = &hp; + } } else if (BIF_ARG_1 == am_context_switches) { Eterm cs = erts_make_integer(erts_get_total_context_switches(), BIF_P); hp = HAlloc(BIF_P, 3); @@ -3282,7 +3316,7 @@ BIF_RETTYPE statistics_1(BIF_ALIST_1) res = TUPLE2(hp, b1, b2); BIF_RET(res); } else if (BIF_ARG_1 == am_run_queue) { - res = erts_run_queues_len(NULL); + res = erts_run_queues_len(NULL, 1, 0); BIF_RET(make_small(res)); } else if (BIF_ARG_1 == am_wall_clock) { UWord w1, w2; @@ -3302,7 +3336,7 @@ BIF_RETTYPE statistics_1(BIF_ALIST_1) Uint sz, *szp; int no_qs = erts_no_run_queues; Uint *qszs = erts_alloc(ERTS_ALC_T_TMP,sizeof(Uint)*no_qs*2); - (void) erts_run_queues_len(qszs); + (void) erts_run_queues_len(qszs, 0, 0); sz = 0; szp = &sz; hpp = NULL; @@ -3751,6 +3785,18 @@ BIF_RETTYPE erts_internal_is_system_process_1(BIF_ALIST_1) BIF_ERROR(BIF_P, BADARG); } +BIF_RETTYPE erts_internal_system_check_1(BIF_ALIST_1) +{ + Eterm res; + if (ERTS_IS_ATOM_STR("schedulers", BIF_ARG_1)) { + res = erts_system_check_request(BIF_P); + if (is_non_value(res)) + BIF_RET(am_undefined); + BIF_TRAP1(gather_system_check_res_trap, BIF_P, res); + } + + BIF_ERROR(BIF_P, BADARG); +} static erts_smp_atomic_t hipe_test_reschedule_flag; @@ -3765,7 +3811,7 @@ static void broken_halt_test(Eterm bif_arg_2) #if defined(ERTS_HAVE_TRY_CATCH) erts_get_scheduler_data()->run_queue = NULL; #endif - erl_exit(ERTS_DUMP_EXIT, "%T", bif_arg_2); + erts_exit(ERTS_DUMP_EXIT, "%T", bif_arg_2); } @@ -4012,7 +4058,7 @@ BIF_RETTYPE erts_debug_set_internal_state_2(BIF_ALIST_2) BIF_RET(am_true); } else if (ERTS_IS_ATOM_STR("abort", BIF_ARG_1)) { - erl_exit(ERTS_ABORT_EXIT, "%T\n", BIF_ARG_2); + erts_exit(ERTS_ABORT_EXIT, "%T\n", BIF_ARG_2); } else if (ERTS_IS_ATOM_STR("kill_dist_connection", BIF_ARG_1)) { DistEntry *dep = erts_sysname_to_connected_dist_entry(BIF_ARG_2); @@ -4358,6 +4404,8 @@ erts_bif_info_init(void) = erts_export_put(am_erlang, am_gather_gc_info_result, 1); gather_io_bytes_trap = erts_export_put(am_erts_internal, am_gather_io_bytes, 2); + gather_system_check_res_trap + = erts_export_put(am_erts_internal, am_gather_system_check_result, 1); process_info_init(); os_info_init(); } diff --git a/erts/emulator/beam/erl_bif_port.c b/erts/emulator/beam/erl_bif_port.c index 3ff54c7a60..27c24197ea 100644 --- a/erts/emulator/beam/erl_bif_port.c +++ b/erts/emulator/beam/erl_bif_port.c @@ -791,7 +791,7 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_typep, int *err_nump) } else { name_buf = (char *) erts_alloc(ERTS_ALC_T_TMP, i + 1); if (intlist_to_buf(name, name_buf, i) != i) - erl_exit(1, "%s:%d: Internal error\n", __FILE__, __LINE__); + erts_exit(ERTS_ERROR_EXIT, "%s:%d: Internal error\n", __FILE__, __LINE__); name_buf[i] = '\0'; } driver = &vanilla_driver; @@ -1169,7 +1169,7 @@ static Eterm http_bld_uri(struct packet_callback_args* pca, return erts_bld_tuple(hpp, szp, 3, am_scheme, s1, s2); default: - erl_exit(1, "%s, line %d: type=%u\n", __FILE__, __LINE__, uri->type); + erts_exit(ERTS_ERROR_EXIT, "%s, line %d: type=%u\n", __FILE__, __LINE__, uri->type); } } @@ -1329,7 +1329,8 @@ BIF_RETTYPE decode_packet_3(BIF_ALIST_3) ErlSubBin* rest; Eterm res; Eterm options; - int code; + int code; + char delimiter = '\n'; if (!is_binary(BIF_ARG_2) || (!is_list(BIF_ARG_3) && !is_nil(BIF_ARG_3))) { @@ -1370,6 +1371,11 @@ BIF_RETTYPE decode_packet_3(BIF_ALIST_3) case am_line_length: trunc_len = val; goto next_option; + case am_line_delimiter: + if (type == TCP_PB_LINE_LF && val >= 0 && val <= 255) { + delimiter = (char)val; + goto next_option; + } } } } @@ -1390,7 +1396,7 @@ BIF_RETTYPE decode_packet_3(BIF_ALIST_3) pca.aligned_ptr = bin_ptr; } packet_sz = packet_get_length(type, (char*)pca.aligned_ptr, pca.bin_sz, - max_plen, trunc_len, &http_state); + max_plen, trunc_len, delimiter, &http_state); if (!(packet_sz > 0 && packet_sz <= pca.bin_sz)) { if (packet_sz < 0) { goto error; diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c index 03f51132b1..08807d72c9 100644 --- a/erts/emulator/beam/erl_bif_trace.c +++ b/erts/emulator/beam/erl_bif_trace.c @@ -431,6 +431,9 @@ Uint erts_trace_flag2bit(Eterm flag) { switch (flag) { + case am_timestamp: return F_NOW_TS; + case am_strict_monotonic_timestamp: return F_STRICT_MON_TS; + case am_monotonic_timestamp: return F_MON_TS; case am_all: return TRACEE_FLAGS; case am_send: return F_TRACE_SEND; case am_receive: return F_TRACE_RECEIVE; @@ -439,7 +442,6 @@ erts_trace_flag2bit(Eterm flag) case am_set_on_first_spawn: return F_TRACE_SOS1; case am_set_on_link: return F_TRACE_SOL; case am_set_on_first_link: return F_TRACE_SOL1; - case am_timestamp: return F_TIMESTAMP; case am_running: return F_TRACE_SCHED; case am_exiting: return F_TRACE_SCHED_EXIT; case am_garbage_collection: return F_TRACE_GC; @@ -592,7 +594,7 @@ Eterm trace_3(BIF_ALIST_3) ERTS_TRACE_FLAGS(tracee_port) |= mask; else ERTS_TRACE_FLAGS(tracee_port) &= ~mask; - + if (!ERTS_TRACE_FLAGS(tracee_port)) ERTS_TRACER_PROC(tracee_port) = NIL; else if (tracer != NIL) @@ -978,7 +980,7 @@ trace_info_pid(Process* p, Eterm pid_spec, Eterm key) } if (key == am_flags) { - int num_flags = 19; /* MAXIMUM number of flags. */ + int num_flags = 21; /* MAXIMUM number of flags. */ Uint needed = 3+2*num_flags; Eterm flag_list = NIL; Eterm* limit; @@ -996,6 +998,9 @@ trace_info_pid(Process* p, Eterm pid_spec, Eterm key) #endif hp = HAlloc(p, needed); limit = hp+needed; + FLAG(F_NOW_TS, am_timestamp); + FLAG(F_STRICT_MON_TS, am_strict_monotonic_timestamp); + FLAG(F_MON_TS, am_monotonic_timestamp); FLAG(F_TRACE_SEND, am_send); FLAG(F_TRACE_RECEIVE, am_receive); FLAG(F_TRACE_SOS, am_set_on_spawn); @@ -1007,7 +1012,6 @@ trace_info_pid(Process* p, Eterm pid_spec, Eterm key) FLAG(F_TRACE_SCHED, am_running); FLAG(F_TRACE_SCHED_EXIT, am_exiting); FLAG(F_TRACE_GC, am_garbage_collection); - FLAG(F_TIMESTAMP, am_timestamp); FLAG(F_TRACE_ARITY_ONLY, am_arity); FLAG(F_TRACE_RETURN_TO, am_return_to); FLAG(F_TRACE_SILENT, am_silent); @@ -1798,7 +1802,11 @@ Eterm erts_seq_trace(Process *p, Eterm arg1, Eterm arg2, } else if (arg1 == am_print) { current_flag = SEQ_TRACE_PRINT; } else if (arg1 == am_timestamp) { - current_flag = SEQ_TRACE_TIMESTAMP; + current_flag = SEQ_TRACE_NOW_TS; + } else if (arg1 == am_strict_monotonic_timestamp) { + current_flag = SEQ_TRACE_STRICT_MON_TS; + } else if (arg1 == am_monotonic_timestamp) { + current_flag = SEQ_TRACE_MON_TS; } else current_flag = 0; @@ -1909,7 +1917,9 @@ BIF_RETTYPE erl_seq_trace_info(Process *p, Eterm item) #endif ) { if ((item == am_send) || (item == am_receive) || - (item == am_print) || (item == am_timestamp)) { + (item == am_print) || (item == am_timestamp) + || (item == am_monotonic_timestamp) + || (item == am_strict_monotonic_timestamp)) { hp = HAlloc(p,3); res = TUPLE2(hp, item, am_false); BIF_RET(res); @@ -1927,7 +1937,11 @@ BIF_RETTYPE erl_seq_trace_info(Process *p, Eterm item) } else if (item == am_print) { current_flag = SEQ_TRACE_PRINT; } else if (item == am_timestamp) { - current_flag = SEQ_TRACE_TIMESTAMP; + current_flag = SEQ_TRACE_NOW_TS; + } else if (item == am_strict_monotonic_timestamp) { + current_flag = SEQ_TRACE_STRICT_MON_TS; + } else if (item == am_monotonic_timestamp) { + current_flag = SEQ_TRACE_MON_TS; } else { current_flag = 0; } @@ -2237,6 +2251,7 @@ static Eterm system_profile_get(Process *p) { if (erts_system_profile_flags.exclusive) { res = CONS(hp, am_exclusive, res); hp += 2; } + return TUPLE2(hp, system_profile, res); } } @@ -2255,6 +2270,7 @@ BIF_RETTYPE system_profile_2(BIF_ALIST_2) int system_blocked = 0; Process *profiler_p = NULL; Port *profiler_port = NULL; + int ts; if (profiler == am_undefined || list == NIL) { prev = system_profile_get(p); @@ -2286,7 +2302,8 @@ BIF_RETTYPE system_profile_2(BIF_ALIST_2) goto error; } - for (scheduler = 0, runnable_ports = 0, runnable_procs = 0, exclusive = 0; + for (ts = ERTS_TRACE_FLG_NOW_TIMESTAMP, scheduler = 0, + runnable_ports = 0, runnable_procs = 0, exclusive = 0; is_list(list); list = CDR(list_val(list))) { @@ -2299,6 +2316,12 @@ BIF_RETTYPE system_profile_2(BIF_ALIST_2) exclusive = !0; } else if (t == am_scheduler) { scheduler = !0; + } else if (t == am_timestamp) { + ts = ERTS_TRACE_FLG_NOW_TIMESTAMP; + } else if (t == am_strict_monotonic_timestamp) { + ts = ERTS_TRACE_FLG_STRICT_MONOTONIC_TIMESTAMP; + } else if (t == am_monotonic_timestamp) { + ts = ERTS_TRACE_FLG_MONOTONIC_TIMESTAMP; } else goto error; } if (is_not_nil(list)) goto error; @@ -2311,7 +2334,7 @@ BIF_RETTYPE system_profile_2(BIF_ALIST_2) erts_system_profile_flags.runnable_ports = !!runnable_ports; erts_system_profile_flags.runnable_procs = !!runnable_procs; erts_system_profile_flags.exclusive = !!exclusive; - + erts_system_profile_ts_type = ts; erts_smp_thr_progress_unblock(); erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN); diff --git a/erts/emulator/beam/erl_cpu_topology.c b/erts/emulator/beam/erl_cpu_topology.c index 8395f6ecc6..c263eebfcc 100644 --- a/erts/emulator/beam/erl_cpu_topology.c +++ b/erts/emulator/beam/erl_cpu_topology.c @@ -402,7 +402,7 @@ cpu_bind_order_sort(erts_cpu_topology_t *cpudata, break; default: cmp_func = NULL; - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Bad cpu bind type: %d\n", (int) cpu_bind_order); break; @@ -1590,7 +1590,7 @@ get_cpu_topology_term(Process *c_p, int type) } break; default: - erl_exit(ERTS_ABORT_EXIT, "Bad cpu topology type: %d\n", type); + erts_exit(ERTS_ABORT_EXIT, "Bad cpu topology type: %d\n", type); break; } @@ -1967,7 +1967,7 @@ cpu_group_insert(erts_cpu_groups_map_t *map, ix = 0; } while (ix != start); - erl_exit(ERTS_ABORT_EXIT, "Reader groups map full\n"); + erts_exit(ERTS_ABORT_EXIT, "Reader groups map full\n"); } @@ -2290,7 +2290,7 @@ remove_cpu_groups(erts_cpu_groups_callback_t callback, void *arg) prev_cgm = cgm; } - erl_exit(ERTS_ABORT_EXIT, "Cpu groups not found\n"); + erts_exit(ERTS_ABORT_EXIT, "Cpu groups not found\n"); } static int @@ -2320,7 +2320,7 @@ cpu_groups_lookup(erts_cpu_groups_map_t *map, ix = 0; } while (ix != start); - erl_exit(ERTS_ABORT_EXIT, "Logical cpu id %d not found\n", logical); + erts_exit(ERTS_ABORT_EXIT, "Logical cpu id %d not found\n", logical); } static void diff --git a/erts/emulator/beam/erl_db.c b/erts/emulator/beam/erl_db.c index 878ee32b47..870b556851 100644 --- a/erts/emulator/beam/erl_db.c +++ b/erts/emulator/beam/erl_db.c @@ -1295,7 +1295,7 @@ BIF_RETTYPE ets_rename_2(BIF_ALIST_2) goto badarg; if (!remove_named_tab(tb, 1)) - erl_exit(1,"Could not find named tab %s", tb->common.id); + erts_exit(ERTS_ERROR_EXIT,"Could not find named tab %s", tb->common.id); tb->common.id = tb->common.the_name = BIF_ARG_2; @@ -1376,7 +1376,6 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2) status |= DB_ORDERED_SET; status &= ~(DB_SET | DB_BAG | DB_DUPLICATE_BAG); } - /*TT*/ else if (is_tuple(val)) { Eterm *tp = tuple_val(val); if (arityval(tp[0]) == 2) { @@ -1581,7 +1580,7 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2) BIF_P->common.id, make_small(slot)), 0) != DB_ERROR_NONE) { - erl_exit(1,"Could not update ets metadata."); + erts_exit(ERTS_ERROR_EXIT,"Could not update ets metadata."); } db_meta_unlock(meta_pid_to_tab, LCK_WRITE_REC); @@ -2940,7 +2939,7 @@ void init_db(ErtsDbSpinCount db_spin_count) bits = erts_fit_in_bits_int32(db_max_tabs-1); if (bits > SMALL_BITS) { - erl_exit(1,"Max limit for ets tabled too high %u (max %u).", + erts_exit(ERTS_ERROR_EXIT,"Max limit for ets tabled too high %u (max %u).", db_max_tabs, ((Uint)1)<<SMALL_BITS); } meta_main_tab_slot_mask = (((Uint)1)<<bits) - 1; @@ -3001,7 +3000,7 @@ void init_db(ErtsDbSpinCount db_spin_count) db_init_lock(meta_pid_to_tab, "meta_pid_to_tab", "meta_pid_to_tab_FIX");*/ if (db_create_hash(NULL, meta_pid_to_tab) != DB_ERROR_NONE) { - erl_exit(1,"Unable to create ets metadata tables."); + erts_exit(ERTS_ERROR_EXIT,"Unable to create ets metadata tables."); } erts_smp_atomic_set_nob(&init_tb.common.memory_size, 0); @@ -3032,7 +3031,7 @@ void init_db(ErtsDbSpinCount db_spin_count) db_init_lock(meta_pid_to_fixed_tab, "meta_pid_to_fixed_tab", "meta_pid_to_fixed_tab_FIX");*/ if (db_create_hash(NULL, meta_pid_to_fixed_tab) != DB_ERROR_NONE) { - erl_exit(1,"Unable to create ets metadata tables."); + erts_exit(ERTS_ERROR_EXIT,"Unable to create ets metadata tables."); } /* Non visual BIF to trap to. */ @@ -3229,7 +3228,7 @@ retry: * yielding. */ #define ERTS_DB_INTERNAL_ERROR(LSTR) \ - erl_exit(ERTS_ABORT_EXIT, "%s:%d:erts_db_process_exiting(): " LSTR "\n", \ + erts_exit(ERTS_ABORT_EXIT, "%s:%d:erts_db_process_exiting(): " LSTR "\n", \ __FILE__, __LINE__) int @@ -3466,10 +3465,10 @@ static void fix_table_locked(Process* p, DbTable* tb) #endif erts_refc_inc(&tb->common.ref,1); fix = tb->common.fixations; - if (fix == NULL) { - get_now(&(tb->common.megasec), - &(tb->common.sec), - &(tb->common.microsec)); + if (fix == NULL) { + tb->common.time.monotonic + = erts_get_monotonic_time(ERTS_PROC_GET_SCHDATA(p)); + tb->common.time.offset = erts_get_time_offset(); } else { for (; fix != NULL; fix = fix->next) { @@ -3501,7 +3500,7 @@ static void fix_table_locked(Process* p, DbTable* tb) make_small(tb->common.slot)), 0) != DB_ERROR_NONE) { UnUseTmpHeap(3,p); - erl_exit(1,"Could not insert ets metadata in safe_fixtable."); + erts_exit(ERTS_ERROR_EXIT,"Could not insert ets metadata in safe_fixtable."); } UnUseTmpHeap(3,p); db_meta_unlock(meta_pid_to_fixed_tab, LCK_WRITE_REC); @@ -3731,6 +3730,7 @@ static int free_table_cont(Process *p, static Eterm table_info(Process* p, DbTable* tb, Eterm What) { Eterm ret = THE_NON_VALUE; + int use_monotonic; if (What == am_size) { ret = make_small(erts_smp_atomic_read_nob(&tb->common.nitems)); @@ -3788,7 +3788,10 @@ static Eterm table_info(Process* p, DbTable* tb, Eterm What) ret = am_true; else ret = am_false; - } else if (What == am_atom_put("safe_fixed",10)) { + } else if ((use_monotonic + = ERTS_IS_ATOM_STR("safe_fixed_monotonic_time", + What)) + || ERTS_IS_ATOM_STR("safe_fixed", What)) { #ifdef ERTS_SMP erts_smp_mtx_lock(&tb->common.fixlock); #endif @@ -3797,7 +3800,19 @@ static Eterm table_info(Process* p, DbTable* tb, Eterm What) Eterm *hp; Eterm tpl, lst; DbFixation *fix; - need = 7; + Sint64 mtime; + + need = 3; + if (use_monotonic) { + mtime = (Sint64) tb->common.time.monotonic; + mtime += ERTS_MONOTONIC_OFFSET_NATIVE; + if (!IS_SSMALL(mtime)) + need += ERTS_SINT64_HEAP_SIZE(mtime); + } + else { + mtime = 0; + need += 4; + } for (fix = tb->common.fixations; fix != NULL; fix = fix->next) { need += 5; } @@ -3809,11 +3824,18 @@ static Eterm table_info(Process* p, DbTable* tb, Eterm What) lst = CONS(hp,tpl,lst); hp += 2; } - tpl = TUPLE3(hp, - make_small(tb->common.megasec), - make_small(tb->common.sec), - make_small(tb->common.microsec)); - hp += 4; + if (use_monotonic) + tpl = (IS_SSMALL(mtime) + ? make_small(mtime) + : erts_sint64_to_big(mtime, &hp)); + else { + Uint ms, s, us; + erts_make_timestamp_value(&ms, &s, &us, + tb->common.time.monotonic, + tb->common.time.offset); + tpl = TUPLE3(hp, make_small(ms), make_small(s), make_small(us)); + hp += 4; + } ret = TUPLE2(hp, tpl, lst); } else { ret = am_false; diff --git a/erts/emulator/beam/erl_db_hash.c b/erts/emulator/beam/erl_db_hash.c index 81b0c4465c..0b31eb3bcd 100644 --- a/erts/emulator/beam/erl_db_hash.c +++ b/erts/emulator/beam/erl_db_hash.c @@ -148,8 +148,11 @@ static ERTS_INLINE Uint hash_to_ix(DbTableHash* tb, HashValue hval) } /* Remember a slot containing a pseudo-deleted item (INVALID_HASH) -*/ -static ERTS_INLINE void add_fixed_deletion(DbTableHash* tb, int ix) + * Return false if we got raced by unfixing thread + * and the object should be deleted for real. + */ +static ERTS_INLINE int add_fixed_deletion(DbTableHash* tb, int ix, + erts_aint_t fixated_by_me) { erts_aint_t was_next; erts_aint_t exp_next; @@ -160,12 +163,18 @@ static ERTS_INLINE void add_fixed_deletion(DbTableHash* tb, int ix) fixd->slot = ix; was_next = erts_smp_atomic_read_acqb(&tb->fixdel); do { /* Lockless atomic insertion in linked list: */ - exp_next = was_next; + if (NFIXED(tb) <= fixated_by_me) { + erts_db_free(ERTS_ALC_T_DB_FIX_DEL, (DbTable*)tb, + fixd, sizeof(FixedDeletion)); + return 0; /* raced by unfixer */ + } + exp_next = was_next; fixd->next = (FixedDeletion*) exp_next; - was_next = erts_smp_atomic_cmpxchg_relb(&tb->fixdel, - (erts_aint_t) fixd, - exp_next); + was_next = erts_smp_atomic_cmpxchg_mb(&tb->fixdel, + (erts_aint_t) fixd, + exp_next); }while (was_next != exp_next); + return 1; } @@ -607,8 +616,8 @@ void db_unfix_table_hash(DbTableHash *tb) || (erts_smp_lc_rwmtx_is_rlocked(&tb->common.rwlock) && !tb->common.is_thread_safe)); restart: - fixdel = (FixedDeletion*) erts_smp_atomic_xchg_acqb(&tb->fixdel, - (erts_aint_t) NULL); + fixdel = (FixedDeletion*) erts_smp_atomic_xchg_mb(&tb->fixdel, + (erts_aint_t) NULL); while (fixdel != NULL) { FixedDeletion *fx = fixdel; int ix = fx->slot; @@ -1142,9 +1151,9 @@ int db_erase_hash(DbTable *tbl, Eterm key, Eterm *ret) while(b != 0) { if (has_live_key(tb,b,key,hval)) { --nitems_diff; - if (nitems_diff == -1 && IS_FIXED(tb)) { + if (nitems_diff == -1 && IS_FIXED(tb) + && add_fixed_deletion(tb, ix, 0)) { /* Pseudo remove (no need to keep several of same key) */ - add_fixed_deletion(tb, ix); b->hvalue = INVALID_HASH; } else { *bp = b->next; @@ -1196,9 +1205,8 @@ static int db_erase_object_hash(DbTable *tbl, Eterm object, Eterm *ret) ++nkeys; if (db_eq(&tb->common,object, &b->dbterm)) { --nitems_diff; - if (nkeys==1 && IS_FIXED(tb)) { /* Pseudo remove */ - add_fixed_deletion(tb,ix); - b->hvalue = INVALID_HASH; + if (nkeys==1 && IS_FIXED(tb) && add_fixed_deletion(tb,ix,0)) { + b->hvalue = INVALID_HASH; /* Pseudo remove */ bp = &b->next; b = b->next; } else { @@ -1820,14 +1828,17 @@ static int db_select_delete_hash(Process *p, int did_erase = 0; if (db_match_dbterm(&tb->common, p, mpi.mp, 0, &(*current)->dbterm, NULL, 0) == am_true) { + HashDbTerm *del; if (NFIXED(tb) > fixated_by_me) { /* fixated by others? */ if (slot_ix != last_pseudo_delete) { - add_fixed_deletion(tb, slot_ix); - last_pseudo_delete = slot_ix; + if (!add_fixed_deletion(tb, slot_ix, fixated_by_me)) + goto do_erase; + last_pseudo_delete = slot_ix; } (*current)->hvalue = INVALID_HASH; } else { - HashDbTerm *del = *current; + do_erase: + del = *current; *current = (*current)->next; free_term(tb, del); did_erase = 1; @@ -1931,14 +1942,17 @@ static int db_select_delete_continue_hash(Process *p, int did_erase = 0; if (db_match_dbterm(&tb->common, p, mp, 0, &(*current)->dbterm, NULL, 0) == am_true) { + HashDbTerm *del; if (NFIXED(tb) > fixated_by_me) { /* fixated by others? */ if (slot_ix != last_pseudo_delete) { - add_fixed_deletion(tb, slot_ix); + if (!add_fixed_deletion(tb, slot_ix, fixated_by_me)) + goto do_erase; last_pseudo_delete = slot_ix; } (*current)->hvalue = INVALID_HASH; } else { - HashDbTerm *del = *current; + do_erase: + del = *current; *current = (*current)->next; free_term(tb, del); did_erase = 1; @@ -2089,9 +2103,9 @@ static int db_take_hash(Process *p, DbTable *tbl, Eterm key, Eterm *ret) *ret = get_term_list(p, tb, key, hval, b, &bend); while (b != bend) { --nitems_diff; - if (nitems_diff == -1 && IS_FIXED(tb)) { + if (nitems_diff == -1 && IS_FIXED(tb) + && add_fixed_deletion(tb, ix, 0)) { /* Pseudo remove (no need to keep several of same key) */ - add_fixed_deletion(tb, ix); bp = &b->next; b->hvalue = INVALID_HASH; b = b->next; @@ -2131,7 +2145,7 @@ int db_mark_all_deleted_hash(DbTable *tbl) for (i = 0; i < NACTIVE(tb); i++) { if ((list = BUCKET(tb,i)) != NULL) { - add_fixed_deletion(tb, i); + add_fixed_deletion(tb, i, 0); do { list->hvalue = INVALID_HASH; list = list->next; @@ -2855,15 +2869,7 @@ db_lookup_dbterm_hash(Process *p, DbTable *tbl, Eterm key, Eterm obj, q->hvalue = hval; q->next = NULL; *bp = b = q; - - { - int nitems = erts_smp_atomic_inc_read_nob(&tb->common.nitems); - int nactive = NACTIVE(tb); - - if (nitems > nactive * (CHAIN_LEN + 1) && !IS_FIXED(tb)) { - grow(tb, nactive); - } - } + flags |= DB_INC_TRY_GROW; } else { HashDbTerm *q, *next = b->next; @@ -2902,32 +2908,46 @@ db_finalize_dbterm_hash(int cret, DbUpdateHandle* handle) HashDbTerm **bp = (HashDbTerm **) handle->bp; HashDbTerm *b = *bp; erts_smp_rwmtx_t* lck = (erts_smp_rwmtx_t*) handle->lck; + HashDbTerm* free_me = NULL; ERTS_SMP_LC_ASSERT(IS_HASH_WLOCKED(tb, lck)); /* locked by db_lookup_dbterm_hash */ ASSERT((&b->dbterm == handle->dbterm) == !(tb->common.compress && handle->flags & DB_MUST_RESIZE)); if (handle->flags & DB_NEW_OBJECT && cret != DB_ERROR_NONE) { - if (IS_FIXED(tb)) { - add_fixed_deletion(tb, hash_to_ix(tb, b->hvalue)); + if (IS_FIXED(tb) && add_fixed_deletion(tb, hash_to_ix(tb, b->hvalue), + 0)) { b->hvalue = INVALID_HASH; } else { *bp = b->next; - free_term(tb, b); + free_me = b; } WUNLOCK_HASH(lck); erts_smp_atomic_dec_nob(&tb->common.nitems); try_shrink(tb); - } else if (handle->flags & DB_MUST_RESIZE) { - db_finalize_resize(handle, offsetof(HashDbTerm,dbterm)); - WUNLOCK_HASH(lck); - - free_term(tb, b); - } - else { - WUNLOCK_HASH(lck); + } else { + if (handle->flags & DB_MUST_RESIZE) { + db_finalize_resize(handle, offsetof(HashDbTerm,dbterm)); + free_me = b; + } + if (handle->flags & DB_INC_TRY_GROW) { + int nactive; + int nitems = erts_smp_atomic_inc_read_nob(&tb->common.nitems); + WUNLOCK_HASH(lck); + nactive = NACTIVE(tb); + + if (nitems > nactive * (CHAIN_LEN + 1) && !IS_FIXED(tb)) { + grow(tb, nactive); + } + } else { + WUNLOCK_HASH(lck); + } } + + if (free_me) + free_term(tb, free_me); + #ifdef DEBUG handle->dbterm = 0; #endif @@ -3014,7 +3034,7 @@ void db_check_table_hash(DbTable *tbl) if ((list = BUCKET(tb,j)) != 0) { while (list != 0) { if (!is_tuple(make_tuple(list->dbterm.tpl))) { - erl_exit(1, "Bad term in slot %d of ets table", j); + erts_exit(ERTS_ERROR_EXIT, "Bad term in slot %d of ets table", j); } list = list->next; } diff --git a/erts/emulator/beam/erl_db_tree.c b/erts/emulator/beam/erl_db_tree.c index 465aa566ad..61293fbf9a 100644 --- a/erts/emulator/beam/erl_db_tree.c +++ b/erts/emulator/beam/erl_db_tree.c @@ -1213,7 +1213,7 @@ static int db_select_count_continue_tree(Process *p, tptr = tuple_val(continuation); if (arityval(*tptr) != 5) - erl_exit(1,"Internal error in ets:select_count/1"); + erts_exit(ERTS_ERROR_EXIT,"Internal error in ets:select_count/1"); lastkey = tptr[2]; end_condition = tptr[3]; diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c index dab357a079..af5b611afd 100644 --- a/erts/emulator/beam/erl_db_util.c +++ b/erts/emulator/beam/erl_db_util.c @@ -1946,11 +1946,11 @@ restart: #ifdef DMC_DEBUG if (*heap_fence != FENCE_PATTERN) { - erl_exit(1, "Heap fence overwritten in db_prog_match after op " + erts_exit(ERTS_ERROR_EXIT, "Heap fence overwritten in db_prog_match after op " "0x%08x, overwritten with 0x%08x.", save_op, *heap_fence); } if (*stack_fence != FENCE_PATTERN) { - erl_exit(1, "Stack fence overwritten in db_prog_match after op " + erts_exit(ERTS_ERROR_EXIT, "Stack fence overwritten in db_prog_match after op " "0x%08x, overwritten with 0x%08x.", save_op, *stack_fence); } @@ -2615,7 +2615,7 @@ restart: case matchHalt: goto success; default: - erl_exit(1, "Internal error: unexpected opcode in match program."); + erts_exit(ERTS_ERROR_EXIT, "Internal error: unexpected opcode in match program."); } } fail: @@ -2639,11 +2639,11 @@ success: #ifdef DMC_DEBUG if (*heap_fence != FENCE_PATTERN) { - erl_exit(1, "Heap fence overwritten in db_prog_match after op " + erts_exit(ERTS_ERROR_EXIT, "Heap fence overwritten in db_prog_match after op " "0x%08x, overwritten with 0x%08x.", save_op, *heap_fence); } if (*stack_fence != FENCE_PATTERN) { - erl_exit(1, "Stack fence overwritten in db_prog_match after op " + erts_exit(ERTS_ERROR_EXIT, "Stack fence overwritten in db_prog_match after op " "0x%08x, overwritten with 0x%08x.", save_op, *stack_fence); } @@ -3683,7 +3683,7 @@ static DMCRet dmc_one_term(DMCContext *context, break; } default: - erl_exit(1, "db_match_compile: " + erts_exit(ERTS_ERROR_EXIT, "db_match_compile: " "Bad object on heap: 0x%bex\n", c); } return retOk; @@ -4930,7 +4930,7 @@ static DMCRet dmc_fun(DMCContext *context, DMC_PUSH(*text, matchCall3); break; default: - erl_exit(1,"ets:match() internal error, " + erts_exit(ERTS_ERROR_EXIT,"ets:match() internal error, " "guard with more than 3 arguments."); } DMC_PUSH(*text, (UWord) b->biff); @@ -5210,7 +5210,7 @@ static Uint my_size_object(Eterm t) tmp == am_const) { sum += size_object(tuple_val(t)[2]); } else { - erl_exit(1,"Internal error, sizing unrecognized object in " + erts_exit(ERTS_ERROR_EXIT,"Internal error, sizing unrecognized object in " "(d)ets:match compilation."); } break; @@ -5255,7 +5255,7 @@ static Eterm my_copy_struct(Eterm t, Eterm **hp, ErlOffHeap* off_heap) sz = size_object(b); ret = copy_struct(b,sz,hp,off_heap); } else { - erl_exit(1, "Trying to constant-copy non constant expression " + erts_exit(ERTS_ERROR_EXIT, "Trying to constant-copy non constant expression " "0x%bex in (d)ets:match compilation.", t); } } else { diff --git a/erts/emulator/beam/erl_db_util.h b/erts/emulator/beam/erl_db_util.h index 1ccdc0305b..bfd81f5d86 100644 --- a/erts/emulator/beam/erl_db_util.h +++ b/erts/emulator/beam/erl_db_util.h @@ -79,6 +79,7 @@ typedef union db_table DbTable; #define DB_MUST_RESIZE 1 #define DB_NEW_OBJECT 2 +#define DB_INC_TRY_GROW 4 /* Info about a database entry while it's being updated * (by update_counter or update_element) @@ -229,7 +230,10 @@ typedef struct db_table_common { DbTableMethod* meth; /* table methods */ erts_smp_atomic_t nitems; /* Total number of items in table */ erts_smp_atomic_t memory_size;/* Total memory size. NOTE: in bytes! */ - Uint megasec,sec,microsec; /* Last fixation time */ + struct { /* Last fixation time */ + ErtsMonotonicTime monotonic; + ErtsMonotonicTime offset; + } time; DbFixation* fixations; /* List of processes who have done safe_fixtable, "local" fixations not included. */ /* All 32-bit fields */ diff --git a/erts/emulator/beam/erl_debug.c b/erts/emulator/beam/erl_debug.c index 77a1e3d7cb..4928aae9c2 100644 --- a/erts/emulator/beam/erl_debug.c +++ b/erts/emulator/beam/erl_debug.c @@ -189,6 +189,9 @@ pdisplay1(int to, void *to_arg, Process* p, Eterm obj) case BINARY_DEF: erts_print(to, to_arg, "#Bin"); break; + case MATCHSTATE_DEF: + erts_print(to, to_arg, "#Matchstate"); + break; default: erts_print(to, to_arg, "unknown object %x", obj); } @@ -252,14 +255,14 @@ void erts_check_stack(Process *p) Eterm *stack_end = p->htop; if (p->stop > stack_start) - erl_exit(1, + erts_exit(ERTS_ERROR_EXIT, "<%lu.%lu.%lu>: Stack underflow\n", internal_pid_channel_no(p->common.id), internal_pid_number(p->common.id), internal_pid_serial(p->common.id)); if (p->stop < stack_end) - erl_exit(1, + erts_exit(ERTS_ERROR_EXIT, "<%lu.%lu.%lu>: Stack overflow\n", internal_pid_channel_no(p->common.id), internal_pid_number(p->common.id), @@ -284,7 +287,7 @@ void erts_check_stack(Process *p) if (in_mbuf) continue; - erl_exit(1, + erts_exit(ERTS_ERROR_EXIT, "<%lu.%lu.%lu>: Wild stack pointer\n", internal_pid_channel_no(p->common.id), internal_pid_number(p->common.id), @@ -369,7 +372,7 @@ void erts_check_memory(Process *p, Eterm *start, Eterm *end) #ifdef DEBUG if (hval == DEBUG_BAD_WORD) { print_untagged_memory(start, end); - erl_exit(1, "Uninitialized HAlloc'ed memory found @ 0x%0*lx!\n", + erts_exit(ERTS_ERROR_EXIT, "Uninitialized HAlloc'ed memory found @ 0x%0*lx!\n", PTR_SIZE,(unsigned long)(pos - 1)); } #endif @@ -382,7 +385,7 @@ void erts_check_memory(Process *p, Eterm *start, Eterm *end) if (verify_eterm(p,hval)) continue; - erl_exit(1, "Wild pointer found @ 0x%0*lx!\n", + erts_exit(ERTS_ERROR_EXIT, "Wild pointer found @ 0x%0*lx!\n", PTR_SIZE,(unsigned long)(pos - 1)); } } @@ -392,11 +395,11 @@ void verify_process(Process *p) #define VERIFY_AREA(name,ptr,sz) { \ int n = (sz); \ while (n--) if(!verify_eterm(p,*(ptr+n))) \ - erl_exit(1,"Wild pointer found in " name " of %T!\n",p->common.id); } + erts_exit(ERTS_ERROR_EXIT,"Wild pointer found in " name " of %T!\n",p->common.id); } #define VERIFY_ETERM(name,eterm) { \ if(!verify_eterm(p,eterm)) \ - erl_exit(1,"Wild pointer found in " name " of %T!\n",p->common.id); } + erts_exit(ERTS_ERROR_EXIT,"Wild pointer found in " name " of %T!\n",p->common.id); } ErlMessage* mp = p->msg.first; diff --git a/erts/emulator/beam/erl_driver.h b/erts/emulator/beam/erl_driver.h index 6b406d069c..7ab58e336b 100644 --- a/erts/emulator/beam/erl_driver.h +++ b/erts/emulator/beam/erl_driver.h @@ -37,47 +37,6 @@ # endif #endif -#ifdef SIZEOF_CHAR -# define SIZEOF_CHAR_SAVED__ SIZEOF_CHAR -# undef SIZEOF_CHAR -#endif -#ifdef SIZEOF_SHORT -# define SIZEOF_SHORT_SAVED__ SIZEOF_SHORT -# undef SIZEOF_SHORT -#endif -#ifdef SIZEOF_INT -# define SIZEOF_INT_SAVED__ SIZEOF_INT -# undef SIZEOF_INT -#endif -#ifdef SIZEOF_LONG -# define SIZEOF_LONG_SAVED__ SIZEOF_LONG -# undef SIZEOF_LONG -#endif -#ifdef SIZEOF_LONG_LONG -# define SIZEOF_LONG_LONG_SAVED__ SIZEOF_LONG_LONG -# undef SIZEOF_LONG_LONG -#endif -#ifdef HALFWORD_HEAP_EMULATOR -# define HALFWORD_HEAP_EMULATOR_SAVED__ HALFWORD_HEAP_EMULATOR -# undef HALFWORD_HEAP_EMULATOR -#endif -#include "erl_int_sizes_config.h" -#if defined(SIZEOF_CHAR_SAVED__) && SIZEOF_CHAR_SAVED__ != SIZEOF_CHAR -# error SIZEOF_CHAR mismatch -#endif -#if defined(SIZEOF_SHORT_SAVED__) && SIZEOF_SHORT_SAVED__ != SIZEOF_SHORT -# error SIZEOF_SHORT mismatch -#endif -#if defined(SIZEOF_INT_SAVED__) && SIZEOF_INT_SAVED__ != SIZEOF_INT -# error SIZEOF_INT mismatch -#endif -#if defined(SIZEOF_LONG_SAVED__) && SIZEOF_LONG_SAVED__ != SIZEOF_LONG -# error SIZEOF_LONG mismatch -#endif -#if defined(SIZEOF_LONG_LONG_SAVED__) && SIZEOF_LONG_LONG_SAVED__ != SIZEOF_LONG_LONG -# error SIZEOF_LONG_LONG mismatch -#endif - /* This is OK to override by the NIF/driver implementor */ #if defined(HALFWORD_HEAP_EMULATOR_SAVED__) && !defined(HALFWORD_HEAP_EMULATOR) #define HALFWORD_HEAP_EMULATOR HALFWORD_HEAP_EMULATOR_SAVED__ @@ -134,7 +93,7 @@ typedef struct { #define ERL_DRV_EXTENDED_MARKER (0xfeeeeeed) #define ERL_DRV_EXTENDED_MAJOR_VERSION 3 -#define ERL_DRV_EXTENDED_MINOR_VERSION 2 +#define ERL_DRV_EXTENDED_MINOR_VERSION 3 /* * The emulator will refuse to load a driver with a major version @@ -176,28 +135,12 @@ typedef struct { /* * Integer types */ -#if defined(__WIN32__) && (SIZEOF_VOID_P == 8) -typedef unsigned __int64 ErlDrvTermData; -typedef unsigned __int64 ErlDrvUInt; -typedef signed __int64 ErlDrvSInt; -#else -typedef unsigned long ErlDrvTermData; -typedef unsigned long ErlDrvUInt; -typedef signed long ErlDrvSInt; -#endif -#if defined(__WIN32__) -typedef unsigned __int64 ErlDrvUInt64; -typedef __int64 ErlDrvSInt64; -#elif SIZEOF_LONG == 8 -typedef unsigned long ErlDrvUInt64; -typedef long ErlDrvSInt64; -#elif SIZEOF_LONG_LONG == 8 -typedef unsigned long long ErlDrvUInt64; -typedef long long ErlDrvSInt64; -#else -#error No 64-bit integer type -#endif +typedef ErlNapiUInt64 ErlDrvUInt64; +typedef ErlNapiSInt64 ErlDrvSInt64; +typedef ErlNapiUInt ErlDrvUInt; +typedef ErlNapiSInt ErlDrvSInt; +typedef ErlNapiUInt ErlDrvTermData; #if defined(__WIN32__) || defined(_WIN32) typedef ErlDrvUInt ErlDrvSizeT; @@ -250,6 +193,17 @@ typedef struct { unsigned long microsecs; } ErlDrvNowData; +typedef ErlDrvSInt64 ErlDrvTime; + +#define ERL_DRV_TIME_ERROR ((ErlDrvSInt64) ERTS_NAPI_TIME_ERROR__) + +typedef enum { + ERL_DRV_SEC = ERTS_NAPI_SEC__, + ERL_DRV_MSEC = ERTS_NAPI_MSEC__, + ERL_DRV_USEC = ERTS_NAPI_USEC__, + ERL_DRV_NSEC = ERTS_NAPI_NSEC__ +} ErlDrvTimeUnit; + /* * Error codes that can be return from driver. */ @@ -685,8 +639,16 @@ EXTERN long driver_async(ErlDrvPort ix, EXTERN int driver_lock_driver(ErlDrvPort ix); /* Get the current 'now' timestamp (analogue to erlang:now()) */ -EXTERN int driver_get_now(ErlDrvNowData *now); +EXTERN int driver_get_now(ErlDrvNowData *now) ERL_DRV_DEPRECATED_FUNC; +/* Erlang Monotonic Time */ +EXTERN ErlDrvTime erl_drv_monotonic_time(ErlDrvTimeUnit time_unit); +/* Time offset between Erlang Monotonic Time and Erlang System Time */ +EXTERN ErlDrvTime erl_drv_time_offset(ErlDrvTimeUnit time_unit); +/* Time unit conversion */ +EXTERN ErlDrvTime erl_drv_convert_time_unit(ErlDrvTime val, + ErlDrvTimeUnit from, + ErlDrvTimeUnit to); /* These were removed from the ANSI version, now they're back. */ @@ -696,8 +658,8 @@ EXTERN int driver_dl_close(void *); EXTERN char *driver_dl_error(void); /* environment */ -EXTERN int erl_drv_putenv(char *key, char *value); -EXTERN int erl_drv_getenv(char *key, char *value, size_t *value_size); +EXTERN int erl_drv_putenv(const char *key, char *value); +EXTERN int erl_drv_getenv(const char *key, char *value, size_t *value_size); #ifdef __OSE__ typedef ErlDrvUInt ErlDrvOseEventId; diff --git a/erts/emulator/beam/erl_drv_nif.h b/erts/emulator/beam/erl_drv_nif.h index e2385f63f4..f6b946ae82 100644 --- a/erts/emulator/beam/erl_drv_nif.h +++ b/erts/emulator/beam/erl_drv_nif.h @@ -50,6 +50,90 @@ typedef enum { } ErlDrvDirtyJobFlags; #endif +#ifdef SIZEOF_CHAR +# define SIZEOF_CHAR_SAVED__ SIZEOF_CHAR +# undef SIZEOF_CHAR +#endif +#ifdef SIZEOF_SHORT +# define SIZEOF_SHORT_SAVED__ SIZEOF_SHORT +# undef SIZEOF_SHORT +#endif +#ifdef SIZEOF_INT +# define SIZEOF_INT_SAVED__ SIZEOF_INT +# undef SIZEOF_INT +#endif +#ifdef SIZEOF_LONG +# define SIZEOF_LONG_SAVED__ SIZEOF_LONG +# undef SIZEOF_LONG +#endif +#ifdef SIZEOF_LONG_LONG +# define SIZEOF_LONG_LONG_SAVED__ SIZEOF_LONG_LONG +# undef SIZEOF_LONG_LONG +#endif +#ifdef HALFWORD_HEAP_EMULATOR +# define HALFWORD_HEAP_EMULATOR_SAVED__ HALFWORD_HEAP_EMULATOR +# undef HALFWORD_HEAP_EMULATOR +#endif +#include "erl_int_sizes_config.h" +#if defined(SIZEOF_CHAR_SAVED__) && SIZEOF_CHAR_SAVED__ != SIZEOF_CHAR +# error SIZEOF_CHAR mismatch +#endif +#if defined(SIZEOF_SHORT_SAVED__) && SIZEOF_SHORT_SAVED__ != SIZEOF_SHORT +# error SIZEOF_SHORT mismatch +#endif +#if defined(SIZEOF_INT_SAVED__) && SIZEOF_INT_SAVED__ != SIZEOF_INT +# error SIZEOF_INT mismatch +#endif +#if defined(SIZEOF_LONG_SAVED__) && SIZEOF_LONG_SAVED__ != SIZEOF_LONG +# error SIZEOF_LONG mismatch +#endif +#if defined(SIZEOF_LONG_LONG_SAVED__) && SIZEOF_LONG_LONG_SAVED__ != SIZEOF_LONG_LONG +# error SIZEOF_LONG_LONG mismatch +#endif + +#if !defined(__GNUC__) && (defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_)) +typedef unsigned __int64 ErlNapiUInt64; +typedef signed __int64 ErlNapiSInt64; +#define ERL_NAPI_SINT64_MAX__ 9223372036854775807i64 +#define ERL_NAPI_SINT64_MIN__ (-ERL_NAPI_SINT64_MAX__ - 1i64) +#elif SIZEOF_LONG == 8 +typedef unsigned long ErlNapiUInt64; +typedef signed long ErlNapiSInt64; +#define ERL_NAPI_SINT64_MAX__ 9223372036854775807L +#define ERL_NAPI_SINT64_MIN__ (-ERL_NAPI_SINT64_MAX__ - 1L) +#elif SIZEOF_LONG_LONG == 8 +typedef unsigned long long ErlNapiUInt64; +typedef signed long long ErlNapiSInt64; +#define ERL_NAPI_SINT64_MAX__ 9223372036854775807LL +#define ERL_NAPI_SINT64_MIN__ (-ERL_NAPI_SINT64_MAX__ - 1LL) +#else +# error No 64-bit integer type +#endif + +#if SIZEOF_VOID_P == 8 +typedef ErlNapiUInt64 ErlNapiUInt; +typedef ErlNapiSInt64 ErlNapiSInt; +#elif SIZEOF_VOID_P == 4 +# if SIZEOF_LONG == SIZEOF_VOID_P +typedef unsigned long ErlNapiUInt; +typedef signed long ErlNapiSInt; +# elif SIZEOF_INT == SIZEOF_VOID_P +typedef unsigned int ErlNapiUInt; +typedef signed int ErlNapiSInt; +# else +# error No 32-bit integer type +# endif +#else +# error Not support arch +#endif + +#define ERTS_NAPI_TIME_ERROR__ ERL_NAPI_SINT64_MIN__ + +#define ERTS_NAPI_SEC__ 0 +#define ERTS_NAPI_MSEC__ 1 +#define ERTS_NAPI_USEC__ 2 +#define ERTS_NAPI_NSEC__ 3 + #endif /* __ERL_DRV_NIF_H__ */ diff --git a/erts/emulator/beam/erl_drv_thread.c b/erts/emulator/beam/erl_drv_thread.c index e0404eb5c9..184f8e8931 100644 --- a/erts/emulator/beam/erl_drv_thread.c +++ b/erts/emulator/beam/erl_drv_thread.c @@ -43,7 +43,7 @@ fatal_error(int err, char *func) else estr = "Unknown error"; } - erl_exit(ERTS_ABORT_EXIT, "Fatal error in %s: %s [%d]\n", func, estr, err); + erts_exit(ERTS_ABORT_EXIT, "Fatal error in %s: %s [%d]\n", func, estr, err); } #define ERL_DRV_TSD_KEYS_INC 10 diff --git a/erts/emulator/beam/erl_fun.c b/erts/emulator/beam/erl_fun.c index 4268e2d40a..2f13aa364f 100644 --- a/erts/emulator/beam/erl_fun.c +++ b/erts/emulator/beam/erl_fun.c @@ -185,7 +185,7 @@ erts_erase_fun_entry(ErlFunEntry* fe) #endif { if (fe->address != unloaded_fun) - erl_exit(1, + erts_exit(ERTS_ERROR_EXIT, "Internal error: " "Invalid reference count found on #Fun<%T.%d.%d>: " " About to erase fun still referred by code.\n", diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c index d2604f1595..f48c46ca33 100644 --- a/erts/emulator/beam/erl_gc.c +++ b/erts/emulator/beam/erl_gc.c @@ -59,7 +59,7 @@ erts_fprintf(stderr, "stop=%p\n", (p)->stop); \ erts_fprintf(stderr, "htop=%p\n", (p)->htop); \ erts_fprintf(stderr, "heap=%p\n", (p)->heap); \ - erl_exit(ERTS_ABORT_EXIT, "%s, line %d: %T: Overrun stack and heap\n", \ + erts_exit(ERTS_ABORT_EXIT, "%s, line %d: %T: Overrun stack and heap\n", \ __FILE__,__LINE__,(P)->common.id); \ } @@ -268,7 +268,7 @@ erts_next_heap_size(Uint size, Uint offset) low = mid + 1; } } - erl_exit(1, "no next heap size found: %beu, offset %beu\n", size, offset); + erts_exit(ERTS_ERROR_EXIT, "no next heap size found: %beu, offset %beu\n", size, offset); } return 0; } @@ -1237,6 +1237,7 @@ major_collection(Process* p, int need, Eterm* objv, int nobj, Uint *recl) Uint oh_size = (char *) OLD_HTOP(p) - oh; Uint n; Uint new_sz; + int done; /* * Do a fullsweep GC. First figure out the size of the heap @@ -1440,6 +1441,8 @@ major_collection(Process* p, int need, Eterm* objv, int nobj, Uint *recl) *recl += size_before - (HEAP_TOP(p) - HEAP_START(p)); + remove_message_buffers(p); + { ErlMessage *msgp; @@ -1458,15 +1461,21 @@ major_collection(Process* p, int need, Eterm* objv, int nobj, Uint *recl) } } - adjust_after_fullsweep(p, need, objv, nobj); - -#ifdef HARDDEBUG - disallow_heap_frag_ref_in_heap(p); -#endif - remove_message_buffers(p); + if (MBUF(p)) { + /* This is a very rare case when distributed messages copied above + * contained maps so big they did not fit on the heap causing the + * factory to create heap frags. + * Solution: Trigger a minor gc (without tenuring) + */ + HIGH_WATER(p) = HEAP_START(p); + done = 0; + } else { + adjust_after_fullsweep(p, need, objv, nobj); + done = 1; + } ErtsGcQuickSanityCheck(p); - return 1; /* We are done. */ + return done; } static void @@ -1955,7 +1964,18 @@ collect_heap_frags(Process* p, Eterm* n_hstart, Eterm* n_htop, if (p->dictionary != NULL) { disallow_heap_frag_ref(p, n_htop, p->dictionary->data, p->dictionary->used); } - disallow_heap_frag_ref_in_heap(p); + /* OTP-18: Actually we do allow references from heap to heap fragments now. + This can happen when doing "binary_to_term" with a "fat" map contained + in another term. A "fat" map is a hashmap with higher heap demand than + first estimated by "binary_to_term" causing the factory to allocate + additional heap (fragments) for the hashmap tree nodes. + Run map_SUITE:t_gc_rare_map_overflow to provoke this. + + Inverted references like this does not matter however. The copy done + below by move_one_area() with move markers in the fragments and the + sweeping done later by the GC should make everything ok in the end. + */ + /***disallow_heap_frag_ref_in_heap(p);***/ #endif /* @@ -2768,7 +2788,7 @@ within(Eterm *ptr, Process *p) #define ERTS_CHK_OFFHEAP_ASSERT(EXP) \ do { \ if (!(EXP)) \ - erl_exit(ERTS_ABORT_EXIT, \ + erts_exit(ERTS_ABORT_EXIT, \ "%s:%d: Assertion failed: %s\n", \ __FILE__, __LINE__, #EXP); \ } while (0) diff --git a/erts/emulator/beam/erl_goodfit_alloc.c b/erts/emulator/beam/erl_goodfit_alloc.c index f89f8723d9..9b4aad9d91 100644 --- a/erts/emulator/beam/erl_goodfit_alloc.c +++ b/erts/emulator/beam/erl_goodfit_alloc.c @@ -571,8 +571,8 @@ info_options(Allctr_t *allctr, if (hpp || szp) { if (!atoms_initialized) - erl_exit(1, "%s:%d: Internal error: Atoms not initialized", - __FILE__, __LINE__);; + erts_exit(ERTS_ERROR_EXIT, "%s:%d: Internal error: Atoms not initialized", + __FILE__, __LINE__); res = NIL; add_2tup(hpp, szp, &res, am.as, am.gf); diff --git a/erts/emulator/beam/erl_hl_timer.c b/erts/emulator/beam/erl_hl_timer.c index 51a0d68247..fbfde83dba 100644 --- a/erts/emulator/beam/erl_hl_timer.c +++ b/erts/emulator/beam/erl_hl_timer.c @@ -735,7 +735,10 @@ proc_timeout_common(Process *proc, void *tmr) if (tmr == (void *) erts_smp_atomic_cmpxchg_mb(&proc->common.timer, ERTS_PTMR_TIMEDOUT, (erts_aint_t) tmr)) { - erts_aint32_t state = erts_smp_atomic32_read_acqb(&proc->state); + erts_aint32_t state; + erts_smp_proc_lock(proc, ERTS_PROC_LOCKS_MSG_RECEIVE); + state = erts_smp_atomic32_read_acqb(&proc->state); + erts_smp_proc_unlock(proc, ERTS_PROC_LOCKS_MSG_RECEIVE); if (!(state & (ERTS_PSFLG_ACTIVE|ERTS_PSFLG_EXITING))) erts_schedule_process(proc, state, 0); return 1; @@ -1055,6 +1058,8 @@ create_hl_timer(ErtsSchedulerData *esdp, erts_aint32_t refc; Uint32 roflgs; + ERTS_HLT_HDBG_CHK_SRV(srv); + check_canceled_queue(esdp, srv); ERTS_HLT_ASSERT((esdp->no & ~ERTS_TMR_ROFLG_SID_MASK) == 0); @@ -1179,8 +1184,6 @@ create_hl_timer(ErtsSchedulerData *esdp, erts_smp_atomic32_init_nob(&tmr->head.refc, refc); erts_smp_atomic32_init_nob(&tmr->state, ERTS_TMR_STATE_ACTIVE); - ERTS_HLT_HDBG_CHK_SRV(srv); - if (!srv->next_timeout || tmr->timeout < srv->next_timeout->timeout) { if (srv->next_timeout) @@ -3099,7 +3102,8 @@ tt_hdbg_func(ErtsHLTimer *tmr, void *vhdbg) & ~ERTS_HLT_PFLGS_MASK); ERTS_HLT_ASSERT(tmr == prnt); } - ERTS_HLT_ASSERT(btm_rbt_lookup(hdbg->srv->btm_tree, tmr->btm.refn) == tmr); + if (tmr->head.roflgs & ERTS_TMR_ROFLG_BIF_TMR) + ERTS_HLT_ASSERT(btm_rbt_lookup(hdbg->srv->btm_tree, tmr->btm.refn) == tmr); if (tmr->time.tree.same_time) { ErtsHdbgHLT st_hdbg; st_hdbg.srv = hdbg->srv; diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c index 51b72033ca..b4d5bf8fb6 100644 --- a/erts/emulator/beam/erl_init.c +++ b/erts/emulator/beam/erl_init.c @@ -269,7 +269,7 @@ this_rel_num(void) i++; this_rel = atoi(&this_rel_str[i]); if (this_rel < 1) - erl_exit(-1, "Unexpected ERLANG_OTP_RELEASE format\n"); + erts_exit(1, "Unexpected ERLANG_OTP_RELEASE format\n"); } return this_rel; } @@ -415,7 +415,7 @@ erl_first_process_otp(char* modname, void* code, unsigned size, int argc, char** start_mod = erts_atom_put((byte *) modname, sys_strlen(modname), ERTS_ATOM_ENC_LATIN1, 1); if (erts_find_function(start_mod, am_start, 2, erts_active_code_ix()) == NULL) { - erl_exit(5, "No function %s:start/2\n", modname); + erts_exit(ERTS_ERROR_EXIT, "No function %s:start/2\n", modname); } /* @@ -512,12 +512,12 @@ load_preloaded(void) length = preload_p[i].size; module_name = erts_atom_put((byte *) name, sys_strlen(name), ERTS_ATOM_ENC_LATIN1, 1); if ((code = sys_preload_begin(&preload_p[i])) == 0) - erl_exit(1, "Failed to find preloaded code for module %s\n", + erts_exit(ERTS_ERROR_EXIT, "Failed to find preloaded code for module %s\n", name); res = erts_preload_module(NULL, 0, NIL, &module_name, code, length); sys_preload_end(&preload_p[i]); if (res != NIL) - erl_exit(1,"Failed loading preloaded module %s (%T)\n", + erts_exit(ERTS_ERROR_EXIT,"Failed loading preloaded module %s (%T)\n", name, res); i++; } @@ -648,7 +648,7 @@ void erts_usage(void) erts_fprintf(stderr, "Note that if the emulator is started with erlexec (typically\n"); erts_fprintf(stderr, "from the erl script), these flags should be specified with +.\n"); erts_fprintf(stderr, "\n\n"); - erl_exit(-1, ""); + erts_exit(1, ""); } #ifdef USE_THREADS @@ -1445,7 +1445,7 @@ erl_start(int argc, char **argv) } erts_fprintf(stderr, "(" EMULATOR ") emulator version " ERLANG_VERSION "\n"); - erl_exit(0, ""); + erts_exit(0, ""); } break; @@ -2247,26 +2247,20 @@ system_cleanup(int flush_async) } static __decl_noreturn void __noreturn -erl_exit_vv(int n, int flush_async, char *fmt, va_list args1, va_list args2) +erts_exit_vv(int n, int flush_async, char *fmt, va_list args1, va_list args2) { - unsigned int an; - system_cleanup(flush_async); save_statistics(); - if (n < 0) - an = -(unsigned int)n; - else - an = n; if (erts_mtrace_enabled) - erts_mtrace_exit((Uint32) an); + erts_mtrace_exit((Uint32) n); if (fmt != NULL && *fmt != '\0') erl_error(fmt, args2); /* Print error message. */ /* Produce an Erlang core dump if error */ - if (((n > 0 && erts_no_crash_dump == 0) || n == ERTS_DUMP_EXIT) + if (((n == ERTS_ERROR_EXIT && erts_no_crash_dump == 0) || n == ERTS_DUMP_EXIT) && erts_initialized) { erl_crash_dump_v((char*) NULL, 0, fmt, args1); } @@ -2277,29 +2271,29 @@ erl_exit_vv(int n, int flush_async, char *fmt, va_list args1, va_list args2) exit(0); else if (n == ERTS_DUMP_EXIT) ERTS_EXIT_AFTER_DUMP(1); - else if (n > 0 || n == ERTS_ABORT_EXIT) + else if (n == ERTS_ERROR_EXIT || n == ERTS_ABORT_EXIT) abort(); - exit(an); + exit(n); } /* Exit without flushing async threads */ -__decl_noreturn void __noreturn erl_exit(int n, char *fmt, ...) +__decl_noreturn void __noreturn erts_exit(int n, char *fmt, ...) { va_list args1, args2; va_start(args1, fmt); va_start(args2, fmt); - erl_exit_vv(n, 0, fmt, args1, args2); + erts_exit_vv(n, 0, fmt, args1, args2); va_end(args2); va_end(args1); } /* Exit after flushing async threads */ -__decl_noreturn void __noreturn erl_exit_flush_async(int n, char *fmt, ...) +__decl_noreturn void __noreturn erts_flush_async_exit(int n, char *fmt, ...) { va_list args1, args2; va_start(args1, fmt); va_start(args2, fmt); - erl_exit_vv(n, 1, fmt, args1, args2); + erts_exit_vv(n, 1, fmt, args1, args2); va_end(args2); va_end(args1); } diff --git a/erts/emulator/beam/erl_map.c b/erts/emulator/beam/erl_map.c index a91e36e3c5..3c066cea7b 100644 --- a/erts/emulator/beam/erl_map.c +++ b/erts/emulator/beam/erl_map.c @@ -32,7 +32,9 @@ #include "global.h" #include "erl_process.h" #include "error.h" +#define ERL_WANT_HIPE_BIF_WRAPPER__ #include "bif.h" +#undef ERL_WANT_HIPE_BIF_WRAPPER__ #include "erl_binary.h" #include "erl_map.h" @@ -952,8 +954,11 @@ BIF_RETTYPE maps_keys_1(BIF_ALIST_1) { BIF_P->fvalue = BIF_ARG_1; BIF_ERROR(BIF_P, BADMAP); } + /* maps:merge/2 */ +HIPE_WRAPPER_BIF_DISABLE_GC(maps_merge, 2) + BIF_RETTYPE maps_merge_2(BIF_ALIST_2) { if (is_flatmap(BIF_ARG_1)) { if (is_flatmap(BIF_ARG_2)) { @@ -1269,7 +1274,7 @@ recurse: break; } default: - erl_exit(ERTS_ABORT_EXIT, "bad header %ld\r\n", hdrA); + erts_exit(ERTS_ABORT_EXIT, "bad header %ld\r\n", hdrA); } } @@ -1296,7 +1301,7 @@ recurse: break; } default: - erl_exit(ERTS_ABORT_EXIT, "bad header %ld\r\n", hdrB); + erts_exit(ERTS_ABORT_EXIT, "bad header %ld\r\n", hdrB); } } } @@ -1386,7 +1391,7 @@ resume_from_trap: res = make_boxed(nhp); break; default: - erl_exit(ERTS_ABORT_EXIT, "strange mix %d\r\n", sp->mix); + erts_exit(ERTS_ABORT_EXIT, "strange mix %d\r\n", sp->mix); } } @@ -1881,7 +1886,7 @@ void hashmap_iterator_init(ErtsWStack* s, Eterm node, int reverse) { sz = hashmap_bitcount(MAP_HEADER_VAL(hdr)); break; default: - erl_exit(ERTS_ABORT_EXIT, "bad header"); + erts_exit(ERTS_ABORT_EXIT, "bad header"); } WSTACK_PUSH3((*s), (UWord)THE_NON_VALUE, /* end marker */ @@ -1918,7 +1923,7 @@ Eterm* hashmap_iterator_next(ErtsWStack* s) { ASSERT(sz < 17); break; default: - erl_exit(ERTS_ABORT_EXIT, "bad header"); + erts_exit(ERTS_ABORT_EXIT, "bad header"); } idx++; @@ -1968,7 +1973,7 @@ Eterm* hashmap_iterator_prev(ErtsWStack* s) { ASSERT(sz < 17); break; default: - erl_exit(1, "bad header"); + erts_exit(ERTS_ERROR_EXIT, "bad header"); } if (idx > sz) @@ -2156,12 +2161,12 @@ int erts_hashmap_insert_down(Uint32 hx, Eterm key, Eterm node, Uint *sz, size += HAMT_HEAD_BITMAP_SZ(n+1); goto unroll; default: - erl_exit(1, "bad header tag %ld\r\n", hdr & _HEADER_MAP_SUBTAG_MASK); + erts_exit(ERTS_ERROR_EXIT, "bad header tag %ld\r\n", hdr & _HEADER_MAP_SUBTAG_MASK); break; } break; default: - erl_exit(1, "bad primary tag %p\r\n", node); + erts_exit(ERTS_ERROR_EXIT, "bad primary tag %p\r\n", node); break; } } @@ -2276,12 +2281,12 @@ Eterm erts_hashmap_insert_up(Eterm *hp, Eterm key, Eterm value, res = make_hashmap(nhp); break; default: - erl_exit(1, "bad header tag %x\r\n", hdr & _HEADER_MAP_SUBTAG_MASK); + erts_exit(ERTS_ERROR_EXIT, "bad header tag %x\r\n", hdr & _HEADER_MAP_SUBTAG_MASK); break; } break; default: - erl_exit(1, "bad primary tag %x\r\n", primary_tag(node)); + erts_exit(ERTS_ERROR_EXIT, "bad primary tag %x\r\n", primary_tag(node)); break; } @@ -2399,12 +2404,12 @@ static Eterm hashmap_delete(Process *p, Uint32 hx, Eterm key, Eterm map) { /* not occupied */ goto not_found; default: - erl_exit(1, "bad header tag %ld\r\n", hdr & _HEADER_MAP_SUBTAG_MASK); + erts_exit(ERTS_ERROR_EXIT, "bad header tag %ld\r\n", hdr & _HEADER_MAP_SUBTAG_MASK); break; } break; default: - erl_exit(1, "bad primary tag %p\r\n", node); + erts_exit(ERTS_ERROR_EXIT, "bad primary tag %p\r\n", node); break; } } @@ -2581,7 +2586,7 @@ unroll: res = make_hashmap(nhp); break; default: - erl_exit(1, "bad header tag %x\r\n", hdr & _HEADER_MAP_SUBTAG_MASK); + erts_exit(ERTS_ERROR_EXIT, "bad header tag %x\r\n", hdr & _HEADER_MAP_SUBTAG_MASK); break; } } while(!ESTACK_ISEMPTY(stack)); @@ -2722,7 +2727,7 @@ BIF_RETTYPE erts_internal_map_type_1(BIF_ALIST_1) { case HAMT_SUBTAG_NODE_BITMAP: BIF_RET(AM_hashmap_node); default: - erl_exit(1, "bad header"); + erts_exit(ERTS_ERROR_EXIT, "bad header"); } } BIF_P->fvalue = BIF_ARG_1; @@ -2758,7 +2763,7 @@ BIF_RETTYPE erts_internal_map_hashmap_children_1(BIF_ALIST_1) { ptr += 2; break; default: - erl_exit(1, "bad header\r\n"); + erts_exit(ERTS_ERROR_EXIT, "bad header\r\n"); break; } ASSERT(sz < 17); @@ -2836,7 +2841,7 @@ static Eterm hashmap_info(Process *p, Eterm node) { } break; default: - erl_exit(1, "bad header\r\n"); + erts_exit(ERTS_ERROR_EXIT, "bad header\r\n"); break; } } diff --git a/erts/emulator/beam/erl_map.h b/erts/emulator/beam/erl_map.h index c391de3f11..4d9d74bc37 100644 --- a/erts/emulator/beam/erl_map.h +++ b/erts/emulator/beam/erl_map.h @@ -195,14 +195,17 @@ typedef struct hashmap_head_s { [one cons cell + one list term in parent node] per key [one header + one boxed term in parent node] per inner node [one header + one size word] for root node + Observed average number of nodes per key is about 0.35. */ -#define HASHMAP_HEAP_SIZE(KEYS,NODES) ((KEYS)*3 + (NODES)*2) +#define HASHMAP_WORDS_PER_KEY 3 +#define HASHMAP_WORDS_PER_NODE 2 #ifdef DEBUG -# define HASHMAP_ESTIMATED_NODE_COUNT(KEYS) (KEYS) +# define HASHMAP_ESTIMATED_TOT_NODE_SIZE(KEYS) \ + (HASHMAP_WORDS_PER_NODE * (KEYS) * 3/10) /* slightly under estimated */ #else -# define HASHMAP_ESTIMATED_NODE_COUNT(KEYS) (2*(KEYS)/5) +# define HASHMAP_ESTIMATED_TOT_NODE_SIZE(KEYS) \ + (HASHMAP_WORDS_PER_NODE * (KEYS) * 4/10) /* slightly over estimated */ #endif #define HASHMAP_ESTIMATED_HEAP_SIZE(KEYS) \ - HASHMAP_HEAP_SIZE(KEYS,HASHMAP_ESTIMATED_NODE_COUNT(KEYS)) - + ((KEYS)*HASHMAP_WORDS_PER_KEY + HASHMAP_ESTIMATED_TOT_NODE_SIZE(KEYS)) #endif diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c index ef52823287..fa6b2fc613 100644 --- a/erts/emulator/beam/erl_message.c +++ b/erts/emulator/beam/erl_message.c @@ -1174,6 +1174,9 @@ void erts_factory_message_init(ErtsHeapFactory* factory, ASSERT(factory->hp >= factory->hp_start && factory->hp <= factory->hp_end); } +/* One static sized heap that must suffice. + No extra heap fragments will be allocated. +*/ void erts_factory_static_init(ErtsHeapFactory* factory, Eterm* hp, Uint size, @@ -1188,6 +1191,23 @@ void erts_factory_static_init(ErtsHeapFactory* factory, factory->off_heap_saved.overhead = factory->off_heap->overhead; } +/* A temporary heap with default buffer allocated/freed by client. + * factory_close is same as factory_undo + */ +void erts_factory_tmp_init(ErtsHeapFactory* factory, Eterm* hp, Uint size, + Uint32 atype) +{ + factory->mode = FACTORY_TMP; + factory->hp_start = hp; + factory->hp = hp; + factory->hp_end = hp + size; + factory->heap_frags = NULL; + factory->off_heap_saved.first = NULL; + factory->off_heap_saved.overhead = 0; + factory->off_heap = &factory->off_heap_saved; + factory->alloc_type = atype; +} + /* When we know the term is an immediate and need no heap. */ void erts_factory_dummy_init(ErtsHeapFactory* factory) @@ -1231,6 +1251,7 @@ static void reserve_heap(ErtsHeapFactory* factory, Uint need, Uint xtra) return; case FACTORY_HEAP_FRAGS: + case FACTORY_TMP: bp = factory->heap_frags; if (bp) { @@ -1280,6 +1301,9 @@ void erts_factory_close(ErtsHeapFactory* factory) bp->used_size = factory->hp - bp->mem; } break; + case FACTORY_TMP: + erts_factory_undo(factory); + break; case FACTORY_STATIC: break; case FACTORY_CLOSED: break; default: @@ -1371,16 +1395,20 @@ void erts_factory_undo(ErtsHeapFactory* factory) } break; + case FACTORY_TMP: case FACTORY_HEAP_FRAGS: + erts_cleanup_offheap(factory->off_heap); + factory->off_heap->first = NULL; + bp = factory->heap_frags; - do { + while (bp != NULL) { ErlHeapFragment* next_bp = bp->next; - erts_cleanup_offheap(&bp->off_heap); + ASSERT(bp->off_heap.first == NULL); ERTS_HEAP_FREE(factory->alloc_type, (void *) bp, - ERTS_HEAP_FRAG_SIZE(bp->size)); + ERTS_HEAP_FRAG_SIZE(bp->alloc_size)); bp = next_bp; - }while (bp != NULL); + } break; case FACTORY_CLOSED: break; diff --git a/erts/emulator/beam/erl_message.h b/erts/emulator/beam/erl_message.h index fbdf3fb0e2..92ba3e571c 100644 --- a/erts/emulator/beam/erl_message.h +++ b/erts/emulator/beam/erl_message.h @@ -58,7 +58,8 @@ typedef struct { FACTORY_CLOSED = 0, FACTORY_HALLOC, FACTORY_HEAP_FRAGS, - FACTORY_STATIC + FACTORY_STATIC, + FACTORY_TMP } mode; Process* p; Eterm* hp_start; @@ -75,6 +76,7 @@ void erts_factory_proc_init(ErtsHeapFactory*, Process*); void erts_factory_proc_prealloc_init(ErtsHeapFactory*, Process*, Sint size); void erts_factory_message_init(ErtsHeapFactory*, Process*, Eterm* hp, struct erl_heap_fragment*); void erts_factory_static_init(ErtsHeapFactory*, Eterm* hp, Uint size, ErlOffHeap*); +void erts_factory_tmp_init(ErtsHeapFactory*, Eterm* hp, Uint size, Uint32 atype); void erts_factory_dummy_init(ErtsHeapFactory*); Eterm* erts_produce_heap(ErtsHeapFactory*, Uint need, Uint xtra); diff --git a/erts/emulator/beam/erl_monitors.c b/erts/emulator/beam/erl_monitors.c index 7dfa01c8ac..bd899fa2f9 100644 --- a/erts/emulator/beam/erl_monitors.c +++ b/erts/emulator/beam/erl_monitors.c @@ -356,7 +356,7 @@ void erts_add_monitor(ErtsMonitor **root, Uint type, Eterm ref, Eterm pid, tstack[tpos++] = this; this = &((*this)->right); } else { /* Equal key is an error for monitors */ - erl_exit(1,"Insertion of already present monitor!"); + erts_exit(ERTS_ERROR_EXIT,"Insertion of already present monitor!"); break; } } diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index add4a66f90..1097916c97 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -330,7 +330,7 @@ int enif_send(ErlNifEnv* env, const ErlNifPid* to_pid, #ifdef ERTS_SMP c_p = NULL; #else - erl_exit(ERTS_ABORT_EXIT,"enif_send: env==NULL on non-SMP VM"); + erts_exit(ERTS_ABORT_EXIT,"enif_send: env==NULL on non-SMP VM"); #endif } @@ -1173,6 +1173,27 @@ ErlNifTid enif_thread_self(void) { return erl_drv_thread_self(); } int enif_equal_tids(ErlNifTid tid1, ErlNifTid tid2) { return erl_drv_equal_tids(tid1,tid2); } void enif_thread_exit(void *resp) { erl_drv_thread_exit(resp); } int enif_thread_join(ErlNifTid tid, void **respp) { return erl_drv_thread_join(tid,respp); } +int enif_getenv(const char *key, char *value, size_t *value_size) { return erl_drv_getenv(key, value, value_size); } + +ErlNifTime enif_monotonic_time(ErlNifTimeUnit time_unit) +{ + return (ErlNifTime) erts_napi_monotonic_time((int) time_unit); +} + +ErlNifTime enif_time_offset(ErlNifTimeUnit time_unit) +{ + return (ErlNifTime) erts_napi_time_offset((int) time_unit); +} + +ErlNifTime +enif_convert_time_unit(ErlNifTime val, + ErlNifTimeUnit from, + ErlNifTimeUnit to) +{ + return (ErlNifTime) erts_napi_convert_time_unit((ErtsMonotonicTime) val, + (int) from, + (int) to); +} int enif_fprintf(void* filep, const char* format, ...) { diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h index 7d880126f8..75070ad901 100644 --- a/erts/emulator/beam/erl_nif.h +++ b/erts/emulator/beam/erl_nif.h @@ -48,9 +48,11 @@ ** add ErlNifEntry options ** add ErlNifFunc flags ** 2.8: 18.0 add enif_has_pending_exception +** 2.9: 18.2 enif_getenv +** 2.10: Time API */ #define ERL_NIF_MAJOR_VERSION 2 -#define ERL_NIF_MINOR_VERSION 8 +#define ERL_NIF_MINOR_VERSION 10 /* * The emulator will refuse to load a nif-lib with a major version @@ -66,63 +68,36 @@ #include <stdlib.h> -#ifdef SIZEOF_CHAR -# define SIZEOF_CHAR_SAVED__ SIZEOF_CHAR -# undef SIZEOF_CHAR -#endif -#ifdef SIZEOF_SHORT -# define SIZEOF_SHORT_SAVED__ SIZEOF_SHORT -# undef SIZEOF_SHORT -#endif -#ifdef SIZEOF_INT -# define SIZEOF_INT_SAVED__ SIZEOF_INT -# undef SIZEOF_INT -#endif -#ifdef SIZEOF_LONG -# define SIZEOF_LONG_SAVED__ SIZEOF_LONG -# undef SIZEOF_LONG -#endif -#ifdef SIZEOF_LONG_LONG -# define SIZEOF_LONG_LONG_SAVED__ SIZEOF_LONG_LONG -# undef SIZEOF_LONG_LONG -#endif -#ifdef HALFWORD_HEAP_EMULATOR -# define HALFWORD_HEAP_EMULATOR_SAVED__ HALFWORD_HEAP_EMULATOR -# undef HALFWORD_HEAP_EMULATOR -#endif -#include "erl_int_sizes_config.h" - #ifdef __cplusplus extern "C" { #endif -#if (defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_)) -typedef unsigned __int64 ErlNifUInt64; -typedef __int64 ErlNifSInt64; -#elif SIZEOF_LONG == 8 -typedef unsigned long ErlNifUInt64; -typedef long ErlNifSInt64; -#elif SIZEOF_LONG_LONG == 8 -typedef unsigned long long ErlNifUInt64; -typedef long long ErlNifSInt64; -#else -#error No 64-bit integer type -#endif +typedef ErlNapiUInt64 ErlNifUInt64; +typedef ErlNapiSInt64 ErlNifSInt64; +typedef ErlNapiUInt ErlNifUInt; +typedef ErlNapiSInt ErlNifSInt; #ifdef HALFWORD_HEAP_EMULATOR # define ERL_NIF_VM_VARIANT "beam.halfword" typedef unsigned int ERL_NIF_TERM; #else # define ERL_NIF_VM_VARIANT "beam.vanilla" -# if SIZEOF_LONG == SIZEOF_VOID_P -typedef unsigned long ERL_NIF_TERM; -# elif SIZEOF_LONG_LONG == SIZEOF_VOID_P -typedef unsigned long long ERL_NIF_TERM; -# endif +typedef ErlNifUInt ERL_NIF_TERM; #endif typedef ERL_NIF_TERM ERL_NIF_UINT; +typedef ErlNifSInt64 ErlNifTime; + +#define ERL_NIF_TIME_ERROR ((ErlNifSInt64) ERTS_NAPI_TIME_ERROR__) + +typedef enum { + ERL_NIF_SEC = ERTS_NAPI_SEC__, + ERL_NIF_MSEC = ERTS_NAPI_MSEC__, + ERL_NIF_USEC = ERTS_NAPI_USEC__, + ERL_NIF_NSEC = ERTS_NAPI_NSEC__ +} ErlNifTimeUnit; + struct enif_environment_t; typedef struct enif_environment_t ErlNifEnv; @@ -231,6 +206,7 @@ typedef enum { # define ERL_NIF_API_FUNC_DECL(RET_TYPE, NAME, ARGS) RET_TYPE (*NAME) ARGS typedef struct { # include "erl_nif_api_funcs.h" + void* erts_alc_test; } TWinDynNifCallbacks; extern TWinDynNifCallbacks WinDynNifCallbacks; # undef ERL_NIF_API_FUNC_DECL diff --git a/erts/emulator/beam/erl_nif_api_funcs.h b/erts/emulator/beam/erl_nif_api_funcs.h index f93152c921..1448a508a2 100644 --- a/erts/emulator/beam/erl_nif_api_funcs.h +++ b/erts/emulator/beam/erl_nif_api_funcs.h @@ -159,6 +159,10 @@ ERL_NIF_API_FUNC_DECL(int, enif_map_iterator_get_pair, (ErlNifEnv *env, ErlNifMa ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_schedule_nif,(ErlNifEnv*,const char*,int,ERL_NIF_TERM (*)(ErlNifEnv*,int,const ERL_NIF_TERM[]),int,const ERL_NIF_TERM[])); ERL_NIF_API_FUNC_DECL(int, enif_has_pending_exception, (ErlNifEnv *env, ERL_NIF_TERM* reason)); ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM, enif_raise_exception, (ErlNifEnv *env, ERL_NIF_TERM reason)); +ERL_NIF_API_FUNC_DECL(int,enif_getenv,(const char* key, char* value, size_t* value_size)); +ERL_NIF_API_FUNC_DECL(ErlNifTime, enif_monotonic_time, (ErlNifTimeUnit)); +ERL_NIF_API_FUNC_DECL(ErlNifTime, enif_time_offset, (ErlNifTimeUnit)); +ERL_NIF_API_FUNC_DECL(ErlNifTime, enif_convert_time_unit, (ErlNifTime, ErlNifTimeUnit, ErlNifTimeUnit)); /* ** ADD NEW ENTRIES HERE (before this comment) !!! @@ -310,6 +314,10 @@ ERL_NIF_API_FUNC_DECL(int,enif_is_on_dirty_scheduler,(ErlNifEnv*)); # define enif_schedule_nif ERL_NIF_API_FUNC_MACRO(enif_schedule_nif) # define enif_has_pending_exception ERL_NIF_API_FUNC_MACRO(enif_has_pending_exception) # define enif_raise_exception ERL_NIF_API_FUNC_MACRO(enif_raise_exception) +# define enif_getenv ERL_NIF_API_FUNC_MACRO(enif_getenv) +# define enif_monotonic_time ERL_NIF_API_FUNC_MACRO(enif_monotonic_time) +# define enif_time_offset ERL_NIF_API_FUNC_MACRO(enif_time_offset) +# define enif_convert_time_unit ERL_NIF_API_FUNC_MACRO(enif_convert_time_unit) /* ** ADD NEW ENTRIES HERE (before this comment) @@ -543,7 +551,7 @@ static ERL_NIF_INLINE ERL_NIF_TERM enif_make_list9(ErlNifEnv* env, #ifndef enif_make_pid -# define enif_make_pid(ENV, PID) ((const ERL_NIF_TERM)((PID)->pid)) +# define enif_make_pid(ENV, PID) ((void)(ENV),(const ERL_NIF_TERM)((PID)->pid)) #if SIZEOF_LONG == 8 # define enif_get_int64 enif_get_long diff --git a/erts/emulator/beam/erl_node_tables.c b/erts/emulator/beam/erl_node_tables.c index 2fb790b953..e69bd49c42 100644 --- a/erts/emulator/beam/erl_node_tables.c +++ b/erts/emulator/beam/erl_node_tables.c @@ -37,18 +37,18 @@ erts_smp_rwmtx_t erts_node_table_rwmtx; DistEntry *erts_hidden_dist_entries; DistEntry *erts_visible_dist_entries; -DistEntry *erts_not_connected_dist_entries; +DistEntry *erts_not_connected_dist_entries; /* including erts_this_dist_entry */ Sint erts_no_of_hidden_dist_entries; Sint erts_no_of_visible_dist_entries; -Sint erts_no_of_not_connected_dist_entries; +Sint erts_no_of_not_connected_dist_entries; /* including erts_this_dist_entry */ DistEntry *erts_this_dist_entry; ErlNode *erts_this_node; char erts_this_node_sysname_BUFFER[256], *erts_this_node_sysname = "uninitialized yet"; -static Uint node_entries; -static Uint dist_entries; +static Uint node_entries = 0; +static Uint dist_entries = 0; static int references_atoms_need_init = 1; @@ -91,9 +91,6 @@ dist_table_alloc(void *dep_tmpl) erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_RWMTX_OPT_DEFAULT_INITER; rwmtx_opt.type = ERTS_SMP_RWMTX_TYPE_FREQUENT_READ; - if(((DistEntry *) dep_tmpl) == erts_this_dist_entry) - return dep_tmpl; - sysname = ((DistEntry *) dep_tmpl)->sysname; chnl_nr = make_small((Uint) atom_val(sysname)); dep = (DistEntry *) erts_alloc(ERTS_ALC_T_DIST_ENTRY, sizeof(DistEntry)); @@ -132,7 +129,9 @@ dist_table_alloc(void *dep_tmpl) /* Link in */ - /* All new dist entries are "not connected" */ + /* All new dist entries are "not connected". + * erts_this_dist_entry is also always included among "not connected" + */ dep->next = erts_not_connected_dist_entries; if(erts_not_connected_dist_entries) { ASSERT(erts_not_connected_dist_entries->prev == NULL); @@ -149,9 +148,6 @@ dist_table_free(void *vdep) { DistEntry *dep = (DistEntry *) vdep; - if(dep == erts_this_dist_entry) - return; - ASSERT(is_nil(dep->cid)); ASSERT(dep->nlinks == NULL); ASSERT(dep->node_links == NULL); @@ -186,7 +182,7 @@ dist_table_free(void *vdep) #endif erts_free(ERTS_ALC_T_DIST_ENTRY, (void *) dep); - ASSERT(dist_entries > 1); + ASSERT(dist_entries > 0); dist_entries--; } @@ -306,7 +302,7 @@ static void try_delete_dist_entry(void *vdep) * thread incremented refc twice. Once for the new reference * and once for this thread. * - * If refc reach -1, noone has used the entry since we + * If refc reach -1, no one has used the entry since we * set up the timer. Delete the entry. * * If refc reach 0, the entry is currently not in use @@ -369,8 +365,7 @@ erts_dist_table_size(void) ASSERT(dist_entries == (erts_no_of_visible_dist_entries + erts_no_of_hidden_dist_entries - + erts_no_of_not_connected_dist_entries - + 1 /* erts_this_dist_entry */)); + + erts_no_of_not_connected_dist_entries)); #endif res = (hash_table_sz(&erts_dist_table) @@ -543,9 +538,6 @@ node_table_alloc(void *venp_tmpl) { ErlNode *enp; - if(((ErlNode *) venp_tmpl) == erts_this_node) - return venp_tmpl; - enp = (ErlNode *) erts_alloc(ERTS_ALC_T_NODE_ENTRY, sizeof(ErlNode)); node_entries++; @@ -563,8 +555,7 @@ node_table_free(void *venp) { ErlNode *enp = (ErlNode *) venp; - if(enp == erts_this_node) - return; + ERTS_SMP_LC_ASSERT(enp != erts_this_node || erts_thr_progress_is_blocking()); erts_deref_dist_entry(enp->dist_entry); #ifdef DEBUG @@ -572,7 +563,7 @@ node_table_free(void *venp) #endif erts_free(ERTS_ALC_T_NODE_ENTRY, venp); - ASSERT(node_entries > 1); + ASSERT(node_entries > 0); node_entries--; } @@ -650,7 +641,7 @@ static void try_delete_node(void *venp) * thread incremented refc twice. Once for the new reference * and once for this thread. * - * If refc reach -1, noone has used the entry since we + * If refc reach -1, no one has used the entry since we * set up the timer. Delete the entry. * * If refc reach 0, the entry is currently not in use @@ -747,25 +738,24 @@ void erts_print_node_info(int to, void erts_set_this_node(Eterm sysname, Uint creation) { - erts_smp_rwmtx_rwlock(&erts_node_table_rwmtx); - erts_smp_rwmtx_rwlock(&erts_dist_table_rwmtx); + ERTS_SMP_LC_ASSERT(erts_thr_progress_is_blocking()); + ASSERT(erts_refc_read(&erts_this_dist_entry->refc, 2)); - (void) hash_erase(&erts_dist_table, (void *) erts_this_dist_entry); - erts_this_dist_entry->sysname = sysname; - erts_this_dist_entry->creation = creation; - (void) hash_put(&erts_dist_table, (void *) erts_this_dist_entry); + if (erts_refc_dectest(&erts_this_node->refc, 0) == 0) + try_delete_node(erts_this_node); - (void) hash_erase(&erts_node_table, (void *) erts_this_node); - erts_this_node->sysname = sysname; - erts_this_node->creation = creation; - erts_this_node_sysname = erts_this_node_sysname_BUFFER; - erts_snprintf(erts_this_node_sysname, sizeof(erts_this_node_sysname_BUFFER), - "%T", sysname); - (void) hash_put(&erts_node_table, (void *) erts_this_node); + if (erts_refc_dectest(&erts_this_dist_entry->refc, 0) == 0) + try_delete_dist_entry(erts_this_dist_entry); - erts_smp_rwmtx_rwunlock(&erts_dist_table_rwmtx); - erts_smp_rwmtx_rwunlock(&erts_node_table_rwmtx); + erts_this_node = NULL; /* to make sure refc is bumped for this node */ + erts_this_node = erts_find_or_insert_node(sysname, creation); + erts_this_dist_entry = erts_this_node->dist_entry; + + erts_refc_inc(&erts_this_dist_entry->refc, 2); + erts_this_node_sysname = erts_this_node_sysname_BUFFER; + erts_snprintf(erts_this_node_sysname, sizeof(erts_this_node_sysname_BUFFER), + "%T", sysname); } Uint @@ -782,6 +772,7 @@ void erts_init_node_tables(int dd_sec) { erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_RWMTX_OPT_DEFAULT_INITER; HashFunctions f; + ErlNode node_tmpl; if (dd_sec == ERTS_NODE_TAB_DELAY_GC_INFINITY) node_tab_delete_delay = (ErtsMonotonicTime) -1; @@ -793,16 +784,21 @@ void erts_init_node_tables(int dd_sec) rwmtx_opt.type = ERTS_SMP_RWMTX_TYPE_FREQUENT_READ; rwmtx_opt.lived = ERTS_SMP_RWMTX_LONG_LIVED; + erts_smp_rwmtx_init_opt(&erts_node_table_rwmtx, &rwmtx_opt, "node_table"); + erts_smp_rwmtx_init_opt(&erts_dist_table_rwmtx, &rwmtx_opt, "dist_table"); + f.hash = (H_FUN) dist_table_hash; f.cmp = (HCMP_FUN) dist_table_cmp; f.alloc = (HALLOC_FUN) dist_table_alloc; f.free = (HFREE_FUN) dist_table_free; - - erts_this_dist_entry = erts_alloc(ERTS_ALC_T_DIST_ENTRY, sizeof(DistEntry)); - dist_entries = 1; - hash_init(ERTS_ALC_T_DIST_TABLE, &erts_dist_table, "dist_table", 11, f); + f.hash = (H_FUN) node_table_hash; + f.cmp = (HCMP_FUN) node_table_cmp; + f.alloc = (HALLOC_FUN) node_table_alloc; + f.free = (HFREE_FUN) node_table_free; + hash_init(ERTS_ALC_T_NODE_TABLE, &erts_node_table, "node_table", 11, f); + erts_hidden_dist_entries = NULL; erts_visible_dist_entries = NULL; erts_not_connected_dist_entries = NULL; @@ -810,69 +806,23 @@ void erts_init_node_tables(int dd_sec) erts_no_of_visible_dist_entries = 0; erts_no_of_not_connected_dist_entries = 0; - erts_this_dist_entry->next = NULL; - erts_this_dist_entry->prev = NULL; - erts_refc_init(&erts_this_dist_entry->refc, 1); /* erts_this_node */ - - erts_smp_rwmtx_init_opt_x(&erts_this_dist_entry->rwmtx, - &rwmtx_opt, - "dist_entry", - make_small(ERST_INTERNAL_CHANNEL_NO)); - erts_this_dist_entry->sysname = am_Noname; - erts_this_dist_entry->cid = NIL; - erts_this_dist_entry->connection_id = 0; - erts_this_dist_entry->status = 0; - erts_this_dist_entry->flags = 0; - erts_this_dist_entry->version = 0; - - erts_smp_mtx_init_x(&erts_this_dist_entry->lnk_mtx, - "dist_entry_links", - make_small(ERST_INTERNAL_CHANNEL_NO)); - erts_this_dist_entry->node_links = NULL; - erts_this_dist_entry->nlinks = NULL; - erts_this_dist_entry->monitors = NULL; - - erts_smp_mtx_init_x(&erts_this_dist_entry->qlock, - "dist_entry_out_queue", - make_small(ERST_INTERNAL_CHANNEL_NO)); - erts_this_dist_entry->qflgs = 0; - erts_this_dist_entry->qsize = 0; - erts_this_dist_entry->out_queue.first = NULL; - erts_this_dist_entry->out_queue.last = NULL; - erts_this_dist_entry->suspended = NULL; - - erts_this_dist_entry->finalized_out_queue.first = NULL; - erts_this_dist_entry->finalized_out_queue.last = NULL; - erts_smp_atomic_init_nob(&erts_this_dist_entry->dist_cmd_scheduled, 0); - erts_port_task_handle_init(&erts_this_dist_entry->dist_cmd); - erts_this_dist_entry->send = NULL; - erts_this_dist_entry->cache = NULL; - - (void) hash_put(&erts_dist_table, (void *) erts_this_dist_entry); + node_tmpl.sysname = am_Noname; + node_tmpl.creation = 0; + erts_this_node = hash_put(&erts_node_table, &node_tmpl); + /* +1 for erts_this_node */ + erts_refc_init(&erts_this_node->refc, 1); - f.hash = (H_FUN) node_table_hash; - f.cmp = (HCMP_FUN) node_table_cmp; - f.alloc = (HALLOC_FUN) node_table_alloc; - f.free = (HFREE_FUN) node_table_free; - - hash_init(ERTS_ALC_T_NODE_TABLE, &erts_node_table, "node_table", 11, f); + ASSERT(erts_this_node->dist_entry != NULL); + erts_this_dist_entry = erts_this_node->dist_entry; + /* +1 for erts_this_dist_entry */ + /* +1 for erts_this_node->dist_entry */ + erts_refc_init(&erts_this_dist_entry->refc, 2); - erts_this_node = erts_alloc(ERTS_ALC_T_NODE_ENTRY, sizeof(ErlNode)); - node_entries = 1; - erts_refc_init(&erts_this_node->refc, 1); /* The system itself */ - erts_this_node->sysname = am_Noname; - erts_this_node->creation = 0; - erts_this_node->dist_entry = erts_this_dist_entry; erts_this_node_sysname = erts_this_node_sysname_BUFFER; erts_snprintf(erts_this_node_sysname, sizeof(erts_this_node_sysname_BUFFER), "%T", erts_this_node->sysname); - (void) hash_put(&erts_node_table, (void *) erts_this_node); - - erts_smp_rwmtx_init_opt(&erts_node_table_rwmtx, &rwmtx_opt, "node_table"); - erts_smp_rwmtx_init_opt(&erts_dist_table_rwmtx, &rwmtx_opt, "dist_table"); - references_atoms_need_init = 1; } @@ -1100,7 +1050,7 @@ insert_dist_entry(DistEntry *dist, int type, Eterm id, Uint creation) } if(!rdp) - erl_exit(1, + erts_exit(ERTS_ERROR_EXIT, "Reference to non-existing distribution table entry found!\n"); insert_dist_referrer(rdp, type, id, creation); @@ -1161,7 +1111,7 @@ insert_node(ErlNode *node, int type, Eterm id) } if (!rnp) - erl_exit(1, "Reference to non-existing node table entry found!\n"); + erts_exit(ERTS_ERROR_EXIT, "Reference to non-existing node table entry found!\n"); insert_node_referrer(rnp, type, id); } @@ -1410,6 +1360,10 @@ setup_reference_table(void) SYSTEM_REF, TUPLE2(&heap[0], AM_system, am_undefined)); + insert_dist_entry(erts_this_dist_entry, + SYSTEM_REF, + TUPLE2(&heap[0], AM_system, am_undefined), + erts_this_node->creation); UnUseTmpHeapNoproc(3); max = erts_ptab_max(&erts_proc); @@ -1472,12 +1426,6 @@ setup_reference_table(void) insert_links(ERTS_P_LINKS(proc), proc->common.id); if (ERTS_P_MONITORS(proc)) insert_monitors(ERTS_P_MONITORS(proc), proc->common.id); - /* Insert controller */ - { - DistEntry *dep = ERTS_PROC_GET_DIST_ENTRY(proc); - if (dep) - insert_dist_entry(dep, CTRL_REF, proc->common.id, 0); - } } } diff --git a/erts/emulator/beam/erl_port_task.c b/erts/emulator/beam/erl_port_task.c index 5c38db1cbc..ddcca06b0a 100644 --- a/erts/emulator/beam/erl_port_task.c +++ b/erts/emulator/beam/erl_port_task.c @@ -1784,7 +1784,7 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) reds = erts_dist_command(pp, CONTEXT_REDS - pp->reds); break; default: - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Invalid port task type: %d\n", (int) ptp->type); break; @@ -2048,7 +2048,7 @@ begin_port_cleanup(Port *pp, ErtsPortTask **execqp, int *processing_busy_q_p) break; } default: - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Invalid port task type: %d\n", (int) ptp->type); } diff --git a/erts/emulator/beam/erl_printf_term.c b/erts/emulator/beam/erl_printf_term.c index 267c0b3ff4..2917d58932 100644 --- a/erts/emulator/beam/erl_printf_term.c +++ b/erts/emulator/beam/erl_printf_term.c @@ -467,10 +467,7 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount, } break; case BINARY_DEF: - if (header_is_bin_matchstate(*boxed_val(wobj))) { - PRINT_STRING(res, fn, arg, "#MatchState"); - } - else { + { byte* bytep; Uint bytesize = binary_size_rel(obj,obj_base); Uint bitoffs; @@ -633,6 +630,9 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount, } } break; + case MATCHSTATE_DEF: + PRINT_STRING(res, fn, arg, "#MatchState"); + break; default: PRINT_STRING(res, fn, arg, "<unknown:"); PRINT_POINTER(res, fn, arg, wobj); diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index 7b3d12ce09..4ec98d5cc7 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -353,6 +353,7 @@ struct erts_system_monitor_flags_t erts_system_monitor_flags; /* system performance monitor */ Eterm erts_system_profile; struct erts_system_profile_flags_t erts_system_profile_flags; +int erts_system_profile_ts_type = ERTS_TRACE_FLG_NOW_TIMESTAMP; #if ERTS_MAX_PROCESSES > 0x7fffffff #error "Need to store process_count in another type" @@ -515,7 +516,7 @@ dbg_chk_aux_work_val(erts_aint32_t value) valid |= ERTS_SSI_AUX_WORK_DEBUG_WAIT_COMPLETED; if (~valid & value) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Invalid aux_work value found: 0x%x\n", ~valid & value); } @@ -625,11 +626,6 @@ erts_pre_init_process(void) erts_psd_required_locks[ERTS_PSD_SCHED_ID].set_locks = ERTS_PSD_SCHED_ID_SET_LOCKS; - erts_psd_required_locks[ERTS_PSD_DIST_ENTRY].get_locks - = ERTS_PSD_DIST_ENTRY_GET_LOCKS; - erts_psd_required_locks[ERTS_PSD_DIST_ENTRY].set_locks - = ERTS_PSD_DIST_ENTRY_SET_LOCKS; - erts_psd_required_locks[ERTS_PSD_CALL_TIME_BP].get_locks = ERTS_PSD_CALL_TIME_BP_GET_LOCKS; erts_psd_required_locks[ERTS_PSD_CALL_TIME_BP].set_locks @@ -971,11 +967,25 @@ typedef struct { erts_smp_atomic32_t refc; } ErtsSchedWallTimeReq; +typedef struct { + Process *proc; + Eterm ref; + Eterm ref_heap[REF_THING_SIZE]; + Uint req_sched; + erts_smp_atomic32_t refc; +} ErtsSystemCheckReq; + + #if !HALFWORD_HEAP ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(swtreq, ErtsSchedWallTimeReq, 5, ERTS_ALC_T_SCHED_WTIME_REQ) + +ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(screq, + ErtsSystemCheckReq, + 5, + ERTS_ALC_T_SYS_CHECK_REQ) #else static ERTS_INLINE ErtsSchedWallTimeReq * swtreq_alloc(void) @@ -989,6 +999,19 @@ swtreq_free(ErtsSchedWallTimeReq *ptr) { erts_free(ERTS_ALC_T_SCHED_WTIME_REQ, ptr); } + +static ERTS_INLINE ErtsSystemCheckReq * +screq_alloc(void) +{ + return erts_alloc(ERTS_ALC_T_SYS_CHECK_REQ, + sizeof(ErtsSystemCheckReq)); +} + +static ERTS_INLINE void +screq_free(ErtsSystemCheckReq *ptr) +{ + erts_free(ERTS_ALC_T_SYS_CHECK_REQ, ptr); +} #endif static void @@ -1122,6 +1145,75 @@ erts_sched_wall_time_request(Process *c_p, int set, int enable) return ref; } +static void +reply_system_check(void *vscrp) +{ + ErtsSchedulerData *esdp = erts_get_scheduler_data(); + ErtsSystemCheckReq *scrp = (ErtsSystemCheckReq *) vscrp; + ErtsProcLocks rp_locks = (scrp->req_sched == esdp->no ? ERTS_PROC_LOCK_MAIN : 0); + Process *rp = scrp->proc; + Eterm msg; + Eterm *hp = NULL; + Eterm **hpp; + Uint sz; + ErlOffHeap *ohp = NULL; + ErlHeapFragment *bp = NULL; + + ASSERT(esdp); +#ifdef ERTS_DIRTY_SCHEDULERS + ASSERT(!ERTS_SCHEDULER_IS_DIRTY(esdp)); +#endif + + sz = REF_THING_SIZE; + hp = erts_alloc_message_heap(sz, &bp, &ohp, rp, &rp_locks); + hpp = &hp; + msg = STORE_NC(hpp, ohp, scrp->ref); + + erts_queue_message(rp, &rp_locks, bp, msg, NIL); + + if (scrp->req_sched == esdp->no) + rp_locks &= ~ERTS_PROC_LOCK_MAIN; + + if (rp_locks) + erts_smp_proc_unlock(rp, rp_locks); + + erts_proc_dec_refc(rp); + + if (erts_smp_atomic32_dec_read_nob(&scrp->refc) == 0) + screq_free(vscrp); +} + + +Eterm erts_system_check_request(Process *c_p) { + ErtsSchedulerData *esdp = ERTS_PROC_GET_SCHDATA(c_p); + Eterm ref; + ErtsSystemCheckReq *scrp; + Eterm *hp; + + scrp = screq_alloc(); + ref = erts_make_ref(c_p); + hp = &scrp->ref_heap[0]; + + scrp->proc = c_p; + scrp->ref = STORE_NC(&hp, NULL, ref); + scrp->req_sched = esdp->no; + erts_smp_atomic32_init_nob(&scrp->refc, (erts_aint32_t) erts_no_schedulers); + + erts_proc_add_refc(c_p, (Sint) erts_no_schedulers); + +#ifdef ERTS_SMP + if (erts_no_schedulers > 1) + erts_schedule_multi_misc_aux_work(1, + erts_no_schedulers, + reply_system_check, + (void *) scrp); +#endif + + reply_system_check((void *) scrp); + + return ref; +} + static ERTS_INLINE ErtsProcList * proclist_create(Process *p) { @@ -1216,7 +1308,7 @@ erts_sched_finish_poke(ErtsSchedulerSleepInfo *ssi, erts_aint32_t flags) case 0: break; default: - erl_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error\n", + erts_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error\n", __FILE__, __LINE__); break; } @@ -2200,7 +2292,7 @@ handle_reap_ports(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting) erts_port_release(prt); } if (erts_smp_atomic32_dec_read_nob(&erts_halt_progress) == 0) { - erl_exit_flush_async(erts_halt_code, ""); + erts_flush_async_exit(erts_halt_code, ""); } } return aux_work & ~ERTS_SSI_AUX_WORK_REAP_PORTS; @@ -2244,6 +2336,7 @@ handle_aux_work(ErtsAuxWorkData *awdp, erts_aint32_t orig_aux_work, int waiting) erts_aint32_t aux_work = orig_aux_work; erts_aint32_t ignore = 0; + ASSERT(!awdp->esdp || !ERTS_SCHEDULER_IS_DIRTY(awdp->esdp)); #ifdef ERTS_SMP haw_thr_prgr_current_reset(awdp); #endif @@ -2977,14 +3070,13 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) ErtsMonotonicTime current_time; aux_work = erts_atomic32_read_acqb(&ssi->aux_work); - if (aux_work) { - if (!ERTS_SCHEDULER_IS_DIRTY(esdp) && !thr_prgr_active) { + if (aux_work && !ERTS_SCHEDULER_IS_DIRTY(esdp)) { + if (!thr_prgr_active) { erts_thr_progress_active(esdp, thr_prgr_active = 1); sched_wall_time_change(esdp, 1); } aux_work = handle_aux_work(&esdp->aux_work_data, aux_work, 1); - if (aux_work && !ERTS_SCHEDULER_IS_DIRTY(esdp) - && erts_thr_progress_update(esdp)) + if (aux_work && erts_thr_progress_update(esdp)) erts_thr_progress_leader_update(esdp); } @@ -3136,25 +3228,22 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) #endif aux_work = erts_atomic32_read_acqb(&ssi->aux_work); - if (aux_work) { - if (!ERTS_SCHEDULER_IS_DIRTY(esdp)) { - if (!working) - sched_wall_time_change(esdp, working = 1); + if (aux_work && !ERTS_SCHEDULER_IS_DIRTY(esdp)) { + if (!working) + sched_wall_time_change(esdp, working = 1); #ifdef ERTS_SMP - if (!thr_prgr_active) - erts_thr_progress_active(esdp, thr_prgr_active = 1); + if (!thr_prgr_active) + erts_thr_progress_active(esdp, thr_prgr_active = 1); #endif - } aux_work = handle_aux_work(&esdp->aux_work_data, aux_work, 1); #ifdef ERTS_SMP - if (!ERTS_SCHEDULER_IS_DIRTY(esdp) && aux_work && - erts_thr_progress_update(esdp)) + if (aux_work && erts_thr_progress_update(esdp)) erts_thr_progress_leader_update(esdp); #endif } #ifndef ERTS_SMP - if (rq->len != 0 || rq->misc.start) + if (erts_smp_atomic32_read_dirty(&rq->len) != 0 || rq->misc.start) goto sys_woken; #else flgs = erts_smp_atomic32_read_acqb(&ssi->flags); @@ -3253,7 +3342,7 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) } #ifndef ERTS_SMP - if (rq->len == 0 && !rq->misc.start) + if (erts_smp_atomic32_read_dirty(&rq->len) == 0 && !rq->misc.start) goto sys_aux_work; sys_woken: #else @@ -3722,7 +3811,7 @@ immigrate(ErtsRunQueue *c_rq, ErtsMigrationPath *mp) prio = ERTS_PORT_PRIO_LEVEL; break; default: - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%s:%d:%s(): Invalid immigrate queue mask", __FILE__, __LINE__, __func__); prio = 0; @@ -3746,7 +3835,7 @@ immigrate(ErtsRunQueue *c_rq, ErtsMigrationPath *mp) rq = erts_port_runq(prt); if (rq) { if (rq != c_rq) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%s:%d:%s(): Internal error", __FILE__, __LINE__, __func__); erts_enqueue_port(c_rq, prt); @@ -3937,7 +4026,7 @@ evacuate_run_queue(ErtsRunQueue *rq, prt_rq = erts_port_runq(prt); if (prt_rq) { if (prt_rq != to_rq) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%s:%d:%s() internal error\n", __FILE__, __LINE__, __func__); erts_enqueue_port(to_rq, prt); @@ -4138,7 +4227,7 @@ no_procs: return 0; else { if (prt_rq != rq) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%s:%d:%s() internal error\n", __FILE__, __LINE__, __func__); *rq_lockedp = 1; @@ -4970,7 +5059,7 @@ erts_fprintf(stderr, "--------------------------------\n"); rq->out_of_work_count = 0; (void) ERTS_RUNQ_FLGS_READ_BSET(rq, ERTS_RUNQ_FLGS_MIGRATION_INFO, flags); - rq->max_len = rq->len; + rq->max_len = erts_smp_atomic32_read_dirty(&rq->len); for (pix = 0; pix < ERTS_NO_PRIO_LEVELS; pix++) { ErtsRunQueueInfo *rqi; rqi = (pix == ERTS_PORT_PRIO_LEVEL @@ -5128,7 +5217,7 @@ wakeup_other_check(ErtsRunQueue *rq, Uint32 flags) { int wo_reds = rq->wakeup_other_reds; if (wo_reds) { - int left_len = rq->len - 1; + int left_len = erts_smp_atomic32_read_dirty(&rq->len) - 1; if (left_len < 1) { int wo_reduce = wo_reds << wakeup_other.dec_shift; wo_reduce &= wakeup_other.dec_mask; @@ -5201,7 +5290,7 @@ wakeup_other_check_legacy(ErtsRunQueue *rq, Uint32 flags) { int wo_reds = rq->wakeup_other_reds; if (wo_reds) { - erts_aint32_t len = rq->len; + erts_aint32_t len = erts_smp_atomic32_read_dirty(&rq->len); if (len < 2) { rq->wakeup_other -= ERTS_WAKEUP_OTHER_DEC_LEGACY*wo_reds; if (rq->wakeup_other < 0) @@ -5297,7 +5386,7 @@ runq_supervisor(void *unused) ErtsRunQueue *rq = ERTS_RUNQ_IX(ix); if (ERTS_RUNQ_FLGS_GET(rq) & ERTS_RUNQ_FLG_NONEMPTY) { erts_smp_runq_lock(rq); - if (rq->len != 0) + if (erts_smp_atomic32_read_dirty(&rq->len) != 0) wake_scheduler_on_empty_runq(rq); /* forced wakeup... */ erts_smp_runq_unlock(rq); } @@ -5647,7 +5736,7 @@ erts_init_scheduling(int no_schedulers, int no_schedulers_online } rq->out_of_work_count = 0; rq->max_len = 0; - rq->len = 0; + erts_smp_atomic32_set_nob(&rq->len, 0); rq->wakeup_other = 0; rq->wakeup_other_reds = 0; rq->halt_in_progress = 0; @@ -5799,6 +5888,7 @@ erts_init_scheduling(int no_schedulers, int no_schedulers_online init_misc_aux_work(); #if !HALFWORD_HEAP init_swtreq_alloc(); + init_screq_alloc(); #endif erts_atomic32_init_nob(&debug_wait_completed_count, 0); /* debug only */ @@ -6469,9 +6559,6 @@ suspend_process(Process *c_p, Process *p) if (suspended) { - ASSERT(!(ERTS_PSFLG_RUNNING & state) - || p == erts_get_current_process()); - if (suspended > 0 && erts_system_profile_flags.runnable_procs) { /* 'state' is before our change... */ @@ -6803,18 +6890,19 @@ suspend_scheduler(ErtsSchedulerData *esdp) & ERTS_RUNQ_FLGS_QMASK); aux_work = erts_atomic32_read_acqb(&ssi->aux_work); if (aux_work|qmask) { - if (!ERTS_SCHEDULER_IS_DIRTY(esdp) && !thr_prgr_active) { - erts_thr_progress_active(esdp, thr_prgr_active = 1); - sched_wall_time_change(esdp, 1); + if (!ERTS_SCHEDULER_IS_DIRTY(esdp)) { + if (!thr_prgr_active) { + erts_thr_progress_active(esdp, thr_prgr_active = 1); + sched_wall_time_change(esdp, 1); + } + if (aux_work) + aux_work = handle_aux_work(&esdp->aux_work_data, + aux_work, + 1); + + if (aux_work && erts_thr_progress_update(esdp)) + erts_thr_progress_leader_update(esdp); } - if (aux_work) - aux_work = handle_aux_work(&esdp->aux_work_data, - aux_work, - 1); - - if (!ERTS_SCHEDULER_IS_DIRTY(esdp) && - (aux_work && erts_thr_progress_update(esdp))) - erts_thr_progress_leader_update(esdp); if (qmask) { #ifdef ERTS_DIRTY_SCHEDULERS if (ERTS_SCHEDULER_IS_DIRTY(esdp)) { @@ -7031,17 +7119,18 @@ suspend_scheduler(ErtsSchedulerData *esdp) & ERTS_RUNQ_FLGS_QMASK); aux_work = erts_atomic32_read_acqb(&ssi->aux_work); if (aux_work|qmask) { - if (!ERTS_SCHEDULER_IS_DIRTY(esdp) && !thr_prgr_active) { - erts_thr_progress_active(esdp, thr_prgr_active = 1); - sched_wall_time_change(esdp, 1); + if (!ERTS_SCHEDULER_IS_DIRTY(esdp)) { + if (!thr_prgr_active) { + erts_thr_progress_active(esdp, thr_prgr_active = 1); + sched_wall_time_change(esdp, 1); + } + if (aux_work) + aux_work = handle_aux_work(&esdp->aux_work_data, + aux_work, + 1); + if (aux_work && erts_thr_progress_update(esdp)) + erts_thr_progress_leader_update(esdp); } - if (aux_work) - aux_work = handle_aux_work(&esdp->aux_work_data, - aux_work, - 1); - if (!ERTS_SCHEDULER_IS_DIRTY(esdp) && aux_work && - erts_thr_progress_update(esdp)) - erts_thr_progress_leader_update(esdp); if (qmask) { erts_smp_runq_lock(esdp->run_queue); evacuate_run_queue(esdp->run_queue, &sbp); @@ -7938,11 +8027,19 @@ sched_thread_func(void *vesdp) ErtsThrPrgrCallbacks callbacks; ErtsSchedulerData *esdp = vesdp; Uint no = esdp->no; +#ifdef ERTS_SMP + erts_tse_t *tse; +#endif erts_sched_init_time_sup(esdp); + (void) ERTS_RUNQ_FLGS_SET_NOB(esdp->run_queue, + ERTS_RUNQ_FLG_EXEC); + #ifdef ERTS_SMP - ERTS_SCHED_SLEEP_INFO_IX(no - 1)->event = erts_tse_fetch(); + tse = erts_tse_fetch(); + erts_tse_prepare_timed(tse); + ERTS_SCHED_SLEEP_INFO_IX(no - 1)->event = tse; callbacks.arg = (void *) esdp->ssi; callbacks.wakeup = thr_prgr_wakeup; callbacks.prepare_wait = thr_prgr_prep_wait; @@ -8020,7 +8117,7 @@ sched_thread_func(void *vesdp) process_main(); /* No schedulers should *ever* terminate */ - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Scheduler thread number %beu terminated\n", no); return NULL; @@ -8085,7 +8182,7 @@ sched_dirty_cpu_thread_func(void *vesdp) process_main(); /* No schedulers should *ever* terminate */ - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Dirty CPU scheduler thread number %beu terminated\n", no); return NULL; @@ -8148,7 +8245,7 @@ sched_dirty_io_thread_func(void *vesdp) process_main(); /* No schedulers should *ever* terminate */ - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Dirty I/O scheduler thread number %beu terminated\n", no); return NULL; @@ -8178,12 +8275,12 @@ erts_start_schedulers(void) erts_snprintf(opts.name, 16, "runq_supervisor"); erts_atomic_init_nob(&runq_supervisor_sleeping, 0); if (0 != ethr_event_init(&runq_supervision_event)) - erl_exit(1, "Failed to create run-queue supervision event\n"); + erts_exit(ERTS_ERROR_EXIT, "Failed to create run-queue supervision event\n"); if (0 != ethr_thr_create(&runq_supervisor_tid, runq_supervisor, NULL, &opts)) - erl_exit(1, "Failed to create run-queue supervision thread\n"); + erts_exit(ERTS_ERROR_EXIT, "Failed to create run-queue supervision thread\n"); } #endif @@ -8227,14 +8324,14 @@ erts_start_schedulers(void) erts_snprintf(opts.name, 16, "%d_dirty_cpu_scheduler", ix + 1); res = ethr_thr_create(&esdp->tid,sched_dirty_cpu_thread_func,(void*)esdp,&opts); if (res != 0) - erl_exit(1, "Failed to create dirty cpu scheduler thread %d\n", ix); + erts_exit(ERTS_ERROR_EXIT, "Failed to create dirty cpu scheduler thread %d\n", ix); } for (ix = 0; ix < erts_no_dirty_io_schedulers; ix++) { ErtsSchedulerData *esdp = ERTS_DIRTY_IO_SCHEDULER_IX(ix); erts_snprintf(opts.name, 16, "%d_dirty_io_scheduler", ix + 1); res = ethr_thr_create(&esdp->tid,sched_dirty_io_thread_func,(void*)esdp,&opts); if (res != 0) - erl_exit(1, "Failed to create dirty io scheduler thread %d\n", ix); + erts_exit(ERTS_ERROR_EXIT, "Failed to create dirty io scheduler thread %d\n", ix); } } #endif @@ -8250,10 +8347,10 @@ erts_start_schedulers(void) res = ethr_thr_create(&aux_tid, aux_thread, NULL, &opts); if (res != 0) - erl_exit(1, "Failed to create aux thread\n"); + erts_exit(ERTS_ERROR_EXIT, "Failed to create aux thread\n"); if (actual < 1) - erl_exit(1, + erts_exit(ERTS_ERROR_EXIT, "Failed to create any scheduler-threads: %s (%d)\n", erl_errno_id(res), res); @@ -8408,9 +8505,8 @@ pid2proc_not_running(Process *c_p, ErtsProcLocks c_p_locks, resume_process(rp, rp_locks); } else { - rp = erts_pid2proc(c_p, c_p_locks|ERTS_PROC_LOCK_STATUS, - pid, pid_locks|ERTS_PROC_LOCK_STATUS); + pid, ERTS_PROC_LOCK_STATUS); if (!rp) { c_p->flags &= ~F_P2PNR_RESCHED; @@ -8419,40 +8515,84 @@ pid2proc_not_running(Process *c_p, ErtsProcLocks c_p_locks, ASSERT(!(c_p->flags & F_P2PNR_RESCHED)); - if (suspend) { - if (suspend_process(c_p, rp)) - goto done; - } - else { - if (!((ERTS_PSFLG_RUNNING|ERTS_PSFLG_RUNNING_SYS) - & erts_smp_atomic32_read_acqb(&rp->state))) - goto done; + /* + * Suspend the other process in order to prevent + * it from being selected for normal execution. + * This will however not prevent it from being + * selected for execution of a system task. If + * it is selected for execution of a system task + * we might be blocked for quite a while if the + * try-lock below fails. That is, there is room + * for improvement here... + */ - } + if (!suspend_process(c_p, rp)) { + /* Other process running */ - /* Other process running */ + ASSERT(ERTS_PSFLG_RUNNING + & erts_smp_atomic32_read_nob(&rp->state)); - /* - * If we got pending suspenders and suspend ourselves waiting - * to suspend another process we might deadlock. - * In this case we have to yield, be suspended by - * someone else and then do it all over again. - */ - if (!c_p->pending_suspenders) { - /* Mark rp pending for suspend by c_p */ - add_pend_suspend(rp, c_p->common.id, handle_pend_sync_suspend); - ASSERT(is_nil(c_p->suspendee)); + running: - /* Suspend c_p; when rp is suspended c_p will be resumed. */ - suspend_process(c_p, c_p); - c_p->flags |= F_P2PNR_RESCHED; + /* + * If we got pending suspenders and suspend ourselves waiting + * to suspend another process we might deadlock. + * In this case we have to yield, be suspended by + * someone else and then do it all over again. + */ + if (!c_p->pending_suspenders) { + /* Mark rp pending for suspend by c_p */ + add_pend_suspend(rp, c_p->common.id, handle_pend_sync_suspend); + ASSERT(is_nil(c_p->suspendee)); + + /* Suspend c_p; when rp is suspended c_p will be resumed. */ + suspend_process(c_p, c_p); + c_p->flags |= F_P2PNR_RESCHED; + } + /* Yield (caller is assumed to yield immediately in bif). */ + erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_STATUS); + rp = ERTS_PROC_LOCK_BUSY; + } + else { + ErtsProcLocks need_locks = pid_locks & ~ERTS_PROC_LOCK_STATUS; + if (need_locks && erts_smp_proc_trylock(rp, need_locks) == EBUSY) { + if (ERTS_PSFLG_RUNNING_SYS + & erts_smp_atomic32_read_nob(&rp->state)) { + /* Executing system task... */ + resume_process(rp, ERTS_PROC_LOCK_STATUS); + goto running; + } + erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_STATUS); + /* + * If we are unlucky, the process just got selected for + * execution of a system task. In this case we may be + * blocked here for quite a while... Execution of system + * tasks are fortunately quite rare events. We try to + * avoid this by checking if it is in a state executing + * system tasks (above), but it will not prevent all + * scenarios for a long block here... + */ + rp = erts_pid2proc(c_p, c_p_locks|ERTS_PROC_LOCK_STATUS, + pid, pid_locks|ERTS_PROC_LOCK_STATUS); + if (!rp) + goto done; + } + + /* + * The previous suspend has prevented the process + * from being selected for normal execution regardless + * of locks held or not held on it... + */ + ASSERT(!(ERTS_PSFLG_RUNNING + & erts_smp_atomic32_read_nob(&rp->state))); + + if (!suspend) + resume_process(rp, pid_locks|ERTS_PROC_LOCK_STATUS); } - /* Yield (caller is assumed to yield immediately in bif). */ - erts_smp_proc_unlock(rp, pid_locks|ERTS_PROC_LOCK_STATUS); - rp = ERTS_PROC_LOCK_BUSY; } done: + if (rp && rp != ERTS_PROC_LOCK_BUSY && !(pid_locks & ERTS_PROC_LOCK_STATUS)) erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_STATUS); if (unlock_c_p_status) @@ -8947,24 +9087,39 @@ resume_process_1(BIF_ALIST_1) } Uint -erts_run_queues_len(Uint *qlen) +erts_run_queues_len(Uint *qlen, int atomic_queues_read, int incl_active_sched) { int i = 0; Uint len = 0; - ERTS_ATOMIC_FOREACH_RUNQ(rq, - { - Sint pqlen = 0; - int pix; - for (pix = 0; pix < ERTS_NO_PROC_PRIO_LEVELS; pix++) - pqlen += RUNQ_READ_LEN(&rq->procs.prio_info[pix].len); + if (atomic_queues_read) + ERTS_ATOMIC_FOREACH_RUNQ(rq, + { + Sint rq_len = (Sint) erts_smp_atomic32_read_dirty(&rq->len); + ASSERT(rq_len >= 0); + if (incl_active_sched + && (ERTS_RUNQ_FLGS_GET_NOB(rq) & ERTS_RUNQ_FLG_EXEC)) { + rq_len++; + } + if (qlen) + qlen[i++] = rq_len; + len += (Uint) rq_len; + } + ); + else { + for (i = 0; i < erts_no_run_queues; i++) { + ErtsRunQueue *rq = ERTS_RUNQ_IX(i); + Sint rq_len = (Sint) erts_smp_atomic32_read_nob(&rq->len); + ASSERT(rq_len >= 0); + if (incl_active_sched + && (ERTS_RUNQ_FLGS_GET_NOB(rq) & ERTS_RUNQ_FLG_EXEC)) { + rq_len++; + } + if (qlen) + qlen[i] = rq_len; + len += (Uint) rq_len; + } - if (pqlen < 0) - pqlen = 0; - if (qlen) - qlen[i++] = pqlen; - len += pqlen; } - ); return len; } @@ -9177,6 +9332,10 @@ erts_set_process_priority(Process *p, Eterm value) a = erts_smp_atomic32_cmpxchg_mb(&p->state, n, e); } while (a != e); + + if (slocked) + erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS); + } switch (oprio) { @@ -9387,8 +9546,10 @@ Process *schedule(Process *p, int calls) if (flags & (ERTS_RUNQ_FLG_CHK_CPU_BIND|ERTS_RUNQ_FLG_SUSPENDED)) { if (flags & ERTS_RUNQ_FLG_SUSPENDED) { + (void) ERTS_RUNQ_FLGS_UNSET_NOB(rq, ERTS_RUNQ_FLG_EXEC); suspend_scheduler(esdp); - flags = ERTS_RUNQ_FLGS_GET_NOB(rq); + flags = ERTS_RUNQ_FLGS_SET_NOB(rq, ERTS_RUNQ_FLG_EXEC); + flags |= ERTS_RUNQ_FLG_EXEC; } if (flags & ERTS_RUNQ_FLG_CHK_CPU_BIND) { flags = ERTS_RUNQ_FLGS_UNSET(rq, ERTS_RUNQ_FLG_CHK_CPU_BIND); @@ -9403,10 +9564,9 @@ Process *schedule(Process *p, int calls) suspend_scheduler(esdp); #endif - { + if (!ERTS_SCHEDULER_IS_DIRTY(esdp)) { erts_aint32_t aux_work; - int leader_update = ERTS_SCHEDULER_IS_DIRTY(esdp) ? 0 - : erts_thr_progress_update(esdp); + int leader_update = erts_thr_progress_update(esdp); aux_work = erts_atomic32_read_acqb(&esdp->ssi->aux_work); if (aux_work | leader_update | ERTS_SCHED_FAIR) { erts_smp_runq_unlock(rq); @@ -9419,8 +9579,7 @@ Process *schedule(Process *p, int calls) erts_smp_runq_lock(rq); } - ERTS_SMP_LC_ASSERT(ERTS_SCHEDULER_IS_DIRTY(esdp) - || !erts_thr_progress_is_blocking()); + ERTS_SMP_LC_ASSERT(!erts_thr_progress_is_blocking()); } ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq)); @@ -9479,7 +9638,10 @@ Process *schedule(Process *p, int calls) } #endif + (void) ERTS_RUNQ_FLGS_UNSET(rq, ERTS_RUNQ_FLG_EXEC); scheduler_wait(&fcalls, esdp, rq); + flags = ERTS_RUNQ_FLGS_SET_NOB(rq, ERTS_RUNQ_FLG_EXEC); + flags |= ERTS_RUNQ_FLG_EXEC; #ifdef ERTS_SMP non_empty_runq(rq); @@ -9645,12 +9807,14 @@ Process *schedule(Process *p, int calls) | ERTS_PSFLG_PENDING_EXIT | ERTS_PSFLG_ACTIVE_SYS)) == ERTS_PSFLG_SUSPENDED)) { - if (state & ERTS_PSFLG_FREE) - erts_proc_dec_refc(p); if (proxy_p) { free_proxy_proc(proxy_p); proxy_p = NULL; } + else if (state & ERTS_PSFLG_FREE) { + /* free and not queued by proxy */ + erts_proc_dec_refc(p); + } goto pick_next_process; } state = new; @@ -9674,6 +9838,8 @@ Process *schedule(Process *p, int calls) erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS); + state = erts_smp_atomic32_read_nob(&p->state); + if (erts_sched_stat.enabled) { int prio; UWord old = ERTS_PROC_SCHED_ID(p, @@ -11409,6 +11575,22 @@ set_proc_exiting(Process *p, KILL_CATCHES(p); p->i = (BeamInstr *) beam_exit; +#ifndef ERTS_SMP + if (state & (ERTS_PSFLG_RUNNING|ERTS_PSFLG_RUNNING_SYS)) { + /* + * I non smp case: + * + * Currently executing process might be sent an exit + * signal if it is traced by a port that it also is + * linked to, and the port terminates during the + * trace. In this case we want schedule out the + * process as quickly as possible in order to detect + * the event as fast as possible. + */ + ERTS_VBUMP_ALL_REDS(p); + } +#endif + if (enqueue) add2runq(enqueue > 0 ? p : make_proxy_proc(NULL, p, enq_prio), state, @@ -11506,10 +11688,14 @@ save_pending_exiter(Process *p) { ErtsProcList *plp; ErtsRunQueue *rq; + ErtsSchedulerData *esdp = erts_get_scheduler_data(); ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_STATUS & erts_proc_lc_my_proc_locks(p)); - rq = erts_get_runq_current(NULL); + if (!esdp) + rq = RUNQ_READ_RQ(&p->run_queue); + else + rq = esdp->run_queue; plp = proclist_create(p); @@ -11526,6 +11712,7 @@ save_pending_exiter(Process *p) else #endif wake_scheduler(rq); + } #endif @@ -11714,23 +11901,21 @@ send_exit_signal(Process *c_p, /* current process if and only if (need_locks && erts_smp_proc_trylock(rp, need_locks) == EBUSY) { /* ... but we havn't got all locks on it ... */ - save_pending_exiter(rp); + save_pending_exiter(rp); /* * The pending exit will be discovered when next * process is scheduled in */ - goto set_pending_exit; - } - else { - /* ...and we have all locks on it... */ - *rp_locks = ERTS_PROC_LOCKS_ALL; - set_proc_exiting(rp, - state, - (is_immed(rsn) - ? rsn - : copy_object(rsn, rp)), - NULL); + goto set_pending_exit; } + /* ...and we have all locks on it... */ + *rp_locks = ERTS_PROC_LOCKS_ALL; + set_proc_exiting(rp, + state, + (is_immed(rsn) + ? rsn + : copy_object(rsn, rp)), + NULL); } else { /* Process running... */ @@ -12069,7 +12254,7 @@ static void doit_exit_link(ErtsLink *lnk, void *vpcontext) break; default: - erl_exit(1, "bad type in link list\n"); + erts_exit(ERTS_ERROR_EXIT, "bad type in link list\n"); break; } erts_destroy_link(lnk); @@ -12110,7 +12295,8 @@ erts_do_exit_process(Process* p, Eterm reason) #endif if (p->static_flags & ERTS_STC_FLG_SYSTEM_PROC) - erl_exit(1, "System process %T terminated: %T\n", p->common.id, reason); + erts_exit(ERTS_DUMP_EXIT, "System process %T terminated: %T\n", + p->common.id, reason); #ifdef ERTS_SMP ERTS_SMP_CHK_HAVE_ONLY_MAIN_PROC_LOCK(p); @@ -12227,7 +12413,7 @@ erts_continue_exit_process(Process *p) break; case ERTS_SCHDLR_SSPND_EINVAL: default: - erl_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error: %d\n", + erts_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error: %d\n", __FILE__, __LINE__, (int) ssr); } } @@ -12344,9 +12530,7 @@ erts_continue_exit_process(Process *p) erts_proc_dec_refc(p); } - dep = ((p->flags & F_DISTRIBUTION) - ? ERTS_PROC_SET_DIST_ENTRY(p, ERTS_PROC_LOCKS_ALL, NULL) - : NULL); + dep = (p->flags & F_DISTRIBUTION) ? erts_this_dist_entry : NULL; scb = ERTS_PROC_SET_SAVED_CALLS_BUF(p, ERTS_PROC_LOCKS_ALL, NULL); pbt = ERTS_PROC_SET_CALL_TIME(p, ERTS_PROC_LOCKS_ALL, NULL); nif_export = ERTS_PROC_SET_NIF_TRAP_EXPORT(p, ERTS_PROC_LOCKS_ALL, NULL); @@ -12358,8 +12542,6 @@ erts_continue_exit_process(Process *p) if (dep) { erts_do_net_exits(dep, reason); - if(dep) - erts_deref_dist_entry(dep); } /* @@ -12728,10 +12910,10 @@ erts_print_scheduler_info(int to, void *to_arg, ErtsSchedulerData *esdp) { * The same global atomic is used as refcount. * * A BIF that calls this should make sure to schedule out to never come back: - * erl_halt((int)(- code)); + * erts_halt(code); * ERTS_BIF_YIELD1(bif_export[BIF_erlang_halt_1], BIF_P, NIL); */ -void erl_halt(int code) +void erts_halt(int code) { if (-1 == erts_smp_atomic32_cmpxchg_acqb(&erts_halt_progress, erts_no_schedulers, diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h index 20ffe7ea7c..b536426b0f 100644 --- a/erts/emulator/beam/erl_process.h +++ b/erts/emulator/beam/erl_process.h @@ -60,6 +60,9 @@ typedef struct process Process; #include "erl_mseg.h" #include "erl_async.h" #include "erl_gc.h" +#define ERTS_ONLY_INCLUDE_TRACE_FLAGS +#include "erl_trace.h" +#undef ERTS_ONLY_INCLUDE_TRACE_FLAGS #ifdef HIPE #include "hipe_process.h" @@ -170,8 +173,10 @@ extern int erts_sched_thread_suggested_stack_size; (((Uint32) 1) << (ERTS_RUNQ_FLG_BASE2 + 5)) #define ERTS_RUNQ_FLG_PROTECTED \ (((Uint32) 1) << (ERTS_RUNQ_FLG_BASE2 + 6)) +#define ERTS_RUNQ_FLG_EXEC \ + (((Uint32) 1) << (ERTS_RUNQ_FLG_BASE2 + 7)) -#define ERTS_RUNQ_FLG_MAX (ERTS_RUNQ_FLG_BASE2 + 7) +#define ERTS_RUNQ_FLG_MAX (ERTS_RUNQ_FLG_BASE2 + 8) #define ERTS_RUNQ_FLGS_MIGRATION_QMASKS \ (ERTS_RUNQ_FLGS_EMIGRATE_QMASK \ @@ -215,6 +220,9 @@ extern int erts_sched_thread_suggested_stack_size; #define ERTS_RUNQ_FLGS_SET(RQ, FLGS) \ ((Uint32) erts_smp_atomic32_read_bor_relb(&(RQ)->flags, \ (erts_aint32_t) (FLGS))) +#define ERTS_RUNQ_FLGS_SET_NOB(RQ, FLGS) \ + ((Uint32) erts_smp_atomic32_read_bor_nob(&(RQ)->flags, \ + (erts_aint32_t) (FLGS))) #define ERTS_RUNQ_FLGS_BSET(RQ, MSK, FLGS) \ ((Uint32) erts_smp_atomic32_read_bset_relb(&(RQ)->flags, \ (erts_aint32_t) (MSK), \ @@ -222,6 +230,9 @@ extern int erts_sched_thread_suggested_stack_size; #define ERTS_RUNQ_FLGS_UNSET(RQ, FLGS) \ ((Uint32) erts_smp_atomic32_read_band_relb(&(RQ)->flags, \ (erts_aint32_t) ~(FLGS))) +#define ERTS_RUNQ_FLGS_UNSET_NOB(RQ, FLGS) \ + ((Uint32) erts_smp_atomic32_read_band_nob(&(RQ)->flags, \ + (erts_aint32_t) ~(FLGS))) #define ERTS_RUNQ_FLGS_GET(RQ) \ ((Uint32) erts_smp_atomic32_read_acqb(&(RQ)->flags)) #define ERTS_RUNQ_FLGS_GET_NOB(RQ) \ @@ -467,7 +478,7 @@ struct ErtsRunQueue_ { int full_reds_history[ERTS_FULL_REDS_HISTORY_SIZE]; int out_of_work_count; erts_aint32_t max_len; - erts_aint32_t len; + erts_smp_atomic32_t len; int wakeup_other; int wakeup_other_reds; int halt_in_progress; @@ -607,7 +618,7 @@ typedef enum { typedef union { struct { ErtsDirtySchedulerType type: 1; - unsigned num: 31; + Uint num: sizeof(Uint)*8 - 1; } s; Uint no; } ErtsDirtySchedId; @@ -728,7 +739,19 @@ erts_smp_inc_runq_len(ErtsRunQueue *rq, ErtsRunQueueInfo *rqi, int prio) ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq)); - len = erts_smp_atomic32_read_nob(&rqi->len); + len = erts_smp_atomic32_read_dirty(&rq->len); + +#ifdef ERTS_SMP + if (len == 0) + erts_non_empty_runq(rq); +#endif + len++; + if (rq->max_len < len) + rq->max_len = len; + ASSERT(len > 0); + erts_smp_atomic32_set_nob(&rq->len, len); + + len = erts_smp_atomic32_read_dirty(&rqi->len); ASSERT(len >= 0); if (len == 0) { ASSERT((erts_smp_atomic32_read_nob(&rq->flags) @@ -741,15 +764,6 @@ erts_smp_inc_runq_len(ErtsRunQueue *rq, ErtsRunQueueInfo *rqi, int prio) rqi->max_len = len; erts_smp_atomic32_set_relb(&rqi->len, len); - -#ifdef ERTS_SMP - if (rq->len == 0) - erts_non_empty_runq(rq); -#endif - rq->len++; - if (rq->max_len < rq->len) - rq->max_len = len; - ASSERT(rq->len > 0); } ERTS_GLB_INLINE void @@ -759,7 +773,12 @@ erts_smp_dec_runq_len(ErtsRunQueue *rq, ErtsRunQueueInfo *rqi, int prio) ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq)); - len = erts_smp_atomic32_read_nob(&rqi->len); + len = erts_smp_atomic32_read_dirty(&rq->len); + len--; + ASSERT(len >= 0); + erts_smp_atomic32_set_nob(&rq->len, len); + + len = erts_smp_atomic32_read_dirty(&rqi->len); len--; ASSERT(len >= 0); if (len == 0) { @@ -770,8 +789,6 @@ erts_smp_dec_runq_len(ErtsRunQueue *rq, ErtsRunQueueInfo *rqi, int prio) } erts_smp_atomic32_set_relb(&rqi->len, len); - rq->len--; - ASSERT(rq->len >= 0); } ERTS_GLB_INLINE void @@ -781,7 +798,7 @@ erts_smp_reset_max_len(ErtsRunQueue *rq, ErtsRunQueueInfo *rqi) ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq)); - len = erts_smp_atomic32_read_nob(&rqi->len); + len = erts_smp_atomic32_read_dirty(&rqi->len); ASSERT(rqi->max_len >= len); rqi->max_len = len; } @@ -801,12 +818,11 @@ erts_smp_reset_max_len(ErtsRunQueue *rq, ErtsRunQueueInfo *rqi) #define ERTS_PSD_ERROR_HANDLER 0 #define ERTS_PSD_SAVED_CALLS_BUF 1 #define ERTS_PSD_SCHED_ID 2 -#define ERTS_PSD_DIST_ENTRY 3 -#define ERTS_PSD_CALL_TIME_BP 4 -#define ERTS_PSD_DELAYED_GC_TASK_QS 5 -#define ERTS_PSD_NIF_TRAP_EXPORT 6 +#define ERTS_PSD_CALL_TIME_BP 3 +#define ERTS_PSD_DELAYED_GC_TASK_QS 4 +#define ERTS_PSD_NIF_TRAP_EXPORT 5 -#define ERTS_PSD_SIZE 7 +#define ERTS_PSD_SIZE 6 typedef struct { void *data[ERTS_PSD_SIZE]; @@ -824,9 +840,6 @@ typedef struct { #define ERTS_PSD_SCHED_ID_GET_LOCKS ERTS_PROC_LOCK_STATUS #define ERTS_PSD_SCHED_ID_SET_LOCKS ERTS_PROC_LOCK_STATUS -#define ERTS_PSD_DIST_ENTRY_GET_LOCKS ERTS_PROC_LOCK_MAIN -#define ERTS_PSD_DIST_ENTRY_SET_LOCKS ERTS_PROC_LOCK_MAIN - #define ERTS_PSD_CALL_TIME_BP_GET_LOCKS ERTS_PROC_LOCK_MAIN #define ERTS_PSD_CALL_TIME_BP_SET_LOCKS ERTS_PROC_LOCK_MAIN @@ -1174,7 +1187,7 @@ void erts_check_for_holes(Process* p); #define ERTS_PSFLGS_GET_USR_PRIO(PSFLGS) \ (((PSFLGS) >> ERTS_PSFLGS_USR_PRIO_OFFSET) & ERTS_PSFLGS_PRIO_MASK) #define ERTS_PSFLGS_GET_PRQ_PRIO(PSFLGS) \ - (((PSFLGS) >> ERTS_PSFLGS_USR_PRIO_OFFSET) & ERTS_PSFLGS_PRIO_MASK) + (((PSFLGS) >> ERTS_PSFLGS_PRQ_PRIO_OFFSET) & ERTS_PSFLGS_PRIO_MASK) /* * Static flags that do not change after process creation. @@ -1282,6 +1295,7 @@ struct erts_system_profile_flags_t { unsigned int exclusive : 1; }; extern struct erts_system_profile_flags_t erts_system_profile_flags; +extern int erts_system_profile_ts_type; /* process flags */ #define F_HIBERNATE_SCHED (1 << 0) /* Schedule out after hibernate op */ @@ -1297,61 +1311,90 @@ extern struct erts_system_profile_flags_t erts_system_profile_flags; #define F_FORCE_GC (1 << 10) /* Force gc at process in-scheduling */ #define F_DISABLE_GC (1 << 11) /* Disable GC */ +#define ERTS_TRACE_FLAGS_TS_TYPE_SHIFT 0 + +#define F_TRACE_FLAG(N) (1 << (ERTS_TRACE_TS_TYPE_BITS + (N))) + /* process trace_flags */ -#define F_SENSITIVE (1 << 0) -#define F_TRACE_SEND (1 << 1) -#define F_TRACE_RECEIVE (1 << 2) -#define F_TRACE_SOS (1 << 3) /* Set on spawn */ -#define F_TRACE_SOS1 (1 << 4) /* Set on first spawn */ -#define F_TRACE_SOL (1 << 5) /* Set on link */ -#define F_TRACE_SOL1 (1 << 6) /* Set on first link */ -#define F_TRACE_CALLS (1 << 7) -#define F_TIMESTAMP (1 << 8) -#define F_TRACE_PROCS (1 << 9) -#define F_TRACE_FIRST_CHILD (1 << 10) -#define F_TRACE_SCHED (1 << 11) -#define F_TRACE_GC (1 << 12) -#define F_TRACE_ARITY_ONLY (1 << 13) -#define F_TRACE_RETURN_TO (1 << 14) /* Return_to trace when breakpoint tracing */ -#define F_TRACE_SILENT (1 << 15) /* No call trace msg suppress */ -#define F_TRACER (1 << 16) /* May be (has been) tracer */ -#define F_EXCEPTION_TRACE (1 << 17) /* May have exception trace on stack */ + +#define F_NOW_TS (ERTS_TRACE_FLG_NOW_TIMESTAMP \ + << ERTS_TRACE_FLAGS_TS_TYPE_SHIFT) +#define F_STRICT_MON_TS (ERTS_TRACE_FLG_STRICT_MONOTONIC_TIMESTAMP \ + << ERTS_TRACE_FLAGS_TS_TYPE_SHIFT) +#define F_MON_TS (ERTS_TRACE_FLG_MONOTONIC_TIMESTAMP \ + << ERTS_TRACE_FLAGS_TS_TYPE_SHIFT) +#define F_SENSITIVE F_TRACE_FLAG(0) +#define F_TRACE_SEND F_TRACE_FLAG(1) +#define F_TRACE_RECEIVE F_TRACE_FLAG(2) +#define F_TRACE_SOS F_TRACE_FLAG(3) /* Set on spawn */ +#define F_TRACE_SOS1 F_TRACE_FLAG(4) /* Set on first spawn */ +#define F_TRACE_SOL F_TRACE_FLAG(5) /* Set on link */ +#define F_TRACE_SOL1 F_TRACE_FLAG(6) /* Set on first link */ +#define F_TRACE_CALLS F_TRACE_FLAG(7) +#define F_TRACE_PROCS F_TRACE_FLAG(8) +#define F_TRACE_FIRST_CHILD F_TRACE_FLAG(9) +#define F_TRACE_SCHED F_TRACE_FLAG(10) +#define F_TRACE_GC F_TRACE_FLAG(11) +#define F_TRACE_ARITY_ONLY F_TRACE_FLAG(12) +#define F_TRACE_RETURN_TO F_TRACE_FLAG(13) /* Return_to trace when breakpoint tracing */ +#define F_TRACE_SILENT F_TRACE_FLAG(14) /* No call trace msg suppress */ +#define F_TRACER F_TRACE_FLAG(15) /* May be (has been) tracer */ +#define F_EXCEPTION_TRACE F_TRACE_FLAG(16) /* May have exception trace on stack */ /* port trace flags, currently the same as process trace flags */ -#define F_TRACE_SCHED_PORTS (1 << 18) /* Trace of port scheduling */ -#define F_TRACE_SCHED_PROCS (1 << 19) /* With virtual scheduling */ -#define F_TRACE_PORTS (1 << 20) /* Ports equivalent to F_TRACE_PROCS */ -#define F_TRACE_SCHED_NO (1 << 21) /* Trace with scheduler id */ -#define F_TRACE_SCHED_EXIT (1 << 22) +#define F_TRACE_SCHED_PORTS F_TRACE_FLAG(17) /* Trace of port scheduling */ +#define F_TRACE_SCHED_PROCS F_TRACE_FLAG(18) /* With virtual scheduling */ +#define F_TRACE_PORTS F_TRACE_FLAG(19) /* Ports equivalent to F_TRACE_PROCS */ +#define F_TRACE_SCHED_NO F_TRACE_FLAG(20) /* Trace with scheduler id */ +#define F_TRACE_SCHED_EXIT F_TRACE_FLAG(21) -#define F_NUM_FLAGS 23 +#define F_NUM_FLAGS (ERTS_TRACE_TS_TYPE_BITS + 22) #ifdef DEBUG # define F_INITIAL_TRACE_FLAGS (5 << F_NUM_FLAGS) #else # define F_INITIAL_TRACE_FLAGS 0 #endif +/* F_TIMESTAMP_MASK is a bit-field of all all timestamp types */ +#define F_TIMESTAMP_MASK \ + (ERTS_TRACE_TS_TYPE_MASK << ERTS_TRACE_FLAGS_TS_TYPE_SHIFT) + #define TRACEE_FLAGS ( F_TRACE_PROCS | F_TRACE_CALLS \ | F_TRACE_SOS | F_TRACE_SOS1| F_TRACE_RECEIVE \ | F_TRACE_SOL | F_TRACE_SOL1 | F_TRACE_SEND \ - | F_TRACE_SCHED | F_TIMESTAMP | F_TRACE_GC \ + | F_TRACE_SCHED | F_TIMESTAMP_MASK | F_TRACE_GC \ | F_TRACE_ARITY_ONLY | F_TRACE_RETURN_TO \ | F_TRACE_SILENT | F_TRACE_SCHED_PROCS | F_TRACE_PORTS \ | F_TRACE_SCHED_PORTS | F_TRACE_SCHED_NO \ | F_TRACE_SCHED_EXIT) #define ERTS_TRACEE_MODIFIER_FLAGS \ - (F_TRACE_SILENT | F_TIMESTAMP | F_TRACE_SCHED_NO) + (F_TRACE_SILENT | F_TIMESTAMP_MASK | F_TRACE_SCHED_NO) #define ERTS_PORT_TRACEE_FLAGS \ (ERTS_TRACEE_MODIFIER_FLAGS | F_TRACE_PORTS | F_TRACE_SCHED_PORTS) #define ERTS_PROC_TRACEE_FLAGS \ ((TRACEE_FLAGS & ~ERTS_PORT_TRACEE_FLAGS) | ERTS_TRACEE_MODIFIER_FLAGS) +#define SEQ_TRACE_FLAG(N) (1 << (ERTS_TRACE_TS_TYPE_BITS + (N))) + /* Sequential trace flags */ + +/* SEQ_TRACE_TIMESTAMP_MASK is a bit-field */ +#define SEQ_TRACE_TIMESTAMP_MASK \ + (ERTS_TRACE_TS_TYPE_MASK << ERTS_SEQ_TRACE_FLAGS_TS_TYPE_SHIFT) + #define SEQ_TRACE_SEND (1 << 0) #define SEQ_TRACE_RECEIVE (1 << 1) #define SEQ_TRACE_PRINT (1 << 2) -#define SEQ_TRACE_TIMESTAMP (1 << 3) + +#define ERTS_SEQ_TRACE_FLAGS_TS_TYPE_SHIFT 3 + +#define SEQ_TRACE_NOW_TS (ERTS_TRACE_FLG_NOW_TIMESTAMP \ + << ERTS_SEQ_TRACE_FLAGS_TS_TYPE_SHIFT) +#define SEQ_TRACE_STRICT_MON_TS (ERTS_TRACE_FLG_STRICT_MONOTONIC_TIMESTAMP \ + << ERTS_SEQ_TRACE_FLAGS_TS_TYPE_SHIFT) +#define SEQ_TRACE_MON_TS (ERTS_TRACE_FLG_MONOTONIC_TIMESTAMP \ + << ERTS_SEQ_TRACE_FLAGS_TS_TYPE_SHIFT) #ifdef USE_VM_PROBES #define DT_UTAG_PERMANENT (1 << 0) @@ -1440,6 +1483,7 @@ void erts_init_scheduling(int, int int erts_set_gc_state(Process *c_p, int enable); Eterm erts_sched_wall_time_request(Process *c_p, int set, int enable); +Eterm erts_system_check_request(Process *c_p); Eterm erts_gc_info_request(Process *c_p); Uint64 erts_get_proc_interval(void); Uint64 erts_ensure_later_proc_interval(Uint64); @@ -1682,7 +1726,7 @@ void erts_sched_notify_check_cpu_bind(void); Uint erts_active_schedulers(void); void erts_init_process(int, int, int); Eterm erts_process_status(Process *, ErtsProcLocks, Process *, Eterm); -Uint erts_run_queues_len(Uint *); +Uint erts_run_queues_len(Uint *, int, int); void erts_add_to_runq(Process *); Eterm erts_bound_schedulers_term(Process *c_p); Eterm erts_get_cpu_topology_term(Process *c_p, Eterm which); @@ -1887,11 +1931,6 @@ erts_psd_set(Process *p, ErtsProcLocks plocks, int ix, void *data) #define ERTS_PROC_SCHED_ID(P, L, ID) \ ((UWord) erts_psd_set((P), (L), ERTS_PSD_SCHED_ID, (void *) (ID))) -#define ERTS_PROC_GET_DIST_ENTRY(P) \ - ((DistEntry *) erts_psd_get((P), ERTS_PSD_DIST_ENTRY)) -#define ERTS_PROC_SET_DIST_ENTRY(P, L, D) \ - ((DistEntry *) erts_psd_set((P), (L), ERTS_PSD_DIST_ENTRY, (void *) (D))) - #define ERTS_PROC_GET_SAVED_CALLS_BUF(P) \ ((struct saved_calls *) erts_psd_get((P), ERTS_PSD_SAVED_CALLS_BUF)) #define ERTS_PROC_SET_SAVED_CALLS_BUF(P, L, SCB) \ @@ -2312,6 +2351,6 @@ erts_sched_poke(ErtsSchedulerSleepInfo *ssi) #endif -void erl_halt(int code); +void erts_halt(int code); extern erts_smp_atomic32_t erts_halt_progress; extern int erts_halt_code; diff --git a/erts/emulator/beam/erl_process_dict.c b/erts/emulator/beam/erl_process_dict.c index 8606371bdf..3253ee6b70 100644 --- a/erts/emulator/beam/erl_process_dict.c +++ b/erts/emulator/beam/erl_process_dict.c @@ -374,7 +374,7 @@ static void pd_hash_erase(Process *p, Eterm id, Eterm *ret) "display term found in line %d:\n" "%T\n", p->common.id, __LINE__, old); #endif - erl_exit(1, "Damaged process dictionary found during erase/1."); + erts_exit(ERTS_ERROR_EXIT, "Damaged process dictionary found during erase/1."); } if ((range = HASH_RANGE(p->dictionary)) > INITIAL_SIZE && range / 2 > (p->dictionary->numElements)) { @@ -419,7 +419,7 @@ Eterm erts_pd_hash_get(Process *p, Eterm id) "display term found in line %d:\n" "%T\n", p->common.id, __LINE__, tmp); #endif - erl_exit(1, "Damaged process dictionary found during get/1."); + erts_exit(ERTS_ERROR_EXIT, "Damaged process dictionary found during get/1."); } return am_undefined; } @@ -670,7 +670,7 @@ static Eterm pd_hash_put(Process *p, Eterm id, Eterm value) "%T\n", p->common.id, __LINE__, old); #endif - erl_exit(1, "Damaged process dictionary found during put/2."); + erts_exit(ERTS_ERROR_EXIT, "Damaged process dictionary found during put/2."); } if (HASH_RANGE(p->dictionary) <= p->dictionary->numElements) { grow(p); @@ -1024,7 +1024,7 @@ static void pd_check(ProcDict *pd) } continue; } else { - erl_exit(1, + erts_exit(ERTS_ERROR_EXIT, "Found tag 0x%08x in process dictionary at position %d", (unsigned long) t, (int) i); } diff --git a/erts/emulator/beam/erl_process_lock.h b/erts/emulator/beam/erl_process_lock.h index 788348e613..9c59301086 100644 --- a/erts/emulator/beam/erl_process_lock.h +++ b/erts/emulator/beam/erl_process_lock.h @@ -523,6 +523,10 @@ erts_smp_proc_lock__(Process *p, ERTS_LC_ASSERT((locks & ~ERTS_PROC_LOCKS_ALL) == 0); +#ifdef ERTS_ENABLE_LOCK_CHECK + erts_proc_lc_lock(p, locks, file, line); +#endif + old_lflgs = erts_smp_proc_raw_trylock__(p, locks); if (old_lflgs != 0) { @@ -544,9 +548,6 @@ erts_smp_proc_lock__(Process *p, #ifdef ERTS_ENABLE_LOCK_COUNT erts_lcnt_proc_lock_post_x(&(p->lock), locks, file, line); #endif -#ifdef ERTS_ENABLE_LOCK_CHECK - erts_proc_lc_lock(p, locks, file, line); -#endif #ifdef ERTS_PROC_LOCK_DEBUG erts_proc_lock_op_debug(p, locks, 1); @@ -854,9 +855,6 @@ ERTS_GLB_INLINE void erts_proc_dec_refc(Process *p) #endif if (!referred) { ASSERT(ERTS_PROC_IS_EXITING(p)); - ASSERT(ERTS_AINT_NULL - == erts_ptab_pix2intptr_ddrb(&erts_proc, - internal_pid_index(p->common.id))); erts_free_proc(p); } } @@ -872,9 +870,6 @@ ERTS_GLB_INLINE void erts_proc_add_refc(Process *p, Sint add_refc) #endif if (!referred) { ASSERT(ERTS_PROC_IS_EXITING(p)); - ASSERT(ERTS_AINT_NULL - == erts_ptab_pix2intptr_ddrb(&erts_proc, - internal_pid_index(p->common.id))); erts_free_proc(p); } } diff --git a/erts/emulator/beam/erl_ptab.c b/erts/emulator/beam/erl_ptab.c index f7997df051..9ed175fe01 100644 --- a/erts/emulator/beam/erl_ptab.c +++ b/erts/emulator/beam/erl_ptab.c @@ -1255,7 +1255,7 @@ ptab_list_bif_engine(Process *c_p, Eterm *res_accp, Binary *mbp) return 1; default: - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%s:%d:ptab_list_bif_engine(): Invalid state: %d\n", __FILE__, __LINE__, (int) ptlbdp->state); } diff --git a/erts/emulator/beam/erl_term.c b/erts/emulator/beam/erl_term.c index 89459fb278..bae3385d3f 100644 --- a/erts/emulator/beam/erl_term.c +++ b/erts/emulator/beam/erl_term.c @@ -41,7 +41,7 @@ et_abort(const char *expr, const char *file, unsigned line) * Prevent infinite loop. */ have_been_called = 1; - erl_exit(1, "TYPE ASSERTION FAILED, file %s, line %u: %s\n", file, line, expr); + erts_exit(ERTS_ERROR_EXIT, "TYPE ASSERTION FAILED, file %s, line %u: %s\n", file, line, expr); } #else erts_fprintf(stderr, "TYPE ASSERTION FAILED, file %s, line %u: %s\n", file, line, expr); @@ -91,6 +91,7 @@ unsigned tag_val_def(Wterm x) case (_TAG_HEADER_REFC_BIN >> _TAG_PRIMARY_SIZE): return BINARY_DEF; case (_TAG_HEADER_HEAP_BIN >> _TAG_PRIMARY_SIZE): return BINARY_DEF; case (_TAG_HEADER_SUB_BIN >> _TAG_PRIMARY_SIZE): return BINARY_DEF; + case (_TAG_HEADER_BIN_MATCHSTATE >> _TAG_PRIMARY_SIZE): return MATCHSTATE_DEF; } break; diff --git a/erts/emulator/beam/erl_term.h b/erts/emulator/beam/erl_term.h index 90e35151b0..d5e91d80d9 100644 --- a/erts/emulator/beam/erl_term.h +++ b/erts/emulator/beam/erl_term.h @@ -1136,8 +1136,9 @@ _ET_DECLARE_CHECKED(Uint,y_reg_index,Uint) #define FLOAT_DEF 0xe #define BIG_DEF 0xf #define SMALL_DEF 0x10 +#define MATCHSTATE_DEF 0x11 /* not a "real" term */ -#define FIRST_VACANT_TAG_DEF 0x11 +#define FIRST_VACANT_TAG_DEF 0x12 #if ET_DEBUG extern unsigned tag_val_def_debug(Wterm, const char*, unsigned); diff --git a/erts/emulator/beam/erl_thr_progress.c b/erts/emulator/beam/erl_thr_progress.c index 7148b756e7..7b06fd840f 100644 --- a/erts/emulator/beam/erl_thr_progress.c +++ b/erts/emulator/beam/erl_thr_progress.c @@ -502,7 +502,7 @@ erts_thr_progress_register_unmanaged_thread(ErtsThrPrgrCallbacks *callbacks) if (tpd) { if (!tpd->is_temporary) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%s:%d:%s(): Double register of thread\n", __FILE__, __LINE__, __func__); is_blocking = tpd->is_blocking; @@ -524,7 +524,7 @@ erts_thr_progress_register_unmanaged_thread(ErtsThrPrgrCallbacks *callbacks) #endif ASSERT(tpd->id >= 0); if (tpd->id >= intrnl->unmanaged.no) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%s:%d:%s(): Too many unmanaged registered threads\n", __FILE__, __LINE__, __func__); @@ -547,7 +547,7 @@ erts_thr_progress_register_managed_thread(ErtsSchedulerData *esdp, if (tpd) { if (!tpd->is_temporary) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%s:%d:%s(): Double register of thread\n", __FILE__, __LINE__, __func__); is_blocking = tpd->is_blocking; @@ -568,7 +568,7 @@ erts_thr_progress_register_managed_thread(ErtsSchedulerData *esdp, tpd->id = erts_atomic32_inc_read_nob(&intrnl->misc.data.managed_id); ASSERT(tpd->id >= 0); if (tpd->id >= intrnl->managed.no) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%s:%d:%s(): Too many managed registered threads\n", __FILE__, __LINE__, __func__); @@ -1033,7 +1033,7 @@ has_reached_wakeup(ErtsThrPrgrVal wakeup) limit += 1; if (!erts_thr_progress_has_passed__(limit, wakeup)) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Invalid wakeup request value found:" " current=%b64u, wakeup=%b64u, limit=%b64u", current, wakeup, limit); @@ -1102,7 +1102,7 @@ request_wakeup_managed(ErtsThrPrgrData *tpd, ErtsThrPrgrVal value) ix = erts_atomic32_inc_read_nob(&mwd->len) - 1; #if ERTS_THR_PRGR_DBG_CHK_WAKEUP_REQUEST_VALUE if (ix >= intrnl->managed.no) - erl_exit(ERTS_ABORT_EXIT, "Internal error: Too many wakeup requests\n"); + erts_exit(ERTS_ABORT_EXIT, "Internal error: Too many wakeup requests\n"); #endif mwd->id[ix] = tpd->id; diff --git a/erts/emulator/beam/erl_thr_queue.c b/erts/emulator/beam/erl_thr_queue.c index 3a91ca9dbe..7ff456b915 100644 --- a/erts/emulator/beam/erl_thr_queue.c +++ b/erts/emulator/beam/erl_thr_queue.c @@ -224,7 +224,7 @@ ErtsThrQCleanState_t erts_thr_q_destroy(ErtsThrQ_t *q) { if (!q->q.blk) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Trying to destroy not created thread queue\n"); return erts_thr_q_finalize(q); } @@ -589,7 +589,7 @@ enqueue(ErtsThrQ_t *q, void *data, ErtsThrQElement_t *this) #if ERTS_THR_Q_DBG_CHK_DATA if (!data) - erl_exit(ERTS_ABORT_EXIT, "Missing data in enqueue\n"); + erts_exit(ERTS_ABORT_EXIT, "Missing data in enqueue\n"); #endif ASSERT(!q->q.finalizing); @@ -771,7 +771,7 @@ erts_thr_q_dequeue(ErtsThrQ_t *q) #if ERTS_THR_Q_DBG_CHK_DATA head->data.ptr = NULL; if (!res) - erl_exit(ERTS_ABORT_EXIT, "Missing data in dequeue\n"); + erts_exit(ERTS_ABORT_EXIT, "Missing data in dequeue\n"); #endif clean(q, (q->head.deq_fini.automatic diff --git a/erts/emulator/beam/erl_threads.h b/erts/emulator/beam/erl_threads.h index 5347979372..34f91e2ec8 100644 --- a/erts/emulator/beam/erl_threads.h +++ b/erts/emulator/beam/erl_threads.h @@ -649,6 +649,7 @@ ERTS_GLB_INLINE void erts_tsd_set(erts_tsd_key_t key, void *value); ERTS_GLB_INLINE void * erts_tsd_get(erts_tsd_key_t key); ERTS_GLB_INLINE erts_tse_t *erts_tse_fetch(void); ERTS_GLB_INLINE void erts_tse_return(erts_tse_t *ep); +ERTS_GLB_INLINE void erts_tse_prepare_timed(erts_tse_t *ep); ERTS_GLB_INLINE void erts_tse_set(erts_tse_t *ep); ERTS_GLB_INLINE void erts_tse_reset(erts_tse_t *ep); ERTS_GLB_INLINE int erts_tse_wait(erts_tse_t *ep); @@ -3461,6 +3462,15 @@ ERTS_GLB_INLINE void erts_tse_return(erts_tse_t *ep) #endif } +ERTS_GLB_INLINE void erts_tse_prepare_timed(erts_tse_t *ep) +{ +#ifdef USE_THREADS + int res = ethr_event_prepare_timed(&((ethr_ts_event *) ep)->event); + if (res != 0) + erts_thr_fatal_error(res, "prepare timed"); +#endif +} + ERTS_GLB_INLINE void erts_tse_set(erts_tse_t *ep) { #ifdef USE_THREADS diff --git a/erts/emulator/beam/erl_time.h b/erts/emulator/beam/erl_time.h index 36a3d52264..93a0d556bf 100644 --- a/erts/emulator/beam/erl_time.h +++ b/erts/emulator/beam/erl_time.h @@ -133,6 +133,10 @@ typedef struct { extern ErtsTimeSupData erts_time_sup__; +ErtsMonotonicTime erts_napi_monotonic_time(int time_unit); +ErtsMonotonicTime erts_napi_time_offset(int time_unit); +ErtsMonotonicTime erts_napi_convert_time_unit(ErtsMonotonicTime val, int from, int to); + ERTS_GLB_INLINE Uint64 erts_time_unit_conversion(Uint64 value, Uint32 from_time_unit, @@ -345,8 +349,10 @@ erts_time_unit_conversion(Uint64 value, #endif /* !ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT */ #define ERTS_MONOTONIC_TIME_END_EXTERNAL \ - (ERTS_MONOTONIC_TIME_START_EXTERNAL \ - + (ERTS_MONOTONIC_END - ERTS_MONOTONIC_BEGIN)) + (ERTS_MONOTONIC_TIME_START_EXTERNAL < 0 \ + ? (ERTS_MONOTONIC_TIME_START_EXTERNAL \ + + (ERTS_MONOTONIC_END - ERTS_MONOTONIC_BEGIN)) \ + : (ERTS_MONOTONIC_END - ERTS_MONOTONIC_TIME_START_EXTERNAL)) #define ERTS_MSEC_TO_CLKTCKS__(MON) \ ((MON) * (ERTS_CLKTCK_RESOLUTION/1000)) diff --git a/erts/emulator/beam/erl_time_sup.c b/erts/emulator/beam/erl_time_sup.c index 7f8f560681..99005356ed 100644 --- a/erts/emulator/beam/erl_time_sup.c +++ b/erts/emulator/beam/erl_time_sup.c @@ -33,6 +33,8 @@ #include "global.h" #define ERTS_WANT_TIMER_WHEEL_API #include "erl_time.h" +#include "erl_driver.h" +#include "erl_nif.h" static erts_smp_mtx_t erts_timeofday_mtx; static erts_smp_mtx_t erts_get_time_mtx; @@ -57,6 +59,7 @@ static int time_sup_initialized = 0; #define ERTS_MONOTONIC_TIME_TERA \ (ERTS_MONOTONIC_TIME_GIGA*ERTS_MONOTONIC_TIME_KILO) +static void init_time_napi(void); static void schedule_send_time_offset_changed_notifications(ErtsMonotonicTime new_offset); @@ -124,7 +127,11 @@ typedef struct { typedef struct { ErtsMonotonicCorrectionInstance prev; - ErtsMonotonicCorrectionInstance curr; + ErtsMonotonicCorrectionInstance curr; +} ErtsMonotonicCorrectionInstances; + +typedef struct { + ErtsMonotonicCorrectionInstances insts; ErtsMonotonicDriftData drift; ErtsMonotonicTime last_check; int short_check_interval; @@ -272,27 +279,24 @@ static ERTS_INLINE ErtsMonotonicTime read_corrected_time(int os_drift_corrected) { ErtsMonotonicTime os_mtime; - ErtsMonotonicCorrectionData cdata; - ErtsMonotonicCorrectionInstance *cip; + ErtsMonotonicCorrectionInstance ci; erts_smp_rwmtx_rlock(&time_sup.inf.c.parmon.rwmtx); os_mtime = erts_os_monotonic_time(); - cdata = time_sup.inf.c.parmon.cdata; - - erts_smp_rwmtx_runlock(&time_sup.inf.c.parmon.rwmtx); - - if (os_mtime >= cdata.curr.os_mtime) - cip = &cdata.curr; + if (os_mtime >= time_sup.inf.c.parmon.cdata.insts.curr.os_mtime) + ci = time_sup.inf.c.parmon.cdata.insts.curr; else { - if (os_mtime < cdata.prev.os_mtime) - erl_exit(ERTS_ABORT_EXIT, + if (os_mtime < time_sup.inf.c.parmon.cdata.insts.prev.os_mtime) + erts_exit(ERTS_ABORT_EXIT, "OS monotonic time stepped backwards\n"); - cip = &cdata.prev; + ci = time_sup.inf.c.parmon.cdata.insts.prev; } - return calc_corrected_erl_mtime(os_mtime, cip, NULL, + erts_smp_rwmtx_runlock(&time_sup.inf.c.parmon.rwmtx); + + return calc_corrected_erl_mtime(os_mtime, &ci, NULL, os_drift_corrected); } @@ -360,9 +364,8 @@ check_time_correction(void *vesdp) { int init_drift_adj = !vesdp; ErtsSchedulerData *esdp = (ErtsSchedulerData *) vesdp; - ErtsMonotonicCorrectionData cdata; ErtsMonotonicCorrection new_correction; - ErtsMonotonicCorrectionInstance *cip; + ErtsMonotonicCorrectionInstance ci; ErtsMonotonicTime mdiff, sdiff, os_mtime, erl_mtime, os_stime, erl_stime, time_offset, timeout_pos; Uint timeout; @@ -373,16 +376,15 @@ check_time_correction(void *vesdp) erts_os_times(&os_mtime, &os_stime); - cdata = time_sup.inf.c.parmon.cdata; + ci = time_sup.inf.c.parmon.cdata.insts.curr; erts_smp_rwmtx_runlock(&time_sup.inf.c.parmon.rwmtx); - if (os_mtime < cdata.curr.os_mtime) - erl_exit(ERTS_ABORT_EXIT, + if (os_mtime < ci.os_mtime) + erts_exit(ERTS_ABORT_EXIT, "OS monotonic time stepped backwards\n"); - cip = &cdata.curr; - erl_mtime = calc_corrected_erl_mtime(os_mtime, cip, &mdiff, + erl_mtime = calc_corrected_erl_mtime(os_mtime, &ci, &mdiff, os_drift_corrected); time_offset = get_time_offset(); erl_stime = erl_mtime + time_offset; @@ -397,7 +399,7 @@ check_time_correction(void *vesdp) time_sup.inf.c.shadow_offset = 0; } - new_correction = cip->correction; + new_correction = ci.correction; if (time_sup.r.o.warp_mode == ERTS_MULTI_TIME_WARP_MODE && (sdiff < -2*time_sup.r.o.adj.small_diff @@ -408,7 +410,7 @@ check_time_correction(void *vesdp) set_time_offset(time_offset); schedule_send_time_offset_changed_notifications(time_offset); begin_short_intervals = 1; - if (cdata.curr.correction.error != 0) { + if (ci.correction.error != 0) { set_new_correction = 1; new_correction.error = 0; } @@ -425,12 +427,12 @@ check_time_correction(void *vesdp) time_sup.inf.c.shadow_offset -= sdiff; sdiff = 0; begin_short_intervals = 1; - if (cdata.curr.correction.error != 0) { + if (ci.correction.error != 0) { set_new_correction = 1; new_correction.error = 0; } } - else if (cdata.curr.correction.error == 0) { + else if (ci.correction.error == 0) { if (sdiff < -time_sup.r.o.adj.small_diff) { set_new_correction = 1; if (sdiff < -time_sup.r.o.adj.large_diff) @@ -446,9 +448,9 @@ check_time_correction(void *vesdp) new_correction.error = -ERTS_TCORR_ERR_SMALL_ADJ; } } - else if (cdata.curr.correction.error > 0) { + else if (ci.correction.error > 0) { if (sdiff < 0) { - if (cdata.curr.correction.error != ERTS_TCORR_ERR_LARGE_ADJ + if (ci.correction.error != ERTS_TCORR_ERR_LARGE_ADJ && sdiff < -time_sup.r.o.adj.large_diff) { new_correction.error = ERTS_TCORR_ERR_LARGE_ADJ; set_new_correction = 1; @@ -466,9 +468,9 @@ check_time_correction(void *vesdp) new_correction.error = 0; } } - else /* if (cdata.curr.correction.error < 0) */ { + else /* if (ci.correction.error < 0) */ { if (0 < sdiff) { - if (cdata.curr.correction.error != -ERTS_TCORR_ERR_LARGE_ADJ + if (ci.correction.error != -ERTS_TCORR_ERR_LARGE_ADJ && time_sup.r.o.adj.large_diff < sdiff) { new_correction.error = -ERTS_TCORR_ERR_LARGE_ADJ; set_new_correction = 1; @@ -631,8 +633,8 @@ check_time_correction(void *vesdp) #ifdef ERTS_TIME_CORRECTION_PRINT print_correction(set_new_correction, sdiff, - cip->correction.error, - cip->correction.drift, + ci.correction.error, + ci.correction.drift, new_correction.error, new_correction.drift, timeout); @@ -644,7 +646,7 @@ check_time_correction(void *vesdp) os_mtime = erts_os_monotonic_time(); /* Save previous correction instance */ - time_sup.inf.c.parmon.cdata.prev = *cip; + time_sup.inf.c.parmon.cdata.insts.prev = ci; /* * Current correction instance begin when @@ -657,15 +659,15 @@ check_time_correction(void *vesdp) * next OS monotonic time using previous * correction. */ - erl_mtime = calc_corrected_erl_mtime(os_mtime, cip, NULL, + erl_mtime = calc_corrected_erl_mtime(os_mtime, &ci, NULL, os_drift_corrected); /* * Save new current correction instance. */ - time_sup.inf.c.parmon.cdata.curr.erl_mtime = erl_mtime; - time_sup.inf.c.parmon.cdata.curr.os_mtime = os_mtime; - time_sup.inf.c.parmon.cdata.curr.correction = new_correction; + time_sup.inf.c.parmon.cdata.insts.curr.erl_mtime = erl_mtime; + time_sup.inf.c.parmon.cdata.insts.curr.os_mtime = os_mtime; + time_sup.inf.c.parmon.cdata.insts.curr.correction = new_correction; erts_smp_rwmtx_rwunlock(&time_sup.inf.c.parmon.rwmtx); } @@ -784,24 +786,22 @@ static ErtsMonotonicTime finalize_corrected_time_offset(ErtsSystemTime *stimep) { ErtsMonotonicTime os_mtime; - ErtsMonotonicCorrectionData cdata; - ErtsMonotonicCorrectionInstance *cip; + ErtsMonotonicCorrectionInstance ci; int os_drift_corrected = time_sup.r.o.os_corrected_monotonic_time; erts_smp_rwmtx_rlock(&time_sup.inf.c.parmon.rwmtx); erts_os_times(&os_mtime, stimep); - cdata = time_sup.inf.c.parmon.cdata; + ci = time_sup.inf.c.parmon.cdata.insts.curr; erts_smp_rwmtx_runlock(&time_sup.inf.c.parmon.rwmtx); - if (os_mtime < cdata.curr.os_mtime) - erl_exit(ERTS_ABORT_EXIT, + if (os_mtime < ci.os_mtime) + erts_exit(ERTS_ABORT_EXIT, "OS monotonic time stepped backwards\n"); - cip = &cdata.curr; - return calc_corrected_erl_mtime(os_mtime, cip, NULL, + return calc_corrected_erl_mtime(os_mtime, &ci, NULL, os_drift_corrected); } @@ -951,6 +951,8 @@ erts_init_time_sup(int time_correction, ErtsTimeWarpMode time_warp_mode) ErtsMonotonicTime abs_native_offset, native_offset; #endif + init_time_napi(); + erts_hl_timer_init(); ASSERT(ERTS_MONOTONIC_TIME_MIN < ERTS_MONOTONIC_TIME_MAX); @@ -1128,13 +1130,13 @@ erts_init_time_sup(int time_correction, ErtsTimeWarpMode time_warp_mode) cdatap->drift.intervals[0].time.sys = time_sup.inf.c.sinit; cdatap->drift.intervals[0].time.mon = time_sup.inf.c.minit; - cdatap->curr.correction.drift = 0; - cdatap->curr.correction.error = 0; - cdatap->curr.erl_mtime = ERTS_MONOTONIC_BEGIN; - cdatap->curr.os_mtime = time_sup.inf.c.minit; + cdatap->insts.curr.correction.drift = 0; + cdatap->insts.curr.correction.error = 0; + cdatap->insts.curr.erl_mtime = ERTS_MONOTONIC_BEGIN; + cdatap->insts.curr.os_mtime = time_sup.inf.c.minit; cdatap->last_check = time_sup.inf.c.minit; cdatap->short_check_interval = ERTS_INIT_SHORT_INTERVAL_COUNTER; - cdatap->prev = cdatap->curr; + cdatap->insts.prev = cdatap->insts.curr; if (!time_sup.r.o.os_corrected_monotonic_time) time_sup.r.o.get_time = get_corrected_time; @@ -1750,6 +1752,39 @@ erts_get_monotonic_time(ErtsSchedulerData *esdp) return mtime; } +ErtsMonotonicTime +erts_get_time_offset(void) +{ + return get_time_offset(); +} + +static ERTS_INLINE void +make_timestamp_value(Uint* megasec, Uint* sec, Uint* microsec, + ErtsMonotonicTime mtime, ErtsMonotonicTime offset) +{ + ErtsMonotonicTime stime, as; + Uint ms; + + stime = ERTS_MONOTONIC_TO_USEC(mtime + offset); + + as = stime / ERTS_MONOTONIC_TIME_MEGA; + *megasec = ms = (Uint) (stime / ERTS_MONOTONIC_TIME_TERA); + *sec = (Uint) (as - (((ErtsMonotonicTime) ms) + * ERTS_MONOTONIC_TIME_MEGA)); + *microsec = (Uint) (stime - as*ERTS_MONOTONIC_TIME_MEGA); + + ASSERT(((ErtsMonotonicTime) ms)*ERTS_MONOTONIC_TIME_TERA + + ((ErtsMonotonicTime) *sec)*ERTS_MONOTONIC_TIME_MEGA + + *microsec == stime); +} + +void +erts_make_timestamp_value(Uint* megasec, Uint* sec, Uint* microsec, + ErtsMonotonicTime mtime, ErtsMonotonicTime offset) +{ + make_timestamp_value(megasec, sec, microsec, mtime, offset); +} + void get_sys_now(Uint* megasec, Uint* sec, Uint* microsec) { @@ -2167,6 +2202,146 @@ time_unit_conversion(Process *c_p, Eterm term, ErtsMonotonicTime val, ErtsMonoto return ret; } + +/* + * Time Native API (drivers and NIFs) + */ + +#define ERTS_NAPI_TIME_ERROR ((ErtsMonotonicTime) ERTS_NAPI_TIME_ERROR__) + +static void +init_time_napi(void) +{ + /* Verify that time native api constants are as expected... */ + + ASSERT(sizeof(ErtsMonotonicTime) == sizeof(ErlDrvTime)); + ASSERT(ERL_DRV_TIME_ERROR == (ErlDrvTime) ERTS_NAPI_TIME_ERROR); + ASSERT(ERL_DRV_TIME_ERROR < (ErlDrvTime) 0); + ASSERT(ERTS_NAPI_SEC__ == (int) ERL_DRV_SEC); + ASSERT(ERTS_NAPI_MSEC__ == (int) ERL_DRV_MSEC); + ASSERT(ERTS_NAPI_USEC__ == (int) ERL_DRV_USEC); + ASSERT(ERTS_NAPI_NSEC__ == (int) ERL_DRV_NSEC); + + ASSERT(sizeof(ErtsMonotonicTime) == sizeof(ErlNifTime)); + ASSERT(ERL_NIF_TIME_ERROR == (ErlNifTime) ERTS_NAPI_TIME_ERROR); + ASSERT(ERL_NIF_TIME_ERROR < (ErlNifTime) 0); + ASSERT(ERTS_NAPI_SEC__ == (int) ERL_NIF_SEC); + ASSERT(ERTS_NAPI_MSEC__ == (int) ERL_NIF_MSEC); + ASSERT(ERTS_NAPI_USEC__ == (int) ERL_NIF_USEC); + ASSERT(ERTS_NAPI_NSEC__ == (int) ERL_NIF_NSEC); +} + +ErtsMonotonicTime +erts_napi_monotonic_time(int time_unit) +{ + ErtsSchedulerData *esdp; + ErtsMonotonicTime mtime; + + /* At least for now only allow schedulers to do this... */ + esdp = erts_get_scheduler_data(); + if (!esdp) + return ERTS_NAPI_TIME_ERROR; + + mtime = time_sup.r.o.get_time(); + update_last_mtime(esdp, mtime); + + switch (time_unit) { + case ERTS_NAPI_SEC__: + mtime = ERTS_MONOTONIC_TO_SEC(mtime); + mtime += ERTS_MONOTONIC_OFFSET_SEC; + break; + case ERTS_NAPI_MSEC__: + mtime = ERTS_MONOTONIC_TO_MSEC(mtime); + mtime += ERTS_MONOTONIC_OFFSET_MSEC; + break; + case ERTS_NAPI_USEC__: + mtime = ERTS_MONOTONIC_TO_USEC(mtime); + mtime += ERTS_MONOTONIC_OFFSET_USEC; + break; + case ERTS_NAPI_NSEC__: + mtime = ERTS_MONOTONIC_TO_NSEC(mtime); + mtime += ERTS_MONOTONIC_OFFSET_NSEC; + break; + default: + return ERTS_NAPI_TIME_ERROR; + } + + return mtime; +} + +ErtsMonotonicTime +erts_napi_time_offset(int time_unit) +{ + ErtsSchedulerData *esdp; + ErtsSystemTime offs; + + /* At least for now only allow schedulers to do this... */ + esdp = erts_get_scheduler_data(); + if (!esdp) + return ERTS_NAPI_TIME_ERROR; + + offs = get_time_offset(); + switch (time_unit) { + case ERTS_NAPI_SEC__: + offs = ERTS_MONOTONIC_TO_SEC(offs); + offs -= ERTS_MONOTONIC_OFFSET_SEC; + break; + case ERTS_NAPI_MSEC__: + offs = ERTS_MONOTONIC_TO_MSEC(offs); + offs -= ERTS_MONOTONIC_OFFSET_MSEC; + break; + case ERTS_NAPI_USEC__: + offs = ERTS_MONOTONIC_TO_USEC(offs); + offs -= ERTS_MONOTONIC_OFFSET_USEC; + break; + case ERTS_NAPI_NSEC__: + offs = ERTS_MONOTONIC_TO_NSEC(offs); + offs -= ERTS_MONOTONIC_OFFSET_NSEC; + break; + default: + return ERTS_NAPI_TIME_ERROR; + } + return offs; +} + +ErtsMonotonicTime +erts_napi_convert_time_unit(ErtsMonotonicTime val, int from, int to) +{ + ErtsMonotonicTime ffreq, tfreq, denom; + /* + * Convertion between time units using floor function. + * + * Note that this needs to work also for negative + * values. Ordinary integer division on a negative + * value will give ceiling... + */ + + switch ((int) from) { + case ERTS_NAPI_SEC__: ffreq = 1; break; + case ERTS_NAPI_MSEC__: ffreq = 1000; break; + case ERTS_NAPI_USEC__: ffreq = 1000*1000; break; + case ERTS_NAPI_NSEC__: ffreq = 1000*1000*1000; break; + default: return ERTS_NAPI_TIME_ERROR; + } + + switch ((int) to) { + case ERTS_NAPI_SEC__: tfreq = 1; break; + case ERTS_NAPI_MSEC__: tfreq = 1000; break; + case ERTS_NAPI_USEC__: tfreq = 1000*1000; break; + case ERTS_NAPI_NSEC__: tfreq = 1000*1000*1000; break; + default: return ERTS_NAPI_TIME_ERROR; + } + + if (tfreq >= ffreq) + return val * (tfreq / ffreq); + + denom = ffreq / tfreq; + if (val >= 0) + return val / denom; + + return (val - (denom - 1)) / denom; +} + /* Built in functions */ BIF_RETTYPE monotonic_time_0(BIF_ALIST_0) @@ -2223,22 +2398,14 @@ BIF_RETTYPE time_offset_1(BIF_ALIST_1) BIF_RETTYPE timestamp_0(BIF_ALIST_0) { Eterm *hp, res; - ErtsMonotonicTime stime, mtime, all_sec, offset; + ErtsMonotonicTime mtime, offset; Uint mega_sec, sec, micro_sec; mtime = time_sup.r.o.get_time(); offset = get_time_offset(); update_last_mtime(ERTS_PROC_GET_SCHDATA(BIF_P), mtime); - stime = ERTS_MONOTONIC_TO_USEC(mtime + offset); - all_sec = stime / ERTS_MONOTONIC_TIME_MEGA; - mega_sec = (Uint) (stime / ERTS_MONOTONIC_TIME_TERA); - sec = (Uint) (all_sec - (((ErtsMonotonicTime) mega_sec) - * ERTS_MONOTONIC_TIME_MEGA)); - micro_sec = (Uint) (stime - all_sec*ERTS_MONOTONIC_TIME_MEGA); - - ASSERT(((ErtsMonotonicTime) mega_sec)*ERTS_MONOTONIC_TIME_TERA - + ((ErtsMonotonicTime) sec)*ERTS_MONOTONIC_TIME_MEGA - + micro_sec == stime); + + make_timestamp_value(&mega_sec, &sec, µ_sec, mtime, offset); /* * Mega seconds is the only value that potentially diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c index e1b03a057f..114853cac4 100644 --- a/erts/emulator/beam/erl_trace.c +++ b/erts/emulator/beam/erl_trace.c @@ -38,6 +38,7 @@ #include "erl_binary.h" #include "erl_bits.h" #include "erl_thr_progress.h" +#include "erl_bif_unique.h" #if 0 #define DEBUG_PRINTOUTS @@ -77,6 +78,264 @@ enum ErtsSysMsgType { SYS_MSG_TYPE_SYSPROF }; +#define ERTS_TRACE_TS_NOW_MAX_SIZE \ + 4 +#define ERTS_TRACE_TS_MONOTONIC_MAX_SIZE \ + ERTS_MAX_SINT64_HEAP_SIZE +#define ERTS_TRACE_TS_STRICT_MONOTONIC_MAX_SIZE \ + (3 + ERTS_MAX_SINT64_HEAP_SIZE \ + + ERTS_MAX_UINT64_HEAP_SIZE) + +#define ERTS_TRACE_PATCH_TS_MAX_SIZE \ + (1 + ((ERTS_TRACE_TS_NOW_MAX_SIZE \ + > ERTS_TRACE_TS_MONOTONIC_MAX_SIZE) \ + ? ((ERTS_TRACE_TS_NOW_MAX_SIZE \ + > ERTS_TRACE_TS_STRICT_MONOTONIC_MAX_SIZE) \ + ? ERTS_TRACE_TS_NOW_MAX_SIZE \ + : ERTS_TRACE_TS_STRICT_MONOTONIC_MAX_SIZE) \ + : ((ERTS_TRACE_TS_MONOTONIC_MAX_SIZE \ + > ERTS_TRACE_TS_STRICT_MONOTONIC_MAX_SIZE) \ + ? ERTS_TRACE_TS_MONOTONIC_MAX_SIZE \ + : ERTS_TRACE_TS_STRICT_MONOTONIC_MAX_SIZE))) + +#define TFLGS_TS_TYPE(p) ERTS_TFLGS2TSTYPE(ERTS_TRACE_FLAGS((p))) + +/* + * FUTURE CHANGES: + * + * The timestamp functionality has intentionally been + * split in two parts for future use even though it + * is not used like this today. take_timestamp() takes + * the timestamp and calculate heap need for it (which + * is not constant). write_timestamp() writes the + * timestamp to the allocated heap. That is, one typically + * want to take the timestamp before allocating the heap + * and then write it to the heap. + * + * The trace output functionality now use patch_ts_size(), + * write_ts(), and patch_ts(). write_ts() both takes the + * timestamp and writes it. Since we don't know the + * heap need when allocating the heap area we need to + * over allocate (maximum size from patch_ts_size()) and + * then potentially (often) shrink the heap area after the + * timestamp has been written. The only reason it is + * currently done this way is because we do not want to + * make major changes of the trace behavior in a patch. + * This is planned to be changed in next major release. + */ + +typedef struct { + int ts_type_flag; + union { + struct { + Uint ms; + Uint s; + Uint us; + } now; + struct { + ErtsMonotonicTime time; + Sint64 raw_unique; + } monotonic; + } u; +} ErtsTraceTimeStamp; + +static ERTS_INLINE Uint +take_timestamp(ErtsTraceTimeStamp *tsp, int ts_type) +{ + int ts_type_flag = ts_type & -ts_type; /* least significant flag */ + + ASSERT(ts_type_flag == ERTS_TRACE_FLG_NOW_TIMESTAMP + || ts_type_flag == ERTS_TRACE_FLG_MONOTONIC_TIMESTAMP + || ts_type_flag == ERTS_TRACE_FLG_STRICT_MONOTONIC_TIMESTAMP + || ts_type_flag == 0); + + tsp->ts_type_flag = ts_type_flag; + switch (ts_type_flag) { + case 0: + return (Uint) 0; + case ERTS_TRACE_FLG_NOW_TIMESTAMP: +#ifdef HAVE_ERTS_NOW_CPU + if (erts_cpu_timestamp) + erts_get_now_cpu(&tsp->u.now.ms, &tsp->u.now.s, &tsp->u.now.us); + else +#endif + get_now(&tsp->u.now.ms, &tsp->u.now.s, &tsp->u.now.us); + return (Uint) 4; + case ERTS_TRACE_FLG_MONOTONIC_TIMESTAMP: + case ERTS_TRACE_FLG_STRICT_MONOTONIC_TIMESTAMP: { + Uint hsz = 0; + ErtsMonotonicTime mtime = erts_get_monotonic_time(NULL); + mtime = ERTS_MONOTONIC_TO_NSEC(mtime); + mtime += ERTS_MONOTONIC_OFFSET_NSEC; + hsz = (IS_SSMALL(mtime) ? + (Uint) 0 + : ERTS_SINT64_HEAP_SIZE((Sint64) mtime)); + tsp->u.monotonic.time = mtime; + if (ts_type_flag == ERTS_TRACE_FLG_STRICT_MONOTONIC_TIMESTAMP) { + Sint64 raw_unique; + hsz += 3; /* 2-tuple */ + raw_unique = erts_raw_get_unique_monotonic_integer(); + tsp->u.monotonic.raw_unique = raw_unique; + hsz += erts_raw_unique_monotonic_integer_heap_size(raw_unique); + } + return hsz; + } + default: + ERTS_INTERNAL_ERROR("invalid timestamp type"); + return 0; + } +} + +static ERTS_INLINE Eterm +write_timestamp(ErtsTraceTimeStamp *tsp, Eterm **hpp) +{ + int ts_type_flag = tsp->ts_type_flag; + Eterm res; + + switch (ts_type_flag) { + case 0: + return NIL; + case ERTS_TRACE_FLG_NOW_TIMESTAMP: + res = TUPLE3(*hpp, + make_small(tsp->u.now.ms), + make_small(tsp->u.now.s), + make_small(tsp->u.now.us)); + *hpp += 4; + return res; + case ERTS_TRACE_FLG_MONOTONIC_TIMESTAMP: + case ERTS_TRACE_FLG_STRICT_MONOTONIC_TIMESTAMP: { + Sint64 mtime, raw; + Eterm unique, emtime; + + mtime = (Sint64) tsp->u.monotonic.time; + emtime = (IS_SSMALL(mtime) + ? make_small((Sint64) mtime) + : erts_sint64_to_big((Sint64) mtime, hpp)); + + if (ts_type_flag == ERTS_TRACE_FLG_MONOTONIC_TIMESTAMP) + return emtime; + + raw = tsp->u.monotonic.raw_unique; + unique = erts_raw_make_unique_monotonic_integer_value(hpp, + raw); + res = TUPLE2(*hpp, emtime, unique); + *hpp += 3; + return res; + } + default: + ERTS_INTERNAL_ERROR("invalid timestamp type"); + return THE_NON_VALUE; + } +} + +#define PATCH_TS_SIZE(p) patch_ts_size(TFLGS_TS_TYPE(p)) + +static ERTS_INLINE Uint +patch_ts_size(int ts_type) +{ + int ts_type_flag = ts_type & -ts_type; /* least significant flag */ + switch (ts_type_flag) { + case 0: + return 0; + case ERTS_TRACE_FLG_NOW_TIMESTAMP: + return 1 + ERTS_TRACE_TS_NOW_MAX_SIZE; + case ERTS_TRACE_FLG_MONOTONIC_TIMESTAMP: + return 1 + ERTS_TRACE_TS_MONOTONIC_MAX_SIZE; + case ERTS_TRACE_FLG_STRICT_MONOTONIC_TIMESTAMP: + return 1 + ERTS_TRACE_TS_STRICT_MONOTONIC_MAX_SIZE; + default: + ERTS_INTERNAL_ERROR("invalid timestamp type"); + return 0; + } +} + +/* + * Write a timestamp. The timestamp MUST be the last + * thing built on the heap. This since write_ts() might + * adjust the size of the used area. + */ +static Eterm +write_ts(int ts_type, Eterm *hp, ErlHeapFragment *bp, Process *tracer) +{ + ErtsTraceTimeStamp ts; + Sint shrink; + Eterm res, *ts_hp = hp; + Uint hsz; + + ASSERT(ts_type); + + hsz = take_timestamp(&ts, ts_type); + + res = write_timestamp(&ts, &ts_hp); + + ASSERT(ts_hp == hp + hsz); + + switch (ts.ts_type_flag) { + case ERTS_TRACE_FLG_MONOTONIC_TIMESTAMP: + shrink = ERTS_TRACE_TS_MONOTONIC_MAX_SIZE; + break; + case ERTS_TRACE_FLG_STRICT_MONOTONIC_TIMESTAMP: + shrink = ERTS_TRACE_TS_STRICT_MONOTONIC_MAX_SIZE; + break; + default: + return res; + } + + shrink -= hsz; + + ASSERT(shrink >= 0); + + if (shrink) { + if (bp) + bp->used_size -= shrink; +#ifndef ERTS_SMP + else if (tracer) { + Eterm *endp = ts_hp + shrink; + HRelease(tracer, endp, ts_hp); + } +#endif + } + + return res; +} + +/* + * Patch a timestamp into a tuple. The tuple MUST be the last thing + * built on the heap before the call, and the timestamp MUST be + * the last thing after the call. This since patch_ts() might adjust + * the size of the used area. + */ + +#define PATCH_TS__(Type, Tuple, Hp, Bp, Tracer) \ + do { \ + int ts_type__ = (Type); \ + if (ts_type__) \ + patch_ts(ts_type__, (Tuple), (Hp), (Bp), (Tracer)); \ + } while (0) + +#ifdef ERTS_SMP +#define PATCH_TS(Type, Tuple, Hp, Bp, Tracer) \ + PATCH_TS__((Type), (Tuple), (Hp), (Bp), NULL) +#else +#define PATCH_TS(Type, Tuple, Hp, Bp, Tracer) \ + PATCH_TS__((Type), (Tuple), (Hp), (Bp), (Tracer)) +#endif + +static ERTS_INLINE void +patch_ts(int ts_type, Eterm tuple, Eterm* hp, ErlHeapFragment *bp, Process *tracer) +{ + Eterm *tptr = tuple_val(tuple); + int arity = arityval(*tptr); + + ASSERT(ts_type); + ASSERT((tptr+arity+1) == hp); + + tptr[0] = make_arityval(arity+1); + tptr[1] = am_trace_ts; + + *hp = write_ts(ts_type, hp+1, bp, tracer); +} + #ifdef ERTS_SMP static void enqueue_sys_msg_unlocked(enum ErtsSysMsgType type, Eterm from, @@ -365,23 +624,6 @@ erts_get_system_profile(void) { return profile; } - -#ifdef HAVE_ERTS_NOW_CPU -# define GET_NOW(m, s, u) \ -do { \ - if (erts_cpu_timestamp) \ - erts_get_now_cpu(m, s, u); \ - else \ - get_now(m, s, u); \ -} while (0) -#else -# define GET_NOW(m, s, u) do {get_now(m, s, u);} while (0) -#endif - - - -static Eterm* patch_ts(Eterm tuple4, Eterm* hp); - #ifdef ERTS_SMP static void do_send_to_port(Eterm to, @@ -420,7 +662,7 @@ WRITE_SYS_MSG_TO_PORT(Eterm unused_to, erts_encode_ext(message, &ptr); if (!(ptr <= buffer+size)) { - erl_exit(1, "Internal error in do_send_to_port: %d\n", ptr-buffer); + erts_exit(ERTS_ERROR_EXIT, "Internal error in do_send_to_port: %d\n", ptr-buffer); } #ifndef ERTS_SMP @@ -436,11 +678,11 @@ WRITE_SYS_MSG_TO_PORT(Eterm unused_to, /* Send {trace_ts, Pid, out, 0, Timestamp} * followed by {trace_ts, Pid, in, 0, NewTimestamp} * - * 'NewTimestamp' is fetched from GET_NOW() through patch_ts(). + * 'NewTimestamp' through patch_ts(). */ static void -do_send_schedfix_to_port(Port *trace_port, Eterm pid, Eterm timestamp) { -#define LOCAL_HEAP_SIZE (4+5+5) +do_send_schedfix_to_port(Port *trace_port, Eterm pid, Eterm timestamp, int ts_type) { +#define LOCAL_HEAP_SIZE (5+5+ERTS_TRACE_PATCH_TS_MAX_SIZE) DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE); Eterm message; Eterm *hp; @@ -462,9 +704,11 @@ do_send_schedfix_to_port(Port *trace_port, Eterm pid, Eterm timestamp) { SYS_MSG_TYPE_UNDEFINED, message); - message = TUPLE4(hp, am_trace_ts, pid, am_in, mfarity); - hp += 5; - hp = patch_ts(message, hp); + + message = TUPLE5(hp, am_trace_ts, pid, am_in, mfarity, + NIL /* Will be overwritten by timestamp */); + hp += 6; + hp[-1] = write_ts(ts_type, hp, NULL, NULL); do_send_to_port(trace_port->common.id, trace_port, @@ -481,7 +725,7 @@ do_send_schedfix_to_port(Port *trace_port, Eterm pid, Eterm timestamp) { * It is assumed that 'message' is not an 'out' message. * * 'c_p' is the currently executing process, "tracee" is the traced process - * which 'message' concerns => if (*tracee_flags & F_TIMESTAMP), + * which 'message' concerns => if (*tracee_flags & F_TIMESTAMP_MASK), * 'message' must contain a timestamp. */ static void @@ -489,8 +733,9 @@ send_to_port(Process *c_p, Eterm message, Eterm *tracer_pid, Uint *tracee_flags) { Port* trace_port; #ifndef ERTS_SMP -#define LOCAL_HEAP_SIZE (4) - Eterm ts, *hp; + int ts_type; +#define LOCAL_HEAP_SIZE ERTS_TRACE_PATCH_TS_MAX_SIZE + Eterm ts; DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE); #endif @@ -519,7 +764,7 @@ send_to_port(Process *c_p, Eterm message, */ if ( c_p == NULL || - (! IS_TRACED_FL(c_p, F_TRACE_SCHED | F_TIMESTAMP))) { + (! IS_TRACED_FL(c_p, F_TRACE_SCHED | F_TIMESTAMP_MASK))) { #endif do_send_to_port(*tracer_pid, trace_port, @@ -538,22 +783,12 @@ send_to_port(Process *c_p, Eterm message, */ UseTmpHeapNoproc(LOCAL_HEAP_SIZE); - if (*tracee_flags & F_TIMESTAMP) { - ASSERT(is_tuple(message)); - hp = tuple_val(message); - ts = hp[arityval(hp[0])]; - } else { - /* A fake schedule might be needed, - * but this message does not contain a timestamp. - * Create a dummy trace message with timestamp to be - * passed to do_send_schedfix_to_port(). - */ - Uint ms,s,us; - GET_NOW(&ms, &s, &us); - hp = local_heap; - ts = TUPLE3(hp, make_small(ms), make_small(s), make_small(us)); - hp += 4; - } + /* A fake schedule might be needed. + * Create a dummy trace message with timestamp to be + * passed to do_send_schedfix_to_port(). + */ + ts_type = TFLGS_TS_TYPE(c_p); + ts = write_ts(ts_type, local_heap, NULL, NULL); trace_port->control_flags &= ~PORT_CONTROL_FLAG_HEAVY; do_send_to_port(*tracer_pid, @@ -572,7 +807,7 @@ send_to_port(Process *c_p, Eterm message, * just after writning the real trace message, and now gets scheduled * in again. */ - do_send_schedfix_to_port(trace_port, c_p->common.id, ts); + do_send_schedfix_to_port(trace_port, c_p->common.id, ts, ts_type); } erts_port_release(trace_port); @@ -641,20 +876,19 @@ profile_send(Eterm from, Eterm message) { /* A fake schedule out/in message pair will be sent, * if the driver so requests. - * If (timestamp == NIL), one is fetched from GET_NOW(). * * 'c_p' is the currently executing process, may be NULL. */ static void seq_trace_send_to_port(Process *c_p, Eterm seq_tracer, - Eterm message, - Eterm timestamp) + Eterm message) { Port* trace_port; #ifndef ERTS_SMP - Eterm ts, *hp; -#define LOCAL_HEAP_SIZE (4) + int ts_type; + Eterm ts; +#define LOCAL_HEAP_SIZE ERTS_TRACE_PATCH_TS_MAX_SIZE DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE); UseTmpHeapNoproc(LOCAL_HEAP_SIZE); #endif @@ -679,7 +913,7 @@ seq_trace_send_to_port(Process *c_p, } if (c_p == NULL - || (! IS_TRACED_FL(c_p, F_TRACE_SCHED | F_TIMESTAMP))) { + || (! IS_TRACED_FL(c_p, F_TRACE_SCHED | F_TIMESTAMP_MASK))) { #endif do_send_to_port(seq_tracer, trace_port, @@ -696,20 +930,12 @@ seq_trace_send_to_port(Process *c_p, * with 'running' and 'timestamp'. */ - if (timestamp != NIL) { - ts = timestamp; - } else { - /* A fake schedule might be needed, - * but this message does not contain a timestamp. - * Create a dummy trace message with timestamp to be - * passed to do_send_schedfix_to_port(). - */ - Uint ms,s,us; - GET_NOW(&ms, &s, &us); - hp = local_heap; - ts = TUPLE3(hp, make_small(ms), make_small(s), make_small(us)); - hp += 4; - } + /* A fake schedule might be needed. + * Create a dummy trace message with timestamp to be + * passed to do_send_schedfix_to_port(). + */ + ts_type = TFLGS_TS_TYPE(c_p); + ts = write_ts(ts_type, local_heap, NULL, NULL); trace_port->control_flags &= ~PORT_CONTROL_FLAG_HEAVY; do_send_to_port(seq_tracer, @@ -728,7 +954,7 @@ seq_trace_send_to_port(Process *c_p, * just after writing the real trace message, and now gets scheduled * in again. */ - do_send_schedfix_to_port(trace_port, c_p->common.id, ts); + do_send_schedfix_to_port(trace_port, c_p->common.id, ts, ts_type); } erts_port_release(trace_port); @@ -738,32 +964,6 @@ seq_trace_send_to_port(Process *c_p, #endif } -#define TS_HEAP_WORDS 5 -#define TS_SIZE(p) ((ERTS_TRACE_FLAGS((p)) & F_TIMESTAMP) \ - ? TS_HEAP_WORDS \ - : 0) - -/* - * Patch a timestamp into a tuple. The tuple must be the last thing - * built on the heap. - * - * Returns the new hp pointer. -*/ -static Eterm* -patch_ts(Eterm tuple, Eterm* hp) -{ - Uint ms, s, us; - Eterm* ptr = tuple_val(tuple); - int arity = arityval(*ptr); - - ASSERT((ptr+arity+1) == hp); - ptr[0] = make_arityval(arity+1); - ptr[1] = am_trace_ts; - GET_NOW(&ms, &s, &us); - *hp = TUPLE3(hp+1, make_small(ms), make_small(s), make_small(us)); - return hp+5; -} - static ERTS_INLINE void send_to_tracer(Process *tracee, ERTS_TRACER_REF_TYPE tracer_ref, @@ -776,13 +976,13 @@ send_to_tracer(Process *tracee, erts_smp_mtx_lock(&smq_mtx); - if (ERTS_TRACE_FLAGS(tracee) & F_TIMESTAMP) - *hpp = patch_ts(msg, *hpp); - - if (is_internal_pid(ERTS_TRACER_PROC(tracee))) + if (is_internal_pid(ERTS_TRACER_PROC(tracee))) { + PATCH_TS(TFLGS_TS_TYPE(tracee), msg, *hpp, bp, tracer_ref); ERTS_ENQ_TRACE_MSG(tracee->common.id, tracer_ref, msg, bp); + } else { ASSERT(is_internal_port(ERTS_TRACER_PROC(tracee))); + PATCH_TS(TFLGS_TS_TYPE(tracee), msg, *hpp, NULL, NULL); send_to_port(no_fake_sched ? NULL : tracee, msg, &ERTS_TRACER_PROC(tracee), @@ -796,7 +996,7 @@ send_to_tracer(Process *tracee, static void trace_sched_aux(Process *p, Eterm what, int never_fake_sched) { -#define LOCAL_HEAP_SIZE (5+4+1+TS_HEAP_WORDS) +#define LOCAL_HEAP_SIZE (5+4+1+ERTS_TRACE_PATCH_TS_MAX_SIZE) DeclareTmpHeap(local_heap,LOCAL_HEAP_SIZE,p); Eterm tmp, mess, *hp; ErlHeapFragment *bp = NULL; @@ -852,7 +1052,7 @@ trace_sched_aux(Process *p, Eterm what, int never_fake_sched) size += 4; if (sched_no) size += 1; - size += TS_SIZE(p); + size += PATCH_TS_SIZE(p); hp = ERTS_ALLOC_SYSMSG_HEAP(size, &bp, &off_heap, tracer_ref); } @@ -926,7 +1126,7 @@ trace_send(Process *p, Eterm to, Eterm msg) } if (is_internal_port(ERTS_TRACER_PROC(p))) { -#define LOCAL_HEAP_SIZE (11) +#define LOCAL_HEAP_SIZE (6 + ERTS_TRACE_PATCH_TS_MAX_SIZE) DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE); UseTmpHeapNoproc(LOCAL_HEAP_SIZE); @@ -934,9 +1134,7 @@ trace_send(Process *p, Eterm to, Eterm msg) mess = TUPLE5(hp, am_trace, p->common.id, operation, msg, to); hp += 6; erts_smp_mtx_lock(&smq_mtx); - if (ERTS_TRACE_FLAGS(p) & F_TIMESTAMP) { - hp = patch_ts(mess, hp); - } + PATCH_TS(TFLGS_TS_TYPE(p), mess, hp, NULL, NULL); send_to_port(p, mess, &ERTS_TRACER_PROC(p), &ERTS_TRACE_FLAGS(p)); UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE); #undef LOCAL_HEAP_SIZE @@ -955,7 +1153,7 @@ trace_send(Process *p, Eterm to, Eterm msg) sz_msg = size_object(msg); sz_to = size_object(to); - need = sz_msg + sz_to + 6 + TS_SIZE(p); + need = sz_msg + sz_to + 6 + PATCH_TS_SIZE(p); hp = ERTS_ALLOC_SYSMSG_HEAP(need, &bp, &off_heap, tracer_ref); @@ -972,10 +1170,7 @@ trace_send(Process *p, Eterm to, Eterm msg) erts_smp_mtx_lock(&smq_mtx); - if (ERTS_TRACE_FLAGS(p) & F_TIMESTAMP) { - patch_ts(mess, hp); - } - + PATCH_TS(TFLGS_TS_TYPE(p), mess, hp, bp, tracer_ref); ERTS_ENQ_TRACE_MSG(p->common.id, tracer_ref, mess, bp); erts_smp_mtx_unlock(&smq_mtx); } @@ -992,7 +1187,7 @@ trace_receive(Process *rp, Eterm msg) Eterm* hp; if (is_internal_port(ERTS_TRACER_PROC(rp))) { -#define LOCAL_HEAP_SIZE (10) +#define LOCAL_HEAP_SIZE (5+ERTS_TRACE_PATCH_TS_MAX_SIZE) DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE); UseTmpHeapNoproc(LOCAL_HEAP_SIZE); @@ -1000,9 +1195,7 @@ trace_receive(Process *rp, Eterm msg) mess = TUPLE4(hp, am_trace, rp->common.id, am_receive, msg); hp += 5; erts_smp_mtx_lock(&smq_mtx); - if (ERTS_TRACE_FLAGS(rp) & F_TIMESTAMP) { - hp = patch_ts(mess, hp); - } + PATCH_TS(TFLGS_TS_TYPE(rp), mess, hp, NULL, NULL); send_to_port(rp, mess, &ERTS_TRACER_PROC(rp), &ERTS_TRACE_FLAGS(rp)); UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE); #undef LOCAL_HEAP_SIZE @@ -1021,7 +1214,7 @@ trace_receive(Process *rp, Eterm msg) sz_msg = size_object(msg); - hsz = sz_msg + 5 + TS_SIZE(rp); + hsz = sz_msg + 5 + PATCH_TS_SIZE(rp); hp = ERTS_ALLOC_SYSMSG_HEAP(hsz, &bp, &off_heap, tracer_ref); @@ -1031,10 +1224,7 @@ trace_receive(Process *rp, Eterm msg) erts_smp_mtx_lock(&smq_mtx); - if (ERTS_TRACE_FLAGS(rp) & F_TIMESTAMP) { - patch_ts(mess, hp); - } - + PATCH_TS(TFLGS_TS_TYPE(rp), mess, hp, bp, tracer_ref); ERTS_ENQ_TRACE_MSG(rp->common.id, tracer_ref, mess, bp); erts_smp_mtx_unlock(&smq_mtx); } @@ -1084,6 +1274,7 @@ seq_trace_output_generic(Eterm token, Eterm msg, Uint type, Eterm type_atom; int sz_exit; Eterm seq_tracer; + int ts_type; seq_tracer = erts_get_system_seq_tracer(); @@ -1098,7 +1289,7 @@ seq_trace_output_generic(Eterm token, Eterm msg, Uint type, case SEQ_TRACE_PRINT: type_atom = am_print; break; case SEQ_TRACE_RECEIVE: type_atom = am_receive; break; default: - erl_exit(1, "invalid type in seq_trace_output_generic: %d:\n", type); + erts_exit(ERTS_ERROR_EXIT, "invalid type in seq_trace_output_generic: %d:\n", type); return; /* To avoid warning */ } @@ -1111,8 +1302,10 @@ seq_trace_output_generic(Eterm token, Eterm msg, Uint type, return; /* no need to send anything */ } + ts_type = ERTS_SEQTFLGS2TSTYPE(unsigned_val(SEQ_TRACE_T_FLAGS(token))); + if (is_internal_port(seq_tracer)) { -#define LOCAL_HEAP_SIZE (64) +#define LOCAL_HEAP_SIZE (60 + ERTS_TRACE_PATCH_TS_MAX_SIZE) DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE); UseTmpHeapNoproc(LOCAL_HEAP_SIZE); @@ -1128,17 +1321,17 @@ seq_trace_output_generic(Eterm token, Eterm msg, Uint type, mess = TUPLE5(hp, type_atom, lastcnt_serial, SEQ_TRACE_T_SENDER(token), receiver, msg); hp += 6; + erts_smp_mtx_lock(&smq_mtx); - if ((unsigned_val(SEQ_TRACE_T_FLAGS(token)) & SEQ_TRACE_TIMESTAMP) == 0) { + if (!ts_type) { mess = TUPLE3(hp, am_seq_trace, label, mess); - seq_trace_send_to_port(NULL, seq_tracer, mess, NIL); + seq_trace_send_to_port(NULL, seq_tracer, mess); } else { - Uint ms,s,us,ts; - GET_NOW(&ms, &s, &us); - ts = TUPLE3(hp, make_small(ms),make_small(s), make_small(us)); - hp += 4; - mess = TUPLE4(hp, am_seq_trace, label, mess, ts); - seq_trace_send_to_port(process, seq_tracer, mess, ts); + mess = TUPLE4(hp, am_seq_trace, label, mess, + NIL /* Will be overwritten by timestamp */); + hp += 5; + hp[-1] = write_ts(ts_type, hp, NULL, NULL); + seq_trace_send_to_port(process, seq_tracer, mess); } UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE); #undef LOCAL_HEAP_SIZE @@ -1173,8 +1366,7 @@ seq_trace_output_generic(Eterm token, Eterm msg, Uint type, sz_lastcnt_serial = 3; /* TUPLE2 */ sz_msg = size_object(msg); - sz_ts = ((unsigned_val(SEQ_TRACE_T_FLAGS(token)) & SEQ_TRACE_TIMESTAMP) ? - 5 : 0); + sz_ts = patch_ts_size(ts_type); if (exitfrom != NIL) { sz_exit = 4; /* create {'EXIT',exitfrom,msg} */ sz_exitfrom = size_object(exitfrom); @@ -1218,14 +1410,20 @@ seq_trace_output_generic(Eterm token, Eterm msg, Uint type, erts_smp_mtx_lock(&smq_mtx); - if (sz_ts) {/* timestamp should be included */ - Uint ms,s,us,ts; - GET_NOW(&ms, &s, &us); - ts = TUPLE3(hp, make_small(ms),make_small(s), make_small(us)); - hp += 4; - mess = TUPLE4(hp, am_seq_trace, label, mess, ts); - } else { + if (!ts_type) mess = TUPLE3(hp, am_seq_trace, label, mess); + else { + mess = TUPLE4(hp, am_seq_trace, label, mess, + NIL /* Will be overwritten by timestamp */); + hp += 5; + /* Write timestamp in element 6 of the 'msg' tuple */ + hp[-1] = write_ts(ts_type, hp, bp, +#ifndef ERTS_SMP + tracer +#else + NULL +#endif + ); } #ifdef ERTS_SMP @@ -1244,7 +1442,7 @@ seq_trace_output_generic(Eterm token, Eterm msg, Uint type, void erts_trace_return_to(Process *p, BeamInstr *pc) { -#define LOCAL_HEAP_SIZE (4+5+5) +#define LOCAL_HEAP_SIZE (4+5+ERTS_TRACE_PATCH_TS_MAX_SIZE) Eterm* hp; Eterm mfa; Eterm mess; @@ -1269,9 +1467,7 @@ erts_trace_return_to(Process *p, BeamInstr *pc) erts_smp_mtx_lock(&smq_mtx); - if (ERTS_TRACE_FLAGS(p) & F_TIMESTAMP) { - hp = patch_ts(mess, hp); - } + PATCH_TS(TFLGS_TS_TYPE(p), mess, hp, NULL, NULL); if (is_internal_port(ERTS_TRACER_PROC(p))) { send_to_port(p, mess, &ERTS_TRACER_PROC(p), &ERTS_TRACE_FLAGS(p)); @@ -1318,6 +1514,7 @@ erts_trace_return(Process* p, BeamInstr* fi, Eterm retval, Eterm *tracer_pid) Eterm mod, name; int arity; Uint meta_flags, *tracee_flags; + int ts_type; #ifdef ERTS_SMP Eterm tracee; #endif @@ -1353,7 +1550,7 @@ erts_trace_return(Process* p, BeamInstr* fi, Eterm retval, Eterm *tracer_pid) * meta trace => * use fixed flag set instead of process flags */ - meta_flags = F_TRACE_CALLS | F_TIMESTAMP; + meta_flags = F_TRACE_CALLS | F_NOW_TS; tracee_flags = &meta_flags; #ifdef ERTS_SMP tracee = NIL; @@ -1367,8 +1564,10 @@ erts_trace_return(Process* p, BeamInstr* fi, Eterm retval, Eterm *tracer_pid) name = fi[1]; arity = fi[2]; + ts_type = ERTS_TFLGS2TSTYPE(*tracee_flags); + if (is_internal_port(*tracer_pid)) { -#define LOCAL_HEAP_SIZE (4+6+5) +#define LOCAL_HEAP_SIZE (4+6+ERTS_TRACE_PATCH_TS_MAX_SIZE) DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE); UseTmpHeapNoproc(LOCAL_HEAP_SIZE); hp = local_heap; @@ -1377,9 +1576,7 @@ erts_trace_return(Process* p, BeamInstr* fi, Eterm retval, Eterm *tracer_pid) mess = TUPLE5(hp, am_trace, p->common.id, am_return_from, mfa, retval); hp += 6; erts_smp_mtx_lock(&smq_mtx); - if (*tracee_flags & F_TIMESTAMP) { - hp = patch_ts(mess, hp); - } + PATCH_TS(ts_type, mess, hp, NULL, NULL); send_to_port(p, mess, tracer_pid, tracee_flags); UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE); #undef LOCAL_HEAP_SIZE @@ -1390,24 +1587,15 @@ erts_trace_return(Process* p, BeamInstr* fi, Eterm retval, Eterm *tracer_pid) ERTS_TRACER_REF_TYPE tracer_ref; unsigned size; unsigned retval_size; -#ifdef DEBUG - Eterm* limit; -#endif ASSERT(is_internal_pid(*tracer_pid)); ERTS_GET_TRACER_REF(tracer_ref, *tracer_pid, *tracee_flags); - + retval_size = size_object(retval); - size = 6 + 4 + retval_size; - if (*tracee_flags & F_TIMESTAMP) { - size += 1+4; - } + size = 6 + 4 + retval_size + patch_ts_size(ts_type); hp = ERTS_ALLOC_SYSMSG_HEAP(size, &bp, &off_heap, tracer_ref); -#ifdef DEBUG - limit = hp + size; -#endif /* * Build the trace tuple and put it into receive queue of the tracer process. @@ -1421,11 +1609,7 @@ erts_trace_return(Process* p, BeamInstr* fi, Eterm retval, Eterm *tracer_pid) erts_smp_mtx_lock(&smq_mtx); - if (*tracee_flags & F_TIMESTAMP) { - hp = patch_ts(mess, hp); - } - - ASSERT(hp == limit); + PATCH_TS(ts_type, mess, hp, bp, tracer_ref); ERTS_ENQ_TRACE_MSG(tracee, tracer_ref, mess, bp); erts_smp_mtx_unlock(&smq_mtx); @@ -1448,6 +1632,7 @@ erts_trace_exception(Process* p, BeamInstr mfa[3], Eterm class, Eterm value, Eterm cv; Eterm mess; Uint meta_flags, *tracee_flags; + int ts_type; #ifdef ERTS_SMP Eterm tracee; #endif @@ -1486,15 +1671,17 @@ erts_trace_exception(Process* p, BeamInstr mfa[3], Eterm class, Eterm value, * meta trace => * use fixed flag set instead of process flags */ - meta_flags = F_TRACE_CALLS | F_TIMESTAMP; + meta_flags = F_TRACE_CALLS | F_NOW_TS; tracee_flags = &meta_flags; #ifdef ERTS_SMP tracee = NIL; #endif } + ts_type = ERTS_TFLGS2TSTYPE(*tracee_flags); + if (is_internal_port(*tracer_pid)) { -#define LOCAL_HEAP_SIZE (4+3+6+5) +#define LOCAL_HEAP_SIZE (4+3+6+ERTS_TRACE_PATCH_TS_MAX_SIZE) DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE); UseTmpHeapNoproc(LOCAL_HEAP_SIZE); @@ -1507,10 +1694,7 @@ erts_trace_exception(Process* p, BeamInstr mfa[3], Eterm class, Eterm value, hp += 6; ASSERT((hp - local_heap) <= LOCAL_HEAP_SIZE); erts_smp_mtx_lock(&smq_mtx); - if (*tracee_flags & F_TIMESTAMP) { - hp = patch_ts(mess, hp); /* hp += 5 */ - ASSERT((hp - local_heap) == LOCAL_HEAP_SIZE); - } + PATCH_TS(ts_type, mess, hp, NULL, NULL); send_to_port(p, mess, tracer_pid, tracee_flags); UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE); #undef LOCAL_HEAP_SIZE @@ -1521,24 +1705,15 @@ erts_trace_exception(Process* p, BeamInstr mfa[3], Eterm class, Eterm value, ERTS_TRACER_REF_TYPE tracer_ref; unsigned size; unsigned value_size; -#ifdef DEBUG - Eterm* limit; -#endif ASSERT(is_internal_pid(*tracer_pid)); ERTS_GET_TRACER_REF(tracer_ref, *tracer_pid, *tracee_flags); value_size = size_object(value); - size = 6 + 4 + 3 + value_size; - if (*tracee_flags & F_TIMESTAMP) { - size += 1+4; - } + size = 6 + 4 + 3 + value_size + patch_ts_size(ts_type); hp = ERTS_ALLOC_SYSMSG_HEAP(size, &bp, &off_heap, tracer_ref); -#ifdef DEBUG - limit = hp + size; -#endif /* * Build the trace tuple and put it into receive queue of the tracer process. @@ -1555,11 +1730,7 @@ erts_trace_exception(Process* p, BeamInstr mfa[3], Eterm class, Eterm value, erts_smp_mtx_lock(&smq_mtx); - if (*tracee_flags & F_TIMESTAMP) { - hp = patch_ts(mess, hp); - } - - ASSERT(hp == limit); + PATCH_TS(ts_type, mess, hp, bp, tracer_ref); ERTS_ENQ_TRACE_MSG(tracee, tracer_ref, mess, bp); erts_smp_mtx_unlock(&smq_mtx); @@ -1592,6 +1763,7 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec, Eterm pam_result = am_true; Eterm mess; Uint meta_flags, *tracee_flags; + int ts_type; #ifdef ERTS_SMP Eterm tracee; #endif @@ -1633,7 +1805,7 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec, /* No trace messages for sensitive processes. */ return 0; } - meta_flags = F_TRACE_CALLS | F_TIMESTAMP; + meta_flags = F_TRACE_CALLS | F_NOW_TS; tracee_flags = &meta_flags; #ifdef ERTS_SMP tracee = NIL; @@ -1676,12 +1848,14 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec, } args = transformed_args; + ts_type = ERTS_TFLGS2TSTYPE(*tracee_flags); + if (is_internal_port(*tracer_pid)) { #if HEAP_ON_C_STACK - Eterm local_heap[64+MAX_ARG]; + Eterm local_heap[60+ERTS_TRACE_PATCH_TS_MAX_SIZE+MAX_ARG]; #else Eterm *local_heap = erts_alloc(ERTS_ALC_T_TEMP_TERM, - sizeof(Eterm)*(64+MAX_ARG)); + sizeof(Eterm)*(60+ERTS_TRACE_PATCH_TS_MAX_SIZE+MAX_ARG)); #endif hp = local_heap; @@ -1796,9 +1970,7 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec, *hp++ = pam_result; } erts_smp_mtx_lock(&smq_mtx); - if (*tracee_flags & F_TIMESTAMP) { - hp = patch_ts(mess, hp); - } + PATCH_TS(ts_type, mess, hp, NULL, NULL); send_to_port(p, mess, tracer_pid, tracee_flags); erts_smp_mtx_unlock(&smq_mtx); erts_match_set_release_result(p); @@ -1820,9 +1992,6 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec, unsigned sizes[MAX_ARG]; unsigned pam_result_size = 0; int invalid_tracer; -#ifdef DEBUG - Eterm* limit; -#endif ASSERT(is_internal_pid(*tracer_pid)); @@ -1915,10 +2084,7 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec, size += sizes[i]; } } - if (*tracee_flags & F_TIMESTAMP) { - size += 1 + 4; - /* One element in trace tuple + timestamp tuple. */ - } + size += patch_ts_size(ts_type); if (pam_result != am_true) { pam_result_size = size_object(pam_result); size += 1 + pam_result_size; @@ -1926,9 +2092,6 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec, } hp = ERTS_ALLOC_SYSMSG_HEAP(size, &bp, &off_heap, tracer_ref); -#ifdef DEBUG - limit = hp + size; -#endif /* * Build the the {M,F,A} tuple in the message buffer. @@ -1971,11 +2134,7 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec, erts_smp_mtx_lock(&smq_mtx); - if (*tracee_flags & F_TIMESTAMP) { - hp = patch_ts(mess, hp); - } - - ASSERT(hp == limit); + PATCH_TS(ts_type, mess, hp, bp, tracer_ref); ERTS_ENQ_TRACE_MSG(tracee, tracer_ref, mess, bp); erts_smp_mtx_unlock(&smq_mtx); UnUseTmpHeap(ERL_SUB_BIN_SIZE,p); @@ -2010,9 +2169,7 @@ trace_proc(Process *c_p, Process *t_p, Eterm what, Eterm data) mess = TUPLE4(hp, am_trace, t_p->common.id, what, data); hp += 5; erts_smp_mtx_lock(&smq_mtx); - if (ERTS_TRACE_FLAGS(t_p) & F_TIMESTAMP) { - hp = patch_ts(mess, hp); - } + PATCH_TS(TFLGS_TS_TYPE(t_p), mess, hp, NULL, NULL); send_to_port( #ifndef ERTS_SMP /* No fake schedule out and in again after an exit */ @@ -2042,7 +2199,7 @@ trace_proc(Process *c_p, Process *t_p, Eterm what, Eterm data) sz_data = size_object(data); - need = sz_data + 5 + TS_SIZE(t_p); + need = sz_data + 5 + PATCH_TS_SIZE(t_p); hp = ERTS_ALLOC_SYSMSG_HEAP(need, &bp, &off_heap, tracer_ref); @@ -2052,9 +2209,7 @@ trace_proc(Process *c_p, Process *t_p, Eterm what, Eterm data) erts_smp_mtx_lock(&smq_mtx); - if (ERTS_TRACE_FLAGS(t_p) & F_TIMESTAMP) { - hp = patch_ts(mess, hp); - } + PATCH_TS(TFLGS_TS_TYPE(t_p), mess, hp, bp, tracer_ref); ERTS_ENQ_TRACE_MSG(t_p->common.id, tracer_ref, mess, bp); erts_smp_mtx_unlock(&smq_mtx); @@ -2088,9 +2243,7 @@ trace_proc_spawn(Process *p, Eterm pid, mess = TUPLE5(hp, am_trace, p->common.id, am_spawn, pid, mfa); hp += 6; erts_smp_mtx_lock(&smq_mtx); - if (ERTS_TRACE_FLAGS(p) & F_TIMESTAMP) { - hp = patch_ts(mess, hp); - } + PATCH_TS(TFLGS_TS_TYPE(p), mess, hp, NULL, NULL); send_to_port(p, mess, &ERTS_TRACER_PROC(p), &ERTS_TRACE_FLAGS(p)); UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE); #undef LOCAL_HEAP_SIZE @@ -2111,7 +2264,7 @@ trace_proc_spawn(Process *p, Eterm pid, sz_args = size_object(args); sz_pid = size_object(pid); - need = sz_args + 4 + 6 + TS_SIZE(p); + need = sz_args + 4 + 6 + PATCH_TS_SIZE(p); hp = ERTS_ALLOC_SYSMSG_HEAP(need, &bp, &off_heap, tracer_ref); @@ -2124,9 +2277,7 @@ trace_proc_spawn(Process *p, Eterm pid, erts_smp_mtx_lock(&smq_mtx); - if (ERTS_TRACE_FLAGS(p) & F_TIMESTAMP) { - hp = patch_ts(mess, hp); - } + PATCH_TS(TFLGS_TS_TYPE(p), mess, hp, bp, tracer_ref); ERTS_ENQ_TRACE_MSG(p->common.id, tracer_ref, mess, bp); erts_smp_mtx_unlock(&smq_mtx); @@ -2208,11 +2359,8 @@ trace_gc(Process *p, Eterm what) #define LOCAL_HEAP_SIZE \ (sizeof(values)/sizeof(*values)) * \ (2/*cons*/ + 3/*2-tuple*/ + BIG_UINT_HEAP_SIZE) + \ - 5/*4-tuple */ + TS_HEAP_WORDS + 5/*4-tuple */ + ERTS_TRACE_PATCH_TS_MAX_SIZE DeclareTmpHeap(local_heap,LOCAL_HEAP_SIZE,p); -#ifdef DEBUG - Eterm* limit; -#endif ERTS_CT_ASSERT(sizeof(values)/sizeof(*values) == sizeof(tags)/sizeof(Eterm)); @@ -2227,7 +2375,7 @@ trace_gc(Process *p, Eterm what) sizeof(values)/sizeof(*values), tags, values); - size += 5/*4-tuple*/ + TS_SIZE(p); + size += 5/*4-tuple*/ + PATCH_TS_SIZE(p); #endif } else { ASSERT(is_internal_pid(ERTS_TRACER_PROC(p))); @@ -2242,15 +2390,12 @@ trace_gc(Process *p, Eterm what) sizeof(values)/sizeof(*values), tags, values); - size += 5/*4-tuple*/ + TS_SIZE(p); + size += 5/*4-tuple*/ + PATCH_TS_SIZE(p); hp = ERTS_ALLOC_SYSMSG_HEAP(size, &bp, &off_heap, tracer_ref); } -#ifdef DEBUG - limit = hp + size; ASSERT(size <= LOCAL_HEAP_SIZE); -#endif msg = erts_bld_atom_uword_2tup_list(&hp, NULL, @@ -2263,14 +2408,14 @@ trace_gc(Process *p, Eterm what) erts_smp_mtx_lock(&smq_mtx); - if (ERTS_TRACE_FLAGS(p) & F_TIMESTAMP) { - hp = patch_ts(msg, hp); - } - ASSERT(hp == limit); - if (is_internal_port(ERTS_TRACER_PROC(p))) + if (is_internal_port(ERTS_TRACER_PROC(p))) { + PATCH_TS(TFLGS_TS_TYPE(p), msg, hp, NULL, NULL); send_to_port(p, msg, &ERTS_TRACER_PROC(p), &ERTS_TRACE_FLAGS(p)); - else + } + else { + PATCH_TS(TFLGS_TS_TYPE(p), msg, hp, bp, tracer_ref); ERTS_ENQ_TRACE_MSG(p->common.id, tracer_ref, msg, bp); + } erts_smp_mtx_unlock(&smq_mtx); UnUseTmpHeap(LOCAL_HEAP_SIZE,p); #undef LOCAL_HEAP_SIZE @@ -2574,19 +2719,18 @@ monitor_generic(Process *p, Eterm type, Eterm spec) { void profile_scheduler(Eterm scheduler_id, Eterm state) { - Eterm *hp, msg, timestamp; - Uint Ms, s, us; + Eterm *hp, msg; + ErlHeapFragment *bp = NULL; #ifndef ERTS_SMP -#define LOCAL_HEAP_SIZE (4 + 7) +#define LOCAL_HEAP_SIZE (7 + ERTS_TRACE_PATCH_TS_MAX_SIZE) DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE); UseTmpHeapNoproc(LOCAL_HEAP_SIZE); hp = local_heap; #else - ErlHeapFragment *bp; Uint hsz; - hsz = 4 + 7; + hsz = 7 + patch_ts_size(erts_system_profile_ts_type)-1; bp = new_message_buffer(hsz); hp = bp->mem; @@ -2606,10 +2750,13 @@ profile_scheduler(Eterm scheduler_id, Eterm state) { break; } - GET_NOW(&Ms, &s, &us); - timestamp = TUPLE3(hp, make_small(Ms), make_small(s), make_small(us)); hp += 4; - msg = TUPLE6(hp, am_profile, am_scheduler, scheduler_id, state, - make_small(active_sched), timestamp); hp += 7; + msg = TUPLE6(hp, am_profile, am_scheduler, scheduler_id, + state, make_small(active_sched), + NIL /* Will be overwritten by timestamp */); + hp += 7; + + /* Write timestamp in element 6 of the 'msg' tuple */ + hp[-1] = write_ts(erts_system_profile_ts_type, hp, bp, NULL); #ifndef ERTS_SMP profile_send(NIL, msg); @@ -2680,7 +2827,7 @@ trace_port_open(Port *p, Eterm calling_pid, Eterm drv_name) { Eterm* hp; if (is_internal_port(ERTS_TRACER_PROC(p))) { -#define LOCAL_HEAP_SIZE (5+6) +#define LOCAL_HEAP_SIZE (6+ERTS_TRACE_PATCH_TS_MAX_SIZE) DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE); UseTmpHeapNoproc(LOCAL_HEAP_SIZE); @@ -2689,9 +2836,7 @@ trace_port_open(Port *p, Eterm calling_pid, Eterm drv_name) { mess = TUPLE5(hp, am_trace, calling_pid, am_open, p->common.id, drv_name); hp += 6; erts_smp_mtx_lock(&smq_mtx); - if (ERTS_TRACE_FLAGS(p) & F_TIMESTAMP) { - hp = patch_ts(mess, hp); - } + PATCH_TS(TFLGS_TS_TYPE(p), mess, hp, NULL, NULL); /* No fake schedule */ send_to_port(NULL, mess, &ERTS_TRACER_PROC(p), &ERTS_TRACE_FLAGS(p)); UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE); @@ -2705,7 +2850,7 @@ trace_port_open(Port *p, Eterm calling_pid, Eterm drv_name) { ASSERT(is_internal_pid(ERTS_TRACER_PROC(p))); - sz_data = 6 + TS_SIZE(p); + sz_data = 6 + PATCH_TS_SIZE(p); ERTS_GET_TRACER_REF(tracer_ref, ERTS_TRACER_PROC(p), @@ -2718,9 +2863,7 @@ trace_port_open(Port *p, Eterm calling_pid, Eterm drv_name) { erts_smp_mtx_lock(&smq_mtx); - if (ERTS_TRACE_FLAGS(p) & F_TIMESTAMP) { - hp = patch_ts(mess, hp); - } + PATCH_TS(TFLGS_TS_TYPE(p), mess, hp, bp, tracer_ref); ERTS_ENQ_TRACE_MSG(p->common.id, tracer_ref, mess, bp); erts_smp_mtx_unlock(&smq_mtx); @@ -2744,7 +2887,7 @@ trace_port(Port *t_p, Eterm what, Eterm data) { || erts_thr_progress_is_blocking()); if (is_internal_port(ERTS_TRACER_PROC(t_p))) { -#define LOCAL_HEAP_SIZE (5+5) +#define LOCAL_HEAP_SIZE (5+ERTS_TRACE_PATCH_TS_MAX_SIZE) DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE); UseTmpHeapNoproc(LOCAL_HEAP_SIZE); @@ -2752,9 +2895,7 @@ trace_port(Port *t_p, Eterm what, Eterm data) { mess = TUPLE4(hp, am_trace, t_p->common.id, what, data); hp += 5; erts_smp_mtx_lock(&smq_mtx); - if (ERTS_TRACE_FLAGS(t_p) & F_TIMESTAMP) { - hp = patch_ts(mess, hp); - } + PATCH_TS(TFLGS_TS_TYPE(t_p), mess, hp, NULL, NULL); /* No fake schedule */ send_to_port(NULL,mess,&ERTS_TRACER_PROC(t_p),&ERTS_TRACE_FLAGS(t_p)); UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE); @@ -2768,7 +2909,7 @@ trace_port(Port *t_p, Eterm what, Eterm data) { ASSERT(is_internal_pid(ERTS_TRACER_PROC(t_p))); - sz_data = 5 + TS_SIZE(t_p); + sz_data = 5 + PATCH_TS_SIZE(t_p); ERTS_GET_TRACER_REF(tracer_ref, ERTS_TRACER_PROC(t_p), @@ -2781,9 +2922,7 @@ trace_port(Port *t_p, Eterm what, Eterm data) { erts_smp_mtx_lock(&smq_mtx); - if (ERTS_TRACE_FLAGS(t_p) & F_TIMESTAMP) { - hp = patch_ts(mess, hp); - } + PATCH_TS(TFLGS_TS_TYPE(t_p), mess, hp, bp, tracer_ref); ERTS_ENQ_TRACE_MSG(t_p->common.id, tracer_ref, mess, bp); erts_smp_mtx_unlock(&smq_mtx); @@ -2811,7 +2950,7 @@ trace_sched_ports_where(Port *p, Eterm what, Eterm where) { Eterm sched_id = am_undefined; if (is_internal_port(ERTS_TRACER_PROC(p))) { -#define LOCAL_HEAP_SIZE (5+6) +#define LOCAL_HEAP_SIZE (6+ERTS_TRACE_PATCH_TS_MAX_SIZE) DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE); UseTmpHeapNoproc(LOCAL_HEAP_SIZE); @@ -2834,9 +2973,8 @@ trace_sched_ports_where(Port *p, Eterm what, Eterm where) { hp += ws; erts_smp_mtx_lock(&smq_mtx); - if (ERTS_TRACE_FLAGS(p) & F_TIMESTAMP) { - hp = patch_ts(mess, hp); - } + + PATCH_TS(TFLGS_TS_TYPE(p), mess, hp, NULL, NULL); /* No fake scheduling */ send_to_port(NULL, mess, &ERTS_TRACER_PROC(p), &ERTS_TRACE_FLAGS(p)); @@ -2856,7 +2994,7 @@ trace_sched_ports_where(Port *p, Eterm what, Eterm where) { ERTS_TRACER_PROC(p), ERTS_TRACE_FLAGS(p)); - hp = ERTS_ALLOC_SYSMSG_HEAP(ws+TS_SIZE(p), &bp, &off_heap, tracer_ref); + hp = ERTS_ALLOC_SYSMSG_HEAP(ws+PATCH_TS_SIZE(p), &bp, &off_heap, tracer_ref); if (IS_TRACED_FL(p, F_TRACE_SCHED_NO)) { #ifdef ERTS_SMP @@ -2874,10 +3012,7 @@ trace_sched_ports_where(Port *p, Eterm what, Eterm where) { erts_smp_mtx_lock(&smq_mtx); - if (ERTS_TRACE_FLAGS(p) & F_TIMESTAMP) { - hp = patch_ts(mess, hp); - } - + PATCH_TS(TFLGS_TS_TYPE(p), mess, hp, bp, tracer_ref); ERTS_ENQ_TRACE_MSG(p->common.id, tracer_ref, mess, bp); erts_smp_mtx_unlock(&smq_mtx); } @@ -2887,13 +3022,12 @@ trace_sched_ports_where(Port *p, Eterm what, Eterm where) { void profile_runnable_port(Port *p, Eterm status) { - Uint Ms, s, us; - Eterm *hp, msg, timestamp; - + Eterm *hp, msg; + ErlHeapFragment *bp = NULL; Eterm count = make_small(0); #ifndef ERTS_SMP -#define LOCAL_HEAP_SIZE (4 + 6) +#define LOCAL_HEAP_SIZE (6 + ERTS_TRACE_PATCH_TS_MAX_SIZE) DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE); UseTmpHeapNoproc(LOCAL_HEAP_SIZE); @@ -2901,10 +3035,9 @@ profile_runnable_port(Port *p, Eterm status) { hp = local_heap; #else - ErlHeapFragment *bp; Uint hsz; - hsz = 4 + 6; + hsz = 6 + patch_ts_size(erts_system_profile_ts_type)-1; bp = new_message_buffer(hsz); hp = bp->mem; @@ -2912,9 +3045,12 @@ profile_runnable_port(Port *p, Eterm status) { erts_smp_mtx_lock(&smq_mtx); - GET_NOW(&Ms, &s, &us); - timestamp = TUPLE3(hp, make_small(Ms), make_small(s), make_small(us)); hp += 4; - msg = TUPLE5(hp, am_profile, p->common.id, status, count, timestamp); hp += 6; + msg = TUPLE5(hp, am_profile, p->common.id, status, count, + NIL /* Will be overwritten by timestamp */); + hp += 6; + + /* Write timestamp in element 5 of the 'msg' tuple */ + hp[-1] = write_ts(erts_system_profile_ts_type, hp, bp, NULL); #ifndef ERTS_SMP profile_send(p->common.id, msg); @@ -2929,20 +3065,19 @@ profile_runnable_port(Port *p, Eterm status) { /* Process profiling */ void profile_runnable_proc(Process *p, Eterm status){ - Uint Ms, s, us; - Eterm *hp, msg, timestamp; + Eterm *hp, msg; Eterm where = am_undefined; + ErlHeapFragment *bp = NULL; #ifndef ERTS_SMP -#define LOCAL_HEAP_SIZE (4 + 6 + 4) +#define LOCAL_HEAP_SIZE (4 + 6 + ERTS_TRACE_PATCH_TS_MAX_SIZE) DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE); UseTmpHeapNoproc(LOCAL_HEAP_SIZE); hp = local_heap; #else - ErlHeapFragment *bp; - Uint hsz = 4 + 6 + 4; + Uint hsz = 4 + 6 + patch_ts_size(erts_system_profile_ts_type)-1; #endif if (!p->current) { @@ -2951,7 +3086,7 @@ profile_runnable_proc(Process *p, Eterm status){ #ifdef ERTS_SMP if (!p->current) { - hsz = 4 + 6; + hsz -= 4; } bp = new_message_buffer(hsz); @@ -2966,9 +3101,13 @@ profile_runnable_proc(Process *p, Eterm status){ erts_smp_mtx_lock(&smq_mtx); - GET_NOW(&Ms, &s, &us); - timestamp = TUPLE3(hp, make_small(Ms), make_small(s), make_small(us)); hp += 4; - msg = TUPLE5(hp, am_profile, p->common.id, status, where, timestamp); hp += 6; + msg = TUPLE5(hp, am_profile, p->common.id, status, where, + NIL /* Will be overwritten by timestamp */); + hp += 6; + + /* Write timestamp in element 5 of the 'msg' tuple */ + hp[-1] = write_ts(erts_system_profile_ts_type, hp, bp, NULL); + #ifndef ERTS_SMP profile_send(p->common.id, msg); UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE); diff --git a/erts/emulator/beam/erl_trace.h b/erts/emulator/beam/erl_trace.h index 7405490f76..a0058264d7 100644 --- a/erts/emulator/beam/erl_trace.h +++ b/erts/emulator/beam/erl_trace.h @@ -18,8 +18,38 @@ * %CopyrightEnd% */ +#ifndef ERL_TRACE_H__FLAGS__ +#define ERL_TRACE_H__FLAGS__ +/* + * NOTE! The bits used for these flags matter. The flag with + * the least significant bit will take precedence! + * + * The "now timestamp" has highest precedence due to + * compatibility reasons. + */ +#define ERTS_TRACE_FLG_NOW_TIMESTAMP (1 << 0) +#define ERTS_TRACE_FLG_STRICT_MONOTONIC_TIMESTAMP (1 << 1) +#define ERTS_TRACE_FLG_MONOTONIC_TIMESTAMP (1 << 2) + +/* + * The bits used effects trace flags (of processes and ports) + * as well as sequential trace flags. If changed make sure + * these arn't messed up... + */ +#define ERTS_TRACE_TS_TYPE_BITS 3 +#define ERTS_TRACE_TS_TYPE_MASK \ + ((1 << ERTS_TRACE_TS_TYPE_BITS) - 1) + +#define ERTS_TFLGS2TSTYPE(TFLGS) \ + ((int) (((TFLGS) >> ERTS_TRACE_FLAGS_TS_TYPE_SHIFT) \ + & ERTS_TRACE_TS_TYPE_MASK)) +#define ERTS_SEQTFLGS2TSTYPE(SEQTFLGS) \ + ((int) (((SEQTFLGS) >> ERTS_SEQ_TRACE_FLAGS_TS_TYPE_SHIFT) \ + & ERTS_TRACE_TS_TYPE_MASK)) + +#endif /* ERL_TRACE_H__FLAGS__ */ -#ifndef ERL_TRACE_H__ +#if !defined(ERL_TRACE_H__) && !defined(ERTS_ONLY_INCLUDE_TRACE_FLAGS) #define ERL_TRACE_H__ struct binary; diff --git a/erts/emulator/beam/erl_unicode.c b/erts/emulator/beam/erl_unicode.c index 551717139d..36d85b0a22 100644 --- a/erts/emulator/beam/erl_unicode.c +++ b/erts/emulator/beam/erl_unicode.c @@ -2507,7 +2507,7 @@ void erts_copy_utf8_to_utf16_little(byte *target, byte *bytes, int num_chars) ((Uint) (bytes[3] & ((byte) 0x3F))); bytes += 4; } else { - erl_exit(1,"Internal unicode error in prim_file:internal_name2native/1"); + erts_exit(ERTS_ERROR_EXIT,"Internal unicode error in prim_file:internal_name2native/1"); } *target++ = (byte) (unipoint & 0xFF); *target++ = (byte) ((unipoint >> 8) & 0xFF); diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c index c6d7e3fcc5..ffe3303796 100644 --- a/erts/emulator/beam/external.c +++ b/erts/emulator/beam/external.c @@ -570,7 +570,7 @@ void erts_encode_ext(Eterm term, byte **ext) *ep++ = VERSION_MAGIC; ep = enc_term(NULL, term, ep, TERM_TO_BINARY_DFLAGS, NULL); if (!ep) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%s:%d:erts_encode_ext(): Internal data structure error\n", __FILE__, __LINE__); *ext = ep; @@ -1179,7 +1179,7 @@ typedef struct { ErtsHeapFactory factory; int remaining_n; char* remaining_bytes; - Eterm* maps_list; + ErtsWStack flat_maps; ErtsPStack hamt_array; } B2TDecodeContext; @@ -1519,7 +1519,7 @@ static BIF_RETTYPE binary_to_term_int(Process* p, Uint32 flags, Eterm bin, Binar ctx->u.dc.res = (Eterm) (UWord) NULL; ctx->u.dc.next = &ctx->u.dc.res; erts_factory_proc_prealloc_init(&ctx->u.dc.factory, p, ctx->heap_size); - ctx->u.dc.maps_list = NULL; + ctx->u.dc.flat_maps.wstart = NULL; ctx->u.dc.hamt_array.pstart = NULL; ctx->state = B2TDecode; /*fall through*/ @@ -1559,7 +1559,7 @@ static BIF_RETTYPE binary_to_term_int(Process* p, Uint32 flags, Eterm bin, Binar b2t_destroy_context(ctx); if (ctx->u.dc.factory.hp > ctx->u.dc.factory.hp_end) { - erl_exit(1, ":%s, line %d: heap overrun by %d words(s)\n", + erts_exit(ERTS_ERROR_EXIT, ":%s, line %d: heap overrun by %d words(s)\n", __FILE__, __LINE__, ctx->u.dc.factory.hp - ctx->u.dc.factory.hp_end); } erts_factory_close(&ctx->u.dc.factory); @@ -1708,12 +1708,12 @@ erts_term_to_binary_simple(Process* p, Eterm Term, Uint size, int level, Uint fl if ((endp = enc_term(NULL, Term, bytes, flags, NULL)) == NULL) { - erl_exit(1, "%s, line %d: bad term: %x\n", + erts_exit(ERTS_ERROR_EXIT, "%s, line %d: bad term: %x\n", __FILE__, __LINE__, Term); } real_size = endp - bytes; if (real_size > size) { - erl_exit(1, "%s, line %d: buffer overflow: %d word(s)\n", + erts_exit(ERTS_ERROR_EXIT, "%s, line %d: buffer overflow: %d word(s)\n", __FILE__, __LINE__, real_size - size); } @@ -1753,12 +1753,12 @@ erts_term_to_binary_simple(Process* p, Eterm Term, Uint size, int level, Uint fl bytes[0] = VERSION_MAGIC; if ((endp = enc_term(NULL, Term, bytes+1, flags, NULL)) == NULL) { - erl_exit(1, "%s, line %d: bad term: %x\n", + erts_exit(ERTS_ERROR_EXIT, "%s, line %d: bad term: %x\n", __FILE__, __LINE__, Term); } real_size = endp - bytes; if (real_size > size) { - erl_exit(1, "%s, line %d: buffer overflow: %d word(s)\n", + erts_exit(ERTS_ERROR_EXIT, "%s, line %d: buffer overflow: %d word(s)\n", __FILE__, __LINE__, endp - (bytes + size)); } return erts_realloc_binary(bin, real_size); @@ -2650,7 +2650,7 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, ASSERT(node_sz < 17); break; default: - erl_exit(1, "bad header\r\n"); + erts_exit(ERTS_ERROR_EXIT, "bad header\r\n"); } ptr++; @@ -2938,7 +2938,7 @@ dec_term(ErtsDistExternal *edep, int n; ErtsAtomEncoding char_enc; register Eterm* hp; /* Please don't take the address of hp */ - Eterm *maps_list; /* for preprocessing of small maps */ + DECLARE_WSTACK(flat_maps); /* for preprocessing of small maps */ Eterm* next; SWord reds; #ifdef DEBUG @@ -2950,7 +2950,6 @@ dec_term(ErtsDistExternal *edep, next = ctx->u.dc.next; ep = ctx->u.dc.ep; factory = &ctx->u.dc.factory; - maps_list = ctx->u.dc.maps_list; if (ctx->state != B2TDecode) { int n_limit = reds; @@ -3026,15 +3025,18 @@ dec_term(ErtsDistExternal *edep, } } PSTACK_CHANGE_ALLOCATOR(hamt_array, ERTS_ALC_T_SAVED_ESTACK); + WSTACK_CHANGE_ALLOCATOR(flat_maps, ERTS_ALC_T_SAVED_ESTACK); if (ctx->u.dc.hamt_array.pstart) { PSTACK_RESTORE(hamt_array, &ctx->u.dc.hamt_array); } + if (ctx->u.dc.flat_maps.wstart) { + WSTACK_RESTORE(flat_maps, &ctx->u.dc.flat_maps); + } } else { reds = ERTS_SWORD_MAX; next = objp; *next = (Eterm) (UWord) NULL; - maps_list = NULL; } hp = factory->hp; @@ -3595,14 +3597,8 @@ dec_term_atom_common: * vptr, last word for values */ - /* - * Use thing_word to link through decoded maps. - * The list of maps is for later validation. - */ - - mp->thing_word = (Eterm) COMPRESS_POINTER(maps_list); - maps_list = (Eterm *) mp; - + WSTACK_PUSH(flat_maps, (UWord)mp); + mp->thing_word = MAP_HEADER_FLATMAP; mp->size = size; mp->keys = keys; *objp = make_flatmap(mp); @@ -3851,7 +3847,9 @@ dec_term_atom_common: ctx->u.dc.ep = ep; ctx->u.dc.next = next; ctx->u.dc.factory.hp = hp; - ctx->u.dc.maps_list = maps_list; + if (!WSTACK_ISEMPTY(flat_maps)) { + WSTACK_SAVE(flat_maps, &ctx->u.dc.flat_maps); + } if (!PSTACK_IS_EMPTY(hamt_array)) { PSTACK_SAVE(hamt_array, &ctx->u.dc.hamt_array); } @@ -3865,18 +3863,6 @@ dec_term_atom_common: } } - /* Iterate through all the maps and check for validity and sort keys - * - done here for when we know it is complete. - */ - - while (maps_list) { - next = (Eterm *)(EXPAND_POINTER(*maps_list)); - *maps_list = MAP_HEADER_FLATMAP; - if (!erts_validate_and_sort_flatmap((flatmap_t*)maps_list)) - goto error; - maps_list = next; - } - ASSERT(hp <= factory->hp_end || (factory->mode == FACTORY_CLOSED && is_immed(*dbg_resultp))); factory->hp = hp; @@ -3885,20 +3871,31 @@ dec_term_atom_common: */ if (!PSTACK_IS_EMPTY(hamt_array)) { - do { - struct dec_term_hamt* hamt = PSTACK_TOP(hamt_array); - - *hamt->objp = erts_hashmap_from_array(factory, - hamt->leaf_array, - hamt->size, - 1); - if (is_non_value(*hamt->objp)) - goto error_hamt; - - (void) PSTACK_POP(hamt_array); - } while (!PSTACK_IS_EMPTY(hamt_array)); - PSTACK_DESTROY(hamt_array); + do { + struct dec_term_hamt* hamt = PSTACK_TOP(hamt_array); + + *hamt->objp = erts_hashmap_from_array(factory, + hamt->leaf_array, + hamt->size, + 1); + if (is_non_value(*hamt->objp)) + goto error_hamt; + + (void) PSTACK_POP(hamt_array); + } while (!PSTACK_IS_EMPTY(hamt_array)); + PSTACK_DESTROY(hamt_array); + } + + /* Iterate through all the (flat)maps and check for validity and sort keys + * - done here for when we know it is complete. + */ + + while(!WSTACK_ISEMPTY(flat_maps)) { + next = (Eterm *)WSTACK_POP(flat_maps); + if (!erts_validate_and_sort_flatmap((flatmap_t*)next)) + goto error; } + WSTACK_DESTROY(flat_maps); ASSERT((Eterm*)EXPAND_POINTER(*dbg_resultp) != NULL); @@ -3924,6 +3921,7 @@ error_hamt: ctx->state = B2TDecodeFail; ctx->reds = reds; } + WSTACK_DESTROY(flat_maps); return NULL; } @@ -4112,7 +4110,7 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, ASSERT(node_sz < 17); break; default: - erl_exit(1, "bad header\r\n"); + erts_exit(ERTS_ERROR_EXIT, "bad header\r\n"); } ptr++; @@ -4204,7 +4202,7 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, break; default: - erl_exit(1,"Internal data structure error (in encode_size_struct2)%x\n", + erts_exit(ERTS_ERROR_EXIT,"Internal data structure error (in encode_size_struct2)%x\n", obj); } diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index ec9296d034..1b8595fe57 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -428,7 +428,7 @@ void erl_grow_estack(ErtsEStack*, Uint need); #define ESTACK_CHANGE_ALLOCATOR(s,t) \ do { \ if ((s).start != ESTK_DEF_STACK(s)) { \ - erl_exit(1, "Internal error - trying to change allocator " \ + erts_exit(ERTS_ERROR_EXIT, "Internal error - trying to change allocator " \ "type of active estack\n"); \ } \ (s).alloc_type = (t); \ @@ -589,7 +589,7 @@ do { \ #define WSTACK_CHANGE_ALLOCATOR(s,t) \ do { \ if (s.wstart != WSTK_DEF_STACK(s)) { \ - erl_exit(1, "Internal error - trying to change allocator " \ + erts_exit(ERTS_ERROR_EXIT, "Internal error - trying to change allocator " \ "type of active wstack\n"); \ } \ s.alloc_type = (t); \ @@ -781,7 +781,7 @@ ErtsPStack s = { (byte*)PSTK_DEF_STACK(s), /* pstart */ \ #define PSTACK_CHANGE_ALLOCATOR(s,t) \ do { \ if (s.pstart != (byte*)PSTK_DEF_STACK(s)) { \ - erl_exit(1, "Internal error - trying to change allocator " \ + erts_exit(ERTS_ERROR_EXIT, "Internal error - trying to change allocator " \ "type of active pstack\n"); \ } \ s.alloc_type = (t); \ @@ -952,8 +952,8 @@ double erts_get_positive_zero_float(void); /* config.c */ -__decl_noreturn void __noreturn erl_exit(int n, char*, ...); -__decl_noreturn void __noreturn erl_exit_flush_async(int n, char*, ...); +__decl_noreturn void __noreturn erts_exit(int n, char*, ...); +__decl_noreturn void __noreturn erts_flush_async_exit(int n, char*, ...); void erl_error(char*, va_list); /* copy.c */ @@ -1398,7 +1398,7 @@ erts_alloc_message_heap_state(Uint size, #endif if (size > (Uint) INT_MAX) - erl_exit(ERTS_ABORT_EXIT, "HUGE size (%beu)\n", size); + erts_exit(ERTS_ABORT_EXIT, "HUGE size (%beu)\n", size); if ( #if defined(ERTS_SMP) diff --git a/erts/emulator/beam/hash.c b/erts/emulator/beam/hash.c index e0fde337f2..895fe657d1 100644 --- a/erts/emulator/beam/hash.c +++ b/erts/emulator/beam/hash.c @@ -133,7 +133,7 @@ Hash* hash_init(ErtsAlcType_t type, Hash* h, char* name, int size, HashFunctions while (h_size_table[ix] != -1 && h_size_table[ix] < size) ix++; if (h_size_table[ix] == -1) - erl_exit(1, "panic: too large hash table size (%d)\n", size); + erts_exit(ERTS_ERROR_EXIT, "panic: too large hash table size (%d)\n", size); size = h_size_table[ix]; sz = size*sizeof(HashBucket*); diff --git a/erts/emulator/beam/index.c b/erts/emulator/beam/index.c index 06d0b5123d..5f6ea14732 100644 --- a/erts/emulator/beam/index.c +++ b/erts/emulator/beam/index.c @@ -84,7 +84,7 @@ index_put_entry(IndexTable* t, void* tmpl) Uint sz; if (ix >= t->limit) { /* A core dump is unnecessary */ - erl_exit(ERTS_DUMP_EXIT, "no more index entries in %s (max=%d)\n", + erts_exit(ERTS_DUMP_EXIT, "no more index entries in %s (max=%d)\n", t->htable.name, t->limit); } sz = INDEX_PAGE_SIZE*sizeof(IndexSlot*); @@ -123,7 +123,7 @@ void erts_index_merge(Hash* src, IndexTable* dst) ix = dst->entries++; if (ix >= dst->size) { if (ix >= dst->limit) { - erl_exit(1, "no more index entries in %s (max=%d)\n", + erts_exit(ERTS_ERROR_EXIT, "no more index entries in %s (max=%d)\n", dst->htable.name, dst->limit); } sz = INDEX_PAGE_SIZE*sizeof(IndexSlot*); diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c index 900616c981..fbcb0c31fc 100644 --- a/erts/emulator/beam/io.c +++ b/erts/emulator/beam/io.c @@ -50,6 +50,7 @@ #include "erl_map.h" #include "erl_bif_unique.h" #include "erl_hl_timer.h" +#include "erl_time.h" extern ErlDrvEntry fd_driver_entry; #ifndef __OSE__ @@ -1528,8 +1529,19 @@ erts_schedule_proc2port_signal(Process *c_p, erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN); if (sched_res != 0) { - if (refp) + if (refp) { + /* + * We need to restore the message queue save + * pointer to the beginning of the message queue + * since the caller now wont wait for a message + * containing the reference created above... + */ + ASSERT(c_p); + erts_smp_proc_lock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE); + JOIN_MESSAGE(c_p); + erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE); *refp = NIL; + } return ERTS_PORT_OP_DROPPED; } return ERTS_PORT_OP_SCHEDULED; @@ -3466,7 +3478,7 @@ terminate_port(Port *prt) if ((state & ERTS_PORT_SFLG_HALT) && (erts_smp_atomic32_dec_read_nob(&erts_halt_progress) == 0)) { erts_port_release(prt); /* We will exit and never return */ - erl_exit_flush_async(erts_halt_code, ""); + erts_flush_async_exit(erts_halt_code, ""); } if (is_internal_port(send_closed_port_id)) deliver_result(send_closed_port_id, connected_id, am_closed); @@ -4881,7 +4893,7 @@ void erts_raw_port_command(Port* p, byte* buf, Uint len) ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(p)); if (len > (Uint) INT_MAX) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Absurdly large data buffer (%beu bytes) passed to" "output callback of %s driver.\n", len, @@ -6762,6 +6774,28 @@ driver_get_now(ErlDrvNowData *now_data) return 0; } +ErlDrvTime +erl_drv_monotonic_time(ErlDrvTimeUnit time_unit) +{ + return (ErlDrvTime) erts_napi_monotonic_time((int) time_unit); +} + +ErlDrvTime +erl_drv_time_offset(ErlDrvTimeUnit time_unit) +{ + return (ErlDrvTime) erts_napi_time_offset((int) time_unit); +} + +ErlDrvTime +erl_drv_convert_time_unit(ErlDrvTime val, + ErlDrvTimeUnit from, + ErlDrvTimeUnit to) +{ + return (ErlDrvTime) erts_napi_convert_time_unit((ErtsMonotonicTime) val, + (int) from, + (int) to); +} + static void ref_to_driver_monitor(Eterm ref, ErlDrvMonitor *mon) { RefThing *refp; @@ -7289,7 +7323,7 @@ driver_system_info(ErlDrvSysInfo *sip, size_t si_size) * of ErlDrvSysInfo (introduced in driver version 1.0). */ if (!sip || si_size < ERL_DRV_SYS_INFO_SIZE(smp_support)) - erl_exit(1, + erts_exit(ERTS_ERROR_EXIT, "driver_system_info(%p, %ld) called with invalid arguments\n", sip, si_size); @@ -7596,15 +7630,15 @@ int null_func(void) } int -erl_drv_putenv(char *key, char *value) +erl_drv_putenv(const char *key, char *value) { - return erts_sys_putenv_raw(key, value); + return erts_sys_putenv_raw((char*)key, value); } int -erl_drv_getenv(char *key, char *value, size_t *value_size) +erl_drv_getenv(const char *key, char *value, size_t *value_size) { - return erts_sys_getenv_raw(key, value, value_size); + return erts_sys_getenv_raw((char*)key, value, value_size); } /* get heart_port diff --git a/erts/emulator/beam/packet_parser.c b/erts/emulator/beam/packet_parser.c index 2dd421a9e9..a737a86f14 100644 --- a/erts/emulator/beam/packet_parser.c +++ b/erts/emulator/beam/packet_parser.c @@ -256,6 +256,7 @@ int packet_get_length(enum PacketParseType htype, const char* ptr, unsigned n, /* Bytes read so far */ unsigned max_plen, /* Max packet length, 0=no limit */ unsigned trunc_len, /* Truncate (lines) if longer, 0=no limit */ + char delimiter, /* Line delimiting character */ int* statep) /* Protocol specific state */ { unsigned hlen, plen; @@ -299,9 +300,9 @@ int packet_get_length(enum PacketParseType htype, goto remain; case TCP_PB_LINE_LF: { - /* TCP_PB_LINE_LF: [Data ... \n] */ + /* TCP_PB_LINE_LF: [Data ... Delimiter] */ const char* ptr2; - if ((ptr2 = memchr(ptr, '\n', n)) == NULL) { + if ((ptr2 = memchr(ptr, delimiter, n)) == NULL) { if (n > max_plen && max_plen != 0) { /* packet full */ DEBUGF((" => packet full (no NL)=%d\r\n", n)); goto error; diff --git a/erts/emulator/beam/packet_parser.h b/erts/emulator/beam/packet_parser.h index ff158ff8b8..717d905fad 100644 --- a/erts/emulator/beam/packet_parser.h +++ b/erts/emulator/beam/packet_parser.h @@ -105,7 +105,8 @@ int packet_get_length(enum PacketParseType htype, const char* ptr, unsigned n, /* Bytes read so far */ unsigned max_plen, /* Packet max length, 0=no limit */ unsigned trunc_len, /* Truncate (lines) if longer, 0=no limit */ - int* statep); /* Internal protocol state */ + char delimiter, /* Line delimiting character */ + int* statep); /* Internal protocol state */ ERTS_GLB_INLINE void packet_get_body(enum PacketParseType htype, diff --git a/erts/emulator/beam/register.c b/erts/emulator/beam/register.c index 7ade8bca0f..020e61d136 100644 --- a/erts/emulator/beam/register.c +++ b/erts/emulator/beam/register.c @@ -125,7 +125,7 @@ static RegProc* reg_alloc(RegProc *tmpl) { RegProc* obj = (RegProc*) erts_alloc(ERTS_ALC_T_REG_PROC, sizeof(RegProc)); if (!obj) { - erl_exit(1, "Can't allocate %d bytes of memory\n", sizeof(RegProc)); + erts_exit(ERTS_ERROR_EXIT, "Can't allocate %d bytes of memory\n", sizeof(RegProc)); } obj->name = tmpl->name; obj->p = tmpl->p; diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h index bb871b05ba..6497a1e648 100644 --- a/erts/emulator/beam/sys.h +++ b/erts/emulator/beam/sys.h @@ -611,15 +611,16 @@ static unsigned long zero_value = 0, one_value = 1; # endif /* !__WIN32__ */ #endif /* WANT_NONBLOCKING */ -__decl_noreturn void __noreturn erl_exit(int n, char*, ...); +__decl_noreturn void __noreturn erts_exit(int n, char*, ...); -/* Some special erl_exit() codes: */ -#define ERTS_INTR_EXIT INT_MIN /* called from signal handler */ -#define ERTS_ABORT_EXIT (INT_MIN + 1) /* no crash dump; only abort() */ -#define ERTS_DUMP_EXIT (INT_MIN + 2) /* crash dump; then exit() */ +/* Some special erts_exit() codes: */ +#define ERTS_INTR_EXIT -1 /* called from signal handler */ +#define ERTS_ABORT_EXIT -2 /* no crash dump; only abort() */ +#define ERTS_DUMP_EXIT -3 /* crash dump; then exit() */ +#define ERTS_ERROR_EXIT -4 /* crash dump; then abort() */ #define ERTS_INTERNAL_ERROR(What) \ - erl_exit(ERTS_ABORT_EXIT, "%s:%d:%s(): Internal error: %s\n", \ + erts_exit(ERTS_ABORT_EXIT, "%s:%d:%s(): Internal error: %s\n", \ __FILE__, __LINE__, __func__, What) Eterm erts_check_io_info(void *p); @@ -634,7 +635,6 @@ Uint erts_sys_misc_mem_sz(void); /* Io constants to erts_print and erts_putc */ #define ERTS_PRINT_STDERR (2) #define ERTS_PRINT_STDOUT (1) -#define ERTS_PRINT_INVALID (0) /* Don't want to use 0 since CBUF was 0 */ #define ERTS_PRINT_FILE (-1) #define ERTS_PRINT_SBUF (-2) #define ERTS_PRINT_SNBUF (-3) @@ -820,6 +820,10 @@ int local_to_univ(Sint *year, Sint *month, Sint *day, void get_now(Uint*, Uint*, Uint*); struct ErtsSchedulerData_; ErtsMonotonicTime erts_get_monotonic_time(struct ErtsSchedulerData_ *); +ErtsMonotonicTime erts_get_time_offset(void); +void +erts_make_timestamp_value(Uint* megasec, Uint* sec, Uint* microsec, + ErtsMonotonicTime mtime, ErtsMonotonicTime offset); void get_sys_now(Uint*, Uint*, Uint*); void set_break_quit(void (*)(void), void (*)(void)); @@ -930,7 +934,7 @@ erts_refc_inc(erts_refc_t *refcp, erts_aint_t min_val) #ifdef ERTS_REFC_DEBUG erts_aint_t val = erts_smp_atomic_inc_read_nob((erts_smp_atomic_t *) refcp); if (val < min_val) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "erts_refc_inc(): Bad refc found (refc=%ld < %ld)!\n", val, min_val); #else @@ -944,7 +948,7 @@ erts_refc_inctest(erts_refc_t *refcp, erts_aint_t min_val) erts_aint_t val = erts_smp_atomic_inc_read_nob((erts_smp_atomic_t *) refcp); #ifdef ERTS_REFC_DEBUG if (val < min_val) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "erts_refc_inctest(): Bad refc found (refc=%ld < %ld)!\n", val, min_val); #endif @@ -957,7 +961,7 @@ erts_refc_dec(erts_refc_t *refcp, erts_aint_t min_val) #ifdef ERTS_REFC_DEBUG erts_aint_t val = erts_smp_atomic_dec_read_nob((erts_smp_atomic_t *) refcp); if (val < min_val) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "erts_refc_dec(): Bad refc found (refc=%ld < %ld)!\n", val, min_val); #else @@ -971,7 +975,7 @@ erts_refc_dectest(erts_refc_t *refcp, erts_aint_t min_val) erts_aint_t val = erts_smp_atomic_dec_read_nob((erts_smp_atomic_t *) refcp); #ifdef ERTS_REFC_DEBUG if (val < min_val) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "erts_refc_dectest(): Bad refc found (refc=%ld < %ld)!\n", val, min_val); #endif @@ -984,7 +988,7 @@ erts_refc_add(erts_refc_t *refcp, erts_aint_t diff, erts_aint_t min_val) #ifdef ERTS_REFC_DEBUG erts_aint_t val = erts_smp_atomic_add_read_nob((erts_smp_atomic_t *) refcp, diff); if (val < min_val) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "erts_refc_add(%ld): Bad refc found (refc=%ld < %ld)!\n", diff, val, min_val); #else @@ -998,7 +1002,7 @@ erts_refc_read(erts_refc_t *refcp, erts_aint_t min_val) erts_aint_t val = erts_smp_atomic_read_nob((erts_smp_atomic_t *) refcp); #ifdef ERTS_REFC_DEBUG if (val < min_val) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "erts_refc_read(): Bad refc found (refc=%ld < %ld)!\n", val, min_val); #endif diff --git a/erts/emulator/beam/time.c b/erts/emulator/beam/time.c index 0ab6661c9f..988338ed81 100644 --- a/erts/emulator/beam/time.c +++ b/erts/emulator/beam/time.c @@ -555,7 +555,7 @@ erts_init_time(int time_correction, ErtsTimeWarpMode time_warp_mode) itime = erts_init_time_sup(time_correction, time_warp_mode); #ifdef TIW_ITIME_IS_CONSTANT if (itime != TIW_ITIME) { - erl_exit(ERTS_ABORT_EXIT, "timer resolution mismatch %d != %d", itime, TIW_ITIME); + erts_exit(ERTS_ABORT_EXIT, "timer resolution mismatch %d != %d", itime, TIW_ITIME); } #else tiw_itime = itime; diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c index 342e91e983..b9ce70e364 100644 --- a/erts/emulator/beam/utils.c +++ b/erts/emulator/beam/utils.c @@ -399,9 +399,6 @@ erts_print(int to, void *arg, char *format, ...) case ERTS_PRINT_DSBUF: res = erts_vdsprintf((erts_dsprintf_buf_t *) arg, format, arg_list); break; - case ERTS_PRINT_INVALID: - res = -EINVAL; - break; default: res = erts_vfdprintf((int) to, format, arg_list); break; @@ -844,7 +841,6 @@ Uint32 make_hash(Eterm term_arg) Eterm hash = 0; unsigned op; - /* Must not collide with the real tag_val_def's: */ #define MAKE_HASH_TUPLE_OP (FIRST_VACANT_TAG_DEF) #define MAKE_HASH_TERM_ARRAY_OP (FIRST_VACANT_TAG_DEF+1) #define MAKE_HASH_CDR_PRE_OP (FIRST_VACANT_TAG_DEF+2) @@ -1059,7 +1055,7 @@ tail_recur: } default: - erl_exit(1, "Invalid tag in make_hash(0x%X,0x%X)\n", term, op); + erts_exit(ERTS_ERROR_EXIT, "Invalid tag in make_hash(0x%X,0x%X)\n", term, op); return 0; } if (WSTACK_ISEMPTY(stack)) break; @@ -1332,7 +1328,7 @@ make_hash2(Eterm term) i = hashmap_bitcount(MAP_HEADER_VAL(hdr)); break; default: - erl_exit(1, "bad header"); + erts_exit(ERTS_ERROR_EXIT, "bad header"); } while (i) { if (is_list(*ptr)) { @@ -1495,7 +1491,7 @@ make_hash2(Eterm term) break; default: - erl_exit(1, "Invalid tag in make_hash2(0x%X)\n", term); + erts_exit(ERTS_ERROR_EXIT, "Invalid tag in make_hash2(0x%X)\n", term); } } break; @@ -1526,7 +1522,7 @@ make_hash2(Eterm term) UINT32_HASH(NIL_DEF, HCONST_2); goto hash2_common; default: - erl_exit(1, "Invalid tag in make_hash2(0x%X)\n", term); + erts_exit(ERTS_ERROR_EXIT, "Invalid tag in make_hash2(0x%X)\n", term); } case _TAG_IMMED1_SMALL: { @@ -1542,7 +1538,7 @@ make_hash2(Eterm term) } break; default: - erl_exit(1, "Invalid tag in make_hash2(0x%X)\n", term); + erts_exit(ERTS_ERROR_EXIT, "Invalid tag in make_hash2(0x%X)\n", term); hash2_common: /* Uint32 hash always has the hash value of the previous term, @@ -1737,7 +1733,7 @@ make_internal_hash(Eterm term) i = hashmap_bitcount(MAP_HEADER_VAL(hdr)); break; default: - erl_exit(1, "bad header"); + erts_exit(ERTS_ERROR_EXIT, "bad header"); } while (i) { if (is_list(*ptr)) { @@ -1913,7 +1909,7 @@ make_internal_hash(Eterm term) goto pop_next; } default: - erl_exit(1, "Invalid tag in make_hash2(0x%X)\n", term); + erts_exit(ERTS_ERROR_EXIT, "Invalid tag in make_hash2(0x%X)\n", term); } } break; @@ -1926,7 +1922,7 @@ make_internal_hash(Eterm term) goto pop_next; default: - erl_exit(1, "Invalid tag in make_hash2(0x%X)\n", term); + erts_exit(ERTS_ERROR_EXIT, "Invalid tag in make_hash2(0x%X)\n", term); pop_next: if (ESTACK_ISEMPTY(s)) { @@ -2209,7 +2205,7 @@ tail_recur: } default: - erl_exit(1, "Invalid tag in make_broken_hash\n"); + erts_exit(ERTS_ERROR_EXIT, "Invalid tag in make_broken_hash\n"); return 0; } if (WSTACK_ISEMPTY(stack)) break; @@ -2883,7 +2879,7 @@ tailrecur_ne: ASSERT(sz > 0 && sz < 17); break; default: - erl_exit(1, "Unknown hashmap subsubtag\n"); + erts_exit(ERTS_ERROR_EXIT, "Unknown hashmap subsubtag\n"); } goto term_array; } diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index 8aff6c1865..5e25747ddf 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -125,8 +125,6 @@ #include "dtrace-wrapper.h" -void erl_exit(int n, char *fmt, ...); - static ErlDrvSysInfo sys_info; /* For explanation of this var, see comment for same var in erl_async.c */ @@ -515,21 +513,10 @@ struct t_data static void *ef_safe_alloc(Uint s) { void *p = EF_ALLOC(s); - if (!p) erl_exit(1, "efile drv: Can't allocate %lu bytes of memory\n", (unsigned long)s); - return p; -} - -#if 0 /* Currently not used */ - -static void *ef_safe_realloc(void *op, Uint s) -{ - void *p = EF_REALLOC(op, s); - if (!p) erl_exit(1, "efile drv: Can't reallocate %lu bytes of memory\n", (unsigned long)s); + if (!p) erts_exit(ERTS_ERROR_EXIT, "efile drv: Can't allocate %lu bytes of memory\n", (unsigned long)s); return p; } -#endif - /********************************************************************* * ErlIOVec manipulation functions. */ @@ -1532,10 +1519,10 @@ static void invoke_writev(void *data) { * with errno. */ errno = EINVAL; - if (! (status = - erts_gzwrite((ErtsGzFile)d->fd, - iov[i].iov_base, - iov[i].iov_len)) == iov[i].iov_len) { + status = erts_gzwrite((ErtsGzFile)d->fd, + iov[i].iov_base, + iov[i].iov_len) == iov[i].iov_len; + if (! status) { d->errInfo.posix_errno = d->errInfo.os_errno = errno; /* XXX Correct? */ break; @@ -2581,7 +2568,6 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data) case FILE_CLOSE_ON_PORT_EXIT: /* See file_stop. However this is never invoked after the port is killed. */ free_data(data); - EF_FREE(desc); desc = NULL; /* This is it for this port, so just send dtrace and return, avoid doing anything to the freed data */ DTRACE6(efile_drv_return, sched_i1, sched_i2, sched_utag, diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 549de6503c..2d2bd80783 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2013. All Rights Reserved. + * Copyright Ericsson AB 1997-2015. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -885,6 +885,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) #define INET_LOPT_MSGQ_LOWTRMRK 37 /* set local msgq low watermark */ #define INET_LOPT_NETNS 38 /* Network namespace pathname */ #define INET_LOPT_TCP_SHOW_ECONNRESET 39 /* tell user about incoming RST */ +#define INET_LOPT_LINE_DELIM 40 /* Line delimiting char */ /* SCTP options: a separate range, from 100: */ #define SCTP_OPT_RTOINFO 100 #define SCTP_OPT_ASSOCINFO 101 @@ -1047,7 +1048,7 @@ typedef union { #endif typedef struct _multi_timer_data { - ErlDrvNowData when; + ErlDrvTime when; ErlDrvTermData caller; void (*timeout_function)(ErlDrvData drv_data, ErlDrvTermData caller); struct _multi_timer_data *next; @@ -1154,6 +1155,7 @@ typedef struct { #else Uint32 send_oct[2]; /* number of octets sent, 64 bits */ #endif + char delimiter; /* Line delimiting character (def: '\n') */ unsigned long send_cnt; /* number of packets sent */ unsigned long send_max; /* maximum packet send */ double send_avg; /* average packet size sent */ @@ -1572,7 +1574,7 @@ static const struct in6_addr in6addr_loopback = #endif /* HAVE_IN6 */ /* XXX: is this a driver interface function ??? */ -void erl_exit(int n, char*, ...); +void erts_exit(int n, char*, ...); /* * Malloc wrapper, @@ -1585,7 +1587,7 @@ void erl_exit(int n, char*, ...); static void *alloc_wrapper(ErlDrvSizeT size){ void *ret = driver_alloc(size); if(ret == NULL) - erl_exit(1,"Out of virtual memory in malloc (%s)", __FILE__); + erts_exit(ERTS_ERROR_EXIT,"Out of virtual memory in malloc (%s)", __FILE__); return ret; } #define ALLOC(X) alloc_wrapper(X) @@ -1593,7 +1595,7 @@ static void *alloc_wrapper(ErlDrvSizeT size){ static void *realloc_wrapper(void *current, ErlDrvSizeT size){ void *ret = driver_realloc(current,size); if(ret == NULL) - erl_exit(1,"Out of virtual memory in realloc (%s)", __FILE__); + erts_exit(ERTS_ERROR_EXIT,"Out of virtual memory in realloc (%s)", __FILE__); return ret; } #define REALLOC(X,Y) realloc_wrapper(X,Y) @@ -1854,7 +1856,7 @@ check_double_release(InetDrvBufStk *bs, ErlDrvBinary* buf) int i; for (i = 0; i < bs->buf.pos; ++i) { if (bs->buf.stk[i] == buf) { - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Multiple buffer release in inet_drv, this " "is a bug, save the core and send it to " "[email protected]!"); @@ -2749,7 +2751,7 @@ int ssl_tls_inetdrv(void* arg, unsigned type, unsigned major, unsigned minor, { tcp_descriptor* desc = (tcp_descriptor*) arg; int i = 0; - ErlDrvTermData spec[28]; + ErlDrvTermData spec[30]; ErlDrvTermData caller = ERL_DRV_NIL; ErlDrvBinary* bin; int ret; @@ -2790,11 +2792,11 @@ int ssl_tls_inetdrv(void* arg, unsigned type, unsigned major, unsigned minor, if (desc->inet.active == INET_PASSIVE) { i = LOAD_TUPLE(spec, i, 2); i = LOAD_TUPLE(spec, i, 4); - ASSERT(i <= 28); + ASSERT(i <= sizeof(spec)/sizeof(*spec)); ret = erl_drv_send_term(desc->inet.dport, caller, spec, i); } else { - ASSERT(i <= 28); + ASSERT(i <= sizeof(spec)/sizeof(*spec)); ret = erl_drv_output_term(desc->inet.dport, spec, i); } done: @@ -6074,9 +6076,9 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) int arg_sz; enum PacketParseType old_htype = desc->htype; int old_active = desc->active; - int propagate = 0; /* Set to 1 if failure to set this option - should be propagated to erlang (not all - errors can be propagated for BC reasons) */ + int propagate; /* Set to 1 if failure to set this option + should be propagated to erlang (not all + errors can be propagated for BC reasons) */ int res; #ifdef HAVE_SCTP /* SCTP sockets are treated completely separately: */ @@ -6093,6 +6095,7 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) arg_ptr = (char*) &ival; arg_sz = sizeof(ival); proto = SOL_SOCKET; + propagate = 0; switch(opt) { case INET_LOPT_HEADER: @@ -6276,6 +6279,12 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) } continue; + case INET_LOPT_LINE_DELIM: + DEBUGF(("inet_set_opts(%ld): s=%d, LINE_DELIM=%d\r\n", + (long)desc->port, desc->s, ival)); + desc->delimiter = (char)ival; + continue; + case INET_OPT_REUSEADDR: #ifdef __WIN32__ continue; /* Bjorn says */ @@ -7108,7 +7117,7 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc, do { \ ErlDrvSizeT new_need = ((Ptr) - (*dest)) + (Size); \ if (new_need > dest_used) { \ - erl_exit(1,"Internal error in inet_drv, " \ + erts_exit(ERTS_ERROR_EXIT,"Internal error in inet_drv, " \ "miscalculated buffer size"); \ } \ dest_used = new_need; \ @@ -7485,7 +7494,7 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc, do { \ int need; \ if ((Index) > spec_allocated) { \ - erl_exit(1,"Internal error in inet_drv, " \ + erts_exit(ERTS_ERROR_EXIT,"Internal error in inet_drv, " \ "miscalculated buffer size"); \ } \ need = (Index) + (N); \ @@ -8371,6 +8380,7 @@ static ErlDrvData inet_start(ErlDrvPort port, int size, int protocol) desc->deliver = INET_DELIVER_TERM; /* standard term format */ desc->active = INET_PASSIVE; /* start passive */ desc->active_count = 0; + desc->delimiter = '\n'; /* line delimiting char */ desc->oph = NULL; desc->opt = NULL; @@ -9882,7 +9892,7 @@ static int tcp_remain(tcp_descriptor* desc, int* len) tlen = packet_get_length(desc->inet.htype, ptr, n, desc->inet.psize, desc->i_bufsz, - &desc->http_state); + desc->inet.delimiter, &desc->http_state); DEBUGF(("tcp_remain(%ld): s=%d, n=%d, nfill=%d nsz=%d, tlen %d\r\n", (long)desc->inet.port, desc->inet.s, n, nfill, nsz, tlen)); @@ -12134,115 +12144,18 @@ make_noninheritable_handle(SOCKET s) * Multi-timers */ -static void absolute_timeout(unsigned millis, ErlDrvNowData *out) -{ - unsigned rest; - unsigned long millipart; - unsigned long secpart; - unsigned long megasecpart; - unsigned tmo_secs = (millis / 1000U); - unsigned tmo_millis = (millis % 1000); - driver_get_now(out); - rest = (out->microsecs) % 1000; - millipart = ((out->microsecs) / 1000UL); - if (rest >= 500) { - ++millipart; - } - secpart = out->secs; - megasecpart = out->megasecs; - millipart += tmo_millis; - secpart += (millipart / 1000000UL); - millipart %= 1000000UL; - secpart += tmo_secs; - megasecpart += (secpart / 1000000UL); - secpart %= 1000000UL; - out->megasecs = megasecpart; - out->secs = secpart; - out->microsecs = (millipart * 1000UL); -} - -static unsigned relative_timeout(ErlDrvNowData *in) -{ - ErlDrvNowData now; - unsigned rest; - unsigned long millipart, in_millis, in_secs, in_megasecs; - - driver_get_now(&now); - - in_secs = in->secs; - in_megasecs = in->megasecs; - - rest = (now.microsecs) % 1000; - millipart = ((now.microsecs) / 1000UL); - if (rest >= 500) { - ++millipart; - } - in_millis = ((in->microsecs) / 1000UL); - if ( in_millis < millipart ) { - if (in_secs > 0) { - --in_secs; - } else { - in_secs = (1000000UL - 1UL); - if (in_megasecs <= now.megasecs) { - return 0; - } else { - --in_megasecs; - } - } - in_millis += 1000UL; - } - in_millis -= millipart; - - if (in_secs < now.secs) { - if (in_megasecs <= now.megasecs) { - return 0; - } else { - --in_megasecs; - } - in_secs += 1000000; - } - in_secs -= now.secs; - if (in_megasecs < now.megasecs) { - return 0; - } else { - in_megasecs -= now.megasecs; - } - return (unsigned) ((in_megasecs * 1000000000UL) + - (in_secs * 1000UL) + - in_millis); -} - -#ifdef DEBUG -static int nowcmp(ErlDrvNowData *d1, ErlDrvNowData *d2) -{ - /* Assume it's not safe to do signed conversion on megasecs... */ - if (d1->megasecs < d2->megasecs) { - return -1; - } else if (d1->megasecs > d2->megasecs) { - return 1; - } else if (d1->secs != d2->secs) { - return ((int) d1->secs) - ((int) d2->secs); - } - return ((int) d1->microsecs) - ((int) d2->microsecs); -} -#endif - static void fire_multi_timers(MultiTimerData **first, ErlDrvPort port, ErlDrvData data) { - unsigned next_timeout; + ErlDrvTime next_timeout; if (!*first) { ASSERT(0); return; } #ifdef DEBUG { - ErlDrvNowData chk; - driver_get_now(&chk); - chk.microsecs /= 10000UL; - chk.microsecs *= 10000UL; - chk.microsecs += 10000; - ASSERT(nowcmp(&chk,&((*first)->when)) >= 0); + ErlDrvTime chk = erl_drv_monotonic_time(ERL_DRV_MSEC); + ASSERT(chk >= (*first)->when); } #endif do { @@ -12254,9 +12167,9 @@ static void fire_multi_timers(MultiTimerData **first, ErlDrvPort port, return; } (*first)->prev = NULL; - next_timeout = relative_timeout(&((*first)->when)); - } while (next_timeout == 0); - driver_set_timer(port,next_timeout); + next_timeout = (*first)->when - erl_drv_monotonic_time(ERL_DRV_MSEC); + } while (next_timeout <= 0); + driver_set_timer(port, (unsigned long) next_timeout); } static void clean_multi_timers(MultiTimerData **first, ErlDrvPort port) @@ -12279,8 +12192,10 @@ static void remove_multi_timer(MultiTimerData **first, ErlDrvPort port, MultiTim driver_cancel_timer(port); *first = p->next; if (*first) { - unsigned ntmo = relative_timeout(&((*first)->when)); - driver_set_timer(port,ntmo); + ErlDrvTime ntmo = (*first)->when - erl_drv_monotonic_time(ERL_DRV_MSEC); + if (ntmo < 0) + ntmo = 0; + driver_set_timer(port, (unsigned long) ntmo); } } if (p->next != NULL) { @@ -12294,26 +12209,14 @@ static MultiTimerData *add_multi_timer(MultiTimerData **first, ErlDrvPort port, void (*timeout_fun)(ErlDrvData drv_data, ErlDrvTermData caller)) { -#define eq_mega(a, b) ((a)->when.megasecs == (b)->when.megasecs) -#define eq_sec(a, b) ((a)->when.secs == (b)->when.secs) MultiTimerData *mtd, *p, *s; mtd = ALLOC(sizeof(MultiTimerData)); - absolute_timeout(timeout, &(mtd->when)); + mtd->when = erl_drv_monotonic_time(ERL_DRV_MSEC) + ((ErlDrvTime) timeout) + 1; mtd->timeout_function = timeout_fun; mtd->caller = caller; mtd->next = mtd->prev = NULL; for(p = *first,s = NULL; p != NULL; s = p, p = p->next) { - if (p->when.megasecs >= mtd->when.megasecs) { - break; - } - } - for (; p!= NULL && eq_mega(p, mtd); s = p, p = p->next) { - if (p->when.secs >= mtd->when.secs) { - break; - } - } - for (; p!= NULL && eq_mega(p, mtd) && eq_sec(p, mtd); s = p, p = p->next) { - if (p->when.microsecs >= mtd->when.microsecs) { + if (p->when >= mtd->when) { break; } } @@ -12343,12 +12246,6 @@ static MultiTimerData *add_multi_timer(MultiTimerData **first, ErlDrvPort port, } return mtd; } -#undef eq_mega -#undef eq_sec - - - - /*----------------------------------------------------------------------------- diff --git a/erts/emulator/drivers/unix/ttsl_drv.c b/erts/emulator/drivers/unix/ttsl_drv.c index 0f773b69fb..25cad37e25 100644 --- a/erts/emulator/drivers/unix/ttsl_drv.c +++ b/erts/emulator/drivers/unix/ttsl_drv.c @@ -720,6 +720,7 @@ static void ttysl_from_erlang(ErlDrvData ttysl_data, char* buf, ErlDrvSizeT coun } driver_enq_bin(ttysl_port,putcbuf,0,putcpos); + driver_free_binary(putcbuf); if (sz == 0) { for (;;) { @@ -732,13 +733,13 @@ static void ttysl_from_erlang(ErlDrvData ttysl_data, char* buf, ErlDrvSizeT coun else written = 0; if (written < 0) { - if (errno == EAGAIN) { + if (errno == ERRNO_BLOCK || errno == EINTR) { driver_select(ttysl_port,(ErlDrvEvent)(long)ttysl_fd, ERL_DRV_USE|ERL_DRV_WRITE,1); break; } else { - /* we ignore all other errors */ - break; + driver_failure_posix(ttysl_port, errno); + return; } } else { if (driver_deq(ttysl_port, written) == 0) @@ -778,11 +779,12 @@ static void ttysl_to_tty(ErlDrvData ttysl_data, ErlDrvEvent fd) { else written = 0; if (written < 0) { - if (errno == EAGAIN) { - break; - } else { - /* we ignore all other errors */ + if (errno == EINTR) { + continue; + } else if (errno != ERRNO_BLOCK){ + driver_failure_posix(ttysl_port, errno); } + break; } else { sz = driver_deq(ttysl_port, written); if (sz < TTY_BUFFSIZE && ttysl_send_ok) { @@ -1207,6 +1209,7 @@ static int outc(int c) putcbuf->orig_bytes[putcpos++] = c; if (putcpos == putclen) { driver_enq_bin(ttysl_port,putcbuf,0,putclen); + driver_free_binary(putcbuf); putcpos = 0; putclen = TTY_BUFFSIZE; putcbuf = driver_alloc_binary(BUFSIZ); diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c index 06ba986044..00da48b107 100644 --- a/erts/emulator/drivers/unix/unix_efile.c +++ b/erts/emulator/drivers/unix/unix_efile.c @@ -39,16 +39,21 @@ #ifdef HAVE_SYS_UIO_H #include <sys/types.h> #include <sys/uio.h> +#if defined(HAVE_SENDFILE) && (defined(__FreeBSD__) || defined(__DragonFly__)) +/* Need to define __BSD_VISIBLE in order to expose prototype of sendfile */ +#define __BSD_VISIBLE 1 +#include <sys/socket.h> +#endif #endif #if defined(HAVE_SENDFILE) && (defined(__linux__) || (defined(__sun) && defined(__SVR4))) #include <sys/sendfile.h> #endif #if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__) -#define DARWIN 1 +#define __DARWIN__ 1 #endif -#if defined(DARWIN) || defined(HAVE_LINUX_FALLOC_H) || defined(HAVE_POSIX_FALLOCATE) +#if defined(__DARWIN__) || defined(HAVE_LINUX_FALLOC_H) || defined(HAVE_POSIX_FALLOCATE) #include <fcntl.h> #endif @@ -476,11 +481,11 @@ efile_fsync(Efile_error *errInfo, /* Where to return error codes. */ #ifdef NO_FSYNC undefined fsync /* XXX: Really? */ #else -#if defined(DARWIN) && defined(F_FULLFSYNC) +#if defined(__DARWIN__) && defined(F_FULLFSYNC) return check_error(fcntl(fd, F_FULLFSYNC), errInfo); #else return check_error(fsync(fd), errInfo); -#endif /* DARWIN */ +#endif /* __DARWIN__ */ #endif /* NO_FSYNC */ } @@ -962,7 +967,7 @@ efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd, retval = len; } } while (len == SENDFILE_CHUNK_SIZE); -#elif defined(DARWIN) +#elif defined(__DARWIN__) int retval; off_t len; do { diff --git a/erts/emulator/drivers/win32/win_con.c b/erts/emulator/drivers/win32/win_con.c index 0d63d46698..7fe708dc7b 100644 --- a/erts/emulator/drivers/win32/win_con.c +++ b/erts/emulator/drivers/win32/win_con.c @@ -279,7 +279,7 @@ ConInit(void) } /* - ConNormalExit() is called from erl_exit() when the emulator + ConNormalExit() is called from erts_exit() when the emulator is stopping. If the exit has not been initiated by this console thread (WM_DESTROY or ID_BREAK), the function must invoke the console thread to save the user preferences. @@ -529,7 +529,7 @@ ConThreadInit(LPVOID param) /* PostQuitMessage() results in WM_QUIT which makes GetMessage() return 0 (which stops the main loop). Before we return from - the console thread, the ctrl_handler is called to do erl_exit. + the console thread, the ctrl_handler is called to do erts_exit. */ (*ctrl_handler)(CTRL_CLOSE_EVENT); return msg.wParam; diff --git a/erts/emulator/hipe/hipe_bif0.c b/erts/emulator/hipe/hipe_bif0.c index efbe951ce5..c838150db8 100644 --- a/erts/emulator/hipe/hipe_bif0.c +++ b/erts/emulator/hipe/hipe_bif0.c @@ -406,7 +406,7 @@ BIF_RETTYPE hipe_bifs_enter_code_2(BIF_ALIST_2) nrcallees = arityval(tuple_val(BIF_ARG_2)[0]); else nrcallees = 0; - erl_exit(1, "%s: failed to allocate %lu bytes and %lu trampolines\r\n", + erts_exit(ERTS_ERROR_EXIT, "%s: failed to allocate %lu bytes and %lu trampolines\r\n", __func__, (unsigned long)nrbytes, (unsigned long)nrcallees); } memcpy(address, bytes, nrbytes); @@ -1311,7 +1311,7 @@ static void *hipe_make_stub(Eterm m, Eterm f, unsigned int arity, int is_remote) export_entry = erts_export_get_or_make_stub(m, f, arity); StubAddress = hipe_make_native_stub(export_entry, arity); if (!StubAddress) - erl_exit(1, "hipe_make_stub: code allocation failed\r\n"); + erts_exit(ERTS_ERROR_EXIT, "hipe_make_stub: code allocation failed\r\n"); return StubAddress; } @@ -1741,7 +1741,7 @@ BIF_RETTYPE hipe_bifs_check_crc_1(BIF_ALIST_1) if (!term_to_Uint(BIF_ARG_1, &crc)) BIF_ERROR(BIF_P, BADARG); - if (crc == HIPE_SYSTEM_CRC) + if (crc == HIPE_ERTS_CHECKSUM) BIF_RET(am_true); BIF_RET(am_false); } diff --git a/erts/emulator/hipe/hipe_bif0.tab b/erts/emulator/hipe/hipe_bif0.tab index e3328c7d2c..5ce254314a 100644 --- a/erts/emulator/hipe/hipe_bif0.tab +++ b/erts/emulator/hipe/hipe_bif0.tab @@ -142,4 +142,4 @@ atom bs_validate_unicode atom bs_validate_unicode_retract atom emulate_fpe atom emasculate_binary - +atom is_divisible diff --git a/erts/emulator/hipe/hipe_bif_list.m4 b/erts/emulator/hipe/hipe_bif_list.m4 index b3bd5e4357..7240280345 100644 --- a/erts/emulator/hipe/hipe_bif_list.m4 +++ b/erts/emulator/hipe/hipe_bif_list.m4 @@ -193,6 +193,7 @@ standard_bif_interface_2(nbif_rethrow, hipe_rethrow) standard_bif_interface_3(nbif_find_na_or_make_stub, hipe_find_na_or_make_stub) standard_bif_interface_2(nbif_nonclosure_address, hipe_nonclosure_address) nocons_nofail_primop_interface_0(nbif_fclearerror_error, hipe_fclearerror_error) +standard_bif_interface_2(nbif_is_divisible, hipe_is_divisible) /* * Mbox primops with implicit P parameter. @@ -269,21 +270,23 @@ noproc_primop_interface_1(nbif_atomic_inc, hipe_atomic_inc) /* BIFs that disable GC while trapping are called via a wrapper * to reserve stack space for the "trap frame". */ -define(CFUN,`ifelse($1,term_to_binary_1,hipe_wrapper_term_to_binary_1, -ifelse($1,term_to_binary_2,hipe_wrapper_term_to_binary_2, -ifelse($1,binary_to_term_1,hipe_wrapper_binary_to_term_1, -ifelse($1,binary_to_term_2,hipe_wrapper_binary_to_term_2, -ifelse($1,binary_to_list_1,hipe_wrapper_binary_to_list_1, -ifelse($1,binary_to_list_3,hipe_wrapper_binary_to_list_3, -ifelse($1,bitstring_to_list_1,hipe_wrapper_bitstring_to_list_1, -ifelse($1,list_to_binary_1,hipe_wrapper_list_to_binary_1, -ifelse($1,iolist_to_binary_1,hipe_wrapper_iolist_to_binary_1, -ifelse($1,binary_list_to_bin_1,hipe_wrapper_binary_list_to_bin_1, -ifelse($1,list_to_bitstring_1,hipe_wrapper_list_to_bitstring_1, -ifelse($1,send_2,hipe_wrapper_send_2, -ifelse($1,send_3,hipe_wrapper_send_3, -ifelse($1,ebif_bang_2,hipe_wrapper_ebif_bang_2, -$1))))))))))))))') +define(CFUN,`ifelse( +$1, term_to_binary_1, hipe_wrapper_$1, +$1, term_to_binary_2, hipe_wrapper_$1, +$1, binary_to_term_1, hipe_wrapper_$1, +$1, binary_to_term_2, hipe_wrapper_$1, +$1, binary_to_list_1, hipe_wrapper_$1, +$1, binary_to_list_3, hipe_wrapper_$1, +$1, bitstring_to_list_1, hipe_wrapper_$1, +$1, list_to_binary_1, hipe_wrapper_$1, +$1, iolist_to_binary_1, hipe_wrapper_$1, +$1, binary_list_to_bin_1, hipe_wrapper_$1, +$1, list_to_bitstring_1, hipe_wrapper_$1, +$1, send_2, hipe_wrapper_$1, +$1, send_3, hipe_wrapper_$1, +$1, ebif_bang_2, hipe_wrapper_$1, +$1, maps_merge_2, hipe_wrapper_$1, +$1)') define(BIF_LIST,`standard_bif_interface_$3(nbif_$4, CFUN($4))') include(TARGET/`erl_bif_list.h') diff --git a/erts/emulator/hipe/hipe_mkliterals.c b/erts/emulator/hipe/hipe_mkliterals.c index aa12df2932..dfa5313739 100644 --- a/erts/emulator/hipe/hipe_mkliterals.c +++ b/erts/emulator/hipe/hipe_mkliterals.c @@ -269,9 +269,6 @@ static const struct literal { /* freason codes */ { "FREASON_TRAP", TRAP }, - /* special Erlang constants */ - { "THE_NON_VALUE", (int)THE_NON_VALUE }, - /* funs */ #ifdef HIPE { "EFE_NATIVE_ADDRESS", offsetof(struct erl_fun_entry, native_address) }, @@ -526,6 +523,8 @@ static const struct rts_param rts_params[] = { { 49, "P_MSG_FIRST", 1, offsetof(struct process, msg.first) }, { 50, "P_MSG_SAVE", 1, offsetof(struct process, msg.save) }, { 51, "P_CALLEE_EXP", 1, offsetof(struct process, hipe.u.callee_exp) }, + + { 52, "THE_NON_VALUE", 1, (int)THE_NON_VALUE }, }; #define NR_PARAMS ARRAY_SIZE(rts_params) @@ -543,6 +542,8 @@ static void compute_crc(void) crc_value = crc_update_int(crc_value, &literals[i].value); crc_value &= 0x07FFFFFF; literals_crc = crc_value; + + crc_value = crc_init(); for (i = 0; i < NR_PARAMS; ++i) if (rts_params[i].is_defined) crc_value = crc_update_int(crc_value, &rts_params[i].value); @@ -628,6 +629,7 @@ static int do_c(FILE *fp, const char* this_exe) print_params(fp, c_define_param); fprintf(fp, "#define HIPE_LITERALS_CRC %uU\n", literals_crc); fprintf(fp, "#define HIPE_SYSTEM_CRC %uU\n", system_crc); + fprintf(fp, "#define HIPE_ERTS_CHECKSUM (HIPE_LITERALS_CRC ^ HIPE_SYSTEM_CRC)\n"); fprintf(fp, "\n"); fprintf(fp, "#define RTS_PARAMS_CASES"); print_params(fp, c_case_param); @@ -645,12 +647,14 @@ static int do_e(FILE *fp, const char* this_exe) fprintf(fp, "\n"); print_params(fp, e_define_param); fprintf(fp, "\n"); + fprintf(fp, "-define(HIPE_LITERALS_CRC, %u).\n", literals_crc); if (is_xcomp) { fprintf(fp, "-define(HIPE_SYSTEM_CRC, %u).\n", system_crc); } else { fprintf(fp, "-define(HIPE_SYSTEM_CRC, hipe_bifs:system_crc()).\n"); } + fprintf(fp, "-define(HIPE_ERTS_CHECKSUM, (?HIPE_LITERALS_CRC bxor ?HIPE_SYSTEM_CRC)).\n"); return 0; } diff --git a/erts/emulator/hipe/hipe_mode_switch.c b/erts/emulator/hipe/hipe_mode_switch.c index 968452a641..9243e029f6 100644 --- a/erts/emulator/hipe/hipe_mode_switch.c +++ b/erts/emulator/hipe/hipe_mode_switch.c @@ -108,7 +108,7 @@ static const char *code_str(unsigned code) static void __noreturn hipe_abort(const char *expr, const char *file, unsigned line) { - erl_exit(1, "ASSERTION FAILED, file %s, line %u: %s\r\n", file, line, expr); + erts_exit(ERTS_ERROR_EXIT, "ASSERTION FAILED, file %s, line %u: %s\r\n", file, line, expr); } #define HIPE_ASSERT3(expr, file, line) \ @@ -316,7 +316,7 @@ Process *hipe_mode_switch(Process *p, unsigned cmd, Eterm reg[]) break; } default: - erl_exit(1, "hipe_mode_switch: cmd %#x\r\n", cmd); + erts_exit(ERTS_ERROR_EXIT, "hipe_mode_switch: cmd %#x\r\n", cmd); } do_return_from_native: DPRINTF("result == %#x (%s)", result, code_str(result)); @@ -560,7 +560,7 @@ Process *hipe_mode_switch(Process *p, unsigned cmd, Eterm reg[]) goto do_throw_to_native; } default: - erl_exit(1, "hipe_mode_switch: result %#x\r\n", result); + erts_exit(ERTS_ERROR_EXIT, "hipe_mode_switch: result %#x\r\n", result); } HIPE_CHECK_PCB(p); p->def_arg_reg[3] = result; diff --git a/erts/emulator/hipe/hipe_native_bif.c b/erts/emulator/hipe/hipe_native_bif.c index 98bda43f0e..994f963ece 100644 --- a/erts/emulator/hipe/hipe_native_bif.c +++ b/erts/emulator/hipe/hipe_native_bif.c @@ -93,9 +93,6 @@ BIF_RETTYPE hipe_set_timeout(BIF_ALIST_1) { Process* p = BIF_P; Eterm timeout_value = BIF_ARG_1; -#if !defined(ARCH_64) - Uint time_val; -#endif /* XXX: This should be converted to follow BEAM conventions, * but that requires some compiler changes. * @@ -174,7 +171,7 @@ void hipe_fclearerror_error(Process *p) #if !defined(NO_FPE_SIGNALS) erts_fp_check_init_error(&p->fp_exception); #else - erl_exit(ERTS_ABORT_EXIT, "Emulated FPE not cleared by HiPE"); + erts_exit(ERTS_ABORT_EXIT, "Emulated FPE not cleared by HiPE"); #endif } @@ -507,6 +504,18 @@ int hipe_bs_validate_unicode_retract(ErlBinMatchBuffer* mb, Eterm arg) return 1; } +BIF_RETTYPE hipe_is_divisible(BIF_ALIST_2) +{ + /* Arguments are Eterm-sized unsigned integers */ + Uint dividend = BIF_ARG_1; + Uint divisor = BIF_ARG_2; + if (dividend % divisor) { + BIF_ERROR(BIF_P, BADARG); + } else { + return NIL; + } +} + /* This is like the loop_rec_fr BEAM instruction */ Eterm hipe_check_get_msg(Process *c_p) diff --git a/erts/emulator/hipe/hipe_native_bif.h b/erts/emulator/hipe/hipe_native_bif.h index 0e1a75f7eb..55a0d3bb1b 100644 --- a/erts/emulator/hipe/hipe_native_bif.h +++ b/erts/emulator/hipe/hipe_native_bif.h @@ -68,6 +68,7 @@ AEXTERN(Eterm,nbif_bs_put_utf16le,(Process*,Eterm,byte*,unsigned int)); AEXTERN(Eterm,nbif_bs_get_utf16,(void)); AEXTERN(Eterm,nbif_bs_validate_unicode,(Process*,Eterm)); AEXTERN(Eterm,nbif_bs_validate_unicode_retract,(void)); +AEXTERN(void,nbif_is_divisible,(Process*,Uint,Uint)); AEXTERN(void,nbif_select_msg,(Process*)); AEXTERN(Eterm,nbif_cmp_2,(void)); @@ -93,6 +94,7 @@ BIF_RETTYPE hipe_bs_put_utf16le(BIF_ALIST_3); BIF_RETTYPE hipe_bs_validate_unicode(BIF_ALIST_1); struct erl_bin_match_buffer; int hipe_bs_validate_unicode_retract(struct erl_bin_match_buffer*, Eterm); +BIF_RETTYPE hipe_is_divisible(BIF_ALIST_2); #ifdef NO_FPE_SIGNALS AEXTERN(void,nbif_emulate_fpe,(Process*)); diff --git a/erts/emulator/hipe/hipe_primops.h b/erts/emulator/hipe/hipe_primops.h index adf7b1f382..0bec677574 100644 --- a/erts/emulator/hipe/hipe_primops.h +++ b/erts/emulator/hipe/hipe_primops.h @@ -68,6 +68,8 @@ PRIMOP_LIST(am_bs_get_utf16, &nbif_bs_get_utf16) PRIMOP_LIST(am_bs_validate_unicode, &nbif_bs_validate_unicode) PRIMOP_LIST(am_bs_validate_unicode_retract, &nbif_bs_validate_unicode_retract) +PRIMOP_LIST(am_is_divisible, &nbif_is_divisible) + PRIMOP_LIST(am_cmp_2, &nbif_cmp_2) PRIMOP_LIST(am_op_exact_eqeq_2, &nbif_eq_2) diff --git a/erts/emulator/hipe/hipe_x86_signal.c b/erts/emulator/hipe/hipe_x86_signal.c index bb8a3f041f..b7dae88417 100644 --- a/erts/emulator/hipe/hipe_x86_signal.c +++ b/erts/emulator/hipe/hipe_x86_signal.c @@ -198,7 +198,7 @@ static void do_init(void) #define INIT() do { if (!init_done()) do_init(); } while (0) #endif /* __DARWIN__ */ -#if !defined(__GLIBC__) && !defined(__DARWIN__) && !defined(__NetBSD__) +#if defined(__sun__) /* * Assume Solaris/x86 2.8. * There is a number of sigaction() procedures in libc: @@ -232,7 +232,56 @@ static void do_init(void) } #define _NSIG NSIG #define INIT() do { if (!init_done()) do_init(); } while (0) -#endif /* not glibc or darwin */ +#endif /* __sun__ */ + +#if defined(__FreeBSD__) +/* + * This is a copy of Darwin code for FreeBSD. + * CAVEAT: detailed semantics are not verified yet. + */ +#include <dlfcn.h> +static int (*__next_sigaction)(int, const struct sigaction*, struct sigaction*); +#define init_done() (__next_sigaction != 0) +extern int _sigaction(int, const struct sigaction*, struct sigaction*); +#define __SIGACTION _sigaction +static void do_init(void) +{ + __next_sigaction = dlsym(RTLD_NEXT, "sigaction"); + if (__next_sigaction != 0) + return; + perror("dlsym_freebsd"); + abort(); +} +#define _NSIG NSIG +#define INIT() do { if (!init_done()) do_init(); } while (0) +#endif /* __FreeBSD__ */ + +#if !(defined(__GLIBC__) || defined(__DARWIN__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__sun__)) +/* + * Unknown libc -- assume musl. Note: musl deliberately does not provide a musl-specific + * feature test macro, so we cannot check for it. + * + * sigaction is a weak alias for __sigaction, which is a wrapper for __libc_sigaction. + * There are libc-internal calls to __libc_sigaction which install handlers, so we must + * override __libc_sigaction rather than __sigaction. + */ +#include <dlfcn.h> +static int (*__next_sigaction)(int, const struct sigaction*, struct sigaction*); +#define init_done() (__next_sigaction != 0) +#define __SIGACTION __libc_sigaction +static void do_init(void) +{ + __next_sigaction = dlsym(RTLD_NEXT, "__libc_sigaction"); + if (__next_sigaction != 0) + return; + perror("dlsym"); + abort(); +} +#ifndef _NSIG +#define _NSIG NSIG +#endif +#define INIT() do { if (!init_done()) do_init(); } while (0) +#endif /* !(__GLIBC__ || __DARWIN__ || __NetBSD__ || __FreeBSD__ || __sun__) */ #if !defined(__NetBSD__) /* @@ -272,7 +321,7 @@ int __SIGACTION(int signum, const struct sigaction *act, struct sigaction *oldac /* * This catches the application's own sigaction() calls. */ -#if !defined(__DARWIN__) && !defined(__NetBSD__) +#if !defined(__DARWIN__) && !defined(__NetBSD__) && !defined(__FreeBSD__) int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact) { return my_sigaction(signum, act, oldact); diff --git a/erts/emulator/sys/common/erl_mmap.c b/erts/emulator/sys/common/erl_mmap.c index 754047829f..4180e65fdc 100644 --- a/erts/emulator/sys/common/erl_mmap.c +++ b/erts/emulator/sys/common/erl_mmap.c @@ -1334,7 +1334,7 @@ os_unreserve_physical(char *ptr, UWord size) void *res = mmap((void *) ptr, (size_t) size, ERTS_MMAP_UNRESERVE_PROT, ERTS_MMAP_UNRESERVE_FLAGS, ERTS_MMAP_FD, 0); if (res == (void *) MAP_FAILED) - erl_exit(ERTS_ABORT_EXIT, "Failed to unreserve memory"); + erts_exit(ERTS_ABORT_EXIT, "Failed to unreserve memory"); } static void * @@ -2126,7 +2126,7 @@ erts_mmap_init(ErtsMMapInit *init) #endif erts_page_inv_mask = pagesize - 1; if (pagesize & erts_page_inv_mask) - erl_exit(-1, "erts_mmap: Invalid pagesize: %bpu\n", + erts_exit(1, "erts_mmap: Invalid pagesize: %bpu\n", pagesize); ERTS_MMAP_OP_RINGBUF_INIT(); @@ -2140,7 +2140,7 @@ erts_mmap_init(ErtsMMapInit *init) #if HAVE_MMAP && !defined(MAP_ANON) mmap_state.mmap_fd = open("/dev/zero", O_RDWR); if (mmap_state.mmap_fd < 0) - erl_exit(-1, "erts_mmap: Failed to open /dev/zero\n"); + erts_exit(1, "erts_mmap: Failed to open /dev/zero\n"); #endif erts_smp_mtx_init(&mmap_state.mtx, "erts_mmap"); @@ -2155,7 +2155,7 @@ erts_mmap_init(ErtsMMapInit *init) sz = end - ptr; start = os_mmap_virtual(ptr, sz); if (!start || start > ptr || start >= end) - erl_exit(-1, + erts_exit(1, "erts_mmap: Failed to create virtual range for super carrier\n"); sz = start - ptr; if (sz) @@ -2193,7 +2193,7 @@ erts_mmap_init(ErtsMMapInit *init) start = os_mmap(NULL, sz, 1); } if (!start) - erl_exit(-1, + erts_exit(1, "erts_mmap: Failed to create super carrier of size %bpu MB\n", init->scs/1024/1024); end = start + sz; @@ -2242,7 +2242,7 @@ erts_mmap_init(ErtsMMapInit *init) if ((desc_size + ERTS_SUPERALIGNED_SIZE + ERTS_PAGEALIGNED_SIZE) > end - start) - erl_exit(-1, "erts_mmap: No space for segments in super carrier\n"); + erts_exit(1, "erts_mmap: No space for segments in super carrier\n"); mmap_state.sa.bot = start; mmap_state.sa.bot += desc_size; @@ -2280,7 +2280,7 @@ erts_mmap_init(ErtsMMapInit *init) */ #ifdef ERTS_HAVE_OS_PHYSICAL_MEMORY_RESERVATION if (virtual_map && !os_reserve_physical(start, mmap_state.sa.bot - start)) - erl_exit(-1, "erts_mmap: Failed to reserve physical memory for descriptors\n"); + erts_exit(1, "erts_mmap: Failed to reserve physical memory for descriptors\n"); #endif mmap_state.desc.unused_start = start; mmap_state.desc.unused_end = mmap_state.sa.bot; diff --git a/erts/emulator/sys/common/erl_mseg.c b/erts/emulator/sys/common/erl_mseg.c index 0d51aad863..3398be2b07 100644 --- a/erts/emulator/sys/common/erl_mseg.c +++ b/erts/emulator/sys/common/erl_mseg.c @@ -1490,7 +1490,7 @@ erts_mseg_init(ErtsMsegInit_t *init) #if HALFWORD_HEAP if (sizeof(void *) != 8) - erl_exit(-1,"Halfword emulator cannot be run in 32bit mode"); + erts_exit(1,"Halfword emulator cannot be run in 32bit mode"); init->mmap.virtual_range.start = (char *) sbrk(0); init->mmap.virtual_range.end = (char *) 0x100000000UL; @@ -1500,7 +1500,7 @@ erts_mseg_init(ErtsMsegInit_t *init) erts_mmap_init(&init->mmap); if (!IS_2POW(GET_PAGE_SIZE)) - erl_exit(ERTS_ABORT_EXIT, "erts_mseg: Unexpected page_size %beu\n", GET_PAGE_SIZE); + erts_exit(ERTS_ABORT_EXIT, "erts_mseg: Unexpected page_size %beu\n", GET_PAGE_SIZE); ASSERT((MSEG_ALIGNED_SIZE % GET_PAGE_SIZE) == 0); diff --git a/erts/emulator/sys/common/erl_os_monotonic_time_extender.c b/erts/emulator/sys/common/erl_os_monotonic_time_extender.c index b79485241f..367b22d989 100644 --- a/erts/emulator/sys/common/erl_os_monotonic_time_extender.c +++ b/erts/emulator/sys/common/erl_os_monotonic_time_extender.c @@ -44,7 +44,7 @@ static void *os_monotonic_time_extender(void *vstatep) erts_milli_sleep(sleep_time); } - erl_exit(ERTS_ABORT_EXIT, "os_monotonic_time_extender thread terminating"); + erts_exit(ERTS_ABORT_EXIT, "os_monotonic_time_extender thread terminating"); return NULL; } diff --git a/erts/emulator/sys/common/erl_poll.c b/erts/emulator/sys/common/erl_poll.c index 884c403da4..21fa214364 100644 --- a/erts/emulator/sys/common/erl_poll.c +++ b/erts/emulator/sys/common/erl_poll.c @@ -431,7 +431,7 @@ static ERTS_INLINE int is_interrupted_reset(ErtsPollSet ps) { #if defined(USE_THREADS) || ERTS_POLL_ASYNC_INTERRUPT_SUPPORT - return (erts_atomic32_xchg_nob(&ps->wakeup_state, ERTS_POLL_NOT_WOKEN) + return (erts_atomic32_xchg_acqb(&ps->wakeup_state, ERTS_POLL_NOT_WOKEN) == ERTS_POLL_WOKEN_INTR); #else return 0; @@ -442,7 +442,7 @@ static ERTS_INLINE void woke_up(ErtsPollSet ps) { #if defined(USE_THREADS) || ERTS_POLL_ASYNC_INTERRUPT_SUPPORT - erts_aint32_t wakeup_state = erts_atomic32_read_nob(&ps->wakeup_state); + erts_aint32_t wakeup_state = erts_atomic32_read_acqb(&ps->wakeup_state); if (wakeup_state == ERTS_POLL_NOT_WOKEN) (void) erts_atomic32_cmpxchg_nob(&ps->wakeup_state, ERTS_POLL_WOKEN, @@ -469,14 +469,9 @@ wake_poller(ErtsPollSet ps, int interrupted, int async_signal_safe) wakeup_state = erts_atomic32_cmpxchg_relb(&ps->wakeup_state, ERTS_POLL_WOKEN, ERTS_POLL_NOT_WOKEN); - else { - /* - * We might unnecessarily write to the pipe, however, - * that isn't problematic. - */ - wakeup_state = erts_atomic32_read_nob(&ps->wakeup_state); - erts_atomic32_set_relb(&ps->wakeup_state, ERTS_POLL_WOKEN_INTR); - } + else + wakeup_state = erts_atomic32_xchg_relb(&ps->wakeup_state, + ERTS_POLL_WOKEN_INTR); wake = wakeup_state == ERTS_POLL_NOT_WOKEN; } /* diff --git a/erts/emulator/sys/common/erl_poll.h b/erts/emulator/sys/common/erl_poll.h index 19ce582154..bd3a46ef0f 100644 --- a/erts/emulator/sys/common/erl_poll.h +++ b/erts/emulator/sys/common/erl_poll.h @@ -140,7 +140,7 @@ struct erts_sys_fd_type { #endif #define ERTS_POLL_EV_E2N(EV) \ - ((__uint32_t) (EV)) + ((uint32_t) (EV)) #define ERTS_POLL_EV_N2E(EV) \ ((ErtsPollEvents) (EV)) diff --git a/erts/emulator/sys/ose/erl_poll.c b/erts/emulator/sys/ose/erl_poll.c index 5cee582a00..c690f08dea 100644 --- a/erts/emulator/sys/ose/erl_poll.c +++ b/erts/emulator/sys/ose/erl_poll.c @@ -658,7 +658,7 @@ int erts_poll_wait(ErtsPollSet ps, break; default: res = 0; - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error: Invalid wakeup_state=%d\n", __FILE__, __LINE__, (int) wakeup_state); } diff --git a/erts/emulator/sys/ose/sys.c b/erts/emulator/sys/ose/sys.c index bcd0ffa0b6..e354faf02c 100644 --- a/erts/emulator/sys/ose/sys.c +++ b/erts/emulator/sys/ose/sys.c @@ -570,7 +570,7 @@ break_requested(void) fprintf(stderr,"break!\n"); #endif if (ERTS_BREAK_REQUESTED) - erl_exit(ERTS_INTR_EXIT, ""); + erts_exit(ERTS_INTR_EXIT, ""); ERTS_SET_BREAK_REQUESTED; ERTS_CHK_IO_AS_INTR(); /* Make sure we don't sleep in poll */ diff --git a/erts/emulator/sys/ose/sys_float.c b/erts/emulator/sys/ose/sys_float.c index 3d9abc6bd1..51875792ae 100644 --- a/erts/emulator/sys/ose/sys_float.c +++ b/erts/emulator/sys/ose/sys_float.c @@ -90,7 +90,7 @@ void erts_fp_check_init_error(volatile unsigned long *fpexnp) snprintf(buf, sizeof buf, "ERTS_FP_CHECK_INIT at %p: detected unhandled FPE at %p\r\n", __builtin_return_address(0), (void*)*fpexnp); if (write(2, buf, strlen(buf)) <= 0) - erl_exit(ERTS_ABORT_EXIT, "%s", buf); + erts_exit(ERTS_ABORT_EXIT, "%s", buf); *fpexnp = 0; #if defined(__i386__) || defined(__x86_64__) erts_restore_fpu(); diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c index b036b20b7b..d94b37430e 100644 --- a/erts/emulator/sys/unix/sys.c +++ b/erts/emulator/sys/unix/sys.c @@ -638,14 +638,14 @@ erl_sys_init(void) res = erts_sys_getenv_raw("BINDIR", bindir, &bindirsz); if (res != 0) { if (res < 0) - erl_exit(-1, + erts_exit(1, "Environment variable BINDIR is not set\n"); if (res > 0) - erl_exit(-1, + erts_exit(1, "Value of environment variable BINDIR is too large\n"); } if (bindir[0] != DIR_SEPARATOR_CHAR) - erl_exit(-1, + erts_exit(1, "Environment variable BINDIR does not contain an" " absolute path\n"); csp_path_sz = (strlen(bindir) @@ -825,7 +825,7 @@ break_requested(void) fprintf(stderr,"break!\n"); #endif if (ERTS_BREAK_REQUESTED) - erl_exit(ERTS_INTR_EXIT, ""); + erts_exit(ERTS_INTR_EXIT, ""); ERTS_SET_BREAK_REQUESTED; ERTS_CHK_IO_AS_INTR(); /* Make sure we don't sleep in poll */ @@ -864,7 +864,7 @@ sigusr1_exit(void) } prepare_crash_dump(secs); - erl_exit(1, "Received SIGUSR1\n"); + erts_exit(ERTS_ERROR_EXIT, "Received SIGUSR1\n"); } #ifdef ETHR_UNUSABLE_SIGUSRX @@ -920,7 +920,7 @@ static RETSIGTYPE suspend_signal(int signum) static void quit_requested(void) { - erl_exit(ERTS_INTR_EXIT, ""); + erts_exit(ERTS_INTR_EXIT, ""); } #if (defined(SIG_SIGSET) || defined(SIG_SIGNAL)) @@ -2527,7 +2527,7 @@ fd_async(void *async_data) SysIOVec *iov0; SysIOVec *iov; int iovlen; - int err; + int err = 0; /* much of this code is stolen from efile_drv:invoke_writev */ driver_pdl_lock(dd->blocking->pdl); iov0 = driver_peekq(dd->port_num, &iovlen); @@ -2542,8 +2542,11 @@ fd_async(void *async_data) memcpy(iov,iov0,iovlen*sizeof(SysIOVec)); driver_pdl_unlock(dd->blocking->pdl); - res = writev(dd->ofd, iov, iovlen); - err = errno; + do { + res = writev(dd->ofd, iov, iovlen); + } while (res < 0 && errno == EINTR); + if (res < 0) + err = errno; erts_free(ERTS_ALC_T_SYS_WRITE_BUF, iov); } @@ -2582,7 +2585,12 @@ void fd_ready_async(ErlDrvData drv_data, return /* 0; */; } } else if (dd->blocking->res < 0) { - driver_failure_posix(port_num, dd->blocking->err); + if (dd->blocking->err == ERRNO_BLOCK) { + set_busy_port(port_num, 1); + /* still data left to write in queue */ + driver_async(port_num, &dd->blocking->pkey, fd_async, dd, NULL); + } else + driver_failure_posix(port_num, dd->blocking->err); return; /* -1; */ } return; /* 0; */ @@ -3157,7 +3165,7 @@ signal_dispatcher_thread_func(void *unused) if (res < 0) { if (errno == EINTR) continue; - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "signal-dispatcher thread got unexpected error: %s (%d)\n", erl_errno_id(errno), errno); @@ -3206,7 +3214,7 @@ signal_dispatcher_thread_func(void *unused) sigusr1_exit(); break; default: - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "signal-dispatcher thread received unknown " "signal notification: '%c'\n", buf[i]); @@ -3225,7 +3233,7 @@ init_smp_sig_notify(void) thr_opts.name = "sys_sig_dispatcher"; if (pipe(sig_notify_fds) < 0) { - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Failed to create signal-dispatcher pipe: %s (%d)\n", erl_errno_id(errno), errno); @@ -3241,7 +3249,7 @@ init_smp_sig_notify(void) static void init_smp_sig_suspend(void) { if (pipe(sig_suspend_fds) < 0) { - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Failed to create sig_suspend pipe: %s (%d)\n", erl_errno_id(errno), errno); @@ -3257,7 +3265,7 @@ static void initialize_darwin_main_thread_pipes(void) { if (pipe(erts_darwin_main_thread_pipe) < 0 || pipe(erts_darwin_main_thread_result_pipe) < 0) { - erl_exit(1,"Fatal error initializing Darwin main thread stealing"); + erts_exit(ERTS_ERROR_EXIT,"Fatal error initializing Darwin main thread stealing"); } } diff --git a/erts/emulator/sys/unix/sys_float.c b/erts/emulator/sys/unix/sys_float.c index 1ef9e5eef7..8fe7e599e5 100644 --- a/erts/emulator/sys/unix/sys_float.c +++ b/erts/emulator/sys/unix/sys_float.c @@ -90,7 +90,7 @@ void erts_fp_check_init_error(volatile unsigned long *fpexnp) snprintf(buf, sizeof buf, "ERTS_FP_CHECK_INIT at %p: detected unhandled FPE at %p\r\n", __builtin_return_address(0), (void*)*fpexnp); if (write(2, buf, strlen(buf)) <= 0) - erl_exit(ERTS_ABORT_EXIT, "%s", buf); + erts_exit(ERTS_ABORT_EXIT, "%s", buf); *fpexnp = 0; #if defined(__i386__) || defined(__x86_64__) erts_restore_fpu(); diff --git a/erts/emulator/sys/unix/sys_time.c b/erts/emulator/sys/unix/sys_time.c index 2e1914f564..95b3daa4ed 100644 --- a/erts/emulator/sys/unix/sys_time.c +++ b/erts/emulator/sys/unix/sys_time.c @@ -342,7 +342,7 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) * times() (CLK_TCK), the resolution is always one millisecond.. */ if ((erts_sys_time_data__.r.o.ticks_per_sec = TICKS_PER_SEC()) < 0) - erl_exit(ERTS_ABORT_EXIT, "Can't get clock ticks/sec\n"); + erts_exit(ERTS_ABORT_EXIT, "Can't get clock ticks/sec\n"); #if defined(OS_MONOTONIC_TIME_USING_TIMES) #if ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT @@ -450,7 +450,7 @@ posix_clock_gettime(clockid_t id, char *name) if (clock_gettime(id, &ts) != 0) { int err = errno; char *errstr = err ? strerror(err) : "unknown"; - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "clock_gettime(%s, _) failed: %s (%d)\n", name, errstr, err); } @@ -495,13 +495,13 @@ posix_clock_gettime_times(clockid_t mid, char *mname, if (mres != 0) { char *errstr = merr ? strerror(merr) : "unknown"; - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "clock_gettime(%s, _) failed: %s (%d)\n", mname, errstr, merr); } if (sres != 0) { char *errstr = serr ? strerror(serr) : "unknown"; - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "clock_gettime(%s, _) failed: %s (%d)\n", sname, errstr, serr); } @@ -674,7 +674,7 @@ mach_clocks_init(void) clck_srv_p = &internal_state.r.o.mach.clock.monotonic.srv; kret = host_get_clock_service(host, id, clck_srv_p); if (kret != KERN_SUCCESS) { - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "host_get_clock_service(_, %s, _) failed\n", name); } @@ -686,7 +686,7 @@ mach_clocks_init(void) clck_srv_p = &internal_state.r.o.mach.clock.wall.srv; kret = host_get_clock_service(host, id, clck_srv_p); if (kret != KERN_SUCCESS) { - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "host_get_clock_service(_, %s, _) failed\n", name); } @@ -695,7 +695,7 @@ mach_clocks_init(void) if (atexit(mach_clocks_fini) != 0) { int err = errno; char *errstr = err ? strerror(err) : "unknown"; - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Failed to register mach_clocks_fini() " "for call at exit: %s (%d)\n", errstr, err); @@ -717,7 +717,7 @@ mach_clock_getres(ErtsMachClock *clk) (clock_attr_t) attr, &cnt); if (kret != KERN_SUCCESS || cnt != 1) { - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "clock_get_attributes(%s, _) failed\n", clk->name); } @@ -735,7 +735,7 @@ mach_clock_get_time(ErtsMachClock *clk) kret = clock_get_time(clk->srv, &time_spec); if (kret != KERN_SUCCESS) - erl_exit(ERTS_ABORT_EXIT, "clock_get_time(%s, _) failed\n", clk->name); + erts_exit(ERTS_ABORT_EXIT, "clock_get_time(%s, _) failed\n", clk->name); return ERTS_TimeSpec2Sint64(&time_spec); } @@ -781,11 +781,11 @@ erts_os_times(ErtsMonotonicTime *mtimep, ErtsSystemTime *stimep) &sys_time_spec); if (mkret != KERN_SUCCESS) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "clock_get_time(%s, _) failed\n", internal_state.r.o.mach.clock.monotonic.name); if (skret != KERN_SUCCESS) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "clock_get_time(%s, _) failed\n", internal_state.r.o.mach.clock.wall.name); @@ -850,7 +850,7 @@ erts_os_system_time(void) if (gettimeofday(&tv, NULL) != 0) { int err = errno; char *errstr = err ? strerror(err) : "unknown"; - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "gettimeofday(_, NULL) failed: %s (%d)\n", errstr, err); } diff --git a/erts/emulator/sys/win32/erl_poll.c b/erts/emulator/sys/win32/erl_poll.c index 466f4a3b48..547d4b1d21 100644 --- a/erts/emulator/sys/win32/erl_poll.c +++ b/erts/emulator/sys/win32/erl_poll.c @@ -436,7 +436,7 @@ wakeup_cause(ErtsPollSet ps) break; default: res = 0; - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error: Invalid wakeup_state=%d\n", __FILE__, __LINE__, (int) wakeup_state); } @@ -576,7 +576,7 @@ static void signal_standby(ErtsPollSet ps) --(ps->standby_wait_counter); if (ps->standby_wait_counter < 0) { LeaveCriticalSection(&(ps->standby_crit)); - erl_exit(1,"Standby signalled by more threads than expected"); + erts_exit(ERTS_ERROR_EXIT,"Standby signalled by more threads than expected"); } if (!(ps->standby_wait_counter)) { SetEvent(ps->standby_wait_event); @@ -738,7 +738,7 @@ static void *break_waiter(void *param) erts_mtx_unlock(&break_waiter_lock); break; default: - erl_exit(1,"Unexpected event in break_waiter"); + erts_exit(ERTS_ERROR_EXIT,"Unexpected event in break_waiter"); } } } @@ -1157,7 +1157,7 @@ int erts_poll_wait(ErtsPollSet ps, HARDDEBUGF(("Oups!")); /* Oups, got signalled before we took the lock, can't reset */ if(!is_io_ready(ps)) { - erl_exit(1,"Internal error: " + erts_exit(ERTS_ERROR_EXIT,"Internal error: " "Inconsistent io structures in erl_poll.\n"); } START_WAITER(ps,w); @@ -1215,7 +1215,7 @@ int erts_poll_wait(ErtsPollSet ps, ERTS_SET_BREAK_REQUESTED; break; case BREAK_WAITER_GOT_HALT: - erl_exit(0,""); + erts_exit(0,""); break; default: break; diff --git a/erts/emulator/sys/win32/erl_win32_sys_ddll.c b/erts/emulator/sys/win32/erl_win32_sys_ddll.c index 9a5557e93d..7c24a77e31 100644 --- a/erts/emulator/sys/win32/erl_win32_sys_ddll.c +++ b/erts/emulator/sys/win32/erl_win32_sys_ddll.c @@ -52,7 +52,8 @@ void erl_sys_ddll_init(void) { #define ERL_NIF_API_FUNC_DECL(RET,NAME,ARGS) nif_callbacks.NAME = NAME #include "erl_nif_api_funcs.h" #undef ERL_NIF_API_FUNC_DECL - + nif_callbacks.erts_alc_test = erts_alc_test; + return; } diff --git a/erts/emulator/sys/win32/erl_win_dyn_driver.h b/erts/emulator/sys/win32/erl_win_dyn_driver.h index 5e62320be4..9c699fdba0 100644 --- a/erts/emulator/sys/win32/erl_win_dyn_driver.h +++ b/erts/emulator/sys/win32/erl_win_dyn_driver.h @@ -103,6 +103,11 @@ WDD_TYPEDEF(ErlDrvSInt, driver_pdl_inc_refc, (ErlDrvPDL)); WDD_TYPEDEF(ErlDrvSInt, driver_pdl_dec_refc, (ErlDrvPDL)); WDD_TYPEDEF(void, driver_system_info, (ErlDrvSysInfo *, size_t)); WDD_TYPEDEF(int, driver_get_now, (ErlDrvNowData *)); +WDD_TYPEDEF(ErlDrvTime, erl_drv_monotonic_time, (ErlDrvTimeUnit)); +WDD_TYPEDEF(ErlDrvTime, erl_drv_time_offset, (ErlDrvTimeUnit)); +WDD_TYPEDEF(ErlDrvTime, erl_drv_convert_time_unit, (ErlDrvTime, + ErlDrvTimeUnit, + ErlDrvTimeUnit)); WDD_TYPEDEF(int, driver_monitor_process, (ErlDrvPort port, ErlDrvTermData process, ErlDrvMonitor *monitor)); @@ -145,8 +150,8 @@ WDD_TYPEDEF(ErlDrvTid, erl_drv_thread_self, (void)); WDD_TYPEDEF(int, erl_drv_equal_tids, (ErlDrvTid tid1, ErlDrvTid tid2)); WDD_TYPEDEF(void, erl_drv_thread_exit, (void *resp)); WDD_TYPEDEF(int, erl_drv_thread_join, (ErlDrvTid, void **respp)); -WDD_TYPEDEF(int, erl_drv_putenv, (char *key, char *value)); -WDD_TYPEDEF(int, erl_drv_getenv, (char *key, char *value, size_t *value_size)); +WDD_TYPEDEF(int, erl_drv_putenv, (const char *key, char *value)); +WDD_TYPEDEF(int, erl_drv_getenv, (const char *key, char *value, size_t *value_size)); typedef struct { WDD_FTYPE(null_func) *null_func; @@ -217,6 +222,9 @@ typedef struct { WDD_FTYPE(driver_pdl_dec_refc) *driver_pdl_dec_refc; WDD_FTYPE(driver_system_info) *driver_system_info; WDD_FTYPE(driver_get_now) *driver_get_now; + WDD_FTYPE(erl_drv_monotonic_time) *erl_drv_monotonic_time; + WDD_FTYPE(erl_drv_time_offset) *erl_drv_time_offset; + WDD_FTYPE(erl_drv_convert_time_unit) *erl_drv_convert_time_unit; WDD_FTYPE(driver_monitor_process) *driver_monitor_process; WDD_FTYPE(driver_demonitor_process) *driver_demonitor_process; WDD_FTYPE(driver_get_monitored_process) *driver_get_monitored_process; @@ -328,6 +336,9 @@ extern TWinDynDriverCallbacks WinDynDriverCallbacks; #define driver_pdl_dec_refc (WinDynDriverCallbacks.driver_pdl_dec_refc) #define driver_system_info (WinDynDriverCallbacks.driver_system_info) #define driver_get_now (WinDynDriverCallbacks.driver_get_now) +#define erl_drv_monotonic_time (WinDynDriverCallbacks.erl_drv_monotonic_time) +#define erl_drv_time_offset (WinDynDriverCallbacks.erl_drv_time_offset) +#define erl_drv_convert_time_unit (WinDynDriverCallbacks.erl_drv_convert_time_unit) #define driver_monitor_process \ (WinDynDriverCallbacks.driver_monitor_process) #define driver_demonitor_process \ @@ -463,6 +474,9 @@ do { \ ((W).driver_pdl_dec_refc) = driver_pdl_dec_refc; \ ((W).driver_system_info) = driver_system_info; \ ((W).driver_get_now) = driver_get_now; \ +((W).erl_drv_monotonic_time) = erl_drv_monotonic_time; \ +((W).erl_drv_time_offset) = erl_drv_time_offset; \ +((W).erl_drv_convert_time_unit) = erl_drv_convert_time_unit; \ ((W).driver_monitor_process) = driver_monitor_process; \ ((W).driver_demonitor_process) = driver_demonitor_process; \ ((W).driver_get_monitored_process) = driver_get_monitored_process; \ diff --git a/erts/emulator/sys/win32/sys.c b/erts/emulator/sys/win32/sys.c index fce76db28f..37d3e16256 100644 --- a/erts/emulator/sys/win32/sys.c +++ b/erts/emulator/sys/win32/sys.c @@ -38,7 +38,7 @@ void erts_sys_init_float(void); void erl_start(int, char**); -void erl_exit(int n, char*, ...); +void erts_exit(int n, char*, ...); void erl_error(char*, va_list); void erl_crash_dump(char*, int, char*, ...); @@ -200,7 +200,7 @@ erts_sys_misc_mem_sz(void) */ void sys_tty_reset(int exit_code) { - if (exit_code > 0) + if (exit_code == ERTS_ERROR_EXIT) ConWaitForExit(); else ConNormalExit(); @@ -3110,13 +3110,13 @@ check_supported_os_version(void) || int_os_version.dwMajorVersion < major || (int_os_version.dwMajorVersion == major && int_os_version.dwMinorVersion < minor)) - erl_exit(-1, + erts_exit(1, "Windows version not supported " "(min required: winnt %d.%d)\n", major, minor); } #else - erl_exit(-1, + erts_exit(1, "Windows version not supported " "(min required: win %d.%d)\n", nt_major, nt_minor); diff --git a/erts/emulator/sys/win32/sys_interrupt.c b/erts/emulator/sys/win32/sys_interrupt.c index d6178de03c..a89211fa8e 100644 --- a/erts/emulator/sys/win32/sys_interrupt.c +++ b/erts/emulator/sys/win32/sys_interrupt.c @@ -81,7 +81,7 @@ BOOL WINAPI ctrl_handler_ignore_break(DWORD dwCtrlType) return TRUE; /* else pour through... */ case CTRL_CLOSE_EVENT: - erl_exit(0, ""); + erts_exit(0, ""); break; } return TRUE; @@ -106,7 +106,7 @@ BOOL WINAPI ctrl_handler_replace_intr(DWORD dwCtrlType) /* else pour through... */ case CTRL_CLOSE_EVENT: case CTRL_SHUTDOWN_EVENT: - erl_exit(0, ""); + erts_exit(0, ""); break; } return TRUE; @@ -133,7 +133,7 @@ BOOL WINAPI ctrl_handler(DWORD dwCtrlType) return TRUE; /* else pour through... */ case CTRL_CLOSE_EVENT: - erl_exit(0, ""); + erts_exit(0, ""); break; } return TRUE; diff --git a/erts/emulator/sys/win32/sys_time.c b/erts/emulator/sys/win32/sys_time.c index 9e5f78703a..3cf7f7cf07 100644 --- a/erts/emulator/sys/win32/sys_time.c +++ b/erts/emulator/sys/win32/sys_time.c @@ -147,7 +147,7 @@ os_monotonic_time_qpc(void) LARGE_INTEGER pc; if (!(*internal_state.r.o.pQueryPerformanceCounter)(&pc)) - erl_exit(ERTS_ABORT_EXIT, "QueryPerformanceCounter() failed\n"); + erts_exit(ERTS_ABORT_EXIT, "QueryPerformanceCounter() failed\n"); return (ErtsMonotonicTime) pc.QuadPart; } @@ -164,7 +164,7 @@ os_times_qpc(ErtsMonotonicTime *mtimep, ErtsSystemTime *stimep) GetSystemTime(&st); if (!qpcr) - erl_exit(ERTS_ABORT_EXIT, "QueryPerformanceCounter() failed\n"); + erts_exit(ERTS_ABORT_EXIT, "QueryPerformanceCounter() failed\n"); *mtimep = (ErtsMonotonicTime) pc.QuadPart; @@ -251,7 +251,7 @@ sys_hrtime_qpc(void) LARGE_INTEGER pc; if (!(*internal_state.r.o.pQueryPerformanceCounter)(&pc)) - erl_exit(ERTS_ABORT_EXIT, "QueryPerformanceCounter() failed\n"); + erts_exit(ERTS_ABORT_EXIT, "QueryPerformanceCounter() failed\n"); ASSERT(pc.QuadPart > 0); diff --git a/erts/emulator/test/alloc_SUITE.erl b/erts/emulator/test/alloc_SUITE.erl index 7c7ddde5d4..aa6a1fbcdc 100644 --- a/erts/emulator/test/alloc_SUITE.erl +++ b/erts/emulator/test/alloc_SUITE.erl @@ -31,7 +31,8 @@ rbtree/1, mseg_clear_cache/1, erts_mmap/1, - cpool/1]). + cpool/1, + migration/1]). -export([init_per_testcase/2, end_per_testcase/2]). @@ -43,7 +44,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [basic, coalesce, threads, realloc_copy, bucket_index, - bucket_mask, rbtree, mseg_clear_cache, erts_mmap, cpool]. + bucket_mask, rbtree, mseg_clear_cache, erts_mmap, cpool, migration]. groups() -> []. @@ -64,7 +65,7 @@ end_per_group(_GroupName, Config) -> init_per_testcase(Case, Config) when is_list(Config) -> Dog = ?t:timetrap(?t:seconds(?DEFAULT_TIMETRAP_SECS)), - [{watchdog, Dog},{testcase, Case}|Config]. + [{watchdog, Dog}, {testcase, Case}, {debug,false} | Config]. end_per_testcase(_Case, Config) when is_list(Config) -> Dog = ?config(watchdog, Config), @@ -112,6 +113,14 @@ cpool(suite) -> []; cpool(doc) -> []; cpool(Cfg) -> ?line drv_case(Cfg). +migration(Cfg) -> + case erlang:system_info(smp_support) of + true -> + drv_case(Cfg, concurrent, "+MZe true"); + false -> + {skipped, "No smp"} + end. + erts_mmap(Config) when is_list(Config) -> case {?t:os_type(), is_halfword_vm()} of {{unix, _}, false} -> @@ -176,18 +185,17 @@ erts_mmap_do(Config, SCO, SCRPM, SCRFSD) -> %% %% drv_case(Config) -> - drv_case(Config, ""). + drv_case(Config, one_shot, ""). -drv_case(Config, Command) when is_list(Config), - is_list(Command) -> +drv_case(Config, Mode, NodeOpts) when is_list(Config) -> case ?t:os_type() of {Family, _} when Family == unix; Family == win32 -> - ?line {ok, Node} = start_node(Config), + ?line {ok, Node} = start_node(Config, NodeOpts), ?line Self = self(), ?line Ref = make_ref(), ?line spawn_link(Node, fun () -> - Res = run_drv_case(Config, Command), + Res = run_drv_case(Config, Mode), Self ! {Ref, Res} end), ?line Result = receive {Ref, Rslt} -> Rslt end, @@ -199,49 +207,172 @@ drv_case(Config, Command) when is_list(Config), | io_lib:format("~p",[SkipOs])])} end. -run_drv_case(Config, Command) -> - ?line DataDir = ?config(data_dir,Config), - ?line CaseName = ?config(testcase,Config), - case erl_ddll:load_driver(DataDir, CaseName) of - ok -> ok; - {error, Error} -> - io:format("~s\n", [erl_ddll:format_error(Error)]), - ?line ?t:fail() +run_drv_case(Config, Mode) -> + DataDir = ?config(data_dir,Config), + CaseName = ?config(testcase,Config), + File = filename:join(DataDir, CaseName), + {ok,CaseName,Bin} = compile:file(File, [binary,return_errors]), + {module,CaseName} = erlang:load_module(CaseName,Bin), + print_stats(CaseName), + ok = CaseName:init(File), + + SlaveState = slave_init(CaseName), + case Mode of + one_shot -> + Result = one_shot(CaseName); + + concurrent -> + Result = concurrent(CaseName) end, - ?line Port = open_port({spawn, atom_to_list(CaseName)}, []), - ?line true = is_port(Port), - ?line Port ! {self(), {command, Command}}, - ?line Result = receive_drv_result(Port, CaseName), - ?line Port ! {self(), close}, - ?line receive - {Port, closed} -> - ok - end, - ?line ok = erl_ddll:unload_driver(CaseName), - ?line Result. - -receive_drv_result(Port, CaseName) -> - ?line receive - {print, Port, CaseName, Str} -> - ?line ?t:format("~s", [Str]), - ?line receive_drv_result(Port, CaseName); - {'EXIT', Port, Error} -> - ?line ?t:fail(Error); - {'EXIT', error, Error} -> - ?line ?t:fail(Error); - {failed, Port, CaseName, Comment} -> - ?line ?t:fail(Comment); - {skipped, Port, CaseName, Comment} -> - ?line {skipped, Comment}; - {succeeded, Port, CaseName, ""} -> - ?line succeeded; - {succeeded, Port, CaseName, Comment} -> - ?line {comment, Comment} - end. - -start_node(Config) -> - start_node(Config, []). + + wait_for_memory_deallocations(), + print_stats(CaseName), + + true = erlang:delete_module(CaseName), + slave_end(SlaveState), + Result. + +slave_init(migration) -> + A0 = case application:start(sasl) of + ok -> [sasl]; + _ -> [] + end, + case application:start(os_mon) of + ok -> [os_mon|A0]; + _ -> A0 + end; +slave_init(_) -> []. + +slave_end(Apps) -> + lists:foreach(fun (A) -> application:stop(A) end, Apps). + +wait_for_memory_deallocations() -> + try + erts_debug:set_internal_state(wait, deallocations) + catch + error:undef -> + erts_debug:set_internal_state(available_internal_state, true), + wait_for_memory_deallocations() + end. + +print_stats(migration) -> + {Btot,Ctot} = lists:foldl(fun({instance,Inr,Istats}, {Bacc,Cacc}) -> + {mbcs,MBCS} = lists:keyfind(mbcs, 1, Istats), + Btup = lists:keyfind(blocks, 1, MBCS), + Ctup = lists:keyfind(carriers, 1, MBCS), + io:format("{instance,~p,~p,~p}\n", [Inr, Btup, Ctup]), + {tuple_add(Bacc,Btup),tuple_add(Cacc,Ctup)}; + (_, Acc) -> Acc + end, + {{blocks,0,0,0},{carriers,0,0,0}}, + erlang:system_info({allocator,test_alloc})), + + io:format("Number of blocks : ~p\n", [Btot]), + io:format("Number of carriers: ~p\n", [Ctot]); + +print_stats(_) -> ok. + +tuple_add(T1, T2) -> + list_to_tuple(lists:zipwith(fun(E1,E2) when is_number(E1), is_number(E2) -> + E1 + E2; + (A,A) -> + A + end, + tuple_to_list(T1), tuple_to_list(T2))). + + +one_shot(CaseName) -> + State = CaseName:start({1, 0, erlang:system_info(build_type)}), + Result0 = CaseName:run(State), + false = (Result0 =:= continue), + Result1 = handle_result(State, Result0), + CaseName:stop(State), + Result1. + + +many_shot(CaseName, I, Mem) -> + State = CaseName:start({I, Mem, erlang:system_info(build_type)}), + Result1 = repeat_while(fun() -> + Result0 = CaseName:run(State), + handle_result(State, Result0) + end, + 10*1000, I), + CaseName:stop(State), + flush_log(), + Result1. + +concurrent(CaseName) -> + NSched = erlang:system_info(schedulers), + Mem = (free_memory() * 3) div 4, + PRs = lists:map(fun(I) -> spawn_opt(fun() -> + many_shot(CaseName, I, + Mem div NSched) + end, + [monitor, {scheduler,I}]) + end, + lists:seq(1, NSched)), + lists:foreach(fun({Pid,Ref}) -> + receive {'DOWN', Ref, process, Pid, Reason} -> + Reason + end + end, + PRs), + ok. + +repeat_while(Fun, Timeout, I) -> + TRef = erlang:start_timer(Timeout, self(), timeout), + R = repeat_while_loop(Fun, TRef, I), + erlang:cancel_timer(TRef, [{async,true},{info,false}]), + R. + +repeat_while_loop(Fun, TRef, I) -> + receive + {timeout, TRef, timeout} -> + io:format("~p: Timeout, enough is enough.",[I]), + succeeded + after 0 -> + %%io:format("~p calls fun\n", [self()]), + case Fun() of + continue -> repeat_while_loop(Fun, TRef, I); + R -> R + end + end. + +flush_log() -> + receive + {print, Str} -> + ?t:format("~s", [Str]), + flush_log() + after 0 -> + ok + end. + +handle_result(_State, Result0) -> + flush_log(), + case Result0 of + {'EXIT', Error} -> + ?line ?t:fail(Error); + {'EXIT', error, Error} -> + ?line ?t:fail(Error); + {failed, Comment} -> + ?line ?t:fail(Comment); + {skipped, Comment} -> + ?line {skipped, Comment}; + {succeeded, ""} -> + ?line succeeded; + {succeeded, Comment} -> + ?line {comment, Comment}; + continue -> + continue + end. + start_node(Config, Opts) when is_list(Config), is_list(Opts) -> + case ?config(debug,Config) of + true -> {ok, node()}; + _ -> start_node_1(Config, Opts) + end. + +start_node_1(Config, Opts) -> Pa = filename:dirname(code:which(?MODULE)), Name = list_to_atom(atom_to_list(?MODULE) ++ "-" @@ -252,6 +383,7 @@ start_node(Config, Opts) when is_list(Config), is_list(Opts) -> ++ integer_to_list(erlang:unique_integer([positive]))), ?t:start_node(Name, slave, [{args, Opts++" -pa "++Pa}]). +stop_node(Node) when Node =:= node() -> ok; stop_node(Node) -> ?t:stop_node(Node). @@ -261,3 +393,23 @@ is_halfword_vm() -> {4, 8} -> true; {WS, WS} -> false end. + +free_memory() -> + %% Free memory in MB. + try + SMD = memsup:get_system_memory_data(), + {value, {free_memory, Free}} = lists:keysearch(free_memory, 1, SMD), + TotFree = (Free + + case lists:keysearch(cached_memory, 1, SMD) of + {value, {cached_memory, Cached}} -> Cached; + false -> 0 + end + + case lists:keysearch(buffered_memory, 1, SMD) of + {value, {buffered_memory, Buffed}} -> Buffed; + false -> 0 + end), + TotFree div (1024*1024) + catch + error : undef -> + ?t:fail({"os_mon not built"}) + end. diff --git a/erts/emulator/test/alloc_SUITE_data/Makefile.src b/erts/emulator/test/alloc_SUITE_data/Makefile.src index a441fe946b..e31de54e1b 100644 --- a/erts/emulator/test/alloc_SUITE_data/Makefile.src +++ b/erts/emulator/test/alloc_SUITE_data/Makefile.src @@ -25,7 +25,8 @@ TEST_DRVS = basic@dll@ \ bucket_mask@dll@ \ rbtree@dll@ \ mseg_clear_cache@dll@ \ - cpool@dll@ + cpool@dll@ \ + migration@dll@ CC = @CC@ LD = @LD@ diff --git a/erts/emulator/test/alloc_SUITE_data/allocator_test.h b/erts/emulator/test/alloc_SUITE_data/allocator_test.h index 1d6b2f4907..97ee58cdad 100644 --- a/erts/emulator/test/alloc_SUITE_data/allocator_test.h +++ b/erts/emulator/test/alloc_SUITE_data/allocator_test.h @@ -20,9 +20,20 @@ #ifndef ALLOCATOR_TEST_H__ #define ALLOCATOR_TEST_H__ -typedef ErlDrvUInt Ulong; +#if SIZEOF_VOID_P == SIZEOF_INT +typedef unsigned int Ulong; +#elif SIZEOF_VOID_P == SIZEOF_LONG +typedef unsigned long Ulong; +#elif SIZEOF_VOID_P == SIZEOF_LONG_LONG +typedef unsigned long long Ulong; +#else +# error No pointer sized integer type found ??? +#endif -#ifndef __WIN32__ +#ifdef __WIN32__ +typedef Ulong erts_alc_test_Fn(Ulong, Ulong, Ulong, Ulong); +# define erts_alc_test ((erts_alc_test_Fn*)WinDynNifCallbacks.erts_alc_test) +#else Ulong erts_alc_test(Ulong, Ulong, Ulong, Ulong); #endif @@ -85,6 +96,7 @@ typedef void* erts_cond; #define CPOOL_DELETE(A,B) ((Carrier_t *) ALC_TEST2(0x022, (A), (B))) #define CPOOL_IS_EMPTY(A) ((int) ALC_TEST1(0x023, (A))) #define CPOOL_IS_IN_POOL(A,B) ((int) ALC_TEST2(0x024, (A), (B))) +#define UMEM2BLK_TEST(P) ((Block_t*) ALC_TEST1(0x025, (P))) /* From erl_goodfit_alloc.c */ #define BKT_IX(A, S) ((Ulong) ALC_TEST2(0x100, (A), (S))) @@ -142,5 +154,9 @@ typedef void* erts_cond; #define THR_JOIN(T) ((void) ALC_TEST1(0xf11, (T))) #define THR_EXIT(R) ((void) ALC_TEST1(0xf12, (R))) #define IS_SMP_ENABLED ((int) ALC_TEST0(0xf13)) +#define ALLOC_TEST(S) ((void*) ALC_TEST1(0xf14, (S))) +#define FREE_TEST(P) ((void) ALC_TEST1(0xf15, (P))) +#define SET_TEST_MBC_USER_HEADER(SZ,CMBC,DMBC) ((int)ALC_TEST3(0xf16, (SZ), (CMBC), (DMBC))) +#define GET_TEST_MBC_SIZE() ((int) ALC_TEST0(0xf17)) #endif diff --git a/erts/emulator/test/alloc_SUITE_data/basic.c b/erts/emulator/test/alloc_SUITE_data/basic.c index 323a24a11f..debb3d7ebe 100644 --- a/erts/emulator/test/alloc_SUITE_data/basic.c +++ b/erts/emulator/test/alloc_SUITE_data/basic.c @@ -60,3 +60,6 @@ testcase_cleanup(TestCaseState_t *tcs) if (tcs->extra) STOP_ALC((Allctr_t *) tcs->extra); } + +ERL_NIF_INIT(basic, testcase_nif_funcs, testcase_nif_init, + NULL, NULL, NULL); diff --git a/erts/emulator/test/alloc_SUITE_data/basic.erl b/erts/emulator/test/alloc_SUITE_data/basic.erl new file mode 100644 index 0000000000..a018fd5582 --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/basic.erl @@ -0,0 +1,10 @@ +-module(basic). + +-export([init/1, start/1, run/1, stop/1]). + +init(File) -> + ok = erlang:load_nif(File, 0). + +start(_) -> erlang:nif_error(not_loaded). +run(_) -> erlang:nif_error(not_loaded). +stop(_) -> erlang:nif_error(not_loaded). diff --git a/erts/emulator/test/alloc_SUITE_data/bucket_index.c b/erts/emulator/test/alloc_SUITE_data/bucket_index.c index c13f229049..45cb53fbf7 100644 --- a/erts/emulator/test/alloc_SUITE_data/bucket_index.c +++ b/erts/emulator/test/alloc_SUITE_data/bucket_index.c @@ -113,3 +113,5 @@ test_it(TestCaseState_t *tcs, unsigned sbct) sbct ? sbct_buf : "default"); } +ERL_NIF_INIT(bucket_index, testcase_nif_funcs, testcase_nif_init, + NULL, NULL, NULL); diff --git a/erts/emulator/test/alloc_SUITE_data/bucket_index.erl b/erts/emulator/test/alloc_SUITE_data/bucket_index.erl new file mode 100644 index 0000000000..c54f54e2f5 --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/bucket_index.erl @@ -0,0 +1,10 @@ +-module(bucket_index). + +-export([init/1, start/1, run/1, stop/1]). + +init(File) -> + ok = erlang:load_nif(File, 0). + +start(_) -> erlang:nif_error(not_loaded). +run(_) -> erlang:nif_error(not_loaded). +stop(_) -> erlang:nif_error(not_loaded). diff --git a/erts/emulator/test/alloc_SUITE_data/bucket_mask.c b/erts/emulator/test/alloc_SUITE_data/bucket_mask.c index 8d6166771e..c94c265f4e 100644 --- a/erts/emulator/test/alloc_SUITE_data/bucket_mask.c +++ b/erts/emulator/test/alloc_SUITE_data/bucket_mask.c @@ -52,7 +52,7 @@ testcase_run(TestCaseState_t *tcs) typedef struct linked_block { struct linked_block* next; }Linked; - Linked* link; + Linked* link = NULL; Linked* fence_list; Linked* pad_list; void* tmp; @@ -183,3 +183,5 @@ testcase_run(TestCaseState_t *tcs) tcs->extra = NULL; } +ERL_NIF_INIT(bucket_mask, testcase_nif_funcs, testcase_nif_init, + NULL, NULL, NULL); diff --git a/erts/emulator/test/alloc_SUITE_data/bucket_mask.erl b/erts/emulator/test/alloc_SUITE_data/bucket_mask.erl new file mode 100644 index 0000000000..589a50e1fa --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/bucket_mask.erl @@ -0,0 +1,10 @@ +-module(bucket_mask). + +-export([init/1, start/1, run/1, stop/1]). + +init(File) -> + ok = erlang:load_nif(File, 0). + +start(_) -> erlang:nif_error(not_loaded). +run(_) -> erlang:nif_error(not_loaded). +stop(_) -> erlang:nif_error(not_loaded). diff --git a/erts/emulator/test/alloc_SUITE_data/coalesce.c b/erts/emulator/test/alloc_SUITE_data/coalesce.c index 0a5e0c5b0e..7791409a34 100644 --- a/erts/emulator/test/alloc_SUITE_data/coalesce.c +++ b/erts/emulator/test/alloc_SUITE_data/coalesce.c @@ -317,3 +317,6 @@ testcase_cleanup(TestCaseState_t *tcs) if (tcs->extra) STOP_ALC((Allctr_t *) tcs->extra); } + +ERL_NIF_INIT(coalesce, testcase_nif_funcs, testcase_nif_init, + NULL, NULL, NULL); diff --git a/erts/emulator/test/alloc_SUITE_data/coalesce.erl b/erts/emulator/test/alloc_SUITE_data/coalesce.erl new file mode 100644 index 0000000000..453c726c4e --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/coalesce.erl @@ -0,0 +1,10 @@ +-module(coalesce). + +-export([init/1, start/1, run/1, stop/1]). + +init(File) -> + ok = erlang:load_nif(File, 0). + +start(_) -> erlang:nif_error(not_loaded). +run(_) -> erlang:nif_error(not_loaded). +stop(_) -> erlang:nif_error(not_loaded). diff --git a/erts/emulator/test/alloc_SUITE_data/cpool.c b/erts/emulator/test/alloc_SUITE_data/cpool.c index 75c2bc13ae..73026cc758 100644 --- a/erts/emulator/test/alloc_SUITE_data/cpool.c +++ b/erts/emulator/test/alloc_SUITE_data/cpool.c @@ -86,13 +86,13 @@ thread_func(void *arg) for (i = 0; i < (TEST_NO_CARRIERS_PER_THREAD+TEST_CARRIERS_OFFSET); i++) { int d; if (i < TEST_NO_CARRIERS_PER_THREAD) { - CPOOL_INSERT(alloc, crr[i]); + (void) CPOOL_INSERT(alloc, crr[i]); if ((i & 0x7) == 0) FATAL_ASSERT(CPOOL_IS_IN_POOL(alloc, crr[i])); } d = i-TEST_CARRIERS_OFFSET; if (d >= 0) { - CPOOL_DELETE(alloc, crr[d]); + (void) CPOOL_DELETE(alloc, crr[d]); if ((d & 0x7) == 0) FATAL_ASSERT(!CPOOL_IS_IN_POOL(alloc, crr[d])); } @@ -129,7 +129,7 @@ testcase_run(TestCaseState_t *tcs) for (c = 0; c < TEST_NO_CARRIERS_PER_THREAD; c++) { Carrier_t *crr = (Carrier_t *) p; p += zcrr_sz; - ZERO_CRR_INIT(alloc, crr); + (void) ZERO_CRR_INIT(alloc, crr); threads[t].crr[c] = crr; } } @@ -156,3 +156,6 @@ testcase_run(TestCaseState_t *tcs) ASSERT(tcs, no_threads == TEST_NO_THREADS); } + +ERL_NIF_INIT(cpool, testcase_nif_funcs, testcase_nif_init, + NULL, NULL, NULL); diff --git a/erts/emulator/test/alloc_SUITE_data/cpool.erl b/erts/emulator/test/alloc_SUITE_data/cpool.erl new file mode 100644 index 0000000000..89053471fa --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/cpool.erl @@ -0,0 +1,10 @@ +-module(cpool). + +-export([init/1, start/1, run/1, stop/1]). + +init(File) -> + ok = erlang:load_nif(File, 0). + +start(_) -> erlang:nif_error(not_loaded). +run(_) -> erlang:nif_error(not_loaded). +stop(_) -> erlang:nif_error(not_loaded). diff --git a/erts/emulator/test/alloc_SUITE_data/migration.c b/erts/emulator/test/alloc_SUITE_data/migration.c new file mode 100644 index 0000000000..b006360043 --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/migration.c @@ -0,0 +1,343 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2014. 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% + */ + +/* + * Test the carrier migration logic + */ + +#ifndef __WIN32__ +#include <sys/types.h> +#include <unistd.h> +#include <errno.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include "testcase_driver.h" +#include "allocator_test.h" + +#define FATAL_ASSERT(A) \ + ((void) ((A) \ + ? 1 \ + : (fatal_assert_failed(#A, \ + (char *) __FILE__, \ + __LINE__), \ + 0))) + +static void +fatal_assert_failed(char* expr, char* file, int line) +{ + fflush(stdout); + fprintf(stderr, "%s:%d: Assertion failed: %s\n", + file, line, expr); + fflush(stderr); + abort(); +} + + +char * +testcase_name(void) +{ + return "migration"; +} + +/* Turns out random_r() is a nonstandard glibc extension. +#define HAVE_RANDOM_R +*/ +#ifdef HAVE_RANDOM_R + +typedef struct { struct random_data rnd; char rndbuf[32]; } MyRandState; + +static void myrand_init(MyRandState* mrs, unsigned int seed) +{ + int res; + memset(&mrs->rnd, 0, sizeof(mrs->rnd)); + res = initstate_r(seed, mrs->rndbuf, sizeof(mrs->rndbuf), &mrs->rnd); + FATAL_ASSERT(res == 0); +} + +static int myrand(MyRandState* mrs) +{ + int32_t x; + int res = random_r(&mrs->rnd, &x); + FATAL_ASSERT(res == 0); + return (int)x; +} + +#else /* !HAVE_RANDOM_R */ + +typedef unsigned int MyRandState; + +static void myrand_init(MyRandState* mrs, unsigned int seed) +{ + *mrs = seed; +} + +static int myrand(MyRandState* mrs) +{ + /* Taken from rand(3) man page. + * Modified to return a full 31-bit value by using low half of *mrs as well. + */ + *mrs = (*mrs) * 1103515245 + 12345; + return (int) (((*mrs >> 16) | (*mrs << 16)) & ~(1 << 31)); +} + +#endif /* !HAVE_RANDOM_R */ + +#define MAX_BLOCK_PER_THR 200 +#define BLOCKS_PER_MBC 10 +#define MAX_ROUNDS 10000 + +typedef struct MyBlock_ { + struct MyBlock_* next; + struct MyBlock_** prevp; +} MyBlock; + +typedef struct { + MyBlock* blockv[MAX_BLOCK_PER_THR]; + MyRandState rand_state; + enum { GROWING, SHRINKING, CLEANUP, DONE } phase; + int nblocks; + int goal_nblocks; + int round; + int nr_of_migrations; + int nr_of_carriers; + int max_blocks_in_mbc; + int block_size; + int max_nblocks; +} MigrationState; + +typedef struct { + ErlNifMutex* mtx; + int nblocks; + MyBlock* first; + MigrationState* employer; +} MyCrrInfo; + + +static int crr_info_offset = -1; +static void (*orig_create_mbc_fn)(Allctr_t *allctr, Carrier_t *carrier); +static void (*orig_destroying_mbc_fn)(Allctr_t *allctr, Carrier_t *carrier); + +static void my_creating_mbc(Allctr_t *allctr, Carrier_t *carrier) +{ + MyCrrInfo* mci = (MyCrrInfo*) ((char*)carrier + crr_info_offset); + if (orig_create_mbc_fn) + orig_create_mbc_fn(allctr, carrier); + + mci->mtx = enif_mutex_create("alloc_SUITE.migration"); + mci->nblocks = 0; + mci->first = NULL; + mci->employer = NULL; +} + +static void my_destroying_mbc(Allctr_t *allctr, Carrier_t *carrier) +{ + MyCrrInfo* mci = (MyCrrInfo*) ((char*)carrier + crr_info_offset); + + FATAL_ASSERT(mci->nblocks == 0); + FATAL_ASSERT(mci->first == NULL); + enif_mutex_destroy(mci->mtx); + + if (orig_destroying_mbc_fn) + orig_destroying_mbc_fn(allctr, carrier); +} + +static int migration_init(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + void* creating_mbc_arg = (void*)my_creating_mbc; + void* destroying_mbc_arg = (void*)my_destroying_mbc; + + if (testcase_nif_init(env, priv_data, load_info)) + return -1; + + crr_info_offset = SET_TEST_MBC_USER_HEADER(sizeof(MyCrrInfo), + &creating_mbc_arg, + &destroying_mbc_arg); + FATAL_ASSERT(crr_info_offset >= 0); + orig_create_mbc_fn = creating_mbc_arg; + orig_destroying_mbc_fn = destroying_mbc_arg; + + return 0; +} + +static void add_block(MyBlock* p, MigrationState* state) +{ + MyCrrInfo* mci = (MyCrrInfo*)((char*)BLK_TO_MBC(UMEM2BLK_TEST(p)) + crr_info_offset); + + enif_mutex_lock(mci->mtx); + if (++mci->nblocks > state->max_blocks_in_mbc) + state->max_blocks_in_mbc = mci->nblocks; + p->next = mci->first; + p->prevp = &mci->first; + mci->first = p; + if (p->next) + p->next->prevp = &p->next; + if (mci->employer != state) { + if (!mci->employer) { + FATAL_ASSERT(mci->nblocks == 1); + state->nr_of_carriers++; + } + else { + state->nr_of_migrations++; + } + mci->employer = state; + } + enif_mutex_unlock(mci->mtx); +} + +static void remove_block(MyBlock* p) +{ + MyCrrInfo* mci = (MyCrrInfo*)((char*)BLK_TO_MBC(UMEM2BLK_TEST(p)) + crr_info_offset); + + enif_mutex_lock(mci->mtx); + mci->nblocks--; + if (p->next) + p->next->prevp = p->prevp; + *p->prevp = p->next; + enif_mutex_unlock(mci->mtx); +} + +static int rand_int(MigrationState* state, int low, int high) +{ + int x; + FATAL_ASSERT(high >= low); + x = myrand(&state->rand_state); + return low + (x % (high+1-low)); +} + + +static void do_cleanup(TestCaseState_t *tcs, MigrationState* state) +{ + if (state->nblocks == 0) { + state->phase = DONE; + testcase_printf(tcs, "%d: Done %d rounds", tcs->thr_nr, state->round); + testcase_printf(tcs, "%d: Cleanup all blocks", tcs->thr_nr); + testcase_printf(tcs, "%d: Empty carriers detected = %d", tcs->thr_nr, + state->nr_of_carriers); + testcase_printf(tcs, "%d: Migrations detected = %d", tcs->thr_nr, + state->nr_of_migrations); + testcase_printf(tcs, "%d: Max blocks in carrier = %d", tcs->thr_nr, + state->max_blocks_in_mbc); + } + else { + state->nblocks--; + if (state->blockv[state->nblocks]) { + remove_block(state->blockv[state->nblocks]); + FREE_TEST(state->blockv[state->nblocks]); + } + } +} + + +void +testcase_run(TestCaseState_t *tcs) +{ + MigrationState* state = (MigrationState*) tcs->extra; + + if (!tcs->extra) { + if (!IS_SMP_ENABLED) + testcase_skipped(tcs, "No SMP support"); + + tcs->extra = enif_alloc(sizeof(MigrationState)); + state = (MigrationState*) tcs->extra; + memset(state->blockv, 0, sizeof(state->blockv)); + myrand_init(&state->rand_state, tcs->thr_nr); + state->phase = GROWING; + state->nblocks = 0; + state->round = 0; + state->nr_of_migrations = 0; + state->nr_of_carriers = 0; + state->max_blocks_in_mbc = 0; + state->block_size = GET_TEST_MBC_SIZE() / (BLOCKS_PER_MBC+1); + if (MAX_BLOCK_PER_THR * state->block_size < tcs->free_mem) { + state->max_nblocks = MAX_BLOCK_PER_THR; + } else { + state->max_nblocks = tcs->free_mem / state->block_size; + } + state->goal_nblocks = rand_int(state, 1, state->max_nblocks); + } + + switch (state->phase) { + case GROWING: { + MyBlock* p; + FATAL_ASSERT(!state->blockv[state->nblocks]); + p = ALLOC_TEST(rand_int(state, state->block_size/2, state->block_size)); + FATAL_ASSERT(p); + add_block(p, state); + state->blockv[state->nblocks] = p; + if (++state->nblocks >= state->goal_nblocks) { + /*testcase_printf(tcs, "%d: Grown to %d blocks", tcs->thr_nr, state->nblocks);*/ + state->phase = SHRINKING; + state->goal_nblocks = rand_int(state, 0, state->goal_nblocks-1); + } + else + FATAL_ASSERT(!state->blockv[state->nblocks]); + break; + } + case SHRINKING: { + int ix = rand_int(state, 0, state->nblocks-1); + FATAL_ASSERT(state->blockv[ix]); + remove_block(state->blockv[ix]); + FREE_TEST(state->blockv[ix]); + state->blockv[ix] = state->blockv[--state->nblocks]; + state->blockv[state->nblocks] = NULL; + + if (state->nblocks <= state->goal_nblocks) { + /*testcase_printf(tcs, "%d: Shrunk to %d blocks", tcs->thr_nr, state->nblocks);*/ + if (++state->round >= MAX_ROUNDS) { + state->phase = CLEANUP; + } else { + state->phase = GROWING; + state->goal_nblocks = rand_int(state, state->goal_nblocks+1, state->max_nblocks); + } + } + break; + } + case CLEANUP: + do_cleanup(tcs, state); + break; + + default: + FATAL_ASSERT(!"Invalid phase"); + } + + if (state->phase == DONE) { + } + else { + testcase_continue(tcs); + } +} + +void +testcase_cleanup(TestCaseState_t *tcs) +{ + MigrationState* state = (MigrationState*) tcs->extra; + + while (state->phase != DONE) + do_cleanup(tcs, state); + + enif_free(tcs->extra); + tcs->extra = NULL; +} + + +ERL_NIF_INIT(migration, testcase_nif_funcs, migration_init, + NULL, NULL, NULL); diff --git a/erts/emulator/test/alloc_SUITE_data/migration.erl b/erts/emulator/test/alloc_SUITE_data/migration.erl new file mode 100644 index 0000000000..440a99becd --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/migration.erl @@ -0,0 +1,10 @@ +-module(migration). + +-export([init/1, start/1, run/1, stop/1]). + +init(File) -> + ok = erlang:load_nif(File, 0). + +start(_) -> erlang:nif_error(not_loaded). +run(_) -> erlang:nif_error(not_loaded). +stop(_) -> erlang:nif_error(not_loaded). diff --git a/erts/emulator/test/alloc_SUITE_data/mseg_clear_cache.c b/erts/emulator/test/alloc_SUITE_data/mseg_clear_cache.c index 9c03f3a331..e5df3d647f 100644 --- a/erts/emulator/test/alloc_SUITE_data/mseg_clear_cache.c +++ b/erts/emulator/test/alloc_SUITE_data/mseg_clear_cache.c @@ -101,3 +101,6 @@ testcase_cleanup(TestCaseState_t *tcs) tcs->extra = NULL; } } + +ERL_NIF_INIT(mseg_clear_cache, testcase_nif_funcs, testcase_nif_init, + NULL, NULL, NULL); diff --git a/erts/emulator/test/alloc_SUITE_data/mseg_clear_cache.erl b/erts/emulator/test/alloc_SUITE_data/mseg_clear_cache.erl new file mode 100644 index 0000000000..befd6c2e8e --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/mseg_clear_cache.erl @@ -0,0 +1,10 @@ +-module(mseg_clear_cache). + +-export([init/1, start/1, run/1, stop/1]). + +init(File) -> + ok = erlang:load_nif(File, 0). + +start(_) -> erlang:nif_error(not_loaded). +run(_) -> erlang:nif_error(not_loaded). +stop(_) -> erlang:nif_error(not_loaded). diff --git a/erts/emulator/test/alloc_SUITE_data/rbtree.c b/erts/emulator/test/alloc_SUITE_data/rbtree.c index 8d4d5535a8..38bbbdf90c 100644 --- a/erts/emulator/test/alloc_SUITE_data/rbtree.c +++ b/erts/emulator/test/alloc_SUITE_data/rbtree.c @@ -20,7 +20,7 @@ #include "testcase_driver.h" #include "allocator_test.h" -#define NO_BLOCKS 100000 +int NO_BLOCKS; #define RIGHT_VISITED (1 << 0) #define LEFT_VISITED (1 << 1) @@ -265,9 +265,10 @@ check_tree(TestCaseState_t *tcs, Allctr_t *alc, Ulong size) ASSERT(tcs, curr_blacks == 0); ASSERT(tcs, i == -1); + /* testcase_printf(tcs, "Red-Black Tree OK! Max depth = %d; " "Black depth = %d\n", max_i+1, blacks < 0 ? 0 : blacks); - + */ return res; } @@ -468,6 +469,12 @@ testcase_run(TestCaseState_t *tcs) Allctr_t *a; rbtree_test_data *td; + NO_BLOCKS = 100*1000; + if (enif_is_identical(tcs->build_type, + enif_make_atom(tcs->curr_env,"valgrind"))) { + NO_BLOCKS /= 10; + } + /* Best fit... */ testcase_printf(tcs, "Setup...\n"); @@ -577,3 +584,6 @@ testcase_run(TestCaseState_t *tcs) testcase_printf(tcs, "aoffcaobf test succeeded!\n"); } + +ERL_NIF_INIT(rbtree, testcase_nif_funcs, testcase_nif_init, + NULL, NULL, NULL); diff --git a/erts/emulator/test/alloc_SUITE_data/rbtree.erl b/erts/emulator/test/alloc_SUITE_data/rbtree.erl new file mode 100644 index 0000000000..f5b7120ff2 --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/rbtree.erl @@ -0,0 +1,10 @@ +-module(rbtree). + +-export([init/1, start/1, run/1, stop/1]). + +init(File) -> + ok = erlang:load_nif(File, 0). + +start(_) -> erlang:nif_error(not_loaded). +run(_) -> erlang:nif_error(not_loaded). +stop(_) -> erlang:nif_error(not_loaded). diff --git a/erts/emulator/test/alloc_SUITE_data/realloc_copy.c b/erts/emulator/test/alloc_SUITE_data/realloc_copy.c index e405f06225..c4147eb00d 100644 --- a/erts/emulator/test/alloc_SUITE_data/realloc_copy.c +++ b/erts/emulator/test/alloc_SUITE_data/realloc_copy.c @@ -278,3 +278,5 @@ testcase_cleanup(TestCaseState_t *tcs) STOP_ALC((Allctr_t *) tcs->extra); } +ERL_NIF_INIT(realloc_copy, testcase_nif_funcs, testcase_nif_init, + NULL, NULL, NULL); diff --git a/erts/emulator/test/alloc_SUITE_data/realloc_copy.erl b/erts/emulator/test/alloc_SUITE_data/realloc_copy.erl new file mode 100644 index 0000000000..cc6617bf64 --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/realloc_copy.erl @@ -0,0 +1,10 @@ +-module(realloc_copy). + +-export([init/1, start/1, run/1, stop/1]). + +init(File) -> + ok = erlang:load_nif(File, 0). + +start(_) -> erlang:nif_error(not_loaded). +run(_) -> erlang:nif_error(not_loaded). +stop(_) -> erlang:nif_error(not_loaded). diff --git a/erts/emulator/test/alloc_SUITE_data/testcase_driver.c b/erts/emulator/test/alloc_SUITE_data/testcase_driver.c index bc674c56b7..7dcca544e5 100644 --- a/erts/emulator/test/alloc_SUITE_data/testcase_driver.c +++ b/erts/emulator/test/alloc_SUITE_data/testcase_driver.c @@ -23,141 +23,147 @@ #include <stdarg.h> #include <setjmp.h> #include <string.h> +#include <limits.h> #ifdef __WIN32__ -#undef HAVE_VSNPRINTF -#define HAVE_VSNPRINTF 1 -#define vsnprintf _vsnprintf +static void my_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) +{ + _vsnprintf(outBuf, size, format, ap); + outBuf[size-1] = 0; /* be sure string is terminated */ +} +#elif defined(HAVE_VSNPRINTF) +# define my_vsnprintf(B,S,F,A) (void)vsnprintf(B,S,F,A) +#else +# warning Using unsafe 'vsprintf' without buffer overflow protection +# define my_vsnprintf(B,S,F,A) (void)vsprintf(B,F,A) #endif -#ifndef HAVE_VSNPRINTF -#define HAVE_VSNPRINTF 0 -#endif +static void my_snprintf(char *outBuf, size_t size, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + my_vsnprintf(outBuf, size, format, ap); + va_end(ap); +} #define COMMENT_BUF_SZ 4096 #define TESTCASE_FAILED 0 #define TESTCASE_SKIPPED 1 #define TESTCASE_SUCCEEDED 2 +#define TESTCASE_CONTINUE 3 typedef struct { TestCaseState_t visible; - ErlDrvPort port; - ErlDrvTermData port_id; int result; - jmp_buf done_jmp_buf; + jmp_buf* done_jmp_buf; char *comment; char comment_buf[COMMENT_BUF_SZ]; } InternalTestCaseState_t; -ErlDrvData testcase_drv_start(ErlDrvPort port, char *command); -void testcase_drv_stop(ErlDrvData drv_data); -void testcase_drv_run(ErlDrvData drv_data, char *buf, ErlDrvSizeT len); - -static ErlDrvEntry testcase_drv_entry = { - NULL, - testcase_drv_start, - testcase_drv_stop, - testcase_drv_run, - NULL, - NULL, - "testcase_drv", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - ERL_DRV_EXTENDED_MARKER, - ERL_DRV_EXTENDED_MAJOR_VERSION, - ERL_DRV_EXTENDED_MINOR_VERSION, - 0, - NULL, - NULL, - NULL +ERL_NIF_TERM testcase_nif_start(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +ERL_NIF_TERM testcase_nif_stop(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +ERL_NIF_TERM testcase_nif_run(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); + +ErlNifFunc testcase_nif_funcs[] = +{ + {"start", 1, testcase_nif_start}, + {"run", 1, testcase_nif_run}, + {"stop", 1, testcase_nif_stop} }; +static ErlNifResourceType* testcase_rt; +static ERL_NIF_TERM print_atom; -DRIVER_INIT(testcase_drv) +int testcase_nif_init(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) { - testcase_drv_entry.driver_name = testcase_name(); - return &testcase_drv_entry; + testcase_rt = enif_open_resource_type(env, NULL, "testcase_rt", NULL, + ERL_NIF_RT_CREATE, NULL); + + print_atom = enif_make_atom(env, "print"); + return 0; } -ErlDrvData -testcase_drv_start(ErlDrvPort port, char *command) -{ +ERL_NIF_TERM +testcase_nif_start(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ /* (ThrNr, FreeMeg, BuildType) */ + ERL_NIF_TERM ret; InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) - driver_alloc(sizeof(InternalTestCaseState_t)); - if (!itcs) { - return ERL_DRV_ERROR_GENERAL; + enif_alloc_resource(testcase_rt, sizeof(InternalTestCaseState_t)); + int free_megabyte; + const int max_megabyte = INT_MAX / (1024*1024); + const ERL_NIF_TERM* tpl; + int tpl_arity; + + if (!itcs + || !enif_get_tuple(env, argv[0], &tpl_arity, &tpl) + || tpl_arity != 3 + || !enif_get_int(env, tpl[0], &itcs->visible.thr_nr) + || !enif_get_int(env, tpl[1], &free_megabyte)) { + enif_make_badarg(env); } - + itcs->visible.free_mem = (free_megabyte < max_megabyte ? + free_megabyte : max_megabyte) * (1024*1024); itcs->visible.testcase_name = testcase_name(); + itcs->visible.build_type = tpl[2]; itcs->visible.extra = NULL; - itcs->port = port; - itcs->port_id = driver_mk_port(port); itcs->result = TESTCASE_FAILED; itcs->comment = ""; - return (ErlDrvData) itcs; + ret = enif_make_resource(env, itcs); + enif_release_resource(itcs); + return ret; } -void -testcase_drv_stop(ErlDrvData drv_data) +ERL_NIF_TERM +testcase_nif_stop(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { - testcase_cleanup((TestCaseState_t *) drv_data); - driver_free((void *) drv_data); + InternalTestCaseState_t *itcs; + if (!enif_get_resource(env, argv[0], testcase_rt, (void**)&itcs)) + return enif_make_badarg(env); + testcase_cleanup(&itcs->visible); + return enif_make_atom(env,"ok"); } -void -testcase_drv_run(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) +ERL_NIF_TERM +testcase_nif_run(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { - InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) drv_data; - ErlDrvTermData result_atom; - ErlDrvTermData msg[12]; + InternalTestCaseState_t *itcs; + const char* result_atom; + jmp_buf the_jmp_buf; + + if (!enif_get_resource(env, argv[0], testcase_rt, (void**)&itcs)) + return enif_make_badarg(env); - itcs->visible.command = buf; - itcs->visible.command_len = len; + itcs->visible.curr_env = env; - if (setjmp(itcs->done_jmp_buf) == 0) { - testcase_run((TestCaseState_t *) itcs); + /* For some unknown reason, first call to setjmp crashes on win64 + * when jmp_buf is allocated as part of the resource. But it works when + * allocated on stack. It used to work when this was a driver. + */ + itcs->done_jmp_buf = &the_jmp_buf; + + if (setjmp(the_jmp_buf) == 0) { + testcase_run(&itcs->visible); itcs->result = TESTCASE_SUCCEEDED; } switch (itcs->result) { - case TESTCASE_SUCCEEDED: - result_atom = driver_mk_atom("succeeded"); - break; - case TESTCASE_SKIPPED: - result_atom = driver_mk_atom("skipped"); - break; - case TESTCASE_FAILED: + case TESTCASE_CONTINUE: + return enif_make_atom(env, "continue"); + + case TESTCASE_SUCCEEDED: result_atom = "succeeded"; break; + case TESTCASE_SKIPPED: result_atom = "skipped"; break; + case TESTCASE_FAILED: result_atom = "failed"; break; default: - result_atom = driver_mk_atom("failed"); - break; + result_atom = "failed"; + my_snprintf(itcs->comment_buf, sizeof(itcs->comment_buf), + "Unexpected test result code %d.", itcs->result); + itcs->comment = itcs->comment_buf; } - msg[0] = ERL_DRV_ATOM; - msg[1] = (ErlDrvTermData) result_atom; - - msg[2] = ERL_DRV_PORT; - msg[3] = itcs->port_id; - - msg[4] = ERL_DRV_ATOM; - msg[5] = driver_mk_atom(itcs->visible.testcase_name); - - msg[6] = ERL_DRV_STRING; - msg[7] = (ErlDrvTermData) itcs->comment; - msg[8] = (ErlDrvTermData) strlen(itcs->comment); - - msg[9] = ERL_DRV_TUPLE; - msg[10] = (ErlDrvTermData) 4; - - erl_drv_output_term(itcs->port_id, msg, 11); + return enif_make_tuple2(env, enif_make_atom(env, result_atom), + enif_make_string(env, itcs->comment, ERL_NIF_LATIN1)); } int @@ -172,34 +178,22 @@ testcase_assertion_failed(TestCaseState_t *tcs, void testcase_printf(TestCaseState_t *tcs, char *frmt, ...) { - InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) tcs; - ErlDrvTermData msg[12]; + InternalTestCaseState_t* itcs = (InternalTestCaseState_t*)tcs; + ErlNifPid pid; + ErlNifEnv* msg_env = enif_alloc_env(); + ERL_NIF_TERM msg; va_list va; va_start(va, frmt); -#if HAVE_VSNPRINTF - vsnprintf(itcs->comment_buf, COMMENT_BUF_SZ, frmt, va); -#else - vsprintf(itcs->comment_buf, frmt, va); -#endif + my_vsnprintf(itcs->comment_buf, COMMENT_BUF_SZ, frmt, va); va_end(va); - msg[0] = ERL_DRV_ATOM; - msg[1] = (ErlDrvTermData) driver_mk_atom("print"); + msg = enif_make_tuple2(msg_env, print_atom, + enif_make_string(msg_env, itcs->comment_buf, ERL_NIF_LATIN1)); - msg[2] = ERL_DRV_PORT; - msg[3] = itcs->port_id; + enif_send(itcs->visible.curr_env, enif_self(itcs->visible.curr_env, &pid), + msg_env, msg); - msg[4] = ERL_DRV_ATOM; - msg[5] = driver_mk_atom(itcs->visible.testcase_name); - - msg[6] = ERL_DRV_STRING; - msg[7] = (ErlDrvTermData) itcs->comment_buf; - msg[8] = (ErlDrvTermData) strlen(itcs->comment_buf); - - msg[9] = ERL_DRV_TUPLE; - msg[10] = (ErlDrvTermData) 4; - - erl_drv_output_term(itcs->port_id, msg, 11); + enif_free_env(msg_env); } @@ -208,17 +202,13 @@ void testcase_succeeded(TestCaseState_t *tcs, char *frmt, ...) InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) tcs; va_list va; va_start(va, frmt); -#if HAVE_VSNPRINTF - vsnprintf(itcs->comment_buf, COMMENT_BUF_SZ, frmt, va); -#else - vsprintf(itcs->comment_buf, frmt, va); -#endif + my_vsnprintf(itcs->comment_buf, COMMENT_BUF_SZ, frmt, va); va_end(va); itcs->result = TESTCASE_SUCCEEDED; itcs->comment = itcs->comment_buf; - longjmp(itcs->done_jmp_buf, 1); + longjmp(*itcs->done_jmp_buf, 1); } void testcase_skipped(TestCaseState_t *tcs, char *frmt, ...) @@ -226,17 +216,20 @@ void testcase_skipped(TestCaseState_t *tcs, char *frmt, ...) InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) tcs; va_list va; va_start(va, frmt); -#if HAVE_VSNPRINTF - vsnprintf(itcs->comment_buf, COMMENT_BUF_SZ, frmt, va); -#else - vsprintf(itcs->comment_buf, frmt, va); -#endif + my_vsnprintf(itcs->comment_buf, COMMENT_BUF_SZ, frmt, va); va_end(va); itcs->result = TESTCASE_SKIPPED; itcs->comment = itcs->comment_buf; - longjmp(itcs->done_jmp_buf, 1); + longjmp(*itcs->done_jmp_buf, 1); +} + +void testcase_continue(TestCaseState_t *tcs) +{ + InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) tcs; + itcs->result = TESTCASE_CONTINUE; + longjmp(*itcs->done_jmp_buf, 1); } void testcase_failed(TestCaseState_t *tcs, char *frmt, ...) @@ -246,37 +239,33 @@ void testcase_failed(TestCaseState_t *tcs, char *frmt, ...) size_t bufsz = sizeof(buf); va_list va; va_start(va, frmt); -#if HAVE_VSNPRINTF - vsnprintf(itcs->comment_buf, COMMENT_BUF_SZ, frmt, va); -#else - vsprintf(itcs->comment_buf, frmt, va); -#endif + my_vsnprintf(itcs->comment_buf, COMMENT_BUF_SZ, frmt, va); va_end(va); itcs->result = TESTCASE_FAILED; itcs->comment = itcs->comment_buf; - if (erl_drv_getenv("ERL_ABORT_ON_FAILURE", buf, &bufsz) == 0 + if (enif_getenv("ERL_ABORT_ON_FAILURE", buf, &bufsz) == 0 && strcmp("true", buf) == 0) { fprintf(stderr, "Testcase \"%s\" failed: %s\n", itcs->visible.testcase_name, itcs->comment); abort(); } - longjmp(itcs->done_jmp_buf, 1); + longjmp(*itcs->done_jmp_buf, 1); } void *testcase_alloc(size_t size) { - return driver_alloc(size); + return enif_alloc(size); } void *testcase_realloc(void *ptr, size_t size) { - return driver_realloc(ptr, size); + return enif_realloc(ptr, size); } void testcase_free(void *ptr) { - driver_free(ptr); + enif_free(ptr); } diff --git a/erts/emulator/test/alloc_SUITE_data/testcase_driver.h b/erts/emulator/test/alloc_SUITE_data/testcase_driver.h index 5d17eaec64..f0ca91bd06 100644 --- a/erts/emulator/test/alloc_SUITE_data/testcase_driver.h +++ b/erts/emulator/test/alloc_SUITE_data/testcase_driver.h @@ -20,13 +20,15 @@ #ifndef TESTCASE_DRIVER_H__ #define TESTCASE_DRIVER_H__ -#include "erl_driver.h" +#include "erl_nif.h" #include <stdlib.h> typedef struct { + ErlNifEnv* curr_env; char *testcase_name; - char *command; - int command_len; + int thr_nr; + int free_mem; /* in bytes */ + ERL_NIF_TERM build_type; /* opt, debug, valgrind, ... */ void *extra; } TestCaseState_t; @@ -34,9 +36,11 @@ typedef struct { ((void) ((B) ? 1 : testcase_assertion_failed((TCS), __FILE__, __LINE__, #B))) +int testcase_nif_init(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info); void testcase_printf(TestCaseState_t *tcs, char *frmt, ...); void testcase_succeeded(TestCaseState_t *tcs, char *frmt, ...); void testcase_skipped(TestCaseState_t *tcs, char *frmt, ...); +void testcase_continue(TestCaseState_t *tcs); void testcase_failed(TestCaseState_t *tcs, char *frmt, ...); int testcase_assertion_failed(TestCaseState_t *tcs, char *file, int line, char *assertion); @@ -45,8 +49,11 @@ void *testcase_realloc(void *ptr, size_t size); void testcase_free(void *ptr); +/* Implemented by testcase: */ char *testcase_name(void); void testcase_run(TestCaseState_t *tcs); void testcase_cleanup(TestCaseState_t *tcs); -#endif +extern ErlNifFunc testcase_nif_funcs[3]; + +#endif /* TESTCASE_DRIVER_H__ */ diff --git a/erts/emulator/test/alloc_SUITE_data/threads.c b/erts/emulator/test/alloc_SUITE_data/threads.c index edad24ee6b..2f5f841e3d 100644 --- a/erts/emulator/test/alloc_SUITE_data/threads.c +++ b/erts/emulator/test/alloc_SUITE_data/threads.c @@ -86,7 +86,7 @@ static void fail(int t_no, char *frmt, ...) tc_failed = 1; - if (erl_drv_getenv("ERL_ABORT_ON_FAILURE", buf, &bufsz) == 0 + if (enif_getenv("ERL_ABORT_ON_FAILURE", buf, &bufsz) == 0 && strcmp("true", buf) == 0) { fprintf(stderr, "Testcase \"%s\" failed: %s\n", testcase_name(), err_buf); @@ -187,7 +187,6 @@ testcase_run(TestCaseState_t *tcs) for(i = 1; i <= NO_OF_THREADS; i++) { char *alc; - int res; threads[i].arg.no_ops_per_bl = NO_OF_OPS_PER_BL; @@ -397,7 +396,7 @@ alloc_op(int t_no, Allctr_t *a, block *bp, int id, int clean_up) bp->p = (unsigned char *) ALLOC(a, bp->s); if(!bp->p) fail(t_no, "ALLOC(%lu) failed [id=%d])\n", bp->s, id); - memset((void *) bp->p, id, (size_t) bp->s); + memset((void *) bp->p, (unsigned char)id, (size_t) bp->s); } else { unsigned char *p = (unsigned char *) REALLOC(a, bp->p, bp->as[bp->i]); @@ -407,7 +406,7 @@ alloc_op(int t_no, Allctr_t *a, block *bp, int id, int clean_up) if(bp->s < bp->as[bp->i]) { CHECK_BLOCK_DATA(t_no, p, bp->s, id); - memset((void *) p, id, (size_t) bp->as[bp->i]); + memset((void *) p, (unsigned char)id, (size_t) bp->as[bp->i]); } else CHECK_BLOCK_DATA(t_no, p, bp->as[bp->i], id); @@ -446,3 +445,6 @@ thread_func(void *arg) exit_thread(td->t_no, 1); return NULL; } + +ERL_NIF_INIT(threads, testcase_nif_funcs, testcase_nif_init, + NULL, NULL, NULL); diff --git a/erts/emulator/test/alloc_SUITE_data/threads.erl b/erts/emulator/test/alloc_SUITE_data/threads.erl new file mode 100644 index 0000000000..a7b4965f5e --- /dev/null +++ b/erts/emulator/test/alloc_SUITE_data/threads.erl @@ -0,0 +1,10 @@ +-module(threads). + +-export([init/1, start/1, run/1, stop/1]). + +init(File) -> + ok = erlang:load_nif(File, 0). + +start(_) -> erlang:nif_error(not_loaded). +run(_) -> erlang:nif_error(not_loaded). +stop(_) -> erlang:nif_error(not_loaded). diff --git a/erts/emulator/test/bs_construct_SUITE.erl b/erts/emulator/test/bs_construct_SUITE.erl index cadb30e1a4..7ed99f5b4e 100644 --- a/erts/emulator/test/bs_construct_SUITE.erl +++ b/erts/emulator/test/bs_construct_SUITE.erl @@ -29,7 +29,7 @@ mem_leak/1, coerce_to_float/1, bjorn/1, huge_float_field/1, huge_binary/1, system_limit/1, badarg/1, copy_writable_binary/1, kostis/1, dynamic/1, bs_add/1, - otp_7422/1, zero_width/1, bad_append/1]). + otp_7422/1, zero_width/1, bad_append/1, bs_add_overflow/1]). -include_lib("test_server/include/test_server.hrl"). @@ -40,7 +40,7 @@ all() -> in_guard, mem_leak, coerce_to_float, bjorn, huge_float_field, huge_binary, system_limit, badarg, copy_writable_binary, kostis, dynamic, bs_add, otp_7422, zero_width, - bad_append]. + bad_append, bs_add_overflow]. groups() -> []. @@ -551,10 +551,24 @@ huge_binary(Config) when is_list(Config) -> ?line 16777216 = size(<<0:(id(1 bsl 26)),(-1):(id(1 bsl 26))>>), ?line garbage_collect(), {Shift,Return} = case free_mem() of - undefined -> {32,ok}; - Mb when Mb > 600 -> {32,ok}; - Mb when Mb > 300 -> {31,"Limit huge binaries to 256 Mb"}; - _ -> {30,"Limit huge binary to 128 Mb"} + undefined -> + %% This test has to be inlined inside the case to + %% use a literal Shift + ?line garbage_collect(), + ?line id(<<0:((1 bsl 32)-1)>>), + {32,ok}; + Mb when Mb > 600 -> + ?line garbage_collect(), + ?line id(<<0:((1 bsl 32)-1)>>), + {32,ok}; + Mb when Mb > 300 -> + ?line garbage_collect(), + ?line id(<<0:((1 bsl 31)-1)>>), + {31,"Limit huge binaries to 256 Mb"}; + _ -> + ?line garbage_collect(), + ?line id(<<0:((1 bsl 30)-1)>>), + {30,"Limit huge binary to 128 Mb"} end, ?line garbage_collect(), ?line id(<<0:((1 bsl Shift)-1)>>), @@ -911,5 +925,19 @@ append_unit_8(Bin) -> append_unit_16(Bin) -> <<Bin/binary-unit:16,0:1>>. +%% Produce a large result of bs_add that, if cast to signed int, would overflow +%% into a negative number that fits a smallnum. +bs_add_overflow(Config) -> + case erlang:system_info(wordsize) of + 8 -> + {skip, "64-bit architecture"}; + 4 -> + Large = <<0:((1 bsl 30)-1)>>, + {'EXIT',{system_limit,_}} = + (catch <<Large/bits, Large/bits, Large/bits, Large/bits, + Large/bits, Large/bits, Large/bits, Large/bits, + Large/bits>>), + ok + end. id(I) -> I. diff --git a/erts/emulator/test/distribution_SUITE.erl b/erts/emulator/test/distribution_SUITE.erl index d71cedbdc5..151fab0a0e 100644 --- a/erts/emulator/test/distribution_SUITE.erl +++ b/erts/emulator/test/distribution_SUITE.erl @@ -164,7 +164,7 @@ bulk_send(Terms, BinSize) -> ?line stop_node(Node), ?line test_server:timetrap_cancel(Dog), - {comment, integer_to_list(trunc(Size/1024/Elapsed+0.5)) ++ " K/s"}. + {comment, integer_to_list(trunc(Size/1024/max(1,Elapsed)+0.5)) ++ " K/s"}. bulk_sendsend(Terms, BinSize) -> {Rate1, MonitorCount1} = bulk_sendsend2(Terms, BinSize, 5), diff --git a/erts/emulator/test/distribution_SUITE_data/run.erl b/erts/emulator/test/distribution_SUITE_data/run.erl index f5169e160c..d5ed139369 100644 --- a/erts/emulator/test/distribution_SUITE_data/run.erl +++ b/erts/emulator/test/distribution_SUITE_data/run.erl @@ -30,16 +30,19 @@ from(H, [_ | T]) -> from(H, T); from(H, []) -> []. start() -> - net_kernel:start([fideridum,shortnames]), - {ok, Node} = slave:start(host(), heppel), - P = spawn(Node, a, b, []), - B1 = term_to_binary(P), - N1 = node(P), - ok = net_kernel:stop(), - N2 = node(P), - io:format("~w~n", [N1 == N2]), + Result = do_it(), + + %% Do GCs and node_and_dist_references + %% in an attempt to crash the VM (without OTP-13076 fix) + lists:foreach(fun(P) -> erlang:garbage_collect(P) end, + processes()), + erts_debug:set_internal_state(available_internal_state, true), + erts_debug:get_internal_state(node_and_dist_references), + + io:format("~w~n", [Result]), + if - N1 == N2 -> + Result -> init:stop(); true -> %% Make sure that the io:format/2 output is really written @@ -47,3 +50,29 @@ start() -> erlang:yield(), init:stop() end. + + +do_it() -> + {ok, _} = net_kernel:start([fideridum,shortnames]), + {ok, Node} = slave:start(host(), heppel), + P = spawn(Node, net_kernel, stop, []), + B1 = term_to_binary(P), + N1 = node(P), + ok = net_kernel:stop(), + N2 = node(P), + + %% OTP-13076 + %% Restart distribution with same node name as previous remote node + %% Repeat to wrap around creation + Result = lists:foldl(fun(_, Acc) -> + timer:sleep(2), % give net_kernel:stop() time to take effect :-( + {ok, _} = net_kernel:start([heppel,shortnames]), + N3 = node(P), + ok = net_kernel:stop(), + N4 = node(P), + Acc and (N3 =:= N1) and (N4 =:= N1) + end, + (N2 =:= N1), + lists:seq(1,3)), + + Result. diff --git a/erts/emulator/test/erts_debug_SUITE.erl b/erts/emulator/test/erts_debug_SUITE.erl index 3dd77eb920..35677f9953 100644 --- a/erts/emulator/test/erts_debug_SUITE.erl +++ b/erts/emulator/test/erts_debug_SUITE.erl @@ -139,23 +139,48 @@ flat_size_big_1(Term, Size0, Limit) when Size0 < Limit -> flat_size_big_1(_, _, _) -> ok. df(Config) when is_list(Config) -> - ?line P0 = pps(), - ?line PrivDir = ?config(priv_dir, Config), - ?line ok = file:set_cwd(PrivDir), - ?line erts_debug:df(?MODULE), - ?line Beam = filename:join(PrivDir, ?MODULE_STRING++".dis"), - ?line {ok,Bin} = file:read_file(Beam), - ?line ok = io:put_chars(binary_to_list(Bin)), - ?line ok = file:delete(Beam), - ?line true = (P0 == pps()), + P0 = pps(), + PrivDir = ?config(priv_dir, Config), + ok = file:set_cwd(PrivDir), + + AllLoaded = [M || {M,_} <- code:all_loaded()], + {Pid,Ref} = spawn_monitor(fun() -> df_smoke(AllLoaded) end), + receive + {'DOWN',Ref,process,Pid,Status} -> + normal = Status + after 20*1000 -> + %% Not finished (i.e. a slow computer). Stop now. + Pid ! stop, + receive + {'DOWN',Ref,process,Pid,Status} -> + normal = Status, + io:format("...") + end + end, + io:nl(), + _ = [_ = file:delete(atom_to_list(M) ++ ".dis") || + M <- AllLoaded], + + true = (P0 == pps()), ok. +df_smoke([M|Ms]) -> + io:format("~p", [M]), + erts_debug:df(M), + receive + stop -> + ok + after 0 -> + df_smoke(Ms) + end; +df_smoke([]) -> ok. + pps() -> {erlang:ports()}. instructions(Config) when is_list(Config) -> - ?line Is = erts_debug:instructions(), - ?line _ = [list_to_atom(I) || I <- Is], + Is = erts_debug:instructions(), + _ = [list_to_atom(I) || I <- Is], ok. id(I) -> diff --git a/erts/emulator/test/estone_SUITE.erl b/erts/emulator/test/estone_SUITE.erl index dc8f0aaee9..d49ab3de4d 100644 --- a/erts/emulator/test/estone_SUITE.erl +++ b/erts/emulator/test/estone_SUITE.erl @@ -382,11 +382,11 @@ apply_micro(M) -> {weight_percentage, M#micro.weight}, {loops, M#micro.loops}, {microsecs,MicroSecs}, - {estones, (M#micro.weight * M#micro.weight * ?STONEFACTOR) div MicroSecs}, + {estones, (M#micro.weight * M#micro.weight * ?STONEFACTOR) div max(1,MicroSecs)}, {gcs, GC1 - GC0}, {kilo_word_reclaimed, (Words1 - Words0) div 1000}, {kilo_reductions, Reds div 1000}, - {gc_intensity, gci(Elapsed, GC1 - GC0, Words1 - Words0)}]. + {gc_intensity, gci(max(1,Elapsed), GC1 - GC0, Words1 - Words0)}]. monotonic_time() -> try erlang:monotonic_time() catch error:undef -> erlang:now() end. diff --git a/erts/emulator/test/map_SUITE.erl b/erts/emulator/test/map_SUITE.erl index 1a89101916..a256cf4195 100644 --- a/erts/emulator/test/map_SUITE.erl +++ b/erts/emulator/test/map_SUITE.erl @@ -58,6 +58,7 @@ %% erlang t_erlang_hash/1, t_map_encode_decode/1, + t_gc_rare_map_overflow/1, %% non specific BIF related t_bif_build_and_check/1, @@ -121,6 +122,7 @@ all() -> [ %% erlang t_erlang_hash, t_map_encode_decode, + t_gc_rare_map_overflow, t_map_size, t_is_map, %% non specific BIF related @@ -2181,7 +2183,9 @@ t_map_encode_decode(Config) when is_list(Config) -> {<<>>, sc9}, {3.14158, sc10}, {[3.14158], sc11}, {more_atoms, sc12}, {{more_tuples}, sc13}, {self(), sc14}, - {{},{}},{[],[]} + {{},{}},{[],[]}, + {map_s, #{a=>a, 2=>b, 3=>c}}, + {map_l, maps:from_list([{I,I}||I <- lists:seq(1,74)])} ], ok = map_encode_decode_and_match(Pairs,[],#{}), @@ -2245,9 +2249,30 @@ t_map_encode_decode(Config) when is_list(Config) -> %% bad size (too small) .. should fail just truncate it .. weird. %% possibly change external format so truncated will be #{a:=1} - #{ a:=b } = - erlang:binary_to_term(<<131,116,0,0,0,1,100,0,1,97,100,0,1,98,97,1,97,1>>), - + #{ a:=b } = erlang:binary_to_term(<<131,116,0,0,0,1,100,0,1,97,100,0,1,98,97,1,97,1>>), + + %% specific fannerl (opensource app) binary_to_term error in 18.1 + + #{bias := {1,1,0}, + bit_fail := 0, + connections := #{{2,9} := _, + {8,14} := _, + {2,12} := _, + {5,7} := _, + {11,16} := _, + {11,15} := _}, + layers := {5,7,3}, + network_type := fann_nettype_layer, + num_input := 5, + num_layers := 3, + num_output := 3, + rprop_delta_max := _, + rprop_delta_min := _, + total_connections := 66, + total_neurons := 17, + train_error_function := fann_errorfunc_tanh, + train_stop_function := fann_stopfunc_mse, + training_algorithm := fann_train_rprop} = erlang:binary_to_term(fannerl()), ok. map_encode_decode_and_match([{K,V}|Pairs], EncodedPairs, M0) -> @@ -2391,6 +2416,9 @@ check_keys_exist([K|Ks],M) -> check_keys_exist(Ks,M). t_bif_merge_and_check(Config) when is_list(Config) -> + + io:format("rand:export_seed() -> ~p\n",[rand:export_seed()]), + %% simple disjunct ones %% make sure all keys are unique Kss = [[a,b,c,d], @@ -2438,8 +2466,49 @@ t_bif_merge_and_check(Config) when is_list(Config) -> M41 = maps:merge(M4,M1), ok = check_key_values(KVs1 ++ [{d,5}] ++ KVs, M41), + [begin Ma = random_map(SzA, a), + Mb = random_map(SzB, b), + ok = merge_maps(Ma, Mb) + end || SzA <- [3,10,20,100,200,1000], SzB <- [3,10,20,100,200,1000]], + + ok. + +% Generate random map with an average of Sz number of pairs: K -> {V,K} +random_map(Sz, V) -> + random_map_insert(#{}, 0, V, Sz*2). + +random_map_insert(M0, K0, _, Sz) when K0 > Sz -> + M0; +random_map_insert(M0, K0, V, Sz) -> + Key = K0 + rand:uniform(3), + random_map_insert(M0#{Key => {V,Key}}, Key, V, Sz). + + +merge_maps(A, B) -> + AB = maps:merge(A, B), + %%io:format("A=~p\nB=~p\n",[A,B]), + maps_foreach(fun(K,VB) -> VB = maps:get(K, AB) + end, B), + maps_foreach(fun(K,VA) -> + case {maps:get(K, AB),maps:find(K, B)} of + {VA, error} -> ok; + {VB, {ok, VB}} -> ok + end + end, A), + + maps_foreach(fun(K,V) -> + case {maps:find(K, A),maps:find(K, B)} of + {{ok, V}, error} -> ok; + {error, {ok, V}} -> ok; + {{ok,_}, {ok, V}} -> ok + end + end, AB), ok. +maps_foreach(Fun, Map) -> + maps:fold(fun(K,V,_) -> Fun(K,V) end, void, Map). + + check_key_values([],_) -> ok; check_key_values([{K,V}|KVs],M) -> V = maps:get(K,M), @@ -2922,3 +2991,189 @@ do_badmap_17(Config) -> %% Use this function to avoid compile-time evaluation of an expression. id(I) -> I. + + +%% OTP-13146 +%% Provoke major GC with a lot of "fat" maps on external format in msg queue +%% causing heap fragments to be allocated. +t_gc_rare_map_overflow(Config) -> + Pa = filename:dirname(code:which(?MODULE)), + {ok, Node} = test_server:start_node(gc_rare_map_overflow, slave, [{args, "-pa \""++Pa++"\""}]), + erts_debug:set_internal_state(available_internal_state, true), + try + Echo = spawn_link(Node, fun Loop() -> receive {From,Msg} -> From ! Msg + end, + Loop() + end), + FatMap = fatmap(34), + false = (flatmap =:= erts_internal:map_type(FatMap)), + + t_gc_rare_map_overflow_do(Echo, FatMap, fun() -> erlang:garbage_collect() end), + + %% Repeat test for minor gc: + t_gc_rare_map_overflow_do(Echo, FatMap, fun() -> minor_collect() end), + + unlink(Echo), + + %% Test fatmap in exit signal + Exiter = spawn_link(Node, fun Loop() -> receive {From,Msg} -> + "not_a_map" = Msg % badmatch! + end, + Loop() + end), + process_flag(trap_exit, true), + Exiter ! {self(), FatMap}, + {'EXIT', Exiter, {{badmatch,FatMap}, _}} = receive M -> M end, + ok + + after + process_flag(trap_exit, false), + erts_debug:set_internal_state(available_internal_state, false), + test_server:stop_node(Node) + end. + +t_gc_rare_map_overflow_do(Echo, FatMap, GcFun) -> + Master = self(), + true = receive M -> false after 0 -> true end, % assert empty msg queue + Echo ! {Master, token}, + repeat(1000, fun(_) -> Echo ! {Master, FatMap} end, void), + + timer:sleep(100), % Wait for maps to arrive in our msg queue + token = receive Tok -> Tok end, % and provoke move from outer to inner msg queue + + %% Do GC that will "overflow" and create heap frags due to all the fat maps + GcFun(), + + %% Now check that all maps in msg queueu are intact + %% Will crash emulator in OTP-18.1 + repeat(1000, fun(_) -> FatMap = receive FM -> FM end end, void), + ok. + +minor_collect() -> + Before = minor_gcs(), + erts_debug:set_internal_state(force_gc, self()), + erlang:yield(), + After = minor_gcs(), + io:format("minor_gcs: ~p -> ~p\n", [Before, After]). + +minor_gcs() -> + {garbage_collection, Info} = process_info(self(), garbage_collection), + {minor_gcs, GCS} = lists:keyfind(minor_gcs, 1, Info), + GCS. + +%% Generate a map with N (or N+1) keys that has an abnormal heap demand. +%% Done by finding keys that collide in the first 32-bit hash. +fatmap(N) -> + %%erts_debug:set_internal_state(available_internal_state, true), + Table = ets:new(void, [bag, private]), + + Seed0 = rand:seed_s(exsplus, {4711, 3141592, 2718281}), + Seed1 = fatmap_populate(Table, Seed0, (1 bsl 16)), + Keys = fatmap_generate(Table, Seed1, N, []), + ets:delete(Table), + maps:from_list([{K,K} || K <- Keys]). + +fatmap_populate(_, Seed, 0) -> Seed; +fatmap_populate(Table, Seed, N) -> + {I, NextSeed} = rand:uniform_s(1 bsl 48, Seed), + Hash = internal_hash(I), + ets:insert(Table, [{Hash, I}]), + fatmap_populate(Table, NextSeed, N-1). + + +fatmap_generate(_, _, N, Acc) when N =< 0 -> + Acc; +fatmap_generate(Table, Seed, N0, Acc0) -> + {I, NextSeed} = rand:uniform_s(1 bsl 48, Seed), + Hash = internal_hash(I), + case ets:member(Table, Hash) of + true -> + NewKeys = [I | ets:lookup_element(Table, Hash, 2)], + Acc1 = lists:usort(Acc0 ++ NewKeys), + N1 = N0 - (length(Acc1) - length(Acc0)), + fatmap_generate(Table, NextSeed, N1, Acc1); + false -> + fatmap_generate(Table, NextSeed, N0, Acc0) + end. + +internal_hash(Term) -> + erts_debug:get_internal_state({internal_hash, Term}). + + +%% map external_format (fannerl). +fannerl() -> + <<131,116,0,0,0,28,100,0,13,108,101,97,114,110,105,110,103,95,114, + 97,116,101,70,63,230,102,102,96,0,0,0,100,0,17,108,101,97,114,110,105,110, + 103,95,109,111,109,101,110,116,117,109,70,0,0,0,0,0,0,0,0,100,0, + 18,116,114,97,105,110,105,110,103,95,97,108,103,111,114,105,116,104,109,100,0, + 16,102,97,110,110,95,116,114,97,105,110,95,114,112,114,111,112, + 100,0,17,109,101,97,110,95,115,113,117,97,114,101,95,101,114,114,111,114,70, + 0,0,0,0,0,0,0,0,100,0,8,98,105,116,95,102,97,105,108,97,0,100,0,20, + 116,114,97,105,110,95,101,114,114,111,114,95,102,117,110,99,116,105,111, + 110,100,0,19,102,97,110,110,95,101,114,114,111,114,102,117,110,99, + 95,116,97,110,104,100,0,9,110,117,109,95,105,110,112,117,116,97,5,100,0,10,110, + 117,109,95,111,117,116,112,117,116,97,3,100,0,13,116,111,116,97,108, + 95,110,101,117,114,111,110,115,97,17,100,0,17,116,111,116,97,108,95,99,111,110, + 110,101,99,116,105,111,110,115,97,66,100,0,12,110,101,116,119,111,114,107, + 95,116,121,112,101,100,0,18,102,97,110,110,95,110,101,116,116,121,112,101, + 95,108,97,121,101,114,100,0,15,99,111,110,110,101,99,116,105,111,110,95, + 114,97,116,101,70,63,240,0,0,0,0,0,0,100,0,10,110,117,109,95,108,97,121,101, + 114,115,97,3,100,0,19,116,114,97,105,110,95,115,116,111,112,95,102,117,110, + 99,116,105,111,110,100,0,17,102,97,110,110,95,115,116,111,112,102,117,110, + 99,95,109,115,101,100,0,15,113,117,105,99,107,112,114,111,112,95,100,101,99, + 97,121,70,191,26,54,226,224,0,0,0,100,0,12,113,117,105,99,107,112,114, + 111,112,95,109,117,70,63,252,0,0,0,0,0,0,100,0,21,114,112,114,111,112,95,105, + 110,99,114,101,97,115,101,95,102,97,99,116,111,114,70,63,243,51,51, + 64,0,0,0,100,0,21,114,112,114,111,112,95,100,101,99,114,101,97,115,101, + 95,102,97,99,116,111,114,70,63,224,0,0,0,0,0,0,100,0,15,114,112,114,111,112, + 95,100,101,108,116,97,95,109,105,110,70,0,0,0,0,0,0,0,0,100,0,15,114,112,114, + 111,112,95,100,101,108,116,97,95,109,97,120,70,64,73,0,0,0,0,0,0,100,0, + 16,114,112,114,111,112,95,100,101,108,116,97,95,122,101,114,111,70,63,185,153, + 153,160,0,0,0,100,0,26,115,97,114,112,114,111,112,95,119,101,105,103, + 104,116,95,100,101,99,97,121,95,115,104,105,102,116,70,192,26,147,116,192,0,0,0, + 100,0,35,115,97,114,112,114,111,112,95,115,116,101,112,95,101,114, + 114,111,114,95,116,104,114,101,115,104,111,108,100,95,102,97,99,116,111,114,70, + 63,185,153,153,160,0,0,0,100,0,24,115,97,114,112,114,111,112,95,115, + 116,101,112,95,101,114,114,111,114,95,115,104,105,102,116,70,63,246,40,245, + 192,0,0,0,100,0,19,115,97,114,112,114,111,112,95,116,101,109,112,101,114, + 97,116,117,114,101,70,63,142,184,81,224,0,0,0,100,0,6,108,97,121,101,114,115, + 104,3,97,5,97,7,97,3,100,0,4,98,105,97,115,104,3,97,1,97,1,97,0,100,0,11, + 99,111,110,110,101,99,116,105,111,110,115,116,0,0,0,66,104,2,97,0,97,6,70, + 191,179,51,44,64,0,0,0,104,2,97,1,97,6,70,63,178,130,90,32,0,0,0,104,2,97,2, + 97,6,70,63,82,90,88,0,0,0,0,104,2,97,3,97,6,70,63,162,91,63,192,0,0,0,104,2, + 97,4,97,6,70,191,151,70,169,0,0,0,0,104,2,97,5,97,6,70,191,117,52,222,0,0,0, + 0,104,2,97,0,97,7,70,63,152,240,139,0,0,0,0,104,2,97,1,97,7,70,191,166,31, + 187,160,0,0,0,104,2,97,2,97,7,70,191,150,70,63,0,0,0,0,104,2,97,3,97,7,70, + 63,152,181,126,128,0,0,0,104,2,97,4,97,7,70,63,151,187,162,128,0,0,0,104,2, + 97,5,97,7,70,191,143,161,101,0,0,0,0,104,2,97,0,97,8,70,191,153,102,36,128,0, + 0,0,104,2,97,1,97,8,70,63,160,139,250,64,0,0,0,104,2,97,2,97,8,70,63,164,62, + 196,64,0,0,0,104,2,97,3,97,8,70,191,178,78,209,192,0,0,0,104,2,97,4,97,8,70, + 191,185,19,76,224,0,0,0,104,2,97,5,97,8,70,63,183,142,196,96,0,0,0,104,2,97,0, + 97,9,70,63,150,104,248,0,0,0,0,104,2,97,1,97,9,70,191,164,4,100,224,0,0,0, + 104,2,97,2,97,9,70,191,169,42,42,224,0,0,0,104,2,97,3,97,9,70,63,145,54,78,128,0, + 0,0,104,2,97,4,97,9,70,63,126,243,134,0,0,0,0,104,2,97,5,97,9,70,63,177, + 203,25,96,0,0,0,104,2,97,0,97,10,70,63,172,104,47,64,0,0,0,104,2,97,1,97,10, + 70,63,161,242,193,64,0,0,0,104,2,97,2,97,10,70,63,175,208,241,192,0,0,0,104,2, + 97,3,97,10,70,191,129,202,161,0,0,0,0,104,2,97,4,97,10,70,63,178,151,55,32,0,0,0, + 104,2,97,5,97,10,70,63,137,155,94,0,0,0,0,104,2,97,0,97,11,70,191,179, + 106,160,0,0,0,0,104,2,97,1,97,11,70,63,184,253,164,96,0,0,0,104,2,97,2,97,11, + 70,191,143,30,157,0,0,0,0,104,2,97,3,97,11,70,63,153,225,140,128,0,0,0,104, + 2,97,4,97,11,70,63,161,35,85,192,0,0,0,104,2,97,5,97,11,70,63,175,200,55,192, + 0,0,0,104,2,97,0,97,12,70,191,180,116,132,96,0,0,0,104,2,97,1,97,12,70,191, + 165,151,152,0,0,0,0,104,2,97,2,97,12,70,191,180,197,91,160,0,0,0,104,2,97,3,97,12, + 70,191,91,30,160,0,0,0,0,104,2,97,4,97,12,70,63,180,251,45,32,0,0,0, + 104,2,97,5,97,12,70,63,165,134,77,64,0,0,0,104,2,97,6,97,14,70,63,181,56,242,96, + 0,0,0,104,2,97,7,97,14,70,191,165,239,234,224,0,0,0,104,2,97,8,97,14, + 70,191,154,65,216,128,0,0,0,104,2,97,9,97,14,70,63,150,250,236,0,0,0,0,104,2,97, + 10,97,14,70,191,141,105,108,0,0,0,0,104,2,97,11,97,14,70,191,152,40, + 165,0,0,0,0,104,2,97,12,97,14,70,63,141,159,46,0,0,0,0,104,2,97,13,97,14,70, + 191,183,172,137,32,0,0,0,104,2,97,6,97,15,70,63,163,26,123,192,0,0,0,104, + 2,97,7,97,15,70,63,176,184,106,32,0,0,0,104,2,97,8,97,15,70,63,152,234,144, + 0,0,0,0,104,2,97,9,97,15,70,191,172,58,70,160,0,0,0,104,2,97,10,97,15,70, + 63,161,211,211,192,0,0,0,104,2,97,11,97,15,70,191,148,171,120,128,0,0,0,104, + 2,97,12,97,15,70,63,180,117,214,224,0,0,0,104,2,97,13,97,15,70,191,104, + 230,216,0,0,0,0,104,2,97,6,97,16,70,63,178,53,103,96,0,0,0,104,2,97,7,97,16, + 70,63,170,230,232,64,0,0,0,104,2,97,8,97,16,70,191,183,45,100,192,0,0,0, + 104,2,97,9,97,16,70,63,184,100,97,32,0,0,0,104,2,97,10,97,16,70,63,169,174, + 254,64,0,0,0,104,2,97,11,97,16,70,191,119,121,234,0,0,0,0,104,2,97,12,97, + 16,70,63,149,12,170,128,0,0,0,104,2,97,13,97,16,70,191,144,193,191,0,0,0,0>>. diff --git a/erts/emulator/test/match_spec_SUITE.erl b/erts/emulator/test/match_spec_SUITE.erl index c6cc414bba..3f986ca2ed 100644 --- a/erts/emulator/test/match_spec_SUITE.erl +++ b/erts/emulator/test/match_spec_SUITE.erl @@ -170,12 +170,11 @@ test_1(Config) when is_list(Config) -> [{['$1','$1'],[{is_atom, '$1'}],[kakalorum]}], [{call, {?MODULE, f2, [a, a]}}]), -% case tr0(fun() -> ?MODULE:f2(a, a) end, -% {?MODULE, f2, 2}, -% [{['$1','$1'],[{is_atom, '$1'}],[{message, {process_dump}}]}]) of -% [{trace, _, call, {?MODULE, f2, [a, a]}, Bin}] -> -% erlang:display(binary_to_list(Bin)) -% end, + %% Verify that 'process_dump' can handle a matchstate on the stack. + tr(fun() -> fbinmatch(<<0>>, 0) end, + {?MODULE, f1, 1}, + [{['_'],[],[{message, {process_dump}}]}], + [fun({trace, _, call, {?MODULE, f1, [0]}, _Bin}) -> true end]), % Error cases ?line errchk([{['$1','$1'],[{is_atom, '$1'}],[{banka, kanin}]}]), @@ -999,14 +998,14 @@ tr(Fun, MFA, TraceFlags, Pat, PatFlags, Expected0) -> erlang:trace(P, true, TraceFlags), erlang:trace_pattern(MFA, Pat, PatFlags), lists:map( - fun(X) -> - list_to_tuple([trace, P | tuple_to_list(X)]) + fun(X) when is_function(X,1) -> X; + (X) -> list_to_tuple([trace, P | tuple_to_list(X)]) end, Expected0) end). tr(RunFun, ControlFun) -> - P = spawn(?MODULE, runner, [self(), RunFun]), + P = spawn_link(?MODULE, runner, [self(), RunFun]), collect(P, ControlFun(P)). collect(P, TMs) -> @@ -1025,18 +1024,33 @@ collect([]) -> collect([TM | TMs]) -> ?t:format( "Expecting: ~p~n", [TM]), receive - M -> - case if element(1, M) == trace_ts -> - list_to_tuple(lists:reverse( - tl(lists:reverse(tuple_to_list(M))))); - true -> M - end of - TM -> - ?t:format("Got: ~p~n", [M]), - collect(TMs); - _ -> - ?t:format("Got unexpected: ~p~n", [M]), - flush({got_unexpected,M}) + M0 -> + M = case element(1, M0) of + trace_ts -> + list_to_tuple(lists:reverse( + tl(lists:reverse(tuple_to_list(M0))))); + _ -> M0 + end, + case is_function(TM,1) of + true -> + case (catch TM(M)) of + true -> + ?t:format("Got: ~p~n", [M]), + collect(TMs); + _ -> + ?t:format("Got unexpected: ~p~n", [M]), + flush({got_unexpected,M}) + end; + + false -> + case M of + TM -> + ?t:format("Got: ~p~n", [M]), + collect(TMs); + _ -> + ?t:format("Got unexpected: ~p~n", [M]), + flush({got_unexpected,M}) + end end end. @@ -1116,6 +1130,10 @@ fn(X, Y) -> fn(X, Y, Z) -> [X, Y, Z]. +fbinmatch(<<Int, Rest/binary>>, Acc) -> + fbinmatch(Rest, [?MODULE:f1(Int) | Acc]); +fbinmatch(<<>>, Acc) -> Acc. + id(X) -> X. diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl index af2b955184..2400505159 100644 --- a/erts/emulator/test/nif_SUITE.erl +++ b/erts/emulator/test/nif_SUITE.erl @@ -42,7 +42,8 @@ otp_9668/1, consume_timeslice/1, dirty_nif/1, dirty_nif_send/1, dirty_nif_exception/1, call_dirty_nif_exception/1, nif_schedule/1, nif_exception/1, call_nif_exception/1, - nif_nan_and_inf/1, nif_atom_too_long/1 + nif_nan_and_inf/1, nif_atom_too_long/1, + nif_monotonic_time/1, nif_time_offset/1, nif_convert_time_unit/1 ]). -export([many_args_100/100]). @@ -72,7 +73,8 @@ all() -> otp_9828, otp_9668, consume_timeslice, nif_schedule, dirty_nif, dirty_nif_send, dirty_nif_exception, - nif_exception, nif_nan_and_inf, nif_atom_too_long + nif_exception, nif_nan_and_inf, nif_atom_too_long, + nif_monotonic_time, nif_time_offset, nif_convert_time_unit ]. groups() -> @@ -615,7 +617,6 @@ resource_new_do2(Type) -> ?line {PtrA,BinA} = get_resource(Type, ResA), ?line {PtrB,BinB} = get_resource(Type, ResB), ?line true = (PtrA =/= PtrB), - ?line [] = last_resource_dtor_call(), %% forget ResA and make it garbage {{PtrA,BinA}, {ResB,PtrB,BinB}}. @@ -1713,7 +1714,9 @@ tmpmem() -> false -> undefined; MemInfo -> MSBCS = lists:foldl( - fun ({instance, _, L}, Acc) -> + fun ({instance, 0, _}, Acc) -> + Acc; % Ignore instance 0 + ({instance, _, L}, Acc) -> {value,{_,MBCS}} = lists:keysearch(mbcs, 1, L), {value,{_,SBCS}} = lists:keysearch(sbcs, 1, L), [MBCS,SBCS | Acc] @@ -1783,6 +1786,148 @@ nif_raise_exceptions(NifFunc) -> end end, ok, ExcTerms). +-define(ERL_NIF_TIME_ERROR, -9223372036854775808). +-define(TIME_UNITS, [seconds, milli_seconds, micro_seconds, nano_seconds]). + +nif_monotonic_time(Config) -> + ?ERL_NIF_TIME_ERROR = monotonic_time(invalid_time_unit), + mtime_loop(1000000). + +mtime_loop(0) -> + ok; +mtime_loop(N) -> + chk_mtime(?TIME_UNITS), + mtime_loop(N-1). + +chk_mtime([]) -> + ok; +chk_mtime([TU|TUs]) -> + A = erlang:monotonic_time(TU), + B = monotonic_time(TU), + C = erlang:monotonic_time(TU), + try + true = A =< B, + true = B =< C + catch + _ : _ -> + ?t:fail({monotonic_time_missmatch, TU, A, B, C}) + end, + chk_mtime(TUs). + +nif_time_offset(Config) -> + ?ERL_NIF_TIME_ERROR = time_offset(invalid_time_unit), + toffs_loop(1000000). + +toffs_loop(0) -> + ok; +toffs_loop(N) -> + chk_toffs(?TIME_UNITS), + toffs_loop(N-1). + +chk_toffs([]) -> + ok; +chk_toffs([TU|TUs]) -> + TO = erlang:time_offset(TU), + NifTO = time_offset(TU), + case TO =:= NifTO of + true -> + ok; + false -> + case erlang:system_info(time_warp_mode) of + no_time_warp -> + ?t:fail({time_offset_mismatch, TU, TO, NifTO}); + _ -> + %% Most frequent time offset change + %% is currently only every 15:th + %% second so this should currently + %% work... + NTO = erlang:time_offset(TU), + case NifTO =:= NTO of + true -> + ok; + false -> + ?t:fail({time_offset_mismatch, TU, TO, NifTO, NTO}) + end + end + end, + chk_toffs(TUs). + +nif_convert_time_unit(Config) -> + ?ERL_NIF_TIME_ERROR = convert_time_unit(0, seconds, invalid_time_unit), + ?ERL_NIF_TIME_ERROR = convert_time_unit(0, invalid_time_unit, seconds), + ?ERL_NIF_TIME_ERROR = convert_time_unit(0, invalid_time_unit, invalid_time_unit), + lists:foreach(fun (Offset) -> + lists:foreach(fun (Diff) -> + chk_ctu(Diff+(Offset*1000*1000*1000)) + end, + [999999999999, + 99999999999, + 9999999999, + 999999999, + 99999999, + 9999999, + 999999, + 99999, + 999, + 99, + 9, + 1, + 11, + 101, + 1001, + 10001, + 100001, + 1000001, + 10000001, + 100000001, + 1000000001, + 100000000001, + 1000000000001, + 5, + 50, + 500, + 5000, + 50000, + 500000, + 5000000, + 50000000, + 500000000, + 5000000000, + 50000000000, + 500000000000]) + end, + [-4711, -1000, -475, -5, -4, -3, -2, -1, 0, + 1, 2, 3, 4, 5, 475, 1000, 4711]), + ctu_loop(1000000). + +ctu_loop(0) -> + ok; +ctu_loop(N) -> + chk_ctu(erlang:monotonic_time(nano_seconds)), + ctu_loop(N-1). + +chk_ctu(Time) -> + chk_ctu(Time, ?TIME_UNITS). + +chk_ctu(_Time, []) -> + ok; +chk_ctu(Time, [FromTU|FromTUs]) -> + chk_ctu(Time, FromTU, ?TIME_UNITS), + chk_ctu(Time, FromTUs). + +chk_ctu(_Time, _FromTU, []) -> + ok; +chk_ctu(Time, FromTU, [ToTU|ToTUs]) -> + T = erlang:convert_time_unit(Time, nano_seconds, FromTU), + TE = erlang:convert_time_unit(T, FromTU, ToTU), + TN = convert_time_unit(T, FromTU, ToTU), + case TE =:= TN of + false -> + ?t:fail({conversion_mismatch, FromTU, T, ToTU, TE, TN}); + true -> + chk_ctu(Time, FromTU, ToTUs) + end. + %% The NIFs: lib_version() -> undefined. call_history() -> ?nif_stub. @@ -1852,6 +1997,11 @@ make_map_remove_nif(_,_) -> ?nif_stub. maps_from_list_nif(_) -> ?nif_stub. sorted_list_from_maps_nif(_) -> ?nif_stub. +%% Time +monotonic_time(_) -> ?nif_stub. +time_offset(_) -> ?nif_stub. +convert_time_unit(_,_,_) -> ?nif_stub. + nif_stub_error(Line) -> exit({nif_not_loaded,module,?MODULE,line,Line}). diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c index 98e1efe18f..8ebce4fef4 100644 --- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c +++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c @@ -34,6 +34,10 @@ static ERL_NIF_TERM atom_self; static ERL_NIF_TERM atom_ok; static ERL_NIF_TERM atom_join; static ERL_NIF_TERM atom_binary_resource_type; +static ERL_NIF_TERM atom_seconds; +static ERL_NIF_TERM atom_milli_seconds; +static ERL_NIF_TERM atom_micro_seconds; +static ERL_NIF_TERM atom_nano_seconds; typedef struct @@ -138,6 +142,10 @@ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) atom_ok = enif_make_atom(env,"ok"); atom_join = enif_make_atom(env,"join"); atom_binary_resource_type = enif_make_atom(env,"binary_resource_type"); + atom_seconds = enif_make_atom(env,"seconds"); + atom_milli_seconds = enif_make_atom(env,"milli_seconds"); + atom_micro_seconds = enif_make_atom(env,"micro_seconds"); + atom_nano_seconds = enif_make_atom(env,"nano_seconds"); *priv_data = data; return 0; @@ -1885,6 +1893,87 @@ static ERL_NIF_TERM sorted_list_from_maps_nif(ErlNifEnv* env, int argc, const ER return enif_make_tuple2(env, list_f, list_b); } + +static ERL_NIF_TERM monotonic_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ErlNifTimeUnit time_unit; + + if (argc != 1) + return atom_false; + + if (enif_compare(argv[0], atom_seconds) == 0) + time_unit = ERL_NIF_SEC; + else if (enif_compare(argv[0], atom_milli_seconds) == 0) + time_unit = ERL_NIF_MSEC; + else if (enif_compare(argv[0], atom_micro_seconds) == 0) + time_unit = ERL_NIF_USEC; + else if (enif_compare(argv[0], atom_nano_seconds) == 0) + time_unit = ERL_NIF_NSEC; + else + time_unit = 4711; /* invalid time unit */ + + return enif_make_int64(env, enif_monotonic_time(time_unit)); +} + +static ERL_NIF_TERM time_offset(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ErlNifTimeUnit time_unit; + + if (argc != 1) + return atom_false; + + if (enif_compare(argv[0], atom_seconds) == 0) + time_unit = ERL_NIF_SEC; + else if (enif_compare(argv[0], atom_milli_seconds) == 0) + time_unit = ERL_NIF_MSEC; + else if (enif_compare(argv[0], atom_micro_seconds) == 0) + time_unit = ERL_NIF_USEC; + else if (enif_compare(argv[0], atom_nano_seconds) == 0) + time_unit = ERL_NIF_NSEC; + else + time_unit = 4711; /* invalid time unit */ + return enif_make_int64(env, enif_time_offset(time_unit)); +} + +static ERL_NIF_TERM convert_time_unit(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ErlNifSInt64 i64; + ErlNifTime val; + ErlNifTimeUnit from, to; + + if (argc != 3) + return atom_false; + + if (!enif_get_int64(env, argv[0], &i64)) + return enif_make_badarg(env); + + val = (ErlNifTime) i64; + + if (enif_compare(argv[1], atom_seconds) == 0) + from = ERL_NIF_SEC; + else if (enif_compare(argv[1], atom_milli_seconds) == 0) + from = ERL_NIF_MSEC; + else if (enif_compare(argv[1], atom_micro_seconds) == 0) + from = ERL_NIF_USEC; + else if (enif_compare(argv[1], atom_nano_seconds) == 0) + from = ERL_NIF_NSEC; + else + from = 4711; /* invalid time unit */ + + if (enif_compare(argv[2], atom_seconds) == 0) + to = ERL_NIF_SEC; + else if (enif_compare(argv[2], atom_milli_seconds) == 0) + to = ERL_NIF_MSEC; + else if (enif_compare(argv[2], atom_micro_seconds) == 0) + to = ERL_NIF_USEC; + else if (enif_compare(argv[2], atom_nano_seconds) == 0) + to = ERL_NIF_NSEC; + else + to = 4711; /* invalid time unit */ + + return enif_make_int64(env, enif_convert_time_unit(val, from, to)); +} + static ErlNifFunc nif_funcs[] = { {"lib_version", 0, lib_version}, @@ -1954,7 +2043,10 @@ static ErlNifFunc nif_funcs[] = {"make_map_update_nif", 3, make_map_update_nif}, {"make_map_remove_nif", 2, make_map_remove_nif}, {"maps_from_list_nif", 1, maps_from_list_nif}, - {"sorted_list_from_maps_nif", 1, sorted_list_from_maps_nif} + {"sorted_list_from_maps_nif", 1, sorted_list_from_maps_nif}, + {"monotonic_time", 1, monotonic_time}, + {"time_offset", 1, time_offset}, + {"convert_time_unit", 3, convert_time_unit} }; ERL_NIF_INIT(nif_SUITE,nif_funcs,load,reload,upgrade,unload) diff --git a/erts/emulator/test/nif_SUITE_data/nif_mod.c b/erts/emulator/test/nif_SUITE_data/nif_mod.c index 9c78c0e04d..f7e729e2b6 100644 --- a/erts/emulator/test/nif_SUITE_data/nif_mod.c +++ b/erts/emulator/test/nif_SUITE_data/nif_mod.c @@ -240,7 +240,7 @@ static ERL_NIF_TERM lib_version(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg static ERL_NIF_TERM get_priv_data_ptr(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { ADD_CALL("get_priv_data_ptr"); - return enif_make_ulong(env, (unsigned long)priv_data(env)); + return enif_make_uint64(env, (ErlNifUInt64)priv_data(env)); } static ERL_NIF_TERM make_new_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) diff --git a/erts/emulator/test/num_bif_SUITE.erl b/erts/emulator/test/num_bif_SUITE.erl index f07f79b83d..90b6a36262 100644 --- a/erts/emulator/test/num_bif_SUITE.erl +++ b/erts/emulator/test/num_bif_SUITE.erl @@ -429,7 +429,7 @@ t_string_to_integer(Config) when is_list(Config) -> list_to_binary(Value))), {'EXIT', {badarg, _}} = (catch erlang:list_to_integer(Value)) - end,["1.0"," 1"," -1",""]), + end,["1.0"," 1"," -1","","+"]), % Custom base error cases lists:foreach(fun({Value,Base}) -> diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl index 4c311e1f06..97aa5e573e 100644 --- a/erts/emulator/test/process_SUITE.erl +++ b/erts/emulator/test/process_SUITE.erl @@ -1478,7 +1478,15 @@ processes_this_tab(doc) -> processes_this_tab(suite) -> []; processes_this_tab(Config) when is_list(Config) -> - sys_mem_cond_run(1024, fun () -> chk_processes_bif_test_res(processes_bif_test()) end). + Mem = case {erlang:system_info(build_type), + erlang:system_info(allocator)} of + {lcnt, {_, _Vsn, [sys_alloc], _Opts}} -> + %% When running +Mea min + lcnt we may need more memory + 1024 * 4; + _ -> + 1024 + end, + sys_mem_cond_run(Mem, fun () -> chk_processes_bif_test_res(processes_bif_test()) end). chk_processes_bif_test_res(ok) -> ok; chk_processes_bif_test_res({comment, _} = Comment) -> Comment; diff --git a/erts/emulator/test/save_calls_SUITE.erl b/erts/emulator/test/save_calls_SUITE.erl index 544d841f16..4e50fdc898 100644 --- a/erts/emulator/test/save_calls_SUITE.erl +++ b/erts/emulator/test/save_calls_SUITE.erl @@ -156,8 +156,19 @@ save_calls_1() -> ?line erlang:process_flag(self(), save_calls, 10), ?line {last_calls, L3} = process_info(self(), last_calls), + true = (L3 /= false), ?line L31 = lists:filter(fun is_local_function/1, L3), ?line [] = L31, + erlang:process_flag(self(), save_calls, 0), + + %% Also check that it works on another process ... + Pid = spawn(fun () -> receive after infinity -> ok end end), + erlang:process_flag(Pid, save_calls, 10), + {last_calls, L4} = process_info(Pid, last_calls), + true = (L4 /= false), + L41 = lists:filter(fun is_local_function/1, L4), + [] = L41, + exit(Pid,kill), ok. do_bipp() -> diff --git a/erts/emulator/test/statistics_SUITE.erl b/erts/emulator/test/statistics_SUITE.erl index 56ecf4195a..a6305d453c 100644 --- a/erts/emulator/test/statistics_SUITE.erl +++ b/erts/emulator/test/statistics_SUITE.erl @@ -32,7 +32,7 @@ run_queue_one/1, scheduler_wall_time/1, reductions/1, reductions_big/1, garbage_collection/1, io/1, - badarg/1]). + badarg/1, run_queues_lengths_active_tasks/1]). %% Internal exports. @@ -54,7 +54,8 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [{group, wall_clock}, {group, runtime}, reductions, reductions_big, {group, run_queue}, scheduler_wall_time, - garbage_collection, io, badarg]. + garbage_collection, io, badarg, + run_queues_lengths_active_tasks]. groups() -> [{wall_clock, [], @@ -409,3 +410,63 @@ badarg(Config) when is_list(Config) -> ?line case catch statistics(bad_atom) of {'EXIT', {badarg, _}} -> ok end. + +tok_loop() -> + tok_loop(). + +run_queues_lengths_active_tasks(Config) -> + TokLoops = lists:map(fun (_) -> + spawn_opt(fun () -> + tok_loop() + end, + [link, {priority, low}]) + end, + lists:seq(1,10)), + + TRQLs0 = statistics(total_run_queue_lengths), + TATs0 = statistics(total_active_tasks), + true = is_integer(TRQLs0), + true = is_integer(TATs0), + true = TRQLs0 >= 0, + true = TATs0 >= 11, + + NoScheds = erlang:system_info(schedulers), + RQLs0 = statistics(run_queue_lengths), + ATs0 = statistics(active_tasks), + NoScheds = length(RQLs0), + NoScheds = length(ATs0), + true = lists:sum(RQLs0) >= 0, + true = lists:sum(ATs0) >= 11, + + SO = erlang:system_flag(schedulers_online, 1), + + %% Give newly suspended schedulers some time to + %% migrate away work from their run queues... + receive after 1000 -> ok end, + + TRQLs1 = statistics(total_run_queue_lengths), + TATs1 = statistics(total_active_tasks), + true = TRQLs1 >= 10, + true = TATs1 >= 11, + NoScheds = erlang:system_info(schedulers), + + RQLs1 = statistics(run_queue_lengths), + ATs1 = statistics(active_tasks), + NoScheds = length(RQLs1), + NoScheds = length(ATs1), + TRQLs2 = lists:sum(RQLs1), + TATs2 = lists:sum(ATs1), + true = TRQLs2 >= 10, + true = TATs2 >= 11, + [TRQLs2|_] = RQLs1, + [TATs2|_] = ATs1, + + erlang:system_flag(schedulers_online, SO), + + lists:foreach(fun (P) -> + unlink(P), + exit(P, bang) + end, + TokLoops), + + ok. diff --git a/erts/emulator/test/system_profile_SUITE.erl b/erts/emulator/test/system_profile_SUITE.erl index e4b6511d1f..2ecb4a28a7 100644 --- a/erts/emulator/test/system_profile_SUITE.erl +++ b/erts/emulator/test/system_profile_SUITE.erl @@ -113,13 +113,27 @@ runnable_procs(suite) -> runnable_procs(doc) -> ["Tests system_profiling with runnable_procs."]; runnable_procs(Config) when is_list(Config) -> + lists:foreach(fun (TsType) -> + Arg = case TsType of + no_timestamp -> + {timestamp, []}; + _ -> + {TsType, [TsType]} + end, + do_runnable_procs(Arg), + receive after 1000 -> ok end + end, + [no_timestamp, timestamp, monotonic_timestamp, + strict_monotonic_timestamp]). + +do_runnable_procs({TsType, TsTypeFlag}) -> Pid = start_profiler_process(), % start a ring of processes % FIXME: Set #laps and #nodes in config file Nodes = 10, Laps = 10, Master = ring(Nodes), - undefined = erlang:system_profile(Pid, [runnable_procs]), + undefined = erlang:system_profile(Pid, [runnable_procs]++TsTypeFlag), % loop a message ok = ring_message(Master, message, Laps), Events = get_profiler_events(), @@ -127,9 +141,9 @@ runnable_procs(Config) when is_list(Config) -> erlang:system_profile(undefined, []), put(master, Master), put(laps, Laps), - true = has_runnable_event(Events), + true = has_runnable_event(TsType, Events), Pids = sort_events_by_pid(Events), - ok = check_events(Pids), + ok = check_events(TsType, Pids), erase(), exit(Pid,kill), ok. @@ -139,8 +153,22 @@ runnable_ports(suite) -> runnable_ports(doc) -> ["Tests system_profiling with runnable_port."]; runnable_ports(Config) when is_list(Config) -> + lists:foreach(fun (TsType) -> + Arg = case TsType of + no_timestamp -> + {timestamp, []}; + _ -> + {TsType, [TsType]} + end, + do_runnable_ports(Arg, Config), + receive after 1000 -> ok end + end, + [no_timestamp, timestamp, monotonic_timestamp, + strict_monotonic_timestamp]). + +do_runnable_ports({TsType, TsTypeFlag}, Config) -> Pid = start_profiler_process(), - undefined = erlang:system_profile(Pid, [runnable_ports]), + undefined = erlang:system_profile(Pid, [runnable_ports]++TsTypeFlag), EchoPid = echo(Config), % FIXME: Set config to number_of_echos Laps = 10, @@ -149,9 +177,9 @@ runnable_ports(Config) when is_list(Config) -> Events = get_profiler_events(), kill_em_all = kill_echo(EchoPid), erlang:system_profile(undefined, []), - true = has_runnable_event(Events), + true = has_runnable_event(TsType, Events), Pids = sort_events_by_pid(Events), - ok = check_events(Pids), + ok = check_events(TsType, Pids), erase(), exit(Pid,kill), ok. @@ -166,8 +194,19 @@ scheduler(Config) when is_list(Config) -> {_, 1} -> {skipped, "No need for scheduler test when only one scheduler online."}; _ -> Nodes = 10, - ok = check_block_system(Nodes), - ok = check_multi_scheduling_block(Nodes) + lists:foreach(fun (TsType) -> + Arg = case TsType of + no_timestamp -> + {timestamp, []}; + _ -> + {TsType, [TsType]} + end, + ok = check_block_system(Arg, Nodes), + ok = check_multi_scheduling_block(Arg, Nodes), + receive after 1000 -> ok end + end, + [no_timestamp, timestamp, monotonic_timestamp, + strict_monotonic_timestamp]) end. % the profiler pid should not be profiled @@ -195,9 +234,9 @@ dont_profile_profiler(Config) when is_list(Config) -> %%% Check scheduler profiling -check_multi_scheduling_block(Nodes) -> +check_multi_scheduling_block({TsType, TsTypeFlag}, Nodes) -> Pid = start_profiler_process(), - undefined = erlang:system_profile(Pid, [scheduler]), + undefined = erlang:system_profile(Pid, [scheduler]++TsTypeFlag), {ok, Supervisor} = start_load(Nodes), wait(600), erlang:system_flag(multi_scheduling, block), @@ -205,23 +244,23 @@ check_multi_scheduling_block(Nodes) -> erlang:system_flag(multi_scheduling, unblock), {Pid, [scheduler]} = erlang:system_profile(undefined, []), Events = get_profiler_events(), - true = has_scheduler_event(Events), + true = has_scheduler_event(TsType, Events), stop_load(Supervisor), exit(Pid,kill), erase(), ok. -check_block_system(Nodes) -> +check_block_system({TsType, TsTypeFlag}, Nodes) -> Dummy = spawn(?MODULE, profiler_process, [[]]), Pid = start_profiler_process(), - undefined = erlang:system_profile(Pid, [scheduler]), + undefined = erlang:system_profile(Pid, [scheduler]++TsTypeFlag), {ok, Supervisor} = start_load(Nodes), wait(300), undefined = erlang:system_monitor(Dummy, [busy_port]), {Dummy, [busy_port]} = erlang:system_monitor(undefined, []), {Pid, [scheduler]} = erlang:system_profile(undefined, []), Events = get_profiler_events(), - true = has_scheduler_event(Events), + true = has_scheduler_event(TsType, Events), stop_load(Supervisor), exit(Pid,kill), exit(Dummy,kill), @@ -230,40 +269,49 @@ check_block_system(Nodes) -> %%% Check events -check_events([]) -> ok; -check_events([Pid | Pids]) -> +check_events(_TsType, []) -> ok; +check_events(TsType, [Pid | Pids]) -> Master = get(master), Laps = get(laps), CheckPids = get(pids), {Events, N} = get_pid_events(Pid), ok = check_event_flow(Events), - ok = check_event_ts(Events), + ok = check_event_ts(TsType, Events), IsMember = lists:member(Pid, CheckPids), case Pid of Master -> io:format("Expected ~p and got ~p profile events from ~p: ok~n", [Laps*2+2, N, Pid]), N = Laps*2 + 2, - check_events(Pids); + check_events(TsType, Pids); Pid when IsMember == true -> io:format("Expected ~p and got ~p profile events from ~p: ok~n", [Laps*2, N, Pid]), N = Laps*2, - check_events(Pids); + check_events(TsType, Pids); Pid -> - check_events(Pids) + check_events(TsType, Pids) end. %% timestamp consistency check for descending timestamps -check_event_ts(Events) -> - check_event_ts(Events, undefined). -check_event_ts([], _) -> ok; -check_event_ts([Event | Events], undefined) -> - check_event_ts(Events, Event); -check_event_ts([{Pid, _, _, TS1}=Event | Events], {Pid,_,_,TS0}) -> - Time = timer:now_diff(TS1, TS0), +check_event_ts(TsType, Events) -> + check_event_ts(TsType, Events, undefined). +check_event_ts(_TsType, [], _) -> ok; +check_event_ts(TsType, [Event | Events], undefined) -> + check_event_ts(TsType, Events, Event); +check_event_ts(TsType, [{Pid, _, _, TS1}=Event | Events], {Pid,_,_,TS0}) -> + Time = case TsType of + timestamp -> + timer:now_diff(TS1, TS0); + monotonic_timestamp -> + TS1 - TS0; + strict_monotonic_timestamp -> + {MT1, _} = TS1, + {MT0, _} = TS0, + MT1 - MT0 + end, if Time < 0.0 -> timestamp_error; - true -> check_event_ts(Events, Event) + true -> check_event_ts(TsType, Events, Event) end. %% consistency check for active vs. inactive activity (runnable) @@ -428,6 +476,44 @@ port_echo_loop(Port) -> %% Helpers %%% +check_ts(no_timestamp, Ts) -> + try + no_timestamp = Ts + catch + _ : _ -> + ?t:fail({unexpected_timestamp, Ts}) + end, + ok; +check_ts(timestamp, Ts) -> + try + {Ms,S,Us} = Ts, + true = is_integer(Ms), + true = is_integer(S), + true = is_integer(Us) + catch + _ : _ -> + ?t:fail({unexpected_timestamp, Ts}) + end, + ok; +check_ts(monotonic_timestamp, Ts) -> + try + true = is_integer(Ts) + catch + _ : _ -> + ?t:fail({unexpected_timestamp, Ts}) + end, + ok; +check_ts(strict_monotonic_timestamp, Ts) -> + try + {MT, UMI} = Ts, + true = is_integer(MT), + true = is_integer(UMI) + catch + _ : _ -> + ?t:fail({unexpected_timestamp, Ts}) + end, + ok. + start_load(N) -> Pid = spawn_link(?MODULE, run_load, [N, []]), {ok, Pid}. @@ -454,21 +540,24 @@ list_load() -> end, list_load(). - -has_scheduler_event(Events) -> +has_scheduler_event(TsType, Events) -> lists:any( fun (Pred) -> case Pred of - {profile, scheduler, _ID, _Activity, _NR, _TS} -> true; + {profile, scheduler, _ID, _Activity, _NR, TS} -> + check_ts(TsType, TS), + true; _ -> false end end, Events). -has_runnable_event(Events) -> +has_runnable_event(TsType, Events) -> lists:any( fun (Pred) -> case Pred of - {profile, _Pid, _Activity, _MFA, _TS} -> true; + {profile, _Pid, _Activity, _MFA, TS} -> + check_ts(TsType, TS), + true; _ -> false end end, Events). diff --git a/erts/emulator/test/time_SUITE.erl b/erts/emulator/test/time_SUITE.erl index 33076c7461..787870588d 100644 --- a/erts/emulator/test/time_SUITE.erl +++ b/erts/emulator/test/time_SUITE.erl @@ -320,7 +320,41 @@ timestamp(suite) -> timestamp(doc) -> ["Test that os:timestamp works."]; timestamp(Config) when is_list(Config) -> - repeating_timestamp_check(100000). + try + repeating_timestamp_check(100000) + catch + throw : {fail, Failure} -> + %% + %% Our time warping test machines currently warps + %% time every 6:th second. If we get a warp during + %% 10 seconds, assume this is a time warping test + %% and ignore the failure. + %% + case had_time_warp(10) of + true -> + {skip, "Seems to be time warp test run..."}; + false -> + test_server:fail(Failure) + end + end. + +os_system_time_offset() -> + erlang:convert_time_unit(os:system_time() - erlang:monotonic_time(), + native, micro_seconds). + +had_time_warp(Secs) -> + had_time_warp(os_system_time_offset(), Secs). + +had_time_warp(OrigOffs, 0) -> + false; +had_time_warp(OrigOffs, N) -> + receive after 1000 -> ok end, + case OrigOffs - os_system_time_offset() of + Diff when Diff > 500000; Diff < -500000 -> + true; + _Diff -> + had_time_warp(OrigOffs, N-1) + end. repeating_timestamp_check(0) -> ok; @@ -346,15 +380,15 @@ repeating_timestamp_check(N) -> NSecs = NA*1000000+NB+round(NC/1000000), case Secs - NSecs of TooLarge when TooLarge > 3600 -> - test_server:fail( - lists:flatten( + throw({fail, + lists:flatten( io_lib:format("os:timestamp/0 is ~w s more than erlang:now/0", - [TooLarge]))); + [TooLarge]))}); TooSmall when TooSmall < -3600 -> - test_server:fail( + throw({fail, lists:flatten( io_lib:format("os:timestamp/0 is ~w s less than erlang:now/0", - [-TooSmall]))); + [-TooSmall]))}); _ -> ok end, diff --git a/erts/emulator/test/trace_bif_SUITE.erl b/erts/emulator/test/trace_bif_SUITE.erl index a12c41a3aa..96b7dd159f 100644 --- a/erts/emulator/test/trace_bif_SUITE.erl +++ b/erts/emulator/test/trace_bif_SUITE.erl @@ -67,7 +67,8 @@ trace_on_and_off(Config) when is_list(Config) -> ?line Pid = spawn(?MODULE, bif_process, []), ?line Self = self(), ?line 1 = erlang:trace(Pid, true, [call,timestamp]), - ?line {flags,[timestamp,call]} = erlang:trace_info(Pid,flags), + ?line {flags, Flags} = erlang:trace_info(Pid,flags), + ?line [call,timestamp] = lists:sort(Flags), ?line {tracer, Self} = erlang:trace_info(Pid,tracer), ?line 1 = erlang:trace(Pid, false, [timestamp]), ?line {flags,[call]} = erlang:trace_info(Pid,flags), @@ -111,93 +112,145 @@ do_trace_bif(Flags) -> trace_bif_timestamp(doc) -> "Test tracing BIFs with timestamps."; trace_bif_timestamp(Config) when is_list(Config) -> - do_trace_bif_timestamp([]). - + do_trace_bif_timestamp([], timestamp, [timestamp]), + do_trace_bif_timestamp([], timestamp, + [timestamp, + monotonic_timestamp, + strict_monotonic_timestamp]), + do_trace_bif_timestamp([], strict_monotonic_timestamp, + [strict_monotonic_timestamp]), + do_trace_bif_timestamp([], strict_monotonic_timestamp, + [monotonic_timestamp, strict_monotonic_timestamp]), + do_trace_bif_timestamp([], monotonic_timestamp, [monotonic_timestamp]). + trace_bif_timestamp_local(doc) -> "Test tracing BIFs with timestamps and local flag."; trace_bif_timestamp_local(Config) when is_list(Config) -> - do_trace_bif_timestamp([local]). - -do_trace_bif_timestamp(Flags) -> - ?line Pid=spawn(?MODULE, bif_process, []), - ?line 1 = erlang:trace(Pid, true, [call,timestamp]), - ?line erlang:trace_pattern({erlang,'_','_'}, [], Flags), - - ?line Pid ! {do_bif, time, []}, - ?line receive_trace_msg_ts({trace_ts,Pid,call,{erlang,time,[]}}), - - ?line Pid ! {do_bif, statistics, [runtime]}, - ?line receive_trace_msg_ts({trace_ts,Pid,call, - {erlang,statistics, [runtime]}}), - - ?line Pid ! {do_time_bif}, - ?line receive_trace_msg_ts({trace_ts,Pid,call, - {erlang,time, []}}), - - ?line Pid ! {do_statistics_bif}, - ?line receive_trace_msg_ts({trace_ts,Pid,call, - {erlang,statistics, [runtime]}}), + do_trace_bif_timestamp([local], timestamp, [timestamp]), + do_trace_bif_timestamp([local], timestamp, + [timestamp, + monotonic_timestamp, + strict_monotonic_timestamp]), + do_trace_bif_timestamp([local], strict_monotonic_timestamp, + [strict_monotonic_timestamp]), + do_trace_bif_timestamp([local], strict_monotonic_timestamp, + [monotonic_timestamp, strict_monotonic_timestamp]), + do_trace_bif_timestamp([local], monotonic_timestamp, [monotonic_timestamp]). + +do_trace_bif_timestamp(Flags, TsType, TsFlags) -> + io:format("Testing with TsType=~p TsFlags=~p~n", [TsType, TsFlags]), + Pid=spawn(?MODULE, bif_process, []), + 1 = erlang:trace(Pid, true, [call]++TsFlags), + erlang:trace_pattern({erlang,'_','_'}, [], Flags), + + Ts0 = make_ts(TsType), + Pid ! {do_bif, time, []}, + Ts1 = receive_trace_msg_ts({trace_ts,Pid,call,{erlang,time,[]}}, + Ts0,TsType), + + Pid ! {do_bif, statistics, [runtime]}, + Ts2 = receive_trace_msg_ts({trace_ts,Pid,call, + {erlang,statistics, [runtime]}}, + Ts1, TsType), + + Pid ! {do_time_bif}, + Ts3 = receive_trace_msg_ts({trace_ts,Pid,call, + {erlang,time, []}}, + Ts2, TsType), + + Pid ! {do_statistics_bif}, + Ts4 = receive_trace_msg_ts({trace_ts,Pid,call, + {erlang,statistics, [runtime]}}, + Ts3, TsType), + + check_ts(TsType, Ts4, make_ts(TsType)), %% We should be able to turn off the timestamp. - ?line 1 = erlang:trace(Pid, false, [timestamp]), + 1 = erlang:trace(Pid, false, TsFlags), - ?line Pid ! {do_statistics_bif}, - ?line receive_trace_msg({trace,Pid,call, - {erlang,statistics, [runtime]}}), + Pid ! {do_statistics_bif}, + receive_trace_msg({trace,Pid,call, + {erlang,statistics, [runtime]}}), - ?line Pid ! {do_bif, statistics, [runtime]}, - ?line receive_trace_msg({trace,Pid,call, - {erlang,statistics, [runtime]}}), + Pid ! {do_bif, statistics, [runtime]}, + receive_trace_msg({trace,Pid,call, + {erlang,statistics, [runtime]}}), - ?line 1 = erlang:trace(Pid, false, [call]), - ?line erlang:trace_pattern({erlang,'_','_'}, false, Flags), + 1 = erlang:trace(Pid, false, [call]), + erlang:trace_pattern({erlang,'_','_'}, false, Flags), - ?line exit(Pid, die), + exit(Pid, die), ok. trace_bif_return(doc) -> "Test tracing BIF's with return/return_to trace."; trace_bif_return(Config) when is_list(Config) -> - ?line Pid=spawn(?MODULE, bif_process, []), - ?line 1 = erlang:trace(Pid, true, [call,timestamp,return_to]), - ?line erlang:trace_pattern({erlang,'_','_'}, [{'_',[],[{return_trace}]}], - [local]), - - - ?line Pid ! {do_bif, time, []}, - ?line receive_trace_msg_ts({trace_ts,Pid,call,{erlang,time,[]}}), - ?line receive_trace_msg_ts_return_from({trace_ts,Pid,return_from, - {erlang,time,0}}), - ?line receive_trace_msg_ts_return_to({trace_ts,Pid,return_to, - {?MODULE, bif_process,0}}), - - - ?line Pid ! {do_bif, statistics, [runtime]}, - ?line receive_trace_msg_ts({trace_ts,Pid,call, - {erlang,statistics, [runtime]}}), - ?line receive_trace_msg_ts_return_from({trace_ts,Pid,return_from, - {erlang,statistics,1}}), - ?line receive_trace_msg_ts_return_to({trace_ts,Pid,return_to, - {?MODULE, bif_process,0}}), - - - ?line Pid ! {do_time_bif}, - ?line receive_trace_msg_ts({trace_ts,Pid,call, - {erlang,time, []}}), - ?line receive_trace_msg_ts_return_from({trace_ts,Pid,return_from, - {erlang,time,0}}), - ?line receive_trace_msg_ts_return_to({trace_ts,Pid,return_to, - {?MODULE, bif_process,0}}), - - - - ?line Pid ! {do_statistics_bif}, - ?line receive_trace_msg_ts({trace_ts,Pid,call, - {erlang,statistics, [runtime]}}), - ?line receive_trace_msg_ts_return_from({trace_ts,Pid,return_from, - {erlang,statistics,1}}), - ?line receive_trace_msg_ts_return_to({trace_ts,Pid,return_to, - {?MODULE, bif_process,0}}), + do_trace_bif_return(timestamp, [timestamp]), + do_trace_bif_return(timestamp, + [timestamp, + monotonic_timestamp, + strict_monotonic_timestamp]), + do_trace_bif_return(strict_monotonic_timestamp, + [strict_monotonic_timestamp]), + do_trace_bif_return(strict_monotonic_timestamp, + [monotonic_timestamp, strict_monotonic_timestamp]), + do_trace_bif_return(monotonic_timestamp, [monotonic_timestamp]). + +do_trace_bif_return(TsType, TsFlags) -> + io:format("Testing with TsType=~p TsFlags=~p~n", [TsType, TsFlags]), + Pid=spawn(?MODULE, bif_process, []), + 1 = erlang:trace(Pid, true, [call,return_to]++TsFlags), + erlang:trace_pattern({erlang,'_','_'}, [{'_',[],[{return_trace}]}], + [local]), + + Ts0 = make_ts(TsType), + Pid ! {do_bif, time, []}, + Ts1 = receive_trace_msg_ts({trace_ts,Pid,call,{erlang,time,[]}}, + Ts0, TsType), + Ts2 = receive_trace_msg_ts_return_from({trace_ts,Pid,return_from, + {erlang,time,0}}, + Ts1, TsType), + Ts3 = receive_trace_msg_ts_return_to({trace_ts,Pid,return_to, + {?MODULE, bif_process,0}}, + Ts2, TsType), + + + Pid ! {do_bif, statistics, [runtime]}, + Ts4 = receive_trace_msg_ts({trace_ts,Pid,call, + {erlang,statistics, [runtime]}}, + Ts3, TsType), + Ts5 = receive_trace_msg_ts_return_from({trace_ts,Pid,return_from, + {erlang,statistics,1}}, + Ts4, TsType), + Ts6 = receive_trace_msg_ts_return_to({trace_ts,Pid,return_to, + {?MODULE, bif_process,0}}, + Ts5, TsType), + + + Pid ! {do_time_bif}, + Ts7 = receive_trace_msg_ts({trace_ts,Pid,call, + {erlang,time, []}}, + Ts6, TsType), + Ts8 = receive_trace_msg_ts_return_from({trace_ts,Pid,return_from, + {erlang,time,0}}, + Ts7, TsType), + Ts9 = receive_trace_msg_ts_return_to({trace_ts,Pid,return_to, + {?MODULE, bif_process,0}}, + Ts8, TsType), + + + + Pid ! {do_statistics_bif}, + Ts10 = receive_trace_msg_ts({trace_ts,Pid,call, + {erlang,statistics, [runtime]}}, + Ts9, TsType), + Ts11 = receive_trace_msg_ts_return_from({trace_ts,Pid,return_from, + {erlang,statistics,1}}, + Ts10, TsType), + Ts12 = receive_trace_msg_ts_return_to({trace_ts,Pid,return_to, + {?MODULE, bif_process,0}}, + Ts11, TsType), + check_ts(TsType, Ts12, make_ts(TsType)), ok. @@ -213,10 +266,11 @@ receive_trace_msg(Mess) -> ?t:fail() end. -receive_trace_msg_ts({trace_ts, Pid, call, {erlang,F,A}}) -> +receive_trace_msg_ts({trace_ts, Pid, call, {erlang,F,A}}, PrevTs, TsType) -> receive - {trace_ts, Pid, call, {erlang, F, A}, _Ts} -> - ok; + {trace_ts, Pid, call, {erlang, F, A}, Ts} -> + check_ts(TsType, PrevTs, Ts), + Ts; Other -> io:format("Expected: {trace, ~p, call, {~p, ~p, ~p}, TimeStamp}},~n" "Got: ~p~n", @@ -227,10 +281,11 @@ receive_trace_msg_ts({trace_ts, Pid, call, {erlang,F,A}}) -> ?t:fail() end. -receive_trace_msg_ts_return_from({trace_ts, Pid, return_from, {erlang,F,A}}) -> +receive_trace_msg_ts_return_from({trace_ts, Pid, return_from, {erlang,F,A}}, PrevTs, TsType) -> receive - {trace_ts, Pid, return_from, {erlang, F, A}, _Value, _Ts} -> - ok; + {trace_ts, Pid, return_from, {erlang, F, A}, _Value, Ts} -> + check_ts(TsType, PrevTs, Ts), + Ts; Other -> io:format("Expected: {trace_ts, ~p, return_from, {~p, ~p, ~p}, Value, TimeStamp}},~n" "Got: ~p~n", @@ -241,10 +296,11 @@ receive_trace_msg_ts_return_from({trace_ts, Pid, return_from, {erlang,F,A}}) -> ?t:fail() end. -receive_trace_msg_ts_return_to({trace_ts, Pid, return_to, {M,F,A}}) -> +receive_trace_msg_ts_return_to({trace_ts, Pid, return_to, {M,F,A}}, PrevTs, TsType) -> receive - {trace_ts, Pid, return_to, {M, F, A}, _Ts} -> - ok; + {trace_ts, Pid, return_to, {M, F, A}, Ts} -> + check_ts(TsType, PrevTs, Ts), + Ts; Other -> io:format("Expected: {trace_ts, ~p, return_to, {~p, ~p, ~p}, TimeStamp}},~n" "Got: ~p~n", @@ -255,6 +311,33 @@ receive_trace_msg_ts_return_to({trace_ts, Pid, return_to, {M,F,A}}) -> ?t:fail() end. +make_ts(timestamp) -> + erlang:now(); +make_ts(monotonic_timestamp) -> + erlang:monotonic_time(nano_seconds); +make_ts(strict_monotonic_timestamp) -> + MT = erlang:monotonic_time(nano_seconds), + UMI = erlang:unique_integer([monotonic]), + {MT, UMI}. + +check_ts(timestamp, PrevTs, Ts) -> + {Ms, S, Us} = Ts, + true = is_integer(Ms), + true = is_integer(S), + true = is_integer(Us), + true = PrevTs < Ts, + Ts; +check_ts(monotonic_timestamp, PrevTs, Ts) -> + true = is_integer(Ts), + true = PrevTs =< Ts, + Ts; +check_ts(strict_monotonic_timestamp, PrevTs, Ts) -> + {MT, UMI} = Ts, + true = is_integer(MT), + true = is_integer(UMI), + true = PrevTs < Ts, + Ts. + bif_process() -> receive {do_bif, Name, Args} -> diff --git a/erts/emulator/test/trace_port_SUITE.erl b/erts/emulator/test/trace_port_SUITE.erl index d6346f3af0..a77710205e 100644 --- a/erts/emulator/test/trace_port_SUITE.erl +++ b/erts/emulator/test/trace_port_SUITE.erl @@ -35,7 +35,8 @@ fake_schedule_after_getting_linked/1, fake_schedule_after_getting_unlinked/1, gc/1, - default_tracer/1]). + default_tracer/1, + tracer_port_crash/1]). -include_lib("test_server/include/test_server.hrl"). @@ -45,7 +46,7 @@ test_cases() -> fake_schedule_after_register, fake_schedule_after_getting_linked, fake_schedule_after_getting_unlinked, gc, - default_tracer]. + default_tracer, tracer_port_crash]. suite() -> [{ct_hooks,[ts_install_cth]}]. @@ -473,6 +474,42 @@ default_tracer(Config) when is_list(Config) -> ?line M = N, ok. +tracer_port_crash(Config) when is_list(Config) -> + case test_server:is_native(?MODULE) orelse + test_server:is_native(lists) of + true -> + {skip,"Native code"}; + false -> + Tr = start_tracer(Config), + Port = get(tracer_port), + Tracee = spawn(fun () -> + register(trace_port_linker, self()), + link(Port), + receive go -> ok end, + lists:reverse([1,b,c]), + receive die -> ok end + end), + Tr ! {unlink_tracer_port, self()}, + receive {unlinked_tracer_port, Tr} -> ok end, + port_control(Port, $c, []), %% Make port commands crash tracer port... + trace_func({lists,reverse,1}, []), + trace_pid(Tracee, true, [call]), + trace_info(Tracee, flags), + trace_info(self(), tracer), + Tracee ! go, + receive after 1000 -> ok end, + case whereis(trace_port_linker) of + undefined -> + ok; + Id -> +% erts_debug:set_internal_state(available_internal_state, true), +% erts_debug:set_internal_state(abort, {trace_port_linker, Id}) + ?t:fail({trace_port_linker, Id}) + end, + undefined = process_info(Tracee), + ok + end. + %%% Help functions. huge_data() -> huge_data(16384). @@ -631,6 +668,10 @@ tracer_loop(RelayTo, Port) -> {Port,{data,Msg}} -> RelayTo ! binary_to_term(Msg), tracer_loop(RelayTo, Port); + {unlink_tracer_port, From} -> + unlink(Port), + From ! {unlinked_tracer_port, self()}, + tracer_loop(RelayTo, Port); Other -> exit({bad_message,Other}) end. diff --git a/erts/emulator/test/trace_port_SUITE_data/echo_drv.c b/erts/emulator/test/trace_port_SUITE_data/echo_drv.c index a8d4ede4fe..e40b9193ea 100644 --- a/erts/emulator/test/trace_port_SUITE_data/echo_drv.c +++ b/erts/emulator/test/trace_port_SUITE_data/echo_drv.c @@ -1,5 +1,6 @@ #include <stdio.h> #include "erl_driver.h" +#include <errno.h> @@ -14,6 +15,7 @@ enum e_heavy { typedef struct _erl_drv_data { ErlDrvPort erlang_port; enum e_heavy heavy; + int crash; } EchoDrvData; static EchoDrvData echo_drv_data, *echo_drv_data_p; @@ -78,6 +80,7 @@ static EchoDrvData *echo_drv_start(ErlDrvPort port, char *command) echo_drv_data_p = &echo_drv_data; echo_drv_data_p->erlang_port = port; echo_drv_data_p->heavy = heavy_off; + echo_drv_data_p->crash = 0; return echo_drv_data_p; } @@ -87,6 +90,12 @@ static void echo_drv_stop(EchoDrvData *data_p) { static void echo_drv_output(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) { EchoDrvData* data_p = (EchoDrvData *) drv_data; + + if (data_p->crash) { + driver_failure_posix(data_p->erlang_port, EINTR); + return; + } + driver_output(data_p->erlang_port, buf, len); switch (data_p->heavy) { case heavy_off: @@ -100,6 +109,7 @@ static void echo_drv_output(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) { data_p->heavy = heavy_off; break; } + } static void echo_drv_finish() { @@ -115,6 +125,8 @@ static ErlDrvSSizeT echo_drv_control(ErlDrvData drv_data, case 'h': data_p->heavy = heavy_set; break; + case 'c': + data_p->crash = 1; } return 0; } diff --git a/erts/emulator/utils/make_alloc_types b/erts/emulator/utils/make_alloc_types index 88f537ea09..925b9d5810 100755 --- a/erts/emulator/utils/make_alloc_types +++ b/erts/emulator/utils/make_alloc_types @@ -246,7 +246,7 @@ print DST " print DST "#define ERTS_ALC_C_MIN ($c_no)\n\n"; -foreach my $c (keys(%c_tab)) { +foreach my $c (sort keys(%c_tab)) { push(@c_order, $c); set_number($c_tab{$c}, $c_no); print DST "#define ERTS_ALC_C_$c ($c_no)\n"; diff --git a/erts/emulator/utils/make_version b/erts/emulator/utils/make_version index 3461dc1637..37bdff181a 100755 --- a/erts/emulator/utils/make_version +++ b/erts/emulator/utils/make_version @@ -59,7 +59,11 @@ print FILE <<EOF; #define ERLANG_OTP_RELEASE "$release" #define ERLANG_OTP_VERSION "$otp_version" #define ERLANG_VERSION "$version" -#define ERLANG_COMPILE_DATE "$time_str" +#if ERTS_SAVED_COMPILE_TIME +# define ERLANG_COMPILE_DATE "$time_str" +#else +# define ERLANG_COMPILE_DATE "" +#endif #define ERLANG_ARCHITECTURE "$architecture" EOF diff --git a/erts/emulator/utils/mkver.c b/erts/emulator/utils/mkver.c index 96cd315a95..6641873712 100644 --- a/erts/emulator/utils/mkver.c +++ b/erts/emulator/utils/mkver.c @@ -35,8 +35,10 @@ int argc; char** argv; { FILE *file; +#if ERTS_SAVED_COMPILE_TIME time_t now; - char *cnow; +#endif + char *cnow = ""; if (argc != 2) { fprintf(stderr, "usage: mkver version\n"); @@ -48,9 +50,11 @@ char** argv; exit(1); } +#if ERTS_SAVED_COMPILE_TIME time(&now); cnow = ctime(&now); cnow[24] = '\0'; /* tidelipom */ +#endif fprintf(file, "/* This file was created by mkver -- don't modify.*/\n"); fprintf(file, "#define ERLANG_VERSION \"%s\"\n", argv[1]); fprintf(file, "#define ERLANG_COMPILE_DATE \"%s\"\n", cnow); diff --git a/erts/emulator/valgrind/suppress.patched.3.6.0 b/erts/emulator/valgrind/suppress.patched.3.6.0 index 16cecf2dba..fcde4a0123 100644 --- a/erts/emulator/valgrind/suppress.patched.3.6.0 +++ b/erts/emulator/valgrind/suppress.patched.3.6.0 @@ -368,7 +368,7 @@ Memcheck:Addr4 ... fun:erts_print_scheduler_info ... -fun:erl_exit +fun:erts_exit fun:broken_halt_test fun:erts_debug_set_internal_state_2 fun:process_main diff --git a/erts/emulator/valgrind/suppress.standard b/erts/emulator/valgrind/suppress.standard index a1f3f82364..bb07c92fc1 100644 --- a/erts/emulator/valgrind/suppress.standard +++ b/erts/emulator/valgrind/suppress.standard @@ -336,7 +336,7 @@ Memcheck:Addr4 ... fun:erts_print_scheduler_info ... -fun:erl_exit +fun:erts_exit fun:broken_halt_test fun:erts_debug_set_internal_state_2 fun:process_main diff --git a/erts/epmd/src/epmd.c b/erts/epmd/src/epmd.c index 132bda725c..5513cb2d7e 100644 --- a/erts/epmd/src/epmd.c +++ b/erts/epmd/src/epmd.c @@ -29,7 +29,7 @@ #ifdef HAVE_STDLIB_H # include <stdlib.h> #endif - +#include <time.h> /* forward declarations */ static void usage(EpmdVars *); @@ -343,7 +343,7 @@ static void run_daemon(EpmdVars *g) for (fd = 0; fd < g->max_conn ; fd++) /* close all files ... */ close(fd); /* Syslog on linux will try to write to whatever if we dont - inform it of that the log is closed. */ + inform it that the log is closed. */ closelog(); /* These shouldn't be needed but for safety... */ diff --git a/erts/epmd/src/epmd_cli.c b/erts/epmd/src/epmd_cli.c index a8fe865d9a..6fc05e153e 100644 --- a/erts/epmd/src/epmd_cli.c +++ b/erts/epmd/src/epmd_cli.c @@ -136,19 +136,33 @@ void epmd_call(EpmdVars *g,int what) static int conn_to_epmd(EpmdVars *g) { struct EPMD_SOCKADDR_IN address; + size_t salen = 0; int connect_sock; - - connect_sock = socket(FAMILY, SOCK_STREAM, 0); - if (connect_sock<0) - goto error; + unsigned short sport = g->port; + +#if defined(EPMD6) + SET_ADDR6(address, in6addr_loopback, sport); + salen = sizeof(struct sockaddr_in6); + + connect_sock = socket(AF_INET6, SOCK_STREAM, 0); + if (connect_sock>=0) { + + if (connect(connect_sock, (struct sockaddr*)&address, salen) == 0) + return connect_sock; - { /* store port number in unsigned short */ - unsigned short sport = g->port; - SET_ADDR(address, EPMD_ADDR_LOOPBACK, sport); + close(connect_sock); } +#endif + SET_ADDR(address, htonl(INADDR_LOOPBACK), sport); + salen = sizeof(struct sockaddr_in); - if (connect(connect_sock, (struct sockaddr*)&address, sizeof address) < 0) + connect_sock = socket(AF_INET, SOCK_STREAM, 0); + if (connect_sock<0) goto error; + + if (connect(connect_sock, (struct sockaddr*)&address, salen) < 0) + goto error; + return connect_sock; error: diff --git a/erts/epmd/src/epmd_int.h b/erts/epmd/src/epmd_int.h index 26100afc93..09317094c7 100644 --- a/erts/epmd/src/epmd_int.h +++ b/erts/epmd/src/epmd_int.h @@ -55,6 +55,7 @@ # ifndef WINDOWS_H_INCLUDES_WINSOCK2_H # include <winsock2.h> # endif +# include <ws2tcpip.h> # include <windows.h> # include <process.h> #endif @@ -130,6 +131,10 @@ # include <systemd/sd-daemon.h> #endif /* HAVE_SYSTEMD_DAEMON */ +#if defined(HAVE_IN6) && defined(AF_INET6) && defined(HAVE_INET_PTON) +# define EPMD6 +#endif + /* ************************************************************************ */ /* Replace some functions by others by making the function name a macro */ @@ -183,33 +188,53 @@ /* ************************************************************************ */ /* Macros that let us use IPv6 */ -#if defined(HAVE_IN6) && defined(AF_INET6) && defined(EPMD6) +#if HAVE_IN6 +# if ! defined(HAVE_IN6ADDR_ANY) || ! HAVE_IN6ADDR_ANY +# if HAVE_DECL_IN6ADDR_ANY_INIT +static const struct in6_addr in6addr_any = { { IN6ADDR_ANY_INIT } }; +# else +static const struct in6_addr in6addr_any = + { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }; +# endif /* HAVE_IN6ADDR_ANY_INIT */ +# endif /* ! HAVE_DECL_IN6ADDR_ANY */ + +# if ! defined(HAVE_IN6ADDR_LOOPBACK) || ! HAVE_IN6ADDR_LOOPBACK +# if HAVE_DECL_IN6ADDR_LOOPBACK_INIT +static const struct in6_addr in6addr_loopback = + { { IN6ADDR_LOOPBACK_INIT } }; +# else +static const struct in6_addr in6addr_loopback = + { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } }; +# endif /* HAVE_IN6ADDR_LOOPBACK_INIT */ +# endif /* ! HAVE_DECL_IN6ADDR_LOOPBACK */ +#endif /* HAVE_IN6 */ + +#define IS_ADDR_LOOPBACK(addr) ((addr).s_addr == htonl(INADDR_LOOPBACK)) + +#if defined(EPMD6) -#define EPMD_SOCKADDR_IN sockaddr_in6 -#define EPMD_IN_ADDR in6_addr -#define EPMD_S_ADDR s6_addr -#define EPMD_ADDR_LOOPBACK in6addr_loopback.s6_addr -#define EPMD_ADDR_ANY in6addr_any.s6_addr +#define EPMD_SOCKADDR_IN sockaddr_storage #define FAMILY AF_INET6 -#define SET_ADDR(dst, addr, port) do { \ - memset((char*)&(dst), 0, sizeof(dst)); \ - memcpy((char*)&(dst).sin6_addr.s6_addr, (char*)&(addr), 16); \ - (dst).sin6_family = AF_INET6; \ - (dst).sin6_flowinfo = 0; \ - (dst).sin6_port = htons(port); \ +#define SET_ADDR6(dst, addr, port) do { \ + struct sockaddr_in6 *sa = (struct sockaddr_in6 *)&(dst); \ + memset(sa, 0, sizeof(dst)); \ + sa->sin6_family = AF_INET6; \ + sa->sin6_addr = (addr); \ + sa->sin6_port = htons(port); \ } while(0) -#define IS_ADDR_LOOPBACK(addr) \ - (memcmp((addr).s6_addr, in6addr_loopback.s6_addr, 16) == 0) +#define SET_ADDR(dst, addr, port) do { \ + struct sockaddr_in *sa = (struct sockaddr_in *)&(dst); \ + memset(sa, 0, sizeof(dst)); \ + sa->sin_family = AF_INET; \ + sa->sin_addr.s_addr = (addr); \ + sa->sin_port = htons(port); \ + } while(0) #else /* Not IP v6 */ #define EPMD_SOCKADDR_IN sockaddr_in -#define EPMD_IN_ADDR in_addr -#define EPMD_S_ADDR s_addr -#define EPMD_ADDR_LOOPBACK htonl(INADDR_LOOPBACK) -#define EPMD_ADDR_ANY htonl(INADDR_ANY) #define FAMILY AF_INET #define SET_ADDR(dst, addr, port) do { \ @@ -219,8 +244,6 @@ (dst).sin_port = htons(port); \ } while(0) -#define IS_ADDR_LOOPBACK(addr) ((addr).s_addr == htonl(INADDR_LOOPBACK)) - #endif /* Not IP v6 */ /* ************************************************************************ */ diff --git a/erts/epmd/src/epmd_srv.c b/erts/epmd/src/epmd_srv.c index 8c8d7304f2..e1bac99ef9 100644 --- a/erts/epmd/src/epmd_srv.c +++ b/erts/epmd/src/epmd_srv.c @@ -76,6 +76,7 @@ static time_t current_time(EpmdVars*); static Connection *conn_init(EpmdVars*); static int conn_open(EpmdVars*,int); +static int conn_local_peer_check(EpmdVars*, int); static int conn_close_fd(EpmdVars*,int); static void node_init(EpmdVars*); @@ -206,10 +207,11 @@ void run(EpmdVars *g) { struct EPMD_SOCKADDR_IN iserv_addr[MAX_LISTEN_SOCKETS]; int listensock[MAX_LISTEN_SOCKETS]; - int num_sockets; + int num_sockets = 0; int i; int opt; unsigned short sport = g->port; + int bound = 0; node_init(g); g->conn = conn_init(g); @@ -252,64 +254,82 @@ void run(EpmdVars *g) if (g->addresses != NULL && /* String contains non-separator characters if: */ g->addresses[strspn(g->addresses," ,")] != '\000') { - char *tmp; - char *token; - int loopback_ok = 0; + char *tmp = NULL; + char *token = NULL; + + /* Always listen on the loopback. */ + SET_ADDR(iserv_addr[num_sockets],htonl(INADDR_LOOPBACK),sport); + num_sockets++; +#if defined(EPMD6) + SET_ADDR6(iserv_addr[num_sockets],in6addr_loopback,sport); + num_sockets++; +#endif - if ((tmp = (char *)malloc(strlen(g->addresses) + 1)) == NULL) + if ((tmp = strdup(g->addresses)) == NULL) { dbg_perror(g,"cannot allocate memory"); epmd_cleanup_exit(g,1); } - strcpy(tmp,g->addresses); - for(token = strtok(tmp,", "), num_sockets = 0; + for(token = strtok(tmp,", "); token != NULL; - token = strtok(NULL,", "), num_sockets++) + token = strtok(NULL,", ")) { - struct EPMD_IN_ADDR addr; -#ifdef HAVE_INET_PTON - int ret; + struct in_addr addr; +#if defined(EPMD6) + struct in6_addr addr6; + struct sockaddr_storage *sa = &iserv_addr[num_sockets]; - if ((ret = inet_pton(FAMILY,token,&addr)) == -1) + if (inet_pton(AF_INET6,token,&addr6) == 1) { - dbg_perror(g,"cannot convert IP address to network format"); - epmd_cleanup_exit(g,1); + SET_ADDR6(iserv_addr[num_sockets],addr6,sport); + } + else if (inet_pton(AF_INET,token,&addr) == 1) + { + SET_ADDR(iserv_addr[num_sockets],addr.s_addr,sport); + } + else +#else + if ((addr.s_addr = inet_addr(token)) != INADDR_NONE) + { + SET_ADDR(iserv_addr[num_sockets],addr.s_addr,sport); } - else if (ret == 0) -#elif !defined(EPMD6) - if ((addr.EPMD_S_ADDR = inet_addr(token)) == INADDR_NONE) + else #endif { dbg_tty_printf(g,0,"cannot parse IP address \"%s\"",token); epmd_cleanup_exit(g,1); } +#if defined(EPMD6) + if (sa->ss_family == AF_INET6 && IN6_IS_ADDR_LOOPBACK(&addr6)) + continue; + + if (sa->ss_family == AF_INET) +#endif if (IS_ADDR_LOOPBACK(addr)) - loopback_ok = 1; + continue; - if (num_sockets - loopback_ok == MAX_LISTEN_SOCKETS - 1) + num_sockets++; + + if (num_sockets >= MAX_LISTEN_SOCKETS) { dbg_tty_printf(g,0,"cannot listen on more than %d IP addresses", MAX_LISTEN_SOCKETS); epmd_cleanup_exit(g,1); } - - SET_ADDR(iserv_addr[num_sockets],addr.EPMD_S_ADDR,sport); } free(tmp); - - if (!loopback_ok) - { - SET_ADDR(iserv_addr[num_sockets],EPMD_ADDR_LOOPBACK,sport); - num_sockets++; - } } else { - SET_ADDR(iserv_addr[0],EPMD_ADDR_ANY,sport); - num_sockets = 1; + SET_ADDR(iserv_addr[num_sockets],htonl(INADDR_ANY),sport); + num_sockets++; +#if defined(EPMD6) + SET_ADDR6(iserv_addr[num_sockets],in6addr_any,sport); + num_sockets++; +#endif } #ifdef HAVE_SYSTEMD_DAEMON } @@ -340,13 +360,39 @@ void run(EpmdVars *g) #endif /* HAVE_SYSTEMD_DAEMON */ for (i = 0; i < num_sockets; i++) { - if ((listensock[i] = socket(FAMILY,SOCK_STREAM,0)) < 0) + struct sockaddr *sa = (struct sockaddr *)&iserv_addr[i]; +#if defined(EPMD6) + size_t salen = (sa->sa_family == AF_INET6 ? + sizeof(struct sockaddr_in6) : + sizeof(struct sockaddr_in)); +#else + size_t salen = sizeof(struct sockaddr_in); +#endif + + if ((listensock[i] = socket(sa->sa_family,SOCK_STREAM,0)) < 0) { - dbg_perror(g,"error opening stream socket"); + switch (errno) { + case EAFNOSUPPORT: + case EPROTONOSUPPORT: + continue; + default: + dbg_perror(g,"error opening stream socket"); + epmd_cleanup_exit(g,1); + } + } + g->listenfd[bound++] = listensock[i]; + +#if HAVE_DECL_IPV6_V6ONLY + opt = 1; + if (sa->sa_family == AF_INET6 && + setsockopt(listensock[i],IPPROTO_IPV6,IPV6_V6ONLY,&opt, + sizeof(opt)) <0) + { + dbg_perror(g,"can't set IPv6 only socket option"); epmd_cleanup_exit(g,1); } - g->listenfd[i] = listensock[i]; - +#endif + /* * Note that we must not enable the SO_REUSEADDR on Windows, * because addresses will be reused even if they are still in use. @@ -378,8 +424,7 @@ void run(EpmdVars *g) dbg_perror(g,"failed to set non-blocking mode of listening socket %d", listensock[i]); - if (bind(listensock[i], (struct sockaddr*) &iserv_addr[i], - sizeof(iserv_addr[i])) < 0) + if (bind(listensock[i], (struct sockaddr*) &iserv_addr[i], salen) < 0) { if (errno == EADDRINUSE) { @@ -400,6 +445,11 @@ void run(EpmdVars *g) } select_fd_set(g, listensock[i]); } + if (bound == 0) { + dbg_perror(g,"unable to bind any address"); + epmd_cleanup_exit(g,1); + } + num_sockets = bound; #ifdef HAVE_SYSTEMD_DAEMON } sd_notifyf(0, "READY=1\n" @@ -444,8 +494,8 @@ void run(EpmdVars *g) } for (i = 0; i < num_sockets; i++) - if (FD_ISSET(listensock[i],&read_mask)) { - if (do_accept(g, listensock[i]) && g->active_conn < g->max_conn) { + if (FD_ISSET(g->listenfd[i],&read_mask)) { + if (do_accept(g, g->listenfd[i]) && g->active_conn < g->max_conn) { /* * The accept() succeeded, and we have at least one file * descriptor still free, which means that another accept() @@ -700,11 +750,9 @@ static void do_request(g, fd, s, buf, bsize) put_int16(node->creation, wbuf+2); } - if (g->delay_write) /* Test of busy server */ - sleep(g->delay_write); - if (reply(g, fd, wbuf, 4) != 4) { + node_unreg(g, name); dbg_tty_printf(g,1,"** failed to send ALIVE2_RESP for \"%s\"", name); return; @@ -1007,15 +1055,6 @@ static int conn_open(EpmdVars *g,int fd) for (i = 0; i < g->max_conn; i++) { if (g->conn[i].open == EPMD_FALSE) { - struct sockaddr_in si; - struct sockaddr_in di; -#ifdef HAVE_SOCKLEN_T - socklen_t st; -#else - int st; -#endif - st = sizeof(si); - g->active_conn++; s = &g->conn[i]; @@ -1026,20 +1065,7 @@ static int conn_open(EpmdVars *g,int fd) s->open = EPMD_TRUE; s->keep = EPMD_FALSE; - /* Determine if connection is from localhost */ - if (getpeername(s->fd,(struct sockaddr*) &si,&st) || - st < sizeof(si)) { - /* Failure to get peername is regarded as non local host */ - s->local_peer = EPMD_FALSE; - } else { - /* Only 127.x.x.x and connections from the host's IP address - allowed, no false positives */ - s->local_peer = - (((((unsigned) ntohl(si.sin_addr.s_addr)) & 0xFF000000U) == - 0x7F000000U) || - (getsockname(s->fd,(struct sockaddr*) &di,&st) ? - EPMD_FALSE : si.sin_addr.s_addr == di.sin_addr.s_addr)); - } + s->local_peer = conn_local_peer_check(g, s->fd); dbg_tty_printf(g,2,(s->local_peer) ? "Local peer connected" : "Non-local peer connected"); @@ -1047,7 +1073,7 @@ static int conn_open(EpmdVars *g,int fd) s->got = 0; s->mod_time = current_time(g); /* Note activity */ - s->buf = (char *)malloc(INBUF_SIZE); + s->buf = malloc(INBUF_SIZE); if (s->buf == NULL) { dbg_printf(g,0,"epmd: Insufficient memory"); @@ -1065,6 +1091,60 @@ static int conn_open(EpmdVars *g,int fd) return EPMD_FALSE; } +static int conn_local_peer_check(EpmdVars *g, int fd) +{ + struct EPMD_SOCKADDR_IN si; + struct EPMD_SOCKADDR_IN di; + + struct sockaddr_in *si4 = (struct sockaddr_in *)&si; + struct sockaddr_in *di4 = (struct sockaddr_in *)&di; + +#if defined(EPMD6) + struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&si; + struct sockaddr_in6 *di6 = (struct sockaddr_in6 *)&di; +#endif + +#ifdef HAVE_SOCKLEN_T + socklen_t st; +#else + int st; +#endif + + st = sizeof(si); + + /* Determine if connection is from localhost */ + if (getpeername(fd,(struct sockaddr*) &si,&st) || + st > sizeof(si)) { + /* Failure to get peername is regarded as non local host */ + return EPMD_FALSE; + } + + /* Only 127.x.x.x and connections from the host's IP address + allowed, no false positives */ +#if defined(EPMD6) + if (si.ss_family == AF_INET6 && IN6_IS_ADDR_LOOPBACK(&(si6->sin6_addr))) + return EPMD_TRUE; + + if (si.ss_family == AF_INET) +#endif + if ((((unsigned) ntohl(si4->sin_addr.s_addr)) & 0xFF000000U) == + 0x7F000000U) + return EPMD_TRUE; + + if (getsockname(fd,(struct sockaddr*) &di,&st)) + return EPMD_FALSE; + +#if defined(EPMD6) + if (si.ss_family == AF_INET6) + return IN6_ARE_ADDR_EQUAL( &(si6->sin6_addr), &(di6->sin6_addr)); + if (si.ss_family == AF_INET) +#endif + return si4->sin_addr.s_addr == di4->sin_addr.s_addr; +#if defined(EPMD6) + return EPMD_FALSE; +#endif +} + static int conn_close_fd(EpmdVars *g,int fd) { int i; diff --git a/erts/epmd/test/epmd_SUITE.erl b/erts/epmd/test/epmd_SUITE.erl index e8bbfdbb18..d5837e5b8c 100644 --- a/erts/epmd/test/epmd_SUITE.erl +++ b/erts/epmd/test/epmd_SUITE.erl @@ -43,6 +43,7 @@ -export( [ register_name/1, + register_name_ipv6/1, register_names_1/1, register_names_2/1, register_duplicate_name/1, @@ -76,7 +77,9 @@ buffer_overrun_2/1, no_nonlocal_register/1, no_nonlocal_kill/1, - no_live_killing/1 + no_live_killing/1, + + socket_reset_before_alive2_reply_is_written/1 ]). @@ -111,7 +114,8 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [register_name, register_names_1, register_names_2, + [register_name, register_name_ipv6, + register_names_1, register_names_2, register_duplicate_name, unicode_name, long_unicode_name, get_port_nr, slow_get_port_nr, unregister_others_name_1, unregister_others_name_2, @@ -123,7 +127,8 @@ all() -> returns_valid_populated_extra_with_nulls, names_stdout, {group, buffer_overrun}, no_nonlocal_register, - no_nonlocal_kill, no_live_killing]. + no_nonlocal_kill, no_live_killing, + socket_reset_before_alive2_reply_is_written]. groups() -> [{buffer_overrun, [], @@ -169,6 +174,24 @@ register_name(Config) when is_list(Config) -> ?line ok = close(Sock), % Unregister ok. +register_name_ipv6(doc) -> + ["Register a name over IPv6"]; +register_name_ipv6(suite) -> + []; +register_name_ipv6(Config) when is_list(Config) -> + % Test if the host has an IPv6 loopback address + Res = gen_tcp:listen(0, [inet6, {ip, {0,0,0,0,0,0,0,1}}]), + case Res of + {ok,LSock} -> + gen_tcp:close(LSock), + ?line ok = epmdrun(), + ?line {ok,Sock} = register_node6("foobar6"), + ?line ok = close(Sock), % Unregister + ok; + _Error -> + {skip, "Host does not have an IPv6 loopback address"} + end. + register_names_1(doc) -> ["Register and unregister two nodes"]; register_names_1(suite) -> @@ -242,13 +265,14 @@ register_node(Name) -> register_node(Name,Port) -> register_node_v2(Port,$M,0,5,5,Name,""). +register_node6(Name) -> + register_node_v2({0,0,0,0,0,0,0,1},?DUMMY_PORT,$M,0,5,5,Name,""). + register_node_v2(Port, NodeType, Prot, HVsn, LVsn, Name, Extra) -> - Utf8Name = unicode:characters_to_binary(Name), - Req = [?EPMD_ALIVE2_REQ, put16(Port), NodeType, Prot, - put16(HVsn), put16(LVsn), - put16(size(Utf8Name)), binary_to_list(Utf8Name), - size16(Extra), Extra], - case send_req(Req) of + register_node_v2("localhost", Port, NodeType, Prot, HVsn, LVsn, Name, Extra). +register_node_v2(Addr, Port, NodeType, Prot, HVsn, LVsn, Name, Extra) -> + Req = alive2_req(Port, NodeType, Prot, HVsn, LVsn, Name, Extra), + case send_req(Req, Addr) of {ok,Sock} -> case recv(Sock,4) of {ok, [?EPMD_ALIVE2_RESP,_Res=0,_C0,_C1]} -> @@ -938,6 +962,42 @@ no_live_killing(Config) when is_list(Config) -> ?line close(Sock3), ok. +socket_reset_before_alive2_reply_is_written(doc) -> + ["Check for regression - don't make zombie from node which " + "sends TCP RST at wrong time"]; +socket_reset_before_alive2_reply_is_written(suite) -> + []; +socket_reset_before_alive2_reply_is_written(Config) when is_list(Config) -> + %% - delay_write for easier triggering of race condition + %% - relaxed_command_check for gracefull shutdown of epmd even if there + %% is stuck node. + ?line ok = epmdrun("-delay_write 1 -relaxed_command_check"), + + %% We can't use send_req/1 directly as we want to do inet:setopts/2 + %% on our socket. + ?line {ok, Sock} = connect(), + + %% Issuing close/1 on such socket will result in immediate RST packet. + ?line ok = inet:setopts(Sock, [{linger, {true, 0}}]), + + Req = alive2_req(4711, 77, 0, 5, 5, "test", []), + ?line ok = send(Sock, [size16(Req), Req]), + + timer:sleep(500), %% Wait for the first 1/2 of delay_write before closing + ?line ok = close(Sock), + + timer:sleep(500 + ?SHORT_PAUSE), %% Wait for the other 1/2 of delay_write + + %% Wait another delay_write interval, due to delay doubling in epmd. + %% Should be removed when this is issue is fixed there. + timer:sleep(1000), + + ?line {ok, SockForNames} = connect_active(), + + %% And there should be no stuck nodes + ?line {ok, []} = do_get_names(SockForNames), + ?line ok = close(SockForNames), + ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Terminate all tests with killing epmd. @@ -1151,7 +1211,9 @@ send_direct(Sock, Bytes) -> end. send_req(Req) -> - case connect() of + send_req(Req, "localhost"). +send_req(Req, Addr) -> + case connect(Addr) of {ok,Sock} -> case send(Sock, [size16(Req), Req]) of ok -> @@ -1200,3 +1262,12 @@ flat_count([_|T], N) -> flat_count(T, N); flat_count([], N) -> N. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +alive2_req(Port, NodeType, Prot, HVsn, LVsn, Name, Extra) -> + Utf8Name = unicode:characters_to_binary(Name), + [?EPMD_ALIVE2_REQ, put16(Port), NodeType, Prot, + put16(HVsn), put16(LVsn), + put16(size(Utf8Name)), binary_to_list(Utf8Name), + size16(Extra), Extra]. diff --git a/erts/etc/common/erlexec.c b/erts/etc/common/erlexec.c index cde0b25a2a..af1c198281 100644 --- a/erts/etc/common/erlexec.c +++ b/erts/etc/common/erlexec.c @@ -73,6 +73,7 @@ static const char plusM_au_allocs[]= { 'R', /* driver_alloc */ 'S', /* sl_alloc */ 'T', /* temp_alloc */ + 'Z', /* test_alloc */ '\0' }; @@ -718,7 +719,7 @@ int main(int argc, char **argv) * on itself here. We'll avoid doing that. */ if (strcmp(argv[i], "-make") == 0) { - add_args("-noshell", "-noinput", "-s", "make", "all", NULL); + add_args("-noshell", "-noinput", "-s", "make", "all_or_nothing", NULL); add_Eargs("-B"); haltAfterwards = 1; i = argc; /* Skip rest of command line */ diff --git a/erts/etc/common/heart.c b/erts/etc/common/heart.c index 01ef840b5d..1a826221fb 100644 --- a/erts/etc/common/heart.c +++ b/erts/etc/common/heart.c @@ -472,10 +472,6 @@ message_loop(erlin_fd, erlout_fd) switch (mp->op) { case HEART_BEAT: timestamp(&last_received); -#ifdef USE_WATCHDOG - /* reset the hardware watchdog timer */ - wd_reset(); -#endif break; case SHUT_DOWN: return R_SHUT_DOWN; @@ -718,14 +714,12 @@ do_terminate(int erlin_fd, int reason) { print_error("Would reboot. Terminating."); else { kill_old_erlang(); - /* suppress gcc warning with 'if' */ ret = system(command); print_error("Executed \"%s\" -> %d. Terminating.",command, ret); } free_env_val(command); } else { kill_old_erlang(); - /* suppress gcc warning with 'if' */ ret = system((char*)&cmd[0]); print_error("Executed \"%s\" -> %d. Terminating.",cmd, ret); } diff --git a/erts/etc/win32/cygwin_tools/vc/cc.sh b/erts/etc/win32/cygwin_tools/vc/cc.sh index 48a579d5f0..651b6e098d 100755 --- a/erts/etc/win32/cygwin_tools/vc/cc.sh +++ b/erts/etc/win32/cygwin_tools/vc/cc.sh @@ -267,7 +267,7 @@ for x in $SOURCES; do echo echo after_sed=`date '+%s'` - echo Made dependencises for $x':' `expr $after_sed '-' $start_time` 's' >&2 + echo Made dependencies for $x':' `expr $after_sed '-' $start_time` 's' >&2 fi else cat $MSG_FILE diff --git a/erts/etc/win32/msys_tools/vc/cc.sh b/erts/etc/win32/msys_tools/vc/cc.sh index ad05e5375b..72005862ed 100644 --- a/erts/etc/win32/msys_tools/vc/cc.sh +++ b/erts/etc/win32/msys_tools/vc/cc.sh @@ -242,7 +242,7 @@ for x in $SOURCES; do if [ $PREPROCESSING = true ]; then output_flag="-E" else - output_flag="-c -Fo`cmd //C echo ${output_filename}`" + output_flag="-FS -c -Fo`cmd //C echo ${output_filename}`" fi params="$COMMON_CFLAGS $MD $DEBUG_FLAGS $OPTIMIZE_FLAGS \ $CMD ${output_flag} $MPATH" @@ -250,6 +250,8 @@ for x in $SOURCES; do echo cc.sh "$SAVE" >>$CC_SH_DEBUG_LOG echo cl.exe $params >>$CC_SH_DEBUG_LOG fi + # MSYS2 (currently) converts the paths wrong, avoid it + export MSYS2_ARG_CONV_EXCL=-FoC eval cl.exe $params >$MSG_FILE 2>$ERR_FILE RES=$? if test $PREPROCESSING = false; then @@ -266,7 +268,7 @@ for x in $SOURCES; do echo echo after_sed=`date '+%s'` - echo Made dependencises for $x':' `expr $after_sed '-' $start_time` 's' >&2 + echo Made dependencies for $x':' `expr $after_sed '-' $start_time` 's' >&2 fi else cat $MSG_FILE @@ -274,6 +276,7 @@ for x in $SOURCES; do fi rm -f $ERR_FILE $MSG_FILE if [ $RES != 0 ]; then + echo Failed: cl.exe $params rm -rf $TMPOBJDIR exit $RES fi @@ -312,7 +315,10 @@ if [ $LINKING = true ]; then stdlib="-lLIBMTD";; esac # And finally call the next script to do the linking... - params="$out_spec $LINKCMD $stdlib" + params="$out_spec $LINKCMD $stdlib" + if [ "X$CC_SH_DEBUG_LOG" != "X" ]; then + echo ld.sh $ACCUM_OBJECTS $params + fi eval ld.sh $ACCUM_OBJECTS $params RES=$? fi diff --git a/erts/etc/win32/msys_tools/vc/emu_cc.sh b/erts/etc/win32/msys_tools/vc/emu_cc.sh index 01f75b2468..10d59214ea 100644 --- a/erts/etc/win32/msys_tools/vc/emu_cc.sh +++ b/erts/etc/win32/msys_tools/vc/emu_cc.sh @@ -29,6 +29,7 @@ WTOOLDIR0=`win2msys_path.sh "$TOOLDIR"` WTOOLDIR=`cmd //C echo $WTOOLDIR0` # Do primitive 'make' newer_exe=`find $TOOLDIR -newer $COFFIX.c -name coffix.exe -print` +export MSYS2_ARG_CONV_EXCL="-FeC" if [ -z $newer_exe ]; then echo recompiling $COFFIX.exe cl.exe -Fe${WTOOLDIR}/coffix.exe ${WTOOLDIR}/coffix.c diff --git a/erts/etc/win32/msys_tools/vc/mc.sh b/erts/etc/win32/msys_tools/vc/mc.sh index e9ea9ff9a9..14b5ebaa8f 100644 --- a/erts/etc/win32/msys_tools/vc/mc.sh +++ b/erts/etc/win32/msys_tools/vc/mc.sh @@ -80,9 +80,14 @@ if [ -n "$OUTPUT_DIRNAME" ]; then exit $RES fi fi +# MSYS2 (currently) converts the paths wrong, avoid it +export MSYS2_ARG_CONV_EXCL= eval $MCC "$CMD" >/tmp/mc.exe.${p}.1 2>/tmp/mc.exe.${p}.2 RES=$? -tail +2 /tmp/mc.exe.${p}.2 >&2 +if [ $RES != 0 ]; then + echo Failed: $MCC "$CMD" +fi +tail -n +2 /tmp/mc.exe.${p}.2 >&2 cat /tmp/mc.exe.${p}.1 rm -f /tmp/mc.exe.${p}.2 /tmp/mc.exe.${p}.1 exit $RES diff --git a/erts/etc/win32/msys_tools/vc/rc.sh b/erts/etc/win32/msys_tools/vc/rc.sh index 1b3b1c85bd..1f8ade17cb 100644 --- a/erts/etc/win32/msys_tools/vc/rc.sh +++ b/erts/etc/win32/msys_tools/vc/rc.sh @@ -79,9 +79,14 @@ if [ "X$RC_SH_DEBUG_LOG" != "X" ]; then echo rc.sh "$SAVE" >>$RC_SH_DEBUG_LOG echo rc.exe $CMD >>$RC_SH_DEBUG_LOG fi +# MSYS2 (currently) converts the paths wrong, avoid it +export MSYS2_ARG_CONV_EXCL=-Fo eval $RCC "$CMD" >/tmp/rc.exe.${p}.1 2>/tmp/rc.exe.${p}.2 RES=$? -tail +2 /tmp/rc.exe.${p}.2 >&2 +if [ $RES != 0 ]; then + echo Failed: $RCC "$CMD" +fi +tail -n +2 /tmp/rc.exe.${p}.2 >&2 cat /tmp/rc.exe.${p}.1 rm -f /tmp/rc.exe.${p}.2 /tmp/rc.exe.${p}.1 exit $RES diff --git a/erts/etc/win32/nsis/Makefile b/erts/etc/win32/nsis/Makefile index 49d835170a..64f44ff86d 100644 --- a/erts/etc/win32/nsis/Makefile +++ b/erts/etc/win32/nsis/Makefile @@ -42,7 +42,13 @@ include $(ERL_TOP)/make/otp_release_targets.mk TARGET_DIR = $(RELEASE_PATH) -ifeq ($(MSYSTEM),MINGW32) +ifdef MSYSTEM + ifeq ($(MSYSTEM),$(filter $(MSYSTEM),MSYS MINGW32 MINGW64)) + USEMSYS := true + endif +endif + +ifeq ($(USEMSYS),true) MAKENSISFLAGS = //V2 WTESTROOT=$(shell (msys2win_path.sh "$(RELEASE_PATH)")) @@ -63,7 +69,7 @@ else endif REDIST_FILE=$(shell (sh ./find_redist.sh || echo "")) -ifeq ($(MSYSTEM),MINGW32) +ifeq ($(USEMSYS),true) NICEREDISTFILE=$(shell (msys2win_path.sh -m "$(REDIST_FILE)" 2>/dev/null || echo "")) else NICEREDISTFILE=$(shell (cygpath -d -m "$(REDIST_FILE)" 2>/dev/null || echo "")) diff --git a/erts/etc/win32/nsis/find_redist.sh b/erts/etc/win32/nsis/find_redist.sh index c0895c9dd5..03e92b21c7 100755 --- a/erts/etc/win32/nsis/find_redist.sh +++ b/erts/etc/win32/nsis/find_redist.sh @@ -164,7 +164,7 @@ fi #echo $BPATH_LIST for BP in $BPATH_LIST; do - for verdir in "sdk v2.0" "sdk v3.5" "v6.0A" "v7.0" "v7.0A" "v7.1"; do + for verdir in "sdk v2.0" "sdk v3.5" "v6.0A" "v7.0" "v7.0A" "v7.1" "VC redist 1033"; do BPATH=$BP fail=false allow_fail=false diff --git a/erts/include/internal/ethread.h b/erts/include/internal/ethread.h index f9c203e97c..8964f95652 100644 --- a/erts/include/internal/ethread.h +++ b/erts/include/internal/ethread.h @@ -54,7 +54,8 @@ #endif #if defined(ETHR_DEBUG) || !defined(ETHR_INLINE) || ETHR_XCHK \ - || (defined(__GNUC__) && defined(ERTS_MIXED_CYGWIN_VC)) + || (defined(__GNUC__) && defined(ERTS_MIXED_CYGWIN_VC)) \ + || (defined(__GNUC__) && defined(ERTS_MIXED_MSYS_VC)) # undef ETHR_INLINE # define ETHR_INLINE # undef ETHR_FORCE_INLINE diff --git a/erts/include/internal/ethread_header_config.h.in b/erts/include/internal/ethread_header_config.h.in index 9cabd0591a..f4b08cfced 100644 --- a/erts/include/internal/ethread_header_config.h.in +++ b/erts/include/internal/ethread_header_config.h.in @@ -166,6 +166,10 @@ /* Define if you use a gcc that supports the double word cmpxchg instruction */ #undef ETHR_GCC_HAVE_DW_CMPXCHG_ASM_SUPPORT +/* Define if gcc wont let you clobber ebx with cmpxchg8b and position + independent code */ +#undef ETHR_CMPXCHG8B_PIC_NO_CLOBBER_EBX + /* Define if you get a register shortage with cmpxchg8b and position independent code */ #undef ETHR_CMPXCHG8B_REGISTER_SHORTAGE diff --git a/erts/include/internal/i386/ethr_dw_atomic.h b/erts/include/internal/i386/ethr_dw_atomic.h index e8c4119ef0..5444a6345c 100644 --- a/erts/include/internal/i386/ethr_dw_atomic.h +++ b/erts/include/internal/i386/ethr_dw_atomic.h @@ -115,13 +115,19 @@ ethr_native_dw_atomic_addr(ethr_native_dw_atomic_t *var) return (ethr_sint_t *) ETHR_DW_NATMC_MEM__(var); } -#if ETHR_SIZEOF_PTR == 4 && defined(__PIC__) && __PIC__ +#if defined(ETHR_CMPXCHG8B_PIC_NO_CLOBBER_EBX) && defined(__PIC__) && __PIC__ +#if ETHR_SIZEOF_PTR != 4 +# error unexpected pic issue +#endif /* * When position independent code is used in 32-bit mode, the EBX register - * is used for storage of global offset table address, and we may not - * use it as input or output in an asm. We need to save and restore the - * EBX register explicitly (for some reason gcc doesn't provide this - * service to us). + * is used for storage of global offset table address. When compiling with + * an old gcc (< vsn 5) we may not use it as input or output in an inline + * asm. We then need to save and restore the EBX register explicitly (for + * some reason old gcc compilers didn't provide this service to us). + * ETHR_CMPXCHG8B_PIC_NO_CLOBBER_EBX will be defined if we need to + * explicitly manage EBX ourselves. + * */ # define ETHR_NO_CLOBBER_EBX__ 1 #else @@ -151,36 +157,53 @@ ethr_native_dw_atomic_cmpxchg_mb(ethr_native_dw_atomic_t *var, ETHR_DW_DBG_ALIGNED__(p); +#if ETHR_NO_CLOBBER_EBX__ && ETHR_CMPXCHG8B_REGISTER_SHORTAGE + /* + * gcc wont let us use ebx as input and we + * get a register shortage + */ + __asm__ __volatile__( -#if ETHR_NO_CLOBBER_EBX__ "pushl %%ebx\n\t" -# if ETHR_CMPXCHG8B_REGISTER_SHORTAGE "movl (%7), %%ebx\n\t" "movl 4(%7), %%ecx\n\t" -# else - "movl %8, %%ebx\n\t" -# endif -#endif - "lock; cmpxchg" ETHR_DW_CMPXCHG_SFX__ " %0\n\t" + "lock; cmpxchg8b %0\n\t" "setz %3\n\t" -#if ETHR_NO_CLOBBER_EBX__ "popl %%ebx\n\t" -#endif : "=m"(*p), "=d"(xchg[1]), "=a"(xchg[0]), "=c"(xchgd) - : "m"(*p), "1"(xchg[1]), "2"(xchg[0]), -#if ETHR_NO_CLOBBER_EBX__ -# if ETHR_CMPXCHG8B_REGISTER_SHORTAGE - "3"(new) -# else - "3"(new[1]), - "r"(new[0]) -# endif + : "m"(*p), "1"(xchg[1]), "2"(xchg[0]), "r"(new) + : "cc", "memory"); + +#elif ETHR_NO_CLOBBER_EBX__ + /* + * gcc wont let us use ebx as input + */ + + __asm__ __volatile__( + "pushl %%ebx\n\t" + "movl %8, %%ebx\n\t" + "lock; cmpxchg8b %0\n\t" + "setz %3\n\t" + "popl %%ebx\n\t" + : "=m"(*p), "=d"(xchg[1]), "=a"(xchg[0]), "=q"(xchgd) + : "m"(*p), "1"(xchg[1]), "2"(xchg[0]), "c"(new[1]), "r"(new[0]) + : "cc", "memory"); + #else - "3"(new[1]), - "b"(new[0]) -#endif + /* + * gcc lets us place values in the registers where + * we want them + */ + + __asm__ __volatile__( + "lock; cmpxchg" ETHR_DW_CMPXCHG_SFX__ " %0\n\t" + "setz %3\n\t" + : "=m"(*p), "=d"(xchg[1]), "=a"(xchg[0]), "=q"(xchgd) + : "m"(*p), "1"(xchg[1]), "2"(xchg[0]), "c"(new[1]), "b"(new[0]) : "cc", "memory"); +#endif + return (int) xchgd; } diff --git a/erts/include/internal/pthread/ethr_event.h b/erts/include/internal/pthread/ethr_event.h index 74cfa68e16..deb4b29686 100644 --- a/erts/include/internal/pthread/ethr_event.h +++ b/erts/include/internal/pthread/ethr_event.h @@ -83,12 +83,22 @@ ETHR_INLINE_FUNC_NAME_(ethr_event_reset)(ethr_event *e) #elif defined(ETHR_PTHREADS) /* --- Posix mutex/cond pipe/select implementation of events ---------------- */ +#if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__) +# define __DARWIN__ 1 +#endif + +#ifdef __DARWIN__ +typedef struct ethr_event_fdsets___ ethr_event_fdsets__; +#endif typedef struct { ethr_atomic32_t state; pthread_mutex_t mtx; pthread_cond_t cnd; int fd[2]; +#ifdef __DARWIN__ + ethr_event_fdsets__ *fdsets; +#endif } ethr_event; #define ETHR_EVENT_OFF_WAITER_SELECT__ ((ethr_sint32_t) -2) @@ -148,6 +158,7 @@ ETHR_INLINE_FUNC_NAME_(ethr_event_reset)(ethr_event *e) #endif int ethr_event_init(ethr_event *e); +int ethr_event_prepare_timed(ethr_event *e); int ethr_event_destroy(ethr_event *e); int ethr_event_wait(ethr_event *e); int ethr_event_swait(ethr_event *e, int spincount); diff --git a/erts/include/internal/win/ethr_event.h b/erts/include/internal/win/ethr_event.h index bf110e10f9..458565b9ea 100644 --- a/erts/include/internal/win/ethr_event.h +++ b/erts/include/internal/win/ethr_event.h @@ -56,6 +56,7 @@ ETHR_INLINE_FUNC_NAME_(ethr_event_reset)(ethr_event *e) #endif int ethr_event_init(ethr_event *e); +int ethr_event_prepare_timed(ethr_event *e); int ethr_event_destroy(ethr_event *e); int ethr_event_wait(ethr_event *e); int ethr_event_swait(ethr_event *e, int spincount); diff --git a/erts/lib_src/pthread/ethr_event.c b/erts/lib_src/pthread/ethr_event.c index ba664236f6..69e7be342c 100644 --- a/erts/lib_src/pthread/ethr_event.c +++ b/erts/lib_src/pthread/ethr_event.c @@ -29,6 +29,13 @@ #include "config.h" #endif +#if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__) +# define __DARWIN__ 1 +#endif +#ifdef __DARWIN__ +# define _DARWIN_UNLIMITED_SELECT +#endif + #include "ethread.h" #undef ETHR_INCLUDE_MONOTONIC_CLOCK__ #define ETHR_INCLUDE_MONOTONIC_CLOCK__ @@ -56,6 +63,12 @@ ethr_event_init(ethr_event *e) } int +ethr_event_prepare_timed(ethr_event *e) +{ + return 0; +} + +int ethr_event_destroy(ethr_event *e) { return 0; @@ -81,6 +94,9 @@ wait__(ethr_event *e, int spincount, ethr_sint64_t timeout) tsp = NULL; } else { +#ifdef ETHR_HAVE_ETHR_GET_MONOTONIC_TIME + start = ethr_get_monotonic_time(); +#endif tsp = &ts; time = timeout; if (spincount == 0) { @@ -89,9 +105,6 @@ wait__(ethr_event *e, int spincount, ethr_sint64_t timeout) goto return_event_on; goto set_timeout; } -#ifdef ETHR_HAVE_ETHR_GET_MONOTONIC_TIME - start = ethr_get_monotonic_time(); -#endif } while (1) { @@ -171,6 +184,17 @@ return_event_on: #include <errno.h> #include <string.h> +#ifdef __DARWIN__ + +struct ethr_event_fdsets___ { + fd_set *rsetp; + fd_set *esetp; + size_t mem_size; + fd_mask mem[1]; +}; + +#endif + static void setup_nonblocking_pipe(ethr_event *e) { @@ -188,6 +212,35 @@ setup_nonblocking_pipe(ethr_event *e) flgs = fcntl(e->fd[1], F_GETFL, 0); fcntl(e->fd[1], F_SETFL, flgs | O_NONBLOCK); + +#ifndef __DARWIN__ + if (e->fd[0] >= FD_SETSIZE) + ETHR_FATAL_ERROR__(ENOTSUP); +#else + { + int nmasks; + ethr_event_fdsets__ *fdsets; + size_t mem_size; + + nmasks = (e->fd[0]+NFDBITS)/NFDBITS; + mem_size = 2*nmasks*sizeof(fd_mask); + if (mem_size < 2*sizeof(fd_set)) { + mem_size = 2*sizeof(fd_set); + nmasks = mem_size/(2*sizeof(fd_mask)); + } + + fdsets = malloc(sizeof(ethr_event_fdsets__) + + mem_size + - sizeof(fd_mask)); + if (!fdsets) + ETHR_FATAL_ERROR__(ENOMEM); + fdsets->rsetp = (fd_set *) (char *) &fdsets->mem[0]; + fdsets->esetp = (fd_set *) (char *) &fdsets->mem[nmasks]; + fdsets->mem_size = mem_size; + e->fdsets = fdsets; + } +#endif + ETHR_MEMBAR(ETHR_StoreStore); } @@ -252,6 +305,19 @@ ethr_event_init(ethr_event *e) e->fd[0] = e->fd[1] = ETHR_EVENT_INVALID_FD__; +#ifdef __DARWIN__ + e->fdsets = NULL; +#endif + + return 0; +} + +int +ethr_event_prepare_timed(ethr_event *e) +{ + if (e->fd[0] == ETHR_EVENT_INVALID_FD__) + setup_nonblocking_pipe(e); + return 0; } @@ -263,13 +329,14 @@ ethr_event_destroy(ethr_event *e) close(e->fd[0]); close(e->fd[1]); } +#ifdef __DARWIN__ + if (e->fdsets) + free(e->fdsets); +#endif res = pthread_mutex_destroy(&e->mtx); if (res != 0) return res; - res = pthread_cond_destroy(&e->cnd); - if (res != 0) - return res; - return 0; + return pthread_cond_destroy(&e->cnd); } static ETHR_INLINE int @@ -403,8 +470,10 @@ wait__(ethr_event *e, int spincount, ethr_sint64_t timeout) int fd; int sres; ssize_t rres; - fd_set rset; - fd_set eset; +#ifndef __DARWIN__ + fd_set rset, eset; +#endif + fd_set *rsetp, *esetp; struct timeval select_timeout; #ifdef ETHR_HAVE_ETHR_GET_MONOTONIC_TIME @@ -457,12 +526,22 @@ wait__(ethr_event *e, int spincount, ethr_sint64_t timeout) ETHR_ASSERT(act == val); } + +#ifdef __DARWIN__ + rsetp = e->fdsets->rsetp; + esetp = e->fdsets->esetp; + memset((void *) &e->fdsets->mem[0], 0, e->fdsets->mem_size); +#else FD_ZERO(&rset); - FD_SET(fd, &rset); FD_ZERO(&eset); - FD_SET(fd, &eset); + rsetp = &rset; + esetp = &eset; +#endif + + FD_SET(fd, rsetp); + FD_SET(fd, esetp); - sres = select(fd + 1, &rset, NULL, &eset, &select_timeout); + sres = select(fd + 1, rsetp, NULL, esetp, &select_timeout); if (sres == 0) res = ETIMEDOUT; else { diff --git a/erts/lib_src/win/ethr_event.c b/erts/lib_src/win/ethr_event.c index c88c8784a2..6951a216c5 100644 --- a/erts/lib_src/win/ethr_event.c +++ b/erts/lib_src/win/ethr_event.c @@ -47,6 +47,12 @@ ethr_event_init(ethr_event *e) } int +ethr_event_prepare_timed(ethr_event *e) +{ + return 0; +} + +int ethr_event_destroy(ethr_event *e) { BOOL res = CloseHandle(e->handle); diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam Binary files differindex df12c6f8e0..f1ae49150b 100644 --- a/erts/preloaded/ebin/erl_prim_loader.beam +++ b/erts/preloaded/ebin/erl_prim_loader.beam diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam Binary files differindex 863a5e61ef..990973c57d 100644 --- a/erts/preloaded/ebin/erlang.beam +++ b/erts/preloaded/ebin/erlang.beam diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam Binary files differindex dc8c711e1a..7461e3bc5b 100644 --- a/erts/preloaded/ebin/erts_internal.beam +++ b/erts/preloaded/ebin/erts_internal.beam diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam Binary files differindex 851513b2e9..0060a2cf42 100644 --- a/erts/preloaded/ebin/init.beam +++ b/erts/preloaded/ebin/init.beam diff --git a/erts/preloaded/ebin/otp_ring0.beam b/erts/preloaded/ebin/otp_ring0.beam Binary files differindex 33c112f4de..b1868d7e10 100644 --- a/erts/preloaded/ebin/otp_ring0.beam +++ b/erts/preloaded/ebin/otp_ring0.beam diff --git a/erts/preloaded/ebin/prim_eval.beam b/erts/preloaded/ebin/prim_eval.beam Binary files differindex ebca6e7eea..dc16909d26 100644 --- a/erts/preloaded/ebin/prim_eval.beam +++ b/erts/preloaded/ebin/prim_eval.beam diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam Binary files differindex e8817d183e..f6e15ba499 100644 --- a/erts/preloaded/ebin/prim_file.beam +++ b/erts/preloaded/ebin/prim_file.beam diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam Binary files differindex 5a188be3ba..673627498e 100644 --- a/erts/preloaded/ebin/prim_inet.beam +++ b/erts/preloaded/ebin/prim_inet.beam diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam Binary files differindex 969239be98..813060c41d 100644 --- a/erts/preloaded/ebin/prim_zip.beam +++ b/erts/preloaded/ebin/prim_zip.beam diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam Binary files differindex 281f668f8c..5ce932aeec 100644 --- a/erts/preloaded/ebin/zlib.beam +++ b/erts/preloaded/ebin/zlib.beam diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 291356c7b1..063b9a1f26 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -185,6 +185,8 @@ 'receive' | 'print' | 'timestamp' | + 'monotonic_timestamp' | + 'strict_monotonic_timestamp' | 'label' | 'serial'. @@ -198,7 +200,10 @@ 'exclusive' | 'runnable_ports' | 'runnable_procs' | - 'scheduler'. + 'scheduler' | + 'timestamp' | + 'monotonic_timestamp' | + 'strict_monotonic_timestamp'. -type system_monitor_option() :: 'busy_port' | @@ -230,6 +235,8 @@ garbage_collection | timestamp | cpu_timestamp | + monotonic_timestamp | + strict_monotonic_timestamp | arity | set_on_spawn | set_on_first_spawn | @@ -258,6 +265,8 @@ running | garbage_collection | timestamp | + monotonic_timestamp | + strict_monotonic_timestamp | arity. -type trace_info_return() :: @@ -1974,6 +1983,7 @@ localtime_to_universaltime(_Localtime, _IsDst) -> %% CHECK! Why the strange very thorough specification of the error %% condition with disallowed arity in erl_bif_types? %% Not documented +%% Shadowed by erl_bif_types: erlang:make_fun/3 -spec erlang:make_fun(Module, Function, Arity) -> function() when Module :: atom(), Function :: atom(), @@ -2177,6 +2187,8 @@ send(_Dest,_Msg,_Options) -> ('receive') -> {'receive', boolean()}; (print) -> {print, boolean()}; (timestamp) -> {timestamp, boolean()}; + (monotonic_timestamp) -> {timestamp, boolean()}; + (strict_monotonic_timestamp) -> {strict_monotonic_timestamp, boolean()}; (label) -> [] | {label, non_neg_integer()}; (serial) -> [] | {serial, {non_neg_integer(), non_neg_integer()}}. seq_trace_info(_What) -> @@ -2204,7 +2216,9 @@ setelement(_Index, _Tuple1, _Value) -> spawn_opt(_Tuple) -> erlang:nif_error(undefined). --spec statistics(context_switches) -> {ContextSwitches,0} when +-spec statistics(active_tasks) -> [ActiveTasks] when + ActiveTasks :: non_neg_integer(); + (context_switches) -> {ContextSwitches,0} when ContextSwitches :: non_neg_integer(); (exact_reductions) -> {Total_Exact_Reductions, Exact_Reductions_Since_Last_Call} when @@ -2221,6 +2235,8 @@ spawn_opt(_Tuple) -> Total_Reductions :: non_neg_integer(), Reductions_Since_Last_Call :: non_neg_integer(); (run_queue) -> non_neg_integer(); + (run_queue_lengths) -> [RunQueueLenght] when + RunQueueLenght :: non_neg_integer(); (runtime) -> {Total_Run_Time, Time_Since_Last_Call} when Total_Run_Time :: non_neg_integer(), Time_Since_Last_Call :: non_neg_integer(); @@ -2228,6 +2244,10 @@ spawn_opt(_Tuple) -> SchedulerId :: pos_integer(), ActiveTime :: non_neg_integer(), TotalTime :: non_neg_integer(); + (total_active_tasks) -> ActiveTasks when + ActiveTasks :: non_neg_integer(); + (total_run_queue_lengths) -> TotalRunQueueLenghts when + TotalRunQueueLenghts :: non_neg_integer(); (wall_clock) -> {Total_Wallclock_Time, Wallclock_Time_Since_Last_Call} when Total_Wallclock_Time :: non_neg_integer(), @@ -2423,7 +2443,7 @@ tuple_to_list(_Tuple) -> MinBinVHeapSize :: pos_integer()}; (modified_timing_level) -> integer() | undefined; (multi_scheduling) -> disabled | blocked | enabled; - (multi_scheduling_blockers) -> [PID :: pid()]; + (multi_scheduling_blockers) -> [Pid :: pid()]; (nif_version) -> string(); (otp_release) -> string(); (os_monotonic_time_source) -> [{atom(),term()}]; diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index 7ed4efea4b..6db77a8482 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -35,6 +35,9 @@ -export([port_command/3, port_connect/2, port_close/1, port_control/3, port_call/3, port_info/1, port_info/2]). +-export([system_check/1, + gather_system_check_result/1]). + -export([request_system_task/3]). -export([check_process_code/2]). @@ -197,6 +200,23 @@ request_system_task(_Pid, _Prio, _Request) -> check_process_code(_Module, _OptionList) -> erlang:nif_error(undefined). +-spec system_check(Type) -> 'ok' when + Type :: 'schedulers'. + +system_check(_Type) -> + erlang:nif_error(undefined). + +gather_system_check_result(Ref) when is_reference(Ref) -> + gather_system_check_result(Ref, erlang:system_info(schedulers)). + +gather_system_check_result(_Ref, 0) -> + ok; +gather_system_check_result(Ref, N) -> + receive + Ref -> + gather_system_check_result(Ref, N - 1) + end. + %% term compare where integer() < float() = true -spec cmp_term(A,B) -> Result when diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index c4e37b76f1..0ad5824ad1 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -167,7 +167,6 @@ stop(Status) -> init ! {stop,{stop,Status}}, ok. boot(BootArgs) -> register(init, self()), process_flag(trap_exit, true), - start_on_load_handler_process(), {Start0,Flags,Args} = parse_boot_args(BootArgs), Start = map(fun prepare_run_args/1, Start0), Flags0 = flags_to_atoms_again(Flags), @@ -225,6 +224,7 @@ code_path_choice() -> end. boot(Start,Flags,Args) -> + start_on_load_handler_process(), BootPid = do_boot(Flags,Start), State = #state{flags = Flags, args = Args, diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl index c87b2645ec..ab5359ebbc 100644 --- a/erts/preloaded/src/prim_file.erl +++ b/erts/preloaded/src/prim_file.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2013. All Rights Reserved. +%% Copyright Ericsson AB 2000-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -1276,6 +1276,7 @@ lseek_position(_) -> %% Translates the response from the driver into %% {ok, Result} or {error, Reason}. +-dialyzer({no_improper_lists, translate_response/2}). translate_response(?FILE_RESP_OK, []) -> ok; translate_response(?FILE_RESP_ERROR, List) when is_list(List) -> diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index 4d04e1dacb..bd74831bb7 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -232,7 +232,7 @@ bindx(S, AddFlag, Addrs) -> %% if timeout is given: %% timeout < 0 -> infinity %% 0 -> immediate connect (mostly works for loopback) -%% > 0 -> wait for timout ms if not connected then +%% > 0 -> wait for timeout ms if not connected then %% return {error, timeout} %% %% ASYNC_CONNECT(insock(), IP, Port, Timeout) -> {ok, S, Ref} | {error, Reason} @@ -273,7 +273,7 @@ async_connect(S, IP, Port, Time) -> %% if timeout is given: %% timeout < 0 -> infinity %% 0 -> immediate accept (poll) -%% > 0 -> wait for timout ms for accept if no accept then +%% > 0 -> wait for timeout ms for accept if no accept then %% return {error, timeout} %% %% ASYNC_ACCEPT(insock(), Timeout) @@ -1147,6 +1147,7 @@ enc_opt(packet_size) -> ?INET_LOPT_PACKET_SIZE; enc_opt(read_packets) -> ?INET_LOPT_READ_PACKETS; enc_opt(netns) -> ?INET_LOPT_NETNS; enc_opt(show_econnreset) -> ?INET_LOPT_TCP_SHOW_ECONNRESET; +enc_opt(line_delimiter) -> ?INET_LOPT_LINE_DELIM; enc_opt(raw) -> ?INET_OPT_RAW; % Names of SCTP opts: enc_opt(sctp_rtoinfo) -> ?SCTP_OPT_RTOINFO; @@ -1205,6 +1206,7 @@ dec_opt(?INET_LOPT_PACKET_SIZE) -> packet_size; dec_opt(?INET_LOPT_READ_PACKETS) -> read_packets; dec_opt(?INET_LOPT_NETNS) -> netns; dec_opt(?INET_LOPT_TCP_SHOW_ECONNRESET) -> show_econnreset; +dec_opt(?INET_LOPT_LINE_DELIM) -> line_delimiter; dec_opt(?INET_OPT_RAW) -> raw; dec_opt(I) when is_integer(I) -> undefined. @@ -1287,6 +1289,7 @@ type_opt_1(packet) -> {httph_bin,?TCP_PB_HTTPH_BIN}, {ssl, ?TCP_PB_SSL_TLS}, % obsolete {ssl_tls, ?TCP_PB_SSL_TLS}]}; +type_opt_1(line_delimiter) -> int; type_opt_1(mode) -> {enum,[{list, ?INET_MODE_LIST}, {binary, ?INET_MODE_BINARY}]}; diff --git a/erts/test/ethread_SUITE_data/ethread_tests.c b/erts/test/ethread_SUITE_data/ethread_tests.c index 12f7f3db7a..b51771c736 100644 --- a/erts/test/ethread_SUITE_data/ethread_tests.c +++ b/erts/test/ethread_SUITE_data/ethread_tests.c @@ -1457,6 +1457,9 @@ do { \ ASSERT(ethr_ ## A ## _read ## B(&A) == 0x33333333); \ } while (0) +ethr_atomic32_t atomic32; +ethr_atomic_t atomic; +ethr_dw_atomic_t dw_atomic; static void atomic_basic_test(void) @@ -1465,8 +1468,6 @@ atomic_basic_test(void) * Verify that each op does what it is expected * to do for at least one input. */ - ethr_atomic32_t atomic32; - ethr_atomic_t atomic; print_line("AT_AINT32_MAX=%d",AT_AINT32_MAX); print_line("AT_AINT32_MIN=%d",AT_AINT32_MIN); @@ -1629,7 +1630,6 @@ atomic_basic_test(void) /* Double word */ { - ethr_dw_atomic_t dw_atomic; ethr_dw_sint_t dw0, dw1; dw0.sint[0] = 4711; dw0.sint[1] = 4712; diff --git a/erts/test/upgrade_SUITE.erl b/erts/test/upgrade_SUITE.erl index 8a91cf5b7e..83cd2359d8 100644 --- a/erts/test/upgrade_SUITE.erl +++ b/erts/test/upgrade_SUITE.erl @@ -40,7 +40,7 @@ %% - typer requires hipe (in the .app file) %% - erl_interface, jinterface support no upgrade -define(appup_exclude, - [dialyzer,hipe,typer,erl_interface,jinterface]). + [dialyzer,hipe,typer,erl_interface,jinterface,ose]). init_per_suite(Config) -> %% Check that a real release is running, not e.g. cerl diff --git a/erts/vsn.mk b/erts/vsn.mk index 1012f5eafd..57c1ea63bc 100644 --- a/erts/vsn.mk +++ b/erts/vsn.mk @@ -18,7 +18,7 @@ # %CopyrightEnd% # -VSN = 7.0 +VSN = 7.3.1.1 # Port number 4365 in 4.2 # Port number 4366 in 4.3 diff --git a/lib/.gitignore b/lib/.gitignore index 58c49adce0..b1da61706d 100644 --- a/lib/.gitignore +++ b/lib/.gitignore @@ -133,10 +133,12 @@ # mnesia +/mnesia/doc/src/Mnesia_App_A.xml /mnesia/doc/src/Mnesia_App_B.xml /mnesia/doc/src/Mnesia_App_C.xml /mnesia/doc/src/Mnesia_App_D.xml /mnesia/doc/src/Mnesia_chap2.xml +/mnesia/doc/src/Mnesia_chap3.xml /mnesia/doc/src/Mnesia_chap4.xml /mnesia/doc/src/Mnesia_chap5.xml /mnesia/doc/src/Mnesia_chap7.xml diff --git a/lib/asn1/doc/src/notes.xml b/lib/asn1/doc/src/notes.xml index 9b2d6bbde5..78d856b0be 100644 --- a/lib/asn1/doc/src/notes.xml +++ b/lib/asn1/doc/src/notes.xml @@ -32,6 +32,50 @@ <p>This document describes the changes made to the asn1 application.</p> +<section><title>Asn1 4.0.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + When compiling to the PER format, the ASN.1 compiler + would crash when attempting to compile an ASN.1 module + with a constrained INTEGER with more than 65536 values + and named values. (Thanks to Ingars for reporting this + bug.)</p> + <p> + Own Id: OTP-13257</p> + </item> + <item> + <p>The ASN.1 compiler will now emit Dialyzer suppressions + for improper lists. Thus, there is no longer any need to + use <c>--Wno_improper_lists</c> when analyzing modules + generated by the ASN.1 compiler.</p> + <p> + Own Id: OTP-13324</p> + </item> + </list> + </section> + +</section> + +<section><title>Asn1 4.0.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Trying to encode an empty named BIT STRING in BER would + fail with a <c>function_clause</c> exception. (Thanks to + Svilen Ivanov for reporting this bug.)</p> + <p> + Own Id: OTP-13149</p> + </item> + </list> + </section> + +</section> + <section><title>Asn1 4.0</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/asn1/src/asn1ct_check.erl b/lib/asn1/src/asn1ct_check.erl index 4d17cfb966..f2c895bfaa 100644 --- a/lib/asn1/src/asn1ct_check.erl +++ b/lib/asn1/src/asn1ct_check.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2013. All Rights Reserved. +%% Copyright Ericsson AB 1997-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -1552,9 +1552,11 @@ match_syntax_objset_1(_, {object,_,_}=Object, ClassDef) -> make_objset(ClassDef, Set) -> #typedef{typespec=#'ObjectSet'{class=ClassDef,set=Set}}. +-spec syntax_match_error(_) -> no_return(). syntax_match_error(S) -> asn1_error(S, syntax_nomatch). +-spec syntax_match_error(_, _) -> no_return(). syntax_match_error(S, What0) -> What = printable_string(What0), asn1_error(S, {syntax_nomatch,What}). @@ -5745,6 +5747,7 @@ return_asn1_error(#state{mname=Where}, Item, Error) -> Pos = asn1ct:get_pos_of_def(Item), {structured_error,{Where,Pos},?MODULE,Error}. +-spec asn1_error(_, _) -> no_return(). asn1_error(S, Error) -> throw({error,return_asn1_error(S, Error)}). diff --git a/lib/asn1/src/asn1ct_gen.erl b/lib/asn1/src/asn1ct_gen.erl index 093bcb5a6c..6d5062a118 100644 --- a/lib/asn1/src/asn1ct_gen.erl +++ b/lib/asn1/src/asn1ct_gen.erl @@ -1289,6 +1289,7 @@ gen_head(Erules,Mod,Hrl) -> emit({"-module('",Mod,"').",nl}), put(currmod,Mod), emit({"-compile(nowarn_unused_vars).",nl}), + emit({"-dialyzer(no_improper_lists).",nl}), case Hrl of 0 -> ok; _ -> emit({"-include(\"",Mod,".hrl\").",nl}) diff --git a/lib/asn1/src/asn1ct_imm.erl b/lib/asn1/src/asn1ct_imm.erl index 527f4f0ba9..e09256cde9 100644 --- a/lib/asn1/src/asn1ct_imm.erl +++ b/lib/asn1/src/asn1ct_imm.erl @@ -1120,38 +1120,41 @@ per_enc_constrained(Val0, Lb, Ub, false) -> per_enc_constrained(Val0, Lb, Ub, true) -> {Prefix,Val} = sub_lb(Val0, Lb), Range = Ub - Lb + 1, + Check = {ult,Val,Range}, if Range < 256 -> NumBits = per_num_bits(Range), - Check = {ult,Val,Range}, Put = [{put_bits,Val,NumBits,[1]}], {Prefix,Check,Put}; Range =:= 256 -> NumBits = 8, - Check = {ult,Val,Range}, Put = [{put_bits,Val,NumBits,[1,align]}], {Prefix,Check,Put}; Range =< 65536 -> - Check = {ult,Val,Range}, Put = [{put_bits,Val,16,[1,align]}], {Prefix,Check,Put}; true -> - {var,VarBase} = Val, - Bin = {var,VarBase++"@bin"}, - BinSize0 = {var,VarBase++"@bin_size0"}, - BinSize = {var,VarBase++"@bin_size"}, - Check = {ult,Val,Range}, RangeOctsLen = byte_size(binary:encode_unsigned(Range - 1)), BitsNeeded = per_num_bits(RangeOctsLen), - Enc = [{call,binary,encode_unsigned,[Val],Bin}, - {call,erlang,byte_size,[Bin],BinSize0}, - {sub,BinSize0,1,BinSize}, - {'cond',[['_', - {put_bits,BinSize,BitsNeeded,[1]}, - {put_bits,Bin,binary,[8,align]}]]}], - {Prefix,Check,Enc} + {Prefix,Check,per_enc_constrained_huge(BitsNeeded, Val)} end. +per_enc_constrained_huge(BitsNeeded, {var,VarBase}=Val) -> + Bin = {var,VarBase++"@bin"}, + BinSize0 = {var,VarBase++"@bin_size0"}, + BinSize = {var,VarBase++"@bin_size"}, + [{call,binary,encode_unsigned,[Val],Bin}, + {call,erlang,byte_size,[Bin],BinSize0}, + {sub,BinSize0,1,BinSize}, + {'cond',[['_', + {put_bits,BinSize,BitsNeeded,[1]}, + {put_bits,Bin,binary,[8,align]}]]}]; +per_enc_constrained_huge(BitsNeeded, Val) when is_integer(Val) -> + Bin = binary:encode_unsigned(Val), + BinSize = erlang:byte_size(Bin), + [{put_bits,BinSize-1,BitsNeeded,[1]}, + {put_bits,Val,8*BinSize,[1,align]}]. + per_enc_unconstrained(Val, Aligned) -> case Aligned of false -> []; diff --git a/lib/asn1/src/asn1rtt_ber.erl b/lib/asn1/src/asn1rtt_ber.erl index 39fa8aaf99..e50b14941c 100644 --- a/lib/asn1/src/asn1rtt_ber.erl +++ b/lib/asn1/src/asn1rtt_ber.erl @@ -739,6 +739,8 @@ encode_named_bit_string([H|_]=Bits, NamedBitList, TagIn) when is_atom(H) -> do_encode_named_bit_string(Bits, NamedBitList, TagIn); encode_named_bit_string([{bit,_}|_]=Bits, NamedBitList, TagIn) -> do_encode_named_bit_string(Bits, NamedBitList, TagIn); +encode_named_bit_string([], _NamedBitList, TagIn) -> + encode_unnamed_bit_string(<<>>, TagIn); encode_named_bit_string(Bits, _NamedBitList, TagIn) when is_bitstring(Bits) -> encode_unnamed_bit_string(Bits, TagIn). @@ -746,6 +748,8 @@ encode_named_bit_string(C, [H|_]=Bits, NamedBitList, TagIn) when is_atom(H) -> do_encode_named_bit_string(C, Bits, NamedBitList, TagIn); encode_named_bit_string(C, [{bit,_}|_]=Bits, NamedBitList, TagIn) -> do_encode_named_bit_string(C, Bits, NamedBitList, TagIn); +encode_named_bit_string(C, [], _NamedBitList, TagIn) -> + encode_unnamed_bit_string(C, <<>>, TagIn); encode_named_bit_string(C, Bits, _NamedBitList, TagIn) when is_bitstring(Bits) -> encode_unnamed_bit_string(C, Bits, TagIn). diff --git a/lib/asn1/test/asn1_SUITE.erl b/lib/asn1/test/asn1_SUITE.erl index ce87fd3180..6dea1787a8 100644 --- a/lib/asn1/test/asn1_SUITE.erl +++ b/lib/asn1/test/asn1_SUITE.erl @@ -628,12 +628,22 @@ ber_other(Config, Rule, Opts) -> der(Config) -> asn1_test_lib:compile_all(ber_modules(), Config, [der]). -module_test(M, Config, Rule, Opts) -> - asn1_test_lib:compile(M, Config, [Rule|Opts]), - case asn1ct:test(list_to_atom(M), [{i, ?config(case_dir, Config)}]) of - ok -> ok; - Error -> - erlang:error({test_failed, M, Opts, Error}) +module_test(M0, Config, Rule, Opts) -> + asn1_test_lib:compile(M0, Config, [Rule|Opts]), + case list_to_atom(M0) of + 'LDAP' -> + %% Because of the recursive definition of 'Filter' in + %% the LDAP module, the construction of a sample + %% value for 'Filter' is not guaranteed to terminate. + ok; + M -> + TestOpts = [{i, ?config(case_dir, Config)}], + case asn1ct:test(M, TestOpts) of + ok -> + ok; + Error -> + erlang:error({test_failed, M, Opts, Error}) + end end. diff --git a/lib/asn1/test/asn1_SUITE_data/Prim.asn1 b/lib/asn1/test/asn1_SUITE_data/Prim.asn1 index b4c011fd39..4fe0901683 100644 --- a/lib/asn1/test/asn1_SUITE_data/Prim.asn1 +++ b/lib/asn1/test/asn1_SUITE_data/Prim.asn1 @@ -60,4 +60,11 @@ BEGIN e BOOLEAN, magic INTEGER } + + Longitude ::= INTEGER { + oneMicrodegreeEast(10), + oneMicrodegreeWest(-10), + unavailable(1800000001) + } (-1799999999..1800000001) + END diff --git a/lib/asn1/test/asn1_test_lib.erl b/lib/asn1/test/asn1_test_lib.erl index 4fee5a64cc..ae2e5641ec 100644 --- a/lib/asn1/test/asn1_test_lib.erl +++ b/lib/asn1/test/asn1_test_lib.erl @@ -58,7 +58,7 @@ dialyze(Files) -> Beams0 = [code:which(module(F)) || F <- Files], Beams = [code:which(asn1rt_nif)|Beams0], case dialyzer:run([{files,Beams}, - {warnings,[no_improper_lists]}, + {warnings,[]}, {get_warnings,true}]) of [] -> ok; diff --git a/lib/asn1/test/testPrim.erl b/lib/asn1/test/testPrim.erl index 8fa9973ea5..dc2e0fa2e7 100644 --- a/lib/asn1/test/testPrim.erl +++ b/lib/asn1/test/testPrim.erl @@ -78,8 +78,37 @@ int(Rules) -> roundtrip('ASeq', {'ASeq',false,250,true,200,true,199,true,77788}), roundtrip('ASeq', {'ASeq',true,0,false,0,true,0,true,68789}), + %%========================================================== + %% Longitude ::= INTEGER { + %% oneMicrodegreeEast(10), + %% oneMicrodegreeWest(-10), + %% unavailable(1800000001) + %% } (-1799999999..1800000001) + %%========================================================== + + Enc10 = encoding(Rules, oneMicrodegreeEast), + Enc10 = roundtrip('Longitude', oneMicrodegreeEast), + Enc10 = roundtrip('Longitude', 10, oneMicrodegreeEast), + + Enc20 = encoding(Rules, oneMicrodegreeWest), + Enc20 = roundtrip('Longitude', oneMicrodegreeWest), + Enc20 = roundtrip('Longitude', -10, oneMicrodegreeWest), + + Enc30 = roundtrip('Longitude', unavailable), + Enc30 = roundtrip('Longitude', 1800000001, unavailable), + ok. +encoding(Rules, Type) -> + asn1_test_lib:hex_to_bin(encoding_1(Rules, Type)). + +encoding_1(ber, oneMicrodegreeEast) -> "02010A"; +encoding_1(per, oneMicrodegreeEast) -> "C06B49D2 09"; +encoding_1(uper, oneMicrodegreeEast) -> "6B49D209"; + +encoding_1(ber, oneMicrodegreeWest) -> "0201F6"; +encoding_1(per, oneMicrodegreeWest) -> "C06B49D1 F5"; +encoding_1(uper, oneMicrodegreeWest) -> "6B49D1F5". enum(Rules) -> diff --git a/lib/asn1/test/testPrimStrings.erl b/lib/asn1/test/testPrimStrings.erl index fa778765b1..46793c6bff 100644 --- a/lib/asn1/test/testPrimStrings.erl +++ b/lib/asn1/test/testPrimStrings.erl @@ -123,6 +123,7 @@ bit_string(Rules, Opts) -> %% Bs2 ::= BIT STRING {su(0), mo(1), tu(2), we(3), th(4), fr(5), sa(6) } (SIZE (7)) %%========================================================== + roundtrip('Bs2', []), roundtrip('Bs2', [mo,tu,fr]), bs_roundtrip('Bs2', <<2#0110010:7>>, [mo,tu,fr]), bs_roundtrip('Bs2', <<2#0110011:7>>, [mo,tu,fr,sa]), @@ -131,6 +132,7 @@ bit_string(Rules, Opts) -> %% Bs3 ::= BIT STRING {su(0), mo(1), tu(2), we(3), th(4), fr(5), sa(6) } (SIZE (1..7)) %%========================================================== + roundtrip('Bs3', []), roundtrip('Bs3', [mo,tu,fr]), bs_roundtrip('Bs3', <<2#0110010:7>>, [mo,tu,fr]), bs_roundtrip('Bs3', <<2#0110010:7>>, [mo,tu,fr]), @@ -139,6 +141,13 @@ bit_string(Rules, Opts) -> bs_roundtrip('Bs3', <<2#11:2>>, [su,mo]), %%========================================================== + %% Bs4 ::= BIT STRING {su(0), mo(1), tu(2), we(3), th(4), fr(5), sa(6) } + %%========================================================== + + roundtrip('Bs4', []), + roundtrip('Bs4', [mo,tu,fr,sa]), + + %%========================================================== %% Bs7 ::= BIT STRING (SIZE (24)) %%========================================================== diff --git a/lib/asn1/vsn.mk b/lib/asn1/vsn.mk index d4c46863a3..ab2c127ca2 100644 --- a/lib/asn1/vsn.mk +++ b/lib/asn1/vsn.mk @@ -1 +1 @@ -ASN1_VSN = 4.0 +ASN1_VSN = 4.0.2 diff --git a/lib/common_test/doc/src/Makefile b/lib/common_test/doc/src/Makefile index cedddd75ac..a0c89b1222 100644 --- a/lib/common_test/doc/src/Makefile +++ b/lib/common_test/doc/src/Makefile @@ -36,26 +36,24 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) # Target Specs # ---------------------------------------------------- -# REMEMBER: links to HTML files for these modules in ref_man.xml -CT_MODULES = \ - ct \ - ct_master \ - ct_cover \ - ct_telnet \ - ct_ftp \ - ct_ssh \ - ct_rpc \ - ct_snmp \ - unix_telnet \ - ct_slave \ - ct_property_test \ - ct_netconfc - CT_XML_FILES = $(CT_MODULES:=.xml) XML_APPLICATION_FILES = ref_man.xml XML_REF1_FILES = ct_run.xml -XML_REF3_FILES = $(CT_XML_FILES) ct_hooks.xml +# REMEMBER: links to HTML files for these modules in ref_man.xml +XML_REF3_FILES = ct.xml \ + ct_master.xml \ + ct_cover.xml \ + ct_telnet.xml \ + ct_ftp.xml \ + ct_ssh.xml \ + ct_rpc.xml \ + ct_snmp.xml \ + unix_telnet.xml \ + ct_slave.xml \ + ct_property_test.xml \ + ct_netconfc.xml \ + ct_hooks.xml XML_REF6_FILES = common_test_app.xml XML_PART_FILES = part.xml @@ -80,8 +78,6 @@ XML_CHAPTER_FILES = \ notes.xml \ notes_history.xml -MAKE_EDOC = make_edoc - BOOK_FILES = book.xml GIF_FILES = \ @@ -92,7 +88,7 @@ GIF_FILES = \ INSTALL_NOTES = ../../notes.html XML_FILES=$(XML_APPLICATION_FILES) $(XML_REF1_FILES) $(XML_REF3_FILES) $(XML_REF6_FILES) \ - $(XML_PART_FILES) $(XML_CHAPTER_FILES) $(XML_REF_FILES) $(BOOK_FILES) + $(XML_PART_FILES) $(XML_CHAPTER_FILES) $(BOOK_FILES) # ---------------------------------------------------- @@ -119,19 +115,11 @@ DVIPS_FLAGS += # Targets # ---------------------------------------------------- -CT_SRC_DIR = $(ERL_TOP)/../internal_tools/common_test/src - $(HTMLDIR)/%.gif: %.gif $(INSTALL_DATA) $< $@ docs: pdf html man -$(CT_XML_FILES): %.xml: ../../src/%.erl - escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -preprocess true -i $(XMERL_DIR)/include \ - -i ../../../test_server/include -i ../../include \ - -i ../../../../erts/lib/kernel/include -i ../../../../lib/kernel/include \ - -i ../../../../erts/lib/snmp/include -i ../../../../lib/snmp/include ../../src/$(@:%.xml=%.erl) - $(TOP_PDF_FILE): $(XML_FILES) pdf: $(TOP_PDF_FILE) @@ -146,7 +134,6 @@ man: $(MAN6_FILES) $(MAN3_FILES) $(MAN1_FILES) debug opt: clean clean_docs: - rm -f $(CT_XML_FILES) rm -rf $(HTMLDIR)/* rm -f $(MAN1DIR)/* rm -f $(MAN3DIR)/* diff --git a/lib/common_test/doc/src/basics_chapter.xml b/lib/common_test/doc/src/basics_chapter.xml index a01e3a9272..1a5a686fa0 100644 --- a/lib/common_test/doc/src/basics_chapter.xml +++ b/lib/common_test/doc/src/basics_chapter.xml @@ -31,74 +31,74 @@ </header> <marker id="basics"></marker> <section> - <title>Introduction</title> + <title>General</title> - <p>The <em>Common Test</em> framework (CT) is a tool which supports - implementation and automated execution of test cases towards arbitrary - types of target systems. The CT framework is based on the OTP Test - Server and it's the main tool being used in all testing- and verification - activities that are part of Erlang/OTP system development- and maintenance. + <p>The <c>Common Test</c> framework is a tool that supports + implementation and automated execution of test cases to any + types of target systems. <c>Common Test</c> is the main tool being used + in all testing- and verification activities that are part of Erlang/OTP + system development and maintenance. </p> - <p>Test cases can be executed individually or in batches. Common Test - also features a distributed testing mode with central control and logging - (a feature that makes it possible to test multiple systems independently in - one common session, useful e.g. for running automated large-scale regression - tests). + <p>Test cases can be executed individually or in batches. <c>Common Test</c> + also features a distributed testing mode with central control and logging. + With this feature, multiple systems can be tested independently in + one common session. This is useful, for example, when running automated + large-scale regression tests. </p> <p> - The SUT (System Under Test) may consist of one or several target - nodes. CT contains a generic test server which, together with - other test utilities, is used to perform test case execution. - It is possible to start the tests from a GUI or from the OS- or + The System Under Test (SUT) can consist of one or more target + nodes. <c>Common Test</c> contains a generic test server that, + together with other test utilities, is used to perform test case execution. + The tests can be started from a GUI, from the OS shell, or from an Erlang shell. <em>Test suites</em> are files (Erlang modules) that contain the <em>test cases</em> (Erlang functions) to be executed. <em>Support modules</em> provide functions - that the test cases utilize in order to carry out the tests. + that the test cases use to do the tests. </p> - <p>In a black-box testing scenario, CT based test programs connect to - the target system(s) via standard O&M and CLI protocols. CT + <p>In a black-box testing scenario, <c>Common Test</c>-based test programs connect to + the target system(s) through standard O&M and CLI protocols. <c>Common Test</c> provides implementations of, and wrapper interfaces to, some of these - protocols (most of which exist as stand-alone components and + protocols (most of which exist as standalone components and applications in OTP). The wrappers simplify configuration and add - verbosity for logging purposes. CT will be continously extended with - useful support modules. (Note however that it's - a straightforward task to use any arbitrary Erlang/OTP component - for testing purposes with Common Test, without needing a CT wrapper - for it. It's as simple as calling Erlang functions). There - are a number of target independent interfaces supported in CT, such as - Generic Telnet, FTP, etc, which can be specialized or used - directly for controlling instruments, traffic load generators, etc. + verbosity for logging purposes. <c>Common Test</c> is continously extended with + useful support modules. However, notice that it is + a straightforward task to use any Erlang/OTP component + for testing purposes with <c>Common Test</c>, without needing a <c>Common Test</c> + wrapper for it. It is as simple as calling Erlang functions. A number of + target-independent interfaces are supported in <c>Common Test</c>, such as + Generic Telnet and FTP. These can be specialized or used + directly for controlling instruments, traffic load generators, and so on. </p> - <p>Common Test is also a very useful tool for white-box testing Erlang - code (e.g. module testing), since the test programs can call exported Erlang - functions directly and there's very little overhead required for + <p><c>Common Test</c> is also a very useful tool for white-box testing Erlang + code (for example, module testing), as the test programs can call exported Erlang + functions directly. there is very little overhead required for implementing basic test suites and executing simple tests. For black-box - testing Erlang software, Erlang RPC as well as standard O&M interfaces - can for example be used. + testing Erlang software, Erlang RPC and standard O&M interfaces + can be used for example. </p> - <p>A test case can handle several connections towards one or - several target systems, instruments and traffic generators in - parallel in order to perform the necessary actions for a - test. The handling of many connections in parallel is one of - the major strengths of Common Test (thanks to the efficient - support for concurrency in the Erlang runtime system - which CT users - can take great advantage of!). + <p>A test case can handle several connections to one or + more target systems, instruments, and traffic generators in + parallel to perform the necessary actions for a test. + The handling of many connections in parallel is one of + the major strengths of <c>Common Test</c>, thanks to the efficient + support for concurrency in the Erlang runtime system, which <c>Common Test</c> + users can take great advantage of. </p> </section> <section> <title>Test Suite Organisation</title> <p> - The test suites are organized in test directories and each test suite - may have a separate data directory. Typically, these files and directories - are version controlled similarly to other forms of source code (possibly by - means of a version control system like GIT or Subversion). However, CT does - not itself put any requirements on (or has any form of awareness of) + Test suites are organized in test directories and each test suite + can have a separate data directory. Typically, these files and directories + are version-controlled similar to other forms of source code (possibly by + a version control system like GIT or Subversion). However, <c>Common Test</c> + does not itself put any requirements on (or has any awareness of) possible file and directory versions. </p> </section> @@ -109,8 +109,8 @@ Support libraries contain functions that are useful for all test suites, or for test suites in a specific functional area or subsystem. In addition to the general support libraries provided by the - CT framework, and the various libraries and applications provided by - Erlang/OTP, there might also be a need for customized (user specific) + <c>Common Test</c> framework, and the various libraries and applications provided by + Erlang/OTP, there can also be a need for customized (user specific) support libraries. </p> </section> @@ -121,118 +121,122 @@ Testing is performed by running test suites (sets of test cases) or individual test cases. A test suite is implemented as an Erlang module named <c><![CDATA[<suite_name>_SUITE.erl]]></c> which contains a number of test cases. - A test case is an Erlang function which tests one or more things. - The test case is the smallest unit that the CT test server deals with. + A test case is an Erlang function that tests one or more things. + The test case is the smallest unit that the <c>Common Test</c> test server deals with. </p> <p> - Subsets of test cases, called test case groups, may also be defined. A test case + Subsets of test cases, called test case groups, can also be defined. A test case group can have execution properties associated with it. Execution properties - specify whether the test cases in the group should be executed in - random order, in parallel, in sequence, and if the execution of the group - should be repeated. Test case groups may also be nested (i.e. a group may, - besides test cases, contain sub-groups). + specify if the test cases in the group are to be executed in + random order, in parallel, or in sequence, and if the execution of the group + is to be repeated. Test case groups can also be nested (that is, a group can, + besides test cases, contain subgroups). </p> <p> - Besides test cases and groups, the test suite may also contain configuration + Besides test cases and groups, the test suite can also contain configuration functions. These functions are meant to be used for setting up (and verifying) - environment and state on the SUT (and/or the CT host node), required for - the tests to execute correctly. Examples of operations: Opening a connection - to the SUT, initializing a database, running an installation script, etc. - Configuration may be performed per suite, per test case group and per - individual test case. + environment and state in the SUT (and/or the <c>Common Test</c> host node), + required for the tests to execute correctly. Examples of operations are: + Opening a connection to the SUT, initializing a database, running an installation + script, and so on. Configuration can be performed per suite, per test case group, + and per individual test case. </p> <p> The test suite module must conform to a <seealso marker="common_test">callback interface</seealso> - specified by the CT test server. See the - <seealso marker="write_test_chapter#intro">Writing Test Suites</seealso> chapter - for more information. + specified by the <c>Common Test</c> test server. For details, see section + <seealso marker="write_test_chapter#intro">Writing Test Suites</seealso>. </p> <p> A test case is considered successful if it returns to the caller, no matter - what the returned value is. A few return values have special meaning however - (such as <c>{skip,Reason}</c> which indicates that the test case is skipped, - <c>{comment,Comment}</c> which prints a comment in the log for the test case and - <c>{save_config,Config}</c> which makes the CT test server pass <c>Config</c> to - the next test case). + what the returned value is. However, a few return values have special meaning + as follows:</p> + <list type="bulleted"> + <item><c>{skip,Reason}</c> indicates that the test case is skipped.</item> + <item><c>{comment,Comment}</c> prints a comment in the log for the test case.</item> + <item><c>{save_config,Config}</c> makes the <c>Common Test</c> test server pass + <c>Config</c> to the next test case.</item> + </list> + <p> A test case failure is specified as a runtime error (a crash), no matter what the reason for termination is. If you use Erlang pattern matching effectively, - you can take advantage of this property. The result will be concise and + you can take advantage of this property. The result is concise and readable test case functions that look much more like scripts than actual programs. - Simple example: + A simple example: </p> <pre> - session(_Config) -> - {started,ServerId} = my_server:start(), - {clients,[]} = my_server:get_clients(ServerId), - MyId = self(), - connected = my_server:connect(ServerId, MyId), - {clients,[MyId]} = my_server:get_clients(ServerId), - disconnected = my_server:disconnect(ServerId, MyId), - {clients,[]} = my_server:get_clients(ServerId), - stopped = my_server:stop(ServerId). - </pre> + session(_Config) -> + {started,ServerId} = my_server:start(), + {clients,[]} = my_server:get_clients(ServerId), + MyId = self(), + connected = my_server:connect(ServerId, MyId), + {clients,[MyId]} = my_server:get_clients(ServerId), + disconnected = my_server:disconnect(ServerId, MyId), + {clients,[]} = my_server:get_clients(ServerId), + stopped = my_server:stop(ServerId).</pre> <p> As a test suite runs, all information (including output to <c>stdout</c>) is - recorded in several different log files. A minimum of information is displayed + recorded in many different log files. A minimum of information is displayed in the user console (only start and stop information, plus a note for each failed test case). </p> <p> The result from each test case is recorded in a dedicated HTML log file, created for the particular test run. An overview page displays each test case represented - by row in a table showing total execution time, whether the case was successful, - failed or skipped, plus an optional user comment. (For a failed test case, the - reason for termination is also printed in the comment field). The overview page + by a table row showing total execution time, if the case was successful, + failed, or skipped, plus an optional user comment. For a failed test case, the + reason for termination is also printed in the comment field. The overview page has a link to each test case log file, providing simple navigation with any standard HTML browser. </p> </section> <section> +<marker id="External_Interfaces"></marker> <title>External Interfaces</title> <p> - The CT test server requires that the test suite defines and exports the + The <c>Common Test</c> test server requires that the test suite defines and exports the following mandatory or optional callback functions: </p> <taglist> - <tag>all()</tag> - <item>Returns a list of all test cases and groups in the suite. (Mandatory)</item> - <tag>suite()</tag> - <item>Info function used to return properties for the suite. (Optional)</item> - <tag>groups()</tag> - <item>For declaring test case groups. (Optional)</item> - <tag>init_per_suite(Config)</tag> - <item>Suite level configuration function, executed before the first - test case. (Optional)</item> - <tag>end_per_suite(Config)</tag> - <item>Suite level configuration function, executed after the last - test case. (Optional)</item> - <tag>group(GroupName)</tag> - <item>Info function used to return properties for a test case group. (Optional)</item> - <tag>init_per_group(GroupName, Config)</tag> - <item>Configuration function for a group, executed before the first - test case. (Optional)</item> - <tag>end_per_group(GroupName, Config)</tag> - <item>Configuration function for a group, executed after the last - test case. (Optional)</item> - <tag>init_per_testcase(TestCase, Config)</tag> - <item>Configuration function for a testcase, executed before each - test case. (Optional)</item> - <tag>end_per_testcase(TestCase, Config)</tag> - <item>Configuration function for a testcase, executed after each - test case. (Optional)</item> + <tag><c>all()</c></tag> + <item><p>Returns a list of all test cases and groups in the suite. (Mandatory)</p></item> + <tag><c>suite()</c></tag> + <item><p>Information function used to return properties for the suite. (Optional)</p></item> + <tag><c>groups()</c></tag> + <item><p>For declaring test case groups. (Optional)</p></item> + <tag><c>init_per_suite(Config)</c></tag> + <item><p>Suite level configuration function, executed before the first + test case. (Optional)</p></item> + <tag><c>end_per_suite(Config)</c></tag> + <item><p>Suite level configuration function, executed after the last + test case. (Optional)</p></item> + <tag><c>group(GroupName)</c></tag> + <item><p>Information function used to return properties for a test case group. (Optional)</p></item> + <tag><c>init_per_group(GroupName, Config)</c></tag> + <item><p>Configuration function for a group, executed before the first + test case. (Optional)</p></item> + <tag><c>end_per_group(GroupName, Config)</c></tag> + <item><p>Configuration function for a group, executed after the last + test case. (Optional)</p></item> + <tag><c>init_per_testcase(TestCase, Config)</c></tag> + <item><p>Configuration function for a testcase, executed before each + test case. (Optional)</p></item> + <tag><c>end_per_testcase(TestCase, Config)</c></tag> + <item><p>Configuration function for a testcase, executed after each + test case. (Optional)</p></item> </taglist> <p> - For each test case the CT test server expects these functions: + For each test case, the <c>Common Test</c> test server expects the + following functions: </p> <taglist> <tag>Testcasename()</tag> - <item>Info function that returns a list of test case properties. (Optional)</item> + <item><p>Information function that returns a list of test case properties. (Optional)</p></item> <tag>Testcasename(Config)</tag> - <item>The actual test case function.</item> + <item><p>The test case function.</p></item> </taglist> </section> </chapter> diff --git a/lib/common_test/doc/src/common_test_app.xml b/lib/common_test/doc/src/common_test_app.xml index cc554eb84e..10c93e2ed1 100644 --- a/lib/common_test/doc/src/common_test_app.xml +++ b/lib/common_test/doc/src/common_test_app.xml @@ -33,89 +33,84 @@ <file>common_test_app.sgml</file> </header> <module>common_test</module> - <modulesummary>A framework for automated testing of arbitrary target nodes</modulesummary> + <modulesummary>A framework for automated testing of any target nodes.</modulesummary> <description> - <p>The <em>Common Test</em> framework is an environment for + <p>The <c>Common Test</c> framework is an environment for implementing and performing automatic and semi-automatic execution of - test cases. + test cases.</p> - Common Test uses the OTP Test Server as engine for test case - execution and logging.</p> - - <p>In brief, Common Test supports:</p> + <p>In brief, <c>Common Test</c> supports:</p> <list> - <item>Automated execution of test suites (sets of test cases).</item> - <item>Logging of the events during execution.</item> - <item>HTML presentation of test suite results.</item> - <item>HTML presentation of test suite code.</item> - <item>Support functions for test suite authors.</item> - <item>Step by step execution of test cases.</item> + <item>Automated execution of test suites (sets of test cases)</item> + <item>Logging of events during execution</item> + <item>HTML presentation of test suite results</item> + <item>HTML presentation of test suite code</item> + <item>Support functions for test suite authors</item> + <item>Step-by-step execution of test cases</item> </list> - - <p>The following sections describe the mandatory and optional test suite - functions Common Test will call during test execution. For more details - see <seealso marker="write_test_chapter">Common Test User's - Guide.</seealso> </p> - + + <p>The following section describes the mandatory and optional test suite + functions that <c>Common Test</c> calls during test execution. + For more details, see section + <seealso marker="write_test_chapter">Writing Test Suites</seealso> + in the User's Guide.</p> + </description> <section> - <title>TEST CASE CALLBACK FUNCTIONS</title> + <title>Test Case Callback Functions</title> <p>The following functions define the callback interface for a test suite.</p> </section> - + <funcs> <func> <name>Module:all() -> Tests | {skip,Reason} </name> <fsummary>Returns the list of all test case groups and test cases in the module.</fsummary> <type> - <v>Tests = [TestCase | {group,GroupName} | - {group,GroupName,Properties} | - {group,GroupName,Properties,SubGroups}]</v> + <v>Tests = [TestCase | {group,GroupName} | {group,GroupName,Properties} | {group,GroupName,Properties,SubGroups}]</v> <v>TestCase = atom()</v> <v>GroupName = atom()</v> - <v>Properties = [parallel | sequence | Shuffle | {RepeatType,N}] | - default</v> - <v>SubGroups = [{GroupName,Properties} | - {GroupName,Properties,SubGroups}]</v> + <v>Properties = [parallel | sequence | Shuffle | {RepeatType,N}] | default</v> + <v>SubGroups = [{GroupName,Properties} | {GroupName,Properties,SubGroups}]</v> <v>Shuffle = shuffle | {shuffle,Seed}</v> <v>Seed = {integer(),integer(),integer()}</v> - <v>RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | - repeat_until_any_ok | repeat_until_any_fail</v> + <v>RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | repeat_until_any_ok | repeat_until_any_fail</v> <v>N = integer() | forever</v> <v>Reason = term()</v> </type> - + <desc> - <p> MANDATORY </p> - - <p>This function must return the list of all test cases and test - case groups in the test suite module that are to be executed. - This list also specifies the order the cases and groups will - be executed by Common Test. A test case is represented by an atom, + <p>MANDATORY</p> + + <p>Returns the list of all test cases and test case groups in the + test suite module to be executed. This list also specifies the + order the cases and groups are executed by <c>Common Test</c>. + A test case is represented by an atom, the name of the test case function. A test case group is represented by a <c>group</c> tuple, where <c>GroupName</c>, - an atom, is the name of the group (defined in <seealso marker="#Module:groups-0"><c>groups/0</c></seealso>). - Execution properties for groups may also be specified, both - for a top level group and for any of its sub-groups. - Group execution properties specified here, will override - properties in the group definition (see <seealso marker="#Module:groups-0"><c>groups/0</c></seealso>). + an atom, is the name of the group (defined in + <seealso marker="#Module:groups-0"><c>groups/0</c></seealso>). + Execution properties for groups can also be specified, both + for a top-level group and for any of its subgroups. + Group execution properties specified here override + properties in the group definition (see + <seealso marker="#Module:groups-0"><c>groups/0</c></seealso>). (With value <c>default</c>, the group definition properties - will be used).</p> - - <p> If <c>{skip,Reason}</c> is returned, all test cases - in the module will be skipped, and the <c>Reason</c> will - be printed on the HTML result page.</p> - - <p>For details on groups, see - <seealso marker="write_test_chapter#test_case_groups">Test case - groups</seealso> in the User's Guide.</p> - + are used).</p> + + <p>If <c>{skip,Reason}</c> is returned, all test cases + in the module are skipped and <c>Reason</c> + is printed on the HTML result page.</p> + + <p>For details on groups, see section + <seealso marker="write_test_chapter#test_case_groups">Test Case + Groups</seealso> in the User's Guide.</p> + </desc> </func> @@ -123,25 +118,24 @@ <name>Module:groups() -> GroupDefs</name> <fsummary>Returns a list of test case group definitions.</fsummary> <type> - <v>GroupDefs = [Group]</v> - <v>Group = {GroupName,Properties,GroupsAndTestCases}</v> - <v>GroupName = atom()</v> - <v>Properties = [parallel | sequence | Shuffle | {RepeatType,N}]</v> - <v>GroupsAndTestCases = [Group | {group,GroupName} | TestCase]</v> - <v>TestCase = atom()</v> - <v>Shuffle = shuffle | {shuffle,Seed}</v> - <v>Seed = {integer(),integer(),integer()}</v> - <v>RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | - repeat_until_any_ok | repeat_until_any_fail</v> - <v>N = integer() | forever</v> + <v>GroupDefs = [Group]</v> + <v>Group = {GroupName,Properties,GroupsAndTestCases}</v> + <v>GroupName = atom()</v> + <v>Properties = [parallel | sequence | Shuffle | {RepeatType,N}]</v> + <v>GroupsAndTestCases = [Group | {group,GroupName} | TestCase]</v> + <v>TestCase = atom()</v> + <v>Shuffle = shuffle | {shuffle,Seed}</v> + <v>Seed = {integer(),integer(),integer()}</v> + <v>RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | repeat_until_any_ok | repeat_until_any_fail</v> + <v>N = integer() | forever</v> </type> - + <desc> - <p> OPTIONAL </p> - - <p>Function for defining test case groups. Please see - <seealso marker="write_test_chapter#test_case_groups">Test case - groups</seealso> in the User's Guide for details.</p> + <p>OPTIONAL</p> + + <p>Defines test case groups. For details, see section + <seealso marker="write_test_chapter#test_case_groups">Test Case + Groups</seealso> in the User's Guide.</p> </desc> </func> @@ -150,75 +144,71 @@ <fsummary>Test suite info function (providing default data for the suite).</fsummary> <type> - <v> Info = {timetrap,Time} | {require,Required} | - {require,Name,Required} | {userdata,UserData} | - {silent_connections,Conns} | {stylesheet,CSSFile} | - {ct_hooks, CTHs}</v> - <v> Time = TimeVal | TimeFunc</v> - <v> TimeVal = MilliSec | {seconds,integer()} | {minutes,integer()} | - {hours,integer()}</v> - <v> TimeFunc = {Mod,Func,Args} | Fun</v> - <v> MilliSec = integer()</v> - <v> Mod = atom()</v> - <v> Func = atom()</v> - <v> Args = list()</v> - <v> Fun = fun()</v> - <v> Required = Key | {Key,SubKeys} | {Key,SubKey} | {Key,SubKey,SubKeys}</v> - <v> Key = atom()</v> - <v> SubKeys = SubKey | [SubKey]</v> - <v> SubKey = atom()</v> - <v> Name = atom()</v> - <v> UserData = term()</v> - <v> Conns = [atom()]</v> - <v> CSSFile = string()</v> - <v> CTHs = [CTHModule |</v> - <v> {CTHModule, CTHInitArgs} |</v> - <v> {CTHModule, CTHInitArgs, CTHPriority}]</v> - <v> CTHModule = atom()</v> - <v> CTHInitArgs = term()</v> + <v>Info = {timetrap,Time} | {require,Required} | {require,Name,Required} | {userdata,UserData} | {silent_connections,Conns} | {stylesheet,CSSFile} | {ct_hooks, CTHs}</v> + <v>Time = TimeVal | TimeFunc</v> + <v>TimeVal = MilliSec | {seconds,integer()} | {minutes,integer()} | {hours,integer()}</v> + <v>TimeFunc = {Mod,Func,Args} | Fun</v> + <v>MilliSec = integer()</v> + <v>Mod = atom()</v> + <v>Func = atom()</v> + <v>Args = list()</v> + <v>Fun = fun()</v> + <v>Required = Key | {Key,SubKeys} | {Key,SubKey} | {Key,SubKey,SubKeys}</v> + <v>Key = atom()</v> + <v>SubKeys = SubKey | [SubKey]</v> + <v>SubKey = atom()</v> + <v>Name = atom()</v> + <v>UserData = term()</v> + <v>Conns = [atom()]</v> + <v>CSSFile = string()</v> + <v>CTHs = [CTHModule |</v> + <v> {CTHModule, CTHInitArgs} |</v> + <v> {CTHModule, CTHInitArgs, CTHPriority}]</v> + <v>CTHModule = atom()</v> + <v>CTHInitArgs = term()</v> </type> <desc> - - <p> OPTIONAL </p> - - <p>This is the test suite info function. It is supposed to - return a list of tagged tuples that specify various properties - related to the execution of this test suite (common for all - test cases in the suite).</p> - - <p>The <c>timetrap</c> tag sets the maximum time each - test case is allowed to execute (including <seealso marker="#Module:init_per_testcase-2"><c>init_per_testcase/2</c></seealso> - and <seealso marker="#Module:end_per_testcase-2"><c>end_per_testcase/2</c></seealso>). If the timetrap time is - exceeded, the test case fails with reason + + <p>OPTIONAL</p> + + <p>The test suite information function. Returns a list of tagged + tuples specifying various properties related to the execution of + this test suite (common for all test cases in the suite).</p> + + <p>Tag <c>timetrap</c> sets the maximum time that each + test case is allowed to execute (including + <seealso marker="#Module:init_per_testcase-2"><c>init_per_testcase/2</c></seealso> + and + <seealso marker="#Module:end_per_testcase-2"><c>end_per_testcase/2</c></seealso>). + If the timetrap time is exceeded, the test case fails with reason <c>timetrap_timeout</c>. A <c>TimeFunc</c> function can be used to - set a new timetrap by returning a <c>TimeVal</c>. It may also be - used to trigger a timetrap timeout by, at some point, returning a - value other than a <c>TimeVal</c>. (See the - <seealso marker="write_test_chapter#timetraps">User's Guide</seealso> - for details). - </p> - - <p>The <c>require</c> tag specifies configuration variables - that are required by test cases (and/or configuration functions) + set a new timetrap by returning a <c>TimeVal</c>. It can also be + used to trigger a timetrap time-out by, at some point, returning a + value other than a <c>TimeVal</c>. For details, see section + <seealso marker="write_test_chapter#timetraps">Timetrap Time-Outs</seealso> + in the User's Guide.</p> + + <p>Tag <c>require</c> specifies configuration variables + required by test cases (or configuration functions) in the suite. If the required configuration variables are not found - in any of the configuration files, all test cases are skipped. For more - information about the 'require' functionality, see the - reference manual for the function - <seealso marker="ct#require-1"><c>ct:require/1/2</c></seealso>.</p> + in any of the configuration files, all test cases are skipped. + For details about the <c>require</c> functionality, see funtion + <seealso marker="ct#require-1"><c>ct:require/1,2</c></seealso>.</p> - <p>With <c>userdata</c>, it is possible for the user to - specify arbitrary test suite related information which can be - read by calling <seealso marker="ct#userdata-2"><c>ct:userdata/2</c></seealso>.</p> + <p>With <c>userdata</c>, the user can + specify any test suite-related information, which can be + read by calling + <seealso marker="ct#userdata-2"><c>ct:userdata/2</c></seealso>.</p> - <p>The <c>ct_hooks</c> tag specifies which + <p>Tag <c>ct_hooks</c> specifies the <seealso marker="ct_hooks_chapter">Common Test Hooks</seealso> - are to be run together with this suite.</p> - - <p>Other tuples than the ones defined will simply be ignored.</p> + to be run with this suite.</p> - <p>For more information about the test suite info function, - see <seealso marker="write_test_chapter#suite">Test - suite info function</seealso> in the User's Guide.</p> + <p>Other tuples than the ones defined are ignored.</p> + + <p>For details about the test suite information function, see section + <seealso marker="write_test_chapter#suite">Test + Suite Information Function</seealso> in the User's Guide.</p> </desc> </func> @@ -227,129 +217,133 @@ {skip_and_save,Reason,SaveConfig}</name> <fsummary>Test suite initializations.</fsummary> <type> - <v> Config = NewConfig = SaveConfig = [{Key,Value}]</v> - <v> Key = atom()</v> - <v> Value = term()</v> - <v> Reason = term()</v> + <v>Config = NewConfig = SaveConfig = [{Key,Value}]</v> + <v>Key = atom()</v> + <v>Value = term()</v> + <v>Reason = term()</v> </type> <desc> - - <p> OPTIONAL </p> - + + <p>OPTIONAL</p> + <p>This configuration function is called as the first function in the - suite. It typically contains initializations which are common for - all test cases in the suite, and which shall only be done - once. The <c>Config</c> parameter is the configuration data - which can be modified here. Whatever is returned from this - function is given as <c>Config</c> to all configuration functions - and test cases in the suite. If <c>{skip,Reason}</c> - is returned, all test cases in the suite will be skipped - and <c>Reason</c> printed in the overview log for the suite.</p> - <p>For information on <c>save_config</c> and <c>skip_and_save</c>, - please see - <seealso marker="dependencies_chapter#save_config">Dependencies - between Test Cases and Suites</seealso> in the User's Guide.</p> - </desc> + suite. It typically contains initializations that are common for + all test cases in the suite, and that must only be done + once. Parameter <c>Config</c> is the configuration data + that can be modified. Whatever is returned from this + function is specified as <c>Config</c> to all configuration functions + and test cases in the suite.</p> + + <p>If <c>{skip,Reason}</c> + is returned, all test cases in the suite are skipped + and <c>Reason</c> is printed in the overview log for the suite.</p> + + <p>For information on <c>save_config</c> and <c>skip_and_save</c>, + see section + <seealso marker="dependencies_chapter#save_config">Saving + Configuration Data</seealso> in the User's Guide.</p> + </desc> </func> - + <func> <name>Module:end_per_suite(Config) -> term() | {save_config,SaveConfig}</name> - <fsummary>Test suite finalization. </fsummary> + <fsummary>Test suite finalization.</fsummary> <type> - <v> Config = SaveConfig = [{Key,Value}]</v> - <v> Key = atom()</v> - <v> Value = term()</v> + <v>Config = SaveConfig = [{Key,Value}]</v> + <v>Key = atom()</v> + <v>Value = term()</v> </type> - + <desc> - <p> OPTIONAL </p> + <p>OPTIONAL</p> <p>This function is called as the last test case in the suite. It is meant to be used for cleaning up after - <seealso marker="#Module:init_per_suite-1"><c>init_per_suite/1</c></seealso>. - For information on <c>save_config</c>, please see - <seealso marker="dependencies_chapter#save_config">Dependencies - between Test Cases and Suites</seealso> in the User's Guide.</p> + <seealso marker="#Module:init_per_suite-1"><c>init_per_suite/1</c></seealso>.</p> + <p>For information on <c>save_config</c>, see section + <seealso marker="dependencies_chapter#save_config">Saving + Configuration Data</seealso> in the User's Guide.</p> </desc> </func> <func> <name>Module:group(GroupName) -> [Info] </name> - <fsummary>Test case group info function (providing default data - for a test case group, i.e. its test cases and sub-groups).</fsummary> + <fsummary>Test case group information function (providing default data + for a test case group, that is, its test cases and + subgroups).</fsummary> <type> - <v> Info = {timetrap,Time} | {require,Required} | - {require,Name,Required} | {userdata,UserData} | - {silent_connections,Conns} | {stylesheet,CSSFile} | - {ct_hooks, CTHs}</v> - <v> Time = TimeVal | TimeFunc</v> - <v> TimeVal = MilliSec | {seconds,integer()} | {minutes,integer()} | - {hours,integer()}</v> - <v> TimeFunc = {Mod,Func,Args} | Fun</v> - <v> MilliSec = integer()</v> - <v> Mod = atom()</v> - <v> Func = atom()</v> - <v> Args = list()</v> - <v> Fun = fun()</v> - <v> Required = Key | {Key,SubKeys} | {Key,Subkey} | {Key,Subkey,SubKeys}</v> - <v> Key = atom()</v> - <v> SubKeys = SubKey | [SubKey]</v> - <v> SubKey = atom()</v> - <v> Name = atom()</v> - <v> UserData = term()</v> - <v> Conns = [atom()]</v> - <v> CSSFile = string()</v> - <v> CTHs = [CTHModule |</v> - <v> {CTHModule, CTHInitArgs} |</v> - <v> {CTHModule, CTHInitArgs, CTHPriority}]</v> - <v> CTHModule = atom()</v> - <v> CTHInitArgs = term()</v> - </type> - <desc> - - <p> OPTIONAL </p> - - <p>This is the test case group info function. It is supposed to + <v>Info = {timetrap,Time} | {require,Required} | {require,Name,Required} | {userdata,UserData} | {silent_connections,Conns} | {stylesheet,CSSFile} | {ct_hooks, CTHs}</v> + <v>Time = TimeVal | TimeFunc</v> + <v>TimeVal = MilliSec | {seconds,integer()} | {minutes,integer()} | {hours,integer()}</v> + <v>TimeFunc = {Mod,Func,Args} | Fun</v> + <v>MilliSec = integer()</v> + <v>Mod = atom()</v> + <v>Func = atom()</v> + <v>Args = list()</v> + <v>Fun = fun()</v> + <v>Required = Key | {Key,SubKeys} | {Key,Subkey} | {Key,Subkey,SubKeys}</v> + <v>Key = atom()</v> + <v>SubKeys = SubKey | [SubKey]</v> + <v>SubKey = atom()</v> + <v>Name = atom()</v> + <v>UserData = term()</v> + <v>Conns = [atom()]</v> + <v>CSSFile = string()</v> + <v>CTHs = [CTHModule |</v> + <v> {CTHModule, CTHInitArgs} |</v> + <v> {CTHModule, CTHInitArgs, CTHPriority}]</v> + <v>CTHModule = atom()</v> + <v>CTHInitArgs = term()</v> + </type> + <desc> + + <p>OPTIONAL</p> + + <p>The test case group information function. It is supposed to return a list of tagged tuples that specify various properties - related to the execution of a test case group (i.e. its test cases - and sub-groups). Properties set by + related to the execution of a test case group (that is, its test + cases and subgroups). Properties set by <seealso marker="#Module:group-1"><c>group/1</c></seealso> override - properties with the same key that have been previously set by + properties with the same key that have been set previously by <seealso marker="#Module:suite-0"><c>suite/0</c></seealso>.</p> - <p>The <c>timetrap</c> tag sets the maximum time each - test case is allowed to execute (including <seealso marker="#Module:init_per_testcase-2"><c>init_per_testcase/2</c></seealso> - and <seealso marker="#Module:end_per_testcase-2"><c>end_per_testcase/2</c></seealso>). If the timetrap time is + <p>Tag <c>timetrap</c> sets the maximum time that each + test case is allowed to execute (including + <seealso marker="#Module:init_per_testcase-2"><c>init_per_testcase/2</c></seealso> + and + <seealso marker="#Module:end_per_testcase-2"><c>end_per_testcase/2</c></seealso>). + If the timetrap time is exceeded, the test case fails with reason <c>timetrap_timeout</c>. A <c>TimeFunc</c> function can be used to - set a new timetrap by returning a <c>TimeVal</c>. It may also be - used to trigger a timetrap timeout by, at some point, returning a - value other than a <c>TimeVal</c>. (See the - <seealso marker="write_test_chapter#timetraps">User's Guide</seealso> - for details).</p> + set a new timetrap by returning a <c>TimeVal</c>. It can also be + used to trigger a timetrap time-out by, at some point, returning a + value other than a <c>TimeVal</c>. For details, see section + <seealso marker="write_test_chapter#timetraps">Timetrap + Time-Outs</seealso> in the User's Guide.</p> - <p>The <c>require</c> tag specifies configuration variables - that are required by test cases (and/or configuration functions) + <p>Tag <c>require</c> specifies configuration variables + required by test cases (or configuration functions) in the suite. If the required configuration variables are not found - in any of the configuration files, all test cases in this group are skipped. - For more information about the 'require' functionality, see the - reference manual for the function - <seealso marker="ct#require-1"><c>ct:require/1/2</c></seealso>.</p> + in any of the configuration files, all test cases in this group are + skipped. For details about the <c>require</c> functionality, see + function + <seealso marker="ct#require-1"><c>ct:require/1,2</c></seealso>.</p> - <p>With <c>userdata</c>, it is possible for the user to - specify arbitrary test case group related information which can be - read by calling <seealso marker="ct#userdata-2"><c>ct:userdata/2</c></seealso>.</p> + <p>With <c>userdata</c>, the user can + specify any test case group related information that can be + read by calling + <seealso marker="ct#userdata-2"><c>ct:userdata/2</c></seealso>.</p> - <p>The <c>ct_hooks</c> tag specifies which + <p>Tag <c>ct_hooks</c> specifies the <seealso marker="ct_hooks_chapter">Common Test Hooks</seealso> - are to be run together with this suite.</p> - - <p>Other tuples than the ones defined will simply be ignored.</p> + to be run with this suite.</p> - <p>For more information about the test case group info function, - see <seealso marker="write_test_chapter#suite">Test - case group info function</seealso> in the User's Guide.</p> + <p>Other tuples than the ones defined are ignored.</p> + + <p>For details about the test case group information function, + see section <seealso marker="write_test_chapter#group_info">Group + Information Function</seealso> in the User's Guide.</p> </desc> </func> @@ -358,59 +352,66 @@ {skip,Reason}</name> <fsummary>Test case group initializations.</fsummary> <type> - <v> GroupName = atom()</v> - <v> Config = NewConfig = [{Key,Value}]</v> - <v> Key = atom()</v> - <v> Value = term()</v> - <v> Reason = term()</v> + <v>GroupName = atom()</v> + <v>Config = NewConfig = [{Key,Value}]</v> + <v>Key = atom()</v> + <v>Value = term()</v> + <v>Reason = term()</v> </type> <desc> - - <p> OPTIONAL </p> - + + <p>OPTIONAL</p> + <p>This configuration function is called before execution of a - test case group. It typically contains initializations which are - common for all test cases and sub-groups in the group, and which - shall only be performed once. <c>GroupName</c> is the name of the - group, as specified in the group definition (see <seealso marker="#Module:groups-0"><c>groups/0</c></seealso>). The - <c>Config</c> parameter is the configuration data which can be modified - here. The return value of this function is given as <c>Config</c> - to all test cases and sub-groups in the group. If <c>{skip,Reason}</c> - is returned, all test cases in the group will be skipped and - <c>Reason</c> printed in the overview log for the group.</p> - - <p>For information about test case groups, please see - <seealso marker="write_test_chapter#test_case_groups">Test case - groups</seealso> chapter in the User's Guide.</p> + test case group. It typically contains initializations that are + common for all test cases and subgroups in the group, and that + must only be performed once. <c>GroupName</c> is the name of the + group, as specified in the group definition (see + <seealso marker="#Module:groups-0"><c>groups/0</c></seealso>). + Parameter <c>Config</c> is the configuration data that can be + modified. + The return value of this function is given as <c>Config</c> + to all test cases and subgroups in the group.</p> + + <p>If <c>{skip,Reason}</c> + is returned, all test cases in the group are skipped and + <c>Reason</c> is printed in the overview log for the group.</p> + + <p>For information about test case groups, see section + <seealso marker="write_test_chapter#test_case_groups">Test Case + Groups</seealso> in the User's Guide.</p> </desc> </func> - + <func> <name>Module:end_per_group(GroupName, Config) -> term() | {return_group_result,Status}</name> <fsummary>Test case group finalization.</fsummary> <type> - <v> GroupName = atom()</v> - <v> Config = [{Key,Value}]</v> - <v> Key = atom()</v> - <v> Value = term()</v> - <v> Status = ok | skipped | failed</v> + <v>GroupName = atom()</v> + <v>Config = [{Key,Value}]</v> + <v>Key = atom()</v> + <v>Value = term()</v> + <v>Status = ok | skipped | failed</v> </type> - + <desc> - <p> OPTIONAL </p> - - <p>This function is called after the execution of a test case group is finished. - It is meant to be used for cleaning up after <seealso marker="#Module:init_per_group-2"><c>init_per_group/2</c></seealso>. - By means of <c>{return_group_result,Status}</c>, it is possible to return a - status value for a nested sub-group. The status can be retrieved in - <seealso marker="#Module:end_per_group-2"><c>end_per_group/2</c></seealso> for the group on the level above. The status will also - be used by Common Test for deciding if execution of a group should proceed in - case the property <c>sequence</c> or <c>repeat_until_*</c> is set.</p> - - <p>For more information about test case groups, please see - <seealso marker="write_test_chapter#test_case_groups">Test case - groups</seealso> chapter in the User's Guide.</p> + <p>OPTIONAL</p> + + <p>This function is called after the execution of a test case group + is finished. It is meant to be used for cleaning up after + <seealso marker="#Module:init_per_group-2"><c>init_per_group/2</c></seealso>. + A status value for a nested subgroup can be returned with + <c>{return_group_result,Status}</c>. The status can be retrieved in + <seealso marker="#Module:end_per_group-2"><c>end_per_group/2</c></seealso> + for the group on the level above. The status is also used by + <c>Common Test</c> for deciding if execution of a group is to + proceed if property <c>sequence</c> or <c>repeat_until_*</c> + is set.</p> + + <p>For details about test case groups, see section + <seealso marker="write_test_chapter#test_case_groups">Test Case + Groups</seealso> in the User's Guide.</p> </desc> </func> @@ -424,168 +425,173 @@ <v> Value = term()</v> <v> Reason = term()</v> </type> - <desc> - + <desc> + <p>OPTIONAL</p> - - <p>This function is called before each test case. The - <c>TestCase</c> argument is the name of the test case, and + + <p>This function is called before each test case. Argument + <c>TestCase</c> is the test case name, and <c>Config</c> (list of key-value tuples) is the configuration - data that can be modified here. The <c>NewConfig</c> list returned + data that can be modified. The <c>NewConfig</c> list returned from this function is given as <c>Config</c> to the test case. If <c>{fail,Reason}</c> is returned, the test case is - marked as failed without being executed. If <c>{skip,Reason}</c> is - returned, the test case will be skipped and <c>Reason</c> printed - in the overview log for the suite.</p> + marked as failed without being executed.</p> + + <p>If <c>{skip,Reason}</c> is returned, the test case is skipped + and <c>Reason</c> is printed in the overview log for the suite.</p> </desc> </func> - + <func> <name>Module:end_per_testcase(TestCase, Config) -> term() | {fail,Reason} | {save_config,SaveConfig}</name> <fsummary>Test case finalization.</fsummary> <type> - <v> TestCase = atom()</v> - <v> Config = SaveConfig = [{Key,Value}]</v> - <v> Key = atom()</v> - <v> Value = term()</v> - <v> Reason = term()</v> + <v>TestCase = atom()</v> + <v>Config = SaveConfig = [{Key,Value}]</v> + <v>Key = atom()</v> + <v>Value = term()</v> + <v>Reason = term()</v> </type> <desc> - - <p> OPTIONAL </p> - - <p> This function is called after each test case, and can be used - to clean up after <seealso marker="#Module:init_per_testcase-2"><c>init_per_testcase/2</c></seealso> and the test case. - Any return value (besides <c>{fail,Reason}</c> and <c>{save_config,SaveConfig}</c>) - is ignored. By returning <c>{fail,Reason}</c>, <c>TestCase</c> will be marked as - failed (even though it was actually successful in the sense that it returned - a value instead of terminating). For information on <c>save_config</c>, please see - <seealso marker="dependencies_chapter#save_config">Dependencies between - Test Cases and Suites</seealso> in the User's Guide</p> + + <p>OPTIONAL</p> + + <p>This function is called after each test case, and can be used + to clean up after + <seealso marker="#Module:init_per_testcase-2"><c>init_per_testcase/2</c></seealso> + and the test case. Any return value (besides <c>{fail,Reason}</c> + and <c>{save_config,SaveConfig}</c>) is ignored. By returning + <c>{fail,Reason}</c>, <c>TestCase</c> is marked as faulty (even + though it was successful in the sense that it returned + a value instead of terminating).</p> + + <p>For information on <c>save_config</c>, see section + <seealso marker="dependencies_chapter#save_config">Saving + Configuration Data</seealso> in the User's Guide.</p> </desc> </func> - + <func> <name>Module:Testcase() -> [Info] </name> - <fsummary>Test case info function. </fsummary> + <fsummary>Test case information function.</fsummary> <type> - <v> Info = {timetrap,Time} | {require,Required} | - {require,Name,Required} | {userdata,UserData} | - {silent_connections,Conns}</v> - <v> Time = TimeVal | TimeFunc</v> - <v> TimeVal = MilliSec | {seconds,integer()} | {minutes,integer()} | - {hours,integer()}</v> - <v> TimeFunc = {Mod,Func,Args} | Fun</v> - <v> MilliSec = integer()</v> - <v> Mod = atom()</v> - <v> Func = atom()</v> - <v> Args = list()</v> - <v> Fun = fun()</v> - <v> Required = Key | {Key,SubKeys} | {Key,Subkey} | {Key,Subkey,SubKeys}</v> - <v> Key = atom()</v> - <v> SubKeys = SubKey | [SubKey]</v> - <v> SubKey = atom()</v> - <v> Name = atom()</v> - <v> UserData = term()</v> - <v> Conns = [atom()]</v> + <v>Info = {timetrap,Time} | {require,Required} | {require,Name,Required} | {userdata,UserData} | {silent_connections,Conns}</v> + <v>Time = TimeVal | TimeFunc</v> + <v>TimeVal = MilliSec | {seconds,integer()} | {minutes,integer()} | {hours,integer()}</v> + <v>TimeFunc = {Mod,Func,Args} | Fun</v> + <v>MilliSec = integer()</v> + <v>Mod = atom()</v> + <v>Func = atom()</v> + <v>Args = list()</v> + <v>Fun = fun()</v> + <v>Required = Key | {Key,SubKeys} | {Key,Subkey} | {Key,Subkey,SubKeys}</v> + <v>Key = atom()</v> + <v>SubKeys = SubKey | [SubKey]</v> + <v>SubKey = atom()</v> + <v>Name = atom()</v> + <v>UserData = term()</v> + <v>Conns = [atom()]</v> </type> - - <desc> + + <desc> <p>OPTIONAL</p> - - <p>This is the test case info function. It is supposed to + + <p>The test case information function. It is supposed to return a list of tagged tuples that specify various properties related to the execution of this particular test case. - Properties set by <seealso marker="#Module:Testcase-0"><c>Testcase/0</c></seealso> override - properties that have been previously set for the test case - by <seealso marker="#Module:group-1"><c>group/1</c></seealso> or <seealso marker="#Module:suite-0"><c>suite/0</c></seealso>.</p> - - <p>The <c>timetrap</c> tag sets the maximum time the + Properties set by + <seealso marker="#Module:Testcase-0"><c>Testcase/0</c></seealso> + override properties set previously for the test case by + <seealso marker="#Module:group-1"><c>group/1</c></seealso> or + <seealso marker="#Module:suite-0"><c>suite/0</c></seealso>.</p> + + <p>Tag <c>timetrap</c> sets the maximum time that the test case is allowed to execute. If the timetrap time is - exceeded, the test case fails with reason - <c>timetrap_timeout</c>. <seealso marker="#Module:init_per_testcase-2"><c>init_per_testcase/2</c></seealso> - and <seealso marker="#Module:end_per_testcase-2"><c>end_per_testcase/2</c></seealso> are included in the - timetrap time. A <c>TimeFunc</c> function can be used to - set a new timetrap by returning a <c>TimeVal</c>. It may also be - used to trigger a timetrap timeout by, at some point, returning a - value other than a <c>TimeVal</c>. (See the - <seealso marker="write_test_chapter#timetraps">User's Guide</seealso> - for details).</p> + exceeded, the test case fails with reason <c>timetrap_timeout</c>. + <seealso marker="#Module:init_per_testcase-2"><c>init_per_testcase/2</c></seealso> + and + <seealso marker="#Module:end_per_testcase-2"><c>end_per_testcase/2</c></seealso> + are included in the timetrap time. + A <c>TimeFunc</c> function can be used to + set a new timetrap by returning a <c>TimeVal</c>. It can also be + used to trigger a timetrap time-out by, at some point, returning a + value other than a <c>TimeVal</c>. For details, see section + <seealso marker="write_test_chapter#timetraps">Timetrap + Time-Outs</seealso> in the User's Guide.</p> - <p>The <c>require</c> tag specifies configuration variables - that are required by the test case (and/or <c>init/end_per_testcase/2</c>). + <p>Tag <c>require</c> specifies configuration variables + that are required by the test case (or <c>init_per_testcase/2</c> + or <c>end_per_testcase/2</c>). If the required configuration variables are not found in any of the - configuration files, the test case is skipped. For more - information about the 'require' functionality, see the - reference manual for the function - <seealso marker="ct#require-1"><c>ct:require/1/2</c></seealso>.</p> - - <p>If <c>timetrap</c> and/or <c>require</c> is not set, the - default values specified by <seealso marker="#Module:suite-0"><c>suite/0</c></seealso> (or - <seealso marker="#Module:group-1"><c>group/1</c></seealso>) will be used.</p> - - <p>With <c>userdata</c>, it is possible for the user to - specify arbitrary test case related information which can be - read by calling <seealso marker="ct#userdata-3"><c>ct:userdata/3</c></seealso>.</p> - - <p>Other tuples than the ones defined will simply be ignored.</p> + configuration files, the test case is skipped. For details about + the <c>require</c> functionality, see function + <seealso marker="ct#require-1"><c>ct:require/1,2</c></seealso>.</p> + + <p>If <c>timetrap</c> or <c>require</c> is not set, the + default values specified by + <seealso marker="#Module:suite-0"><c>suite/0</c></seealso> (or + <seealso marker="#Module:group-1"><c>group/1</c></seealso>) are used.</p> + + <p>With <c>userdata</c>, the user can specify any test case-related + information that can be read by calling + <seealso marker="ct#userdata-3"><c>ct:userdata/3</c></seealso>.</p> + + <p>Other tuples than the ones defined are ignored.</p> - <p>For more information about the test case info function, - see <seealso marker="write_test_chapter#info_function">Test - case info function</seealso> in the User's Guide.</p> + <p>For details about the test case information function, see section + <seealso marker="write_test_chapter#info_function">Test + Case Information Function</seealso> in the User's Guide.</p> </desc> </func> - - + <func> <name>Module:Testcase(Config) -> term() | {skip,Reason} | {comment,Comment} | {save_config,SaveConfig} | {skip_and_save,Reason,SaveConfig} | exit() </name> - <fsummary>A test case</fsummary> + <fsummary>A test case.</fsummary> <type> - <v> Config = SaveConfig = [{Key,Value}]</v> - <v> Key = atom()</v> - <v> Value = term()</v> - <v> Reason = term()</v> - <v> Comment = string()</v> + <v>Config = SaveConfig = [{Key,Value}]</v> + <v>Key = atom()</v> + <v>Value = term()</v> + <v>Reason = term()</v> + <v>Comment = string()</v> </type> - + <desc> - <p> MANDATORY </p> - - <p>This is the implementation of a test case. Here you must - call the functions you want to test, and do whatever you - need to check the result. If something fails, make sure the - function causes a runtime error, or call <seealso marker="ct#fail-1"><c>ct:fail/1/2</c></seealso> + <p>MANDATORY</p> + + <p>The implementation of a test case. Call the functions to test and + check the result. If something fails, ensure the + function causes a runtime error or call + <seealso marker="ct#fail-1"><c>ct:fail/1,2</c></seealso> (which also causes the test case process to terminate).</p> - - <p>Elements from the <c>Config</c> list can e.g. be read - with <c>proplists:get_value/2</c> (or the macro <c>?config</c> - defined in <c>ct.hrl</c>).</p> - <p>You can return <c>{skip,Reason}</c> if you decide not to - run the test case after all. <c>Reason</c> will then be - printed in 'Comment' field on the HTML result page.</p> - - <p>You can return <c>{comment,Comment}</c> if you wish to - print some information in the 'Comment' field on the HTML - result page.</p> - - <p>If the function returns anything else, the test case is - considered successful. (The return value always gets printed - in the test case log file).</p> + <p>Elements from the <c>Config</c> list can, for example, be read + with <c>proplists:get_value/2</c> in <c>STDLIB</c> + (or the macro <c>?config</c> defined in <c>ct.hrl</c>).</p> + + <p>If you decide not to run the test case after all, return + <c>{skip,Reason}</c>. <c>Reason</c> is then + printed in field <c>Comment</c> on the HTML result page.</p> + + <p>To print some information in field <c>Comment</c> on the HTML + result page, return <c>{comment,Comment}</c>.</p> - <p>For more information about test case implementation, please - see <seealso marker="write_test_chapter#test_cases">Test - cases</seealso> in the User's Guide.</p> + <p>If the function returns anything else, the test case is + considered successful. The return value always gets printed + in the test case log file.</p> - <p>For information on <c>save_config</c> and <c>skip_and_save</c>, please see - <seealso marker="dependencies_chapter#save_config">Dependencies between - Test Cases and Suites</seealso> in the User's Guide.</p> + <p>For details about test case implementation, see section + <seealso marker="write_test_chapter#test_cases">Test Cases</seealso> + in the User's Guide.</p> + + <p>For information on <c>save_config</c> and <c>skip_and_save</c>, + see section + <seealso marker="dependencies_chapter#save_config">Saving + Configuration Data</seealso> in the User's Guide.</p> </desc> </func> - + </funcs> </erlref> - diff --git a/lib/common_test/doc/src/config_file_chapter.xml b/lib/common_test/doc/src/config_file_chapter.xml index c7fd6e0b28..62ebfccb98 100644 --- a/lib/common_test/doc/src/config_file_chapter.xml +++ b/lib/common_test/doc/src/config_file_chapter.xml @@ -35,18 +35,18 @@ <section> <title>General</title> - <p>To avoid hard coding data values related to the test and/or SUT (System - Under Test) in the test suites, the data may instead be specified by means - of configuration files or strings that Common Test reads before + <p>To avoid hard-coding data values related to the test and/or System + Under Test (SUT) in the test suites, the data can instead be specified through + configuration files or strings that <c>Common Test</c> reads before the start of a test run. External configuration data makes it possible to - change test properties without having to modify the actual test suites - using the data. Examples of configuration data:</p> + change test properties without modifying the test suites + using the data. Examples of configuration data follows:</p> - <list> + <list type="bulleted"> <item>Addresses to the test plant or other instruments</item> <item>User login information</item> <item>Names of files needed by the test</item> - <item>Names of programs that should be executed during the test</item> + <item>Names of programs to be executed during the test</item> <item>Any other variable needed by the test</item> </list> @@ -57,154 +57,150 @@ <p>A configuration file can contain any number of elements of the type:</p> <pre> - {CfgVarName,Value}.</pre> + {CfgVarName,Value}.</pre> <p>where</p> <pre> - CfgVarName = atom() - Value = term() | [{CfgVarName,Value}]</pre> + CfgVarName = atom() + Value = term() | [{CfgVarName,Value}]</pre> </section> <section> - <title>Requiring and reading configuration data</title> + <title>Requiring and Reading Configuration Data</title> <marker id="require_config_data"></marker> <p>In a test suite, one must <em>require</em> that a configuration - variable (<c>CfgVarName</c> in the definition above) exists before - attempting to read the associated value in a test case or config function.</p> - - <p><c>require</c> is an assert statement that can be part of the <seealso - marker="write_test_chapter#suite">test suite info function</seealso> or - <seealso marker="write_test_chapter#info_function">test case info - function</seealso>. If the required variable is not available, the - test is skipped (unless a default value has been specified, see the - <seealso marker="write_test_chapter#info_function">test case info - function</seealso> chapter for details). There is also a function - <seealso marker="ct#require-1"><c>ct:require/1/2</c></seealso> which can be called from a test case - in order to check if a specific variable is available. The return + variable (<c>CfgVarName</c> in the previous definition) exists before + attempting to read the associated value in a test case or configuration function.</p> + + <p><c>require</c> is an assert statement, which can be part of the <seealso + marker="write_test_chapter#suite">Test Suite Information Function</seealso> or + <seealso marker="write_test_chapter#info_function">Test Case Information + Function</seealso>. If the required variable is unavailable, the + test is skipped (unless a default value has been specified, see section + <seealso marker="write_test_chapter#info_function">Test Case Information + Function</seealso> for details). Also, function + <seealso marker="ct#require-1"><c>ct:require/1/2</c></seealso> can be called + from a test case to check if a specific variable is available. The return value from this function must be checked explicitly and appropriate - action be taken depending on the result (e.g. to skip the test case - if the variable in question doesn't exist).</p> + action be taken depending on the result (for example, to skip the test case + if the variable in question does not exist).</p> - <p>A <c>require</c> statement in the test suite info- or test case - info-list should look like this: + <p>A <c>require</c> statement in the test suite information case or test case + information-list is to look like <c>{require,CfgVarName}</c> or <c>{require,AliasName,CfgVarName}</c>. The arguments <c>AliasName</c> and <c>CfgVarName</c> are the same as the - arguments to <seealso marker="ct#require-1"><c>ct:require/1/2</c></seealso> which are described in the - reference manual for <seealso marker="ct">ct</seealso>. + arguments to <seealso marker="ct#require-1"><c>ct:require/1,2</c></seealso>. <c>AliasName</c> becomes an alias for the configuration variable, and can be used as reference to the configuration data value. - The configuration variable may be associated with an - arbitrary number of alias names, but each name must be unique within - the same test suite. There are two main uses for alias names:</p> - <list> - <item>They may be introduced to identify connections (see below).</item> - <item>They may used to help adapt configuration data to a test suite + The configuration variable can be associated with any + number of alias names, but each name must be unique within + the same test suite. The two main uses for alias names follows:</p> + <list type="bulleted"> + <item>To identify connections (described later).</item> + <item>To help adapt configuration data to a test suite (or test case) and improve readability.</item> </list> - <p>To read the value of a config variable, use the function - <seealso marker="ct#get_config-1"><c>get_config/1/2/3</c></seealso> - which is also described in the reference - manual for <seealso marker="ct">ct</seealso>.</p> - <p>Example:</p> + <p>To read the value of a configuration variable, use function + <seealso marker="ct#get_config-1"><c>get_config/1,2,3</c></seealso>. + </p> + <p><em>Example:</em></p> <pre> - suite() -> - [{require, domain, 'CONN_SPEC_DNS_SUFFIX'}]. + suite() -> + [{require, domain, 'CONN_SPEC_DNS_SUFFIX'}]. - ... - - testcase(Config) -> - Domain = ct:get_config(domain), - ...</pre> + ... + + testcase(Config) -> + Domain = ct:get_config(domain), + ...</pre> </section> <section> - <title>Using configuration variables defined in multiple files</title> + <title>Using Configuration Variables Defined in Multiple Files</title> <p>If a configuration variable is defined in multiple files and you - want to access all possible values, you may use the <seealso marker="ct#get_config-3"><c>ct:get_config/3</c></seealso> - function and specify <c>all</c> in the options list. The values will then - be returned in a list and the order of the elements corresponds to the order - that the config files were specified at startup. Please see - the <seealso marker="ct">ct</seealso> reference manual for details.</p> + want to access all possible values, use function + <seealso marker="ct#get_config-3"><c>ct:get_config/3</c></seealso> + and specify <c>all</c> in the options list. The values are then + returned in a list and the order of the elements corresponds to the order + that the configuration files were specified at startup.</p> </section> <section> - <title>Encrypted configuration files</title> + <title>Encrypted Configuration Files</title> <marker id="encrypted_config_files"></marker> - <p>It is possible to encrypt configuration files containing sensitive data - if these files must be stored in open and shared directories.</p> - <p>Call <seealso marker="ct#encrypt_config_file-2"><c>ct:encrypt_config_file/2/3</c></seealso> to have Common Test encrypt a - specified file using the DES3 function in the OTP <c>crypto</c> application. - The encrypted file can then be used as a regular configuration file, - in combination with other encrypted files or normal text files. The key - for decrypting the configuration file must be provided when running the test, - however. This can be done by means of the <c>decrypt_key</c> or - <c>decrypt_file</c> flag/option, or a key file in a predefined location.</p> + <p>Configuration files containing sensitive data can be encrypted + if they must be stored in open and shared directories.</p> + <p>To have <c>Common Test</c> encrypt a + specified file using function <c>DES3</c> in application <c>Crypto</c>, + call <seealso marker="ct#encrypt_config_file-2"><c>ct:encrypt_config_file/2,3</c></seealso> + The encrypted file can then be used as a regular configuration file + in combination with other encrypted files or normal text files. However, the + key for decrypting the configuration file must be provided when running the test. + This can be done with flag/option <c>decrypt_key</c> or + <c>decrypt_file</c>, or a key file in a predefined location.</p> - <p>Common Test also provides decryption functions, - <seealso marker="ct#decrypt_config_file-2"><c>ct:decrypt_config_file/2/3</c></seealso>, for recreating the original text - files.</p> - - <p>Please see the <seealso marker="ct">ct</seealso> reference manual for - more information.</p> + <p><c>Common Test</c> also provides decryption functions, + <seealso marker="ct#decrypt_config_file-2"><c>ct:decrypt_config_file/2,3</c></seealso>, + for recreating the original text files.</p> </section> <section> - <title>Opening connections by using configuration data</title> - <p>There are two different methods for opening a connection - by means of the support functions in e.g. <seealso marker="ct_ssh"><c>ct_ssh</c></seealso>, <seealso marker="ct_ftp"><c>ct_ftp</c></seealso>, - and <seealso marker="ct_telnet"><c>ct_telnet</c></seealso>:</p> - <list> + <title>Opening Connections Using Configuration Data</title> + <p>Two different methods for opening a connection using the support functions + in, for example, <seealso marker="ct_ssh"><c>ct_ssh</c></seealso>, + <seealso marker="ct_ftp"><c>ct_ftp</c></seealso>, and + <seealso marker="ct_telnet"><c>ct_telnet</c></seealso> follows:</p> + <list type="bulleted"> <item>Using a configuration target name (an alias) as reference.</item> <item>Using the configuration variable as reference.</item> </list> <p>When a target name is used for referencing the configuration data - (that specifies the connection to be opened), the same name may be used + (that specifies the connection to be opened), the same name can be used as connection identity in all subsequent calls related to the connection - (also for closing it). It's only possible to have one open connection - per target name. If attempting to open a new connection using a name - already associated with an open connection, Common Test will - return the already existing handle so that the previously opened connection - will be used. This is a practical feature since it makes it possible to + (also for closing it). Only one open connection per target name + is possible. If you attempt to open a new connection using a name + already associated with an open connection, <c>Common Test</c> + returns the already existing handle so the previously opened connection + is used. This feature makes it possible to call the function for opening a particular connection whenever - useful. An action like this will not necessarily open any new - connections unless it's required (which could be the case if e.g. the - previous connection has been closed unexpectedly by the server). - Another benefit of using named connections is that it's not - necessary to pass handle references around in the suite for these - connections. + useful. An action like this does not necessarily open any new + connections unless it is required (which could be the case if, for example, + the previous connection has been closed unexpectedly by the server). + Using named connections also removes the need to pass handle references + around in the suite for these connections. </p> <p>When a configuration variable name is used as reference to the data specifying the connection, the handle returned as a result of opening the connection must be used in all subsequent calls (also for closing the connection). Repeated calls to the open function with the same - variable name as reference will result in multiple connections - being opened. This can be useful e.g. if a test case needs to open + variable name as reference results in multiple connections being opened. + This can be useful, for example, if a test case needs to open multiple connections to the same server on the target node (using the same configuration data for each connection). </p> </section> <section> - <title>User specific configuration data formats</title> + <title>User-Specific Configuration Data Formats</title> - <p>It is possible for the user to specify configuration data on a + <p>The user can specify configuration data on a different format than key-value tuples in a text file, as described - so far. The data can e.g. be read from arbitrary files, fetched from - the web over http, or requested from a user specific process. - To support this, Common Test provides a callback module plugin + so far. The data can, for example, be read from any files, fetched from + the web over HTTP, or requested from a user-specific process. + To support this, <c>Common Test</c> provides a callback module plugin mechanism to handle configuration data.</p> <section> - <title>Default callback modules for handling configuration data</title> - <p>The Common Test application includes default callback modules - for handling configuration data specified in standard config files - (see above) and in xml files:</p> - <list> + <title>Default Callback Modules for Handling Configuration Data</title> + <p><c>Common Test</c> includes default callback modules + for handling configuration data specified in standard configuration files + (described earlier) and in XML files as follows:</p> + <list type="bulleted"> <item> <c>ct_config_plain</c> - for reading configuration files with - key-value tuples (standard format). This handler will be used to + key-value tuples (standard format). This handler is used to parse configuration files if no user callback is specified. </item> <item> @@ -215,59 +211,59 @@ </section> <section> - <title>Using XML configuration files</title> - <p>This is an example of an XML configuration file:</p> - <pre><![CDATA[ -<config> + <title>Using XML Configuration Files</title> + <p>An example of an XML configuration file follows:</p> + <pre> + <![CDATA[ + <config> <ftp_host> <ftp>"targethost"</ftp> <username>"tester"</username> <password>"letmein"</password> </ftp_host> <lm_directory>"/test/loadmodules"</lm_directory> -</config>]]></pre> + </config>]]></pre> - <p>This configuration file, once read, will produce the same configuration + <p>Once read, this file produces the same configuration variables as the following text file:</p> <pre> -{ftp_host, [{ftp,"targethost"}, - {username,"tester"}, - {password,"letmein"}]}. + {ftp_host, [{ftp,"targethost"}, + {username,"tester"}, + {password,"letmein"}]}. -{lm_directory, "/test/loadmodules"}.</pre> + {lm_directory, "/test/loadmodules"}.</pre> </section> <section> - <title>How to implement a user specific handler</title> + <title>Implement a User-Specific Handler</title> - <p>The user specific handler can be written to handle special + <p>The user-specific handler can be written to handle special configuration file formats. The parameter can be either file - name(s) or configuration string(s) (the empty list is valid).</p> + names or configuration strings (the empty list is valid).</p> <p>The callback module implementing the handler is responsible for - checking correctness of configuration strings.</p> + checking the correctness of configuration strings.</p> - <p>To perform validation of the configuration strings, the callback module - should have the following function exported:</p> + <p>To validate the configuration strings, the callback module + is to have function <c>Callback:check_parameter/1</c> exported.</p> - <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>ct_run</c> or <c>ct:run_test</c>.</p> + <p>The input argument is passed from <c>Common Test</c>, as defined in the test + specification, or specified 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 + <p>The return value is to be any of the following values, indicating if the specified configuration parameter is valid:</p> - <list> + <list type="bulleted"> <item> - <c>{ok, {file, FileName}}</c> - parameter is a file name and - the file exists, + <c>{ok, {file, FileName}}</c> - the parameter is a file name and + the file exists. </item> <item> - <c>{ok, {config, ConfigString}}</c> - parameter is a config string - and it is correct, + <c>{ok, {config, ConfigString}}</c> - the parameter is a configuration string + and it is correct. </item> <item> - <c>{error, {nofile, FileName}}</c> - there is no file with the given - name in the current directory, + <c>{error, {nofile, FileName}}</c> - there is no file with the specified + name in the current directory. </item> <item> <c>{error, {wrong_config, ConfigString}}</c> - the configuration string @@ -275,196 +271,196 @@ </item> </list> - <p>To perform reading of configuration data - initially before the tests - start, or as a result of data being reloaded during test execution - - the following function should be exported from the callback module:</p> - - <p><c>Callback:read_config/1</c></p> + <p>The function <c>Callback:read_config/1</c> is to be exported from the + callback module to read configuration data, initially before the tests + start, or as a result of data being reloaded during test execution. + The input argument is the same as for function <c>check_parameter/1</c>.</p> - <p>The input argument is the same as for the <c>check_parameter/1</c> function.</p> - <p>The return value should be either:</p> + <p>The return value is to be either of the following:</p> - <list> + <list type="bulleted"> <item> - <c>{ok, Config}</c> - if the configuration variables are read successfully, + <c>{ok, Config}</c> - if the configuration variables are read successfully. </item> <item> <c>{error, {Error, ErrorDetails}}</c> - if the callback module fails to - proceed with the given configuration parameters. + proceed with the specified configuration parameters. </item> </list> <p><c>Config</c> is the proper Erlang key-value list, with possible - key-value sublists as values, like for the configuration file - example above:</p> + key-value sublists as values, like the earlier configuration file + example:</p> <pre> - [{ftp_host, [{ftp, "targethost"}, {username, "tester"}, {password, "letmein"}]}, - {lm_directory, "/test/loadmodules"}]</pre> + [{ftp_host, [{ftp, "targethost"}, {username, "tester"}, {password, "letmein"}]}, + {lm_directory, "/test/loadmodules"}]</pre> </section> </section> <section> - <title>Examples of configuration data handling</title> + <title>Examples of Configuration Data Handling</title> - <p>A config file for using the FTP client to access files on a remote - host could look like this:</p> + <p>A configuration file for using the FTP client to access files on a remote + host can look as follows:</p> <pre> - {ftp_host, [{ftp,"targethost"}, - {username,"tester"}, - {password,"letmein"}]}. + {ftp_host, [{ftp,"targethost"}, + {username,"tester"}, + {password,"letmein"}]}. - {lm_directory, "/test/loadmodules"}.</pre> + {lm_directory, "/test/loadmodules"}.</pre> - <p>The XML version shown in the chapter above can also be used, but it should be + <p>The XML version shown earlier can also be used, but it is to be explicitly specified that the <c>ct_config_xml</c> callback module is to be - used by Common Test.</p> + used by <c>Common Test</c>.</p> - <p>Example of how to assert that the configuration data is available and - use it for an FTP session:</p> + <p>The following is an example of how to assert that the configuration data is available + and can be used for an FTP session:</p> <pre> - init_per_testcase(ftptest, Config) -> - {ok,_} = ct_ftp:open(ftp), - Config. - - end_per_testcase(ftptest, _Config) -> - ct_ftp:close(ftp). - - ftptest() -> - [{require,ftp,ftp_host}, - {require,lm_directory}]. - - ftptest(Config) -> - Remote = filename:join(ct:get_config(lm_directory), "loadmodX"), - Local = filename:join(?config(priv_dir,Config), "loadmodule"), - ok = ct_ftp:recv(ftp, Remote, Local), - ...</pre> + init_per_testcase(ftptest, Config) -> + {ok,_} = ct_ftp:open(ftp), + Config. + + end_per_testcase(ftptest, _Config) -> + ct_ftp:close(ftp). + + ftptest() -> + [{require,ftp,ftp_host}, + {require,lm_directory}]. + + ftptest(Config) -> + Remote = filename:join(ct:get_config(lm_directory), "loadmodX"), + Local = filename:join(?config(priv_dir,Config), "loadmodule"), + ok = ct_ftp:recv(ftp, Remote, Local), + ...</pre> - <p>An example of how the above functions could be rewritten - if necessary to open multiple connections to the FTP server:</p> + <p>The following is an example of how the functions in the previous example + can be rewritten if it is necessary to open multiple connections to the + FTP server:</p> <pre> - init_per_testcase(ftptest, Config) -> - {ok,Handle1} = ct_ftp:open(ftp_host), - {ok,Handle2} = ct_ftp:open(ftp_host), - [{ftp_handles,[Handle1,Handle2]} | Config]. - - end_per_testcase(ftptest, Config) -> - lists:foreach(fun(Handle) -> ct_ftp:close(Handle) end, - ?config(ftp_handles,Config)). - - ftptest() -> - [{require,ftp_host}, - {require,lm_directory}]. - - ftptest(Config) -> - Remote = filename:join(ct:get_config(lm_directory), "loadmodX"), - Local = filename:join(?config(priv_dir,Config), "loadmodule"), - [Handle | MoreHandles] = ?config(ftp_handles,Config), - ok = ct_ftp:recv(Handle, Remote, Local), - ...</pre> + init_per_testcase(ftptest, Config) -> + {ok,Handle1} = ct_ftp:open(ftp_host), + {ok,Handle2} = ct_ftp:open(ftp_host), + [{ftp_handles,[Handle1,Handle2]} | Config]. + + end_per_testcase(ftptest, Config) -> + lists:foreach(fun(Handle) -> ct_ftp:close(Handle) end, + ?config(ftp_handles,Config)). + + ftptest() -> + [{require,ftp_host}, + {require,lm_directory}]. + + ftptest(Config) -> + Remote = filename:join(ct:get_config(lm_directory), "loadmodX"), + Local = filename:join(?config(priv_dir,Config), "loadmodule"), + [Handle | MoreHandles] = ?config(ftp_handles,Config), + ok = ct_ftp:recv(Handle, Remote, Local), + ...</pre> </section> <section> - <title>Example of user specific configuration handler</title> - <p>A simple configuration handling driver which will ask an external server for - configuration data can be implemented this way:</p> + <title>Example of User-Specific Configuration Handler</title> + <p>A simple configuration handling driver, asking an external server for + configuration data, can be implemented as follows:</p> <pre> --module(config_driver). --export([read_config/1, check_parameter/1]). - -read_config(ServerName)-> - ServerModule = list_to_atom(ServerName), - ServerModule:start(), - ServerModule:get_config(). - -check_parameter(ServerName)-> - ServerModule = list_to_atom(ServerName), - case code:is_loaded(ServerModule) of - {file, _}-> - {ok, {config, ServerName}}; - false-> - case code:load_file(ServerModule) of - {module, ServerModule}-> - {ok, {config, ServerName}}; - {error, nofile}-> - {error, {wrong_config, "File not found: " ++ ServerName ++ ".beam"}} - end - end.</pre> - - <p>The configuration string for this driver may be "config_server", if the - config_server.erl module below is compiled and exists in the code path + -module(config_driver). + -export([read_config/1, check_parameter/1]). + + read_config(ServerName)-> + ServerModule = list_to_atom(ServerName), + ServerModule:start(), + ServerModule:get_config(). + + check_parameter(ServerName)-> + ServerModule = list_to_atom(ServerName), + case code:is_loaded(ServerModule) of + {file, _}-> + {ok, {config, ServerName}}; + false-> + case code:load_file(ServerModule) of + {module, ServerModule}-> + {ok, {config, ServerName}}; + {error, nofile}-> + {error, {wrong_config, "File not found: " ++ ServerName ++ ".beam"}} + end + end.</pre> + + <p>The configuration string for this driver can be <c>config_server</c>, if the + <c>config_server.erl</c> module that follows is compiled and exists in the code path during test execution:</p> <pre> --module(config_server). --export([start/0, stop/0, init/1, get_config/0, loop/0]). - --define(REGISTERED_NAME, ct_test_config_server). - -start()-> - case whereis(?REGISTERED_NAME) of - undefined-> - spawn(?MODULE, init, [?REGISTERED_NAME]), - wait(); - _Pid-> - ok - end, - ?REGISTERED_NAME. - -init(Name)-> - register(Name, self()), - loop(). - -get_config()-> - call(self(), get_config). - -stop()-> - call(self(), stop). - -call(Client, Request)-> - case whereis(?REGISTERED_NAME) of - undefined-> - {error, {not_started, Request}}; - Pid-> - Pid ! {Client, Request}, - receive - Reply-> - {ok, Reply} - after 4000-> - {error, {timeout, Request}} - end - end. - -loop()-> - receive - {Pid, stop}-> - Pid ! ok; - {Pid, get_config}-> - {D,T} = erlang:localtime(), - Pid ! - [{localtime, [{date, D}, {time, T}]}, - {node, erlang:node()}, - {now, erlang:now()}, - {config_server_pid, self()}, - {config_server_vsn, ?vsn}], - ?MODULE:loop() - end. - -wait()-> - case whereis(?REGISTERED_NAME) of - undefined-> - wait(); - _Pid-> - ok - end.</pre> - - <p>In this example, the handler also provides the ability to dynamically reload - configuration variables. If <c>ct:reload_config(localtime)</c> is called from + -module(config_server). + -export([start/0, stop/0, init/1, get_config/0, loop/0]). + + -define(REGISTERED_NAME, ct_test_config_server). + + start()-> + case whereis(?REGISTERED_NAME) of + undefined-> + spawn(?MODULE, init, [?REGISTERED_NAME]), + wait(); + _Pid-> + ok + end, + ?REGISTERED_NAME. + + init(Name)-> + register(Name, self()), + loop(). + + get_config()-> + call(self(), get_config). + + stop()-> + call(self(), stop). + + call(Client, Request)-> + case whereis(?REGISTERED_NAME) of + undefined-> + {error, {not_started, Request}}; + Pid-> + Pid ! {Client, Request}, + receive + Reply-> + {ok, Reply} + after 4000-> + {error, {timeout, Request}} + end + end. + + loop()-> + receive + {Pid, stop}-> + Pid ! ok; + {Pid, get_config}-> + {D,T} = erlang:localtime(), + Pid ! + [{localtime, [{date, D}, {time, T}]}, + {node, erlang:node()}, + {now, erlang:now()}, + {config_server_pid, self()}, + {config_server_vsn, ?vsn}], + ?MODULE:loop() + end. + + wait()-> + case whereis(?REGISTERED_NAME) of + undefined-> + wait(); + _Pid-> + ok + end.</pre> + + <p>Here, the handler also provides for dynamically reloading of + configuration variables. If + <seealso marker="ct#reload_config-1"><c>ct:reload_config(localtime)</c></seealso> is called from the test case function, all variables loaded with <c>config_driver:read_config/1</c> - will be updated with their latest values, and the new value for variable - <c>localtime</c> will be returned.</p> + are updated with their latest values, and the new value for variable + <c>localtime</c> is returned.</p> </section> </chapter> diff --git a/lib/common_test/doc/src/cover_chapter.xml b/lib/common_test/doc/src/cover_chapter.xml index f164fff0ad..094aa7d80c 100644 --- a/lib/common_test/doc/src/cover_chapter.xml +++ b/lib/common_test/doc/src/cover_chapter.xml @@ -33,256 +33,251 @@ <section> <marker id="cover"></marker> <title>General</title> - <p>Although Common Test was created primarly for the purpose of - black box testing, nothing prevents it from working perfectly as - a white box testing tool as well. This is especially true when + <p>Although <c>Common Test</c> was created primarily for + black-box testing, nothing prevents it from working perfectly as + a white-box testing tool as well. This is especially true when the application to test is written in Erlang. Then the test - ports are easily realized by means of Erlang function calls.</p> + ports are easily realized with Erlang function calls.</p> - <p>When white box testing an Erlang application, it is useful to - be able to measure the code coverage of the test. Common Test + <p>When white-box testing an Erlang application, it is useful to + be able to measure the code coverage of the test. <c>Common Test</c> provides simple access to the OTP Cover tool for this - purpose. Common Test handles all necessary communication with - the Cover tool (starting, compiling, analysing, etc). All the - Common Test user needs to do is to specify the extent of the + purpose. <c>Common Test</c> handles all necessary communication with + the Cover tool (starting, compiling, analysing, and so on). + The <c>Common Test</c> user only needs to specify the extent of the code coverage analysis.</p> </section> <section> - <title>Usage</title> - <p>To specify what modules should be included - in the code coverage test, you provide a cover specification - file. Using this file you can point out specific modules or - specify directories that contain modules which should all be - included in the analysis. You can also, in the same fashion, - specify modules that should be excluded from the analysis.</p> + <title>Use</title> + <p>To specify the modules to be included in the code coverage test, + provide a cover specification file. With this file you can point + out specific modules or specify directories containing modules to be + included in the analysis. You can also specify modules to be excluded + from the analysis.</p> <p>If you are testing a distributed Erlang application, it is likely that code you want included in the code coverage analysis - gets executed on an Erlang node other than the one Common Test - is running on. If this is the case you need to specify these - other nodes in the cover specification file or add them - dynamically to the code coverage set of nodes. See the - <c>ct_cover</c> page in the reference manual for details on the - latter.</p> + gets executed on another Erlang node than the one <c>Common Test</c> + is running on. If so, you must specify these other nodes in the + cover specification file or add them dynamically to the code coverage + set of nodes. For details on the latter, see module + <seealso marker="ct_cover"><c>ct_cover</c></seealso>.</p> <p>In the cover specification file you can also specify your required level of the code coverage analysis; <c>details</c> or <c>overview</c>. In detailed mode, you get a coverage overview - page, showing you per module and total coverage percentages, as - well as one HTML file printed for each module included in the - analysis that shows exactly what parts of the code have been + page, showing per module and total coverage percentages. + You also get an HTML file printed for each module included in the + analysis showing exactly what parts of the code have been executed during the test. In overview mode, only the code - coverage overview page gets printed.</p> + coverage overview page is printed.</p> <p>You can choose to export and import code coverage data between tests. If you specify the name of an export file in the cover - specification file, Common Test will export collected coverage - data to this file at the end of the test. You may similarly - specify that previously exported data should be imported and - included in the analysis for a test (you can specify multiple - import files). This way it is possible to analyse total code coverage - without necessarily running all tests at once.</p> - - <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>ct_run</c>. - Example:</p> - - <p><c>$ ct_run -dir $TESTOBJS/db -cover $TESTOBJS/db/config/db.coverspec</c></p> + specification file, <c>Common Test</c> exports collected coverage + data to this file at the end of the test. You can similarly + specify previously exported data to be imported and + included in the analysis for a test (multiple import files can be specified). + This way, the total code coverage can be analyzed without necessarily + running all tests at once.</p> + + <p>To activate the code coverage support, specify the name of the cover + specification file as you start <c>Common Test</c>. + Do this by using flag <c>-cover</c> with + <seealso marker="ct_run"><c>ct_run</c></seealso>, + for example:</p> + <pre> + $ ct_run -dir $TESTOBJS/db -cover $TESTOBJS/db/config/db.coverspec</pre> - <p>You may also pass the cover specification file name in a - call to <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso>, by adding a <c>{cover,CoverSpec}</c> - tuple to the <c>Opts</c> argument. Also, you can of course - enable code coverage in your test specifications (read - more in the chapter about - <seealso marker="run_test_chapter#test_specifications">using test - specifications</seealso>).</p> + <p>You can also pass the cover specification file name in a + call to <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso>, + by adding a <c>{cover,CoverSpec}</c> tuple to argument <c>Opts</c>.</p> + <p>You can also enable code coverage in your test specifications (see section + <seealso marker="run_test_chapter#test_specifications">Test Specifications</seealso> + in section Running Tests and Analyzing Results).</p> </section> <section> <marker id="cover_stop"></marker> - <title>Stopping the cover tool when tests are completed</title> - <p>By default the Cover tool is automatically stopped when the - tests are completed. This causes the original (non cover - compiled) modules to be loaded back in to the test node. If a - process at this point is still running old code of any of the + <title>Stopping the Cover Tool When Tests Are Completed</title> + <p>By default, the Cover tool is automatically stopped when the + tests are completed. This causes the original (non-cover + compiled) modules to be loaded back into the test node. If a + process at this point still runs old code of any of the modules that are cover compiled, meaning that it has not done any fully qualified function call after the cover compilation, - the process will now be killed. To avoid this it is possible to - set the value of the <c>cover_stop</c> option to - <c>false</c>. This means that the modules will stay cover - compiled, and it is therefore only recommended if the erlang - node(s) under test is terminated after the test is completed - or if cover can be manually stopped.</p> - - <p>The option can be set by using the <c>-cover_stop</c> flag with - <c>ct_run</c>, by adding <c>{cover_stop,true|false}</c> to the - Opts argument to <seealso - marker="ct#run_test-1"><c>ct:run_test/1</c></seealso>, or by adding - a <c>cover_stop</c> term in your test specification (see chapter - about <seealso - marker="run_test_chapter#test_specifications">test - specifications</seealso>).</p> + the process is killed. To avoid this, set the value of option + <c>cover_stop</c> to <c>false</c>. This means that the + modules stay cover compiled. Therefore, this is only recommended + if the Erlang nodes under test are terminated after the test is + completed, or if cover can be manually stopped.</p> + + <p>The option can be set by using flag <c>-cover_stop</c> with + <c>ct_run</c>, by adding <c>{cover_stop,true|false}</c> to argument + <c>Opts</c> to + <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso>, + or by adding a <c>cover_stop</c> term in the test specification (see section + <seealso marker="run_test_chapter#test_specifications">Test Specifications</seealso> + in section Running Tests and Analyzing Results).</p> </section> <section> - <title>The cover specification file</title> - <p>These are the terms allowed in a cover specification file:</p> + <title>The Cover Specification File</title> + <p>The following terms are allowed in a cover specification file:</p> <pre> - %% List of Nodes on which cover will be active during test. - %% Nodes = [atom()] - {nodes, Nodes}. - - %% Files with previously exported cover data to include in analysis. - %% CoverDataFiles = [string()] - {import, CoverDataFiles}. - - %% Cover data file to export from this session. - %% CoverDataFile = string() - {export, CoverDataFile}. - - %% Cover analysis level. - %% Level = details | overview - {level, Level}. - - %% Directories to include in cover. - %% Dirs = [string()] - {incl_dirs, Dirs}. - - %% Directories, including subdirectories, to include. - {incl_dirs_r, Dirs}. - - %% Specific modules to include in cover. - %% Mods = [atom()] - {incl_mods, Mods}. - - %% Directories to exclude in cover. - {excl_dirs, Dirs}. - - %% Directories, including subdirectories, to exclude. - {excl_dirs_r, Dirs}. - - %% Specific modules to exclude in cover. - {excl_mods, Mods}. - - %% Cross cover compilation - %% Tag = atom(), an identifier for a test run - %% Mod = [atom()], modules to compile for accumulated analysis - {cross,[{Tag,Mods}]}. - </pre> - - <p>The <c>incl_dirs_r</c> and <c>excl_dirs_r</c> terms tell Common - Test to search the given directories recursively and include - or exclude any module found during the search. The - <c>incl_dirs</c> and <c>excl_dirs</c> terms result in a - non-recursive search for modules (i.e. only modules found in - the given directories are included or excluded).</p> - <p><em>Note:</em> Directories containing Erlang modules that are - to be included in a code coverage test must exist in the code - server path, or the cover tool will fail to recompile the modules. - (It is not sufficient to specify these directories in the cover - specification file for Common Test).</p> + %% List of Nodes on which cover will be active during test. + %% Nodes = [atom()] + {nodes, Nodes}. + + %% Files with previously exported cover data to include in analysis. + %% CoverDataFiles = [string()] + {import, CoverDataFiles}. + + %% Cover data file to export from this session. + %% CoverDataFile = string() + {export, CoverDataFile}. + + %% Cover analysis level. + %% Level = details | overview + {level, Level}. + + %% Directories to include in cover. + %% Dirs = [string()] + {incl_dirs, Dirs}. + + %% Directories, including subdirectories, to include. + {incl_dirs_r, Dirs}. + + %% Specific modules to include in cover. + %% Mods = [atom()] + {incl_mods, Mods}. + + %% Directories to exclude in cover. + {excl_dirs, Dirs}. + + %% Directories, including subdirectories, to exclude. + {excl_dirs_r, Dirs}. + + %% Specific modules to exclude in cover. + {excl_mods, Mods}. + + %% Cross cover compilation + %% Tag = atom(), an identifier for a test run + %% Mod = [atom()], modules to compile for accumulated analysis + {cross,[{Tag,Mods}]}.</pre> + + <p>The terms <c>incl_dirs_r</c> and <c>excl_dirs_r</c> tell <c>Common + Test</c> to search the specified directories recursively and include + or exclude any module found during the search. The terms + <c>incl_dirs</c> and <c>excl_dirs</c> result in a + non-recursive search for modules (that is, only modules found in + the specified directories are included or excluded).</p> + <note><p>Directories containing Erlang modules to be included in a code + coverage test must exist in the code server path. Otherwise, + the Cover tool fails to recompile the modules. It is not sufficient to + specify these directories in the cover specification file for + <c>Common Test</c>.</p></note> </section> <section> <marker id="cross_cover"/> - <title>Cross cover analysis</title> + <title>Cross Cover Analysis</title> <p>The cross cover mechanism allows cover analysis of modules - across multiple tests. It is useful if some code, e.g. a library - module, is used by many different tests and the accumulated cover - result is desirable.</p> + across multiple tests. It is useful if some code, for example, a + library module, is used by many different tests and the accumulated + cover result is desirable.</p> - <p>This can of course also be achieved in a more customized way by - using the <c>export</c> parameter in the cover specification and - analysing the result off line, but the cross cover mechanism is a - build in solution which also provides the logging.</p> + <p>This can also be achieved in a more customized way by + using parameter <c>export</c> in the cover specification and + analysing the result off line. However, the cross cover mechanism is a + built-in solution that also provides logging.</p> - <p>The mechanism is easiest explained via an example:</p> + <p>The mechanism is easiest explained by an example:</p> - <p>Let's say that there are two systems, <c>s1</c> and <c>s2</c>, - which are tested in separate test runs. System <c>s1</c> contains - a library module <c>m1</c> which is tested by the <c>s1</c> test - run and is included in <c>s1</c>'s cover specification:</p> + <p>Assume that there are two systems, <c>s1</c> and <c>s2</c>, + that are tested in separate test runs. System <c>s1</c> contains + a library module <c>m1</c> tested by test run <c>s1</c> and + is included in the cover specification of <c>s1</c> as follows:</p> <code type="none"> -s1.cover: - {incl_mods,[m1]}.</code> + s1.cover: + {incl_mods,[m1]}.</code> <p>When analysing code coverage, the result for <c>m1</c> can be seen in the cover log in the <c>s1</c> test result.</p> - <p>Now, let's imagine that since <c>m1</c> is a library module, it - is also used quite a bit by system <c>s2</c>. The <c>s2</c> test - run does not specifically test <c>m1</c>, but it might still be - interesting to see which parts of <c>m1</c> is actually covered by - the <c>s2</c> tests. To do this, <c>m1</c> could be included also - in <c>s2</c>'s cover specification:</p> + <p>Now, imagine that as <c>m1</c> is a library module, it + is also often used by system <c>s2</c>. Test run <c>s2</c> + does not specifically test <c>m1</c>, but it can still be + interesting to see which parts of <c>m1</c> that are covered + by the <c>s2</c> tests. To do this, <c>m1</c> can be included also + in the cover specification of <c>s2</c> as follows:</p> <code type="none"> -s2.cover: - {incl_mods,[m1]}.</code> + s2.cover: + {incl_mods,[m1]}.</code> - <p>This would give an entry for <c>m1</c> also in the cover log - for the <c>s2</c> test run. The problem is that this would only - reflect the coverage by <c>s2</c> tests, not the accumulated - result over <c>s1</c> and <c>s2</c>. And this is where the cross + <p>This gives an entry for <c>m1</c> also in the cover log + for test run <c>s2</c>. The problem is that this only + reflects the coverage by <c>s2</c> tests, not the accumulated + result over <c>s1</c> and <c>s2</c>. This is where the cross cover mechanism comes in handy.</p> - <p>If instead the cover specification for <c>s2</c> was like - this:</p> + <p>If instead the cover specification for <c>s2</c> is like + the following:</p> <code type="none"> -s2.cover: - {cross,[{s1,[m1]}]}.</code> + s2.cover: + {cross,[{s1,[m1]}]}.</code> - <p>then <c>m1</c> would be cover compiled in the <c>s2</c> test - run, but not shown in the coverage log. Instead, if - <c>ct_cover:cross_cover_analyse/2</c> is called after both - <c>s1</c> and <c>s2</c> test runs are completed, the accumulated - result for <c>m1</c> would be available in the cross cover log for - the <c>s1</c> test run.</p> + <p>Then <c>m1</c> is cover compiled in test run <c>s2</c>, + but not shown in the coverage log. Instead, if + <seealso marker="ct_cover#cross_cover_analyse-2"><c>ct_cover:cross_cover_analyse/2</c></seealso> + is called after both <c>s1</c> and <c>s2</c> test runs are completed, + the accumulated result for <c>m1</c> is available in the cross cover + log for test run <c>s1</c>.</p> - <p>The call to the analyse function must be like this:</p> + <p>The call to the analyze function must be as follows:</p> <code type="none"> -ct_cover:cross_cover_analyse(Level, [{s1,S1LogDir},{s2,S2LogDir}]).</code> + ct_cover:cross_cover_analyse(Level, [{s1,S1LogDir},{s2,S2LogDir}]).</code> - <p>where <c>S1LogDir</c> and <c>S2LogDir</c> are the directories + <p>Here, <c>S1LogDir</c> and <c>S2LogDir</c> are the directories named <c><TestName>.logs</c> for each test respectively.</p> - <p>Note the tags <c>s1</c> and <c>s2</c> which are used in the + <p>Notice the tags <c>s1</c> and <c>s2</c>, which are used in the cover specification file and in the call to - <c>ct_cover:cross_cover_analyse/2</c>. The point of these are only + <c>ct_cover:cross_cover_analyse/2</c>. The purpose of these is only to map the modules specified in the cover specification to the log - directory specified in the call to the analyse function. The name - of the tag has no meaning beyond this.</p> + directory specified in the call to the analyze function. The tag name + has no meaning beyond this.</p> </section> <section> <title>Logging</title> <p>To view the result of a code coverage test, click the button - labled "COVER LOG" in the top level index page for the test run.</p> + labeled "COVER LOG" in the top-level index page for the test run.</p> - <p>Prior to Erlang/OTP 17.1, if your test run consisted of + <p>Before Erlang/OTP 17.1, if your test run consisted of multiple tests, cover would be started and stopped for each test - within the test run. Separate logs would be available via the + within the test run. Separate logs would be available through the "Coverage log" link on the test suite result pages. These links are still available, but now they all point to the same page as - the button on the top level index page. The log contains the - accumulated results for the complete test run. See the release - notes for more information about this change.</p> + the button on the top-level index page. The log contains the + accumulated results for the complete test run. For details about + this change, see the release notes.</p> - <p>The buttonc takes you to the code coverage overview page. If you - have successfully performed a detailed coverage analysis, you - find links to each individual module coverage page here.</p> + <p>The button takes you to the code coverage overview page. If you + have successfully performed a detailed coverage analysis, + links to each individual module coverage page are found here.</p> - <p>If cross cover analysis has been performed, and there are - accumulated coverage results for the current test, then the - - "Coverdata collected over all tests" link will take you to these + <p>If cross cover analysis is performed, and there are + accumulated coverage results for the current test, the link + "Coverdata collected over all tests" takes you to these results.</p> </section> diff --git a/lib/common_test/doc/src/ct.xml b/lib/common_test/doc/src/ct.xml new file mode 100644 index 0000000000..b6c862c233 --- /dev/null +++ b/lib/common_test/doc/src/ct.xml @@ -0,0 +1,1415 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2010</year><year>2012</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + </legalnotice> + + <title>ct</title> + <prepared></prepared> + <responsible></responsible> + <docno></docno> + <approved></approved> + <checked></checked> + <date></date> + <rev>A</rev> + <file>ct.xml</file> + </header> + <module>ct</module> + <modulesummary>Main user interface for the Common Test framework.</modulesummary> + + <description> + + <p>Main user interface for the <c>Common Test</c> framework.</p> + + <p>This module implements the command-line interface for running + tests and basic functions for <c>Common Test</c> case issues, such as + configuration and logging.</p> + + <p><em>Test Suite Support Macros</em></p> + + <p>The <c>config</c> macro is defined in <c>ct.hrl</c>. This macro is + to be used to retrieve information from the <c>Config</c> variable sent + to all test cases. It is used with two arguments; the first is the name + of the configuration variable to retrieve, the second is the + <c>Config</c> variable supplied to the test case.</p> + + <p>Possible configuration variables include:</p> + + <list type="bulleted"> + <item><p><c>data_dir</c> - Data file directory</p></item> + <item><p><c>priv_dir</c> - Scratch file directory</p></item> + <item><p>Whatever added by + <seealso marker="common_test#Module:init_per_suite-1"><c>init_per_suite/1</c></seealso> + or + <seealso marker="common_test#Module:init_per_testcase-2"><c>init_per_testcase/2</c></seealso> + in the test suite.</p></item> + </list> + + </description> + + <section> + <title>Data Types</title> + <marker id="types"/> + <taglist> + + <tag><c>handle() = pid()</c></tag> + <item><marker id="type-handle"/> + <p>The identity (handle) of a connection.</p></item> + + <tag><c>target_name() = atom()</c></tag> + <item><marker id="type-target_name"/> + <p>A name and association to configuration data introduced + through a require statement, or a call to + <seealso marker="#require-2"><c>ct:require/2</c></seealso>, + for example, + <c>ct:require(mynodename,{node,[telnet]})</c>.</p></item> + + </taglist> + </section> + + <funcs> + <func> + <name>abort_current_testcase(Reason) -> ok | {error, ErrorReason}</name> + <fsummary>Aborts the currently executing test case.</fsummary> + <type> + <v>Reason = term()</v> + <v>ErrorReason = no_testcase_running | parallel_group</v> + </type> + <desc><marker id="abort_current_testcase-1"/> + <p>Aborts the currently executing test case. The user must know with + certainty which test case is currently executing. The function is + therefore only safe to call from a function that has been called + (or synchronously invoked) by the test case.</p> + + <p><c>Reason</c>, the reason for aborting the test case, is printed + in the test case log.</p> + </desc> + </func> + + <func> + <name>add_config(Callback, Config) -> ok | {error, Reason}</name> + <fsummary>Loads configuration variables using the specified callback + module and configuration string.</fsummary> + <type> + <v>Callback = atom()</v> + <v>Config = string()</v> + <v>Reason = term()</v> + </type> + <desc><marker id="add_config-2"/> + <p>Loads configuration variables using the specified callback module and + configuration string. The callback module is to be either loaded or + present in the code part. Loaded configuration variables can later + be removed using function + <seealso marker="#remove_config-2"><c>ct:remove_config/2</c></seealso>. + </p> + </desc> + </func> + + <func> + <name>break(Comment) -> ok | {error, Reason}</name> + <fsummary>Cancels any active timetrap and pause the execution of the + current test case until the user calls function continue/0.</fsummary> + <type> + <v>Comment = string()</v> + <v>Reason = {multiple_cases_running, TestCases} | 'enable break with release_shell option'</v> + <v>TestCases = [atom()]</v> + </type> + <desc><marker id="break-1"/> + <p>Cancels any active timetrap and pauses the execution of the + current test case until the user calls function <c>continue/0</c>. + The user can then interact with the Erlang node running the tests, + for example, for debugging purposes or for manually executing a + part of the test case. If a parallel group is executing, + <seealso marker="#break-2"><c>ct:break/2</c></seealso> is to be + called instead.</p> + <p>A cancelled timetrap is not automatically reactivated after the + break, but must be started exlicitly with + <seealso marker="#timetrap-1"><c>ct:timetrap/1</c></seealso>.</p> + <p>In order for the break/continue functionality to work, <c>Common + Test</c> must release the shell process controlling <c>stdin</c>. + This is done by setting start option <c>release_shell</c> + to <c>true</c>. For details, see section + <seealso marker="run_test_chapter#erlang_shell_or_program">Running + Tests from the Erlang Shell or from an Erlang Program</seealso> + in the User's Guide.</p> + </desc> + </func> + + <func> + <name>break(TestCase, Comment) -> ok | {error, Reason}</name> + <fsummary>Works the same way as break/1, only argument TestCase makes it + possible to pause a test case executing in a parallel group.</fsummary> + <type> + <v>TestCase = atom()</v> + <v>Comment = string()</v> + <v>Reason = 'test case not running' | 'enable break with release_shell option'</v> + </type> + <desc><marker id="break-2"/> + <p>Works the same way as + <seealso marker="#break-1"><c>ct:break/1</c></seealso>, only + argument <c>TestCase</c> makes it possible to pause a test case + executing in a parallel group. Function + <seealso marker="#continue-1"><c>ct:continue/1</c></seealso> is to + be used to resume execution of <c>TestCase</c>.</p> + + <p>For details, see + <seealso marker="#break/1"><c>ct:break/1</c></seealso>.</p> + </desc> + </func> + + <func> + <name>capture_get() -> ListOfStrings</name> + <fsummary>Equivalent to capture_get([default]).</fsummary> + <type> + <v>ListOfStrings = [string()]</v> + </type> + <desc><marker id="capture_get-0"/> + <p>Equivalent to + <seealso marker="#capture_get-1">ct:capture_get([default])</seealso>.</p> + </desc> + </func> + + <func> + <name>capture_get(ExclCategories) -> ListOfStrings</name> + <fsummary>Returns and purges the list of text strings buffered during + the latest session of capturing printouts to stdout.</fsummary> + <type> + <v>ExclCategories = [atom()]</v> + <v>ListOfStrings = [string()]</v> + </type> + <desc><marker id="capture_get-1"/> + <p>Returns and purges the list of text strings buffered during the + latest session of capturing printouts to <c>stdout</c>. Log + categories that are to be ignored in <c>ListOfStrings</c> can be + specified with <c>ExclCategories</c>. + If <c>ExclCategories = []</c>, no filtering takes place.</p> + + <p>See also + <seealso marker="#capture_start-0"><c>ct:capture_start/0</c></seealso>, + <seealso marker="#capture_stop-0"><c>ct:capture_stop/0</c></seealso>, + <seealso marker="#log-3"><c>ct:log/3</c></seealso>.</p> + </desc> + </func> + + <func> + <name>capture_start() -> ok</name> + <fsummary>Starts capturing all text strings printed to stdout + during execution of the test case.</fsummary> + <desc><marker id="capture_start-0"/> + <p>Starts capturing all text strings printed to <c>stdout</c> + during execution of the test case.</p> + + <p>See also + <seealso marker="#capture_get-1"><c>ct:capture_get/1</c></seealso>, + <seealso marker="#capture_stop-0"><c>ct:capture_stop/0</c></seealso>.</p> + </desc> + </func> + + <func> + <name>capture_stop() -> ok</name> + <fsummary>Stops capturing text strings (a session started with + capture_start/0).</fsummary> + <desc><marker id="capture_stop-0"/> + <p>Stops capturing text strings (a session started with + <c>capture_start/0</c>).</p> + + <p>See also + <seealso marker="#capture_get-1"><c>ct:capture_get/1</c></seealso>, + <seealso marker="#capture_start-0"><c>ct:capture_start/0</c></seealso>.</p> + </desc> + </func> + + <func> + <name>comment(Comment) -> ok</name> + <fsummary>Prints the specified Comment in the comment field in the + table on the test suite result page.</fsummary> + <type> + <v>Comment = term()</v> + </type> + <desc><marker id="comment-1"/> + <p>Prints the specified <c>Comment</c> in the comment field in the + table on the test suite result page.</p> + + <p>If called several times, only the last comment is printed. The + test case return value <c>{comment,Comment}</c> overwrites the + string set by this function.</p> + </desc> + </func> + + <func> + <name>comment(Format, Args) -> ok</name> + <fsummary>Prints the formatted string in the comment field in the + table on the test suite result page.</fsummary> + <type> + <v>Format = string()</v> + <v>Args = list()</v> + </type> + <desc><marker id="comment-2"/> + <p>Prints the formatted string in the comment field in the table + on the test suite result page.</p> + + <p>Arguments <c>Format</c> and <c>Args</c> are used in a call to + <c>io_lib:format/2</c> to create the comment string. The behavior + of <c>comment/2</c> is otherwise the same as function + <seealso marker="#comment-1"><c>ct:comment/1</c></seealso>.</p> + </desc> + </func> + + <func> + <name>continue() -> ok</name> + <fsummary>This function must be called to continue after a test + case (not executing in a parallel group) has called break/1.</fsummary> + <desc><marker id="continue-0"/> + <p>This function must be called to continue after a test case + (not executing in a parallel group) has called function + <seealso marker="#break-1"><c>ct:break/1</c></seealso>.</p> + </desc> + </func> + + <func> + <name>continue(TestCase) -> ok</name> + <fsummary>This function must be called to continue after a test case + has called break/2.</fsummary> + <type> + <v>TestCase = atom()</v> + </type> + <desc><marker id="continue-1"/> + <p>This function must be called to continue after a test case has + called <seealso marker="#break-2"><c>ct:break/2</c></seealso>. + If the paused test case, <c>TestCase</c>, executes in a parallel + group, this function, rather than <c>continue/0</c>, must be used + to let the test case proceed.</p> + </desc> + </func> + + <func> + <name>decrypt_config_file(EncryptFileName, TargetFileName) -> ok | {error, Reason}</name> + <fsummary>Decrypts EncryptFileName, previously generated with + encrypt_config_file/2,3.</fsummary> + <type> + <v>EncryptFileName = string()</v> + <v>TargetFileName = string()</v> + <v>Reason = term()</v> + </type> + <desc><marker id="decrypt_config_file-2"/> + <p>Decrypts <c>EncryptFileName</c>, previously generated with + <seealso marker="#encrypt_config_file-2"><c>ct:encrypt_config_file/2,3</c></seealso>. + The original file contents is saved in the target file. The + encryption key, a string, must be available in a text file named + <c>.ct_config.crypt</c>, either in the current directory, or the + home directory of the user (it is searched for in that order).</p> + </desc> + </func> + + <func> + <name>decrypt_config_file(EncryptFileName, TargetFileName, KeyOrFile) -> ok | {error, Reason}</name> + <fsummary>Decrypts EncryptFileName, previously generated with + encrypt_config_file/2,3.</fsummary> + <type> + <v>EncryptFileName = string()</v> + <v>TargetFileName = string()</v> + <v>KeyOrFile = {key, string()} | {file, string()}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="decrypt_config_file-3"/> + <p>Decrypts <c>EncryptFileName</c>, previously generated with + <seealso marker="#encrypt_config_file-2"><c>ct:encrypt_config_file/2,3</c></seealso>. + The original file contents is saved in the target file. The key + must have the same value as that used for encryption.</p> + </desc> + </func> + + <func> + <name>encrypt_config_file(SrcFileName, EncryptFileName) -> ok | {error, Reason}</name> + <fsummary>Encrypts the source configuration file with DES3 and saves the + result in file EncryptFileName.</fsummary> + <type> + <v>SrcFileName = string()</v> + <v>EncryptFileName = string()</v> + <v>Reason = term()</v> + </type> + <desc><marker id="encrypt_config_file-2"/> + <p>Encrypts the source configuration file with DES3 and saves the result + in file <c>EncryptFileName</c>. The key, a string, must be + available in a text file named <c>.ct_config.crypt</c>, either + in the current directory, or the home directory of the user (it + is searched for in that order).</p> + + <p>For information about using encrypted configuration files when + running tests, see section + <seealso marker="config_file_chapter#encrypted_config_files">Encrypted + Configuration Files</seealso> in the User's Guide.</p> + + <p>For details on DES3 encryption/decryption, see application + <seealso marker="crypto:index"><c>Crypto</c></seealso>.</p> + </desc> + </func> + + <func> + <name>encrypt_config_file(SrcFileName, EncryptFileName, KeyOrFile) -> ok | {error, Reason}</name> + <fsummary>Encrypts the source configuration file with DES3 and saves the + result in the target file EncryptFileName.</fsummary> + <type> + <v>SrcFileName = string()</v> + <v>EncryptFileName = string()</v> + <v>KeyOrFile = {key, string()} | {file, string()}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="encrypt_config_file-3"/> + <p>Encrypts the source configuration file with DES3 and saves the result + in the target file <c>EncryptFileName</c>. The encryption key + to use is either the value in <c>{key,Key}</c> or the value + stored in the file specified by <c>{file,File}</c>.</p> + + <p>For information about using encrypted configuration files when + running tests, see section + <seealso marker="config_file_chapter#encrypted_config_files">Encrypted + Configuration Files</seealso> in the User's Guide.</p> + + <p>For details on DES3 encryption/decryption, see application + <seealso marker="crypto:index"><c>Crypto</c></seealso>.</p> + </desc> + </func> + + <func> + <name>fail(Reason) -> ok</name> + <fsummary>Terminates a test case with the specified error + Reason.</fsummary> + <type> + <v>Reason = term()</v> + </type> + <desc><marker id="fail-1"/> + <p>Terminates a test case with the specified error <c>Reason</c>.</p> + </desc> + </func> + + <func> + <name>fail(Format, Args) -> ok</name> + <fsummary>Terminates a test case with an error message specified by + a format string and a list of values (used as arguments to + io_lib:format/2).</fsummary> + <type> + <v>Format = string()</v> + <v>Args = list()</v> + </type> + <desc><marker id="fail-2"/> + <p>Terminates a test case with an error message specified by a + format string and a list of values (used as arguments to + <c>io_lib:format/2</c>).</p> + </desc> + </func> + + <func> + <name>get_config(Required) -> Value</name> + <fsummary>Equivalent to get_config(Required, undefined, []).</fsummary> + <desc><marker id="get_config-1"/> + <p>Equivalent to <seealso marker="#get_config-3"><c>ct:get_config(Required, + undefined, [])</c></seealso>.</p> + </desc> + </func> + + <func> + <name>get_config(Required, Default) -> Value</name> + <fsummary>Equivalent to get_config(Required, Default, []).</fsummary> + <desc><marker id="get_config-2"/> + <p>Equivalent to <seealso marker="#get_config-3"><c>ct:get_config(Required, + Default, [])</c></seealso>.</p> + </desc> + </func> + + <func> + <name>get_config(Required, Default, Opts) -> ValueOrElement</name> + <fsummary>Reads configuration data values.</fsummary> + <type> + <v>Required = KeyOrName | {KeyOrName, SubKey} | {KeyOrName, SubKey, SubKey}</v> + <v>KeyOrName = atom()</v> + <v>SubKey = atom()</v> + <v>Default = term()</v> + <v>Opts = [Opt] | []</v> + <v>Opt = element | all</v> + <v>ValueOrElement = term() | Default</v> + </type> + <desc><marker id="get_config-3"/> + <p>Reads configuration data values.</p> + + <p>Returns the matching values or configuration elements, given a + configuration variable key or its associated name (if one has been + specified with + <seealso marker="#require-2"><c>ct:require/2</c></seealso> + or a <c>require</c> statement).</p> + + <p><em>Example:</em></p> + + <p>Given the following configuration file:</p> + + <pre> + {unix,[{telnet,IpAddr}, + {user,[{username,Username}, + {password,Password}]}]}.</pre> + + <p>Then:</p> + + <pre> + ct:get_config(unix,Default) -> [{telnet,IpAddr}, + {user, [{username,Username}, {password,Password}]}] + ct:get_config({unix,telnet},Default) -> IpAddr + ct:get_config({unix,user,username},Default) -> Username + ct:get_config({unix,ftp},Default) -> Default + ct:get_config(unknownkey,Default) -> Default</pre> + + <p>If a configuration variable key has been associated with a name (by + <seealso marker="#require-2"><c>ct:require/2</c></seealso> + or a <c>require</c> statement), the name can be used instead + of the key to read the value:</p> + + <pre> + ct:require(myuser,{unix,user}) -> ok. + ct:get_config(myuser,Default) -> [{username,Username}, {password,Password}]</pre> + + <p>If a configuration variable is defined in multiple files, use option + <c>all</c> to access all possible values. The values are returned + in a list. The order of the elements corresponds to the order + that the configuration files were specified at startup.</p> + + <p>If configuration elements (key-value tuples) are to be returned as + result instead of values, use option <c>element</c>. The + returned elements are then on the form <c>{Required,Value}</c>.</p> + + <p>See also + <seealso marker="#get_config-1"><c>ct:get_config/1</c></seealso>, + <seealso marker="#get_config-2"><c>ct:get_config/2</c></seealso>, + <seealso marker="#require-1"><c>ct:require/1</c></seealso>, + <seealso marker="#require-2"><c>ct:require/2</c></seealso>.</p> + </desc> + </func> + + <func> + <name>get_event_mgr_ref() -> EvMgrRef</name> + <fsummary>Gets a reference to the <c>Common Test</c> event manager.</fsummary> + <type> + <v>EvMgrRef = atom()</v> + </type> + <desc><marker id="get_event_mgr_ref-0"/> + <p>Gets a reference to the <c>Common Test</c> event manager. + The reference can be used to, for example, add a user-specific + event handler while tests are running.</p> + + <p><em>Example:</em></p> + + <pre> + gen_event:add_handler(ct:get_event_mgr_ref(), my_ev_h, [])</pre> + </desc> + </func> + + <func> + <name>get_status() -> TestStatus | {error, Reason} | no_tests_running</name> + <fsummary>Returns status of ongoing test.</fsummary> + <type> + <v>TestStatus = [StatusElem]</v> + <v>StatusElem = {current, TestCaseInfo} | {successful, Successful} | {failed, Failed} | {skipped, Skipped} | {total, Total}</v> + <v>TestCaseInfo = {Suite, TestCase} | [{Suite, TestCase}]</v> + <v>Suite = atom()</v> + <v>TestCase = atom()</v> + <v>Successful = integer()</v> + <v>Failed = integer()</v> + <v>Skipped = {UserSkipped, AutoSkipped}</v> + <v>UserSkipped = integer()</v> + <v>AutoSkipped = integer()</v> + <v>Total = integer()</v> + <v>Reason = term()</v> + </type> + <desc><marker id="get_status-0"/> + <p>Returns status of ongoing test. The returned list contains + information about which test case is executing (a list of cases + when a parallel test case group is executing), as well as + counters for successful, failed, skipped, and total test cases + so far.</p> + </desc> + </func> + + <func> + <name>get_target_name(Handle) -> {ok, TargetName} | {error, Reason}</name> + <fsummary>Returns the name of the target that the specified connection + belongs to.</fsummary> + <type> + <v>Handle = handle()</v> + <v>TargetName = target_name()</v> + </type> + <desc><marker id="get_target_name-1"/> + <p>Returns the name of the target that the specified connection + belongs to.</p> + </desc> + </func> + + <func> + <name>get_testspec_terms() -> TestSpecTerms | undefined</name> + <fsummary>Gets a list of all test specification terms used to + configure and run this test.</fsummary> + <type> + <v>TestSpecTerms = [{Tag, Value}]</v> + <v>Value = [term()]</v> + </type> + <desc><marker id="get_testspec_terms-0"/> + <p>Gets a list of all test specification terms used to configure + and run this test.</p> + </desc> + </func> + + <func> + <name>get_testspec_terms(Tags) -> TestSpecTerms | undefined</name> + <fsummary>Reads one or more terms from the test specification used to + configure and run this test.</fsummary> + <type> + <v>Tags = [Tag] | Tag</v> + <v>Tag = atom()</v> + <v>TestSpecTerms = [{Tag, Value}] | {Tag, Value}</v> + <v>Value = [{Node, term()}] | [term()]</v> + <v>Node = atom()</v> + </type> + <desc><marker id="get_testspec_terms-1"/> + <p>Reads one or more terms from the test specification used to + configure and run this test. <c>Tag</c> is any valid test + specification tag, for example, <c>label</c>, <c>config</c>, or + <c>logdir</c>. User-specific terms are also available to read if + option <c>allow_user_terms</c> is set.</p> + <p>All value tuples returned, except user terms, have the node + name as first element.</p> + <p>To read test terms, use <c>Tag = tests</c> (rather than + <c>suites</c>, <c>groups</c>, or <c>cases</c>). <c>Value</c> is + then the list of <em>all</em> tests on the form + <c>[{Node,Dir,[{TestSpec,GroupsAndCases1},...]},...]</c>, where + <c>GroupsAndCases = [{Group,[Case]}] | [Case]</c>.</p> + </desc> + </func> + + <func> + <name>get_timetrap_info() -> {Time, {Scaling,ScaleVal}}</name> + <fsummary>Reads information about the timetrap set for the current + test case.</fsummary> + <type> + <v>Time = integer() | infinity</v> + <v>Scaling = true | false</v> + <v>ScaleVal = integer()</v> + </type> + <desc><marker id="get_timetrap_info-0"/> + <p>Reads information about the timetrap set for the current test + case. <c>Scaling</c> indicates if <c>Common Test</c> will attempt + to compensate timetraps automatically for runtime delays + introduced by, for example, tools like cover. <c>ScaleVal</c> is + the value of the current scaling multipler (always 1 if scaling is + disabled). Note the <c>Time</c> is not the scaled result.</p> + </desc> + </func> + + <func> + <name>install(Opts) -> ok | {error, Reason}</name> + <fsummary>Installs configuration files and event handlers.</fsummary> + <type> + <v>Opts = [Opt]</v> + <v>Opt = {config, ConfigFiles} | {event_handler, Modules} | {decrypt, KeyOrFile}</v> + <v>ConfigFiles = [ConfigFile]</v> + <v>ConfigFile = string()</v> + <v>Modules = [atom()]</v> + <v>KeyOrFile = {key, Key} | {file, KeyFile}</v> + <v>Key = string()</v> + <v>KeyFile = string()</v> + </type> + <desc><marker id="install-1"/> + <p>Installs configuration files and event handlers.</p> + + <p>Run this function once before the first test.</p> + + <p><em>Example:</em></p> + + <pre> + install([{config,["config_node.ctc","config_user.ctc"]}])</pre> + + <p>This function is automatically run by program <c>ct_run</c>.</p> + </desc> + </func> + + <func> + <name>listenv(Telnet) -> [Env]</name> + <fsummary>Performs command listenv on the specified Telnet connection + and returns the result as a list of key-value pairs.</fsummary> + <type> + <v>Telnet = term()</v> + <v>Env = {Key, Value}</v> + <v>Key = string()</v> + <v>Value = string()</v> + </type> + <desc><marker id="listenv-1"/> + <p>Performs command <c>listenv</c> on the specified Telnet connection + and returns the result as a list of key-value pairs.</p> + </desc> + </func> + + <func> + <name>log(Format) -> ok</name> + <fsummary>Equivalent to log(default, 50, Format, [], []).</fsummary> + <desc><marker id="log-1"/> + <p>Equivalent to + <seealso marker="#log-5"><c>ct:log(default, 50, Format, [], [])</c></seealso>.</p> + </desc> + </func> + + <func> + <name>log(X1, X2) -> ok</name> + <fsummary>Equivalent to log(Category, Importance, Format, + FormatArgs, []).</fsummary> + <type> + <v>X1 = Category | Importance | Format</v> + <v>X2 = Format | FormatArgs</v> + </type> + <desc><marker id="log-2"/> + <p>Equivalent to <seealso marker="#log-5"><c>ct:log(Category, + Importance, Format, FormatArgs, [])</c></seealso>.</p> + </desc> + </func> + + <func> + <name>log(X1, X2, X3) -> ok</name> + <fsummary>Equivalent to log(Category, Importance, Format, + FormatArgs, Opts).</fsummary> + <type> + <v>X1 = Category | Importance</v> + <v>X2 = Importance | Format</v> + <v>X3 = Format | FormatArgs | Opts</v> + </type> + <desc><marker id="log-3"/> + <p>Equivalent to <seealso marker="#log-5"><c>ct:log(Category, + Importance, Format, FormatArgs, Opts)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>log(X1, X2, X3, X4) -> ok</name> + <fsummary>Equivalent to log(Category, Importance, Format, + FormatArgs, Opts).</fsummary> + <type> + <v>X1 = Category | Importance</v> + <v>X2 = Importance | Format</v> + <v>X3 = Format | FormatArgs</v> + <v>X4 = FormatArgs | Opts</v> + </type> + <desc><marker id="log-4"/> + <p>Equivalent to <seealso marker="#log-5"><c>ct:log(Category, + Importance, Format, FormatArgs, Opts)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>log(Category, Importance, Format, FormatArgs, Opts) -> ok</name> + <fsummary>Prints from a test case to the log file.</fsummary> + <type> + <v>Category = atom()</v> + <v>Importance = integer()</v> + <v>Format = string()</v> + <v>FormatArgs = list()</v> + <v>Opts = [Opt]</v> + <v>Opt = no_css | esc_chars</v> + </type> + <desc><marker id="log-5"/> + <p>Prints from a test case to the log file.</p> + + <p>This function is meant for printing a string directly from a + test case to the test case log file.</p> + + <p>Default <c>Category</c> is <c>default</c>, + default <c>Importance</c> is <c>?STD_IMPORTANCE</c>, + and default value for <c>FormatArgs</c> is <c>[]</c>.</p> + + <p>For details on <c>Category</c>, <c>Importance</c> and the <c>no_css</c> + option, see section <seealso marker="write_test_chapter#logging"> + Logging - Categories and Verbosity Levels</seealso> in the User's Guide.</p> + + <p>Common Test will not escape special HTML characters (<, > and &) + in the text printed with this function, unless the <c>esc_chars</c> + option is used.</p> + </desc> + </func> + + <func> + <name>make_priv_dir() -> ok | {error, Reason}</name> + <fsummary>If the test has been started with option create_priv_dir + set to manual_per_tc, in order for the test case to use the private + directory, it must first create it by calling this function.</fsummary> + <type> + <v>Reason = term()</v> + </type> + <desc><marker id="make_priv_dir-0"/> + <p>If the test is started with option <c>create_priv_dir</c> + set to <c>manual_per_tc</c>, in order for the test case to use + the private directory, it must first create it by calling this + function.</p> + </desc> + </func> + + <func> + <name>notify(Name, Data) -> ok</name> + <fsummary>Sends an asynchronous notification of type Name with Data + to the <c>Common Test</c> event manager.</fsummary> + <type> + <v>Name = atom()</v> + <v>Data = term()</v> + </type> + <desc><marker id="notify-2"/> + <p>Sends an asynchronous notification of type <c>Name</c> with + <c>Data</c>to the Common Test event manager. This can later be + caught by any installed event manager.</p> + + <p>See also + <seealso marker="stdlib:gen_event"><c>stdlib:gen_event(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>pal(Format) -> ok</name> + <fsummary>Equivalent to pal(default, 50, Format, []).</fsummary> + <desc><marker id="pal-1"/> + <p>Equivalent to + <seealso marker="#pal-4"><c>ct:pal(default, 50, Format, + [])</c></seealso>.</p> + </desc> + </func> + + <func> + <name>pal(X1, X2) -> ok</name> + <fsummary>Equivalent to pal(Category, Importance, Format, + FormatArgs).</fsummary> + <type> + <v>X1 = Category | Importance | Format</v> + <v>X2 = Format | FormatArgs</v> + </type> + <desc><marker id="pal-2"/> + <p>Equivalent to <seealso marker="#pal-4"><c>ct:pal(Category, + Importance, Format, FormatArgs)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>pal(X1, X2, X3) -> ok</name> + <fsummary>Equivalent to pal(Category, Importance, Format, + FormatArgs).</fsummary> + <type> + <v>X1 = Category | Importance</v> + <v>X2 = Importance | Format</v> + <v>X3 = Format | FormatArgs</v> + </type> + <desc><marker id="pal-3"/> + <p>Equivalent to <seealso marker="#pal-4"><c>ct:pal(Category, + Importance, Format, FormatArgs)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>pal(Category, Importance, Format, FormatArgs) -> ok</name> + <fsummary>Prints and logs from a test case.</fsummary> + <type> + <v>Category = atom()</v> + <v>Importance = integer()</v> + <v>Format = string()</v> + <v>FormatArgs = list()</v> + </type> + <desc><marker id="pal-4"/> + <p>Prints and logs from a test case.</p> + + <p>This function is meant for printing a string from a test case, + both to the test case log file and to the console.</p> + + <p>Default <c>Category</c> is <c>default</c>, + default <c>Importance</c> is <c>?STD_IMPORTANCE</c>, + and default value for <c>FormatArgs</c> is <c>[]</c>.</p> + + <p>For details on <c>Category</c> and <c>Importance</c>, see section + <seealso marker="write_test_chapter#logging">Logging - Categories + and Verbosity Levels</seealso> in the User's Guide.</p> + + <p>Note that special characters in the text (<, > and &) will + be escaped by Common Test before the text is printed to the log + file.</p> + </desc> + </func> + + <func> + <name>parse_table(Data) -> {Heading, Table}</name> + <fsummary>Parses the printout from an SQL table and returns a list of + tuples.</fsummary> + <type> + <v>Data = [string()]</v> + <v>Heading = tuple()</v> + <v>Table = [tuple()]</v> + </type> + <desc><marker id="parse_table-1"/> + <p>Parses the printout from an SQL table and returns a list of + tuples.</p> + + <p>The printout to parse is typically the result of a <c>select</c> + command in SQL. The returned <c>Table</c> is a list of tuples, + where each tuple is a row in the table.</p> + + <p><c>Heading</c> is a tuple of strings representing the headings + of each column in the table.</p> + </desc> + </func> + + <func> + <name>print(Format) -> ok</name> + <fsummary>Equivalent to print(default, 50, Format, []).</fsummary> + <desc><marker id="print-1"/> + <p>Equivalent to <seealso marker="#print-4"><c>ct:print(default, + 50, Format, [])</c></seealso>.</p> + </desc> + </func> + + <func> + <name>print(X1, X2) -> ok</name> + <fsummary>Equivalent to print(Category, Importance, Format, + FormatArgs).</fsummary> + <type> + <v>X1 = Category | Importance | Format</v> + <v>X2 = Format | FormatArgs</v> + </type> + <desc><marker id="print-2"/> + <p>Equivalent to <seealso marker="#print-4"><c>ct:print(Category, + Importance, Format, FormatArgs)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>print(X1, X2, X3) -> ok</name> + <fsummary>Equivalent to print(Category, Importance, Format, + FormatArgs).</fsummary> + <type> + <v>X1 = Category | Importance</v> + <v>X2 = Importance | Format</v> + <v>X3 = Format | FormatArgs</v> + </type> + <desc><marker id="print-3"/> + <p>Equivalent to <seealso marker="#print-4"><c>ct:print(Category, + Importance, Format, FormatArgs)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>print(Category, Importance, Format, FormatArgs) -> ok</name> + <fsummary>Prints from a test case to the console.</fsummary> + <type> + <v>Category = atom()</v> + <v>Importance = integer()</v> + <v>Format = string()</v> + <v>FormatArgs = list()</v> + </type> + <desc><marker id="print-4"/> + <p>Prints from a test case to the console.</p> + + <p>This function is meant for printing a string from a test case to + the console.</p> + + <p>Default <c>Category</c> is <c>default</c>, + default <c>Importance</c> is <c>?STD_IMPORTANCE</c>, + and default value for <c>FormatArgs</c> is <c>[]</c>.</p> + + <p>For details on <c>Category</c> and <c>Importance</c>, see section + <seealso marker="write_test_chapter#logging">Logging - Categories + and Verbosity Levels</seealso> in the User's Guide.</p> + </desc> + </func> + + <func> + <name>reload_config(Required) -> ValueOrElement</name> + <fsummary>Reloads configuration file containing specified configuration + key.</fsummary> + <type> + <v>Required = KeyOrName | {KeyOrName, SubKey} | {KeyOrName, SubKey, SubKey}</v> + <v>KeyOrName = atom()</v> + <v>SubKey = atom()</v> + <v>ValueOrElement = term()</v> + </type> + <desc><marker id="reload_config-1"/> + <p>Reloads configuration file containing specified configuration key.</p> + + <p>This function updates the configuration data from which the + specified configuration variable was read, and returns the (possibly) + new value of this variable.</p> + + <p>If some variables were present in the configuration, but are + not loaded using this function, they are removed from the + configuration table together with their aliases.</p> + </desc> + </func> + + <func> + <name>remove_config(Callback, Config) -> ok</name> + <fsummary>Removes configuration variables (together with + their aliases) that were loaded with specified callback module and + configuration string.</fsummary> + <type> + <v>Callback = atom()</v> + <v>Config = string()</v> + <v>Reason = term()</v> + </type> + <desc><marker id="remove_config-2"/> + <p>Removes configuration variables (together wih their aliases) + that were loaded with specified callback module and configuration + string.</p> + </desc> + </func> + + <func> + <name>require(Required) -> ok | {error, Reason}</name> + <fsummary>Checks if the required configuration is available.</fsummary> + <type> + <v>Required = Key | {Key, SubKeys} | {Key, SubKey, SubKeys}</v> + <v>Key = atom()</v> + <v>SubKeys = SubKey | [SubKey]</v> + <v>SubKey = atom()</v> + </type> + <desc><marker id="require-1"/> + <p>Checks if the required configuration is available. Arbitrarily + deep tuples can be specified as <c>Required</c>. Only the last + element of the tuple can be a list of <c>SubKey</c>s.</p> + + <p><em>Example 1.</em> Require the variable <c>myvar</c>:</p> + + <pre> + ok = ct:require(myvar).</pre> + + <p>In this case the configuration file must at least contain:</p> + + <pre> + {myvar,Value}.</pre> + + <p><em>Example 2.</em> Require key <c>myvar</c> with subkeys + <c>sub1</c> and <c>sub2</c>:</p> + + <pre> + ok = ct:require({myvar,[sub1,sub2]}).</pre> + + <p>In this case the configuration file must at least contain:</p> + + <pre> + {myvar,[{sub1,Value},{sub2,Value}]}.</pre> + + <p><em>Example 3.</em> Require key <c>myvar</c> with subkey + <c>sub1</c> with <c>subsub1</c>:</p> + + <pre> + ok = ct:require({myvar,sub1,sub2}).</pre> + + <p>In this case the configuration file must at least contain:</p> + + <pre> + {myvar,[{sub1,[{sub2,Value}]}]}.</pre> + + <p>See also + <seealso marker="#get_config-1"><c>ct:get_config/1</c></seealso>, + <seealso marker="#get_config-2"><c>ct:get_config/2</c></seealso>, + <seealso marker="#get_config-3"><c>ct:get_config/3</c></seealso>, + <seealso marker="#require-2"><c>ct:require/2</c></seealso>.</p> + </desc> + </func> + + <func> + <name>require(Name, Required) -> ok | {error, Reason}</name> + <fsummary>Checks if the required configuration is available and gives + it a name.</fsummary> + <type> + <v>Name = atom()</v> + <v>Required = Key | {Key, SubKey} | {Key, SubKey, SubKey}</v> + <v>SubKey = Key</v> + <v>Key = atom()</v> + </type> + <desc><marker id="require-2"/> + <p>Checks if the required configuration is available and gives it a + name. The semantics for <c>Required</c> is the same as in + <seealso marker="#require-1"><c>ct:require/1</c></seealso> except + that a list of <c>SubKey</c>s cannot be specified.</p> + + <p>If the requested data is available, the subentry is associated + with <c>Name</c> so that the value of the element can be read with + <seealso marker="#get_config-1"><c>ct:get_config/1,2</c></seealso> + provided <c>Name</c> is used instead of the whole <c>Required</c> + term.</p> + + <p><em>Example:</em></p> + + <p>Require one node with a Telnet connection and an FTP connection. + Name the node <c>a</c>:</p> + + <pre> + ok = ct:require(a,{machine,node}).</pre> + + <p>All references to this node can then use the node name. For + example, a file over FTP is fetched like follows:</p> + + <pre> + ok = ct:ftp_get(a,RemoteFile,LocalFile).</pre> + + <p>For this to work, the configuration file must at least contain:</p> + + <pre> + {machine,[{node,[{telnet,IpAddr},{ftp,IpAddr}]}]}.</pre> + + <note><p>The behavior of this function changed radically in + <c>Common Test</c> 1.6.2. To keep some backwards compatability, + it is still possible to do:<br/> + <c>ct:require(a,{node,[telnet,ftp]}).</c><br/> + This associates the name <c>a</c> with the top-level <c>node</c> + entry. For this to work, the configuration file must at least + contain:<br/> + <c>{node,[{telnet,IpAddr},{ftp,IpAddr}]}.</c></p> + </note> + + <p>See also + <seealso marker="#get_config-1"><c>ct:get_config/1</c></seealso>, + <seealso marker="#get_config-2"><c>ct:get_config/2</c></seealso>, + <seealso marker="#get_config-3"><c>ct:get_config/3</c></seealso>, + <seealso marker="#require-1"><c>ct:require/1</c></seealso>.</p> + </desc> + </func> + + <func> + <name>run(TestDirs) -> Result</name> + <fsummary>Runs all test cases in all suites in the specified + directories.</fsummary> + <type> + <v>TestDirs = TestDir | [TestDir]</v> + </type> + <desc><marker id="run-1"/> + <p>Runs all test cases in all suites in the specified directories.</p> + + <p>See also <seealso marker="#run-3"><c>ct:run/3</c></seealso>.</p> + </desc> + </func> + + <func> + <name>run(TestDir, Suite) -> Result</name> + <fsummary>Runs all test cases in the specified suite.</fsummary> + <desc><marker id="run-2"/> + <p>Runs all test cases in the specified suite.</p> + + <p>See also <seealso marker="#run-3"><c>ct:run/3</c></seealso>.</p> + </desc> + </func> + + <func> + <name>run(TestDir, Suite, Cases) -> Result</name> + <fsummary>Runs the specified test cases.</fsummary> + <type> + <v>TestDir = string()</v> + <v>Suite = atom()</v> + <v>Cases = atom() | [atom()]</v> + <v>Result = [TestResult] | {error, Reason}</v> + </type> + <desc><marker id="run-3"/> + <p>Runs the specified test cases.</p> + + <p>Requires that + <seealso marker="#install-1"><c>ct:install/1</c></seealso> has been + run first.</p> + + <p>Suites (<c>*_SUITE.erl</c>) files must be stored in <c>TestDir</c> + or <c>TestDir/test</c>. All suites are compiled when the test is + run.</p> + </desc> + </func> + + <func> + <name>run_test(Opts) -> Result</name> + <fsummary>Runs tests as specified by the combination of options in + Opts.</fsummary> + <type> + <v>Opts = [OptTuples]</v> + <v>OptTuples = {dir, TestDirs} | {suite, Suites} | {group, Groups} | {testcase, Cases} | {spec, TestSpecs} | {join_specs, Bool} | {label, Label} | {config, CfgFiles} | {userconfig, UserConfig} | {allow_user_terms, Bool} | {logdir, LogDir} | {silent_connections, Conns} | {stylesheet, CSSFile} | {cover, CoverSpecFile} | {cover_stop, Bool} | {step, StepOpts} | {event_handler, EventHandlers} | {include, InclDirs} | {auto_compile, Bool} | {abort_if_missing_suites, Bool} | {create_priv_dir, CreatePrivDir} | {multiply_timetraps, M} | {scale_timetraps, Bool} | {repeat, N} | {duration, DurTime} | {until, StopTime} | {force_stop, ForceStop} | {decrypt, DecryptKeyOrFile} | {refresh_logs, LogDir} | {logopts, LogOpts} | {verbosity, VLevels} | {basic_html, Bool} | {esc_chars, Bool} | {ct_hooks, CTHs} | {enable_builtin_hooks, Bool} | {release_shell, Bool}</v> + <v>TestDirs = [string()] | string()</v> + <v>Suites = [string()] | [atom()] | string() | atom()</v> + <v>Cases = [atom()] | atom()</v> + <v>Groups = GroupNameOrPath | [GroupNameOrPath]</v> + <v>GroupNameOrPath = [atom()] | atom() | all</v> + <v>TestSpecs = [string()] | string()</v> + <v>Label = string() | atom()</v> + <v>CfgFiles = [string()] | string()</v> + <v>UserConfig = [{CallbackMod, CfgStrings}] | {CallbackMod, CfgStrings}</v> + <v>CallbackMod = atom()</v> + <v>CfgStrings = [string()] | string()</v> + <v>LogDir = string()</v> + <v>Conns = all | [atom()]</v> + <v>CSSFile = string()</v> + <v>CoverSpecFile = string()</v> + <v>StepOpts = [StepOpt] | []</v> + <v>StepOpt = config | keep_inactive</v> + <v>EventHandlers = EH | [EH]</v> + <v>EH = atom() | {atom(), InitArgs} | {[atom()], InitArgs}</v> + <v>InitArgs = [term()]</v> + <v>InclDirs = [string()] | string()</v> + <v>CreatePrivDir = auto_per_run | auto_per_tc | manual_per_tc</v> + <v>M = integer()</v> + <v>N = integer()</v> + <v>DurTime = string(HHMMSS)</v> + <v>StopTime = string(YYMoMoDDHHMMSS) | string(HHMMSS)</v> + <v>ForceStop = skip_rest | Bool</v> + <v>DecryptKeyOrFile = {key, DecryptKey} | {file, DecryptFile}</v> + <v>DecryptKey = string()</v> + <v>DecryptFile = string()</v> + <v>LogOpts = [LogOpt]</v> + <v>LogOpt = no_nl | no_src</v> + <v>VLevels = VLevel | [{Category, VLevel}]</v> + <v>VLevel = integer()</v> + <v>Category = atom()</v> + <v>CTHs = [CTHModule | {CTHModule, CTHInitArgs}]</v> + <v>CTHModule = atom()</v> + <v>CTHInitArgs = term()</v> + <v>Result = {Ok, Failed, {UserSkipped, AutoSkipped}} | TestRunnerPid | {error, Reason}</v> + <v>Ok = integer()</v> + <v>Failed = integer()</v> + <v>UserSkipped = integer()</v> + <v>AutoSkipped = integer()</v> + <v>TestRunnerPid = pid()</v> + <v>Reason = term()</v> + </type> + <desc><marker id="run_test-1"/> + <p>Runs tests as specified by the combination of options in + <c>Opts</c>. The options are the same as those used with program + <c>ct_run</c>, see <seealso marker="ct_run#ct_run">Run Tests from + Command Line</seealso> in the <c>ct_run</c> manual page.</p> + <p>Here a <c>TestDir</c> can be used to point out the path to a + <c>Suite</c>. Option <c>testcase</c> corresponds to option + <c>-case</c> in program <c>ct_run</c>. Configuration files + specified in <c>Opts</c> are installed automatically at startup.</p> + + <p><c>TestRunnerPid</c> is returned if <c>release_shell == true</c>. + For details, see + <seealso marker="#break-1"><c>ct:break/1</c></seealso>.</p> + + <p><c>Reason</c> indicates the type of error encountered.</p> + </desc> + </func> + + <func> + <name>run_testspec(TestSpec) -> Result</name> + <fsummary>Runs a test specified by TestSpec.</fsummary> + <type> + <v>TestSpec = [term()]</v> + <v>Result = {Ok, Failed, {UserSkipped, AutoSkipped}} | {error, Reason}</v> + <v>Ok = integer()</v> + <v>Failed = integer()</v> + <v>UserSkipped = integer()</v> + <v>AutoSkipped = integer()</v> + <v>Reason = term()</v> + </type> + <desc><marker id="run_testspec-1"/> + <p>Runs a test specified by <c>TestSpec</c>. The same terms are used + as in test specification files.</p> + + <p><c>Reason</c> indicates the type of error encountered.</p> + </desc> + </func> + + <func> + <name>sleep(Time) -> ok</name> + <fsummary>This function, similar to timer:sleep/1, suspends the + test case for a specified time.</fsummary> + <type> + <v>Time = {hours, Hours} | {minutes, Mins} | {seconds, Secs} | Millisecs | infinity</v> + <v>Hours = integer()</v> + <v>Mins = integer()</v> + <v>Secs = integer()</v> + <v>Millisecs = integer() | float()</v> + </type> + <desc><marker id="sleep-1"/> + <p>This function, similar to <c>timer:sleep/1</c> in <c>STDLIB</c>, + suspends the test case for a specified time. + However, this function also multiplies <c>Time</c> with the + <c>multiply_timetraps</c> value (if set) and under certain + circumstances also scales up the time automatically if + <c>scale_timetraps</c> is set to <c>true</c> (default is + <c>false</c>).</p> + </desc> + </func> + + <func> + <name>start_interactive() -> ok</name> + <fsummary>Starts <c>Common Test</c> in interactive mode.</fsummary> + <desc><marker id="start_interactive-0"/> + <p>Starts <c>Common Test</c> in interactive mode.</p> + + <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 <c>ct_run -shell + [-config File...]</c>.</p> + + <p>If any functions (for example, Telnet or FTP) using + "required configuration data" are to be called from the Erlang shell, + configuration data must first be required with + <seealso marker="#require-2"><c>ct:require/2</c></seealso>.</p> + + <p><em>Example:</em></p> + + <pre> + > ct:require(unix_telnet, unix). + ok + > ct_telnet:open(unix_telnet). + {ok,<0.105.0>} + > ct_telnet:cmd(unix_telnet, "ls ."). + {ok,["ls","file1 ...",...]}</pre> + </desc> + </func> + + <func> + <name>step(TestDir, Suite, Case) -> Result</name> + <fsummary>Steps through a test case with the debugger.</fsummary> + <type> + <v>Case = atom()</v> + </type> + <desc><marker id="step-3"/> + <p>Steps through a test case with the debugger.</p> + + <p>See also <seealso marker="#run-3"><c>ct:run/3</c></seealso>.</p> + </desc> + </func> + + <func> + <name>step(TestDir, Suite, Case, Opts) -> Result</name> + <fsummary>Steps through a test case with the debugger.</fsummary> + <type> + <v>Case = atom()</v> + <v>Opts = [Opt] | []</v> + <v>Opt = config | keep_inactive</v> + </type> + <desc><marker id="step-4"/> + <p>Steps through a test case with the debugger. If option + <c>config</c> has been specifed, breakpoints are also set on + the configuration functions in <c>Suite</c>.</p> + + <p>See also <seealso marker="#run-3"><c>ct:run/3</c></seealso>.</p> + </desc> + </func> + + <func> + <name>stop_interactive() -> ok</name> + <fsummary>Exits the interactive mode.</fsummary> + <desc><marker id="stop_interactive-0"/> + <p>Exits the interactive mode.</p> + + <p>See also + <seealso marker="#start_interactive-0"><c>ct:start_interactive/0</c></seealso>. + </p> + </desc> + </func> + + <func> + <name>sync_notify(Name, Data) -> ok</name> + <fsummary>Sends a synchronous notification of type Name with Data to + the <c>Common Test</c> event manager.</fsummary> + <type> + <v>Name = atom()</v> + <v>Data = term()</v> + </type> + <desc><marker id="sync_notify-2"/> + <p>Sends a synchronous notification of type <c>Name</c> with + <c>Data</c> to the <c>Common Test</c> event manager. This can later be + caught by any installed event manager.</p> + + <p>See also + <seealso marker="stdlib:gen_event"><c>stdlib:gen_event(3)</c></seealso>. + </p> + </desc> + </func> + + <func> + <name>testcases(TestDir, Suite) -> Testcases | {error, Reason}</name> + <fsummary>Returns all test cases in the specified suite.</fsummary> + <type> + <v>TestDir = string()</v> + <v>Suite = atom()</v> + <v>Testcases = list()</v> + <v>Reason = term()</v> + </type> + <desc><marker id="testcases-2"/> + <p>Returns all test cases in the specified suite.</p> + </desc> + </func> + + <func> + <name>timetrap(Time) -> ok</name> + <fsummary>Sets a new timetrap for the running test case.</fsummary> + <type> + <v>Time = {hours, Hours} | {minutes, Mins} | {seconds, Secs} | Millisecs | infinity | Func</v> + <v>Hours = integer()</v> + <v>Mins = integer()</v> + <v>Secs = integer()</v> + <v>Millisecs = integer() | float()</v> + <v>Func = {M, F, A} | function()</v> + <v>M = atom()</v> + <v>F = atom()</v> + <v>A = list()</v> + </type> + <desc><marker id="timetrap-1"/> + <p>Sets a new timetrap for the running test case.</p> + + <p>If the argument is <c>Func</c>, the timetrap is triggered when + this function returns. <c>Func</c> can also return a new + <c>Time</c> value, which in that case is the value for the new + timetrap.</p> + </desc> + </func> + + <func> + <name>userdata(TestDir, Suite) -> SuiteUserData | {error, Reason}</name> + <fsummary>Returns any data specified with tag userdata in the list of + tuples returned from Suite:suite/0.</fsummary> + <type> + <v>TestDir = string()</v> + <v>Suite = atom()</v> + <v>SuiteUserData = [term()]</v> + <v>Reason = term()</v> + </type> + <desc><marker id="userdata-2"/> + <p>Returns any data specified with tag <c>userdata</c> in the list + of tuples returned from + <seealso marker="common_test#Module:suite-0"><c>suite/0</c></seealso>.</p> + </desc> + </func> + + <func> + <name>userdata(TestDir, Suite, Case::GroupOrCase) -> TCUserData | {error, Reason}</name> + <fsummary>Returns any data specified with tag userdata in the list of + tuples returned from Suite:group(GroupName) or Suite:Case().</fsummary> + <type> + <v>TestDir = string()</v> + <v>Suite = atom()</v> + <v>GroupOrCase = {group, GroupName} | atom()</v> + <v>GroupName = atom()</v> + <v>TCUserData = [term()]</v> + <v>Reason = term()</v> + </type> + <desc><marker id="userdata-3"/> + <p>Returns any data specified with tag <c>userdata</c> in the list + of tuples returned from <c>Suite:group(GroupName)</c> or + <c>Suite:Case()</c>.</p> + </desc> + </func> + </funcs> + +</erlref> + + diff --git a/lib/common_test/doc/src/ct_cover.xml b/lib/common_test/doc/src/ct_cover.xml new file mode 100644 index 0000000000..be09c08a68 --- /dev/null +++ b/lib/common_test/doc/src/ct_cover.xml @@ -0,0 +1,106 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2010</year><year>2012</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + </legalnotice> + + <title>ct_cover</title> + <prepared></prepared> + <responsible></responsible> + <docno></docno> + <approved></approved> + <checked></checked> + <date></date> + <rev>A</rev> + <file>ct_cover.xml</file> + </header> + <module>ct_cover</module> + <modulesummary>Common Test framework code coverage support module. + </modulesummary> + +<description> + + <p><c>Common Test</c> framework code coverage support module.</p> + + <p>This module exports help functions for performing code coverage + analysis.</p> + +</description> + + <funcs> + <func> + <name>add_nodes(Nodes) -> {ok, StartedNodes} | {error, Reason}</name> + <fsummary>Adds nodes to current cover test (only works if cover support + is active).</fsummary> + <type> + <v>Nodes = [atom()]</v> + <v>StartedNodes = [atom()]</v> + <v>Reason = cover_not_running | not_main_node</v> + </type> + <desc><marker id="add_nodes-1"/> + <p>Adds nodes to current cover test. Notice that this only works if + cover support is active.</p> + + <p>To have effect, this function is to be called from + <c>init_per_suite/1</c> (see + <seealso marker="common_test"><c>common_test</c></seealso>) + before any tests are performed.</p> + </desc> + </func> + + <func> + <name>cross_cover_analyse(Level, Tests) -> ok</name> + <fsummary>Accumulates cover results over multiple tests.</fsummary> + <type> + <v>Level = overview | details</v> + <v>Tests = [{Tag, Dir}]</v> + <v>Tag = atom()</v> + <v>Dir = string()</v> + </type> + <desc><marker id="cross_cover_analyse-2"/> + <p>Accumulates cover results over multiple tests. See section + <seealso marker="cover_chapter#cross_cover">Cross Cover + Analysis</seealso> in the Users's Guide.</p> + </desc> + </func> + + <func> + <name>remove_nodes(Nodes) -> ok | {error, Reason}</name> + <fsummary>Removes nodes from the current cover test.</fsummary> + <type> + <v>Nodes = [atom()]</v> + <v>Reason = cover_not_running | not_main_node</v> + </type> + <desc><marker id="remove_nodes-1"/> + <p>Removes nodes from the current cover test.</p> + + <p>Call this function to stop cover test on nodes previously + added with + <seealso marker="#add_nodes-1"><c>ct_cover:add_nodes/1</c></seealso>. + Results on the remote node are transferred to the <c>Common Test</c> + node.</p> + </desc> + </func> + </funcs> + +</erlref> + + diff --git a/lib/common_test/doc/src/ct_ftp.xml b/lib/common_test/doc/src/ct_ftp.xml new file mode 100644 index 0000000000..0598dcbe3e --- /dev/null +++ b/lib/common_test/doc/src/ct_ftp.xml @@ -0,0 +1,277 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2010</year><year>2012</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + </legalnotice> + + <title>ct_ftp</title> + <prepared></prepared> + <responsible></responsible> + <docno></docno> + <approved></approved> + <checked></checked> + <date></date> + <rev>A</rev> + <file>ct_ftp.xml</file> + </header> + <module>ct_ftp</module> + <modulesummary>FTP client module (based on the FTP support of the Inets + application).</modulesummary> + + <description> + + <p>FTP client module (based on the FTP support of the <c>Inets</c> + application).</p> + + </description> + + <section> + <title>Data Types</title> + <marker id="types"/> + <taglist> + <tag><c>connection() = handle() | target_name()</c></tag> + <item><marker id="type-connection"/> + <p>For <c>target_name</c>, see module + <seealso marker="ct"><c>ct</c></seealso>.</p></item> + + <tag><c>handle() = handle()</c></tag> + <item><marker id="type-handle"/> + <p>Handle for a specific FTP connection, see module + <seealso marker="ct"><c>ct</c></seealso>.</p></item> + </taglist> + </section> + + <funcs> + <func> + <name>cd(Connection, Dir) -> ok | {error, Reason}</name> + <fsummary>Changes directory on remote host.</fsummary> + <type> + <v>Connection = connection()</v> + <v>Dir = string()</v> + </type> + <desc><marker id="cd-2"/> + <p>Changes directory on remote host.</p> + </desc> + </func> + + <func> + <name>close(Connection) -> ok | {error, Reason}</name> + <fsummary>Closes the FTP connection.</fsummary> + <type> + <v>Connection = connection()</v> + </type> + <desc><marker id="close-1"/> + <p>Closes the FTP connection.</p> + </desc> + </func> + + <func> + <name>delete(Connection, File) -> ok | {error, Reason}</name> + <fsummary>Deletes a file on remote host.</fsummary> + <type> + <v>Connection = connection()</v> + <v>File = string()</v> + </type> + <desc><marker id="delete-2"/> + <p>Deletes a file on remote host.</p> + </desc> + </func> + + <func> + <name>get(KeyOrName, RemoteFile, LocalFile) -> ok | {error, Reason}</name> + <fsummary>Opens an FTP connection and fetches a file from the remote + host.</fsummary> + <type> + <v>KeyOrName = Key | Name</v> + <v>Key = atom()</v> + <v>Name = target_name()</v> + <v>RemoteFile = string()</v> + <v>LocalFile = string()</v> + </type> + <desc><marker id="get-3"/> + <p>Opens an FTP connection and fetches a file from the remote + host.</p> + + <p><c>RemoteFile</c> and <c>LocalFile</c> must be absolute paths.</p> + + <p>The configuration file must be as for + <seealso marker="#put-3"><c>ct_ftp:put/3</c></seealso>.</p> + + <p>For <c>target_name</c>, see module + <seealso marker="ct"><c>ct</c></seealso>.</p> + + <p>See also + <seealso marker="ct#require-2"><c>ct:require/2</c></seealso>.</p> + </desc> + </func> + + <func> + <name>ls(Connection, Dir) -> {ok, Listing} | {error, Reason}</name> + <fsummary>Lists directory Dir.</fsummary> + <type> + <v>Connection = connection()</v> + <v>Dir = string()</v> + <v>Listing = string()</v> + </type> + <desc><marker id="ls-2"/> + <p>Lists directory <c>Dir</c>.</p> + </desc> + </func> + + <func> + <name>open(KeyOrName) -> {ok, Handle} | {error, Reason}</name> + <fsummary>Opens an FTP connection to the specified node.</fsummary> + <type> + <v>KeyOrName = Key | Name</v> + <v>Key = atom()</v> + <v>Name = target_name()</v> + <v>Handle = handle()</v> + </type> + <desc><marker id="open-1"/> + <p>Opens an FTP connection to the specified node.</p> + + <p>You can open a connection for a particular <c>Name</c> and use the + same name as reference for all following subsequent operations. + If you want + the connection to be associated with <c>Handle</c> instead (if you, + for example, need to open multiple connections to a host), use + <c>Key</c>, the configuration variable name, to specify the target. + A connection without an associated target name can only be closed + with the handle value.</p> + + <p>For information on how to create a new <c>Name</c>, see + <seealso marker="ct#require-2"><c>ct:require/2</c></seealso>.</p> + + <p>For <c>target_name</c>, see module + <seealso marker="ct"><c>ct</c></seealso>.</p> + </desc> + </func> + + <func> + <name>put(KeyOrName, LocalFile, RemoteFile) -> ok | {error, Reason}</name> + <fsummary>Opens an FTP connection and sends a file to the remote + host.</fsummary> + <type> + <v>KeyOrName = Key | Name</v> + <v>Key = atom()</v> + <v>Name = target_name()</v> + <v>LocalFile = string()</v> + <v>RemoteFile = string()</v> + </type> + <desc><marker id="put-3"/> + <p>Opens an FTP connection and sends a file to the remote host.</p> + + <p><c>LocalFile</c> and <c>RemoteFile</c> must be absolute paths.</p> + + <p>For <c>target_name</c>, see module + <seealso marker="ct"><c>ct</c></seealso>.</p> + + <p>If the target host is a "special" node, the FTP address must be + specified in the configuration file as follows:</p> + + <pre> + {node,[{ftp,IpAddr}]}.</pre> + + <p>If the target host is something else, for example, a UNIX host, + the configuration file must also include the username and password + (both strings):</p> + + <pre> + {unix,[{ftp,IpAddr}, + {username,Username}, + {password,Password}]}.</pre> + + <p>See also + <seealso marker="ct#require-2"><c>ct:require/2</c></seealso>.</p> + </desc> + </func> + + <func> + <name>recv(Connection, RemoteFile) -> ok | {error, Reason}</name> + <fsummary>Fetches a file over FTP.</fsummary> + <desc><marker id="recv-2"/> + <p>Fetches a file over FTP.</p> + + <p>The file gets the same name on the local host.</p> + + <p>See also <seealso marker="#recv-3"><c>ct_ftp:recv/3</c></seealso>.</p> + </desc> + </func> + + <func> + <name>recv(Connection, RemoteFile, LocalFile) -> ok | {error, Reason}</name> + <fsummary>Fetches a file over FTP.</fsummary> + <type> + <v>Connection = connection()</v> + <v>RemoteFile = string()</v> + <v>LocalFile = string()</v> + </type> + <desc><marker id="recv-3"/> + <p>Fetches a file over FTP.</p> + + <p>The file is named <c>LocalFile</c> on the local host.</p> + </desc> + </func> + + <func> + <name>send(Connection, LocalFile) -> ok | {error, Reason}</name> + <fsummary>Sends a file over FTP.</fsummary> + <desc><marker id="send-2"/> + <p>Sends a file over FTP.</p> + + <p>The file gets the same name on the remote host.</p> + + <p>See also + <seealso marker="#send-3"><c>ct_ftp:send/3</c></seealso>.</p> + </desc> + </func> + + <func> + <name>send(Connection, LocalFile, RemoteFile) -> ok | {error, Reason}</name> + <fsummary>Sends a file over FTP.</fsummary> + <type> + <v>Connection = connection()</v> + <v>LocalFile = string()</v> + <v>RemoteFile = string()</v> + </type> + <desc><marker id="send-3"/> + <p>Sends a file over FTP.</p> + + <p>The file is named <c>RemoteFile</c> on the remote host.</p> + </desc> + </func> + + <func> + <name>type(Connection, Type) -> ok | {error, Reason}</name> + <fsummary>Changes the file transfer type.</fsummary> + <type> + <v>Connection = connection()</v> + <v>Type = ascii | binary</v> + </type> + <desc><marker id="type-2"/> + <p>Changes the file transfer type.</p> + </desc> + </func> + </funcs> + +</erlref> + + diff --git a/lib/common_test/doc/src/ct_hooks.xml b/lib/common_test/doc/src/ct_hooks.xml index a9f9450dd7..12ec3bcec3 100644 --- a/lib/common_test/doc/src/ct_hooks.xml +++ b/lib/common_test/doc/src/ct_hooks.xml @@ -1,5 +1,4 @@ <?xml version="1.0" encoding="UTF-8" ?> - <!DOCTYPE erlref SYSTEM "erlref.dtd"> <erlref> @@ -12,7 +11,7 @@ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software @@ -34,539 +33,572 @@ <file>ct_hooks.sgml</file> </header> <module>ct_hooks</module> - <modulesummary>A callback interface on top of Common Test</modulesummary> + <modulesummary>A callback interface on top of Common Test.</modulesummary> <description> - <p>The <em>Common Test Hook</em> (henceforth called CTH) framework allows - extensions of the default behaviour of Common Test by means of callbacks - before and after all test suite calls. It is meant for advanced users of - Common Test which want to abstract out behaviour which is common to - multiple test suites. </p> + <p>The <em>Common Test Hook (CTH)</em> framework allows extensions of the + default behavior of <c>Common Test</c> by callbacks before and after all + test suite calls. It is intended for advanced users of <c>Common Test</c> + who want to abstract out behavior that is common to multiple test suites. + </p> - <p>In brief, Common Test Hooks allows you to:</p> + <p>In brief, CTH allows you to:</p> - <list> - <item>Manipulate the runtime config before each suite - configuration call</item> - <item>Manipulate the return of all suite configuration calls and in - extension the result of the test themselves.</item> + <list type="bulleted"> + <item><p>Manipulate the runtime configuration before each suite + configuration call.</p></item> + <item><p>Manipulate the return of all suite configuration calls and by + extension the result of the test themselves.</p></item> </list> <p>The following sections describe the mandatory and optional CTH - functions Common Test will call during test execution. For more details - see <seealso marker="ct_hooks_chapter">Common Test Hooks</seealso> in - the User's Guide.</p> + functions that <c>Common Test</c> calls during test execution. + For more details, see section + <seealso marker="ct_hooks_chapter">Common Test Hooks</seealso> in the + User's Guide.</p> - <p>For information about how to add a CTH to your suite see - <seealso marker="ct_hooks_chapter#installing">Installing a CTH - </seealso> in the User's Guide.</p> + <p>For information about how to add a CTH to your suite, see section + <seealso marker="ct_hooks_chapter#installing">Installing a CTH</seealso> + in the User's Guide.</p> + + <note><p>For a minimal example of a CTH, see section + <seealso marker="ct_hooks_chapter#example">Example CTH</seealso> + in the User's Guide.</p></note> - <note><p>See the - <seealso marker="ct_hooks_chapter#example">Example CTH</seealso> - in the User's Guide for a minimal example of a CTH. </p></note> - </description> <section> - <title>CALLBACK FUNCTIONS</title> - <p>The following functions define the callback interface - for a Common Test Hook.</p> + <title>Callback Functions</title> + <p>The following functions define the callback interface for a CTH.</p> </section> <funcs> <func> - <name>Module:init(Id, Opts) -> {ok, State} | - {ok, State, Priority}</name> - <fsummary>Initiates the Common Test Hook</fsummary> + <name>Module:init(Id, Opts) -> {ok, State} | {ok, State, Priority}</name> + <fsummary>Initiates the Common Test Hook.</fsummary> <type> - <v>Id = reference() | term()</v> - <v>Opts = term()</v> - <v>State = term()</v> - <v>Priority = integer()</v> + <v>Id = reference() | term()</v> + <v>Opts = term()</v> + <v>State = term()</v> + <v>Priority = integer()</v> </type> - <desc> - <p> MANDATORY </p> - - <p>Always called before any other callback function. - Use this to initiate any common state. - It should return a state for this CTH.</p> - - <p><c>Id</c> is the return value of - <seealso marker="#Module:id-1">id/1</seealso>, or a <c>reference</c> - (created using - <seealso marker="erts:erlang#make_ref-0">make_ref/0</seealso>) - if <seealso marker="#Module:id-1">id/1</seealso> is not implemented. - </p> - - <p><c>Priority</c> is the relative priority of this hook. Hooks with a - lower priority will be executed first. If no priority is given, - it will be set to 0. </p> - - <p>For details about when init is called see - <seealso marker="ct_hooks_chapter#scope">scope</seealso> - in the User's Guide.</p> - + <p>MANDATORY</p> + + <p>This function is always called before any other callback function. + Use it to initiate any common state. It is to return a state for + this CTH.</p> + + <p><c>Id</c> is either the return value of + <seealso marker="#Module:id-1"><c>ct_hooks:id/1</c></seealso>, + or a <c>reference</c> (created using + <seealso marker="erts:erlang#make_ref-0">erlang:make_ref/0</seealso> + in <c>ERTS</c>) if + <seealso marker="#Module:id-1"><c>ct_hooks:id/1</c></seealso> + is not implemented.</p> + + <p><c>Priority</c> is the relative priority of this hook. Hooks with a + lower priority are executed first. If no priority is specified, it + is set to <c>0</c>.</p> + + <p>For details about when <c>init</c> is called, see section + <seealso marker="ct_hooks_chapter#scope">CTH Scope</seealso> + in the User's Guide.</p> </desc> </func> <func> - <name>Module:pre_init_per_suite(SuiteName, InitData, CTHState) -> - Result</name> - <fsummary>Called before init_per_suite</fsummary> + <name>Module:pre_init_per_suite(SuiteName, InitData, CTHState) -> Result</name> + <fsummary>Called before init_per_suite.</fsummary> <type> - <v>SuiteName = atom()</v> - <v>InitData = Config | SkipOrFail</v> - <v>Config = NewConfig = [{Key,Value}]</v> - <v>CTHState = NewCTHState = term()</v> - <v>Result = {Return, NewCTHState}</v> - <v>Return = NewConfig | SkipOrFail</v> - <v>SkipOrFail = {fail, Reason} | {skip, Reason}</v> - <v>Key = atom()</v> - <v>Value = term()</v> - <v>Reason = term()</v> + <v>SuiteName = atom()</v> + <v>InitData = Config | SkipOrFail</v> + <v>Config = NewConfig = [{Key,Value}]</v> + <v>CTHState = NewCTHState = term()</v> + <v>Result = {Return, NewCTHState}</v> + <v>Return = NewConfig | SkipOrFail</v> + <v>SkipOrFail = {fail, Reason} | {skip, Reason}</v> + <v>Key = atom()</v> + <v>Value = term()</v> + <v>Reason = term()</v> </type> - <desc> - <p> OPTIONAL </p> - - <p>This function is called before - <seealso marker="common_test#Module:init_per_suite-1"> - init_per_suite</seealso> if it exists. - It typically contains initialization/logging which needs to be done - before init_per_suite is called. - If <c>{skip,Reason}</c> or <c>{fail,Reason}</c> is returned, - init_per_suite and all test cases of the suite will be skipped and - Reason printed in the overview log of the suite.</p> - - <p><c>SuiteName</c> is the name of the suite to be run.</p> - - <p><c>InitData</c> is the original config list of the test suite, or - a <c>SkipOrFail</c> tuple if a previous CTH has returned this.</p> - - <p><c>CTHState</c> is the current internal state of the CTH.</p> - - <p><c>Return</c> is the result of the init_per_suite function. - If it is <c>{skip,Reason}</c> or <c>{fail,Reason}</c> - <seealso marker="common_test#Module:init_per_suite-1">init_per_suite - </seealso> will never be called, instead the initiation is considered - to be skipped/failed respectively. If a <c>NewConfig</c> list - is returned, <seealso marker="common_test#Module:init_per_suite-1"> - init_per_suite</seealso> will be called with that <c>NewConfig</c> list. - See <seealso marker="ct_hooks_chapter#pre"> - Pre Hooks</seealso> in the User's Guide for more details.</p> - - - <p>Note that this function is only called if the CTH has been added - before init_per_suite is run, see - <seealso marker="ct_hooks_chapter#scope">CTH Scoping</seealso> - in the User's Guide for details.</p> + <p>OPTIONAL</p> + + <p>This function is called before + <seealso marker="common_test#Module:init_per_suite-1"><c>init_per_suite</c></seealso> + if it exists. It typically contains initialization/logging that must + be done before <c>init_per_suite</c> is called. If + <c>{skip,Reason}</c> or <c>{fail,Reason}</c> is returned, + <c>init_per_suite</c> and all test cases of the suite are skipped + and <c>Reason</c> printed in the overview log of the suite.</p> + + <p><c>SuiteName</c> is the name of the suite to be run.</p> + + <p><c>InitData</c> is the original configuration list of the test + suite, or a <c>SkipOrFail</c> tuple if a previous CTH has returned + this.</p> + + <p><c>CTHState</c> is the current internal state of the CTH.</p> + + <p><c>Return</c> is the result of the <c>init_per_suite</c> function. + If it is <c>{skip,Reason}</c> or <c>{fail,Reason}</c>, + <seealso marker="common_test#Module:init_per_suite-1"><c>init_per_suite</c></seealso> + is never called, instead the initiation is considered to be + skipped or failed, respectively. If a <c>NewConfig</c> list is + returned, + <seealso marker="common_test#Module:init_per_suite-1"><c>init_per_suite</c></seealso> + is called with that <c>NewConfig</c> list. For more details, see + section <seealso marker="ct_hooks_chapter#pre">Pre Hooks</seealso> + in the User's Guide.</p> + + <p>This function is called only if the CTH is added before + <c>init_per_suite is run</c>. For details, see section + <seealso marker="ct_hooks_chapter#scope">CTH Scope</seealso> + in the User's Guide.</p> </desc> </func> - + <func> - <name>Module:post_init_per_suite(SuiteName, Config, Return, CTHState) -> - Result</name> - <fsummary>Called after init_per_suite</fsummary> + <name>Module:post_init_per_suite(SuiteName, Config, Return, CTHState) -> Result</name> + <fsummary>Called after init_per_suite.</fsummary> <type> - <v>SuiteName = atom()</v> - <v>Config = [{Key,Value}]</v> - <v>Return = NewReturn = Config | SkipOrFail | term()</v> - <v>SkipOrFail = {fail, Reason} | {skip, Reason} | term()</v> - <v>CTHState = NewCTHState = term()</v> - <v>Result = {NewReturn, NewCTHState}</v> - <v>Key = atom()</v> - <v>Value = term()</v> - <v>Reason = term()</v> + <v>SuiteName = atom()</v> + <v>Config = [{Key,Value}]</v> + <v>Return = NewReturn = Config | SkipOrFail | term()</v> + <v>SkipOrFail = {fail, Reason} | {skip, Reason} | term()</v> + <v>CTHState = NewCTHState = term()</v> + <v>Result = {NewReturn, NewCTHState}</v> + <v>Key = atom()</v> + <v>Value = term()</v> + <v>Reason = term()</v> </type> - <desc> - <p> OPTIONAL </p> + <p>OPTIONAL</p> + + <p>This function is called after + <seealso marker="common_test#Module:init_per_suite-1"><c>init_per_suite</c></seealso> + if it exists. It typically contains extra checks to ensure that all + the correct dependencies are started correctly.</p> + + <p><c>Return</c> is what + <seealso marker="common_test#Module:init_per_suite-1"><c>init_per_suite</c></seealso> + returned, that is, <c>{fail,Reason}</c>, <c>{skip,Reason}</c>, a + <c>Config</c> list, or a term describing how + <seealso marker="common_test#Module:init_per_suite-1"><c>init_per_suite</c></seealso> + failed.</p> + + <p><c>NewReturn</c> is the possibly modified return value of + <seealso marker="common_test#Module:init_per_suite-1"><c>init_per_suite</c></seealso>. + To recover from a failure in + <seealso marker="common_test#Module:init_per_suite-1"><c>init_per_suite</c></seealso>, + return <c>ConfigList</c> with the <c>tc_status</c> element removed. + For more details, see + <seealso marker="ct_hooks_chapter#post"> Post Hooks</seealso> in + section "Manipulating Tests" in the User's Guide.</p> + + <p><c>CTHState</c> is the current internal state of the CTH.</p> + + <p>This function is called only if the CTH is added before or in + <c>init_per_suite</c>. For details, see section + <seealso marker="ct_hooks_chapter#scope">CTH Scope</seealso> + in the User's Guide.</p> + </desc> + </func> - <p>This function is called after - <seealso marker="common_test#Module:init_per_suite-1"> - init_per_suite</seealso> if it exists. It typically contains extra - checks to make sure that all the correct dependencies have - been started correctly.</p> - - <p><c>Return</c> is what - <seealso marker="common_test#Module:init_per_suite-1">init_per_suite - </seealso> returned, i.e. {fail,Reason}, {skip,Reason}, a <c>Config</c> - list or a term describing how - <seealso marker="common_test#Module:init_per_suite-1">init_per_suite - </seealso> failed.</p> - - <p><c>NewReturn</c> is the possibly modified return value of - <seealso marker="common_test#Module:init_per_suite-1">init_per_suite - </seealso>. It is here possible to recover from a failure in - <seealso marker="common_test#Module:init_per_suite-1">init_per_suite - </seealso> by returning the <c>ConfigList</c> with the <c>tc_status</c> - element removed. See <seealso marker="ct_hooks_chapter#post"> - Post Hooks</seealso> in the User's Guide for more details.</p> - - <p><c>CTHState</c> is the current internal state of the CTH.</p> - - <p>Note that this function is only called if the CTH has been added - before or in init_per_suite, see - <seealso marker="ct_hooks_chapter#scope">CTH Scoping</seealso> - in the User's Guide for details.</p> + <func> + <name>Module:pre_init_per_group(GroupName, InitData, CTHState) -> Result</name> + <fsummary>Called before init_per_group.</fsummary> + <type> + <v>GroupName = atom()</v> + <v>InitData = Config | SkipOrFail</v> + <v>Config = NewConfig = [{Key,Value}]</v> + <v>CTHState = NewCTHState = term()</v> + <v>Result = {NewConfig | SkipOrFail, NewCTHState}</v> + <v>SkipOrFail = {fail,Reason} | {skip, Reason}</v> + <v>Key = atom()</v> + <v>Value = term()</v> + <v>Reason = term()</v> + </type> + <desc> + <p>OPTIONAL</p> + + <p>This function is called before + <seealso marker="common_test#Module:init_per_group-2"><c>init_per_group</c></seealso> + if it exists. It behaves the same way as + <seealso marker="ct_hooks#Module:pre_init_per_suite-3"><c>pre_init_per_suite</c></seealso>, + but for function + <seealso marker="common_test#Module:init_per_group-2"><c>init_per_group</c></seealso> + instead.</p> </desc> </func> - + <func> - <name>Module:pre_init_per_group(GroupName, InitData, CTHState) -> - Result</name> - <fsummary>Called before init_per_group</fsummary> + <name>Module:post_init_per_group(GroupName, Config, Return, CTHState) -> Result</name> + <fsummary>Called after init_per_group.</fsummary> <type> - <v>GroupName = atom()</v> - <v>InitData = Config | SkipOrFail</v> - <v>Config = NewConfig = [{Key,Value}]</v> - <v>CTHState = NewCTHState = term()</v> - <v>Result = {NewConfig | SkipOrFail, NewCTHState}</v> - <v>SkipOrFail = {fail,Reason} | {skip, Reason}</v> - <v>Key = atom()</v> - <v>Value = term()</v> - <v>Reason = term()</v> + <v>GroupName = atom()</v> + <v>Config = [{Key,Value}]</v> + <v>Return = NewReturn = Config | SkipOrFail | term()</v> + <v>SkipOrFail = {fail,Reason} | {skip, Reason}</v> + <v>CTHState = NewCTHState = term()</v> + <v>Result = {NewReturn, NewCTHState}</v> + <v>Key = atom()</v> + <v>Value = term()</v> + <v>Reason = term()</v> </type> - <desc> - <p> OPTIONAL </p> - - <p>This function is called before - <seealso marker="common_test#Module:init_per_group-2"> - init_per_group</seealso> if it exists. It behaves the same way as - <seealso marker="ct_hooks#Module:pre_init_per_suite-3"> - pre_init_per_suite</seealso>, but for the - <seealso marker="common_test#Module:init_per_group-2"> - init_per_group</seealso> instead.</p> + <p>OPTIONAL</p> + + <p>This function is called after + <seealso marker="common_test#Module:init_per_group-2"><c>init_per_group</c></seealso> + if it exists. It behaves the same way as + <seealso marker="ct_hooks#Module:post_init_per_suite-4"><c>post_init_per_suite</c></seealso>, + but for function + <seealso marker="common_test#Module:init_per_group-2"><c>init_per_group</c></seealso> + instead.</p> </desc> </func> - + <func> - <name>Module:post_init_per_group(GroupName, Config, Return, CTHState) -> - Result</name> - <fsummary>Called after init_per_group</fsummary> + <name>Module:pre_init_per_testcase(TestcaseName, InitData, CTHState) -> Result</name> + <fsummary>Called before init_per_testcase.</fsummary> <type> - <v>GroupName = atom()</v> - <v>Config = [{Key,Value}]</v> - <v>Return = NewReturn = Config | SkipOrFail | term()</v> - <v>SkipOrFail = {fail,Reason} | {skip, Reason}</v> - <v>CTHState = NewCTHState = term()</v> - <v>Result = {NewReturn, NewCTHState}</v> - <v>Key = atom()</v> - <v>Value = term()</v> - <v>Reason = term()</v> + <v>TestcaseName = atom()</v> + <v>InitData = Config | SkipOrFail</v> + <v>Config = NewConfig = [{Key,Value}]</v> + <v>CTHState = NewCTHState = term()</v> + <v>Result = {NewConfig | SkipOrFail, NewCTHState}</v> + <v>SkipOrFail = {fail,Reason} | {skip, Reason}</v> + <v>Key = atom()</v> + <v>Value = term()</v> + <v>Reason = term()</v> </type> - <desc> - <p> OPTIONAL </p> - - <p>This function is called after - <seealso marker="common_test#Module:init_per_group-2"> - init_per_group</seealso> if it exists. It behaves the same way as - <seealso marker="ct_hooks#Module:post_init_per_suite-4"> - post_init_per_suite</seealso>, but for the - <seealso marker="common_test#Module:init_per_group-2"> - init_per_group</seealso> instead.</p> + <p>OPTIONAL</p> + + <p>This function is called before + <seealso marker="common_test#Module:init_per_testcase-2"><c>init_per_testcase</c></seealso> + if it exists. It behaves the same way as + <seealso marker="ct_hooks#Module:pre_init_per_suite-3"><c>pre_init_per_suite</c></seealso>, + but for function + <seealso marker="common_test#Module:init_per_testcase-2"><c>init_per_testcase</c></seealso> + instead.</p> + + <p>CTHs cannot be added here right now. That feature may be added in + a later release, but it would right now break backwards + compatibility.</p> </desc> </func> <func> - <name>Module:pre_init_per_testcase(TestcaseName, InitData, CTHState) -> - Result</name> - <fsummary>Called before init_per_testcase</fsummary> + <name>Module:post_init_per_testcase(TestcaseName, Config, Return, CTHState) -> Result</name> + <fsummary>Called after init_per_testcase.</fsummary> <type> - <v>TestcaseName = atom()</v> - <v>InitData = Config | SkipOrFail</v> - <v>Config = NewConfig = [{Key,Value}]</v> - <v>CTHState = NewCTHState = term()</v> - <v>Result = {NewConfig | SkipOrFail, NewCTHState}</v> - <v>SkipOrFail = {fail,Reason} | {skip, Reason}</v> - <v>Key = atom()</v> - <v>Value = term()</v> - <v>Reason = term()</v> + <v>TestcaseName = atom()</v> + <v>Config = [{Key,Value}]</v> + <v>Return = NewReturn = Config | SkipOrFail | term()</v> + <v>SkipOrFail = {fail,Reason} | {skip, Reason}</v> + <v>CTHState = NewCTHState = term()</v> + <v>Result = {NewReturn, NewCTHState}</v> + <v>Key = atom()</v> + <v>Value = term()</v> + <v>Reason = term()</v> </type> - <desc> - <p> OPTIONAL </p> - - <p>This function is called before - <seealso marker="common_test#Module:init_per_testcase-2"> - init_per_testcase</seealso> if it exists. It behaves the same way as - <seealso marker="ct_hooks#Module:pre_init_per_suite-3"> - pre_init_per_suite</seealso>, but for the - <seealso marker="common_test#Module:init_per_testcase-2"> - init_per_testcase</seealso> function instead.</p> - - <p>Note that it is not possible to add CTH's here right now, - that feature might be added later, - but it would right now break backwards compatibility.</p> + <p>OPTIONAL</p> + + <p>This function is called after + <seealso marker="common_test#Module:init_per_testcase-2"><c>init_per_testcase</c></seealso> + if it exists. It behaves the same way as + <seealso marker="ct_hooks#Module:post_init_per_suite-4"><c>post_init_per_suite</c></seealso>, + but for function + <seealso marker="common_test#Module:init_per_testcase-2"><c>init_per_testcase</c></seealso> + instead.</p> </desc> </func> <func> - <name>Module:post_end_per_testcase(TestcaseName, Config, Return, CTHState) - -> Result</name> - <fsummary>Called after end_per_testcase</fsummary> + <name>Module:pre_end_per_testcase(TestcaseName, InitData, CTHState) -> Result</name> + <fsummary>Called before end_per_testcase.</fsummary> <type> - <v>TestcaseName = atom()</v> - <v>Config = [{Key,Value}]</v> - <v>Return = NewReturn = Config | SkipOrFail | term()</v> - <v>SkipOrFail = {fail,Reason} | {skip, Reason}</v> - <v>CTHState = NewCTHState = term()</v> - <v>Result = {NewReturn, NewCTHState}</v> - <v>Key = atom()</v> - <v>Value = term()</v> - <v>Reason = term()</v> + <v>TestcaseName = atom()</v> + <v>InitData = Config</v> + <v>Config = NewConfig = [{Key,Value}]</v> + <v>CTHState = NewCTHState = term()</v> + <v>Result = {NewConfig, NewCTHState}</v> + <v>Key = atom()</v> + <v>Value = term()</v> + <v>Reason = term()</v> </type> - <desc> - <p> OPTIONAL </p> - - <p>This function is called after - <seealso marker="common_test#Module:end_per_testcase-2"> - end_per_testcase</seealso> if it exists. It behaves the same way as - <seealso marker="ct_hooks#Module:post_init_per_suite-4"> - post_init_per_suite</seealso>, but for the - <seealso marker="common_test#Module:end_per_testcase-2"> - end_per_testcase</seealso> function instead.</p> + <p>OPTIONAL</p> + + <p>This function is called before + <seealso marker="common_test#Module:end_per_testcase-2"><c>end_per_testcase</c></seealso> + if it exists. It behaves the same way as + <seealso marker="ct_hooks#Module:pre_end_per_suite-3"><c>pre_end_per_suite</c></seealso>, + but for function + <seealso marker="common_test#Module:end_per_testcase-2"><c>end_per_testcase</c></seealso> + instead.</p> + + <p>This function can not change the result of the test case by returning skip or fail + tuples, but it may insert items in <c>Config</c> that can be read in + <c>end_per_testcase/2</c> or in <c>post_end_per_testcase/4</c>.</p> </desc> </func> <func> - <name>Module:pre_end_per_group(GroupName, EndData, CTHState) -> - Result</name> - <fsummary>Called before end_per_group</fsummary> + <name>Module:post_end_per_testcase(TestcaseName, Config, Return, CTHState) -> Result</name> + <fsummary>Called after end_per_testcase.</fsummary> <type> - <v>GroupName = atom()</v> - <v>EndData = Config | SkipOrFail</v> - <v>Config = NewConfig = [{Key,Value}]</v> - <v>CTHState = NewCTHState = term()</v> - <v>Result = {NewConfig | SkipOrFail, NewCTHState}</v> - <v>SkipOrFail = {fail,Reason} | {skip, Reason}</v> - <v>Key = atom()</v> - <v>Value = term()</v> - <v>Reason = term()</v> + <v>TestcaseName = atom()</v> + <v>Config = [{Key,Value}]</v> + <v>Return = NewReturn = Config | SkipOrFail | term()</v> + <v>SkipOrFail = {fail,Reason} | {skip, Reason}</v> + <v>CTHState = NewCTHState = term()</v> + <v>Result = {NewReturn, NewCTHState}</v> + <v>Key = atom()</v> + <v>Value = term()</v> + <v>Reason = term()</v> </type> - <desc> - <p> OPTIONAL </p> - - <p>This function is called before - <seealso marker="common_test#Module:end_per_group-2"> - end_per_group</seealso> if it exists. It behaves the same way as - <seealso marker="ct_hooks#Module:pre_init_per_suite-3"> - pre_init_per_suite</seealso>, but for the - <seealso marker="common_test#Module:end_per_group-2"> - end_per_group</seealso> function instead.</p> + <p>OPTIONAL</p> + + <p>This function is called after + <seealso marker="common_test#Module:end_per_testcase-2"><c>end_per_testcase</c></seealso> + if it exists. It behaves the same way as + <seealso marker="ct_hooks#Module:post_end_per_suite-4"><c>post_end_per_suite</c></seealso>, + but for function + <seealso marker="common_test#Module:end_per_testcase-2"><c>end_per_testcase</c></seealso> + instead.</p> + </desc> + </func> + + <func> + <name>Module:pre_end_per_group(GroupName, EndData, CTHState) -> Result</name> + <fsummary>Called before end_per_group.</fsummary> + <type> + <v>GroupName = atom()</v> + <v>EndData = Config | SkipOrFail</v> + <v>Config = NewConfig = [{Key,Value}]</v> + <v>CTHState = NewCTHState = term()</v> + <v>Result = {NewConfig | SkipOrFail, NewCTHState}</v> + <v>SkipOrFail = {fail,Reason} | {skip, Reason}</v> + <v>Key = atom()</v> + <v>Value = term()</v> + <v>Reason = term()</v> + </type> + <desc> + <p>OPTIONAL</p> + + <p>This function is called before + <seealso marker="common_test#Module:end_per_group-2"><c>end_per_group</c></seealso> + if it exists. It behaves the same way as + <seealso marker="ct_hooks#Module:pre_init_per_suite-3"><c>pre_init_per_suite</c></seealso>, + but for function + <seealso marker="common_test#Module:end_per_group-2"><c>end_per_group</c></seealso> + instead.</p> </desc> </func> <func> - <name>Module:post_end_per_group(GroupName, Config, Return, CTHState) -> - Result</name> - <fsummary>Called after end_per_group</fsummary> + <name>Module:post_end_per_group(GroupName, Config, Return, CTHState) -> Result</name> + <fsummary>Called after end_per_group.</fsummary> <type> - <v>GroupName = atom()</v> - <v>Config = [{Key,Value}]</v> - <v>Return = NewReturn = Config | SkipOrFail | term()</v> - <v>SkipOrFail = {fail,Reason} | {skip, Reason}</v> - <v>CTHState = NewCTHState = term()</v> - <v>Result = {NewReturn, NewCTHState}</v> - <v>Key = atom()</v> - <v>Value = term()</v> - <v>Reason = term()</v> + <v>GroupName = atom()</v> + <v>Config = [{Key,Value}]</v> + <v>Return = NewReturn = Config | SkipOrFail | term()</v> + <v>SkipOrFail = {fail,Reason} | {skip, Reason}</v> + <v>CTHState = NewCTHState = term()</v> + <v>Result = {NewReturn, NewCTHState}</v> + <v>Key = atom()</v> + <v>Value = term()</v> + <v>Reason = term()</v> </type> - <desc> - <p> OPTIONAL </p> - - <p>This function is called after - <seealso marker="common_test#Module:end_per_group-2"> - end_per_group</seealso> if it exists. It behaves the same way as - <seealso marker="ct_hooks#Module:post_init_per_suite-4"> - post_init_per_suite</seealso>, but for the - <seealso marker="common_test#Module:end_per_group-2"> - end_per_group</seealso> function instead.</p> + <p>OPTIONAL</p> + + <p>This function is called after + <seealso marker="common_test#Module:end_per_group-2"><c>end_per_group</c></seealso> + if it exists. It behaves the same way as + <seealso marker="ct_hooks#Module:post_init_per_suite-4"><c>post_init_per_suite</c></seealso>, + but for function + <seealso marker="common_test#Module:end_per_group-2">end_per_group</seealso> + instead.</p> </desc> </func> <func> - <name>Module:pre_end_per_suite(SuiteName, EndData, CTHState) -> - Result</name> - <fsummary>Called before end_per_suite</fsummary> + <name>Module:pre_end_per_suite(SuiteName, EndData, CTHState) -> Result</name> + <fsummary>Called before end_per_suite.</fsummary> <type> - <v>SuiteName = atom()</v> - <v>EndData = Config | SkipOrFail</v> - <v>Config = NewConfig = [{Key,Value}]</v> - <v>CTHState = NewCTHState = term()</v> - <v>Result = {NewConfig | SkipOrFail, NewCTHState}</v> - <v>SkipOrFail = {fail,Reason} | {skip, Reason}</v> - <v>Key = atom()</v> - <v>Value = term()</v> - <v>Reason = term()</v> + <v>SuiteName = atom()</v> + <v>EndData = Config | SkipOrFail</v> + <v>Config = NewConfig = [{Key,Value}]</v> + <v>CTHState = NewCTHState = term()</v> + <v>Result = {NewConfig | SkipOrFail, NewCTHState}</v> + <v>SkipOrFail = {fail,Reason} | {skip, Reason}</v> + <v>Key = atom()</v> + <v>Value = term()</v> + <v>Reason = term()</v> </type> - <desc> - <p> OPTIONAL </p> - - <p>This function is called before - <seealso marker="common_test#Module:end_per_suite-1"> - end_per_suite</seealso> if it exists. It behaves the same way as - <seealso marker="ct_hooks#Module:pre_init_per_suite-3"> - pre_init_per_suite</seealso>, but for the - <seealso marker="common_test#Module:end_per_suite-1"> - end_per_suite</seealso> function instead.</p> + <p>OPTIONAL</p> + + <p>This function is called before + <seealso marker="common_test#Module:end_per_suite-1"><c>end_per_suite</c></seealso> + if it exists. It behaves the same way as + <seealso marker="ct_hooks#Module:pre_init_per_suite-3"><c>pre_init_per_suite</c></seealso>, + but for function + <seealso marker="common_test#Module:end_per_suite-1"><c>end_per_suite</c></seealso> + instead.</p> </desc> </func> <func> - <name>Module:post_end_per_suite(SuiteName, Config, Return, CTHState) -> - Result</name> - <fsummary>Called after end_per_suite</fsummary> + <name>Module:post_end_per_suite(SuiteName, Config, Return, CTHState) -> Result</name> + <fsummary>Called after end_per_suite.</fsummary> <type> - <v>SuiteName = atom()</v> - <v>Config = [{Key,Value}]</v> - <v>Return = NewReturn = Config | SkipOrFail | term()</v> - <v>SkipOrFail = {fail,Reason} | {skip, Reason}</v> - <v>CTHState = NewCTHState = term()</v> - <v>Result = {NewReturn, NewCTHState}</v> - <v>Key = atom()</v> - <v>Value = term()</v> - <v>Reason = term()</v> + <v>SuiteName = atom()</v> + <v>Config = [{Key,Value}]</v> + <v>Return = NewReturn = Config | SkipOrFail | term()</v> + <v>SkipOrFail = {fail,Reason} | {skip, Reason}</v> + <v>CTHState = NewCTHState = term()</v> + <v>Result = {NewReturn, NewCTHState}</v> + <v>Key = atom()</v> + <v>Value = term()</v> + <v>Reason = term()</v> </type> - <desc> - <p> OPTIONAL </p> - - <p>This function is called after - <seealso marker="common_test#Module:end_per_suite-1"> - end_per_suite</seealso> if it exists. It behaves the same way as - <seealso marker="ct_hooks#Module:post_init_per_suite-4"> - post_init_per_suite</seealso>, but for the - <seealso marker="common_test#Module:end_per_suite-1"> - end_per_suite</seealso> function instead.</p> + <p>OPTIONAL</p> + + <p>This function is called after + <seealso marker="common_test#Module:end_per_suite-1"><c>end_per_suite</c></seealso> + if it exists. It behaves the same way as + <seealso marker="ct_hooks#Module:post_init_per_suite-4"><c>post_init_per_suite</c></seealso>, + but for function + <seealso marker="common_test#Module:end_per_suite-1"><c>end_per_suite</c></seealso> + instead.</p> </desc> </func> <func> - <name>Module:on_tc_fail(TestName, Reason, CTHState) -> - NewCTHState</name> - <fsummary>Called after the CTH scope ends</fsummary> + <name>Module:on_tc_fail(TestName, Reason, CTHState) -> NewCTHState</name> + <fsummary>Called after the CTH scope ends.</fsummary> <type> - <v>TestName = init_per_suite | end_per_suite | - {init_per_group,GroupName} | {end_per_group,GroupName} | - {FuncName,GroupName} | FuncName</v> - <v>FuncName = atom()</v> - <v>GroupName = atom()</v> - <v>Reason = term()</v> - <v>CTHState = NewCTHState = term()</v> + <v>TestName = init_per_suite | end_per_suite | {init_per_group,GroupName} | {end_per_group,GroupName} | {FuncName,GroupName} | FuncName</v> + <v>FuncName = atom()</v> + <v>GroupName = atom()</v> + <v>Reason = term()</v> + <v>CTHState = NewCTHState = term()</v> </type> - <desc> - <p> OPTIONAL </p> - - <p>This function is called whenever a test case (or config function) - fails. It is called after the post function has been called for - the failed test case. I.e. if init_per_suite fails, this function - is called after - <seealso marker="#Module:post_init_per_suite-4"> - post_init_per_suite</seealso>, and if a test case fails, it is called - after <seealso marker="#Module:post_end_per_testcase-4"> - post_end_per_testcase</seealso>. If the failed test case belongs - to a test case group, the first argument is a tuple - <c>{FuncName,GroupName}</c>, otherwise simply the function name.</p> - - <p>The data which comes with the Reason follows the same format as the - <seealso marker="event_handler_chapter#failreason">FailReason - </seealso> in the <seealso marker="event_handler_chapter#tc_done">tc_done</seealso> event. - See <seealso marker="event_handler_chapter#events">Event Handling - </seealso> in the User's Guide for details.</p> + <p>OPTIONAL</p> + + <p>This function is called whenever a test case (or configuration + function) fails. It is called after the post function is called + for the failed test case, that is:</p> + + <list type="bulleted"> + <item><p>If <c>init_per_suite</c> fails, this function is called after + <seealso marker="#Module:post_init_per_suite-4"><c>post_init_per_suite</c></seealso>.</p></item> + <item><p>If a test case fails, this funcion is called after + <seealso marker="#Module:post_end_per_testcase-4"><c>post_end_per_testcase</c></seealso>.</p></item> + </list> + + <p>If the failed test case belongs to a test case group, the first + argument is a tuple <c>{FuncName,GroupName}</c>, otherwise only + the function name.</p> + + <p>The data that comes with <c>Reason</c> follows the same format as + <seealso marker="event_handler_chapter#failreason"><c>FailReason</c></seealso> + in event + <seealso marker="event_handler_chapter#tc_done"><c>tc_done</c></seealso>. + For details, see section + <seealso marker="event_handler_chapter#events">Event Handling</seealso> + in the User's Guide.</p> </desc> </func> <func> - <name>Module:on_tc_skip(TestName, Reason, CTHState) -> - NewCTHState</name> - <fsummary>Called after the CTH scope ends</fsummary> + <name>Module:on_tc_skip(TestName, Reason, CTHState) -> NewCTHState</name> + <fsummary>Called after the CTH scope ends.</fsummary> <type> - <v>TestName = init_per_suite | end_per_suite | - {init_per_group,GroupName} | {end_per_group,GroupName} | - {FuncName,GroupName} | FuncName</v> - <v>FuncName = atom()</v> - <v>GroupName = atom()</v> - <v>Reason = {tc_auto_skip | tc_user_skip, term()}</v> - <v>CTHState = NewCTHState = term()</v> + <v>TestName = init_per_suite | end_per_suite | {init_per_group,GroupName} | {end_per_group,GroupName} | {FuncName,GroupName} | FuncName</v> + <v>FuncName = atom()</v> + <v>GroupName = atom()</v> + <v>Reason = {tc_auto_skip | tc_user_skip, term()}</v> + <v>CTHState = NewCTHState = term()</v> </type> - <desc> - <p> OPTIONAL </p> - - <p>This function is called whenever a test case (or config function) - is skipped. It is called after the post function has been called - for the skipped test case. I.e. if init_per_group is skipped, this - function is called after - <seealso marker="#Module:post_init_per_group-4"> - post_init_per_group</seealso>, and if a test case is skipped, - it is called after - <seealso marker="#Module:post_end_per_testcase-4"> - post_end_per_testcase</seealso>. If the skipped test case belongs to a - test case group, the first argument is a tuple <c>{FuncName,GroupName}</c>, - otherwise simply the function name.</p> - - <p>The data which comes with the Reason follows the same format as - <seealso marker="event_handler_chapter#tc_auto_skip">tc_auto_skip - </seealso> and <seealso marker="event_handler_chapter#tc_user_skip"> - tc_user_skip</seealso> events. - See <seealso marker="event_handler_chapter#events">Event Handling - </seealso> in the User's Guide for details.</p> + <p>OPTIONAL</p> + + <p>This function is called whenever a test case (or configuration + function) is skipped. It is called after the post function is called + for the skipped test case, that is:</p> + + <list type="bulleted"> + <item><p>If <c>init_per_group</c> is skipped, this function is + called after + <seealso marker="#Module:post_init_per_group-4"><c>post_init_per_group</c></seealso>.</p></item> + <item><p>If a test case is skipped, this function is called after + <seealso marker="#Module:post_end_per_testcase-4"><c>post_end_per_testcase</c></seealso>.</p></item> + </list> + + <p>If the skipped test case belongs to a test case group, the first + argument is a tuple <c>{FuncName,GroupName}</c>, otherwise only + the function name.</p> + + <p>The data that comes with <c>Reason</c> follows the same format as + events + <seealso marker="event_handler_chapter#tc_auto_skip"><c>tc_auto_skip</c></seealso> + and + <seealso marker="event_handler_chapter#tc_user_skip"><c>tc_user_skip</c></seealso> + For details, see section + <seealso marker="event_handler_chapter#events">Event Handling</seealso> + in the User's Guide.</p> </desc> </func> <func> <name>Module:terminate(CTHState)</name> - <fsummary>Called after the CTH scope ends</fsummary> + <fsummary>Called after the CTH scope ends.</fsummary> <type> - <v>CTHState = term()</v> + <v>CTHState = term()</v> </type> - <desc> - <p> OPTIONAL </p> + <p>OPTIONAL</p> - <p>This function is called at the end of a CTH's - <seealso marker="ct_hooks_chapter#scope">scope</seealso>. - </p> + <p>This function is called at the end of a CTH + <seealso marker="ct_hooks_chapter#scope">scope</seealso>.</p> </desc> </func> <func> <name>Module:id(Opts) -> Id</name> - <fsummary>Called before the init function of a CTH</fsummary> + <fsummary>Called before the init function of a CTH.</fsummary> <type> - <v>Opts = term()</v> - <v>Id = term()</v> + <v>Opts = term()</v> + <v>Id = term()</v> </type> - <desc> - <p> OPTIONAL </p> - - <p>The <c>Id</c> is used to uniquely identify a CTH instance, - if two CTH's return the same <c>Id</c> the second CTH is ignored - and subsequent calls to the CTH will only be made to the first - instance. For more information see - <seealso marker="ct_hooks_chapter#installing">Installing a CTH - </seealso> in the User's Guide. - </p> - - <p>This function should NOT have any side effects as it might - be called multiple times by Common Test.</p> + <p>OPTIONAL</p> - <p>If not implemented the CTH will act as if this function returned a - call to <c>make_ref/0</c>.</p> - </desc> + <p>The <c>Id</c> identifies a CTH instance uniquely. If two CTHs return + the same <c>Id</c>, the second CTH is ignored and subsequent calls to + the CTH are only made to the first instance. For details, see section + <seealso marker="ct_hooks_chapter#installing">Installing a CTH</seealso> + in the User's Guide.</p> + + <p>This function is <em>not</em> to have any side effects, as it can + be called multiple times by <c>Common Test</c>.</p> + + <p>If not implemented, the CTH acts as if this function returned a call + to <c>make_ref/0</c>.</p> + </desc> </func> - </funcs> </erlref> diff --git a/lib/common_test/doc/src/ct_hooks_chapter.xml b/lib/common_test/doc/src/ct_hooks_chapter.xml index d9892c66f7..3eb1945a61 100644 --- a/lib/common_test/doc/src/ct_hooks_chapter.xml +++ b/lib/common_test/doc/src/ct_hooks_chapter.xml @@ -30,177 +30,181 @@ <file>ct_hooks_chapter.xml</file> </header> - <marker id="general"></marker> <section> + <marker id="general"></marker> <title>General</title> <p> - The <em>Common Test Hook</em> (henceforth called CTH) framework allows - extensions of the default behaviour of Common Test by means of hooks - before and after all test suite calls. CTHs allow advanced Common Test - users to abstract out behaviour which is common to multiple test suites - without littering all test suites with library calls. Some example - usages are: logging, starting and monitoring external systems, - building C files needed by the tests and much more!</p> - - <p>In brief, Common Test Hooks allows you to:</p> - - <list> - <item>Manipulate the runtime config before each suite - configuration call</item> - <item>Manipulate the return of all suite configuration calls and in - extension the result of the test themselves.</item> + The <em>Common Test Hook (CTH)</em> framework allows + extensions of the default behavior of <c>Common Test</c> using hooks + before and after all test suite calls. CTHs allow advanced <c>Common Test</c> + users to abstract out behavior that is common to multiple test suites + without littering all test suites with library calls. this can be used + for logging, starting, and monitoring external systems, + building C files needed by the tests, and so on.</p> + + <p>In brief, CTH allows you to do the following:</p> + + <list type="bulleted"> + <item>Manipulate the runtime configuration before each suite + configuration call.</item> + <item>Manipulate the return of all suite configuration calls, and in + extension, the result of the tests themselves.</item> </list> - <p>The following sections describe how to use CTHs, when they are run - and how to manipulate your test results in a CTH</p> + <p>The following sections describe how to use CTHs, when they are run, + and how to manipulate the test results in a CTH.</p> - <warning><p>When executing within a CTH all timetraps are shutoff. So - if your CTH never returns, the entire test run will be stalled!</p> + <warning><p>When executing within a CTH, all timetraps are shut off. So + if your CTH never returns, the entire test run is stalled.</p> </warning> </section> - <marker id="installing"></marker> <section> + <marker id="installing"></marker> <title>Installing a CTH</title> - <p>There are multiple ways to install a CTH in your test run. You can do it - for all tests in a run, for specific test suites and for specific groups + <p>A CTH can be installed in multiple ways in your test run. You can do it + for all tests in a run, for specific test suites, and for specific groups within a test suite. If you want a CTH to be present in all test suites - within your test run there are three different ways to accomplish that. + within your test run, there are three ways to accomplish that, as follows: </p> - <list> + <list type="bulleted"> <item>Add <c>-ct_hooks</c> as an argument to <seealso marker="run_test_chapter#ct_run">ct_run</seealso>. - To add multiple CTHs using this method append them to each other - using the keyword <c>and</c>, i.e. + To add multiple CTHs using this method, append them to each other + using the keyword <c>and</c>, that is, <c>ct_run -ct_hooks cth1 [{debug,true}] and cth2 ...</c>.</item> - <item>Add the <c>ct_hooks</c> tag to your + <item>Add tag <c>ct_hooks</c> to your <seealso marker="run_test_chapter#test_specifications"> - Test Specification</seealso></item> - <item>Add the <c>ct_hooks</c> tag to your call to - <seealso marker="ct#run_test-1">ct:run_test/1</seealso></item> + Test Specification</seealso>.</item> + <item>Add tag <c>ct_hooks</c> to your call to + <seealso marker="ct#run_test-1">ct:run_test/1</seealso>.</item> </list> - <p>You can also add CTHs within a test suite. This is done by returning - <c>{ct_hooks,[CTH]}</c> in the config list from + <p>CTHs can also be added within a test suite. This is done by returning + <c>{ct_hooks,[CTH]}</c> in the configuration list from <seealso marker="common_test#Module:suite-0">suite/0</seealso>, <seealso marker="common_test#Module:init_per_suite-1"> - init_per_suite/1</seealso> or + init_per_suite/1</seealso>, or <seealso marker="common_test#Module:init_per_group-2"> - init_per_group/2</seealso>. <c>CTH</c> in this case can be either - only the module name of the CTH or a tuple with the module name and the - initial arguments and optionally the hook priority of the CTH. Eg: - <c>{ct_hooks,[my_cth_module]}</c> or - <c>{ct_hooks,[{my_cth_module,[{debug,true}]}]}</c> or - <c>{ct_hooks,[{my_cth_module,[{debug,true}],500}]}</c> - </p> + init_per_group/2</seealso>.</p> + + <p>In this case, <c>CTH</c> can either be only the module name of the CTH + or a tuple with the module name and the initial arguments, and optionally + the hook priority of the CTH. For example, one of the following:</p> + <list type="bulleted"> + <item><c>{ct_hooks,[my_cth_module]}</c></item> + <item><c>{ct_hooks,[{my_cth_module,[{debug,true}]}]}</c></item> + <item><c>{ct_hooks,[{my_cth_module,[{debug,true}],500}]}</c></item> + </list> <section> <title>Overriding CTHs</title> - <p>By default each installation of a CTH will cause a new instance of it - to be activated. This can cause problems if you want to be able to - override CTHs in test specifications while still having them in the - suite info function. The + <p>By default, each installation of a CTH causes a new instance of it + to be activated. This can cause problems if you want to override + CTHs in test specifications while still having them in the + suite information function. The <seealso marker="ct_hooks#Module:id-1">id/1</seealso> callback exists to address this problem. By returning the same - <c>id</c> in both places, Common Test knows that this CTH - has already been installed and will not try to install it again.</p> + <c>id</c> in both places, <c>Common Test</c> knows that this CTH + is already installed and does not try to install it again.</p> </section> <section> - <title>CTH Execution order</title> - <p>By default each CTH installed will be executed in the order which + <title>CTH Execution Order</title> + <p>By default, each CTH installed is executed in the order that they are installed for init calls, and then reversed for end calls. - This is not always wanted so common_test allows + This is not always desired, so <c>Common Test</c> allows the user to specify a priority for each hook. The priority can either - be specified in the CTH <seealso marker="ct_hooks#Module:init-2">init/2 - </seealso> function or when installing the hook. The priority given at - installation will override the priority returned by the CTH. </p> + be specified in the CTH function + <seealso marker="ct_hooks#Module:init-2">init/2</seealso> or when + installing the hook. The priority specified at installation overrides the + priority returned by the CTH.</p> </section> </section> - <marker id="scope"/> <section> + <marker id="scope"/> <title>CTH Scope</title> - <p>Once the CTH is installed into a certain test run it will be there until + <p>Once the CTH is installed into a certain test run it remains there until its scope is expired. The scope of a CTH depends on when it is - installed. - The <seealso marker="ct_hooks#Module:init-2">init/2</seealso> is - called at the beginning of the scope and the - <seealso marker="ct_hooks#Module:terminate-1">terminate/1 - </seealso> function is called when the scope ends.</p> + installed, see the following table. + Function <seealso marker="ct_hooks#Module:init-2">init/2</seealso> is + called at the beginning of the scope and function + <seealso marker="ct_hooks#Module:terminate-1">terminate/1</seealso> + is called when the scope ends.</p> <table> <row> - <cell><em>CTH Installed in</em></cell> + <cell><em>CTH installed in</em></cell> <cell><em>CTH scope begins before</em></cell> <cell><em>CTH scope ends after</em></cell> </row> <row> <cell><seealso marker="run_test_chapter#ct_run">ct_run</seealso></cell> - <cell>the first test suite is to be run.</cell> - <cell>the last test suite has been run.</cell> + <cell>the first test suite is to be run</cell> + <cell>the last test suite has been run</cell> </row> <row> <cell><seealso marker="ct#run_test-1">ct:run_test</seealso></cell> - <cell>the first test suite is to be run.</cell> - <cell>the last test suite has been run.</cell> + <cell>the first test suite is run</cell> + <cell>the last test suite has been run</cell> </row> <row> <cell><seealso marker="run_test_chapter#test_specifications"> Test Specification</seealso></cell> - <cell>the first test suite is to be run.</cell> - <cell>the last test suite has been run.</cell> + <cell>the first test suite is run</cell> + <cell>the last test suite has been run</cell> </row> <row> <cell><seealso marker="common_test#Module:suite-0">suite/0 </seealso></cell> <cell><seealso marker="ct_hooks#Module:pre_init_per_suite-3"> - pre_init_per_suite/3</seealso> is called.</cell> + pre_init_per_suite/3</seealso> is called</cell> <cell><seealso marker="ct_hooks#Module:post_end_per_suite-4"> - post_end_per_suite/4</seealso> has been called for that test suite.</cell> + post_end_per_suite/4</seealso> has been called for that test suite</cell> </row> <row> <cell><seealso marker="common_test#Module:init_per_suite-1"> init_per_suite/1</seealso></cell> <cell><seealso marker="ct_hooks#Module:post_init_per_suite-4"> - post_init_per_suite/4</seealso> is called.</cell> + post_init_per_suite/4</seealso> is called</cell> <cell><seealso marker="ct_hooks#Module:post_end_per_suite-4"> - post_end_per_suite/4</seealso> has been called for that test suite.</cell> + post_end_per_suite/4</seealso> has been called for that test suite</cell> </row> <row> <cell><seealso marker="common_test#Module:init_per_group-2"> init_per_group/2</seealso></cell> <cell><seealso marker="ct_hooks#Module:post_init_per_group-4"> - post_init_per_group/4</seealso> is called.</cell> + post_init_per_group/4</seealso> is called</cell> <cell><seealso marker="ct_hooks#Module:post_end_per_suite-4"> - post_end_per_group/4</seealso> has been called for that group.</cell> + post_end_per_group/4</seealso> has been called for that group</cell> </row> <tcaption>Scope of a CTH</tcaption> </table> <section> <title>CTH Processes and Tables</title> - <p>CTHs are run with the same process scoping as normal test suites - i.e. a different process will execute the init_per_suite hooks then the - init_per_group or per_testcase hooks. So if you want to spawn a - process in the CTH you cannot link with the CTH process as it will exit - after the post hook ends. Also if you for some reason need an ETS - table with your CTH, you will have to spawn a process which handles - it.</p> + <p>CTHs are run with the same process scoping as normal test suites, + that is, a different process executes the <c>init_per_suite</c> hooks then the + <c>init_per_group</c> or <c>per_testcase</c> hooks. So if you want to spawn a + process in the CTH, you cannot link with the CTH process, as it exits + after the post hook ends. Also, if you for some reason need an ETS + table with your CTH, you must spawn a process that handles it.</p> </section> <section> - <title>External configuration data and Logging</title> - <p>It's possible in the CTH to read configuration data values - by calling <seealso marker="ct#get_config-1"><c>ct:get_config/1/2/3</c></seealso> (as explained in the - <seealso marker="config_file_chapter#require_config_data"> - External configuration data</seealso> - chapter). The config variables in question must, as always, first have been - <c>required</c> by means of a suite-, group-, or test case info function, - or the <seealso marker="ct#require-1"><c>ct:require/1/2</c></seealso> function. Note that the latter can also be used - in CT hook functions.</p> - <p>The CT hook functions may call any of the logging functions available + <title>External Configuration Data and Logging</title> + <p>Configuration data values in the CTH can be read + by calling + <seealso marker="ct#get_config-1"><c>ct:get_config/1,2,3</c></seealso> + (as explained in section + <seealso marker="config_file_chapter#require_config_data">Requiring and Reading Configuration Data</seealso>). + The configuration variables in question must, as always, first have been + required by a suite-, group-, or test case information function, + or by function <seealso marker="ct#require-1"><c>ct:require/1/2</c></seealso>. + The latter can also be used in CT hook functions.</p> + <p>The CT hook functions can call any logging function in the <c>ct</c> interface to print information to the log files, or to add comments in the suite overview page. </p> @@ -208,307 +212,328 @@ </section> - <marker id="manipulating"/> <section> - <title>Manipulating tests</title> - <p>It is through CTHs possible to manipulate the results of tests and - configuration functions. The main purpose of doing this with CTHs is to - allow common patterns to be abstracted out from test test suites and applied to - multiple test suites without duplicating any code. All of the callback - functions for a CTH follow a common interface, this interface is - described below.</p> - - <p>Common Test will always call all available hook functions, even pre- and post - hooks for configuration functions that are not implemented in the suite. + <marker id="manipulating"/> + <title>Manipulating Tests</title> + <p>Through CTHs the results of tests and configuration functions can be manipulated. + The main purpose to do this with CTHs is to allow common + patterns to be abstracted out from test suites and applied to + multiple test suites without duplicating any code. All the callback + functions for a CTH follow a common interface described hereafter.</p> + + <p><c>Common Test</c> always calls all available hook functions, even pre- + and post hooks for configuration functions that are not implemented in the suite. For example, <c>pre_init_per_suite(x_SUITE, ...)</c> and - <c>post_init_per_suite(x_SUITE, ...)</c> will be called for test suite - <c>x_SUITE</c>, even if it doesn't export <c>init_per_suite/1</c>. This feature - makes it possible to use hooks as configuration fallbacks, or even - completely replace all configuration functions with hook functions.</p> + <c>post_init_per_suite(x_SUITE, ...)</c> are called for test suite + <c>x_SUITE</c>, even if it does not export <c>init_per_suite/1</c>. + With this feature hooks can be used as configuration fallbacks, and all + configuration functions can be replaced with hook functions.</p> - <marker id="pre"/> <section> + <marker id="pre"/> <title>Pre Hooks</title> <p> - It is possible in a CTH to hook in behaviour before - <seealso marker="common_test#Module:init_per_suite-1">init_per_suite</seealso>, - <seealso marker="common_test#Module:init_per_suite-1">init_per_group</seealso>, - <seealso marker="common_test#Module:init_per_suite-1">init_per_testcase</seealso>, - <seealso marker="common_test#Module:init_per_suite-1">end_per_group</seealso> and - <seealso marker="common_test#Module:init_per_suite-1">end_per_suite</seealso>. + In a CTH, the behavior can be hooked in before the following functions:</p> + + <list type="bulleted"> + <item><seealso marker="common_test#Module:init_per_suite-1"><c>init_per_suite</c></seealso></item> + <item><seealso marker="common_test#Module:init_per_group-2"><c>init_per_group</c></seealso></item> + <item><seealso marker="common_test#Module:init_per_testcase-2"><c>init_per_testcase</c></seealso></item> + <item><seealso marker="common_test#Module:end_per_testcase-2"><c>end_per_testcase</c></seealso></item> + <item><seealso marker="common_test#Module:end_per_group-2"><c>end_per_group</c></seealso></item> + <item><seealso marker="common_test#Module:end_per_suite-1"><c>end_per_suite</c></seealso></item> + </list> + + <p> This is done in the CTH functions called pre_<name of function>. - All of these functions take the same three arguments: <c>Name</c>, - <c>Config</c> and <c>CTHState</c>. The return value of the CTH function - is always a combination of an result for the suite/group/test and an - updated <c>CTHState</c>. If you want the test suite to continue on - executing you should return the config list which you want the test to - use as the result. If you for some reason want to skip/fail the test, - return a tuple with <c>skip</c> or <c>fail</c> and a reason as the - result. Example: - </p> - <code>pre_init_per_suite(SuiteName, Config, CTHState) -> - case db:connect() of - {error,_Reason} -> - {{fail, "Could not connect to DB"}, CTHState}; - {ok, Handle} -> - {[{db_handle, Handle} | Config], CTHState#state{ handle = Handle }} - end.</code> - <note><p>If using multiple CTHs, the first part of the return tuple will be - used as input for the next CTH. So in the case above the next CTH might + These functions take the same three arguments, <c>Name</c>, + <c>Config</c>, and <c>CTHState</c>. The return value of the CTH function + is always a combination of a result for the suite/group/test and an + updated <c>CTHState</c>.</p> + + <p>To let the test suite continue on executing, return the configuration + list that you want the test to use as the result. To skip or + fail the test, return a tuple with <c>skip</c> or <c>fail</c>, and a reason + as the result.</p> + + <p><em>Example:</em></p> + <code> + pre_init_per_suite(SuiteName, Config, CTHState) -> + case db:connect() of + {error,_Reason} -> + {{fail, "Could not connect to DB"}, CTHState}; + {ok, Handle} -> + {[{db_handle, Handle} | Config], CTHState#state{ handle = Handle }} + end.</code> + + <note><p>If you use multiple CTHs, the first part of the return tuple is + used as input for the next CTH. So in the previous example the next CTH can get <c>{fail,Reason}</c> as the second parameter. If you have many CTHs - which interact, it might be a good idea to not let each CTH return - <c>fail</c> or <c>skip</c>. Instead return that an action should be taken - through the <c>Config</c> list and implement a CTH which at the end takes - the correct action.</p></note> + interacting, do not let each CTH return <c>fail</c> or <c>skip</c>. + Instead, return that an action is to be taken through the <c>Config</c> + list and implement a CTH that, at the end, takes the correct action.</p></note> </section> - <marker id="post"/> <section> + <marker id="post"/> <title>Post Hooks</title> - <p>It is also possible in a CTH to hook in behaviour after - <seealso marker="common_test#Module:init_per_suite-1">init_per_suite</seealso>, - <seealso marker="common_test#Module:init_per_suite-1">init_per_group</seealso>, - <seealso marker="common_test#Module:init_per_suite-1">end_per_testcase</seealso>, - <seealso marker="common_test#Module:init_per_suite-1">end_per_group</seealso> and - <seealso marker="common_test#Module:init_per_suite-1">end_per_suite</seealso>. - This is done in the CTH functions called post_<name of function>. - All of these function take the same four arguments: <c>Name</c>, - <c>Config</c>, <c>Return</c> and <c>CTHState</c>. <c>Config</c> in this + <p>In a CTH, behavior can be hooked in after the following functions:</p> + <list type="bulleted"> + <item><seealso marker="common_test#Module:init_per_suite-1"><c>init_per_suite</c></seealso></item> + <item><seealso marker="common_test#Module:init_per_group-2"><c>init_per_group</c></seealso></item> + <item><seealso marker="common_test#Module:init_per_testcase-2"><c>init_per_testcase</c></seealso></item> + <item><seealso marker="common_test#Module:end_per_testcase-2"><c>end_per_testcase</c></seealso></item> + <item><seealso marker="common_test#Module:end_per_group-2"><c>end_per_group</c></seealso></item> + <item><seealso marker="common_test#Module:end_per_suite-1"><c>end_per_suite</c></seealso></item> + </list> + + <p> + This is done in the CTH functions called <c>post_<name of function></c>. + These functions take the same four arguments, <c>Name</c>, + <c>Config</c>, <c>Return</c>, and <c>CTHState</c>. <c>Config</c> in this case is the same <c>Config</c> as the testcase is called with. <c>Return</c> is the value returned by the testcase. If the testcase - failed by crashing, <c>Return</c> will be + fails by crashing, <c>Return</c> is <c>{'EXIT',{{Error,Reason},Stacktrace}}</c>.</p> - <p>The return value of the CTH function is always a combination of an + <p>The return value of the CTH function is always a combination of a result for the suite/group/test and an updated <c>CTHState</c>. If - you want the callback to not affect the outcome of the test you should + you do not want the callback to affect the outcome of the test, return the <c>Return</c> data as it is given to the CTH. You can also - modify the result of the test. By returning the <c>Config</c> list - with the <c>tc_status</c> element removed you can recover from a test + modify the test result. By returning the <c>Config</c> list + with element <c>tc_status</c> removed, you can recover from a test failure. As in all the pre hooks, it is also possible to fail/skip - the test case in the post hook. Example: </p> - - <code>post_end_per_testcase(_TC, Config, {'EXIT',{_,_}}, CTHState) -> - case db:check_consistency() of - true -> - %% DB is good, pass the test. - {proplists:delete(tc_status, Config), CTHState}; - false -> - %% DB is not good, mark as skipped instead of failing - {{skip, "DB is inconsisten!"}, CTHState} - end; -post_end_per_testcase(_TC, Config, Return, CTHState) -> - %% Do nothing if tc does not crash. - {Return, CTHState}.</code> - - <note><p>Recovering from a testcase failure using CTHs should only be done as - a last resort. If used wrongly it could become very difficult to - determine which tests pass or fail in a test run</p></note> + the test case in the post hook.</p> + + <p><em>Example:</em></p> + <code> + post_end_per_testcase(_TC, Config, {'EXIT',{_,_}}, CTHState) -> + case db:check_consistency() of + true -> + %% DB is good, pass the test. + {proplists:delete(tc_status, Config), CTHState}; + false -> + %% DB is not good, mark as skipped instead of failing + {{skip, "DB is inconsisten!"}, CTHState} + end; + post_end_per_testcase(_TC, Config, Return, CTHState) -> + %% Do nothing if tc does not crash. + {Return, CTHState}.</code> + + <note><p>Do recover from a testcase failure using CTHs only a last resort. + If used wrongly, it can be very difficult to determine which tests that + pass or fail in a test run.</p></note> </section> - <marker id="skip_n_fail"/> <section> - <title>Skip and Fail hooks</title> + <title>Skip and Fail Hooks</title> <p> After any post hook has been executed for all installed CTHs, <seealso marker="ct_hooks#Module:on_tc_fail-3">on_tc_fail</seealso> - or <seealso marker="ct_hooks#Module:on_tc_fail-3">on_tc_skip</seealso> - might be called if the testcase failed or was skipped - respectively. You cannot affect the outcome of the tests any further at - this point. + or <seealso marker="ct_hooks#Module:on_tc_skip-3">on_tc_skip</seealso> + is called if the testcase failed or was skipped, respectively. + You cannot affect the outcome of the tests any further at this point. </p> </section> </section> - <marker id="synchronizing"/> <section> - <title>Synchronizing external user applications with Common Test</title> + <marker id="synchronizing"/> + <title>Synchronizing External User Applications with Common Test</title> <p>CTHs can be used to synchronize test runs with external user applications. - The init function may e.g. start and/or communicate with an application that - has the purpose of preparing the SUT for an upcoming test run, or maybe + The init function can, for example, start and/or communicate with an application that + has the purpose of preparing the SUT for an upcoming test run, or initialize a database for saving test data to during the test run. The - terminate function may similarly order such an application to reset the SUT + terminate function can similarly order such an application to reset the SUT after the test run, and/or tell the application to finish active sessions and terminate. Any system error- or progress reports generated during the init- or - termination stage will be saved in the - <seealso marker="run_test_chapter#pre_post_test_io_log">Pre- - and post test I/O log</seealso>. (This is also true for any printouts made + termination stage are saved in the + <seealso marker="run_test_chapter#pre_post_test_io_log">Pre- and Post Test I/O Log</seealso>. + (This is also true for any printouts made with <c>ct:log/2</c> and <c>ct:pal/2</c>).</p> - <p>In order to ensure that Common Test doesn't start executing tests, or + + <p>To ensure that <c>Common Test</c> does not start executing tests, or closes its log files and shuts down, before the external application - is ready for it, Common Test may be synchronized with the application. - During startup and shutdown, Common Test can be suspended, simply by + is ready for it, <c>Common Test</c> can be synchronized with the application. + During startup and shutdown, <c>Common Test</c> can be suspended, simply by having a CTH evaluate a <c>receive</c> expression in the init- or terminate function. The macros <c>?CT_HOOK_INIT_PROCESS</c> (the process executing the hook init function) and <c>?CT_HOOK_TERMINATE_PROCESS</c> (the process executing - the hook terminate function), each specifies the name of the correct Common Test - process to send a message to in order to return from the <c>receive</c>. + the hook terminate function) each specifies the name of the correct <c>Common Test</c> + process to send a message to. This is done to return from the <c>receive</c>. These macros are defined in <c>ct.hrl</c>. </p> </section> - <marker id="example"/> <section> + <marker id="example"/> <title>Example CTH</title> - <p>The CTH below will log information about a test run into a format - parseable by <seealso marker="kernel:file#consult-1">file:consult/1</seealso>. + <p>The following CTH logs information about a test run into a format + parseable by <seealso marker="kernel:file#consult-1">file:consult/1</seealso> + (in <c>Kernel</c>): </p> - <code>%%% @doc Common Test Example Common Test Hook module. --module(example_cth). - -%% Callbacks --export([id/1]). --export([init/2]). - --export([pre_init_per_suite/3]). --export([post_init_per_suite/4]). --export([pre_end_per_suite/3]). --export([post_end_per_suite/4]). - --export([pre_init_per_group/3]). --export([post_init_per_group/4]). --export([pre_end_per_group/3]). --export([post_end_per_group/4]). - --export([pre_init_per_testcase/3]). --export([post_end_per_testcase/4]). - --export([on_tc_fail/3]). --export([on_tc_skip/3]). - --export([terminate/1]). - --record(state, { file_handle, total, suite_total, ts, tcs, data }). - -%% @doc Return a unique id for this CTH. -id(Opts) -> - proplists:get_value(filename, Opts, "/tmp/file.log"). - -%% @doc Always called before any other callback function. Use this to initiate -%% any common state. -init(Id, Opts) -> - {ok,D} = file:open(Id,[write]), - {ok, #state{ file_handle = D, total = 0, data = [] }}. - -%% @doc Called before init_per_suite is called. -pre_init_per_suite(Suite,Config,State) -> - {Config, State#state{ suite_total = 0, tcs = [] }}. - -%% @doc Called after init_per_suite. -post_init_per_suite(Suite,Config,Return,State) -> - {Return, State}. - -%% @doc Called before end_per_suite. -pre_end_per_suite(Suite,Config,State) -> - {Config, State}. - -%% @doc Called after end_per_suite. -post_end_per_suite(Suite,Config,Return,State) -> - Data = {suites, Suite, State#state.suite_total, lists:reverse(State#state.tcs)}, - {Return, State#state{ data = [Data | State#state.data] , - total = State#state.total + State#state.suite_total } }. - -%% @doc Called before each init_per_group. -pre_init_per_group(Group,Config,State) -> - {Config, State}. - -%% @doc Called after each init_per_group. -post_init_per_group(Group,Config,Return,State) -> - {Return, State}. - -%% @doc Called after each end_per_group. -pre_end_per_group(Group,Config,State) -> - {Config, State}. - -%% @doc Called after each end_per_group. -post_end_per_group(Group,Config,Return,State) -> - {Return, State}. - -%% @doc Called before each test case. -pre_init_per_testcase(TC,Config,State) -> - {Config, State#state{ ts = now(), total = State#state.suite_total + 1 } }. - -%% @doc Called after each test case. -post_end_per_testcase(TC,Config,Return,State) -> - TCInfo = {testcase, TC, Return, timer:now_diff(now(), State#state.ts)}, - {Return, State#state{ ts = undefined, tcs = [TCInfo | State#state.tcs] } }. - -%% @doc Called after post_init_per_suite, post_end_per_suite, post_init_per_group, -%% post_end_per_group and post_end_per_testcase if the suite, group or test case failed. -on_tc_fail(TC, Reason, State) -> - State. - -%% @doc Called when a test case is skipped by either user action -%% or due to an init function failing. -on_tc_skip(TC, Reason, State) -> - State. - -%% @doc Called when the scope of the CTH is done -terminate(State) -> - io:format(State#state.file_handle, "~p.~n", - [{test_run, State#state.total, State#state.data}]), - file:close(State#state.file_handle), - ok.</code> + <code> + %%% @doc Common Test Example Common Test Hook module. + -module(example_cth). + + %% Callbacks + -export([id/1]). + -export([init/2]). + + -export([pre_init_per_suite/3]). + -export([post_init_per_suite/4]). + -export([pre_end_per_suite/3]). + -export([post_end_per_suite/4]). + + -export([pre_init_per_group/3]). + -export([post_init_per_group/4]). + -export([pre_end_per_group/3]). + -export([post_end_per_group/4]). + + -export([pre_init_per_testcase/3]). + -export([post_init_per_testcase/4]). + -export([pre_end_per_testcase/3]). + -export([post_end_per_testcase/4]). + + -export([on_tc_fail/3]). + -export([on_tc_skip/3]). + + -export([terminate/1]). + + -record(state, { file_handle, total, suite_total, ts, tcs, data }). + + %% @doc Return a unique id for this CTH. + id(Opts) -> + proplists:get_value(filename, Opts, "/tmp/file.log"). + + %% @doc Always called before any other callback function. Use this to initiate + %% any common state. + init(Id, Opts) -> + {ok,D} = file:open(Id,[write]), + {ok, #state{ file_handle = D, total = 0, data = [] }}. + + %% @doc Called before init_per_suite is called. + pre_init_per_suite(Suite,Config,State) -> + {Config, State#state{ suite_total = 0, tcs = [] }}. + + %% @doc Called after init_per_suite. + post_init_per_suite(Suite,Config,Return,State) -> + {Return, State}. + + %% @doc Called before end_per_suite. + pre_end_per_suite(Suite,Config,State) -> + {Config, State}. + + %% @doc Called after end_per_suite. + post_end_per_suite(Suite,Config,Return,State) -> + Data = {suites, Suite, State#state.suite_total, lists:reverse(State#state.tcs)}, + {Return, State#state{ data = [Data | State#state.data] , + total = State#state.total + State#state.suite_total } }. + + %% @doc Called before each init_per_group. + pre_init_per_group(Group,Config,State) -> + {Config, State}. + + %% @doc Called after each init_per_group. + post_init_per_group(Group,Config,Return,State) -> + {Return, State}. + + %% @doc Called before each end_per_group. + pre_end_per_group(Group,Config,State) -> + {Config, State}. + + %% @doc Called after each end_per_group. + post_end_per_group(Group,Config,Return,State) -> + {Return, State}. + + %% @doc Called before each init_per_testcase. + pre_init_per_testcase(TC,Config,State) -> + {Config, State#state{ ts = now(), total = State#state.suite_total + 1 } }. + + %% Called after each init_per_testcase (immediately before the test case). + post_init_per_testcase(TC,Config,Return,State) -> + {Return, State} + +%% @doc Called before each end_per_testcase (immediately after the test case). + pre_end_per_testcase(TC,Config,State) -> + {Config, State}. + + %% @doc Called after each end_per_testcase. + post_end_per_testcase(TC,Config,Return,State) -> + TCInfo = {testcase, TC, Return, timer:now_diff(now(), State#state.ts)}, + {Return, State#state{ ts = undefined, tcs = [TCInfo | State#state.tcs] } }. + + %% @doc Called after post_init_per_suite, post_end_per_suite, post_init_per_group, + %% post_end_per_group and post_end_per_testcase if the suite, group or test case failed. + on_tc_fail(TC, Reason, State) -> + State. + + %% @doc Called when a test case is skipped by either user action + %% or due to an init function failing. + on_tc_skip(TC, Reason, State) -> + State. + + %% @doc Called when the scope of the CTH is done + terminate(State) -> + io:format(State#state.file_handle, "~p.~n", + [{test_run, State#state.total, State#state.data}]), + file:close(State#state.file_handle), + ok.</code> </section> - <marker id="builtin_cths"/> <section> - <title>Built-in CTHs</title> - <p>Common Test is delivered with a couple of general purpose CTHs that - can be enabled by the user to provide some generic testing functionality. - Some of these are enabled by default when starting running common_test, - they can be disabled by setting <c>enable_builtin_hooks</c> to - <c>false</c> on the command line or in the test specification. In the - table below there is a list of all current CTHs which are delivered with - Common Test.</p> - - <table> - <row> - <cell align="left"><em>CTH Name</em></cell> - <cell align="left"><em>Is Built-in</em></cell> - <cell align="left"><em>Description</em></cell> - </row> - <row> - <cell align="left">cth_log_redirect</cell> - <cell align="left">yes</cell> - <cell align="left">Captures all error_logger and SASL logging events and prints them - to the current test case log. If an event can not be associated with a - testcase it will be printed in the common test framework log. This will - happen for testcases which are run in parallel and events which occur - inbetween testcases. You can configure the level of - <seealso marker="sasl:sasl_app">SASL</seealso> events report - using the normal SASL mechanisms. </cell> - </row> - <row> - <cell align="left">cth_surefire</cell> - <cell align="left">no</cell> - <cell align="left"><p>Captures all test results and outputs them as surefire - XML into a file. The file which is created is by default - called junit_report.xml. The file name can be changed by - setting the <c>path</c> option for this hook, e.g.</p> - - <code>-ct_hooks cth_surefire [{path,"/tmp/report.xml"}]</code> - - <p>If the <c>url_base</c> option is set, an additional - attribute named <c>url</c> will be added to each - <c>testsuite</c> and <c>testcase</c> XML element. The value will - be constructed from the <c>url_base</c> and a relative path - to the test suite or test case log respectively, e.g.</p> - - <code>-ct_hooks cth_surefire [{url_base, "http://myserver.com/"}]</code> - <p>will give a url attribute value similar to</p> - - <code>"http://myserver.com/[email protected]_11.19.39/ -x86_64-unknown-linux-gnu.my_test.logs/run.2012-12-12_11.19.39/suite.log.html"</code> - - <p>Surefire XML can for instance be used by Jenkins to display test - results.</p></cell> - </row> - </table> + <marker id="builtin_cths"/> + <title>Built-In CTHs</title> + <p><c>Common Test</c> is delivered with some general-purpose CTHs that + can be enabled by the user to provide generic testing functionality. + Some of these CTHs are enabled by default when <c>common_test</c> is started to run. + They can be disabled by setting <c>enable_builtin_hooks</c> to + <c>false</c> on the command line or in the test specification. The following + two CTHs are delivered with <c>Common Test</c>:</p> + + <taglist> + <tag><c>cth_log_redirect</c></tag> + <item> + <p>Built-in</p> + <p>Captures all <c>error_logger</c> and <c>SASL</c> logging + events and prints them to the current test case log. If an event cannot be + associated with a test case, it is printed in the <c>Common Test</c> framework log. + This happens for test cases running in parallel and events occuring + in-between test cases. You can configure the level of + <seealso marker="sasl:sasl_app"><c>SASL</c></seealso> events report + using the normal <c>SASL</c> mechanisms.</p> + </item> + <tag><c>cth_surefire</c></tag> + <item> + <p>Not built-in</p> + <p>Captures all test results and outputs them as surefire + XML into a file. The created file is by default + called <c>junit_report.xml</c>. The file name can be changed by + setting option <c>path</c> for this hook, for example:</p> + + <p><c>-ct_hooks cth_surefire [{path,"/tmp/report.xml"}]</c></p> + + <p>If option <c>url_base</c> is set, an extra + attribute named <c>url</c> is added to each + <c>testsuite</c> and <c>testcase</c> XML element. The value + is constructed from <c>url_base</c> and a relative path + to the test suite or test case log, respectively, for example:</p> + + <p><c>-ct_hooks cth_surefire [{url_base, "http://myserver.com/"}]</c></p> + + <p>gives an URL attribute value similar to</p> + + <p><c>"http://myserver.com/[email protected]_11.19.39/ +x86_64-unknown-linux-gnu.my_test.logs/run.2012-12-12_11.19.39/suite.log.html"</c></p> + + <p>Surefire XML can, for example, be used by Jenkins to display test + results.</p> + </item> + </taglist> </section> diff --git a/lib/common_test/doc/src/ct_master.xml b/lib/common_test/doc/src/ct_master.xml new file mode 100644 index 0000000000..06f9b04f1b --- /dev/null +++ b/lib/common_test/doc/src/ct_master.xml @@ -0,0 +1,220 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2010</year><year>2012</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + </legalnotice> + + <title>ct_master</title> + <prepared></prepared> + <responsible></responsible> + <docno></docno> + <approved></approved> + <checked></checked> + <date></date> + <rev>A</rev> + <file>ct_master.xml</file> + </header> + <module>ct_master</module> + <modulesummary>Distributed test execution control for Common Test.</modulesummary> + +<description> + + <p>Distributed test execution control for <c>Common Test</c>.</p> + + <p>This module exports functions for running <c>Common Test</c> nodes on + multiple hosts in parallel.</p> + +</description> + + <funcs> + <func> + <name>abort() -> ok</name> + <fsummary>Stops all running tests.</fsummary> + <desc><marker id="abort-0"/> + <p>Stops all running tests.</p> + </desc> + </func> + + <func> + <name>abort(Nodes) -> ok</name> + <fsummary>Stops tests on specified nodes.</fsummary> + <type> + <v>Nodes = atom() | [atom()]</v> + </type> + <desc><marker id="abort-1"/> + <p>Stops tests on specified nodes.</p> + </desc> + </func> + + <func> + <name>basic_html(Bool) -> ok</name> + <fsummary>If set to true, the ct_master logs are written on a primitive + HTML format, not using the <c>Common Test</c> CSS style sheet.</fsummary> + <type> + <v>Bool = true | false</v> + </type> + <desc><marker id="basic_html-1"/> + <p>If set to <c>true</c>, the <c>ct_master logs</c> are written on a + primitive HTML format, not using the <c>Common Test</c> CSS style + sheet.</p> + </desc> + </func> + + <func> + <name>get_event_mgr_ref() -> MasterEvMgrRef</name> + <fsummary>Gets a reference to the <c>Common Test</c> master event + manager.</fsummary> + <type> + <v>MasterEvMgrRef = atom()</v> + </type> + <desc><marker id="get_event_mgr_ref-0"/> + <p>Gets a reference to the <c>Common Test</c> master event manager. + The reference can be used to, for example, add a user-specific + event handler while tests are running.</p> + + <p><em>Example:</em></p> + + <pre> + gen_event:add_handler(ct_master:get_event_mgr_ref(), my_ev_h, [])</pre> + </desc> + </func> + + <func> + <name>progress() -> [{Node, Status}]</name> + <fsummary>Returns test progress.</fsummary> + <type> + <v>Node = atom()</v> + <v>Status = finished_ok | ongoing | aborted | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="progress-0"/> + <p>Returns test progress. If <c>Status</c> is <c>ongoing</c>, tests + are running on the node and are not yet finished.</p> + </desc> + </func> + + <func> + <name>run(TestSpecs) -> ok</name> + <fsummary>Equivalent to run(TestSpecs, false, [], []).</fsummary> + <type> + <v>TestSpecs = string() | [SeparateOrMerged]</v> + </type> + <desc><marker id="run-1"/> + <p>Equivalent to <seealso marker="#run-4"><c>ct_master:run(TestSpecs, + false, [], [])</c></seealso>.</p> + </desc> + </func> + + <func> + <name>run(TestSpecs, InclNodes, ExclNodes) -> ok</name> + <fsummary>Equivalent to run(TestSpecs, false, InclNodes, ExclNodes). + </fsummary> + <type> + <v>TestSpecs = string() | [SeparateOrMerged]</v> + <v>SeparateOrMerged = string() | [string()]</v> + <v>InclNodes = [atom()]</v> + <v>ExclNodes = [atom()]</v> + </type> + <desc><marker id="run-3"/> + <p>Equivalent to <seealso marker="#run-4"><c>ct_master:run(TestSpecs, + false, InclNodes, ExclNodes)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>run(TestSpecs, AllowUserTerms, InclNodes, ExclNodes) -> ok</name> + <fsummary>Tests are spawned on the nodes as specified in TestSpecs. + </fsummary> + <type> + <v>TestSpecs = string() | [SeparateOrMerged]</v> + <v>SeparateOrMerged = string() | [string()]</v> + <v>AllowUserTerms = bool()</v> + <v>InclNodes = [atom()]</v> + <v>ExclNodes = [atom()]</v> + </type> + <desc><marker id="run-4"/> + <p>Tests are spawned on the nodes as specified in <c>TestSpecs</c>. + Each specification in <c>TestSpec</c> is handled separately. + However, it is also possible to specify a list of specifications to + be merged into one specification before the tests are executed. Any + test without a particular node specification is also executed on + the nodes in <c>InclNodes</c>. Nodes in the <c>ExclNodes</c> list + are excluded from the test.</p> + </desc> + </func> + + <func> + <name>run_on_node(TestSpecs, Node) -> ok</name> + <fsummary>Equivalent to run_on_node(TestSpecs, false, Node).</fsummary> + <type> + <v>TestSpecs = string() | [SeparateOrMerged]</v> + <v>SeparateOrMerged = string() | [string()]</v> + <v>Node = atom()</v> + </type> + <desc><marker id="run_on_node-2"/> + <p>Equivalent to + <seealso marker="#run_on_node-3"><c>ct_master:run_on_node(TestSpecs, + false, Node)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>run_on_node(TestSpecs, AllowUserTerms, Node) -> ok</name> + <fsummary>Tests are spawned on Node according to TestSpecs.</fsummary> + <type> + <v>TestSpecs = string() | [SeparateOrMerged]</v> + <v>SeparateOrMerged = string() | [string()]</v> + <v>AllowUserTerms = bool()</v> + <v>Node = atom()</v> + </type> + <desc><marker id="run_on_node-3"/> + <p>Tests are spawned on <c>Node</c> according to <c>TestSpecs</c>.</p> + </desc> + </func> + + <func> + <name>run_test(Node, Opts) -> ok</name> + <fsummary>Tests are spawned on Node using ct:run_test/1.</fsummary> + <type> + <v>Node = atom()</v> + <v>Opts = [OptTuples]</v> + <v>OptTuples = {config, CfgFiles} | {dir, TestDirs} | {suite, Suites} | {testcase, Cases} | {spec, TestSpecs} | {allow_user_terms, Bool} | {logdir, LogDir} | {event_handler, EventHandlers} | {silent_connections, Conns} | {cover, CoverSpecFile} | {cover_stop, Bool} | {userconfig, UserCfgFiles}</v> + <v>CfgFiles = string() | [string()]</v> + <v>TestDirs = string() | [string()]</v> + <v>Suites = atom() | [atom()]</v> + <v>Cases = atom() | [atom()]</v> + <v>TestSpecs = string() | [string()]</v> + <v>LogDir = string()</v> + <v>EventHandlers = EH | [EH]</v> + <v>EH = atom() | {atom(), InitArgs} | {[atom()], InitArgs}</v> + <v>InitArgs = [term()]</v> + <v>Conns = all | [atom()]</v> + </type> + <desc><marker id="run_test-2"/> + <p>Tests are spawned on <c>Node</c> using + <seealso marker="ct:run_test-1"><c>ct:run_test/1</c></seealso></p> + </desc> + </func> + </funcs> + +</erlref> + + diff --git a/lib/common_test/doc/src/ct_master_chapter.xml b/lib/common_test/doc/src/ct_master_chapter.xml index 16492f39b8..99555164e0 100644 --- a/lib/common_test/doc/src/ct_master_chapter.xml +++ b/lib/common_test/doc/src/ct_master_chapter.xml @@ -22,7 +22,7 @@ </legalnotice> - <title>Using Common Test for Large Scale Testing</title> + <title>Using Common Test for Large-Scale Testing</title> <prepared>Peter Andersson</prepared> <docno></docno> <date></date> @@ -33,217 +33,220 @@ <section> <marker id="general"></marker> <title>General</title> - <p>Large scale automated testing requires running multiple independent + <p>Large-scale automated testing requires running multiple independent test sessions in parallel. This is accomplished by running - a number of Common Test nodes on one or more hosts, testing - different target systems. Configuring, starting and controlling the + some <c>Common Test</c> nodes on one or more hosts, testing + different target systems. Configuring, starting, and controlling the test nodes independently can be a cumbersome operation. To aid - this kind of automated large scale testing, CT offers a master test - node component, CT Master, that handles central configuration and control - in a system of distributed CT nodes.</p> + this kind of automated large-scale testing, <c>Common Test</c> offers a master + test node component, <c>Common Test</c> Master, which handles central configuration and control + in a system of distributed <c>Common Test</c> nodes.</p> - <p>The CT Master server runs on one dedicated Erlang node and uses distributed - Erlang to communicate with any number of CT test nodes, each hosting a regular - CT server. Test specifications are used as input to specify what to test on which + <p>The <c>Common Test</c> Master server runs on one dedicated Erlang node and uses distributed + Erlang to communicate with any number of <c>Common Test</c> test nodes, each hosting a regular + <c>Common Test</c> server. Test specifications are used as input to specify what to test on which test nodes, using what configuration.</p> - <p>The CT Master server writes progress information to HTML log files similarly - to the regular CT server. The logs contain test statistics and links to the - log files written by each independent CT server.</p> + <p>The <c>Common Test</c> Master server writes progress information to HTML log files similarly + to the regular <c>Common Test</c> server. The logs contain test statistics and links to the + log files written by each independent <c>Common Test</c> server.</p> - <p>The CT master API is exported by the <c>ct_master</c> module.</p> + <p>The <c>Common Test</c> Master API is exported by module + <seealso marker="ct_master"><c>ct_master</c></seealso>.</p> </section> <section> - <title>Usage</title> - <p>CT Master requires all test nodes to be on the same network and share a common - file system. As of this date, CT Master can not start test nodes - automatically. The nodes must have been started in advance for CT Master to be + <title>Use</title> + <p><c>Common Test</c> Master requires all test nodes to be on the same network and share a common + file system. <c>Common Test</c> Master cannot start test nodes + automatically. The nodes must be started in advance for <c>Common Test</c> Master to be able to start test sessions on them.</p> - <p>Tests are started by calling:</p> - - <p><c>ct_master:run(TestSpecs)</c> or - <c>ct_master:run(TestSpecs, InclNodes, ExclNodes)</c></p> + <p>Tests are started by calling + <seealso marker="ct_master#run-1"><c>ct_master:run(TestSpecs)</c></seealso> or + <seealso marker="ct_master#run-3"><c>ct_master:run(TestSpecs, InclNodes, ExclNodes)</c></seealso></p> <p><c>TestSpecs</c> is either the name of a test specification file (string) or a list - of test specifications. In case of a list, the specifications will be handled (and + of test specifications. If it is a list, the specifications are handled (and the corresponding tests executed) in sequence. An element in a <c>TestSpecs</c> list - can also be list of test specifications. The specifications in such a list will be - merged into one combined specification prior to test execution. For example:</p> - - <p><c>ct_master:run(["ts1","ts2",["ts3","ts4"]])</c></p> + can also be list of test specifications. The specifications in such a list are + merged into one combined specification before test execution.</p> - <p>means first the tests specified by "ts1" will run, then the tests specified by "ts2" + <p><em>Example:</em></p> + <pre> + ct_master:run(["ts1","ts2",["ts3","ts4"]])</pre> + + <p>Here, the tests specified by "ts1" run first, then the tests specified by "ts2", and finally the tests specified by both "ts3" and "ts4".</p> - <p>The <c>InclNodes</c> argument to <c>run/3</c> is a list of node names. The <c>run/3</c> - function runs the tests in <c>TestSpecs</c> just like <c>run/1</c> but will also - take any test in <c>TestSpecs</c> that's not explicitly tagged with a particular - node name and execute it on the nodes listed in <c>InclNodes</c>. By using <c>run/3</c> - this way it is possible to use any test specification, with or without node information, - in a large scale test environment! <c>ExclNodes</c> is a list of nodes that should be - excluded from the test. I.e. tests that have been specified in the test specification - to run on a particular node will not be performed if that node is at runtime - listed in <c>ExclNodes</c>.</p> - - <p>If CT Master fails initially to connect to any of the test nodes specified in a - test specification or in the <c>InclNodes</c> list, the operator will be prompted with - the option to either start over again (after manually checking the status of the - node(s) in question), to run without the missing nodes, or to abort the operation.</p> + <p>The <c>InclNodes</c> argument to <c>run/3</c> is a list of node names. Function + <c>run/3</c> runs the tests in <c>TestSpecs</c> just like <c>run/1</c>, but also + takes any test in <c>TestSpecs</c>, which is not explicitly tagged with a particular + node name, and execute it on the nodes listed in <c>InclNodes</c>. By using <c>run/3</c> + this way, any test specification can be used, with or without node information, + in a large-scale test environment.</p> + + <p><c>ExclNodes</c> is a list of nodes to be + excluded from the test. That is, tests that are specified in the test specification + to run on a particular node are not performed if that node is + listed in <c>ExclNodes</c> at runtime.</p> - <p>When tests start, CT Master prints information to console about the nodes that are - involved. CT Master also reports when tests finish, successfully or unsuccessfully. If - connection is lost to a node, the test on that node is considered finished. CT Master - will not attempt to reestablish contact with the failing node. At any time to get the - current status of the test nodes, call the function:</p> + <p>If <c>Common Test</c> Master fails initially to connect to any of the test nodes specified in a + test specification or in the <c>InclNodes</c> list, the operator is prompted with + the option to either start over again (after manually checking the status of the + nodes in question), to run without the missing nodes, or to abort the operation.</p> - <p><c>ct_master:progress()</c></p> + <p>When tests start, <c>Common Test</c> Master displays information to console about the involved nodes. + <c>Common Test</c> Master also reports when tests finish, successfully or unsuccessfully. If + connection is lost to a node, the test on that node is considered finished. <c>Common Test</c> Master + does not attempt to re-establish contact with the failing node.</p> - <p>To stop one or more tests, use:</p> + <p>At any time, to get the current status of the test nodes, call function + <seealso marker="ct_master#progress-0"><c>ct_master:progress()</c></seealso>.</p> - <p><c>ct_master:abort()</c> (stop all) or <c>ct_master:abort(Nodes)</c></p> + <p>To stop one or more tests, use function + <seealso marker="ct_master#abort-0"><c>ct_master:abort()</c></seealso> (to stop all) or + <seealso marker="ct_master#abort-1"><c>ct_master:abort(Nodes)</c></seealso>.</p> - <p>For detailed information about the <c>ct_master</c> API, please see the - <seealso marker="ct_master">manual page</seealso> for this module.</p> + <p>For details about the <c>Common Test</c> Master API, see module + <seealso marker="ct_master"><c>ct_master</c></seealso>.</p> </section> <section> <marker id="test_specifications"></marker> <title>Test Specifications</title> - <p>The test specifications used as input to CT Master are fully compatible with the - specifications used as input to the regular CT server. The syntax is described in the - <seealso marker="run_test_chapter#test_specifications">Running Test Suites</seealso> - chapter.</p> + <p>The test specifications used as input to <c>Common Test</c> Master are fully compatible with the + specifications used as input to the regular <c>Common Test</c> server. The syntax is described in section + <seealso marker="run_test_chapter#test_specifications">Test Specifications</seealso> + in section Running Tests and Analyzing Results.</p> <p>All test specification terms can have a <c>NodeRefs</c> element. This element specifies which node or nodes a configuration operation or a test is to be executed - on. <c>NodeRefs</c> is defined as:</p> + on. <c>NodeRefs</c> is defined as follows:</p> <p><c>NodeRefs = all_nodes | [NodeRef] | NodeRef</c></p> - - <p>where</p> <p><c>NodeRef = NodeAlias | node() | master</c></p> <p>A <c>NodeAlias</c> (<c>atom()</c>) is used in a test specification as a - reference to a node name (so the actual node name only needs to be declared once, - which can of course also be achieved using constants). - The alias is declared with a <c>node</c> term:</p> + reference to a node name (so the node name only needs to be declared once, + which also can be achieved using constants). + The alias is declared with a <c>node</c> term as follows:</p> <p><c>{node, NodeAlias, NodeName}</c></p> - <p>If <c>NodeRefs</c> has the value <c>all_nodes</c>, the operation or test will - be performed on all given test nodes. (Declaring a term without a <c>NodeRefs</c> - element actually has the same effect). If <c>NodeRefs</c> has the value - <c>master</c>, the operation is only performed on the CT Master node (namely set + <p>If <c>NodeRefs</c> has the value <c>all_nodes</c>, the operation or test + is performed on all specified test nodes. (Declaring a term without a <c>NodeRefs</c> + element has the same effect). If <c>NodeRefs</c> has the value + <c>master</c>, the operation is only performed on the <c>Common Test</c> Master node (namely set the log directory or install an event handler).</p> - <p>Consider the example in the - <seealso marker="run_test_chapter#test_specifications">Running Test Suites</seealso> - chapter, now extended with node information and intended to be executed by the - CT Master:</p> + <p>Consider the example in section + <seealso marker="run_test_chapter#test_specifications">Test Specifications</seealso> + in section Running Tests and Analysing Results, + now extended with node information and intended to be executed by + <c>Common Test</c> Master:</p> <pre> - {define, 'Top', "/home/test"}. - {define, 'T1', "'Top'/t1"}. - {define, 'T2', "'Top'/t2"}. - {define, 'T3', "'Top'/t3"}. - {define, 'CfgFile', "config.cfg"}. - {define, 'Node', ct_node}. - - {node, node1, 'Node@host_x'}. - {node, node2, 'Node@host_y'}. - - {logdir, master, "'Top'/master_logs"}. - {logdir, "'Top'/logs"}. - - {config, node1, "'T1'/'CfgFile'"}. - {config, node2, "'T2'/'CfgFile'"}. - {config, "'T3'/'CfgFile'"}. - - {suites, node1, 'T1', all}. - {skip_suites, node1, 'T1', [t1B_SUITE,t1D_SUITE], "Not implemented"}. - {skip_cases, node1, 'T1', t1A_SUITE, [test3,test4], "Irrelevant"}. - {skip_cases, node1, 'T1', t1C_SUITE, [test1], "Ignore"}. - - {suites, node2, 'T2', [t2B_SUITE,t2C_SUITE]}. - {cases, node2, 'T2', t2A_SUITE, [test4,test1,test7]}. - - {skip_suites, 'T3', all, "Not implemented"}.</pre> + {define, 'Top', "/home/test"}. + {define, 'T1', "'Top'/t1"}. + {define, 'T2', "'Top'/t2"}. + {define, 'T3', "'Top'/t3"}. + {define, 'CfgFile', "config.cfg"}. + {define, 'Node', ct_node}. + + {node, node1, 'Node@host_x'}. + {node, node2, 'Node@host_y'}. + + {logdir, master, "'Top'/master_logs"}. + {logdir, "'Top'/logs"}. + + {config, node1, "'T1'/'CfgFile'"}. + {config, node2, "'T2'/'CfgFile'"}. + {config, "'T3'/'CfgFile'"}. + + {suites, node1, 'T1', all}. + {skip_suites, node1, 'T1', [t1B_SUITE,t1D_SUITE], "Not implemented"}. + {skip_cases, node1, 'T1', t1A_SUITE, [test3,test4], "Irrelevant"}. + {skip_cases, node1, 'T1', t1C_SUITE, [test1], "Ignore"}. + + {suites, node2, 'T2', [t2B_SUITE,t2C_SUITE]}. + {cases, node2, 'T2', t2A_SUITE, [test4,test1,test7]}. + + {skip_suites, 'T3', all, "Not implemented"}.</pre> <p>This example specifies the same tests as the original example. But - now if started with a call to <c>ct_master:run(TestSpecName)</c>, the - t1 test will be executed on node <c>ct_node@host_x</c> (node1), the - t2 test on <c>ct_node@host_y</c> (node2) and the t3 test on both - node1 and node2. The t1 config file will only be read on - node1 and the t2 config file only on node2, while the t3 config file - will be read on both node1 and node2. Both test nodes will write log - files to the same directory. (The CT Master node will however use a - different log directory than the test nodes).</p> + now if started with a call to <c>ct_master:run(TestSpecName)</c>, test + <c>t1</c> is executed on node <c>ct_node@host_x</c> (<c>node1</c>), test + <c>t2</c> on <c>ct_node@host_y</c> (<c>node2</c>) and test <c>t3</c> + on both <c>node1</c> and <c>node2</c>. Configuration file <c>t1</c> is only read on + <c>node1</c> and configuration file <c>t2</c> only on <c>node2</c>, while the + configuration file <c>t3</c> is read on both <c>node1</c> and <c>node2</c>. + Both test nodes write log files to the same directory. (However, the <c>Common Test</c> Master + node uses a different log directory than the test nodes.)</p> <p>If the test session is instead started with a call to <c>ct_master:run(TestSpecName, [ct_node@host_z], [ct_node@host_x])</c>, - the result is that the t1 test does not run on - <c>ct_node@host_x</c> (or any other node) while the t3 test runs on + the result is that test <c>t1</c> does not run on + <c>ct_node@host_x</c> (or any other node) while test <c>t3</c> runs on both <c>ct_node@host_y</c> and <c>ct_node@host_z</c>.</p> <p>A nice feature is that a test specification that includes node - information can still be used as input to the regular Common Test server - (as described in the - <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>ct_run</c> program), will be performed. Tests without explicit - node association will always be performed too of course!</p> + information can still be used as input to the regular <c>Common Test</c> server + (as described in section + <seealso marker="run_test_chapter#test_specifications">Test Specifications</seealso>). + The result is that any test specified to run on a node with the same + name as the <c>Common Test</c> node in question (typically <c>ct@somehost</c> if started + with the <c>ct_run</c> program), is performed. Tests without explicit + node association are always performed too, of course.</p> </section> <section> - <title>Automatic startup of test target nodes</title> + <title>Automatic Startup of Test Target Nodes</title> <marker id="ct_slave"></marker> - <p>It is possible to automatically start, and perform initial actions, on - test target nodes by using the test specification term <c>init</c>.</p> - <p>Currently, two sub-terms are supported, <c>node_start</c> and <c>eval</c>.</p> - <p>Example:</p> + <p>Initial actions can be started and performed automatically on + test target nodes using test specification term <c>init</c>.</p> + <p>Two subterms are supported, <c>node_start</c> and <c>eval</c>.</p> + <p><em>Example:</em></p> <pre> - {node, node1, node1@host1}. - {node, node2, node1@host2}. - {node, node3, node2@host2}. - {node, node4, node1@host3}. - {init, node1, [{node_start, [{callback_module, my_slave_callback}]}]}. - {init, [node2, node3], {node_start, [{username, "ct_user"}, {password, "ct_password"}]}}. - {init, node4, {eval, {module, function, []}}}.</pre> + {node, node1, node1@host1}. + {node, node2, node1@host2}. + {node, node3, node2@host2}. + {node, node4, node1@host3}. + {init, node1, [{node_start, [{callback_module, my_slave_callback}]}]}. + {init, [node2, node3], {node_start, [{username, "ct_user"}, {password, "ct_password"}]}}. + {init, node4, {eval, {module, function, []}}}.</pre> <p>This test specification declares that <c>node1@host1</c> is to be started using the user callback function <c>callback_module:my_slave_callback/0</c>, and nodes - <c>node1@host2</c> and <c>node2@host2</c> will be started with the default callback - module <c>ct_slave</c>. The given user name and password is used to log into remote - host <c>host2</c>. Also, the function <c>module:function/0</c> will be evaluated on - <c>node1@host3</c>, and the result of this call will be printed to the log.</p> + <c>node1@host2</c> and <c>node2@host2</c> are to be started with the default callback + module <c>ct_slave</c>. The specified username and password are used to log on to remote + host <c>host2</c>. Also, function <c>module:function/0</c> is evaluated on + <c>node1@host3</c>, and the result of this call is printed to the log.</p> - <p>The default <seealso marker="ct_slave">ct_slave</seealso> callback module, - which is part of the Common Test application, has the following features: + <p>The default callback module <seealso marker="ct_slave">ct_slave</seealso>, + has the following features: </p> - <list> + <list type="bulleted"> <item>Starting Erlang target nodes on local or remote hosts - (ssh is used for communication). + (application <c>SSH</c> is used for communication). </item> - <item>Ability to start an Erlang emulator with additional flags + <item>Ability to start an Erlang emulator with more flags (any flags supported by <c>erl</c> are supported). </item> - <item>Supervision of a node being started by means of internal callback - functions. Used to prevent hanging nodes. (Configurable). + <item>Supervision of a node being started using internal callback + functions. Used to prevent hanging nodes. (Configurable.) </item> - <item>Monitoring of the master node by the slaves. A slave node may be - stopped in case the master node terminates. (Configurable). + <item>Monitoring of the master node by the slaves. A slave node can be + stopped if the master node terminates. (Configurable.) </item> - <item>Execution of user functions after a slave node is started. - Functions can be given as a list of {Module, Function, Arguments} tuples. + <item>Execution of user functions after a slave node is started. Functions can + be specified as a list of <c>{Module, Function, Arguments}</c> tuples. </item> </list> - <p>Note that it is possible to specify an <c>eval</c> term for the node as well - as <c>startup_functions</c> in the <c>node_start</c> options list. In this - case first the node will be started, then the <c>startup_functions</c> are + <note><p>An <c>eval</c> term for the node and + <c>startup_functions</c> in the <c>node_start</c> options list can be specified. + In this case, the node is started first, then the <c>startup_functions</c> are executed, and finally functions specified with <c>eval</c> are called. - </p> + </p></note> </section> </chapter> diff --git a/lib/common_test/doc/src/ct_netconfc.xml b/lib/common_test/doc/src/ct_netconfc.xml new file mode 100644 index 0000000000..d8c82c7f2c --- /dev/null +++ b/lib/common_test/doc/src/ct_netconfc.xml @@ -0,0 +1,1039 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2010</year><year>2012</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + </legalnotice> + + <title>ct_netconfc</title> + <prepared></prepared> + <responsible></responsible> + <docno></docno> + <approved></approved> + <checked></checked> + <date></date> + <rev>A</rev> + <file>ct_netconfc.xml</file> + </header> + <module>ct_netconfc</module> + <modulesummary>NETCONF client module.</modulesummary> + +<description> + + <p>NETCONF client module.</p> + + <p>The NETCONF client is compliant with RFC 4741 NETCONF Configuration + Protocol and RFC 4742 Using the NETCONF Configuration Protocol over + Secure SHell (SSH)..</p> + + <p>For each server to test against, the following entry can be added to a + configuration file:</p> + + <pre> + {server_id(),options()}.</pre> + + <p>The <c>server_id()</c> or an associated <c>target_name()</c> (see + module <seealso marker="ct"><c>ct</c></seealso>) must then be used + in calls to + <seealso marker="#open-2"><c>ct_netconfc:open/2</c></seealso>.</p> + + <p>If no configuration exists for a server, a session can still be + opened by calling + <seealso marker="#open-2"><c>ct_netconfc:open/2</c></seealso> with + all necessary options specified in the call. The first argument to + <seealso marker="#open-2"><c>ct_netconfc:open/2</c></seealso> can + then be any atom.</p> + + </description> + + <section> + <marker id="Logging"/> + <title>Logging</title> + <p>The NETCONF server uses <c>error_logger</c> for logging of NETCONF + traffic. A special purpose error handler is implemented in + <c>ct_conn_log_h</c>. To use this error handler, add the + <c>cth_conn_log</c> hook in the test suite, for example:</p> + + <pre> + suite() -> + [{ct_hooks, [{cth_conn_log, [{conn_mod(),hook_options()}]}]}].</pre> + + <p><c>conn_mod()</c> is the name of the <c>Common Test</c> module + implementing the connection protocol, for example, <c>ct_netconfc</c>.</p> + + <p>Hook option <c>log_type</c> specifies the type of logging:</p> + + <taglist> + <tag><c>raw</c></tag> + <item><p>The sent and received NETCONF data is logged to a separate + text file "as is" without any formatting. A link to the file is + added to the test case HTML log.</p>.</item> + + <tag><c>pretty</c></tag> + <item><p>The sent and received NETCONF data is logged to a separate + text file with XML data nicely indented. A link to the file is + added to the test case HTML log.</p></item> + + <tag><c>html (default)</c></tag> + <item><p>The sent and received NETCONF traffic is pretty printed + directly in the test case HTML log.</p></item> + + <tag><c>silent</c></tag> + <item><p>NETCONF traffic is not logged.</p></item> + </taglist> + + <p>By default, all NETCONF traffic is logged in one single log file. + However, different connections can be logged in separate files. + To do this, use hook option <c>hosts</c> and list the names of the + servers/connections to be used in the suite. The connections + must be named for this to work, that is, they must be opened with + <seealso marker="#open-2"><c>ct_netconfc:open/2</c></seealso>.</p> + + <p>Option <c>hosts</c> has no effect if <c>log_type</c> is set to + <c>html</c> or <c>silent</c>.</p> + + <p>The hook options can also be specified in a configuration file with + configuration variable <c>ct_conn_log</c>:</p> + + <pre> + {ct_conn_log,[{conn_mod(),hook_options()}]}.</pre> + + <p>For example:</p> + + <pre> + {ct_conn_log,[{ct_netconfc,[{log_type,pretty}, + {hosts,[key_or_name()]}]}]}</pre> + + <note> + <p>Hook options specified in a configuration file overwrite the + hard-coded hook options in the test suite.</p> + </note> + + <p><em>Logging Example 1:</em></p> + <marker id="Logging_example_1"/> + + <p>The following <c>ct_hooks</c> statement causes pretty printing of + NETCONF traffic to separate logs for the connections named + <c>nc_server1</c> and <c>nc_server2</c>. Any other connections are + logged to default NETCONF log.</p> + + <pre> + suite() -> + [{ct_hooks, [{cth_conn_log, [{ct_netconfc,[{log_type,pretty}}, + {hosts,[nc_server1,nc_server2]}]} + ]}]}].</pre> + + <p>Connections must be opened as follows:</p> + + <pre> + open(nc_server1,[...]), + open(nc_server2,[...]).</pre> + + <p><em>Logging Example 2:</em></p> + <marker id="Logging_example_2"/> + + <p>The following configuration file causes raw logging of all NETCONF + traffic in to one single text file:</p> + + <pre> + {ct_conn_log,[{ct_netconfc,[{log_type,raw}]}]}.</pre> + + <p>The <c>ct_hooks</c> statement must look as follows:</p> + + <pre> + suite() -> + [{ct_hooks, [{cth_conn_log, []}]}].</pre> + + <p>The same <c>ct_hooks</c> statement without the configuration file + would cause HTML logging of all NETCONF connections in to the test + case HTML log.</p> + </section> + + <section> + <marker id="Notifications"/> + <title>Notifications</title> + + <p>The NETCONF client is also compliant with RFC 5277 NETCONF Event + Notifications, which defines a mechanism for an asynchronous message + notification delivery service for the NETCONF protocol.</p> + + <p>Specific functions to support this are + <seealso marker="#create_subscription-6"><c>ct_netconfc:create_subscription/6</c></seealso> + and + <seealso marker="#get_event_streams-3"><c>ct_netconfc:get_event_streams/3</c></seealso>. + (The functions also exist with other arities.)</p> + </section> + + <section> + <title>Data Types</title> + <marker id="types"/> + <taglist> + <tag><c>client() = handle() | key_or_name()</c></tag> + <item><marker id="type-client"/> + <p>For <c>handle()</c>, see module + <seealso marker="ct"><c>ct</c></seealso>.</p></item> + + <tag><c>error_reason() = term()</c></tag> + <item><marker id="type-error_reason"/> </item> + <tag><c>event_time() = {eventTime, xml_attributes(), [xs_datetime()]}</c></tag> + <item><marker id="type-event_time"/> </item> + + <tag><c>handle() = term()</c></tag> + <item><marker id="type-handle"/> + <p>Opaque reference for a connection (NETCONF session). For more + information, see module <seealso marker="ct"><c>ct</c></seealso>.</p> + </item> + + <tag><c>host() = <seealso marker="kernel:inet#type-hostname"><c>inet:hostname()</c></seealso> | <seealso marker="kernel:inet#type-ip_address"><c>inet:ip_address()</c></seealso></c></tag> + <item><marker id="type-host"/></item> + + <tag><c>key_or_name() = server_id() | target_name()</c></tag> + <item><marker id="type-key_or_name"/> + <p>For <c>target_name</c>, see module + <seealso marker="ct"><c>ct</c></seealso>.</p></item> + + <tag><c>netconf_db() = running | startup | candidate</c></tag> + <item><marker id="type-netconf_db"/> </item> + + <tag><c>notification() = {notification, xml_attributes(), notification_content()}</c></tag> + <item><marker id="type-notification"/> </item> + + <tag><c>notification_content() = [event_time() | simple_xml()]</c></tag> + <item><marker id="type-notification_content"/> </item> + + <tag><c>option() = {ssh, host()} | {port, <seealso marker="kernel:inet#type-port_number"><c>inet:port_number()</c></seealso>} | {timeout, timeout()} | SshConnectOption</c></tag> + <item><marker id="type-option"/> + + <p><c>SshConnectOption</c> is any valid option to + <seealso marker="ssh:ssh#connect-3"><c>ssh:connect/3,4</c></seealso>. + Common options used are <c>user</c>, <c>password</c> + and <c>user_dir</c>. The <c>SshConnectOptions</c> are + verfied by the SSH application.</p></item> + + <tag><c>options() = [option()]</c></tag> + <item><marker id="type-options"/> + <p>Options used for setting up an SSH connection to a NETCONF + server.</p></item> + + <tag><c>server_id() = atom()</c></tag> + <item><marker id="type-server_id"/> + <p>The identity of a server, specified in a configuration + file.</p></item> + + <tag><c>simple_xml() = {xml_tag(), xml_attributes(), xml_content()} | {xml_tag(), xml_content()} | xml_tag()</c></tag> + <item><marker id="type-simple_xml"/> + <p>This type is further described in application + <seealso marker="xmerl:index"><c>xmerl</c></seealso>.</p></item> + + <tag><c>stream_data() = {description, string()} | {replaySupport, string()} | {replayLogCreationTime, string()} | {replayLogAgedTime, string()}</c></tag> + <item><marker id="type-stream_data"/> + <p>For details about the data format for the string values, see + "XML Schema for Event Notifications" in RFC 5277.</p></item> + + <tag><c>stream_name() = string()</c></tag> + <item><marker id="type-stream_name"/> </item> + + <tag><c>streams() = [{stream_name(), [stream_data()]}]</c></tag> + <item><marker id="type-streams"/> </item> + + <tag><c>xml_attribute_tag() = atom()</c></tag> + <item><marker id="type-xml_attribute_tag"/> </item> + + <tag><c>xml_attribute_value() = string()</c></tag> + <item><marker id="type-xml_attribute_value"/> </item> + + <tag><c>xml_attributes() = [{xml_attribute_tag(), xml_attribute_value()}]</c></tag> + <item><marker id="type-xml_attributes"/> </item> + + <tag><c>xml_content() = [simple_xml() | iolist()]</c></tag> + <item><marker id="type-xml_content"/> </item> + + <tag><c>xml_tag() = atom()</c></tag> + <item><marker id="type-xml_tag"/> </item> + + <tag><c>xpath() = {xpath, string()}</c></tag> + <item><marker id="type-xpath"/> </item> + + <tag><c>xs_datetime() = string()</c></tag> + <item><marker id="type-xs_datetime"/> + <p>This date and time identifier has the same format as the XML type + <c>dateTime</c> and is compliant with RFC 3339 Date and Time on + the Internet Timestamps. The format is as follows:</p> + <pre> + [-]CCYY-MM-DDThh:mm:ss[.s][Z|(+|-)hh:mm]</pre> + </item> + </taglist> + </section> + + <funcs> + <func> + <name>action(Client, Action) -> Result</name> + <fsummary>Equivalent to action(Client, Action, infinity).</fsummary> + <desc><marker id="action-2"/> + <p>Equivalent to + <seealso marker="#action-3"><c>ct_netconfc:action(Client, Action, + infinity)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>action(Client, Action, Timeout) -> Result</name> + <fsummary>Executes an action.</fsummary> + <type> + <v>Client = client()</v> + <v>Action = simple_xml()</v> + <v>Timeout = timeout()</v> + <v>Result = ok | {ok, [simple_xml()]} | {error, error_reason()}</v> + </type> + <desc><marker id="action-3"/> + <p>Executes an action. If the return type is void, <c>ok</c> is + returned instead of <c>{ok,[simple_xml()]}</c>.</p> + </desc> + </func> + + <func> + <name>close_session(Client) -> Result</name> + <fsummary>Equivalent to close_session(Client, infinity).</fsummary> + <desc><marker id="close_session-1"/> + <p>Equivalent to + <seealso marker="#close_session-2"><c>ct_netconfc:close_session(Client, + infinity)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>close_session(Client, Timeout) -> Result</name> + <fsummary>Requests graceful termination of the session associated with + the client.</fsummary> + <type> + <v>Client = client()</v> + <v>Timeout = timeout()</v> + <v>Result = ok | {error, error_reason()}</v> + </type> + <desc><marker id="close_session-2"/> + <p>Requests graceful termination of the session associated with the + client.</p> + + <p>When a NETCONF server receives a <c>close-session</c> request, it + gracefully closes the session. The server releases any locks and + resources associated with the session and gracefully closes any + associated connections. Any NETCONF requests received after a + <c>close-session</c> request are ignored.</p> + </desc> + </func> + + <func> + <name>copy_config(Client, Source, Target) -> Result</name> + <fsummary>Equivalent to copy_config(Client, Source, Target, + infinity).</fsummary> + <desc><marker id="copy_config-3"/> + <p>Equivalent to + <seealso marker="#copy_config-4"><c>ct_netconfc:copy_config(Client, + Source, Target, infinity)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>copy_config(Client, Target, Source, Timeout) -> Result</name> + <fsummary>Copies configuration data.</fsummary> + <type> + <v>Client = client()</v> + <v>Target = netconf_db()</v> + <v>Source = netconf_db()</v> + <v>Timeout = timeout()</v> + <v>Result = ok | {error, error_reason()}</v> + </type> + <desc><marker id="copy_config-4"/> + <p>Copies configuration data.</p> + + <p>Which source and target options that can be issued depends on the + capabilities supported by the server. That is, <c>:candidate</c> + and/or <c>:startup</c> are required.</p> + </desc> + </func> + + <func> + <name>create_subscription(Client) -> term()</name> + <fsummary>Creates a subscription for event notifications.</fsummary> + <desc><marker id="create_subscription-1"/></desc> + </func> + + <func> + <name>create_subscription(Client, Timeout) -> term()</name> + <fsummary>Creates a subscription for event notifications.</fsummary> + <desc><marker id="create_subscription-2"/></desc> + </func> + + <func> + <name>create_subscription(Client, Stream, Timeout) -> term()</name> + <fsummary>Creates a subscription for event notifications.</fsummary> + <desc><marker id="create_subscription-3"/></desc> + </func> + + <func> + <name>create_subscription(Client, StartTime, StopTime, Timeout) -> term()</name> + <fsummary>Creates a subscription for event notifications.</fsummary> + <desc><marker id="create_subscription-4"/></desc> + </func> + + <func> + <name>create_subscription(Client, Stream, StartTime, StopTime, Timeout) -> term()</name> + <fsummary>Creates a subscription for event notifications.</fsummary> + <desc><marker id="create_subscription-5"/></desc> + </func> + + <func> + <name>create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout) -> Result</name> + <fsummary>Creates a subscription for event notifications.</fsummary> + <type> + <v>Client = client()</v> + <v>Stream = stream_name()</v> + <v>Filter = simple_xml() | [simple_xml()]</v> + <v>StartTime = xs_datetime()</v> + <v>StopTime = xs_datetime()</v> + <v>Timeout = timeout()</v> + <v>Result = ok | {error, error_reason()}</v> + </type> + <desc><marker id="create_subscription-6"/> + <p>Creates a subscription for event notifications.</p> + + <p>This function sets up a subscription for NETCONF event + notifications of the specified stream type, matching the specified + filter. The calling process receives notifications as messages of + type <c>notification()</c>.</p> + + <taglist> + <tag><c>Stream</c></tag> + <item><p>Optional parameter that indicates which stream of event + is of interest. If not present, events in the default NETCONF + stream are sent.</p></item> + <tag><c>Filter</c></tag> + <item><p>Optional parameter that indicates which subset of all + possible events is of interest. The parameter format is the + same as that of the filter parameter in the NETCONF protocol + operations. If not present, all events not precluded by other + parameters are sent.</p></item> + <tag><c>StartTime</c></tag> + <item><p>Optional parameter used to trigger the replay feature and + indicate that the replay is to start at the time specified. + If <c>StartTime</c> is not present, this is not a replay + subscription.</p> + <p>It is not valid to specify start times that are later than + the current time. If <c>StartTime</c> is specified earlier + than the log can support, the replay begins with the earliest + available notification.</p> + <p>This parameter is of type <c>dateTime</c> and compliant to + RFC 3339. Implementations must support time zones.</p></item> + <tag><c>StopTime</c></tag> + <item><p>Optional parameter used with the optional replay feature + to indicate the newest notifications of interest. If + <c>StopTime</c> is not present, the notifications continues + until the subscription is terminated.</p> + <p>Must be used with and be later than <c>StartTime</c>. Values + of <c>StopTime</c> in the future are valid. This parameter is + of type <c>dateTime</c> and compliant to RFC 3339. + Implementations must support time zones.</p></item> + </taglist> + + <p>For more details about the event notification mechanism, see + RFC 5277.</p> + </desc> + </func> + + <func> + <name>delete_config(Client, Target) -> Result</name> + <fsummary>Equivalent to delete_config(Client, Target, + infinity).</fsummary> + <desc><marker id="delete_config-2"/> + <p>Equivalent to + <seealso marker="#delete_config-3"><c>ct_netconfc:delete_config(Client, Target, infinity)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>delete_config(Client, Target, Timeout) -> Result</name> + <fsummary>Deletes configuration data.</fsummary> + <type> + <v>Client = client()</v> + <v>Target = startup | candidate</v> + <v>Timeout = timeout()</v> + <v>Result = ok | {error, error_reason()}</v> + </type> + <desc><marker id="delete_config-3"/> + <p>Deletes configuration data.</p> + + <p>The running configuration cannot be deleted and <c>:candidate</c> + or <c>:startup</c> must be advertised by the server.</p> + </desc> + </func> + + <func> + <name>edit_config(Client, Target, Config) -> Result</name> + <fsummary>Equivalent to edit_config(Client, Target, Config, [], + infinity).</fsummary> + <desc><marker id="edit_config-3"/> + <p>Equivalent to + <seealso marker="#edit_config-5"><c>ct_netconfc:edit_config(Client, + Target, Config, [], infinity)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>edit_config(Client, Target, Config, OptParamsOrTimeout) -> Result</name> + <fsummary>If OptParamsOrTimeout is a time-out value, this function is + equivalent to ct_netconfc:edit_config(Client, Target, Config, [], + Timeout).</fsummary> + <type> + <v>Client = client()</v> + <v>Target = netconf_db()</v> + <v>Config = simple_xml()</v> + <v>OptParamsOrTimeout = [simple_xml()] | timeout()</v> + <v>Result = ok | {error, error_reason()}</v> + </type> + <desc><marker id="edit_config-4"/> + <p>If <c>OptParamsOrTimeout</c> is a time-out value, this function is + equivalent to + <seealso marker="#edit_config-5"><c>ct_netconfc:edit_config(Client, + Target, Config, [], Timeout)</c></seealso>.</p> + + <p>If <c>OptParamsOrTimeout</c> is a list of simple XML, this + function is equivalent to + <seealso marker="#edit_config-5"><c>ct_netconfc:edit_config(Client, + Target, Config, OptParams, infinity)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>edit_config(Client, Target, Config, OptParams, Timeout) -> Result</name> + <fsummary>Edits configuration data.</fsummary> + <type> + <v>Client = client()</v> + <v>Target = netconf_db()</v> + <v>Config = simple_xml()</v> + <v>OptParams = [simple_xml()]</v> + <v>Timeout = timeout()</v> + <v>Result = ok | {error, error_reason()}</v> + </type> + <desc><marker id="edit_config-5"/> + <p>Edits configuration data.</p> + + <p>By default only the running target is available, unless the server + includes <c>:candidate</c> or <c>:startup</c> in its list of + capabilities.</p> + + <p><c>OptParams</c> can be used for specifying optional parameters + (<c>default-operation</c>, <c>test-option</c>, or + <c>error-option</c>) to be added to the <c>edit-config</c> + request. The value must be a list containing valid simple XML, + for example:</p> + + <pre> + [{'default-operation', ["none"]}, + {'error-option', ["rollback-on-error"]}]</pre> + </desc> + </func> + + <func> + <name>get(Client, Filter) -> Result</name> + <fsummary>Equivalent to get(Client, Filter, infinity).</fsummary> + <desc><marker id="get-2"/> + <p>Equivalent to + <seealso marker="#get-3"><c>ct_netconfc:get(Client, Filter, + infinity)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>get(Client, Filter, Timeout) -> Result</name> + <fsummary>Gets data.</fsummary> + <type> + <v>Client = client()</v> + <v>Filter = simple_xml() | xpath()</v> + <v>Timeout = timeout()</v> + <v>Result = {ok, [simple_xml()]} | {error, error_reason()}</v> + </type> + <desc><marker id="get-3"/> + <p>Gets data.</p> + + <p>This operation returns both configuration and state data from the + server.</p> + + <p>Filter type <c>xpath</c> can be used only if the server supports + <c>:xpath</c>.</p> + </desc> + </func> + + <func> + <name>get_capabilities(Client) -> Result</name> + <fsummary>Equivalent to get_capabilities(Client, infinity).</fsummary> + <desc><marker id="get_capabilities-1"/> + <p>Equivalent to + <seealso marker="#get_capabilities-2"><c>ct_netconfc:get_capabilities(Client, + infinity)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>get_capabilities(Client, Timeout) -> Result</name> + <fsummary>Returns the server side capabilities.</fsummary> + <type> + <v>Client = client()</v> + <v>Timeout = timeout()</v> + <v>Result = [string()] | {error, error_reason()}</v> + </type> + <desc><marker id="get_capabilities-2"/> + <p>Returns the server side capabilities.</p> + + <p>The following capability identifiers, defined in RFC 4741 NETCONF + Configuration Protocol, can be returned:</p> + + <list> + <item><p><c>"urn:ietf:params:netconf:base:1.0"</c></p></item> + <item><p><c>"urn:ietf:params:netconf:capability:writable-running:1.0"</c></p></item> + <item><p><c>"urn:ietf:params:netconf:capability:candidate:1.0"</c></p></item> + <item><p><c>"urn:ietf:params:netconf:capability:confirmed-commit:1.0"</c></p></item> + <item><p><c>"urn:ietf:params:netconf:capability:rollback-on-error:1.0"</c></p></item> + <item><p><c>"urn:ietf:params:netconf:capability:startup:1.0"</c></p></item> + <item><p><c>"urn:ietf:params:netconf:capability:url:1.0"</c></p></item> + <item><p><c>"urn:ietf:params:netconf:capability:xpath:1.0"</c></p></item> + </list> + + <p>More identifiers can exist, for example, server-side namespace.</p> + </desc> + </func> + + <func> + <name>get_config(Client, Source, Filter) -> Result</name> + <fsummary>Equivalent to get_config(Client, Source, Filter, + infinity).</fsummary> + <desc><marker id="get_config-3"/> + <p>Equivalent to + <seealso marker="#get_config-4"><c>ct_netconfc:get_config(Client, Source, Filter, infinity)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>get_config(Client, Source, Filter, Timeout) -> Result</name> + <fsummary>Gets configuration data.</fsummary> + <type> + <v>Client = client()</v> + <v>Source = netconf_db()</v> + <v>Filter = simple_xml() | xpath()</v> + <v>Timeout = timeout()</v> + <v>Result = {ok, [simple_xml()]} | {error, error_reason()}</v> + </type> + <desc><marker id="get_config-4"/> + <p>Gets configuration data.</p> + + <p>To be able to access another source than <c>running</c>, the + server must advertise <c>:candidate</c> and/or <c>:startup</c>.</p> + + <p>Filter type <c>xpath</c> can be used only if the server supports + <c>:xpath</c>.</p> + </desc> + </func> + + <func> + <name>get_event_streams(Client, Timeout) -> Result</name> + <fsummary>Equivalent to get_event_streams(Client, [], Timeout).</fsummary> + <desc><marker id="get_event_streams-2"/> + <p>Equivalent to + <seealso marker="#get_event_streams-3"><c>ct_netconfc:get_event_streams(Client, + [], Timeout)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>get_event_streams(Client, Streams, Timeout) -> Result</name> + <fsummary>Sends a request to get the specified event streams.</fsummary> + <type> + <v>Client = client()</v> + <v>Streams = [stream_name()]</v> + <v>Timeout = timeout()</v> + <v>Result = {ok, streams()} | {error, error_reason()}</v> + </type> + <desc><marker id="get_event_streams-3"/> + <p>Sends a request to get the specified event streams.</p> + + <p><c>Streams</c> is a list of stream names. The following filter is + sent to the NETCONF server in a <c>get</c> request:</p> + + <pre> + <netconf xmlns="urn:ietf:params:xml:ns:netmod:notification"> + <streams> + <stream> + <name>StreamName1</name> + </stream> + <stream> + <name>StreamName2</name> + </stream> + ... + </streams> + </netconf></pre> + + <p>If <c>Streams</c> is an empty list, <em>all</em> streams are + requested by sending the following filter:</p> + + <pre> + <netconf xmlns="urn:ietf:params:xml:ns:netmod:notification"> + <streams/> + </netconf></pre> + + <p>If more complex filtering is needed, use + <seealso marker="#get-2"><c>ct_netconfc:get/2</c></seealso> or + <seealso marker="#get-3"><c>ct_netconfc:get/3</c></seealso> and + specify the exact filter according to "XML Schema for Event + Notifications" in RFC 5277.</p> + </desc> + </func> + + <func> + <name>get_session_id(Client) -> Result</name> + <fsummary>Equivalent to get_session_id(Client, infinity).</fsummary> + <desc><marker id="get_session_id-1"/> + <p>Equivalent to + <seealso marker="#get_session_id-2"><c>ct_netconfc:get_session_id(Client, + infinity)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>get_session_id(Client, Timeout) -> Result</name> + <fsummary>Returns the session Id associated with the specified + client.</fsummary> + <type> + <v>Client = client()</v> + <v>Timeout = timeout()</v> + <v>Result = pos_integer() | {error, error_reason()}</v> + </type> + <desc><marker id="get_session_id-2"/> + <p>Returns the session Id associated with the specified client.</p> + </desc> + </func> + + <func> + <name>hello(Client) -> Result</name> + <fsummary>Equivalent to hello(Client, [], infinity).</fsummary> + <desc><marker id="hello-1"/> + <p>Equivalent to + <seealso marker="#hello-3"><c>ct_netconfc:hello(Client, [], + infinity)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>hello(Client, Timeout) -> Result</name> + <fsummary>Equivalent to hello(Client, [], Timeout).</fsummary> + <desc><marker id="hello-2"/> + <p>Equivalent to + <seealso marker="#hello-3"><c>ct_netconfc:hello(Client, [], + Timeout)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>hello(Client, Options, Timeout) -> Result</name> + <fsummary>Exchanges hello messages with the server.</fsummary> + <type> + <v>Client = handle()</v> + <v>Options = [{capability, [string()]}]</v> + <v>Timeout = timeout()</v> + <v>Result = ok | {error, error_reason()}</v> + </type> + <desc><marker id="hello-3"/> + <p>Exchanges <c>hello</c> messages with the server.</p> + + <p>Adds optional capabilities and sends a <c>hello</c> message to the + server and waits for the return.</p> + </desc> + </func> + + <func> + <name>kill_session(Client, SessionId) -> Result</name> + <fsummary>Equivalent to kill_session(Client, SessionId, + infinity).</fsummary> + <desc><marker id="kill_session-2"/> + <p>Equivalent to + <seealso marker="#kill_session-3"><c>ct_netconfc:kill_session(Client, +SessionId, infinity)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>kill_session(Client, SessionId, Timeout) -> Result</name> + <fsummary>Forces termination of the session associated with the supplied + session Id.</fsummary> + <type> + <v>Client = client()</v> + <v>SessionId = pos_integer()</v> + <v>Timeout = timeout()</v> + <v>Result = ok | {error, error_reason()}</v> + </type> + <desc><marker id="kill_session-3"/> + <p>Forces termination of the session associated with the supplied + session Id.</p> + + <p>The server side must abort any ongoing operations, release any + locks and resources associated with the session, and close any + associated connections.</p> + + <p>Only if the server is in the confirmed commit phase, the + configuration is restored to its state before entering the confirmed + commit phase. Otherwise, no configuration rollback is performed.</p> + + <p>If the specified <c>SessionId</c> is equal to the current session + Id, an error is returned.</p> + </desc> + </func> + + <func> + <name>lock(Client, Target) -> Result</name> + <fsummary>Equivalent to lock(Client, Target, infinity).</fsummary> + <desc><marker id="lock-2"/> + <p>Equivalent to + <seealso marker="#lock-3"><c>ct_netconfc:lock(Client, Target, + infinity)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>lock(Client, Target, Timeout) -> Result</name> + <fsummary>Unlocks the configuration target.</fsummary> + <type> + <v>Client = client()</v> + <v>Target = netconf_db()</v> + <v>Timeout = timeout()</v> + <v>Result = ok | {error, error_reason()}</v> + </type> + <desc><marker id="lock-3"/> + <p>Unlocks the configuration target.</p> + + <p>Which target parameters that can be used depends on if + <c>:candidate</c> and/or <c>:startup</c> are supported by the + server. If successfull, the configuration system of the device is + unavailable to other clients (NETCONF, CORBA, SNMP, and so on). + Locks are intended to be short-lived.</p> + + <p>Operation + <seealso marker="#kill_session-2"><c>ct_netconfc:kill_session/2</c></seealso> + or + <seealso marker="#kill_session-3"><c>ct_netconfc:kill_session/3</c></seealso> + can be used to force the release of a lock owned by another NETCONF + session. How this is achieved by the server side is + implementation-specific.</p> + </desc> + </func> + + <func> + <name>only_open(Options) -> Result</name> + <fsummary>Opens a NETCONF session, but does not send hello.</fsummary> + <type> + <v>Options = options()</v> + <v>Result = {ok, handle()} | {error, error_reason()}</v> + </type> + <desc><marker id="only_open-1"/> + <p>Opens a NETCONF session, but does not send <c>hello</c>.</p> + + <p>As <seealso marker="#open-1"><c>ct_netconfc:open/1</c></seealso>, + but does not send a <c>hello</c> message.</p> + </desc> + </func> + + <func> + <name>only_open(KeyOrName, ExtraOptions) -> Result</name> + <fsummary>Opens a name NETCONF session, but does not send + hello.</fsummary> + <type> + <v>KeyOrName = key_or_name()</v> + <v>ExtraOptions = options()</v> + <v>Result = {ok, handle()} | {error, error_reason()}</v> + </type> + <desc><marker id="only_open-2"/> + <p>Opens a name NETCONF session, but does not send <c>hello</c>.</p> + + <p>As <seealso marker="#open-2"><c>ct_netconfc:open/2</c></seealso>, + but does not send a <c>hello</c> message.</p> + </desc> + </func> + + <func> + <name>open(Options) -> Result</name> + <fsummary>Opens a NETCONF session and exchanges hello messages.</fsummary> + <type> + <v>Options = options()</v> + <v>Result = {ok, handle()} | {error, error_reason()}</v> + </type> + <desc><marker id="open-1"/> + <p>Opens a NETCONF session and exchanges <c>hello</c> messages.</p> + + <p>If the server options are specified in a configuration file, + or if a named client is needed for logging purposes (see section + <seealso marker="#Logging">Logging</seealso> in this module), use + <seealso marker="#open-2"><c>ct_netconfc:open/2</c></seealso> + instead.</p> + + <p>The opaque <c>handle()</c> reference returned from this + function is required as client identifier when calling any other + function in this module.</p> + + <p>Option <c>timeout</c> (milliseconds) is used when setting up the + SSH connection and when waiting for the <c>hello</c> message from + the server. It is not used for any other purposes during the + lifetime of the connection.</p> + </desc> + </func> + + <func> + <name>open(KeyOrName, ExtraOptions) -> Result</name> + <fsummary>Opens a named NETCONF session and exchanges hello + messages.</fsummary> + <type> + <v>KeyOrName = key_or_name()</v> + <v>ExtraOptions = options()</v> + <v>Result = {ok, handle()} | {error, error_reason()}</v> + </type> + <desc><marker id="open-2"/> + <p>Opens a named NETCONF session and exchanges <c>hello</c> + messages.</p> + + <p>If <c>KeyOrName</c> is a configured <c>server_id()</c> or a + <c>target_name()</c> associated with such an Id, then the options + for this server are fetched from the configuration file.</p> + + <p>Argument <c>ExtraOptions</c> is added to the options found in the + configuration file. If the same options are specified, the values + from the configuration file overwrite <c>ExtraOptions</c>.</p> + + <p>If the server is not specified in a configuration file, use + <seealso marker="#open-1"><c>ct_netconfc:open/1</c></seealso> + instead.</p> + + <p>The opaque <c>handle()</c> reference returned from this + function can be used as client identifier when calling any other + function in this module. However, if <c>KeyOrName</c> is a + <c>target_name()</c>, that is, if the server is named through a + call to <seealso marker="ct#require-2"><c>ct:require/2</c></seealso> + or a <c>require</c> statement in the test suite, then this name can + be used instead of <c>handle()</c>.</p> + + <p>Option <c>timeout</c> (milliseconds) is used when setting up the + SSH connection and when waiting for the <c>hello</c> message from + the server. It is not used for any other purposes during the + lifetime of the connection.</p> + + <p>See also + <seealso marker="ct#require-2"><c>ct:require/2</c></seealso>.</p> + </desc> + </func> + + <func> + <name>send(Client, SimpleXml) -> Result</name> + <fsummary>Equivalent to send(Client, SimpleXml, infinity).</fsummary> + <desc><marker id="send-2"/> + <p>Equivalent to + <seealso marker="#send-3"><c>ct_netconfc:send(Client, SimpleXml, + infinity)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>send(Client, SimpleXml, Timeout) -> Result</name> + <fsummary>Sends an XML document to the server.</fsummary> + <type> + <v>Client = client()</v> + <v>SimpleXml = simple_xml()</v> + <v>Timeout = timeout()</v> + <v>Result = simple_xml() | {error, error_reason()}</v> + </type> + <desc><marker id="send-3"/> + <p>Sends an XML document to the server.</p> + + <p>The specified XML document is sent "as is" to the server. This + function can be used for sending XML documents that cannot be + expressed by other interface functions in this module.</p> + </desc> + </func> + + <func> + <name>send_rpc(Client, SimpleXml) -> Result</name> + <fsummary>Equivalent to send_rpc(Client, SimpleXml, infinity).</fsummary> + <desc><marker id="send_rpc-2"/> + <p>Equivalent to + <seealso marker="#send_rpc-3"><c>ct_netconfc:send_rpc(Client, + SimpleXml, infinity)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>send_rpc(Client, SimpleXml, Timeout) -> Result</name> + <fsummary>Sends a NETCONF rpc request to the server.</fsummary> + <type> + <v>Client = client()</v> + <v>SimpleXml = simple_xml()</v> + <v>Timeout = timeout()</v> + <v>Result = [simple_xml()] | {error, error_reason()}</v> + </type> + <desc><marker id="send_rpc-3"/> + <p>Sends a NETCONF <c>rpc</c> request to the server.</p> + + <p>The specified XML document is wrapped in a valid NETCONF <c>rpc</c> + request and sent to the server. The <c>message-id</c> and namespace + attributes are added to element <c>rpc</c>.</p> + + <p>This function can be used for sending <c>rpc</c> requests that + cannot be expressed by other interface functions in this module.</p> + </desc> + </func> + + <func> + <name>unlock(Client, Target) -> Result</name> + <fsummary>Equivalent to unlock(Client, Target, infinity).</fsummary> + <desc><marker id="unlock-2"/> + <p>Equivalent to + <seealso marker="#unlock-3"><c>ct_netconfc:unlock(Client, Target, + infinity)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>unlock(Client, Target, Timeout) -> Result</name> + <fsummary>Unlocks the configuration target.</fsummary> + <type> + <v>Client = client()</v> + <v>Target = netconf_db()</v> + <v>Timeout = timeout()</v> + <v>Result = ok | {error, error_reason()}</v> + </type> + <desc><marker id="unlock-3"/> + <p>Unlocks the configuration target.</p> + + <p>If the client earlier has acquired a lock through + <seealso marker="#lock-2"><c>ct_netconfc:lock/2</c></seealso> or + <seealso marker="#lock-3"><c>ct_netconfc:lock/3</c></seealso>, this + operation releases the associated lock. To access another target + than <c>running</c>, the server must support <c>:candidate</c> + and/or <c>:startup</c>.</p> + </desc> + </func> + </funcs> + +</erlref> + + diff --git a/lib/common_test/doc/src/ct_property_test.xml b/lib/common_test/doc/src/ct_property_test.xml new file mode 100644 index 0000000000..2e9bd1969c --- /dev/null +++ b/lib/common_test/doc/src/ct_property_test.xml @@ -0,0 +1,116 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2010</year><year>2012</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + </legalnotice> + + <title>ct_property_test</title> + <prepared></prepared> + <responsible></responsible> + <docno></docno> + <approved></approved> + <checked></checked> + <date></date> + <rev>A</rev> + <file>ct_property_test.xml</file> + </header> + <module>ct_property_test</module> + <modulesummary>EXPERIMENTAL support in Common Test for calling + property-based tests.</modulesummary> + + <description> + + <p>EXPERIMENTAL support in <c>Common Test</c> for calling property-based + tests.</p> + + <p>This module is a first step to run property-based tests in the + <c>Common Test</c> framework. A property testing tool like QuickCheck + or PropEr is assumed to be installed.</p> + + <p>The idea is to have a <c>Common Test</c> test suite calling a property + testing tool with special property test suites as defined by that tool. + The usual Erlang application directory structure is assumed. The tests + are collected in the <c>test</c> directory of the application. The + <c>test</c> directory has a subdirectory <c>property_test</c>, where + everything needed for the property tests is collected.</p> + + <p>A typical <c>Common Test</c> test suite using <c>ct_property_test</c> + is organized as follows:</p> + + <pre> + -include_lib("common_test/include/ct.hrl"). + + all() -> [prop_ftp_case]. + + init_per_suite(Config) -> + ct_property_test:init_per_suite(Config). + + %%%---- test case + prop_ftp_case(Config) -> + ct_property_test:quickcheck( + ftp_simple_client_server:prop_ftp(Config), + Config + ).</pre> + + <warning> + <p>This is experimental code that can be changed or removed anytime + without any warning.</p> + </warning> + + </description> + + <funcs> + <func> + <name>init_per_suite(Config) -> Config | {skip, Reason}</name> + <fsummary>Initializes Config for property testing.</fsummary> + <desc><marker id="init_per_suite-1"/> + <p>Initializes <c>Config</c> for property testing.</p> + + <p>This function investigates if support is available for either + Quickcheck, PropEr, or Triq. The options + <c>{property_dir,AbsPath}</c> and <c>{property_test_tool,Tool}</c> + are set in the <c>Config</c> returned.</p> + + <p>The function is intended to be called in function + <c>init_per_suite</c> in the test suite.</p> + + <p>The property tests are assumed to be in subdirectory + <c>property_test</c>.</p> + </desc> + </func> + + <func> + <name>quickcheck(Property, Config) -> true | {fail, Reason}</name> + <fsummary>Calls quickcheck and returns the result in a form suitable for + Common Test.</fsummary> + <desc><marker id="quickcheck-2"/> + <p>Calls quickcheck and returns the result in a form suitable for + <c>Common Test</c>.</p> + + <p>This function is intended to be called in the test cases in the + test suite.</p> + </desc> + </func> + </funcs> + +</erlref> + + diff --git a/lib/common_test/doc/src/ct_rpc.xml b/lib/common_test/doc/src/ct_rpc.xml new file mode 100644 index 0000000000..0169727581 --- /dev/null +++ b/lib/common_test/doc/src/ct_rpc.xml @@ -0,0 +1,220 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2010</year><year>2012</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + </legalnotice> + + <title>ct_rpc</title> + <prepared></prepared> + <responsible></responsible> + <docno></docno> + <approved></approved> + <checked></checked> + <date></date> + <rev>A</rev> + <file>ct_rpc.xml</file> + </header> + <module>ct_rpc</module> + <modulesummary>Common Test specific layer on Erlang/OTP rpc.</modulesummary> + + <description> + + <p><c>Common Test</c> specific layer on Erlang/OTP <c>rpc</c>.</p> + + </description> + + <funcs> + <func> + <name>app_node(App, Candidates) -> NodeName</name> + <fsummary>From a set of candidate nodes determines which of them is + running the application App.</fsummary> + <type> + <v>App = atom()</v> + <v>Candidates = [NodeName]</v> + <v>NodeName = atom()</v> + </type> + <desc><marker id="app_node-2"/> + <p>From a set of candidate nodes determines which of them is running + the application <c>App</c>. If none of the candidate nodes is + running <c>App</c>, the function makes the test case calling + this function to fail. This function is the same as calling + <c>app_node(App, Candidates, true)</c>.</p> + </desc> + </func> + + <func> + <name>app_node(App, Candidates, FailOnBadRPC) -> NodeName</name> + <fsummary>Same as app_node/2, except that argument FailOnBadRPC + determines if the search for a candidate node is to stop if + badrpc is received at some point.</fsummary> + <type> + <v>App = atom()</v> + <v>Candidates = [NodeName]</v> + <v>NodeName = atom()</v> + <v>FailOnBadRPC = true | false</v> + </type> + <desc><marker id="app_node-3"/> + <p>Same as + <seealso marker="#app_node-2"><c>ct_rpc:app_node/2</c></seealso>, + except that argument <c>FailOnBadRPC</c> determines if the search + for a candidate node is to stop if <c>badrpc</c> is received at + some point.</p> + </desc> + </func> + + <func> + <name>app_node(App, Candidates, FailOnBadRPC, Cookie) -> NodeName</name> + <fsummary>Same as app_node/2, except that argument FailOnBadRPC + determines if the search for a candidate node is to stop if badrpc is + received at some point.</fsummary> + <type> + <v>App = atom()</v> + <v>Candidates = [NodeName]</v> + <v>NodeName = atom()</v> + <v>FailOnBadRPC = true | false</v> + <v>Cookie = atom()</v> + </type> + <desc><marker id="app_node-4"/> + <p>Same as + <seealso marker="#app_node-2"><c>ct_rpc:app_node/2</c></seealso>, + except that argument <c>FailOnBadRPC</c> determines if the search + for a candidate node is to stop if <c>badrpc</c> is received at + some point.</p> + + <p>The cookie on the client node is set to <c>Cookie</c> for this + <c>rpc</c> operation (used to match the server node cookie).</p> + </desc> + </func> + + <func> + <name>call(Node, Module, Function, Args) -> term() | {badrpc, Reason}</name> + <fsummary>Same as call(Node, Module, Function, Args, infinity).</fsummary> + <desc><marker id="call-4"/> + <p>Same as <c>call(Node, Module, Function, Args, infinity)</c>.</p> + </desc> + </func> + + <func> + <name>call(Node, Module, Function, Args, TimeOut) -> term() | {badrpc, Reason}</name> + <fsummary>Evaluates apply(Module, Function, Args) on the node + Node.</fsummary> + <type> + <v>Node = NodeName | {Fun, FunArgs}</v> + <v>Fun = function()</v> + <v>FunArgs = term()</v> + <v>NodeName = atom()</v> + <v>Module = atom()</v> + <v>Function = atom()</v> + <v>Args = [term()]</v> + <v>Reason = timeout | term()</v> + </type> + <desc><marker id="call-5"/> + <p>Evaluates <c>apply(Module, Function, Args)</c> on the node + <c>Node</c>. Returns either whatever <c>Function</c> returns, or + <c>{badrpc, Reason}</c> if the remote procedure call fails. If + <c>Node</c> is <c>{Fun, FunArgs}</c>, applying <c>Fun</c> to + <c>FunArgs</c> is to return a node name.</p> + </desc> + </func> + + <func> + <name>call(Node, Module, Function, Args, TimeOut, Cookie) -> term() | {badrpc, Reason}</name> + <fsummary>Evaluates apply(Module, Function, Args) on the node + Node.</fsummary> + <type> + <v>Node = NodeName | {Fun, FunArgs}</v> + <v>Fun = function()</v> + <v>FunArgs = term()</v> + <v>NodeName = atom()</v> + <v>Module = atom()</v> + <v>Function = atom()</v> + <v>Args = [term()]</v> + <v>Reason = timeout | term()</v> + <v>Cookie = atom()</v> + </type> + <desc><marker id="call-6"/> + <p>Evaluates <c>apply(Module, Function, Args)</c> on the node + <c>Node</c>. Returns either whatever <c>Function</c> returns, or + <c>{badrpc, Reason}</c> if the remote procedure call fails. If + <c>Node</c> is <c>{Fun, FunArgs}</c>, applying <c>Fun</c> to + <c>FunArgs</c> is to return a node name.</p> + + <p>The cookie on the client node is set to <c>Cookie</c> for this + <c>rpc</c> operation (used to match the server node cookie).</p> + </desc> + </func> + + <func> + <name>cast(Node, Module, Function, Args) -> ok</name> + <fsummary>Evaluates apply(Module, Function, Args) on the node + Node.</fsummary> + <type> + <v>Node = NodeName | {Fun, FunArgs}</v> + <v>Fun = function()</v> + <v>FunArgs = term()</v> + <v>NodeName = atom()</v> + <v>Module = atom()</v> + <v>Function = atom()</v> + <v>Args = [term()]</v> + <v>Reason = timeout | term()</v> + </type> + <desc><marker id="cast-4"/> + <p>Evaluates <c>apply(Module, Function, Args)</c> on the node + <c>Node</c>. No response is delivered and the process that makes + the call is not suspended until the evaluation is completed as in + the case of <c>call/3,4</c>. If <c>Node</c> is + <c>{Fun, FunArgs}</c>, applying <c>Fun</c> to <c>FunArgs</c> is to + return a node name.</p> + </desc> + </func> + + <func> + <name>cast(Node, Module, Function, Args, Cookie) -> ok</name> + <fsummary>Evaluates apply(Module, Function, Args) on the node + Node.</fsummary> + <type> + <v>Node = NodeName | {Fun, FunArgs}</v> + <v>Fun = function()</v> + <v>FunArgs = term()</v> + <v>NodeName = atom()</v> + <v>Module = atom()</v> + <v>Function = atom()</v> + <v>Args = [term()]</v> + <v>Reason = timeout | term()</v> + <v>Cookie = atom()</v> + </type> + <desc><marker id="cast-5"/> + <p>Evaluates <c>apply(Module, Function, Args)</c> on the node + <c>Node</c>. No response is delivered and the process that makes + the call is not suspended until the evaluation is completed as in + the case of <c>call/3,4</c>. If <c>Node</c> is + <c>{Fun, FunArgs}</c>, applying <c>Fun</c> to <c>FunArgs</c> is to + return a node name.</p> + + <p>The cookie on the client node is set to <c>Cookie</c> for this + <c>rpc</c> operation (used to match the server node cookie).</p> + </desc> + </func> + </funcs> + +</erlref> + + diff --git a/lib/common_test/doc/src/ct_run.xml b/lib/common_test/doc/src/ct_run.xml index 5518bb039b..2552938346 100644 --- a/lib/common_test/doc/src/ct_run.xml +++ b/lib/common_test/doc/src/ct_run.xml @@ -34,178 +34,192 @@ </header> <com>ct_run</com> <comsummary>Program used for starting Common Test from the - OS command line. - </comsummary> + OS command line.</comsummary> <description> <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>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> - - <p>There is an interface function that corresponds to this program, - called <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso>, for starting Common Test from the Erlang - shell (or an Erlang program). Please see the <c>ct</c> man page for - details.</p> + and the <c>Common Test</c> application (for more information, see + section <seealso marker="install_chapter">Installation</seealso> + in the User's Guide). The program accepts different start flags. + Some flags trigger <c>ct_run</c> to start <c>Common Test</c> and + pass on data to it. Some flags start an Erlang node prepared for + running <c>Common Test</c> in a particular mode.</p> + + <p>The interface function + <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso>, + corresponding to the <c>ct_run</c> program, is used for starting + <c>Common Test</c> from the Erlang shell (or an Erlang program). + For details, see the <seealso marker="ct"><c>ct</c></seealso> + manual page.</p> <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>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 + when <c>ct_run</c> calls <c>erl</c> to start the Erlang node (this + makes it possible to add directories to the code server path, + change the cookie on the node, start more applications, and so on).</p> + + <p>With the optional flag <c>-erl_args</c>, options on the <c>ct_run</c> + command line can be divided into two groups:</p> + + <list type="bulleted"> + <item>One group that <c>Common Test</c> is to process (those + preceding <c>-erl_args</c>).</item> + <item>One group that <c>Common Test</c> is to ignore and pass on + directly to the emulator (those following <c>-erl_args</c>).</item> + </list> + + <p>Options preceding <c>-erl_args</c> that <c>Common Test</c> + does not recognize are also passed on to the emulator untouched. + By <c>-erl_args</c> the user can specify flags with the same name, but 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 - problems loading user modules when Common Test changes working directory - during test runs). Common Test will however ignore <c>-pa</c> and <c>-pz</c> flags - 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>Exit status is set before the program ends. Value <c>0</c> indicates a successful - test result, <c>1</c> indicates one or more failed or auto-skipped test cases, and - <c>2</c> indicates test execution failure.</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> + <p>If flags <c>-pa</c> or <c>-pz</c> are specified in the + <c>Common Test</c> group of options (preceding <c>-erl_args</c>), + relative directories are converted to absolute and reinserted into + the code path by <c>Common Test</c>. This is to avoid problems + loading user modules when <c>Common Test</c> changes working directory + during test runs. However, <c>Common Test</c> ignores flags <c>-pa</c> + and <c>-pz</c> following <c>-erl_args</c> on the command line. These + directories are added to the code path normally (that is, on specified + form).</p> + + <p>Exit status is set before the program ends. Value <c>0</c> indicates + a successful test result, <c>1</c> indicates one or more failed or + auto-skipped test cases, and <c>2</c> indicates test execution failure.</p> + + <p>If <c>ct_run</c> is called with option <c>-help</c>, it prints all + valid start flags to <c>stdout</c>.</p> + </description> <section> <marker id="ct_run"></marker> - <title>Run tests from command line</title> + <title>Run Tests from Command Line</title> <pre> - ct_run -dir TestDir1 TestDir2 .. TestDirN | - [-dir TestDir] -suite Suite1 Suite2 .. SuiteN - [-group Groups1 Groups2 .. GroupsN] [-case Case1 Case2 .. CaseN] - [-step [config | keep_inactive]] - [-config ConfigFile1 ConfigFile2 .. ConfigFileN] - [-userconfig CallbackModule1 ConfigString1 and CallbackModule2 - ConfigString2 and .. CallbackModuleN ConfigStringN] - [-decrypt_key Key] | [-decrypt_file KeyFile] - [-label Label] - [-logdir LogDir] - [-logopts LogOpts] - [-verbosity GenVLevel | [Category1 VLevel1 and - Category2 VLevel2 and .. CategoryN VLevelN]] - [-silent_connections [ConnType1 ConnType2 .. ConnTypeN]] - [-stylesheet CSSFile] - [-cover CoverCfgFile] - [-cover_stop Bool] - [-event_handler EvHandler1 EvHandler2 .. EvHandlerN] | - [-event_handler_init EvHandler1 InitArg1 and - EvHandler2 InitArg2 and .. EvHandlerN InitArgN] - [-include InclDir1 InclDir2 .. InclDirN] - [-no_auto_compile] - [-abort_if_missing_suites] - [-muliply_timetraps Multiplier] - [-scale_timetraps] - [-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc] - [-repeat N] | - [-duration HHMMSS [-force_stop [skip_rest]]] | - [-until [YYMoMoDD]HHMMSS [-force_stop [skip_rest]]] - [-basic_html] - [-ct_hooks CTHModule1 CTHOpts1 and CTHModule2 CTHOpts2 and .. - CTHModuleN CTHOptsN] - [-exit_status ignore_config] - [-help] - </pre> + ct_run -dir TestDir1 TestDir2 .. TestDirN | + [-dir TestDir] -suite Suite1 Suite2 .. SuiteN + [-group Groups1 Groups2 .. GroupsN] [-case Case1 Case2 .. CaseN] + [-step [config | keep_inactive]] + [-config ConfigFile1 ConfigFile2 .. ConfigFileN] + [-userconfig CallbackModule1 ConfigString1 and CallbackModule2 + ConfigString2 and .. CallbackModuleN ConfigStringN] + [-decrypt_key Key] | [-decrypt_file KeyFile] + [-label Label] + [-logdir LogDir] + [-logopts LogOpts] + [-verbosity GenVLevel | [Category1 VLevel1 and + Category2 VLevel2 and .. CategoryN VLevelN]] + [-silent_connections [ConnType1 ConnType2 .. ConnTypeN]] + [-stylesheet CSSFile] + [-cover CoverCfgFile] + [-cover_stop Bool] + [-event_handler EvHandler1 EvHandler2 .. EvHandlerN] | + [-event_handler_init EvHandler1 InitArg1 and + EvHandler2 InitArg2 and .. EvHandlerN InitArgN] + [-include InclDir1 InclDir2 .. InclDirN] + [-no_auto_compile] + [-abort_if_missing_suites] + [-muliply_timetraps Multiplier] + [-scale_timetraps] + [-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc] + [-repeat N] | + [-duration HHMMSS [-force_stop [skip_rest]]] | + [-until [YYMoMoDD]HHMMSS [-force_stop [skip_rest]]] + [-basic_html] + [-no_esc_chars] + [-ct_hooks CTHModule1 CTHOpts1 and CTHModule2 CTHOpts2 and .. + CTHModuleN CTHOptsN] + [-exit_status ignore_config] + [-help]</pre> </section> + <section> - <title>Run tests using test specification</title> + <title>Run Tests using Test Specification</title> <pre> - ct_run -spec TestSpec1 TestSpec2 .. TestSpecN - [-join_specs] - [-config ConfigFile1 ConfigFile2 .. ConfigFileN] - [-userconfig CallbackModule1 ConfigString1 and CallbackModule2 - ConfigString2 and .. and CallbackModuleN ConfigStringN] - [-decrypt_key Key] | [-decrypt_file KeyFile] - [-label Label] - [-logdir LogDir] - [-logopts LogOpts] - [-verbosity GenVLevel | [Category1 VLevel1 and - Category2 VLevel2 and .. CategoryN VLevelN]] - [-allow_user_terms] - [-silent_connections [ConnType1 ConnType2 .. ConnTypeN]] - [-stylesheet CSSFile] - [-cover CoverCfgFile] - [-cover_stop Bool] - [-event_handler EvHandler1 EvHandler2 .. EvHandlerN] | - [-event_handler_init EvHandler1 InitArg1 and - EvHandler2 InitArg2 and .. EvHandlerN InitArgN] - [-include InclDir1 InclDir2 .. InclDirN] - [-no_auto_compile] - [-abort_if_missing_suites] - [-muliply_timetraps Multiplier] - [-scale_timetraps] - [-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc] - [-repeat N] | - [-duration HHMMSS [-force_stop [skip_rest]]] | - [-until [YYMoMoDD]HHMMSS [-force_stop [skip_rest]]] - [-basic_html] - [-ct_hooks CTHModule1 CTHOpts1 and CTHModule2 CTHOpts2 and .. - CTHModuleN CTHOptsN] - [-exit_status ignore_config] - </pre> + ct_run -spec TestSpec1 TestSpec2 .. TestSpecN + [-join_specs] + [-config ConfigFile1 ConfigFile2 .. ConfigFileN] + [-userconfig CallbackModule1 ConfigString1 and CallbackModule2 + ConfigString2 and .. and CallbackModuleN ConfigStringN] + [-decrypt_key Key] | [-decrypt_file KeyFile] + [-label Label] + [-logdir LogDir] + [-logopts LogOpts] + [-verbosity GenVLevel | [Category1 VLevel1 and + Category2 VLevel2 and .. CategoryN VLevelN]] + [-allow_user_terms] + [-silent_connections [ConnType1 ConnType2 .. ConnTypeN]] + [-stylesheet CSSFile] + [-cover CoverCfgFile] + [-cover_stop Bool] + [-event_handler EvHandler1 EvHandler2 .. EvHandlerN] | + [-event_handler_init EvHandler1 InitArg1 and + EvHandler2 InitArg2 and .. EvHandlerN InitArgN] + [-include InclDir1 InclDir2 .. InclDirN] + [-no_auto_compile] + [-abort_if_missing_suites] + [-muliply_timetraps Multiplier] + [-scale_timetraps] + [-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc] + [-repeat N] | + [-duration HHMMSS [-force_stop [skip_rest]]] | + [-until [YYMoMoDD]HHMMSS [-force_stop [skip_rest]]] + [-basic_html] + [-no_esc_chars] + [-ct_hooks CTHModule1 CTHOpts1 and CTHModule2 CTHOpts2 and .. + CTHModuleN CTHOptsN] + [-exit_status ignore_config]</pre> </section> + <section> - <title>Run tests in web based GUI</title> + <title>Run Tests in Web-Based GUI</title> <pre> - ct_run -vts [-browser Browser] - [-dir TestDir1 TestDir2 .. TestDirN] | - [[dir TestDir] -suite Suite [[-group Group] [-case Case]]] - [-config ConfigFile1 ConfigFile2 .. ConfigFileN] - [-userconfig CallbackModule1 ConfigString1 and CallbackModule2 - ConfigString2 and .. and CallbackModuleN ConfigStringN] - [-logopts LogOpts] - [-verbosity GenVLevel | [Category1 VLevel1 and - Category2 VLevel2 and .. CategoryN VLevelN]] - [-decrypt_key Key] | [-decrypt_file KeyFile] - [-include InclDir1 InclDir2 .. InclDirN] - [-no_auto_compile] - [-abort_if_missing_suites] - [-muliply_timetraps Multiplier] - [-scale_timetraps] - [-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc] - [-basic_html]</pre> + ct_run -vts [-browser Browser] + [-dir TestDir1 TestDir2 .. TestDirN] | + [[dir TestDir] -suite Suite [[-group Group] [-case Case]]] + [-config ConfigFile1 ConfigFile2 .. ConfigFileN] + [-userconfig CallbackModule1 ConfigString1 and CallbackModule2 + ConfigString2 and .. and CallbackModuleN ConfigStringN] + [-logopts LogOpts] + [-verbosity GenVLevel | [Category1 VLevel1 and + Category2 VLevel2 and .. CategoryN VLevelN]] + [-decrypt_key Key] | [-decrypt_file KeyFile] + [-include InclDir1 InclDir2 .. InclDirN] + [-no_auto_compile] + [-abort_if_missing_suites] + [-muliply_timetraps Multiplier] + [-scale_timetraps] + [-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc] + [-basic_html] + [-no_esc_chars]</pre> </section> + <section> - <title>Refresh the HTML index files</title> + <title>Refresh HTML Index Files</title> <pre> - ct_run -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> + <title>Run Common Test in Interactive Mode</title> <pre> - ct_run -shell - [-config ConfigFile1 ConfigFile2 ... ConfigFileN] - [-userconfig CallbackModule1 ConfigString1 and CallbackModule2 - ConfigString2 and .. and CallbackModuleN ConfigStringN] - [-decrypt_key Key] | [-decrypt_file KeyFile]</pre> + ct_run -shell + [-config ConfigFile1 ConfigFile2 ... ConfigFileN] + [-userconfig CallbackModule1 ConfigString1 and CallbackModule2 + ConfigString2 and .. and CallbackModuleN ConfigStringN] + [-decrypt_key Key] | [-decrypt_file KeyFile]</pre> </section> + <section> - <title>Start a Common Test Master node</title> + <title>Start a Common Test Master Node</title> <pre> - ct_run -ctmaster</pre> + ct_run -ctmaster</pre> </section> <section> - <title>See also</title> - <p>Please read the <seealso marker="run_test_chapter">Running Test Suites</seealso> - chapter in the Common Test User's Guide for information about the meaning of the - different start flags.</p> + <title>See Also</title> + <p>For information about the start flags, see section + <seealso marker="run_test_chapter">Running Tests and Analyzing + Results</seealso> in the User's Guide.</p> </section> </comref> + diff --git a/lib/common_test/doc/src/ct_slave.xml b/lib/common_test/doc/src/ct_slave.xml new file mode 100644 index 0000000000..44a7b7873f --- /dev/null +++ b/lib/common_test/doc/src/ct_slave.xml @@ -0,0 +1,221 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2010</year><year>2012</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + </legalnotice> + + <title>ct_slave</title> + <prepared></prepared> + <responsible></responsible> + <docno></docno> + <approved></approved> + <checked></checked> + <date></date> + <rev>A</rev> + <file>ct_slave.xml</file> + </header> + <module>ct_slave</module> + <modulesummary>Common Test framework functions for starting and stopping + nodes for Large-Scale Testing.</modulesummary> + + <description> + + <p><c>Common Test</c> framework functions for starting and stopping nodes + for Large-Scale Testing.</p> + + <p>This module exports functions used by the <c>Common Test</c> + Master to start and stop "slave" nodes. It is the default callback + module for the <c>{init, node_start}</c> term in the Test + Specification.</p> + + </description> + + <funcs> + <func> + <name>start(Node) -> Result</name> + <fsummary>Starts an Erlang node with name Node on the local + host.</fsummary> + <type> + <v>Node = atom()</v> + <v>Result = {ok, NodeName} | {error, Reason, NodeName}</v> + <v>Reason = already_started | started_not_connected | boot_timeout | init_timeout | startup_timeout | not_alive</v> + <v>NodeName = atom()</v> + </type> + <desc><marker id="start-1"/> + <p>Starts an Erlang node with name <c>Node</c> on the local host.</p> + + <p>See also + <seealso marker="#start-3"><c>ct_slave:start/3</c></seealso>.</p> + </desc> + </func> + + <func> + <name>start(HostOrNode, NodeOrOpts) -> Result</name> + <fsummary>Starts an Erlang node with default options on a specified + host, or on the local host with specified options.</fsummary> + <type> + <v>HostOrNode = atom()</v> + <v>NodeOrOpts = atom() | list()</v> + <v>Result = {ok, NodeName} | {error, Reason, NodeName}</v> + <v>Reason = already_started | started_not_connected | boot_timeout | init_timeout | startup_timeout | not_alive</v> + <v>NodeName = atom()</v> + </type> + <desc><marker id="start-2"/> + <p>Starts an Erlang node with default options on a specified host, or + on the local host with specified options. That is, the call is + interpreted as <c>start(Host, Node)</c> when the second argument is + atom-valued and <c>start(Node, Opts)</c> when it is list-valued.</p> + + <p>See also + <seealso marker="#start-3"><c>ct_slave:start/3</c></seealso>.</p> + </desc> + </func> + + <func> + <name>start(Host, Node, Opts) -> Result</name> + <fsummary>Starts an Erlang node with name Node on host Host as + specified by the combination of options in Opts.</fsummary> + <type> + <v>Node = atom()</v> + <v>Host = atom()</v> + <v>Opts = [OptTuples]</v> + <v>OptTuples = {username, Username} | {password, Password} | {boot_timeout, BootTimeout} | {init_timeout, InitTimeout} | {startup_timeout, StartupTimeout} | {startup_functions, StartupFunctions} | {monitor_master, Monitor} | {kill_if_fail, KillIfFail} | {erl_flags, ErlangFlags} | {env, [{EnvVar, Value}]}</v> + <v>Username = string()</v> + <v>Password = string()</v> + <v>BootTimeout = integer()</v> + <v>InitTimeout = integer()</v> + <v>StartupTimeout = integer()</v> + <v>StartupFunctions = [StartupFunctionSpec]</v> + <v>StartupFunctionSpec = {Module, Function, Arguments}</v> + <v>Module = atom()</v> + <v>Function = atom()</v> + <v>Arguments = [term]</v> + <v>Monitor = bool()</v> + <v>KillIfFail = bool()</v> + <v>ErlangFlags = string()</v> + <v>EnvVar = string()</v> + <v>Value = string()</v> + <v>Result = {ok, NodeName} | {error, Reason, NodeName}</v> + <v>Reason = already_started | started_not_connected | boot_timeout | init_timeout | startup_timeout | not_alive</v> + <v>NodeName = atom()</v> + </type> + <desc><marker id="start-3"/> + <p>Starts an Erlang node with name <c>Node</c> on host <c>Host</c> as + specified by the combination of options in <c>Opts</c>.</p> + + <p>Options <c>Username</c> and <c>Password</c> are used to log on to the + remote host <c>Host</c>. <c>Username</c>, if omitted, defaults to + the current username. <c>Password</c> is empty by default.</p> + + <p>A list of functions specified in option <c>Startup</c> are + executed after startup of the node. Notice that all used modules + are to be present in the code path on <c>Host</c>.</p> + + <p>The time-outs are applied as follows:</p> + + <taglist> + <tag><c>BootTimeout</c></tag> + <item><p>The time to start the Erlang node, in seconds. Defaults to + 3 seconds. If the node is not pingable within this time, the result + <c>{error, boot_timeout, NodeName}</c> is returned.</p></item> + <tag><c>InitTimeout</c></tag> + <item><p>The time to wait for the node until it calls the internal + callback function informing master about a successful startup. + Defaults to 1 second. In case of a timed out message, the result + <c>{error, init_timeout, NodeName}</c> is returned.</p></item> + <tag><c>StartupTimeout</c></tag> + <item><p>The time to wait until the node stops to run + <c>StartupFunctions</c>. Defaults to 1 second. If this time-out + occurs, the result <c>{error, startup_timeout, NodeName}</c> is + returned.</p></item> + </taglist> + + <p><em>Options:</em></p> + + <taglist> + <tag><c>monitor_master</c></tag> + <item><p>Specifies if the slave node is to be stopped if the + master node stops. Defaults to <c>false</c>.</p></item> + <tag><c>kill_if_fail</c></tag> + <item><p>Specifies if the slave node is to be killed if a time-out + occurs during initialization or startup. Defaults to <c>true</c>. + Notice that the node can also be still alive it the boot time-out + occurred, but it is not killed in this case.</p></item> + <tag><c>erlang_flags</c></tag> + <item><p>Specifies which flags are added to the parameters of the + executable <c>erl</c>.</p></item> + <tag><c>env</c></tag> + <item><p>Specifies a list of environment variables that will extend + the environment.</p></item> + </taglist> + + <p><em>Special return values:</em></p> + + <list type="bulleted"> + <item><p><c>{error, already_started, NodeName}</c> if the node + with the specified name is already started on a specified + host.</p></item> + <item><p><c>{error, started_not_connected, NodeName}</c> if the + node is started, but not connected to the master node.</p></item> + <item><p><c>{error, not_alive, NodeName}</c> if the node on which + <seealso marker="#start-3"><c>ct_slave:start/3</c></seealso> is + called, is not alive. Notice that <c>NodeName</c> is the name of + the current node in this case.</p></item> + </list> + </desc> + </func> + + <func> + <name>stop(Node) -> Result</name> + <fsummary>Stops the running Erlang node with name Node on the local + host.</fsummary> + <type> + <v>Node = atom()</v> + <v>Result = {ok, NodeName} | {error, Reason, NodeName}</v> + <v>Reason = not_started | not_connected | stop_timeout</v> + </type> + <desc><marker id="stop-1"/> + <p>Stops the running Erlang node with name <c>Node</c> on the local + host.</p> + </desc> + </func> + + <func> + <name>stop(Host, Node) -> Result</name> + <fsummary>Stops the running Erlang node with name Node on host + Host.</fsummary> + <type> + <v>Host = atom()</v> + <v>Node = atom()</v> + <v>Result = {ok, NodeName} | {error, Reason, NodeName}</v> + <v>Reason = not_started | not_connected | stop_timeout</v> + <v>NodeName = atom()</v> + </type> + <desc><marker id="stop-2"/> + <p>Stops the running Erlang node with name <c>Node</c> on host + <c>Host</c>.</p> + </desc> + </func> + </funcs> + +</erlref> + + diff --git a/lib/common_test/doc/src/ct_snmp.xml b/lib/common_test/doc/src/ct_snmp.xml new file mode 100644 index 0000000000..d001fb24ec --- /dev/null +++ b/lib/common_test/doc/src/ct_snmp.xml @@ -0,0 +1,523 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2010</year><year>2012</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + </legalnotice> + + <title>ct_snmp</title> + <prepared></prepared> + <responsible></responsible> + <docno></docno> + <approved></approved> + <checked></checked> + <date></date> + <rev>A</rev> + <file>ct_snmp.xml</file> + </header> + <module>ct_snmp</module> + <modulesummary>Common Test user interface module for the SNMP application.</modulesummary> + + <description> + + <p><c>Common Test</c> user interface module for the <c>SNMP</c> + application.</p> + + <p>The purpose of this module is to simplify SNMP configuration for the + test case writer. Many test cases can use default values for common + operations and then no SNMP configuration files need to be supplied. + When it is necessary to change particular configuration parameters, a + subset of the relevant SNMP configuration files can be passed to + <c>ct_snmp</c> by <c>Common Test</c> configuration files. For more + specialized configuration parameters, a simple SNMP configuration file + can be placed in the test suite data directory. To simplify the test + suite, <c>Common Test</c> keeps track of some of the SNMP manager + information. This way the test suite does not have to handle as many + input parameters as if it had to interface wthe OTP SNMP manager + directly.</p> + + <p><em>Configurable SNMP Manager and Agent Parameters:</em></p> + + <p>Manager configuration:</p> + + <taglist> + <tag><c>[{start_manager, boolean()}</c></tag> + <item><p>Optional. Default is <c>true</c>.</p></item> + <tag><c>{users, [{user_name(), [call_back_module(), user_data()]}]}</c></tag> + <item><p>Optional.</p></item> + <tag><c>{usm_users, [{usm_user_name(), [usm_config()]}]}</c></tag> + <item><p>Optional. SNMPv3 only.</p></item> + <tag><c>{managed_agents,[{agent_name(), [user_name(), agent_ip(), agent_port(), [agent_config()]]}]}</c></tag> + <item><p><c>managed_agents</c> is optional.</p></item> + <tag><c>{max_msg_size, integer()}</c></tag> + <item><p>Optional. Default is <c>484</c>.</p></item> + <tag><c>{mgr_port, integer()}</c></tag> + <item><p>Optional. Default is <c>5000</c>.</p></item> + <tag><c>{engine _id, string()}</c></tag> + <item><p>Optional. Default is <c>"mgrEngine"</c>.</p></item> + </taglist> + + <p>Agent configuration:</p> + + <taglist> + <tag><c>{start_agent, boolean()}</c></tag> + <item><p>Optional. Default is <c>false</c>.</p></item> + <tag><c>{agent_sysname, string()}</c></tag> + <item><p>Optional. Default is <c>"ct_test"</c>.</p></item> + <tag><c>{agent_manager_ip, manager_ip()}</c></tag> + <item><p>Optional. Default is <c>localhost</c>.</p></item> + <tag><c>{agent_vsns, list()}</c></tag> + <item><p>Optional. Default is <c>[v2]</c>.</p></item> + <tag><c>{agent_trap_udp, integer()}</c></tag> + <item><p>Optional. Default is <c>5000</c>.</p></item> + <tag><c>{agent_udp, integer()}</c></tag> + <item><p>Optional. Default is <c>4000</c>.</p></item> + <tag><c>{agent_notify_type, atom()}</c></tag> + <item><p>Optional. Default is <c>trap</c>.</p></item> + <tag><c>{agent_sec_type, sec_type()}</c></tag> + <item><p>Optional. Default is <c>none</c>.</p></item> + <tag><c>{agent_passwd, string()}</c></tag> + <item><p>Optional. Default is <c>""</c>.</p></item> + <tag><c>{agent_engine_id, string()}</c></tag> + <item><p>Optional. Default is <c>"agentEngine"</c>.</p></item> + <tag><c>{agent_max_msg_size, string()}</c></tag> + <item><p>Optional. Default is <c>484</c>.</p></item> + </taglist> + + <p>The following parameters represents the SNMP configuration files + <c>context.conf</c>, <c>standard.conf</c>, <c>community.conf</c>, + <c>vacm.conf</c>, <c>usm.conf</c>, <c>notify.conf</c>, + <c>target_addr.conf</c>, and <c>target_params.conf</c>. Notice that + all values in <c>agent.conf</c> can be modified by the parameters + listed above. All these configuration files have default values set by + the <c>SNMP</c> application. These values can be overridden by suppling + a list of valid configuration values or a file located in the test + suites data directory, which can produce a list of valid configuration + values if you apply function <c>file:consult/1</c> to the file.</p> + + <taglist> + <tag><c>{agent_contexts, [term()] | {data_dir_file, rel_path()}}</c></tag> + <item><p>Optional.</p></item> + <tag><c>{agent_community, [term()] | {data_dir_file, rel_path()}}</c></tag> + <item><p>Optional.</p></item> + <tag><c>{agent_sysinfo, [term()] | {data_dir_file, rel_path()}}</c></tag> + <item><p>Optional.</p></item> + <tag><c>{agent_vacm, [term()] | {data_dir_file, rel_path()}}</c></tag> + <item><p>Optional.</p></item> + <tag><c>{agent_usm, [term()] | {data_dir_file, rel_path()}}</c></tag> + <item><p>Optional.</p></item> + <tag><c>{agent_notify_def, [term()] | {data_dir_file, rel_path()}}</c></tag> + <item><p>Optional.</p></item> + <tag><c>{agent_target_address_def, [term()] | {data_dir_file, rel_path()}}</c></tag> + <item><p>Optional.</p></item> + <tag><c>{agent_target_param_def, [term()] | {data_dir_file, rel_path()}}</c></tag> + <item><p>Optional.</p></item> + </taglist> + + <p>Parameter <c>MgrAgentConfName</c> in the functions is to be a name + you allocate in your test suite using a <c>require</c> statement. + Example (where <c>MgrAgentConfName = snmp_mgr_agent</c>):</p> + + <pre> + suite() -> [{require, snmp_mgr_agent, snmp}].</pre> + + <p>or</p> + + <pre> + ct:require(snmp_mgr_agent, snmp).</pre> + + <p>Notice that USM users are needed for SNMPv3 configuration and are + not to be confused with users.</p> + + <p>SNMP traps, inform, and report messages are handled by the user + callback module. For details, see the + <seealso marker="snmp:index"><c>SNMP</c></seealso> application.</p> + + <p>It is recommended to use the <c>.hrl</c> files created by the + Erlang/OTP MIB compiler to define the Object Identifiers (OIDs). + For example, to get the Erlang node name from <c>erlNodeTable</c> + in the OTP-MIB:</p> + + <pre> + Oid = ?erlNodeEntry ++ [?erlNodeName, 1]</pre> + + <p>Furthermore, values can be set for <c>SNMP</c> application configuration + parameters, <c>config</c>, <c>server</c>, <c>net_if</c>, and so on (for + a list of valid parameters and types, see the <seealso marker="snmp:users_guide"><c>User's Guide for the SNMP application</c></seealso>). This is + done by defining a configuration data variable on the following form:</p> + + <pre> + {snmp_app, [{manager, [snmp_app_manager_params()]}, + {agent, [snmp_app_agent_params()]}]}.</pre> + + <p>A name for the data must be allocated in the suite using + <c>require</c> (see the example above). Pass this name as argument + <c>SnmpAppConfName</c> to + <seealso marker="#start-3"><c>ct_snmp:start/3</c></seealso>. + <c>ct_snmp</c> specifies default values for some <c>SNMP</c> application + configuration parameters (such as <c>{verbosity,trace}</c> for parameter + <c>config</c>). This set of defaults is merged with the parameters + specified by the user. The user values override <c>ct_snmp</c> + defaults.</p> + + </description> + + <section> + <title>Data Types</title> + <marker id="types"/> + <taglist> + <tag><c>agent_config() = {Item, Value}</c></tag> + <item><marker id="type-agent_config"/> </item> + <tag><c>agent_ip() = ip()</c></tag> + <item><marker id="type-agent_ip"/> </item> + <tag><c>agent_name() = atom()</c></tag> + <item><marker id="type-agent_name"/> </item> + <tag><c>agent_port() = integer()</c></tag> + <item><marker id="type-agent_port"/> </item> + <tag><c>call_back_module() = atom()</c></tag> + <item><marker id="type-call_back_module"/> </item> + <tag><c>error_index() = integer()</c></tag> + <item><marker id="type-error_index"/> </item> + <tag><c>error_status() = noError | atom()</c></tag> + <item><marker id="type-error_status"/> </item> + <tag><c>ip() = string() | {integer(), integer(), integer(), integer()}</c></tag> + <item><marker id="type-ip"/> </item> + <tag><c>manager_ip() = ip()</c></tag> + <item><marker id="type-manager_ip"/> </item> + <tag><c>oid() = [byte()]</c></tag> + <item><marker id="type-oid"/> </item> + <tag><c>oids() = [oid()]</c></tag> + <item><marker id="type-oids"/> </item> + <tag><c>rel_path() = string()</c></tag> + <item><marker id="type-rel_path"/> </item> + <tag><c>sec_type() = none | minimum | semi</c></tag> + <item><marker id="type-sec_type"/> </item> + <tag><c>snmp_app_agent_params() = term()</c></tag> + <item><marker id="type-snmp_app_agent_params"/> </item> + <tag><c>snmp_app_manager_params() = term()</c></tag> + <item><marker id="type-snmp_app_manager_params"/> </item> + <tag><c>snmpreply() = {error_status(), error_index(), varbinds()}</c></tag> + <item><marker id="type-snmpreply"/> </item> + <tag><c>user_data() = term()</c></tag> + <item><marker id="type-user_data"/> </item> + <tag><c>user_name() = atom()</c></tag> + <item><marker id="type-user_name"/> </item> + <tag><c>usm_config() = {Item, Value}</c></tag> + <item><marker id="type-usm_config"/> </item> + <tag><c>usm_user_name() = string()</c></tag> + <item><marker id="type-usm_user_name"/> </item> + <tag><c>value_type() = o('OBJECT IDENTIFIER') | i('INTEGER') | u('Unsigned32') | g('Unsigned32') | s('OCTET STRING')</c></tag> + <item><marker id="type-value_type"/> </item> + <tag><c>var_and_val() = {oid(), value_type(), value()}</c></tag> + <item><marker id="type-var_and_val"/> </item> + <tag><c>varbind() = term()</c></tag> + <item><marker id="type-varbind"/> </item> + <tag><c>varbinds() = [varbind()]</c></tag> + <item><marker id="type-varbinds"/> </item> + <tag><c>varsandvals() = [var_and_val()]</c></tag> + <item><marker id="type-varsandvals"/> </item> + </taglist> + <p>These data types are described in the documentation for + the <seealso marker="snmp:index"><c>SNMP</c></seealso> application.</p> + </section> + + <funcs> + <func> + <name>get_next_values(Agent, Oids, MgrAgentConfName) -> SnmpReply</name> + <fsummary>Issues a synchronous SNMP get next request.</fsummary> + <type> + <v>Agent = agent_name()</v> + <v>Oids = oids()</v> + <v>MgrAgentConfName = atom()</v> + <v>SnmpReply = snmpreply()</v> + </type> + <desc><marker id="get_next_values-3"/> + <p>Issues a synchronous SNMP <c>get next</c> request.</p> + </desc> + </func> + + <func> + <name>get_values(Agent, Oids, MgrAgentConfName) -> SnmpReply</name> + <fsummary>Issues a synchronous SNMP get request.</fsummary> + <type> + <v>Agent = agent_name()</v> + <v>Oids = oids()</v> + <v>MgrAgentConfName = atom()</v> + <v>SnmpReply = snmpreply()</v> + </type> + <desc><marker id="get_values-3"/> + <p>Issues a synchronous SNMP <c>get</c> request.</p> + </desc> + </func> + + <func> + <name>load_mibs(Mibs) -> ok | {error, Reason}</name> + <fsummary>Loads the MIBs into agent snmp_master_agent.</fsummary> + <type> + <v>Mibs = [MibName]</v> + <v>MibName = string()</v> + <v>Reason = term()</v> + </type> + <desc><marker id="load_mibs-1"/> + <p>Loads the MIBs into agent <c>snmp_master_agent</c>.</p> + </desc> + </func> + + <func> + <name>register_agents(MgrAgentConfName, ManagedAgents) -> ok | {error, Reason}</name> + <fsummary>Explicitly instructs the manager to handle this + agent.</fsummary> + <type> + <v>MgrAgentConfName = atom()</v> + <v>ManagedAgents = [agent()]</v> + <v>Reason = term()</v> + </type> + <desc><marker id="register_agents-2"/> + <p>Explicitly instructs the manager to handle this agent. Corresponds + to making an entry in <c>agents.conf</c>.</p> + + <p>This function tries to register the specified managed agents, without + checking if any of them exist. To change a registered managed agent, + the agent must first be unregistered.</p> + </desc> + </func> + + <func> + <name>register_users(MgrAgentConfName, Users) -> ok | {error, Reason}</name> + <fsummary>Registers the manager entity (=user) responsible for specific + agent(s).</fsummary> + <type> + <v>MgrAgentConfName = atom()</v> + <v>Users = [user()]</v> + <v>Reason = term()</v> + </type> + <desc><marker id="register_users-2"/> + <p>Registers the manager entity (=user) responsible for specific + agent(s). Corresponds to making an entry in <c>users.conf</c>.</p> + + <p>This function tries to register the specified users, without checking + if any of them exist. To change a registered user, the user must + first be unregistered.</p> + </desc> + </func> + + <func> + <name>register_usm_users(MgrAgentConfName, UsmUsers) -> ok | {error, Reason}</name> + <fsummary>Explicitly instructs the manager to handle this USM user.</fsummary> + <type> + <v>MgrAgentConfName = atom()</v> + <v>UsmUsers = [usm_user()]</v> + <v>Reason = term()</v> + </type> + <desc><marker id="register_usm_users-2"/> + <p>Explicitly instructs the manager to handle this USM user. + Corresponds to making an entry in <c>usm.conf</c>.</p> + + <p>This function tries to register the specified users, without checking + if any of them exist. To change a registered user, the user must + first be unregistered.</p> + </desc> + </func> + + <func> + <name>set_info(Config) -> [{Agent, OldVarsAndVals, NewVarsAndVals}]</name> + <fsummary>Returns a list of all successful set requests performed in the + test case in reverse order.</fsummary> + <type> + <v>Config = [{Key, Value}]</v> + <v>Agent = agent_name()</v> + <v>OldVarsAndVals = varsandvals()</v> + <v>NewVarsAndVals = varsandvals()</v> + </type> + <desc><marker id="set_info-1"/> + <p>Returns a list of all successful <c>set</c> requests performed in + the test case in reverse order. The list contains the involved user + and agent, the value before <c>set</c>, and the new value. This is + intended to simplify the cleanup in function <c>end_per_testcase</c>, + that is, the undoing of the <c>set</c> requests and their possible + side-effects.</p> + </desc> + </func> + + <func> + <name>set_values(Agent, VarsAndVals, MgrAgentConfName, Config) -> SnmpReply</name> + <fsummary>Issues a synchronous SNMP set request.</fsummary> + <type> + <v>Agent = agent_name()</v> + <v>Oids = oids()</v> + <v>MgrAgentConfName = atom()</v> + <v>Config = [{Key, Value}]</v> + <v>SnmpReply = snmpreply()</v> + </type> + <desc><marker id="set_values-4"/> + <p>Issues a synchronous SNMP <c>set</c> request.</p> + </desc> + </func> + + <func> + <name>start(Config, MgrAgentConfName) -> ok</name> + <fsummary>Equivalent to start(Config, MgrAgentConfName, + undefined).</fsummary> + <desc><marker id="start-2"/> + <p>Equivalent to + <seealso marker="#start-3"><c>ct_snmp:start(Config, MgrAgentConfName, + undefined)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>start(Config, MgrAgentConfName, SnmpAppConfName) -> ok</name> + <fsummary>Starts an SNMP manager and/or agent.</fsummary> + <type> + <v>Config = [{Key, Value}]</v> + <v>Key = atom()</v> + <v>Value = term()</v> + <v>MgrAgentConfName = atom()</v> + <v>SnmpConfName = atom()</v> + </type> + <desc><marker id="start-3"/> + <p>Starts an SNMP manager and/or agent. In the manager case, + registrations of users and agents, as specified by the configuration + <c>MgrAgentConfName</c>, are performed. When using SNMPv3, called + USM users are also registered. Users, <c>usm_users</c>, and + managed agents can also be registered later using + <seealso marker="#register_users-2"><c>ct_snmp:register_users/2</c></seealso>, + <seealso marker="#register_agents-2"><c>ct_snmp:register_agents/2</c></seealso>, + and + <seealso marker="#register_usm_users-2"><c>ct_snmp:register_usm_users/2</c></seealso>.</p> + + <p>The agent started is called <c>snmp_master_agent</c>. Use + <seealso marker="#load_mibs-1"><c>ct_snmp:load_mibs/1</c></seealso> + to load MIBs into the agent.</p> + + <p>With <c>SnmpAppConfName</c> SNMP applications can be configured + with parameters <c>config</c>, <c>mibs</c>, <c>net_if</c>, and so on. + The values are merged with (and possibly override) default values + set by <c>ct_snmp</c>.</p> + </desc> + </func> + + <func> + <name>stop(Config) -> ok</name> + <fsummary>Stops the SNMP manager and/or agent, and removes all files + created.</fsummary> + <type> + <v>Config = [{Key, Value}]</v> + <v>Key = atom()</v> + <v>Value = term()</v> + </type> + <desc><marker id="stop-1"/> + <p>Stops the SNMP manager and/or agent, and removes all files + created.</p> + </desc> + </func> + + <func> + <name>unload_mibs(Mibs) -> ok | {error, Reason}</name> + <fsummary>Unloads the MIBs from agent snmp_master_agent.</fsummary> + <type> + <v>Mibs = [MibName]</v> + <v>MibName = string()</v> + <v>Reason = term()</v> + </type> + <desc><marker id="unload_mibs-1"/> + <p>Unloads the MIBs from agent <c>snmp_master_agent</c>.</p> + </desc> + </func> + + <func> + <name>unregister_agents(MgrAgentConfName) -> ok</name> + <fsummary>Unregisters all managed agents.</fsummary> + <type> + <v>MgrAgentConfName = atom()</v> + <v>Reason = term()</v> + </type> + <desc><marker id="unregister_agents-1"/> + <p>Unregisters all managed agents.</p> + </desc> + </func> + + <func> + <name>unregister_agents(MgrAgentConfName, ManagedAgents) -> ok</name> + <fsummary>Unregisters the specified managed agents.</fsummary> + <type> + <v>MgrAgentConfName = atom()</v> + <v>ManagedAgents = [agent_name()]</v> + <v>Reason = term()</v> + </type> + <desc><marker id="unregister_agents-2"/> + <p>Unregisters the specified managed agents.</p> + </desc> + </func> + + <func> + <name>unregister_users(MgrAgentConfName) -> ok</name> + <fsummary>Unregisters all users.</fsummary> + <type> + <v>MgrAgentConfName = atom()</v> + <v>Reason = term()</v> + </type> + <desc><marker id="unregister_users-1"/> + <p>Unregisters all users.</p> + </desc> + </func> + + <func> + <name>unregister_users(MgrAgentConfName, Users) -> ok</name> + <fsummary>Unregisters the specified users.</fsummary> + <type> + <v>MgrAgentConfName = atom()</v> + <v>Users = [user_name()]</v> + <v>Reason = term()</v> + </type> + <desc><marker id="unregister_users-2"/> + <p>Unregisters the specified users.</p> + </desc> + </func> + + <func> + <name>unregister_usm_users(MgrAgentConfName) -> ok</name> + <fsummary>Unregisters all USM users.</fsummary> + <type> + <v>MgrAgentConfName = atom()</v> + <v>Reason = term()</v> + </type> + <desc><marker id="unregister_usm_users-1"/> + <p>Unregisters all USM users.</p> + </desc> + </func> + + <func> + <name>unregister_usm_users(MgrAgentConfName, UsmUsers) -> ok</name> + <fsummary>Unregisters the specified USM users.</fsummary> + <type> + <v>MgrAgentConfName = atom()</v> + <v>UsmUsers = [usm_user_name()]</v> + <v>Reason = term()</v> + </type> + <desc><marker id="unregister_usm_users-2"/> + <p>Unregisters the specified USM users.</p> + </desc> + </func> + </funcs> + +</erlref> + + diff --git a/lib/common_test/doc/src/ct_ssh.xml b/lib/common_test/doc/src/ct_ssh.xml new file mode 100644 index 0000000000..92b1f60b8c --- /dev/null +++ b/lib/common_test/doc/src/ct_ssh.xml @@ -0,0 +1,1150 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2010</year><year>2012</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + </legalnotice> + + <title>ct_ssh</title> + <prepared></prepared> + <responsible></responsible> + <docno></docno> + <approved></approved> + <checked></checked> + <date></date> + <rev>A</rev> + <file>ct_ssh.xml</file> + </header> + <module>ct_ssh</module> + <modulesummary>SSH/SFTP client module.</modulesummary> + +<description> + + <p>SSH/SFTP client module.</p> + + <p>This module uses application <c>SSH</c>, which provides detailed + information about, for example, functions, types, and options.</p> + + <p>Argument <c>Server</c> in the SFTP functions is only to be used for + SFTP sessions that have been started on existing SSH connections + (that is, when the original connection type is <c>ssh</c>). Whenever + the connection type is <c>sftp</c>, use the SSH connection reference + only.</p> + + <p>The following options are valid for specifying an SSH/SFTP + connection (that is, can be used as configuration elements):</p> + + <pre> + [{ConnType, Addr}, + {port, Port}, + {user, UserName} + {password, Pwd} + {user_dir, String} + {public_key_alg, PubKeyAlg} + {connect_timeout, Timeout} + {key_cb, KeyCallbackMod}]</pre> + + <p><c>ConnType = ssh | sftp</c>.</p> + + <p>For other types, see + <seealso marker="ssh:ssh"><c>ssh:ssh(3)</c></seealso>.</p> + + <p>All time-out parameters in <c>ct_ssh</c> functions are values in + milliseconds.</p> + + </description> + + <section> + <title>Data Types</title> + <marker id="types"/> + <taglist> + <tag><c>connection() = handle() | target_name()</c></tag> + <item><marker id="type-connection"/> + <p>For <c>target_name</c>, see module + <seealso marker="ct"><c>ct</c></seealso>.</p></item> + + <tag><c>handle() = handle()</c></tag> + <item><marker id="type-handle"/> + <p>Handle for a specific SSH/SFTP connection, see module + <seealso marker="ct"><c>ct</c></seealso>.</p></item> + + <tag><c>ssh_sftp_return() = term()</c></tag> + <item><marker id="type-ssh_sftp_return"/> + <p>Return value from an + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp</c></seealso> + function.</p></item> + </taglist> + </section> + + <funcs> + <func> + <name>apread(SSH, Handle, Position, Length) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="apread-4"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>apread(SSH, Server, Handle, Position, Length) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="apread-5"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>apwrite(SSH, Handle, Position, Data) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="apwrite-4"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>apwrite(SSH, Server, Handle, Position, Data) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="apwrite-5"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>aread(SSH, Handle, Len) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="aread-3"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>aread(SSH, Server, Handle, Len) -> Result</name> + <fsummary>For inforamtion and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="aread-4"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>awrite(SSH, Handle, Data) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="awrite-3"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>awrite(SSH, Server, Handle, Data) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="awrite-4"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>close(SSH, Handle) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="close-2"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>close(SSH, Server, Handle) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="close-3"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>connect(KeyOrName) -> {ok, Handle} | {error, Reason}</name> + <fsummary>Equivalent to connect(KeyOrName, host, []).</fsummary> + <desc><marker id="connect-1"/> + <p>Equivalent to + <seealso marker="#connect-3"><c>ct_ssh:connect(KeyOrName, host, + [])</c></seealso>.</p> + </desc> + </func> + + <func> + <name>connect(KeyOrName, ConnType) -> {ok, Handle} | {error, Reason}</name> + <fsummary>Equivalent to connect(KeyOrName, ConnType, []).</fsummary> + <desc><marker id="connect-2"/> + <p>Equivalent to + <seealso marker="#connect-3"><c>ct_ssh:connect(KeyOrName, ConnType, + [])</c></seealso>.</p> + </desc> + </func> + + <func> + <name>connect(KeyOrName, ConnType, ExtraOpts) -> {ok, Handle} | {error, Reason}</name> + <fsummary>Opens an SSH or SFTP connection using the information + associated with KeyOrName.</fsummary> + <type> + <v>KeyOrName = Key | Name</v> + <v>Key = atom()</v> + <v>Name = target_name()</v> + <v>ConnType = ssh | sftp | host</v> + <v>ExtraOpts = ssh_connect_options()</v> + <v>Handle = handle()</v> + <v>Reason = term()</v> + </type> + <desc><marker id="connect-3"/> + <p>Opens an SSH or SFTP connection using the information associated + with <c>KeyOrName</c>.</p> + + <p>If <c>Name</c> (an alias name for <c>Key</c>) is used to identify + the connection, this name can be used as connection reference for + subsequent calls. Only one open connection at a time associated + with <c>Name</c> is possible. If <c>Key</c> is used, the returned + handle must be used for subsequent calls (multiple connections can + be opened using the configuration data specified by <c>Key</c>).</p> + + <p>For information on how to create a new <c>Name</c>, see + <seealso marker="ct#require-2"><c>ct:require/2</c></seealso>.</p> + + <p>For <c>target_name</c>, see module + <seealso marker="ct"><c>ct</c></seealso>.</p> + + <p><c>ConnType</c> always overrides the type specified in the + address tuple in the configuration data (and in <c>ExtraOpts</c>). + So it is possible to, for example, open an SFTP connection + directly using data originally specifying an SSH connection. Value + <c>host</c> means that the connection type specified by the host + option (either in the configuration data or in <c>ExtraOpts</c>) + is used.</p> + + <p><c>ExtraOpts</c> (optional) are extra SSH options to be added to + the configuration data for <c>KeyOrName</c>. The extra options + override any existing options with the same key in the + configuration data. For details on valid SSH options, see + application <seealso marker="ssh:index"><c>SSH</c></seealso>.</p> + </desc> + </func> + + <func> + <name>del_dir(SSH, Name) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="del_dir-2"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>del_dir(SSH, Server, Name) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="del_dir-3"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>delete(SSH, Name) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="delete-2"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>delete(SSH, Server, Name) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="delete-3"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>disconnect(SSH) -> ok | {error, Reason}</name> + <fsummary>Closes an SSH/SFTP connection.</fsummary> + <type> + <v>SSH = connection()</v> + <v>Reason = term()</v> + </type> + <desc><marker id="disconnect-1"/> + <p>Closes an SSH/SFTP connection.</p> + </desc> + </func> + + <func> + <name>exec(SSH, Command) -> {ok, Data} | {error, Reason}</name> + <fsummary>Equivalent to exec(SSH, Command, DefaultTimeout).</fsummary> + <desc><marker id="exec-2"/> + <p>Equivalent to + <seealso marker="#exec-3"><c>ct_ssh:exec(SSH, Command, + DefaultTimeout)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>exec(SSH, Command, Timeout) -> {ok, Data} | {error, Reason}</name> + <fsummary>Requests server to perform Command.</fsummary> + <type> + <v>SSH = connection()</v> + <v>Command = string()</v> + <v>Timeout = integer()</v> + <v>Data = list()</v> + <v>Reason = term()</v> + </type> + <desc><marker id="exec-3"/> + <p>Requests server to perform <c>Command</c>. A session channel is + opened automatically for the request. <c>Data</c> is received from + the server as a result of the command.</p> + </desc> + </func> + + <func> + <name>exec(SSH, ChannelId, Command, Timeout) -> {ok, Data} | {error, Reason}</name> + <fsummary>Requests server to perform Command.</fsummary> + <type> + <v>SSH = connection()</v> + <v>ChannelId = integer()</v> + <v>Command = string()</v> + <v>Timeout = integer()</v> + <v>Data = list()</v> + <v>Reason = term()</v> + </type> + <desc><marker id="exec-4"/> + <p>Requests server to perform <c>Command</c>. A previously opened + session channel is used for the request. <c>Data</c> is received + from the server as a result of the command.</p> + </desc> + </func> + + <func> + <name>get_file_info(SSH, Handle) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="get_file_info-2"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>get_file_info(SSH, Server, Handle) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="get_file_info-3"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>list_dir(SSH, Path) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="list_dir-2"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>list_dir(SSH, Server, Path) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="list_dir-3"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>make_dir(SSH, Name) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="make_dir-2"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>make_dir(SSH, Server, Name) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="make_dir-3"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>make_symlink(SSH, Name, Target) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="make_symlink-3"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>make_symlink(SSH, Server, Name, Target) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="make_symlink-4"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>open(SSH, File, Mode) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="open-3"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>open(SSH, Server, File, Mode) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="open-4"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>opendir(SSH, Path) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="opendir-2"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>opendir(SSH, Server, Path) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="opendir-3"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>position(SSH, Handle, Location) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="position-3"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>position(SSH, Server, Handle, Location) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="position-4"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>pread(SSH, Handle, Position, Length) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="pread-4"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>pread(SSH, Server, Handle, Position, Length) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="pread-5"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>pwrite(SSH, Handle, Position, Data) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="pwrite-4"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>pwrite(SSH, Server, Handle, Position, Data) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="pwrite-5"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>read(SSH, Handle, Len) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="read-3"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>read(SSH, Server, Handle, Len) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="read-4"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>read_file(SSH, File) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="read_file-2"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>read_file(SSH, Server, File) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="read_file-3"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>read_file_info(SSH, Name) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="read_file_info-2"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>read_file_info(SSH, Server, Name) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="read_file_info-3"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>read_link(SSH, Name) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="read_link-2"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>read_link(SSH, Server, Name) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="read_link-3"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>read_link_info(SSH, Name) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="read_link_info-2"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>read_link_info(SSH, Server, Name) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="read_link_info-3"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>receive_response(SSH, ChannelId) -> {ok, Data} | {error, Reason}</name> + <fsummary>Equivalent to receive_response(SSH, ChannelId, + close).</fsummary> + <desc><marker id="receive_response-2"/> + <p>Equivalent to + <seealso marker="#receive_response-3"><c>ct_ssh:receive_response(SSH, +ChannelId, close)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>receive_response(SSH, ChannelId, End) -> {ok, Data} | {error, Reason}</name> + <fsummary>Equivalent to receive_response(SSH, ChannelId, End, + DefaultTimeout).</fsummary> + <desc><marker id="receive_response-3"/> + <p>Equivalent to + <seealso marker="#receive_response-4"><c>ct_ssh:receive_response(SSH, +ChannelId, End, DefaultTimeout)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>receive_response(SSH, ChannelId, End, Timeout) -> {ok, Data} | {timeout, Data} | {error, Reason}</name> + <fsummary>Receives expected data from server on the specified session + channel.</fsummary> + <type> + <v>SSH = connection()</v> + <v>ChannelId = integer()</v> + <v>End = Fun | close | timeout</v> + <v>Timeout = integer()</v> + <v>Data = list()</v> + <v>Reason = term()</v> + </type> + <desc><marker id="receive_response-4"/> + <p>Receives expected data from server on the specified session + channel.</p> + + <p>If <c>End == close</c>, data is returned to the caller when the + channel is closed by the server. If a time-out occurs before this + happens, the function returns <c>{timeout,Data}</c> (where + <c>Data</c> is the data received so far).</p> + <p>If <c>End == timeout</c>, a time-out is expected and + <c>{ok,Data}</c> is returned both in the case of a time-out and + when the channel is closed.</p> + + <p>If <c>End</c> is a fun, this fun is called with one argument, the + data value in a received <c>ssh_cm</c> message (see + <seealso marker="ssh:ssh_connection"><c>ssh:ssh_connection(3)</c></seealso>. + The fun is to return either <c>true</c> to end the receiving + operation (and have the so far collected data returned) or + <c>false</c> to wait for more data from the server. Even if a fun + is supplied, the function returns immediately if the server closes + the channel).</p> + </desc> + </func> + + <func> + <name>rename(SSH, OldName, NewName) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="rename-3"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>rename(SSH, Server, OldName, NewName) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="rename-4"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>send(SSH, ChannelId, Data) -> ok | {error, Reason}</name> + <fsummary>Equivalent to send(SSH, ChannelId, 0, Data, + DefaultTimeout).</fsummary> + <desc><marker id="send-3"/> + <p>Equivalent to <seealso marker="#send-5"><c>ct_ssh:send(SSH, + ChannelId, 0, Data, DefaultTimeout)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>send(SSH, ChannelId, Data, Timeout) -> ok | {error, Reason}</name> + <fsummary>Equivalent to send(SSH, ChannelId, 0, Data, Timeout).</fsummary> + <desc><marker id="send-4"/> + <p>Equivalent to <seealso marker="#send-5"><c>ct_ssh:send(SSH, + ChannelId, 0, Data, Timeout)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>send(SSH, ChannelId, Type, Data, Timeout) -> ok | {error, Reason}</name> + <fsummary>Sends data to server on specified session channel.</fsummary> + <type> + <v>SSH = connection()</v> + <v>ChannelId = integer()</v> + <v>Type = integer()</v> + <v>Data = list()</v> + <v>Timeout = integer()</v> + <v>Reason = term()</v> + </type> + <desc><marker id="send-5"/> + <p>Sends data to server on specified session channel.</p> + </desc> + </func> + + <func> + <name>send_and_receive(SSH, ChannelId, Data) -> {ok, Data} | {error, Reason}</name> + <fsummary>Equivalent to send_and_receive(SSH, ChannelId, Data, + close).</fsummary> + <desc><marker id="send_and_receive-3"/> + <p>Equivalent to + <seealso marker="#send_and_receive-4"><c>ct_ssh:send_and_receive(SSH, + ChannelId, Data, close)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>send_and_receive(SSH, ChannelId, Data, End) -> {ok, Data} | {error, Reason}</name> + <fsummary>Equivalent to send_and_receive(SSH, ChannelId, 0, Data, End, + DefaultTimeout).</fsummary> + <desc><marker id="send_and_receive-4"/> + <p>Equivalent to + <seealso marker="#send_and_receive-6"><c>ct_ssh;send_and_receive(SSH, +ChannelId, 0, Data, End, DefaultTimeout)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>send_and_receive(SSH, ChannelId, Data, End, Timeout) -> {ok, Data} | {error, Reason}</name> + <fsummary>Equivalent to send_and_receive(SSH, ChannelId, 0, Data, End, + Timeout).</fsummary> + <desc><marker id="send_and_receive-5"/> + <p>Equivalent to + <seealso marker="#send_and_receive-6"><c>ct_ssh:send_and_receive(SSH, +ChannelId, 0, Data, End, Timeout)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>send_and_receive(SSH, ChannelId, Type, Data, End, Timeout) -> {ok, Data} | {error, Reason}</name> + <fsummary>Sends data to server on specified session channel and waits + to receive the server response.</fsummary> + <type> + <v>SSH = connection()</v> + <v>ChannelId = integer()</v> + <v>Type = integer()</v> + <v>Data = list()</v> + <v>End = Fun | close | timeout</v> + <v>Timeout = integer()</v> + <v>Reason = term()</v> + </type> + <desc><marker id="send_and_receive-6"/> + <p>Sends data to server on specified session channel and waits to + receive the server response.</p> + + <p>For details on argument <c>End</c>, see + <seealso marker="#receive_response-4"><c>ct_ssh:receive_response/4</c></seealso>.</p> + </desc> + </func> + + <func> + <name>session_close(SSH, ChannelId) -> ok | {error, Reason}</name> + <fsummary>Closes an SSH session channel.</fsummary> + <type> + <v>SSH = connection()</v> + <v>ChannelId = integer()</v> + <v>Reason = term()</v> + </type> + <desc><marker id="session_close-2"/> + <p>Closes an SSH session channel.</p> + </desc> + </func> + + <func> + <name>session_open(SSH) -> {ok, ChannelId} | {error, Reason}</name> + <fsummary>Equivalent to session_open(SSH, DefaultTimeout).</fsummary> + <desc><marker id="session_open-1"/> + <p>Equivalent to + <seealso marker="#session_open-2"><c>ct_ssh:session_open(SSH, + DefaultTimeout)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>session_open(SSH, Timeout) -> {ok, ChannelId} | {error, Reason}</name> + <fsummary>Opens a channel for an SSH session.</fsummary> + <type> + <v>SSH = connection()</v> + <v>Timeout = integer()</v> + <v>ChannelId = integer()</v> + <v>Reason = term()</v> + </type> + <desc><marker id="session_open-2"/> + <p>Opens a channel for an SSH session.</p> + </desc> + </func> + + <func> + <name>sftp_connect(SSH) -> {ok, Server} | {error, Reason}</name> + <fsummary>Starts an SFTP session on an already existing SSH + connection.</fsummary> + <type> + <v>SSH = connection()</v> + <v>Server = pid()</v> + <v>Reason = term()</v> + </type> + <desc><marker id="sftp_connect-1"/> + <p>Starts an SFTP session on an already existing SSH connection. + <c>Server</c> identifies the new session and must be specified + whenever SFTP requests are to be sent.</p> + </desc> + </func> + + <func> + <name>subsystem(SSH, ChannelId, Subsystem) -> Status | {error, Reason}</name> + <fsummary>Equivalent to subsystem(SSH, ChannelId, Subsystem, + DefaultTimeout).</fsummary> + <desc><marker id="subsystem-3"/> + <p>Equivalent to + <seealso marker="#subsystem-4"><c>ct_ssh:subsystem(SSH, ChannelId, + Subsystem, DefaultTimeout)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>subsystem(SSH, ChannelId, Subsystem, Timeout) -> Status | {error, Reason}</name> + <fsummary>Sends a request to execute a predefined subsystem.</fsummary> + <type> + <v>SSH = connection()</v> + <v>ChannelId = integer()</v> + <v>Subsystem = string()</v> + <v>Timeout = integer()</v> + <v>Status = success | failure</v> + <v>Reason = term()</v> + </type> + <desc><marker id="subsystem-4"/> + <p>Sends a request to execute a predefined subsystem.</p> + </desc> + </func> + + <func> + <name>write(SSH, Handle, Data) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="write-3"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>write(SSH, Server, Handle, Data) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="write-4"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>write_file(SSH, File, Iolist) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="write_file-3"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>write_file(SSH, Server, File, Iolist) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="write_file-4"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>write_file_info(SSH, Name, Info) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="write_file_info-3"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>write_file_info(SSH, Server, Name, Info) -> Result</name> + <fsummary>For information and other types, see ssh_sftp(3).</fsummary> + <type> + <v>SSH = connection()</v> + <v>Result = ssh_sftp_return() | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="write_file_info-4"/> + <p>For information and other types, see + <seealso marker="ssh:ssh_sftp"><c>ssh:ssh_sftp(3)</c></seealso>.</p> + </desc> + </func> + </funcs> + +</erlref> + + diff --git a/lib/common_test/doc/src/ct_telnet.xml b/lib/common_test/doc/src/ct_telnet.xml new file mode 100644 index 0000000000..1de278d30c --- /dev/null +++ b/lib/common_test/doc/src/ct_telnet.xml @@ -0,0 +1,604 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2010</year><year>2012</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + </legalnotice> + + <title>ct_telnet</title> + <prepared></prepared> + <responsible></responsible> + <docno></docno> + <approved></approved> + <checked></checked> + <date></date> + <rev>A</rev> + <file>ct_telnet.xml</file> + </header> + <module>ct_telnet</module> + <modulesummary>Common Test specific layer on top of Telnet client ct_telnet_client.erl</modulesummary> + + <description> + + <p><c>Common Test</c> specific layer on top of Telnet client + <c>ct_telnet_client.erl</c>.</p> + + <p>Use this module to set up Telnet connections, send commands, and + perform string matching on the result. For information about how to use + <c>ct_telnet</c> and configure connections, specifically for UNIX hosts, + see the + <seealso marker="unix_telnet"><c>unix_telnet</c></seealso> manual page. + </p> + + <p>Default values defined in <c>ct_telnet</c>:</p> + <marker id="Default_values"/> + + <list type="bulleted"> + <item><p>Connection timeout (time to wait for connection) = 10 + seconds</p></item> + <item><p>Command timeout (time to wait for a command to return) = + 10 seconds</p></item> + <item><p>Max number of reconnection attempts = 3</p></item> + <item><p>Reconnection interval (time to wait in between + reconnection attempts) = 5 seconds</p></item> + <item><p>Keep alive (sends NOP to the server every 8 sec if + connection is idle) = <c>true</c></p></item> + <item><p>Polling limit (max number of times to poll to get a + remaining string terminated) = 0</p></item> + <item><p>Polling interval (sleep time between polls) = 1 second</p> + </item> + <item><p>The TCP_NODELAY option for the telnet socket + is disabled (set to <c>false</c>) per default</p></item> + </list> + + <p>These parameters can be modified by the user with the following + configuration term:</p> + + <pre> + {telnet_settings, [{connect_timeout,Millisec}, + {command_timeout,Millisec}, + {reconnection_attempts,N}, + {reconnection_interval,Millisec}, + {keep_alive,Bool}, + {poll_limit,N}, + {poll_interval,Millisec}, + {tcp_nodelay,Bool}]}.</pre> + + <p><c>Millisec = integer(), N = integer()</c></p> + + <p>Enter the <c>telnet_settings</c> term in a configuration file included + in the test and <c>ct_telnet</c> retrieves the information + automatically.</p> + + <p><c>keep_alive</c> can be specified per connection, if necessary. For + details, see + <seealso marker="unix_telnet"><c>unix_telnet</c></seealso>.</p> + + </description> + + <section> + <title>Logging</title> + <marker id="Logging"/> + + <p>The default logging behavior of <c>ct_telnet</c> is to print information + about performed operations, commands, and their corresponding results to + the test case HTML log. The following is not printed to the HTML + log: text strings sent from the Telnet server that are not explicitly + received by a <c>ct_telnet</c> function, such as <c>expect/3</c>. + However, <c>ct_telnet</c> can be configured to use a special purpose + event handler, implemented in <c>ct_conn_log_h</c>, for logging + <em>all</em> Telnet traffic. To use this handler, install a <c>Common + Test</c> hook named <c>cth_conn_log</c>. Example (using the test suite + information function):</p> + + <pre> + suite() -> + [{ct_hooks, [{cth_conn_log, [{conn_mod(),hook_options()}]}]}].</pre> + + <p><c>conn_mod()</c> is the name of the <c>Common Test</c> module + implementing the connection protocol, that is, <c>ct_telnet</c>.</p> + + <p>The <c>cth_conn_log</c> hook performs unformatted logging of Telnet + data to a separate text file. All Telnet communication is captured and + printed, including any data sent from the server. The link to + this text file is located at the top of the test case HTML log.</p> + + <p>By default, data for all Telnet connections is logged in one common + file (named <c>default</c>), which can get messy, for example, if + multiple Telnet sessions are running in parallel. Therefore a separate + log file can be created for each connection. To configure this, use hook + option <c>hosts</c> and list the names of the servers/connections + to be used in the suite. The connections must be named for this to + work (see + <seealso marker="#open-1"><c>ct_telnet:open/1,2,3,4</c></seealso>).</p> + + <p>Hook option <c>log_type</c> can be used to change the + <c>cth_conn_log</c> behavior. The default value of this option is + <c>raw</c>, which results in the behavior described above. If the value + is set to <c>html</c>, all Telnet communication is printed to the test + case HTML log instead.</p> + + <p>All <c>cth_conn_log</c> hook options described can also be + specified in a configuration file with configuration variable + <c>ct_conn_log</c>.</p> + + <p><em>Example:</em></p> + + <pre> + {ct_conn_log, [{ct_telnet,[{log_type,raw}, + {hosts,[key_or_name()]}]}]}</pre> + + <note> + <p>Hook options specified in a configuration file overwrite any + hard-coded hook options in the test suite.</p> + </note> + + <marker id="Logging_example"/> + <p><em>Logging Example:</em></p> + + <p>The following <c>ct_hooks</c> statement causes printing of Telnet + traffic to separate logs for the connections <c>server1</c> and + <c>server2</c>. Traffic for any other connections is logged in the + default Telnet log.</p> + + <pre> + suite() -> + [{ct_hooks, + [{cth_conn_log, [{ct_telnet,[{hosts,[server1,server2]}]}]}]}].</pre> + + <p>As previously explained, this specification can also be provided by an + entry like the following in a configuration file:</p> + + <pre> + {ct_conn_log, [{ct_telnet,[{hosts,[server1,server2]}]}]}.</pre> + + <p>In this case the <c>ct_hooks</c> statement in the test suite can look + as follows:</p> + + <pre> + suite() -> + [{ct_hooks, [{cth_conn_log, []}]}].</pre> + </section> + + <section> + <title>Data Types</title> + <marker id="types"/> + <taglist> + <tag><c>connection() = handle() | {target_name(), connection_type()} | target_name()</c></tag> + <item><marker id="type-connection"/> + <p>For <c>target_name()</c>, see module + <seealso marker="ct"><c>ct</c></seealso>.</p></item> + + <tag><c>connection_type() = telnet | ts1 | ts2</c></tag> + <item><marker id="type-connection_type"/> </item> + + <tag><c>handle() = handle()</c></tag> + <item><marker id="type-handle"/> + <p>Handle for a specific Telnet connection, see module + <seealso marker="ct"><c>ct</c></seealso>.</p></item> + + <tag><c>prompt_regexp() = string()</c></tag> + <item><marker id="type-prompt_regexp"/> + <p>Regular expression matching all possible prompts for a specific + target type. <c>regexp</c> must not have any groups, that is, when + matching, <c>re:run/3</c> (in <c>STDLIB</c>) must return a list with + one single element.</p></item> + </taglist> + </section> + + <funcs> + <func> + <name>close(Connection) -> ok | {error, Reason}</name> + <fsummary>Closes the Telnet connection and stops the process managing + it.</fsummary> + <type> + <v>Connection = connection()</v> + <v>Reason = term()</v> + </type> + <desc><marker id="close-1"/> + <p>Closes the Telnet connection and stops the process managing it.</p> + + <p>A connection can be associated with a target name and/or a handle. + If <c>Connection</c> has no associated target name, it can only + be closed with the handle value (see + <seealso marker="#open-4"><c>ct_telnet:open/4</c></seealso>).</p> + </desc> + </func> + + <func> + <name>cmd(Connection, Cmd) -> {ok, Data} | {error, Reason}</name> + <fsummary>Equivalent to cmd(Connection, Cmd, []).</fsummary> + <desc><marker id="cmd-2"/> + <p>Equivalent to + <seealso marker="#cmd-3"><c>ct_telnet:cmd(Connection, Cmd, + [])</c></seealso>.</p> + </desc> + </func> + + <func> + <name>cmd(Connection, Cmd, Opts) -> {ok, Data} | {error, Reason}</name> + <fsummary>Sends a command through Telnet and waits for prompt.</fsummary> + <type> + <v>Connection = connection()</v> + <v>Cmd = string()</v> + <v>Opts = [Opt]</v> + <v>Opt = {timeout, timeout()} | {newline, boolean()}</v> + <v>Data = [string()]</v> + <v>Reason = term()</v> + </type> + <desc><marker id="cmd-3"/> + <p>Sends a command through Telnet and waits for prompt.</p> + + <p>By default, this function adds a new line to the end of the + specified command. If this is not desired, use option + <c>{newline,false}</c>. This is necessary, for example, when + sending Telnet command sequences prefixed with character + Interprete As Command (IAC).</p> + + <p>Option <c>timeout</c> specifies how long the client must wait + for prompt. If the time expires, the function returns + <c>{error,timeout}</c>. For information about the default value + for the command timeout, see the + <seealso marker="#Default_values">list of default values</seealso> + in the beginning of this module.</p> + </desc> + </func> + + <func> + <name>cmdf(Connection, CmdFormat, Args) -> {ok, Data} | {error, Reason}</name> + <fsummary>Equivalent to cmdf(Connection, CmdFormat, Args, []).</fsummary> + <desc><marker id="cmdf-3"/> + <p>Equivalent to + <seealso marker="#cmdf-4"><c>ct_telnet:cmdf(Connection, CmdFormat, + Args, [])</c></seealso>.</p> + </desc> + </func> + + <func> + <name>cmdf(Connection, CmdFormat, Args, Opts) -> {ok, Data} | {error, Reason}</name> + <fsummary>Sends a Telnet command and waits for prompt (uses a format + string and a list of arguments to build the command).</fsummary> + <type> + <v>Connection = connection()</v> + <v>CmdFormat = string()</v> + <v>Args = list()</v> + <v>Opts = [Opt]</v> + <v>Opt = {timeout, timeout()} | {newline, boolean()}</v> + <v>Data = [string()]</v> + <v>Reason = term()</v> + </type> + <desc><marker id="cmdf-4"/> + <p>Sends a Telnet command and waits for prompt (uses a format string + and a list of arguments to build the command).</p> + + <p>For details, see + <seealso marker="#cmd-3"><c>ct_telnet:cmd/3</c></seealso>.</p> + </desc> + </func> + + <func> + <name>expect(Connection, Patterns) -> term()</name> + <fsummary>Equivalent to expect(Connections, Patterns, []).</fsummary> + <desc><marker id="expect-2"/> + <p>Equivalent to + <seealso marker="#expect-3"><c>ct_telnet:expect(Connections, + Patterns, [])</c></seealso>.</p> + </desc> + </func> + + <func> + <name>expect(Connection, Patterns, Opts) -> {ok, Match} | {ok, MatchList, HaltReason} | {error, Reason}</name> + <fsummary>Gets data from Telnet and waits for the expected + pattern.</fsummary> + <type> + <v>Connection = connection()</v> + <v>Patterns = Pattern | [Pattern]</v> + <v>Pattern = string() | {Tag, string()} | prompt | {prompt, Prompt}</v> + <v>Prompt = string()</v> + <v>Tag = term()</v> + <v>Opts = [Opt]</v> + <v>Opt = {idle_timeout, IdleTimeout} | {total_timeout, TotalTimeout} | repeat | {repeat, N} | sequence | {halt, HaltPatterns} | ignore_prompt | no_prompt_check | wait_for_prompt | {wait_for_prompt, Prompt}</v> + <v>IdleTimeout = infinity | integer()</v> + <v>TotalTimeout = infinity | integer()</v> + <v>N = integer()</v> + <v>HaltPatterns = Patterns</v> + <v>MatchList = [Match]</v> + <v>Match = RxMatch | {Tag, RxMatch} | {prompt, Prompt}</v> + <v>RxMatch = [string()]</v> + <v>HaltReason = done | Match</v> + <v>Reason = timeout | {prompt, Prompt}</v> + </type> + <desc><marker id="expect-3"/> + <p>Gets data from Telnet and waits for the expected pattern.</p> + + <p><c>Pattern</c> can be a POSIX regular expression. The function + returns when a pattern is successfully matched (at least one, in + the case of multiple patterns).</p> + + <p><c>RxMatch</c> is a list of matched strings. It looks as + follows <c>[FullMatch, SubMatch1, SubMatch2, ...]</c>, where + <c>FullMatch</c> is the string matched by the whole regular + expression, and <c>SubMatchN</c> is the string that matched + subexpression number <c>N</c>. Subexpressions are denoted with + <c>(' ')</c> in the regular expression.</p> + + <p>If a <c>Tag</c> is speciifed, the returned <c>Match</c> also + includes the matched <c>Tag</c>. Otherwise, only <c>RxMatch</c> + is returned.</p> + + <p><em>Options:</em></p> + + <taglist> + <tag><c>idle_timeout</c></tag> + <item><p>Indicates that the function must return if the Telnet + client is idle (that is, if no data is received) for more than + <c>IdleTimeout</c> milliseconds. Default time-out is 10 + seconds.</p></item> + <tag><c>total_timeout</c></tag> + <item><p>Sets a time limit for the complete <c>expect</c> operation. + After <c>TotalTimeout</c> milliseconds, <c>{error,timeout}</c> + is returned. Default is <c>infinity</c> (that is, no time + limit).</p></item> + <tag><c>ignore_prompt | no_prompt_check</c></tag> + <item><p>>The function returns when a prompt is received, even if + no pattern has yet been matched, and + <c>{error,{prompt,Prompt}}</c> is returned. However, this + behavior can be modified with option <c>ignore_prompt</c> or + option <c>no_prompt_check</c>, which tells <c>expect</c> to + return only when a match is found or after a time-out.</p></item> + <tag><c>ignore_prompt</c></tag> + <item><p><c>ct_telnet</c> ignores any prompt found. This option is + useful if data sent by the server can include a pattern + matching prompt <c>regexp</c> (as returned by + <c>TargedMod:get_prompt_regexp/0</c>), but is not to not cause + the function to return.</p></item> + <tag><c>no_prompt_check</c></tag> + <item><p><c>ct_telnet</c> does not search for a prompt at all. This + is useful if, for example, <c>Pattern</c> itself matches the + prompt.</p></item> + <tag><c>wait_for_prompt</c></tag> + <item><p>Forces <c>ct_telnet</c> to wait until the prompt string + is received before returning (even if a pattern has already been + matched). This is equal to calling + <c>expect(Conn, Patterns++[{prompt,Prompt}], [sequence|Opts])</c>. + Notice that option <c>idle_timeout</c> and <c>total_timeout</c> + can abort the operation of waiting for prompt.</p></item> + <tag><c>repeat | repeat, N</c></tag> + <item><p>The pattern(s) must be matched multiple times. If <c>N</c> + is speciified, the pattern(s) are matched <c>N</c> times, and + the function returns <c>HaltReason = done</c>. This option can be + interrupted by one or more <c>HaltPatterns</c>. <c>MatchList</c> + is always returned, that is, a list of <c>Match</c> instead of + only one <c>Match</c>. Also <c>HaltReason</c> is returned.</p> + </item> + <tag><c>sequence</c></tag> + <item><p>All patterns must be matched in a sequence. A match is not + concluded until all patterns are matched. This option can be + interrupted by one or more <c>HaltPatterns</c>. <c>MatchList</c> + is always returned, that is, a list of <c>Match</c> instead of + only one <c>Match</c>. Also <c>HaltReason</c> is returned.</p> + </item> + </taglist> + + <p><em>Example 1:</em></p> + + <pre> + expect(Connection,[{abc,"ABC"},{xyz,"XYZ"}],[sequence,{halt,[{nnn,"NNN"}]}])</pre> + + <p>First this tries to match <c>"ABC"</c>, and then <c>"XYZ"</c>, but + if <c>"NNN"</c> appears, the function returns + <c>{error,{nnn,["NNN"]}}</c>. If both <c>"ABC"</c> and <c>"XYZ"</c> + are matched, the function returns <c>{ok,[AbcMatch,XyzMatch]}</c>.</p> + + <p><em>Example 2:</em></p> + + <pre> + expect(Connection,[{abc,"ABC"},{xyz,"XYZ"}],[{repeat,2},{halt,[{nnn,"NNN"}]}])</pre> + + <p>This tries to match <c>"ABC"</c> or <c>"XYZ"</c> twice. If + <c>"NNN"</c> appears, the function returns + <c>HaltReason = {nnn,["NNN"]}</c>.</p> + + <p>Options <c>repeat</c> and <c>sequence</c> can be combined to + match a sequence multiple times.</p> + </desc> + </func> + + <func> + <name>get_data(Connection) -> {ok, Data} | {error, Reason}</name> + <fsummary>Gets all data received by the Telnet client since the last + command was sent.</fsummary> + <type> + <v>Connection = connection()</v> + <v>Data = [string()]</v> + <v>Reason = term()</v> + </type> + <desc><marker id="get_data-1"/> + <p>Gets all data received by the Telnet client since the last + command was sent. Only newline-terminated strings are returned. + If the last received string has not yet been terminated, the + connection can be polled automatically until the string is + complete.</p> + + <p>The polling feature is controlled by the configuration values + <c>poll_limit</c> and <c>poll_interval</c> and is by default + disabled. This means that the function immediately returns all + complete strings received and saves a remaining non-terminated + string for a later <c>get_data</c> call.</p> + </desc> + </func> + + <func> + <name>open(Name) -> {ok, Handle} | {error, Reason}</name> + <fsummary>Equivalent to open(Name, telnet).</fsummary> + <desc><marker id="open-1"/> + <p>Equivalent to + <seealso marker="#open-2"><c>ct_telnet:open(Name, + telnet)</c></seealso>.</p> + </desc> + </func> + + <func> + <name>open(Name, ConnType) -> {ok, Handle} | {error, Reason}</name> + <fsummary>Opens a Telnet connection to the specified target + host.</fsummary> + <type> + <v>Name = target_name()</v> + <v>ConnType = connection_type()</v> + <v>Handle = handle()</v> + <v>Reason = term()</v> + </type> + <desc><marker id="open-2"/> + <p>Opens a Telnet connection to the specified target host.</p> + </desc> + </func> + + <func> + <name>open(KeyOrName, ConnType, TargetMod) -> {ok, Handle} | {error, Reason}</name> + <fsummary>Equivalent to open(KeyOrName, ConnType, TargetMod, []).</fsummary> + <desc><marker id="open-3"/> + <p>Equivalent to + <seealso marker="#open-4"><c>ct_telnet:ct_telnet:open(KeyOrName, + ConnType, TargetMod, [])</c></seealso>.</p> + </desc> + </func> + + <func> + <name>open(KeyOrName, ConnType, TargetMod, Extra) -> {ok, Handle} | {error, Reason}</name> + <fsummary>Opens a Telnet connection to the specified target + host.</fsummary> + <type> + <v>KeyOrName = Key | Name</v> + <v>Key = atom()</v> + <v>Name = target_name()</v> + <v>ConnType = connection_type()</v> + <v>TargetMod = atom()</v> + <v>Extra = term()</v> + <v>Handle = handle()</v> + <v>Reason = term()</v> + </type> + <desc><marker id="open-4"/> + <p>Opens a Telnet connection to the specified target host.</p> + + <p>The target data must exist in a configuration file. The connection + can be associated with <c>Name</c> and/or the returned <c>Handle</c>. + To allocate a name for the target, use one of the following + alternatives:</p> + + <list type="bulleted"> + <item><p><seealso marker="ct#require-2"><c>ct:require/2</c></seealso> + in a test case</p></item> + <item><p>A <c>require</c> statement in the suite information + function (<c>suite/0</c>)</p></item> + <item><p>A <c>require</c> statement in a test case information + function</p></item> + </list> + + <p>If you want the connection to be associated with <c>Handle</c> only + (if you, for example, need to open multiple connections to a host), + use <c>Key</c>, the configuration variable name, to specify the + target. Notice that a connection without an associated target name + can only be closed with the <c>Handle</c> value.</p> + + <p><c>TargetMod</c> is a module that exports the functions + <c>connect(Ip, Port, KeepAlive, Extra)</c> and + <c>get_prompt_regexp()</c> for the specified <c>TargetType</c> + (for example, <c>unix_telnet</c>).</p> + + <p>For <c>target_name()</c>, see module + <seealso marker="ct"><c>ct</c></seealso>.</p> + + <p>See also + <seealso marker="ct#require-2"><c>ct:require/2</c></seealso>.</p> + </desc> + </func> + + <func> + <name>send(Connection, Cmd) -> ok | {error, Reason}</name> + <fsummary>Equivalent to send(Connection, Cmd, []).</fsummary> + <desc><marker id="send-2"/> + <p>Equivalent to + <seealso marker="#send-3"><c>ct_telnet:send(Connection, Cmd, + [])</c></seealso>.</p> + </desc> + </func> + + <func> + <name>send(Connection, Cmd, Opts) -> ok | {error, Reason}</name> + <fsummary>Sends a Telnet command and returns immediately.</fsummary> + <type> + <v>Connection = connection()</v> + <v>Cmd = string()</v> + <v>Opts = [Opt]</v> + <v>Opt = {newline, boolean()}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="send-3"/> + <p>Sends a Telnet command and returns immediately.</p> + + <p>By default, this function adds a newline to the end of the + specified command. If this is not desired, option + <c>{newline,false}</c> can be used. This is necessary, for example, + when sending Telnet command sequences prefixed with character + Interprete As Command (IAC).</p> + + <p>The resulting output from the command can be read with + <seealso marker="#get_data-1"><c>ct_telnet:get_data/2</c></seealso> or + <seealso marker="#expect-2"><c>ct_telnet:expect/2,3</c></seealso>.</p> + </desc> + </func> + + <func> + <name>sendf(Connection, CmdFormat, Args) -> ok | {error, Reason}</name> + <fsummary>Equivalent to sendf(Connection, CmdFormat, Args, []).</fsummary> + <desc><marker id="sendf-3"/> + <p>Equivalent to + <seealso marker="#sendf-4"><c>ct_telnet:sendf(Connection, CmdFormat, + Args, [])</c></seealso>.</p> + </desc> + </func> + + <func> + <name>sendf(Connection, CmdFormat, Args, Opts) -> ok | {error, Reason}</name> + <fsummary>Sends a Telnet command and returns immediately (uses a format + string and a list of arguments to build the command).</fsummary> + <type> + <v>Connection = connection()</v> + <v>CmdFormat = string()</v> + <v>Args = list()</v> + <v>Opts = [Opt]</v> + <v>Opt = {newline, boolean()}</v> + <v>Reason = term()</v> + </type> + <desc><marker id="sendf-4"/> + <p>Sends a Telnet command and returns immediately (uses a format + string and a list of arguments to build the command).</p> + </desc> + </func> + </funcs> + + <section> + <title>See Also</title> + <p><seealso marker="unix_telnet"><c>unix_telnet</c></seealso></p> + </section> + +</erlref> + + diff --git a/lib/common_test/doc/src/dependencies_chapter.xml b/lib/common_test/doc/src/dependencies_chapter.xml index fb758d90df..29c54e819a 100644 --- a/lib/common_test/doc/src/dependencies_chapter.xml +++ b/lib/common_test/doc/src/dependencies_chapter.xml @@ -33,217 +33,220 @@ <section> <title>General</title> <p>When creating test suites, it is strongly recommended to not - create dependencies between test cases, i.e. letting test cases + create dependencies between test cases, that is, letting test cases depend on the result of previous test cases. There are various - reasons for this, for example:</p> + reasons for this, such as, the following:</p> - <list> + <list type="bulleted"> <item>It makes it impossible to run test cases individually.</item> - <item>It makes it impossible to run test cases in different order.</item> - <item>It makes debugging very difficult (since a fault could be + <item>It makes it impossible to run test cases in a different order.</item> + <item>It makes debugging difficult (as a fault can be the result of a problem in a different test case than the one failing).</item> - <item>There exists no good and explicit ways to declare dependencies, so - it may be very difficult to see and understand these in test suite + <item>There are no good and explicit ways to declare dependencies, so + it can be difficult to see and understand these in test suite code and in test logs.</item> - <item>Extending, restructuring and maintaining test suites with + <item>Extending, restructuring, and maintaining test suites with test case dependencies is difficult.</item> </list> <p>There are often sufficient means to work around the need for test case dependencies. Generally, the problem is related to the state of - the system under test (SUT). The action of one test case may alter the state - of the system and for some other test case to run properly, the new state + the System Under Test (SUT). The action of one test case can change the + system state. For some other test case to run properly, this new state must be known.</p> <p>Instead of passing data between test cases, it is recommended that the test cases read the state from the SUT and perform assertions - (i.e. let the test case run if the state is as expected, otherwise reset or fail) - and/or use the state to set variables necessary for the test case to execute - properly. Common actions can often be implemented as library functions for - test cases to call to set the SUT in a required state. (Such common actions - may of course also be separately tested if necessary, to ensure they are - working as expected). It is sometimes also possible, but not always desirable, - to group tests together in one test case, i.e. let a test case perform a - "scenario" test (a test that consists of subtests).</p> - - <p>Consider for example a server application under test. The following + (that is, let the test case run if the state is as expected, otherwise reset or fail). + It is also recommended to use the state to set variables necessary for the + test case to execute properly. Common actions can often be implemented as + library functions for test cases to call to set the SUT in a required state. + (Such common actions can also be separately tested, if necessary, + to ensure that they work as expected). It is sometimes also possible, + but not always desirable, to group tests together in one test case, that is, + let a test case perform a "scenario" test (a test consisting of subtests).</p> + + <p>Consider, for example, a server application under test. The following functionality is to be tested:</p> - <list> - <item>Starting the server.</item> - <item>Configuring the server.</item> - <item>Connecting a client to the server.</item> - <item>Disconnecting a client from the server.</item> - <item>Stopping the server.</item> + <list type="bulleted"> + <item>Starting the server</item> + <item>Configuring the server</item> + <item>Connecting a client to the server</item> + <item>Disconnecting a client from the server</item> + <item>Stopping the server</item> </list> - <p>There are obvious dependencies between the listed functions. We can't configure - the server if it hasn't first been started, we can't connect a client until - the server has been properly configured, etc. If we want to have one test - case for each of the functions, we might be tempted to try to always run the + <p>There are obvious dependencies between the listed functions. The server cannot + be configured if it has not first been started, a client connot be connectd until + the server is properly configured, and so on. If we want to have one test + case for each function, we might be tempted to try to always run the test cases in the stated order and carry possible data (identities, handles, - etc) between the cases and therefore introduce dependencies between them. - To avoid this we could consider starting and stopping the server for every test. - We would implement the start and stop action as common functions that may be - called from init_per_testcase and end_per_testcase. (We would of course test - the start and stop functionality separately). The configuration could perhaps also - be implemented as a common function, maybe grouped with the start function. - Finally the testing of connecting and disconnecting a client may be grouped into - one test case. The resulting suite would look something like this:</p> - + and so on) between the cases and therefore introduce dependencies between them.</p> + + <p>To avoid this, we can consider starting and stopping the server for every test. + We can thus implement the start and stop action as common functions to be + called from + <seealso marker="common_test#Module:init_per_testcase-2"><c>init_per_testcase</c></seealso> and + <seealso marker="common_test#Module:end_per_testcase-2"><c>end_per_testcase</c></seealso>. + (Remember to test the start and stop functionality separately.) + The configuration can also be implemented as a common function, maybe grouped + with the start function. Finally, the testing of connecting and disconnecting a + client can be grouped into one test case. The resulting suite can look as + follows:</p> <pre> - -module(my_server_SUITE). - -compile(export_all). - -include_lib("ct.hrl"). + -module(my_server_SUITE). + -compile(export_all). + -include_lib("ct.hrl"). + + %%% init and end functions... - %%% init and end functions... + suite() -> [{require,my_server_cfg}]. - suite() -> [{require,my_server_cfg}]. + init_per_testcase(start_and_stop, Config) -> + Config; - init_per_testcase(start_and_stop, Config) -> - Config; + init_per_testcase(config, Config) -> + [{server_pid,start_server()} | Config]; - init_per_testcase(config, Config) -> - [{server_pid,start_server()} | Config]; + init_per_testcase(_, Config) -> + ServerPid = start_server(), + configure_server(), + [{server_pid,ServerPid} | Config]. - init_per_testcase(_, Config) -> - ServerPid = start_server(), - configure_server(), - [{server_pid,ServerPid} | Config]. + end_per_testcase(start_and_stop, _) -> + ok; - end_per_testcase(start_and_stop, _) -> - ok; + end_per_testcase(_, _) -> + ServerPid = ?config(server_pid), + stop_server(ServerPid). - end_per_testcase(_, _) -> - ServerPid = ?config(server_pid), - stop_server(ServerPid). + %%% test cases... - %%% test cases... + all() -> [start_and_stop, config, connect_and_disconnect]. - all() -> [start_and_stop, config, connect_and_disconnect]. + %% test that starting and stopping works + start_and_stop(_) -> + ServerPid = start_server(), + stop_server(ServerPid). - %% test that starting and stopping works - start_and_stop(_) -> - ServerPid = start_server(), - stop_server(ServerPid). + %% configuration test + config(Config) -> + ServerPid = ?config(server_pid, Config), + configure_server(ServerPid). - %% configuration test - config(Config) -> - ServerPid = ?config(server_pid, Config), - configure_server(ServerPid). + %% test connecting and disconnecting client + connect_and_disconnect(Config) -> + ServerPid = ?config(server_pid, Config), + {ok,SessionId} = my_server:connect(ServerPid), + ok = my_server:disconnect(ServerPid, SessionId). - %% test connecting and disconnecting client - connect_and_disconnect(Config) -> - ServerPid = ?config(server_pid, Config), - {ok,SessionId} = my_server:connect(ServerPid), - ok = my_server:disconnect(ServerPid, SessionId). + %%% common functions... - %%% common functions... + start_server() -> + {ok,ServerPid} = my_server:start(), + ServerPid. - start_server() -> - {ok,ServerPid} = my_server:start(), - ServerPid. + stop_server(ServerPid) -> + ok = my_server:stop(), + ok. - stop_server(ServerPid) -> - ok = my_server:stop(), - ok. + configure_server(ServerPid) -> + ServerCfgData = ct:get_config(my_server_cfg), + ok = my_server:configure(ServerPid, ServerCfgData), + ok.</pre> - configure_server(ServerPid) -> - ServerCfgData = ct:get_config(my_server_cfg), - ok = my_server:configure(ServerPid, ServerCfgData), - ok. - </pre> </section> <section> <marker id="save_config"></marker> - <title>Saving configuration data</title> + <title>Saving Configuration Data</title> - <p>There might be situations where it is impossible, or infeasible at least, to - implement independent test cases. Maybe it is simply not possible to read the - SUT state. Maybe resetting the SUT is impossible and it takes much too long + <p>Sometimes it is impossible, or infeasible, to + implement independent test cases. Maybe it is not possible to read the + SUT state. Maybe resetting the SUT is impossible and it takes too long time to restart the system. In situations where test case dependency is necessary, CT offers a structured way to carry data from one test case to the next. The - same mechanism may also be used to carry data from one test suite to the next.</p> + same mechanism can also be used to carry data from one test suite to the next.</p> <p>The mechanism for passing data is called <c>save_config</c>. The idea is that - one test case (or suite) may save the current value of Config - or any list of - key-value tuples - so that it can be read by the next executing test case - (or test suite). The configuration data is not saved permanently but can only - be passed from one case (or suite) to the next.</p> + one test case (or suite) can save the current value of <c>Config</c>, or any list of + key-value tuples, so that the next executing test case (or test suite) can read it. + The configuration data is not saved permanently but can only be passed from one + case (or suite) to the next.</p> - <p>To save <c>Config</c> data, return the tuple:</p> + <p>To save <c>Config</c> data, return tuple <c>{save_config,ConfigList}</c> + from <c>end_per_testcase</c> or from the main test case function.</p> - <p><c>{save_config,ConfigList}</c></p> - - <p>from <c>end_per_testcase</c> or from the main test case function. To read data - saved by a previous test case, use the <c>config</c> macro with a - <c>saved_config</c> key:</p> + <p>To read data saved by a previous test case, use macro <c>config</c> with a + <c>saved_config</c> key as follows:</p> <p><c>{Saver,ConfigList} = ?config(saved_config, Config)</c></p> <p><c>Saver</c> (<c>atom()</c>) is the name of the previous test case (where the - data was saved). The <c>config</c> macro may be used to extract particular data + data was saved). The <c>config</c> macro can be used to extract particular data also from the recalled <c>ConfigList</c>. It is strongly recommended that <c>Saver</c> is always matched to the expected name of the saving test case. - This way problems due to restructuring of the test suite may be avoided. Also it - makes the dependency more explicit and the test suite easier to read and maintain.</p> + This way, problems because of restructuring of the test suite can be avoided. + Also, it makes the dependency more explicit and the test suite easier to read + and maintain.</p> <p>To pass data from one test suite to another, the same mechanism is used. The data - should be saved by the <c>end_per_suite</c> function and read by <c>init_per_suite</c> + is to be saved by finction + <seealso marker="common_test#Module:end_per_suite-1"><c>end_per_suite</c></seealso> + and read by function + <seealso marker="common_test#Module:init_per_suite-1"><c>init_per_suite</c></seealso> in the suite that follows. When passing data between suites, <c>Saver</c> carries the name of the test suite.</p> - <p>Example:</p> + <p><em>Example:</em></p> <pre> - -module(server_b_SUITE). - -compile(export_all). - -include_lib("ct.hrl"). - - %%% init and end functions... - - init_per_suite(Config) -> - %% read config saved by previous test suite - {server_a_SUITE,OldConfig} = ?config(saved_config, Config), - %% extract server identity (comes from server_a_SUITE) - ServerId = ?config(server_id, OldConfig), - SessionId = connect_to_server(ServerId), - [{ids,{ServerId,SessionId}} | Config]. - - end_per_suite(Config) -> - %% save config for server_c_SUITE (session_id and server_id) - {save_config,Config} - - %%% test cases... - - all() -> [allocate, deallocate]. - - allocate(Config) -> - {ServerId,SessionId} = ?config(ids, Config), - {ok,Handle} = allocate_resource(ServerId, SessionId), - %% save handle for deallocation test - NewConfig = [{handle,Handle}], - {save_config,NewConfig}. - - deallocate(Config) -> - {ServerId,SessionId} = ?config(ids, Config), - {allocate,OldConfig} = ?config(saved_config, Config), - Handle = ?config(handle, OldConfig), - ok = deallocate_resource(ServerId, SessionId, Handle). - </pre> - - <p>It is also possible to save <c>Config</c> data from a test case that is to be - skipped. To accomplish this, return the following tuple:</p> - - <p><c>{skip_and_save,Reason,ConfigList}</c></p> - - <p>The result will be that the test case is skipped with <c>Reason</c> printed to - the log file (as described in previous chapters), and <c>ConfigList</c> is saved - for the next test case. <c>ConfigList</c> may be read by means of - <c>?config(saved_config, Config)</c>, as described above. <c>skip_and_save</c> - may also be returned from <c>init_per_suite</c>, in which case the saved data can + -module(server_b_SUITE). + -compile(export_all). + -include_lib("ct.hrl"). + + %%% init and end functions... + + init_per_suite(Config) -> + %% read config saved by previous test suite + {server_a_SUITE,OldConfig} = ?config(saved_config, Config), + %% extract server identity (comes from server_a_SUITE) + ServerId = ?config(server_id, OldConfig), + SessionId = connect_to_server(ServerId), + [{ids,{ServerId,SessionId}} | Config]. + + end_per_suite(Config) -> + %% save config for server_c_SUITE (session_id and server_id) + {save_config,Config} + + %%% test cases... + + all() -> [allocate, deallocate]. + + allocate(Config) -> + {ServerId,SessionId} = ?config(ids, Config), + {ok,Handle} = allocate_resource(ServerId, SessionId), + %% save handle for deallocation test + NewConfig = [{handle,Handle}], + {save_config,NewConfig}. + + deallocate(Config) -> + {ServerId,SessionId} = ?config(ids, Config), + {allocate,OldConfig} = ?config(saved_config, Config), + Handle = ?config(handle, OldConfig), + ok = deallocate_resource(ServerId, SessionId, Handle).</pre> + + <p>To save <c>Config</c> data from a test case that is to be + skipped, return tuple + <c>{skip_and_save,Reason,ConfigList}</c>.</p> + + <p>The result is that the test case is skipped with <c>Reason</c> printed to + the log file (as described earlier) and <c>ConfigList</c> is saved + for the next test case. <c>ConfigList</c> can be read using + <c>?config(saved_config, Config)</c>, as described earlier. <c>skip_and_save</c> + can also be returned from <c>init_per_suite</c>. In this case, the saved data can be read by <c>init_per_suite</c> in the suite that follows.</p> </section> @@ -251,60 +254,63 @@ <marker id="sequences"></marker> <title>Sequences</title> - <p>It is possible that test cases depend on each other so that - if one case fails, the following test(s) should not be executed. + <p>Sometimes test cases depend on each other so that + if one case fails, the following tests are not to be executed. Typically, if the <c>save_config</c> facility is used and a test case that is expected to save data crashes, the following - case can not run. CT offers a way to declare such dependencies, + case cannot run. <c>Common Test</c> offers a way to declare such dependencies, called sequences.</p> <p>A sequence of test cases is defined as a test case group - with a <c>sequence</c> property. Test case groups are defined by - means of the <c>groups/0</c> function in the test suite (see the - <seealso marker="write_test_chapter#test_case_groups">Test case groups</seealso> - chapter for details).</p> - - <p>For example, if we would like to make sure that if <c>allocate</c> - in <c>server_b_SUITE</c> (above) crashes, <c>deallocate</c> is skipped, - we may define a sequence like this:</p> + with a <c>sequence</c> property. Test case groups are defined + through function <c>groups/0</c> in the test suite (for details, see section + <seealso marker="write_test_chapter#test_case_groups">Test Case Groups</seealso>.</p> + + <p>For example, to ensure that if <c>allocate</c> + in <c>server_b_SUITE</c> crashes, <c>deallocate</c> is skipped, + the following sequence can be defined:</p> <pre> - groups() -> [{alloc_and_dealloc, [sequence], [alloc,dealloc]}].</pre> + groups() -> [{alloc_and_dealloc, [sequence], [alloc,dealloc]}].</pre> - <p>Let's also assume the suite contains the test case <c>get_resource_status</c>, - which is independent of the other two cases, then the <c>all</c> function could - look like this:</p> + <p>Assume that the suite contains the test case <c>get_resource_status</c> + that is independent of the other two cases, then function <c>all</c> can + look as follows:</p> <pre> - all() -> [{group,alloc_and_dealloc}, get_resource_status].</pre> + all() -> [{group,alloc_and_dealloc}, get_resource_status].</pre> <p>If <c>alloc</c> succeeds, <c>dealloc</c> is also executed. If <c>alloc</c> fails - however, <c>dealloc</c> is not executed but marked as SKIPPED in the html log. - <c>get_resource_status</c> will run no matter what happens to the <c>alloc_and_dealloc</c> + however, <c>dealloc</c> is not executed but marked as <c>SKIPPED</c> in the HTML log. + <c>get_resource_status</c> runs no matter what happens to the <c>alloc_and_dealloc</c> cases.</p> - <p>Test cases in a sequence will be executed in order until they have all succeeded or - until one case fails. If one fails, all following cases in the sequence are skipped. - The cases in the sequence that have succeeded up to that point are reported as successful - in the log. An arbitrary number of sequences may be specified. Example:</p> + <p>Test cases in a sequence are executed in order until all succeed or + one fails. If one fails, all following cases in the sequence are skipped. + The cases in the sequence that have succeeded up to that point are reported as + successful in the log. Any number of sequences can be specified.</p> + <p><em>Example:</em></p> <pre> - groups() -> [{scenarioA, [sequence], [testA1, testA2]}, - {scenarioB, [sequence], [testB1, testB2, testB3]}]. - - all() -> [test1, - test2, - {group,scenarioA}, - test3, - {group,scenarioB}, - test4].</pre> - - <p>It is possible to have sub-groups in a sequence group. Such sub-groups can have - any property, i.e. they are not required to also be sequences. If you want the status - of the sub-group to affect the sequence on the level above, return - <c>{return_group_result,Status}</c> from <c>end_per_group/2</c>, as described in the - <seealso marker="write_test_chapter#repeated_groups">Repeated groups</seealso> - chapter. A failed sub-group (<c>Status == failed</c>) will cause the execution of a + groups() -> [{scenarioA, [sequence], [testA1, testA2]}, + {scenarioB, [sequence], [testB1, testB2, testB3]}]. + + all() -> [test1, + test2, + {group,scenarioA}, + test3, + {group,scenarioB}, + test4].</pre> + + <p>A sequence group can have subgroups. Such subgroups can have + any property, that is, they are not required to also be sequences. If you want the + status of the subgroup to affect the sequence on the level above, return + <c>{return_group_result,Status}</c> from + <seealso marker="common_test#Module:end_per_group-2"><c>end_per_group/2</c></seealso>, + as described in section + <seealso marker="write_test_chapter#repeated_groups">Repeated Groups</seealso> + in Writing Test Suites. + A failed subgroup (<c>Status == failed</c>) causes the execution of a sequence to fail in the same way a test case does.</p> </section> </chapter> diff --git a/lib/common_test/doc/src/event_handler_chapter.xml b/lib/common_test/doc/src/event_handler_chapter.xml index cb7033b196..31128a7114 100644 --- a/lib/common_test/doc/src/event_handler_chapter.xml +++ b/lib/common_test/doc/src/event_handler_chapter.xml @@ -33,144 +33,171 @@ <section> <marker id="event_handling"></marker> <title>General</title> - <p>It is possible for the operator of a Common Test system to receive - event notifications continously during a test run. It is reported e.g. - when a test case starts and stops, what the current count of successful, - failed and skipped cases is, etc. This information can be used for - different purposes such as logging progress and results on - other format than HTML, saving statistics to a database for report - generation and test system supervision.</p> - - <p>Common Test has a framework for event handling which is based on - the OTP event manager concept and gen_event behaviour. When the Common Test - server starts, it spawns an event manager. During test execution the - manager gets a notification from the server every time something - of potential interest happens. Any event handler plugged into the - event manager can match on events of interest, take action, or maybe - simply pass the information on. Event handlers are Erlang modules - implemented by the Common Test user according to the gen_event - behaviour (see the OTP User's Guide and Reference Manual for more - information).</p> - - <p>As already described, a Common Test server always starts an event manager. - The server also plugs in a default event handler which has as its only - purpose to relay notifications to a globally registered CT Master - event manager (if a CT Master server is running in the system). - The CT Master also spawns an event manager at startup. - Event handlers plugged into this manager will receive the events from - all the test nodes as well as information from the CT Master server - itself.</p> - - <p>User specific event handlers may be plugged into a Common Test event - manager, either by telling Common Test to install them before the test - run (see below), or by adding the handlers dynamically during the test - run by means of - <c>gen_event:add_handler/3</c> or <c>gen_event:add_sup_handler/3</c>. - In the latter scenario, the reference of the Common Test event manager is - required. To get it, call <c>ct:get_event_mgr_ref/0</c> or (on the CT - Master node) <c>ct_master:get_event_mgr_ref/0</c>.</p> + <p>The operator of a <c>Common Test</c> system can receive + event notifications continuously during a test run. For example, + <c>Common Test</c> reports when a test case starts and stops, + the current count of successful, failed, and skipped cases, and so on. + This information can be used for different purposes such as logging progress + and results in another format than HTML, saving statistics to a database + for report generation, and test system supervision.</p> + + <p><c>Common Test</c> has a framework for event handling based on + the OTP event manager concept and <c>gen_event</c> behavior. + When the <c>Common Test</c> server starts, it spawns an event manager. + During test execution the manager gets a notification from the server + when something of potential interest happens. Any event handler plugged into + the event manager can match on events of interest, take action, or + pass the information on. The event handlers are Erlang modules + implemented by the <c>Common Test</c> user according to the <c>gen_event</c> + behavior (for details, see module + <seealso marker="stdlib:gen_event"><c>stdlib:gen_event</c></seealso> and + section + <seealso marker="doc/design_principles:events"><c>gen_event Behaviour</c></seealso> + in OTP Design Principles in the System Documentation). + </p> + + <p>A <c>Common Test</c> server always starts an event manager. + The server also plugs in a default event handler, which only + purpose is to relay notifications to a globally registered <c>Common Test</c> + Master event manager (if a <c>Common Test</c> Master server is running in the system). + The <c>Common Test</c> Master also spawns an event manager at startup. + Event handlers plugged into this manager receives the events from + all the test nodes, plus information from the <c>Common Test</c> Master server. + </p> + + <p>User-specific event handlers can be plugged into a <c>Common Test</c> event + manager, either by telling <c>Common Test</c> to install them before the test + run (described later), or by adding the handlers dynamically during the test + run using + <seealso marker="stdlib:gen_event#add_handler-3"><c>stdlib:gen_event:add_handler/3</c></seealso> or + <seealso marker="stdlib:gen_event#add_sup_handler-3"><c>stdlib:gen_event:add_sup_handler/3</c></seealso>. + In the latter scenario, the reference of the <c>Common Test</c> event manager is + required. To get it, call + <seealso marker="ct#get_event_mgr_ref-0"><c>ct:get_event_mgr_ref/0</c></seealso> + or (on the <c>Common Test</c> Master node) + <seealso marker="ct_master#get_event_mgr_ref-0"><c>ct_master:get_event_mgr_ref/0</c></seealso>.</p> </section> <section> <marker id="usage"></marker> - <title>Usage</title> - <p>Event handlers may be installed by means of an <c>event_handler</c> - start flag (<c>ct_run</c>) or option (<seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso>), where the - argument specifies the names of one or more event handler modules. - Example:</p> + <title>Use</title> + <p>Event handlers can be installed by an <c>event_handler</c> start flag + (<seealso marker="ct_run"><c>ct_run</c></seealso>) or option + <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso>, where the + argument specifies the names of one or more event handler modules.</p> + + <p><em>Example:</em></p> <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[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 - these modules must be precompiled, and that their locations must be - added explicitly to the Erlang code server search path (like in the - example).</p> - <p>An event_handler tuple in the argument <c>Opts</c> has the following - definition (see also <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso> in the reference manual):</p> + <p>To pass start arguments to the event handler init function, use option + <c><![CDATA[ct_run -event_handler_init]]></c> instead of + <c><![CDATA[-event_handler]]></c>.</p> + + <note><p>All event handler modules must have <c>gen_event</c> behavior. + These modules must be precompiled and their locations must be + added explicitly to the Erlang code server search path (as in the previous + example).</p></note> + + <p>An event_handler tuple in argument <c>Opts</c> has the following definition + (see <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso>):</p> <pre> - {event_handler,EventHandlers} + {event_handler,EventHandlers} - EventHandlers = EH | [EH] - EH = atom() | {atom(),InitArgs} | {[atom()],InitArgs} - InitArgs = [term()]</pre> + EventHandlers = EH | [EH] + EH = atom() | {atom(),InitArgs} | {[atom()],InitArgs} + InitArgs = [term()]</pre> - <p>Example:</p> + <p>In the following example, two event handlers for the <c>my_SUITE</c> test are installed:</p> <pre> - 1> ct:run_test([{suite,"test/my_SUITE"},{event_handler,[my_evh1,{my_evh2,[node()]}]}]).</pre> - <p>This will install two event handlers for the <c>my_SUITE</c> test. Event handler - <c>my_evh1</c> is started with <c>[]</c> as argument to the init function. Event handler - <c>my_evh2</c> is started with the name of the current node in the init argument list.</p> + 1> ct:run_test([{suite,"test/my_SUITE"},{event_handler,[my_evh1,{my_evh2,[node()]}]}]).</pre> + <p>Event handler <c>my_evh1</c> is started with <c>[]</c> as argument to the init function. + Event handler <c>my_evh2</c> is started with the name of the current node in the init argument list.</p> - <p>Event handlers can also be plugged in by means of + <p>Event handlers can also be plugged in using one of the following <seealso marker="run_test_chapter#test_specifications">test specification</seealso> terms:</p> - - <p><c>{event_handler, EventHandlers}</c>, or</p> - <p><c>{event_handler, EventHandlers, InitArgs}</c>, or</p> - <p><c>{event_handler, NodeRefs, EventHandlers}</c>, or</p> - <p><c>{event_handler, NodeRefs, EventHandlers, InitArgs}</c></p> + <list type="bulleted"> + <item><c>{event_handler, EventHandlers}</c></item> + <item><c>{event_handler, EventHandlers, InitArgs}</c></item> + <item><c>{event_handler, NodeRefs, EventHandlers}</c></item> + <item><c>{event_handler, NodeRefs, EventHandlers, InitArgs}</c></item> + </list> <p><c>EventHandlers</c> is a list of module names. Before a test session starts, the init function of each plugged in event handler - is called (with the InitArgs list as argument or [] if - no start arguments are given).</p> + is called (with the <c>InitArgs</c> list as argument or <c>[]</c> if + no start arguments are specified).</p> - <p>To plug a handler into the CT Master event manager, specify + <p>To plug in a handler to the <c>Common Test</c> Master event manager, specify <c>master</c> as the node in <c>NodeRefs</c>.</p> - <p>For an event handler to be able to match on events, the module must + <p>To be able to match on events, the event handler module must include the header file <c>ct_event.hrl</c>. An event is a record with the following definition:</p> <p><c>#event{name, node, data}</c></p> - <p><c>name</c> is the label (type) of the event. <c>node</c> is the name of the - node the event has originated from (only relevant for CT Master event handlers). - <c>data</c> is specific for the particular event.</p> + <taglist> + <tag><c>name</c></tag> + <item><p>Label (type) of the event.</p></item> + <tag><c>node</c></tag> + <item><p>Name of the node that the event originated from + (only relevant for <c>Common Test</c> Master event handlers).</p></item> + <tag><c>data</c></tag> + <item><p>Specific for the event.</p></item> + </taglist> + <marker id="events"></marker> - <p><em>General events:</em></p> + <section> + <title>General Events</title> + + <p>The general events are as follows:</p> - <list> - <item><c>#event{name = start_logging, data = LogDir}</c> - <p><c>LogDir = string()</c>, top level log directory for the test run.</p> - <p>Indicates that the logging process of Common Test - has started successfully and is ready to receive IO + <taglist> + <tag><c>#event{name = start_logging, data = LogDir}</c></tag> + <item> + <p><c>LogDir = string()</c>, top-level log directory for the test run.</p> + <p>This event indicates that the logging process of <c>Common Test</c> + has started successfully and is ready to receive I/O messages.</p></item> - <item><c>#event{name = stop_logging, data = []}</c> - <p>Indicates that the logging process of Common Test - has been shut down at the end of the test run. + <tag><c>#event{name = stop_logging, data = []}</c></tag> + <item> + <p>This event indicates that the logging process of <c>Common Test</c> + was shut down at the end of the test run. </p></item> - <item><c>#event{name = test_start, data = {StartTime,LogDir}}</c> + <tag><c>#event{name = test_start, data = {StartTime,LogDir}}</c></tag> + <item> <p><c>StartTime = {date(),time()}</c>, test run start date and time.</p> - <p><c>LogDir = string()</c>, top level log directory for the test run.</p> - <p>This event indicates that Common Test has finished initial preparations - and will begin executing test cases. + <p><c>LogDir = string()</c>, top-level log directory for the test run.</p> + <p>This event indicates that <c>Common Test</c> has finished initial preparations + and begins executing test cases. </p></item> - <item><c>#event{name = test_done, data = EndTime}</c> + <tag><c>#event{name = test_done, data = EndTime}</c></tag> + <item> <p><c>EndTime = {date(),time()}</c>, date and time the test run finished.</p> - <p>This indicates that the last test case has been executed and - Common Test is shutting down. + <p>This event indicates that the last test case has been executed and + <c>Common Test</c> is shutting down. </p></item> - <item><c>#event{name = start_info, data = {Tests,Suites,Cases}}</c> - <p><c>Tests = integer()</c>, the number of tests.</p> - <p><c>Suites = integer()</c>, the total number of suites.</p> - <p><c>Cases = integer() | unknown</c>, the total number of test cases.</p> - <p>Initial test run information that can be interpreted as: "This test - run will execute <c>Tests</c> separate tests, in total containing + <tag><c>#event{name = start_info, data = {Tests,Suites,Cases}}</c></tag> + <item> + <p><c>Tests = integer()</c>, number of tests.</p> + <p><c>Suites = integer()</c>, total number of suites.</p> + <p><c>Cases = integer() | unknown</c>, total number of test cases.</p> + <p>This event gives initial test run information that can be interpreted as: + "This test run will execute <c>Tests</c> separate tests, in total containing <c>Cases</c> number of test cases, in <c>Suites</c> number of suites". - Note that if a test case group with a repeat property exists in any test, - the total number of test cases can not be calculated (unknown). + However, if a test case group with a repeat property exists in any test, + the total number of test cases cannot be calculated (unknown). </p></item> - <item><c>#event{name = tc_start, data = {Suite,FuncOrGroup}}</c> + <tag><c>#event{name = tc_start, data = {Suite,FuncOrGroup}}</c></tag> + <item> <p><c>Suite = atom()</c>, name of the test suite.</p> <p><c>FuncOrGroup = Func | {Conf,GroupName,GroupProperties}</c></p> <p><c>Func = atom()</c>, name of test case or configuration function.</p> @@ -180,22 +207,24 @@ <p>This event informs about the start of a test case, or a group configuration function. The event is sent also for <c>init_per_suite</c> and <c>end_per_suite</c>, but not for <c>init_per_testcase</c> and <c>end_per_testcase</c>. If a group - configuration function is starting, the group name and execution properties - are also given. + configuration function starts, the group name and execution properties + are also specified. </p></item> - <item><c>#event{name = tc_logfile, data = {{Suite,Func},LogFileName}}</c> + <tag><c>#event{name = tc_logfile, data = {{Suite,Func},LogFileName}}</c></tag> + <item> <p><c>Suite = atom()</c>, name of the test suite.</p> <p><c>Func = atom()</c>, name of test case or configuration function.</p> - <p><c>LogFileName = string()</c>, full name of test case log file.</p> + <p><c>LogFileName = string()</c>, full name of the test case log file.</p> <p>This event is sent at the start of each test case (and configuration function except <c>init/end_per_testcase</c>) and carries information about the - full name (i.e. the file name including the absolute directory path) of + full name (that is, the file name including the absolute directory path) of the current test case log file. </p></item> - <marker id="tc_done"/> - <item><c>#event{name = tc_done, data = {Suite,FuncOrGroup,Result}}</c> + <tag><c>#event{name = tc_done, data = {Suite,FuncOrGroup,Result}}</c></tag> + <item> + <marker id="tc_done"/> <p><c>Suite = atom()</c>, name of the suite.</p> <p><c>FuncOrGroup = Func | {Conf,GroupName,GroupProperties}</c></p> <p><c>Func = atom()</c>, name of test case or configuration function.</p> @@ -210,34 +239,37 @@ {require_failed_in_suite0,RequireInfo} | {failed,{Suite,init_per_testcase,FailInfo}} | UserTerm</c>, - the reason why the case has been skipped.</p> + why the case was skipped.</p> <marker id="failreason"/> <p><c>FailReason = {error,FailInfo} | {error,{RunTimeError,StackTrace}} | {timetrap_timeout,integer()} | {failed,{Suite,end_per_testcase,FailInfo}}</c>, reason for failure.</p> - <p><c>RequireInfo = {not_available,atom() | tuple()}</c>, why require has failed.</p> + <p><c>RequireInfo = {not_available,atom() | tuple()}</c>, why require failed.</p> <p><c>FailInfo = {timetrap_timeout,integer()} | {RunTimeError,StackTrace} | UserTerm</c>, - detailed information about an error.</p> - <p><c>RunTimeError = term()</c>, a run-time error, e.g. badmatch, undef, etc.</p> - <p><c>StackTrace = list()</c>, list of function calls preceeding a run-time error.</p> - <p><c>UserTerm = term()</c>, arbitrary data specified by user, or <c>exit/1</c> info.</p> - <p>This event informs about the end of a test case or a configuration function (see the - <c>tc_start</c> event for details on the FuncOrGroup element). With this event comes the - final result of the function in question. It is possible to determine on the top level - of <c>Result</c> if the function was successful, skipped (by the user), or if it failed. - It is of course possible to dig deeper and also perform pattern matching on the various - reasons for skipped or failed. Note that <c>{'EXIT',Reason}</c> tuples have been translated into - <c>{error,Reason}</c>. Note also that if a <c>{failed,{Suite,end_per_testcase,FailInfo}</c> - result is received, it actually means the test case was successful, but that + error details.</p> + <p><c>RunTimeError = term()</c>, a runtime error, for example, + <c>badmatch</c> or <c>undef</c>.</p> + <p><c>StackTrace = list()</c>, list of function calls preceding a runtime error.</p> + <p><c>UserTerm = term()</c>, any data specified by user, or <c>exit/1</c> information.</p> + <p>This event informs about the end of a test case or a configuration function (see event + <c>tc_start</c> for details on element <c>FuncOrGroup</c>). With this event + comes the final result of the function in question. It is possible to determine on the + top level of <c>Result</c> if the function was successful, skipped (by the user), + or if it failed.</p> + <p>It is also possible to dig deeper and, for example, perform pattern matching + on the various reasons for skipped or failed. Notice that <c>{'EXIT',Reason}</c> tuples + are translated into <c>{error,Reason}</c>. + Notice also that if a <c>{failed,{Suite,end_per_testcase,FailInfo}</c> + result is received, the test case was successful, but <c>end_per_testcase</c> for the case failed. </p></item> + <tag><c>#event{name = tc_auto_skip, data = {Suite,TestName,Reason}}</c></tag> <item> <marker id="tc_auto_skip"></marker> - <c>#event{name = tc_auto_skip, data = {Suite,TestName,Reason}}</c> <p><c>Suite = atom()</c>, the name of the suite.</p> <p><c>TestName = init_per_suite | end_per_suite | {init_per_group,GroupName} | {end_per_group,GroupName} | @@ -246,101 +278,116 @@ <p><c>GroupName = atom()</c>, the name of the test case group.</p> <p><c>Reason = {failed,FailReason} | {require_failed_in_suite0,RequireInfo}</c>, - reason for auto skipping <c>Func</c>.</p> + reason for auto-skipping <c>Func</c>.</p> <p><c>FailReason = {Suite,ConfigFunc,FailInfo}} | {Suite,FailedCaseInSequence}</c>, reason for failure.</p> - <p><c>RequireInfo = {not_available,atom() | tuple()}</c>, why require has failed.</p> + <p><c>RequireInfo = {not_available,atom() | tuple()}</c>, why require failed.</p> <p><c>ConfigFunc = init_per_suite | init_per_group</c></p> <p><c>FailInfo = {timetrap_timeout,integer()} | {RunTimeError,StackTrace} | bad_return | UserTerm</c>, - detailed information about an error.</p> - <p><c>FailedCaseInSequence = atom()</c>, name of a case that has failed in a sequence.</p> - <p><c>RunTimeError = term()</c>, a run-time error, e.g. badmatch, undef, etc.</p> - <p><c>StackTrace = list()</c>, list of function calls preceeding a run-time error.</p> - <p><c>UserTerm = term()</c>, arbitrary data specified by user, or <c>exit/1</c> info.</p> - <p>This event gets sent for every test case or configuration function that Common Test + error details.</p> + <p><c>FailedCaseInSequence = atom()</c>, the name of a case that failed in a sequence.</p> + <p><c>RunTimeError = term()</c>, a runtime error, for example <c>badmatch</c> or + <c>undef</c>.</p> + <p><c>StackTrace = list()</c>, list of function calls preceeding a runtime error.</p> + <p><c>UserTerm = term()</c>, any data specified by user, or <c>exit/1</c> information.</p> + <p>This event is sent for every test case or configuration function that <c>Common Test</c> has skipped automatically because of either a failed <c>init_per_suite</c> or <c>init_per_group</c>, a failed <c>require</c> in <c>suite/0</c>, or a failed test case - in a sequence. Note that this event is never received as a result of a test case getting - skipped because of <c>init_per_testcase</c> failing, since that information is carried with - the <c>tc_done</c> event. If a failed test case belongs to a test case group, the second - data element is a tuple <c>{FuncName,GroupName}</c>, otherwise simply the function name. + in a sequence. Notice that this event is never received as a result of a test case getting + skipped because of <c>init_per_testcase</c> failing, as that information is carried with + event <c>tc_done</c>. If a failed test case belongs to a test case group, the second + data element is a tuple <c>{FuncName,GroupName}</c>, otherwise only the function name. </p></item> + <tag><c>#event{name = tc_user_skip, data = {Suite,TestName,Comment}}</c></tag> <item> - <marker id="tc_user_skip"></marker> - <c>#event{name = tc_user_skip, data = {Suite,TestName,Comment}}</c> + <marker id="tc_user_skip"></marker> <p><c>Suite = atom()</c>, the name of the suite.</p> <p><c>TestName = init_per_suite | end_per_suite | {init_per_group,GroupName} | {end_per_group,GroupName} | {FuncName,GroupName} | FuncName</c></p> <p><c>FuncName = atom()</c>, the name of the test case or configuration function.</p> <p><c>GroupName = atom()</c>, the name of the test case group.</p> - <p><c>Comment = string()</c>, reason for skipping the test case.</p> - <p>This event specifies that a test case has been skipped by the user. - It is only ever received if the skip was declared in a test specification. + <p><c>Comment = string()</c>, why the test case was skipped.</p> + <p>This event specifies that a test case was skipped by the user. + It is only received if the skip is declared in a test specification. Otherwise, user skip information is received as a <c>{skipped,SkipReason}</c> - result in the <c>tc_done</c> event for the test case. If a skipped test case belongs + result in event <c>tc_done</c> for the test case. If a skipped test case belongs to a test case group, the second data element is a tuple <c>{FuncName,GroupName}</c>, - otherwise simply the function name. + otherwise only the function name. </p></item> - <item><c>#event{name = test_stats, data = {Ok,Failed,Skipped}}</c> - <p><c>Ok = integer()</c>, the current number of successful test cases.</p> - <p><c>Failed = integer()</c>, the current number of failed test cases.</p> + <tag><c>#event{name = test_stats, data = {Ok,Failed,Skipped}}</c></tag> + <item> + <p><c>Ok = integer()</c>, current number of successful test cases.</p> + <p><c>Failed = integer()</c>, current number of failed test cases.</p> <p><c>Skipped = {UserSkipped,AutoSkipped}</c></p> - <p><c>UserSkipped = integer()</c>, the current number of user skipped test cases.</p> - <p><c>AutoSkipped = integer()</c>, the current number of auto skipped test cases.</p> - <p>This is a statistics event with the current count of successful, skipped - and failed test cases so far. This event gets sent after the end of each test case, - immediately following the <c>tc_done</c> event. + <p><c>UserSkipped = integer()</c>, current number of user-skipped test cases.</p> + <p><c>AutoSkipped = integer()</c>, current number of auto-skipped test cases.</p> + <p>This is a statistics event with current count of successful, skipped, + and failed test cases so far. This event is sent after the end of each test case, + immediately following event <c>tc_done</c>. </p></item> - </list> + </taglist> + </section> + + <section> + <title>Internal Events</title> - <p><em>Internal events:</em></p> + <p>The internal events are as follows:</p> - <list> - <item><c>#event{name = start_make, data = Dir}</c> + <taglist> + <tag><c>#event{name = start_make, data = Dir}</c></tag> + <item> <p><c>Dir = string()</c>, running make in this directory.</p> - <p>An internal event saying that Common Test will start compiling + <p>This internal event says that <c>Common Test</c> starts compiling modules in directory <c>Dir</c>. </p></item> - <item><c>#event{name = finished_make, data = Dir}</c> + <tag><c>#event{name = finished_make, data = Dir}</c></tag> + <item> <p><c>Dir = string()</c>, finished running make in this directory.</p> - <p>An internal event saying that Common Test is finished compiling + <p>This internal event says that <c>Common Test</c> is finished compiling modules in directory <c>Dir</c>. </p></item> - <item><c>#event{name = start_write_file, data = FullNameFile}</c> + <tag><c>#event{name = start_write_file, data = FullNameFile}</c></tag> + <item> <p><c>FullNameFile = string(), full name of the file.</c></p> - <p>An internal event used by the Common Test Master process to + <p>This internal event is used by the <c>Common Test</c> Master process to synchronize particular file operations. </p></item> - <item><c>#event{name = finished_write_file, data = FullNameFile}</c> + <tag><c>#event{name = finished_write_file, data = FullNameFile}</c></tag> + <item> <p><c>FullNameFile = string(), full name of the file.</c></p> - <p>An internal event used by the Common Test Master process to + <p>This internal event is used by the <c>Common Test</c> Master process to synchronize particular file operations. </p></item> - </list> - + </taglist> + </section> + <section> + <title>Notes</title> + <p>The events are also documented in <c>ct_event.erl</c>. This module - may serve as an example of what an event handler for the CT event + can serve as an example of what an event handler for the <c>Common Test</c> event manager can look like.</p> - <note><p>To ensure that printouts to standard out (or printouts made with - <seealso marker="ct#log-2"><c>ct:log/2/3</c></seealso> or <seealso marker="ct:pal-2"><c>ct:pal/2/3</c></seealso>) get written to the test case log - file, and not to the Common Test framework log, you can syncronize - with the Common Test server by matching on the <c>tc_start</c> and <c>tc_done</c> - events. In the period between these events, all IO gets directed to the + <note><p>To ensure that printouts to <c>stdout</c> (or printouts made with + <seealso marker="ct#log-2"><c>ct:log/2,3</c></seealso> or + <seealso marker="ct:pal-2"><c>ct:pal,2,3</c></seealso>) get written to the test case log + file, and not to the <c>Common Test</c> framework log, you can synchronize + with the <c>Common Test</c> server by matching on evvents <c>tc_start</c> and <c>tc_done</c>. + In the period between these events, all I/O is directed to the test case log file. These events are sent synchronously to avoid potential - timing problems (e.g. that the test case log file gets closed just before - an IO message from an external process gets through). Knowing this, you - need to be careful that your <c>handle_event/2</c> callback function doesn't - stall the test execution, possibly causing unexpected behaviour as a result.</p></note> + timing problems (for example, that the test case log file is closed just before + an I/O message from an external process gets through). Knowing this, you + need to be careful that your <c>handle_event/2</c> callback function does not + stall the test execution, possibly causing unexpected behavior as a result.</p></note> + </section> </section> </chapter> diff --git a/lib/common_test/doc/src/example_chapter.xml b/lib/common_test/doc/src/example_chapter.xml index 8201107c04..8523c9f485 100644 --- a/lib/common_test/doc/src/example_chapter.xml +++ b/lib/common_test/doc/src/example_chapter.xml @@ -33,476 +33,472 @@ <marker id="top"></marker> <section> - <title>Test suite example</title> - <p>This example test suite shows some tests of a database server. + <title>Test Suite Example</title> + <p>The following example test suite shows some tests of a database server: </p> <code> --module(db_data_type_SUITE). - --include_lib("common_test/include/ct.hrl"). - -%% Test server callbacks --export([suite/0, all/0, - init_per_suite/1, end_per_suite/1, - init_per_testcase/2, end_per_testcase/2]). - -%% Test cases --export([string/1, integer/1]). - --define(CONNECT_STR, "DSN=sqlserver;UID=alladin;PWD=sesame"). - -%%-------------------------------------------------------------------- -%% COMMON TEST CALLBACK FUNCTIONS -%%-------------------------------------------------------------------- - -%%-------------------------------------------------------------------- -%% Function: suite() -> Info -%% -%% Info = [tuple()] -%% List of key/value pairs. -%% -%% Description: Returns list of tuples to set default properties -%% for the suite. -%%-------------------------------------------------------------------- -suite() -> - [{timetrap,{minutes,1}}]. - -%%-------------------------------------------------------------------- -%% Function: init_per_suite(Config0) -> Config1 -%% -%% Config0 = Config1 = [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% -%% Description: Initialization before the suite. -%%-------------------------------------------------------------------- -init_per_suite(Config) -> - {ok, Ref} = db:connect(?CONNECT_STR, []), - TableName = db_lib:unique_table_name(), - [{con_ref, Ref },{table_name, TableName}| Config]. - -%%-------------------------------------------------------------------- -%% Function: end_per_suite(Config) -> term() -%% -%% Config = [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% -%% Description: Cleanup after the suite. -%%-------------------------------------------------------------------- -end_per_suite(Config) -> - Ref = ?config(con_ref, Config), - db:disconnect(Ref), - ok. + -module(db_data_type_SUITE). + + -include_lib("common_test/include/ct.hrl"). + + %% Test server callbacks + -export([suite/0, all/0, + init_per_suite/1, end_per_suite/1, + init_per_testcase/2, end_per_testcase/2]). + + %% Test cases + -export([string/1, integer/1]). + + -define(CONNECT_STR, "DSN=sqlserver;UID=alladin;PWD=sesame"). + + %%-------------------------------------------------------------------- + %% COMMON TEST CALLBACK FUNCTIONS + %%-------------------------------------------------------------------- + + %%-------------------------------------------------------------------- + %% Function: suite() -> Info + %% + %% Info = [tuple()] + %% List of key/value pairs. + %% + %% Description: Returns list of tuples to set default properties + %% for the suite. + %%-------------------------------------------------------------------- + suite() -> + [{timetrap,{minutes,1}}]. + + %%-------------------------------------------------------------------- + %% Function: init_per_suite(Config0) -> Config1 + %% + %% Config0 = Config1 = [tuple()] + %% A list of key/value pairs, holding the test case configuration. + %% + %% Description: Initialization before the suite. + %%-------------------------------------------------------------------- + init_per_suite(Config) -> + {ok, Ref} = db:connect(?CONNECT_STR, []), + TableName = db_lib:unique_table_name(), + [{con_ref, Ref },{table_name, TableName}| Config]. + + %%-------------------------------------------------------------------- + %% Function: end_per_suite(Config) -> term() + %% + %% Config = [tuple()] + %% A list of key/value pairs, holding the test case configuration. + %% + %% Description: Cleanup after the suite. + %%-------------------------------------------------------------------- + end_per_suite(Config) -> + Ref = ?config(con_ref, Config), + db:disconnect(Ref), + ok. -%%-------------------------------------------------------------------- -%% Function: init_per_testcase(TestCase, Config0) -> Config1 -%% -%% TestCase = atom() -%% Name of the test case that is about to run. -%% Config0 = Config1 = [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% -%% Description: Initialization before each test case. -%%-------------------------------------------------------------------- -init_per_testcase(Case, Config) -> - Ref = ?config(con_ref, Config), - TableName = ?config(table_name, Config), - ok = db:create_table(Ref, TableName, table_type(Case)), - Config. - -%%-------------------------------------------------------------------- -%% Function: end_per_testcase(TestCase, Config) -> term() -%% -%% TestCase = atom() -%% Name of the test case that is finished. -%% Config = [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% -%% Description: Cleanup after each test case. -%%-------------------------------------------------------------------- -end_per_testcase(_Case, Config) -> - Ref = ?config(con_ref, Config), - TableName = ?config(table_name, Config), - ok = db:delete_table(Ref, TableName), - ok. - -%%-------------------------------------------------------------------- -%% Function: all() -> GroupsAndTestCases -%% -%% GroupsAndTestCases = [{group,GroupName} | TestCase] -%% GroupName = atom() -%% Name of a test case group. -%% TestCase = atom() -%% Name of a test case. -%% -%% Description: Returns the list of groups and test cases that -%% are to be executed. -%%-------------------------------------------------------------------- -all() -> - [string, integer]. - - -%%-------------------------------------------------------------------- -%% TEST CASES -%%-------------------------------------------------------------------- - -string(Config) -> - insert_and_lookup(dummy_key, "Dummy string", Config). - -integer(Config) -> - insert_and_lookup(dummy_key, 42, Config). - - -insert_and_lookup(Key, Value, Config) -> - Ref = ?config(con_ref, Config), - TableName = ?config(table_name, Config), - ok = db:insert(Ref, TableName, Key, Value), - [Value] = db:lookup(Ref, TableName, Key), - ok = db:delete(Ref, TableName, Key), - [] = db:lookup(Ref, TableName, Key), - ok. - -</code> + %%-------------------------------------------------------------------- + %% Function: init_per_testcase(TestCase, Config0) -> Config1 + %% + %% TestCase = atom() + %% Name of the test case that is about to run. + %% Config0 = Config1 = [tuple()] + %% A list of key/value pairs, holding the test case configuration. + %% + %% Description: Initialization before each test case. + %%-------------------------------------------------------------------- + init_per_testcase(Case, Config) -> + Ref = ?config(con_ref, Config), + TableName = ?config(table_name, Config), + ok = db:create_table(Ref, TableName, table_type(Case)), + Config. + + %%-------------------------------------------------------------------- + %% Function: end_per_testcase(TestCase, Config) -> term() + %% + %% TestCase = atom() + %% Name of the test case that is finished. + %% Config = [tuple()] + %% A list of key/value pairs, holding the test case configuration. + %% + %% Description: Cleanup after each test case. + %%-------------------------------------------------------------------- + end_per_testcase(_Case, Config) -> + Ref = ?config(con_ref, Config), + TableName = ?config(table_name, Config), + ok = db:delete_table(Ref, TableName), + ok. + + %%-------------------------------------------------------------------- + %% Function: all() -> GroupsAndTestCases + %% + %% GroupsAndTestCases = [{group,GroupName} | TestCase] + %% GroupName = atom() + %% Name of a test case group. + %% TestCase = atom() + %% Name of a test case. + %% + %% Description: Returns the list of groups and test cases that + %% are to be executed. + %%-------------------------------------------------------------------- + all() -> + [string, integer]. + + + %%-------------------------------------------------------------------- + %% TEST CASES + %%-------------------------------------------------------------------- + + string(Config) -> + insert_and_lookup(dummy_key, "Dummy string", Config). + + integer(Config) -> + insert_and_lookup(dummy_key, 42, Config). + + + insert_and_lookup(Key, Value, Config) -> + Ref = ?config(con_ref, Config), + TableName = ?config(table_name, Config), + ok = db:insert(Ref, TableName, Key, Value), + [Value] = db:lookup(Ref, TableName, Key), + ok = db:delete(Ref, TableName, Key), + [] = db:lookup(Ref, TableName, Key), + ok.</code> </section> <section> - <title>Test suite templates</title> - <p>The Erlang mode for the Emacs editor includes two Common Test test suite - templates, one with extensive information in the function headers, and + <title>Test Suite Templates</title> + <p>The Erlang mode for the Emacs editor includes two <c>Common Test</c> test + suite templates, one with extensive information in the function headers, and one with minimal information. A test suite template provides a quick start - for implementing a suite from scratch and gives you a good overview - of the available callback functions. Here are the templates in question: + for implementing a suite from scratch and gives a good overview + of the available callback functions. The two templates follows: </p> - <p><em>Large Common Test suite</em></p> + <p><em>Large Common Test Suite</em></p> <code> -%%%------------------------------------------------------------------- -%%% File : example_SUITE.erl -%%% Author : -%%% Description : -%%% -%%% Created : -%%%------------------------------------------------------------------- --module(example_SUITE). - -%% Note: This directive should only be used in test suites. --compile(export_all). - --include_lib("common_test/include/ct.hrl"). - -%%-------------------------------------------------------------------- -%% COMMON TEST CALLBACK FUNCTIONS -%%-------------------------------------------------------------------- - -%%-------------------------------------------------------------------- -%% Function: suite() -> Info -%% -%% Info = [tuple()] -%% List of key/value pairs. -%% -%% Description: Returns list of tuples to set default properties -%% for the suite. -%% -%% Note: The suite/0 function is only meant to be used to return -%% default data values, not perform any other operations. -%%-------------------------------------------------------------------- -suite() -> - [{timetrap,{minutes,10}}]. - -%%-------------------------------------------------------------------- -%% Function: init_per_suite(Config0) -> -%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} -%% -%% Config0 = Config1 = [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% Reason = term() -%% The reason for skipping the suite. -%% -%% Description: Initialization before the suite. -%% -%% Note: This function is free to add any key/value pairs to the Config -%% variable, but should NOT alter/remove any existing entries. -%%-------------------------------------------------------------------- -init_per_suite(Config) -> - Config. - -%%-------------------------------------------------------------------- -%% Function: end_per_suite(Config0) -> term() | {save_config,Config1} -%% -%% Config0 = Config1 = [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% -%% Description: Cleanup after the suite. -%%-------------------------------------------------------------------- -end_per_suite(_Config) -> - ok. - -%%-------------------------------------------------------------------- -%% Function: init_per_group(GroupName, Config0) -> -%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} -%% -%% GroupName = atom() -%% Name of the test case group that is about to run. -%% Config0 = Config1 = [tuple()] -%% A list of key/value pairs, holding configuration data for the group. -%% Reason = term() -%% The reason for skipping all test cases and subgroups in the group. -%% -%% Description: Initialization before each test case group. -%%-------------------------------------------------------------------- -init_per_group(_GroupName, Config) -> - Config. - -%%-------------------------------------------------------------------- -%% Function: end_per_group(GroupName, Config0) -> -%% term() | {save_config,Config1} -%% -%% GroupName = atom() -%% Name of the test case group that is finished. -%% Config0 = Config1 = [tuple()] -%% A list of key/value pairs, holding configuration data for the group. -%% -%% Description: Cleanup after each test case group. -%%-------------------------------------------------------------------- -end_per_group(_GroupName, _Config) -> - ok. - -%%-------------------------------------------------------------------- -%% Function: init_per_testcase(TestCase, Config0) -> -%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} -%% -%% TestCase = atom() -%% Name of the test case that is about to run. -%% Config0 = Config1 = [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% Reason = term() -%% The reason for skipping the test case. -%% -%% Description: Initialization before each test case. -%% -%% Note: This function is free to add any key/value pairs to the Config -%% variable, but should NOT alter/remove any existing entries. -%%-------------------------------------------------------------------- -init_per_testcase(_TestCase, Config) -> - Config. - -%%-------------------------------------------------------------------- -%% Function: end_per_testcase(TestCase, Config0) -> -%% term() | {save_config,Config1} | {fail,Reason} -%% -%% TestCase = atom() -%% Name of the test case that is finished. -%% Config0 = Config1 = [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% Reason = term() -%% The reason for failing the test case. -%% -%% Description: Cleanup after each test case. -%%-------------------------------------------------------------------- -end_per_testcase(_TestCase, _Config) -> - ok. - -%%-------------------------------------------------------------------- -%% Function: groups() -> [Group] -%% -%% Group = {GroupName,Properties,GroupsAndTestCases} -%% GroupName = atom() -%% The name of the group. -%% Properties = [parallel | sequence | Shuffle | {RepeatType,N}] -%% Group properties that may be combined. -%% GroupsAndTestCases = [Group | {group,GroupName} | TestCase] -%% TestCase = atom() -%% The name of a test case. -%% Shuffle = shuffle | {shuffle,Seed} -%% To get cases executed in random order. -%% Seed = {integer(),integer(),integer()} -%% RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | -%% repeat_until_any_ok | repeat_until_any_fail -%% To get execution of cases repeated. -%% N = integer() | forever -%% -%% Description: Returns a list of test case group definitions. -%%-------------------------------------------------------------------- -groups() -> - []. - -%%-------------------------------------------------------------------- -%% Function: all() -> GroupsAndTestCases | {skip,Reason} -%% -%% GroupsAndTestCases = [{group,GroupName} | TestCase] -%% GroupName = atom() -%% Name of a test case group. -%% TestCase = atom() -%% Name of a test case. -%% Reason = term() -%% The reason for skipping all groups and test cases. -%% -%% Description: Returns the list of groups and test cases that -%% are to be executed. -%%-------------------------------------------------------------------- -all() -> - [my_test_case]. - - -%%-------------------------------------------------------------------- -%% TEST CASES -%%-------------------------------------------------------------------- - -%%-------------------------------------------------------------------- -%% Function: TestCase() -> Info -%% -%% Info = [tuple()] -%% List of key/value pairs. -%% -%% Description: Test case info function - returns list of tuples to set -%% properties for the test case. -%% -%% Note: This function is only meant to be used to return a list of -%% values, not perform any other operations. -%%-------------------------------------------------------------------- -my_test_case() -> - []. - -%%-------------------------------------------------------------------- -%% Function: TestCase(Config0) -> -%% ok | exit() | {skip,Reason} | {comment,Comment} | -%% {save_config,Config1} | {skip_and_save,Reason,Config1} -%% -%% Config0 = Config1 = [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% Reason = term() -%% The reason for skipping the test case. -%% Comment = term() -%% A comment about the test case that will be printed in the html log. -%% -%% Description: Test case function. (The name of it must be specified in -%% the all/0 list or in a test case group for the test case -%% to be executed). -%%-------------------------------------------------------------------- -my_test_case(_Config) -> - ok. -</code> + %%%------------------------------------------------------------------- + %%% File : example_SUITE.erl + %%% Author : + %%% Description : + %%% + %%% Created : + %%%------------------------------------------------------------------- + -module(example_SUITE). + + %% Note: This directive should only be used in test suites. + -compile(export_all). + + -include_lib("common_test/include/ct.hrl"). + + %%-------------------------------------------------------------------- + %% COMMON TEST CALLBACK FUNCTIONS + %%-------------------------------------------------------------------- + + %%-------------------------------------------------------------------- + %% Function: suite() -> Info + %% + %% Info = [tuple()] + %% List of key/value pairs. + %% + %% Description: Returns list of tuples to set default properties + %% for the suite. + %% + %% Note: The suite/0 function is only meant to be used to return + %% default data values, not perform any other operations. + %%-------------------------------------------------------------------- + suite() -> + [{timetrap,{minutes,10}}]. + + %%-------------------------------------------------------------------- + %% Function: init_per_suite(Config0) -> + %% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} + %% + %% Config0 = Config1 = [tuple()] + %% A list of key/value pairs, holding the test case configuration. + %% Reason = term() + %% The reason for skipping the suite. + %% + %% Description: Initialization before the suite. + %% + %% Note: This function is free to add any key/value pairs to the Config + %% variable, but should NOT alter/remove any existing entries. + %%-------------------------------------------------------------------- + init_per_suite(Config) -> + Config. + + %%-------------------------------------------------------------------- + %% Function: end_per_suite(Config0) -> term() | {save_config,Config1} + %% + %% Config0 = Config1 = [tuple()] + %% A list of key/value pairs, holding the test case configuration. + %% + %% Description: Cleanup after the suite. + %%-------------------------------------------------------------------- + end_per_suite(_Config) -> + ok. + + %%-------------------------------------------------------------------- + %% Function: init_per_group(GroupName, Config0) -> + %% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} + %% + %% GroupName = atom() + %% Name of the test case group that is about to run. + %% Config0 = Config1 = [tuple()] + %% A list of key/value pairs, holding configuration data for the group. + %% Reason = term() + %% The reason for skipping all test cases and subgroups in the group. + %% + %% Description: Initialization before each test case group. + %%-------------------------------------------------------------------- + init_per_group(_GroupName, Config) -> + Config. + + %%-------------------------------------------------------------------- + %% Function: end_per_group(GroupName, Config0) -> + %% term() | {save_config,Config1} + %% + %% GroupName = atom() + %% Name of the test case group that is finished. + %% Config0 = Config1 = [tuple()] + %% A list of key/value pairs, holding configuration data for the group. + %% + %% Description: Cleanup after each test case group. + %%-------------------------------------------------------------------- + end_per_group(_GroupName, _Config) -> + ok. + + %%-------------------------------------------------------------------- + %% Function: init_per_testcase(TestCase, Config0) -> + %% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} + %% + %% TestCase = atom() + %% Name of the test case that is about to run. + %% Config0 = Config1 = [tuple()] + %% A list of key/value pairs, holding the test case configuration. + %% Reason = term() + %% The reason for skipping the test case. + %% + %% Description: Initialization before each test case. + %% + %% Note: This function is free to add any key/value pairs to the Config + %% variable, but should NOT alter/remove any existing entries. + %%-------------------------------------------------------------------- + init_per_testcase(_TestCase, Config) -> + Config. + + %%-------------------------------------------------------------------- + %% Function: end_per_testcase(TestCase, Config0) -> + %% term() | {save_config,Config1} | {fail,Reason} + %% + %% TestCase = atom() + %% Name of the test case that is finished. + %% Config0 = Config1 = [tuple()] + %% A list of key/value pairs, holding the test case configuration. + %% Reason = term() + %% The reason for failing the test case. + %% + %% Description: Cleanup after each test case. + %%-------------------------------------------------------------------- + end_per_testcase(_TestCase, _Config) -> + ok. + + %%-------------------------------------------------------------------- + %% Function: groups() -> [Group] + %% + %% Group = {GroupName,Properties,GroupsAndTestCases} + %% GroupName = atom() + %% The name of the group. + %% Properties = [parallel | sequence | Shuffle | {RepeatType,N}] + %% Group properties that may be combined. + %% GroupsAndTestCases = [Group | {group,GroupName} | TestCase] + %% TestCase = atom() + %% The name of a test case. + %% Shuffle = shuffle | {shuffle,Seed} + %% To get cases executed in random order. + %% Seed = {integer(),integer(),integer()} + %% RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | + %% repeat_until_any_ok | repeat_until_any_fail + %% To get execution of cases repeated. + %% N = integer() | forever + %% + %% Description: Returns a list of test case group definitions. + %%-------------------------------------------------------------------- + groups() -> + []. + + %%-------------------------------------------------------------------- + %% Function: all() -> GroupsAndTestCases | {skip,Reason} + %% + %% GroupsAndTestCases = [{group,GroupName} | TestCase] + %% GroupName = atom() + %% Name of a test case group. + %% TestCase = atom() + %% Name of a test case. + %% Reason = term() + %% The reason for skipping all groups and test cases. + %% + %% Description: Returns the list of groups and test cases that + %% are to be executed. + %%-------------------------------------------------------------------- + all() -> + [my_test_case]. + + + %%-------------------------------------------------------------------- + %% TEST CASES + %%-------------------------------------------------------------------- + + %%-------------------------------------------------------------------- + %% Function: TestCase() -> Info + %% + %% Info = [tuple()] + %% List of key/value pairs. + %% + %% Description: Test case info function - returns list of tuples to set + %% properties for the test case. + %% + %% Note: This function is only meant to be used to return a list of + %% values, not perform any other operations. + %%-------------------------------------------------------------------- + my_test_case() -> + []. + + %%-------------------------------------------------------------------- + %% Function: TestCase(Config0) -> + %% ok | exit() | {skip,Reason} | {comment,Comment} | + %% {save_config,Config1} | {skip_and_save,Reason,Config1} + %% + %% Config0 = Config1 = [tuple()] + %% A list of key/value pairs, holding the test case configuration. + %% Reason = term() + %% The reason for skipping the test case. + %% Comment = term() + %% A comment about the test case that will be printed in the html log. + %% + %% Description: Test case function. (The name of it must be specified in + %% the all/0 list or in a test case group for the test case + %% to be executed). + %%-------------------------------------------------------------------- + my_test_case(_Config) -> + ok.</code> <br></br> - <p><em>Small Common Test suite</em></p> + <p><em>Small Common Test Suite</em></p> <code> -%%%------------------------------------------------------------------- -%%% File : example_SUITE.erl -%%% Author : -%%% Description : -%%% -%%% Created : -%%%------------------------------------------------------------------- --module(example_SUITE). - --compile(export_all). - --include_lib("common_test/include/ct.hrl"). - -%%-------------------------------------------------------------------- -%% Function: suite() -> Info -%% Info = [tuple()] -%%-------------------------------------------------------------------- -suite() -> - [{timetrap,{seconds,30}}]. - -%%-------------------------------------------------------------------- -%% Function: init_per_suite(Config0) -> -%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} -%% Config0 = Config1 = [tuple()] -%% Reason = term() -%%-------------------------------------------------------------------- -init_per_suite(Config) -> - Config. - -%%-------------------------------------------------------------------- -%% Function: end_per_suite(Config0) -> term() | {save_config,Config1} -%% Config0 = Config1 = [tuple()] -%%-------------------------------------------------------------------- -end_per_suite(_Config) -> - ok. - -%%-------------------------------------------------------------------- -%% Function: init_per_group(GroupName, Config0) -> -%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} -%% GroupName = atom() -%% Config0 = Config1 = [tuple()] -%% Reason = term() -%%-------------------------------------------------------------------- -init_per_group(_GroupName, Config) -> - Config. - -%%-------------------------------------------------------------------- -%% Function: end_per_group(GroupName, Config0) -> -%% term() | {save_config,Config1} -%% GroupName = atom() -%% Config0 = Config1 = [tuple()] -%%-------------------------------------------------------------------- -end_per_group(_GroupName, _Config) -> - ok. - -%%-------------------------------------------------------------------- -%% Function: init_per_testcase(TestCase, Config0) -> -%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} -%% TestCase = atom() -%% Config0 = Config1 = [tuple()] -%% Reason = term() -%%-------------------------------------------------------------------- -init_per_testcase(_TestCase, Config) -> - Config. - -%%-------------------------------------------------------------------- -%% Function: end_per_testcase(TestCase, Config0) -> -%% term() | {save_config,Config1} | {fail,Reason} -%% TestCase = atom() -%% Config0 = Config1 = [tuple()] -%% Reason = term() -%%-------------------------------------------------------------------- -end_per_testcase(_TestCase, _Config) -> - ok. - -%%-------------------------------------------------------------------- -%% Function: groups() -> [Group] -%% Group = {GroupName,Properties,GroupsAndTestCases} -%% GroupName = atom() -%% Properties = [parallel | sequence | Shuffle | {RepeatType,N}] -%% GroupsAndTestCases = [Group | {group,GroupName} | TestCase] -%% TestCase = atom() -%% Shuffle = shuffle | {shuffle,{integer(),integer(),integer()}} -%% RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | -%% repeat_until_any_ok | repeat_until_any_fail -%% N = integer() | forever -%%-------------------------------------------------------------------- -groups() -> - []. - -%%-------------------------------------------------------------------- -%% Function: all() -> GroupsAndTestCases | {skip,Reason} -%% GroupsAndTestCases = [{group,GroupName} | TestCase] -%% GroupName = atom() -%% TestCase = atom() -%% Reason = term() -%%-------------------------------------------------------------------- -all() -> - [my_test_case]. - -%%-------------------------------------------------------------------- -%% Function: TestCase() -> Info -%% Info = [tuple()] -%%-------------------------------------------------------------------- -my_test_case() -> - []. - -%%-------------------------------------------------------------------- -%% Function: TestCase(Config0) -> -%% ok | exit() | {skip,Reason} | {comment,Comment} | -%% {save_config,Config1} | {skip_and_save,Reason,Config1} -%% Config0 = Config1 = [tuple()] -%% Reason = term() -%% Comment = term() -%%-------------------------------------------------------------------- -my_test_case(_Config) -> - ok. -</code> + %%%------------------------------------------------------------------- + %%% File : example_SUITE.erl + %%% Author : + %%% Description : + %%% + %%% Created : + %%%------------------------------------------------------------------- + -module(example_SUITE). + + -compile(export_all). + + -include_lib("common_test/include/ct.hrl"). + + %%-------------------------------------------------------------------- + %% Function: suite() -> Info + %% Info = [tuple()] + %%-------------------------------------------------------------------- + suite() -> + [{timetrap,{seconds,30}}]. + + %%-------------------------------------------------------------------- + %% Function: init_per_suite(Config0) -> + %% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} + %% Config0 = Config1 = [tuple()] + %% Reason = term() + %%-------------------------------------------------------------------- + init_per_suite(Config) -> + Config. + + %%-------------------------------------------------------------------- + %% Function: end_per_suite(Config0) -> term() | {save_config,Config1} + %% Config0 = Config1 = [tuple()] + %%-------------------------------------------------------------------- + end_per_suite(_Config) -> + ok. + + %%-------------------------------------------------------------------- + %% Function: init_per_group(GroupName, Config0) -> + %% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} + %% GroupName = atom() + %% Config0 = Config1 = [tuple()] + %% Reason = term() + %%-------------------------------------------------------------------- + init_per_group(_GroupName, Config) -> + Config. + + %%-------------------------------------------------------------------- + %% Function: end_per_group(GroupName, Config0) -> + %% term() | {save_config,Config1} + %% GroupName = atom() + %% Config0 = Config1 = [tuple()] + %%-------------------------------------------------------------------- + end_per_group(_GroupName, _Config) -> + ok. + + %%-------------------------------------------------------------------- + %% Function: init_per_testcase(TestCase, Config0) -> + %% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} + %% TestCase = atom() + %% Config0 = Config1 = [tuple()] + %% Reason = term() + %%-------------------------------------------------------------------- + init_per_testcase(_TestCase, Config) -> + Config. + + %%-------------------------------------------------------------------- + %% Function: end_per_testcase(TestCase, Config0) -> + %% term() | {save_config,Config1} | {fail,Reason} + %% TestCase = atom() + %% Config0 = Config1 = [tuple()] + %% Reason = term() + %%-------------------------------------------------------------------- + end_per_testcase(_TestCase, _Config) -> + ok. + + %%-------------------------------------------------------------------- + %% Function: groups() -> [Group] + %% Group = {GroupName,Properties,GroupsAndTestCases} + %% GroupName = atom() + %% Properties = [parallel | sequence | Shuffle | {RepeatType,N}] + %% GroupsAndTestCases = [Group | {group,GroupName} | TestCase] + %% TestCase = atom() + %% Shuffle = shuffle | {shuffle,{integer(),integer(),integer()}} + %% RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | + %% repeat_until_any_ok | repeat_until_any_fail + %% N = integer() | forever + %%-------------------------------------------------------------------- + groups() -> + []. + + %%-------------------------------------------------------------------- + %% Function: all() -> GroupsAndTestCases | {skip,Reason} + %% GroupsAndTestCases = [{group,GroupName} | TestCase] + %% GroupName = atom() + %% TestCase = atom() + %% Reason = term() + %%-------------------------------------------------------------------- + all() -> + [my_test_case]. + + %%-------------------------------------------------------------------- + %% Function: TestCase() -> Info + %% Info = [tuple()] + %%-------------------------------------------------------------------- + my_test_case() -> + []. + + %%-------------------------------------------------------------------- + %% Function: TestCase(Config0) -> + %% ok | exit() | {skip,Reason} | {comment,Comment} | + %% {save_config,Config1} | {skip_and_save,Reason,Config1} + %% Config0 = Config1 = [tuple()] + %% Reason = term() + %% Comment = term() + %%-------------------------------------------------------------------- + my_test_case(_Config) -> + ok.</code> </section> </chapter> diff --git a/lib/common_test/doc/src/getting_started_chapter.xml b/lib/common_test/doc/src/getting_started_chapter.xml index ef9c409bf1..802f9ba397 100644 --- a/lib/common_test/doc/src/getting_started_chapter.xml +++ b/lib/common_test/doc/src/getting_started_chapter.xml @@ -31,235 +31,247 @@ </header> <section> - <title>Are you new around here?</title> + <title>Introduction for Newcomers</title> <p> - The purpose of this short chapter is to, with a "learning by example" - approach, give the newcomer a chance to get started quickly writing and - executing some first simple tests. The chapter will introduce some of the - basics, but leave most explanations and details for the later - chapters in this User's Guide. Hopefully though, after this chapter, you - will be inspired and unintimidated enough to go on and get into the - nitty-gritty that follows in this rather heavy User's Guide! If you're - not much into "learning by example" and prefer to get into more technical - detail right away, go ahead and skip to the next chapter. Again, the basics - presented here will be covered in detail in later chapters. + The purpose of this section is to let the newcomer get started in + quickly writing and executing some first simple tests with a + "learning by example" approach. Most explanations are left for later sections. + If you are not much into "learning by example" and prefer more technical + details, go ahead and skip to the next section. </p> <p> - This chapter also tries to demonstrate how dead simple it actually is - to write a very basic (yet for many module testing purposes, often sufficiently - complex) test suite, and execute its test cases. This is not necessarily - obvious when you read the rest of the chapters in the User's Guide. - </p> - <p> - A quick note before we start: In order to understand what's discussed and - examplified here, it is recommended that you first read through the - opening <seealso marker="basics_chapter#basics">Common Test Basics</seealso> - chapter. + This section demonstrates how simple it is to write a basic + (yet for many module testing purposes, often sufficiently complex) + test suite and execute its test cases. This is not necessarily + obvious when you read the remaining sections in this User's Guide. </p> + <note> + <p> + To understand what is discussed and examplified here, we recommended + you to first read section + <seealso marker="basics_chapter#basics">Common Test Basics</seealso>. + </p> + </note> </section> <section> - <title>Test case execution</title> - <p>Execution of test cases is handled this way:</p> + <title>Test Case Execution</title> + <p>Execution of test cases is handled as follows:</p> <image file="tc_execution.gif"> <icaption> - Successful vs unsuccessful test case execution. + Successful and Unsuccessful Test Case Execution </icaption> </image> - <p>For each test case that Common Test is told to execute, it spawns a - dedicated process on which the test case function in question starts + <p>For each test case that <c>Common Test</c> is ordered to execute, it spawns a + dedicated process on which the test case function starts running. (In parallel to the test case process, an idle waiting timer - process is started which is linked to the test case process. If the timer + process is started, which is linked to the test case process. If the timer process runs out of waiting time, it sends an exit signal to terminate - the test case process and this is what's called a <em>timetrap</em>). + the test case process. This is called a <em>timetrap</em>). </p> - <p>In scenario 1, the test case process terminates normally after case A has - finished executing its test code without detecting any errors. The test - case function simply returns a value and Common Test logs the test case as - successful. + <p>In scenario 1, the test case process terminates normally after + <c>case A</c> has finished executing its test code without detecting + any errors. The test case function returns a value and <c>Common Test</c> + logs the test case as successful. </p> - <p>In scenario 2, an error is detected during test case execution - which causes the test case B function to generate an exception. - This causes the test case process to exit with reason - other than normal, and as a result, Common Test will log this as an - unsuccessful test case. + <p>In scenario 2, an error is detected during test <c>case B</c> execution. + This causes the test <c>case B</c> function to generate an exception + and, as a result, the test case process exits with reason other than normal. + <c>Common Test</c> logs this as an unsuccessful (Failed) test case. </p> - <p>As you can understand from the illustration above, Common Test requires - that a test case generates a runtime error to indicate failure (e.g. - by causing a bad match error or by calling <c>exit/1</c>, preferrably - through the <seealso marker="ct#fail-1"><c>ct:fail/1,2</c></seealso> help function). A succesful execution is - indicated by means of a normal return from the test case function. + <p>As you can understand from the illustration, <c>Common Test</c> requires + a test case to generate a runtime error to indicate failure (for example, + by causing a bad match error or by calling <c>exit/1</c>, preferably + through the help function + <seealso marker="ct#fail-1"><c>ct:fail/1,2</c></seealso>). A successful + execution is indicated by a normal return from the test case function. </p> </section> <section> - <title>A simple test suite</title> - <p>As you've seen in the basics chapter, the test suite module implements + <title>A Simple Test Suite</title> + <p>As shown in section + <seealso marker="basics_chapter#External_Interfaces">Common Test Basics</seealso>, + the test suite module implements <seealso marker="common_test">callback functions</seealso> - (mandatory or optional) for various purposes, e.g: + (mandatory or optional) for various purposes, for example: </p> - <list> + <list type="bulleted"> <item>Init/end configuration function for the test suite</item> <item>Init/end configuration function for a test case</item> <item>Init/end configuration function for a test case group</item> <item>Test cases</item> </list> <p> - The configuration functions are optional and if you don't need them for - your test, a test suite with one simple test case could look like this: + The configuration functions are optional. The following example is a test suite + without configuration functions, including one simple test case, to + check that module <c>mymod</c> exists (that is, can be successfully loaded by the + code server): </p> <pre> - -module(my1st_SUITE). - -compile(export_all). + -module(my1st_SUITE). + -compile(export_all). - all() -> - [mod_exists]. + all() -> + [mod_exists]. - mod_exists(_) -> - {module,mymod} = code:load_file(mymod).</pre> + mod_exists(_) -> + {module,mymod} = code:load_file(mymod).</pre> <p> - In this example we check that the <c>mymod</c> module exists (i.e. can be - successfully loaded by the code server). If the operation fails, we will - get a bad match error which terminates the test case. + If the operation fails, a bad match error occurs that terminates the test case. </p> </section> <section> - <title>A test suite with configuration functions</title> + <title>A Test Suite with Configuration Functions</title> <p> - If we need to perform configuration operations in order to run our test, we - implement configuration functions in our suite. The result from a - configuration function is configuration data, or simply <em><c>Config</c></em>. - This is a list of key-value tuples which get passed from the configuration + If you need to perform configuration operations to run your test, you can + implement configuration functions in your suite. The result from a + configuration function is configuration data, or <c>Config</c>. + This is a list of key-value tuples that get passed from the configuration function to the test cases (possibly through configuration functions on - "lower level"). The data flow looks like this: + "lower level"). The data flow looks as follows: </p> <image file="config.gif"> <icaption> - Config data flow in the suite. + Configuration Data Flow in a Suite </icaption> </image> <p> - Here's an example of a test suite which uses configuration functions - to open and close a log file for the test cases (an operation that would - be unnecessary and irrelevant to perform by each test case): + The following example shows a test suite that uses configuration functions + to open and close a log file for the test cases (an operation that is + unnecessary and irrelevant to perform by each test case): </p> <pre> - -module(check_log_SUITE). - -export([all/0, init_per_suite/1, end_per_suite/1]). - -export([check_restart_result/1, check_no_errors/1]). - - -define(value(Key,Config), proplists:get_value(Key,Config)). + -module(check_log_SUITE). + -export([all/0, init_per_suite/1, end_per_suite/1]). + -export([check_restart_result/1, check_no_errors/1]). - all() -> [check_restart_result, check_no_errors]. + -define(value(Key,Config), proplists:get_value(Key,Config)). - init_per_suite(InitConfigData) -> - [{logref,open_log()} | InitConfigData]. + all() -> [check_restart_result, check_no_errors]. - end_per_suite(ConfigData) -> - close_log(?value(logref, ConfigData)). + init_per_suite(InitConfigData) -> + [{logref,open_log()} | InitConfigData]. - check_restart_result(ConfigData) -> - TestData = read_log(restart, ?value(logref, ConfigData)), - {match,_Line} = search_for("restart successful", TestData). - - check_no_errors(ConfigData) -> - TestData = read_log(all, ?value(logref, ConfigData)), - case search_for("error", TestData) of - {match,Line} -> ct:fail({error_found_in_log,Line}); - nomatch -> ok - end.</pre> + end_per_suite(ConfigData) -> + close_log(?value(logref, ConfigData)). + + check_restart_result(ConfigData) -> + TestData = read_log(restart, ?value(logref, ConfigData)), + {match,_Line} = search_for("restart successful", TestData). + + check_no_errors(ConfigData) -> + TestData = read_log(all, ?value(logref, ConfigData)), + case search_for("error", TestData) of + {match,Line} -> ct:fail({error_found_in_log,Line}); + nomatch -> ok + end.</pre> <p> - In this example we have test cases that verify, by parsing a - log file, that our SUT has performed a successful restart and - that no unexpected errors have been printed. + The test cases verify, by parsing a log file, that our SUT has performed + a successful restart and that no unexpected errors are printed. </p> - <p>To execute the test cases in the test suite above, we could type this on - the Unix/Linux command line (assuming for this example that the suite module + <p>To execute the test cases in the recent test suite, type the + following on the UNIX/Linux command line (assuming that the suite module is in the current working directory): </p> <pre> - $ ct_run -dir .</pre> - <p>or</p> + $ ct_run -dir .</pre> + <p>or:</p> <pre> - $ ct_run -suite check_log_SUITE</pre> + $ ct_run -suite check_log_SUITE</pre> - <p>If we want to use the Erlang shell to run our test, we could evaluate this call: + <p>To use the Erlang shell to run our test, you can evaluate the following call: </p> <pre> - 1> ct:run_test([{dir, "."}]).</pre> - <p>or</p> + 1> ct:run_test([{dir, "."}]).</pre> + <p>or:</p> <pre> - 1> ct:run_test([{suite, "check_log_SUITE"}]).</pre> + 1> ct:run_test([{suite, "check_log_SUITE"}]).</pre> <p> - The result from running our test is printed in log files in HTML format - (stored in unique log directories on different level). This illustration - shows the log file structure: + The result from running the test is printed in log files in HTML format + (stored in unique log directories on a different level). The following + illustration shows the log file structure: </p> <image file="html_logs.gif"> <icaption> - HTML log file structure. + HTML Log File Structure </icaption> </image> </section> <section> - <title>What happens next?</title> + <title>Questions and Answers</title> - <p>Well, you might already be asking yourself questions such as:</p> + <p>Here follows some questions that you might have after reading this section + with corresponding tips and links to the answers: + </p> - <list> - <item>"How and where can I specify variable data for my tests that mustn't - be hard-coded in the test suites (such as host names, addresses, - user login data, etc)?" The - <seealso marker="config_file_chapter#top">External Configuration Data</seealso> - chapter will give you that information. + <list type="bulleted"> + <item><p><em>Question:</em> + "How and where can I specify variable data for my tests that must not + be hard-coded in the test suites (such as hostnames, addresses, and + user login data)?"</p> + <p><em>Answer:</em> + See section <seealso marker="config_file_chapter#top">External Configuration Data</seealso>.</p> </item> - <item>"Is there a way to declare a number of different tests and run them - in one session without having to write my own scripts? And can such - declarations be used for regression testing?" The + + <item><p><em>Question:</em> "Is there a way to declare different tests and run them + in one session without having to write my own scripts? Also, can such + declarations be used for regression testing?"</p> + <p><em>Answer:</em> See section <seealso marker="run_test_chapter#test_specifications">Test Specifications</seealso> - chapter answers these questions. + in section Running Tests and Analyzing Results. + </p> </item> - <item>"Can test cases and/or test runs be automatically repeated?" Learn more about + + <item><p><em>Question:</em> "Can test cases and/or test runs be automatically repeated?"</p> + <p><em>Answer:</em> Learn more about <seealso marker="write_test_chapter#test_case_groups">Test Case Groups</seealso> - and also read about start flags/options in the - <seealso marker="run_test_chapter#ct_run">Running Tests</seealso> chapter and - the Reference Manual. + and read about start flags/options in section + <seealso marker="run_test_chapter#ct_run">Running Tests</seealso> and in + the Reference Manual.</p> </item> - <item>"Will Common Test execute my test cases in sequence or in parallel?" The + + <item><p><em>Question:</em> "Does <c>Common Test</c> execute my test cases in sequence or in parallel?"</p> + <p><em>Answer:</em> See <seealso marker="write_test_chapter#test_case_groups">Test Case Groups</seealso> - section in the Running Tests chapter will give you the answer. + in section Writing Test Suites.</p> </item> - <item>"What's the syntax for timetraps (mentioned above), and how do I set them?" - This is explained in the - <seealso marker="write_test_chapter#timetraps">Timetrap Timeouts</seealso> - part of the Writing Test Suites chapter. + + <item><p><em>Question:</em> "What is the syntax for timetraps (mentioned earlier), and how do I set them?"</p> + <p><em>Answer:</em> This is explained in the + <seealso marker="write_test_chapter#timetraps">Timetrap Time-Outs</seealso> + part of section Writing Test Suites.</p> </item> - <item>"What functions are available for logging and printing?" Check the + + <item><p><em>Question:</em> "What functions are available for logging and printing?"</p> + <p><em>Answer:</em> See <seealso marker="write_test_chapter#logging">Logging</seealso> - section in the Writing Test Suites chapter. + in section Writing Test Suites.</p> </item> - <item>"I need data files for my tests. Where do I store them preferrably?" - You should read about + + <item><p><em>Question:</em> "I need data files for my tests. Where do I store them preferably?"</p> + <p><em>Answer:</em> See <seealso marker="write_test_chapter#data_priv_dir">Data and Private - Directories</seealso> for information about this. + Directories</seealso>.</p> </item> - <item>"May I start with a test suite example, please?" - <seealso marker="example_chapter#top">Sure!</seealso> + + <item><p><em>Question:</em> "Can I start with a test suite example, please?"</p> + <p><em>Answer:</em> <seealso marker="example_chapter#top">Welcome!</seealso></p> </item> </list> - <p>You will probably want to get started on your own first test suites now, while - at the same time digging deeper into the Common Test User's Guide and Reference Manual. - You will find that there's lots more to learn about the things that have been introduced - in this chapter. You will of course also be presented many more useful features, such as the - ones listed above. Have fun! + <p>You probably want to get started on your own first test suites now, while + at the same time digging deeper into the <c>Common Test</c> User's Guide and Reference Manual. + There are much more to learn about the things that have been introduced + in this section. There are also many other useful features to learn, + so please continue to the other sections and have fun. </p> </section> </chapter> diff --git a/lib/common_test/doc/src/install_chapter.xml b/lib/common_test/doc/src/install_chapter.xml index 107b0e2eac..9dce1e31a4 100644 --- a/lib/common_test/doc/src/install_chapter.xml +++ b/lib/common_test/doc/src/install_chapter.xml @@ -32,22 +32,23 @@ <section> <marker id="general"></marker> - <title>General information</title> - - <p>The two main interfaces for running tests with Common Test - are an executable program named <c>ct_run</c> 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 + <title>General Information</title> + + <p>The two main interfaces for running tests with <c>Common Test</c> + are an executable program named + <seealso marker="ct_run"><c>ct_run</c></seealso> and the + Erlang module <seealso marker="ct"><c>ct</c></seealso>. + <c>ct_run</c> is compiled for the underlying operating system (for example, + Unix/Linux or Windows) during the build of the Erlang/OTP system, + and is installed automatically with other executable programs in the top level <c>bin</c> directory of Erlang/OTP. The <c>ct</c> interface functions can be called from the Erlang shell, or from any Erlang function, on any supported platform.</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 <c>ct_run</c> executable program, and/or - the interface functions in the <c>ct</c> module.</p> + <p>The <c>Common Test</c> application is installed with the Erlang/OTP + system. No extra installation step is required to start using + <c>Common Test</c> through the <c>ct_run</c> executable program, + and/or the interface functions in the <c>ct</c> module.</p> </section> </chapter> diff --git a/lib/common_test/doc/src/introduction.xml b/lib/common_test/doc/src/introduction.xml new file mode 100644 index 0000000000..e2a42bfd33 --- /dev/null +++ b/lib/common_test/doc/src/introduction.xml @@ -0,0 +1,75 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2013</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + </legalnotice> + + <title>Introduction</title> + <prepared></prepared> + <docno></docno> + <date>2015-10-05</date> + <rev></rev> + <file>introduction.xml</file> + </header> + <section> + <title>Scope</title> + <p><c>Common Test</c> is a portable application for automated + testing. It is suitable for:</p> + <list type="bulleted"> + <item><p>Black-box testing of target systems of any type (that + is, not necessarily implemented in Erlang). This is performed + through standard O&M interfaces (such as SNMP, HTTP, CORBA, + and Telnet) and, if necessary, through user-specific interfaces + (often called test ports).</p></item> + <item><p>White-box testing of Erlang/OTP programs. This is easily + done by calling the target API functions directly from the test + case functions.</p></item> + </list> + <p><c>Common Test</c> also integrates use of the OTP + <seealso marker="tools:cover">cover</seealso> tool in application + <c>Tools</c> for code coverage analysis of Erlang/OTP programs.</p> + + <p><c>Common Test</c> executes test suite programs automatically, + without operator interaction. Test progress and results are + printed to logs in HTML format, easily browsed with a standard + web browser. <c>Common Test</c> also sends notifications about progress + and results through an OTP event manager to event handlers plugged + in to the system. This way, users can integrate their own + programs for, for example, logging, database storing, or supervision with + <c>Common Test</c>.</p> + + <p><c>Common Test</c> provides libraries with useful support + functions to fill various testing needs and requirements. + There is, for example, support for flexible test declarations + through test specifications. There is also support + for central configuration and control of multiple + independent test sessions (to different target systems) + running in parallel.</p> + + </section> + + <section> + <title>Prerequisites</title> + <p>It is assumed that the reader is familiar with the Erlang + programming language.</p > + </section> + +</chapter> diff --git a/lib/common_test/doc/src/notes.xml b/lib/common_test/doc/src/notes.xml index aaf6dffc88..8e85563d9a 100644 --- a/lib/common_test/doc/src/notes.xml +++ b/lib/common_test/doc/src/notes.xml @@ -33,6 +33,251 @@ <file>notes.xml</file> </header> +<section><title>Common_Test 1.12.1.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + If the telnet server would pause during transmission of a + line of text before terminating the line, the + ct_telnet:expect/3 function would print the line twice in + the test case HTML log. This problem has been fixed.</p> + <p> + Own Id: OTP-13730 Aux Id: seq13135 </p> + </item> + </list> + </section> + +</section> + +<section><title>Common_Test 1.12.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The <c>nodelay</c> option used to be enabled + (<c>true</c>) by default for sockets opened by the Common + Test telnet client. This appeared to cause communication + problems with telnet servers on some systems, and + therefore the option is no longer used. Its value may + instead be specified in the telnet connection settings. + See the man page for <c>ct_telnet</c> for details. Please + note that the interface function <c>connect</c> in + <c>unix_telnet</c> has been updated with an extra + argument and is now <c>unix_telnet:connect/7</c>.</p> + <p> + Own Id: OTP-13462 Aux Id: seq13077 </p> + </item> + <item> + <p> + Fix bug in cth_surefire: When a pre_init_per_suite hook + fails before reaching the + cth_surefire:pre_init_per_suite, cth_surefire produced + incorrect XML.</p> + <p> + Own Id: OTP-13513</p> + </item> + <item> + <p> + The <c>ct:get_timetrap_info/0</c> function has been + updated to return more information about timetrap + scaling.</p> + <p> + Own Id: OTP-13535</p> + </item> + <item> + <p> + A problem with stylesheet HTML tags getting incorrectly + escaped by Common Test has been corrected.</p> + <p> + Own Id: OTP-13536</p> + </item> + <item> + <p> + The <c>ct_run</c> start flag <c>-no_esc_chars</c> and + <c>ct:run_test/1</c> start option <c>{esc_chars,Bool}</c> + have been introduced to make it possible to disable + automatic escaping of characters. Automatic escaping of + special HTML characters printed with <c>io:format/1,2</c> + and <c>ct:pal/1,2,3,4</c> was introduced in Common Test + 1.12. The new flag/option may be used to disable this + feature for backwards compatibility reasons. (The option + is also supported in test specifications).</p> + <p> + Own Id: OTP-13537</p> + </item> + </list> + </section> + +</section> + +<section><title>Common_Test 1.12</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + This update fixes the problem with generic printouts in + the html log file not having special characters escaped. + Printouts made with <c>io:format/2</c> and + <c>ct:pal/2</c> will now get special characters escaped + automatically. Common Test will not attempt to escape + characters printed with <c>ct:log/2</c> since it is + assumed that the user may want to print html tagged data + using this function. A new function, <c>ct:log/5</c>, has + been added, which offers optional escaping of characters. + The latter function may also be used to print text to the + log without headers and CSS class wrapping (analogue to + <c>io:format/2</c>).</p> + <p> + Own Id: OTP-13003 Aux Id: seq13005 </p> + </item> + <item> + <p> + Commit 4cf832f1ad163f5b25dd8a6f2d314c169c23c82f + erroneously removed logging of open and close of netconf + connections. This is now corrected.</p> + <p> + Own Id: OTP-13386</p> + </item> + <item> + <p> + The directory to which nodes started with + <c>test_server:start_node/3</c> writes their + erl_crash.dump is changed. The crashdumps were earlier + written to the directory of test_server.beam, but in + later versions of Microsoft Windows this is no longer + writable (even for administrators). The framework + (common_test) log directory is now used instead.</p> + <p> + Own Id: OTP-13388</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + This update makes it possible to specify multiple + instances of the same group or test case in one test + specification term in order to repeat execution. Example: + <c>{groups, "./", my_SUITE, [my_group, my_group], {cases, + all}}, or {cases, "./", my_SUITE, [my_tc, my_tc, + my_tc]}.</c></p> + <p> + Own Id: OTP-13241 Aux Id: seq12979 </p> + </item> + <item> + <p> + Two new CT hook functions have been added: + <c>post_init_per_testcase/4</c> and + <c>pre_end_per_testcase/3</c>. With these hook functions, + it is possible to perform arbitrary actions (including + modifications of test execution, test state and results) + immediately before and after the execution of the test + case.</p> + <p> + Own Id: OTP-13242 Aux Id: seq12991 </p> + </item> + <item> + <p> + The <c>ct_netconfc</c> was earlier very restrictive as to + which SSH options the user could set. This is now + changed, and any SSH option is now allowed. The netconf + client will simply pass on any option, which it does not + recognize, to SSH.</p> + <p> + Own Id: OTP-13338 Aux Id: seq13053,seq13069 </p> + </item> + </list> + </section> + +</section> + +<section><title>Common_Test 1.11.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + If a ssh package contained more than one netconf end tag, + then the second end tag was never detected in + ct_netconfc:handle_data. Instead it was included in the + XML data given to the xmerl parser, which then failed. + The problem was introduced by OTP-13007, and has now been + corrected.</p> + <p> + Own Id: OTP-13323</p> + </item> + </list> + </section> + +</section> + +<section><title>Common_Test 1.11.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + When data from the netconf server was split into many ssh + packages, the netconf client performed really bad. This + is now improved.</p> + <p> + Own Id: OTP-13007</p> + </item> + <item> + <p> + In ct_netconfc, if a timer expired 'at the same time' as + the server sent the rpc-reply, the timeout message might + already be in the client's message queue when the client + removed the timer ref from its 'pending' list. This + caused a crash in the client since the timer ref could no + longer be found when handling the timeout message. This + problem is now fixed by always flushing the timeout + message from the message queue when canceling a timer.</p> + <p> + Own Id: OTP-13008</p> + </item> + <item> + <p> + The error logger handler ct_conn_log_h did not respect + the 'silent' option, and tried to print to an undefined + file descriptor. This has been corrected.</p> + <p> + Own Id: OTP-13035</p> + </item> + <item> + <p> + If the user would let the test run proceed after test + suite compilation failure, Common Test did not set the + exit status to indicate failure as expected. This has + been corrected. Also, the 'abort_if_missing_suites' + option now makes Common Test abort the test run without + asking the user if compilation fails, even if access to + stdin/stdout exists.</p> + <p> + Own Id: OTP-13173 Aux Id: seq12978 </p> + </item> + <item> + <p> + With the Common Test 'create_priv_dir' start option set + to 'auto_per_tc', the name of the priv directory for a + configuration function could clash with the name of the + priv directory for a test case, which would cause Test + Server failure. This error has been corrected.</p> + <p> + Own Id: OTP-13181</p> + </item> + </list> + </section> + +</section> + <section><title>Common_Test 1.11</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -760,7 +1005,7 @@ configuration function or test specification term), the affected test cases get the status <c>user_skipped</c> instead.</p> <p>This update has meant a few changes that - may affect Common Test users in various ways: <list> + may affect Common Test users in various ways:</p> <list> <item>The test results and statistics will be affected, which is important to know when running regression tests and comparing results to previous test runs.</item> @@ -780,7 +1025,7 @@ <c>auto_skipped</c> rather than <c>user_skipped</c> as before.</item> <item>The event messages that Common Test generates during test runs have been affected by this - update. For details see OTP-11524.</item> </list> </p> + update. For details see OTP-11524.</item> </list> <p> Own Id: OTP-11305 Aux Id: OTP-11524 </p> </item> @@ -831,7 +1076,7 @@ <item> <p>The following modifications have been made to the event messages that Common Test sends during test - execution: <list> <item>For the <c>tc_auto_skip</c> + execution:</p> <list> <item>For the <c>tc_auto_skip</c> event, the value of the <c>Func</c> element has changed from <c>end_per_group</c> to <c>{end_per_group,GroupName}</c>.</item> <item>When @@ -843,7 +1088,7 @@ configuration name already in use, the <c>tc_done</c> event now reports the error with a tuple (of size 2) tagged <c>failed</c> instead of <c>skipped</c>.</item> - </list> Please see the Event Handling chapter in the + </list> <p>Please see the Event Handling chapter in the Common Test User's Guide for reference. </p> <p> Own Id: OTP-11524 Aux Id: OTP-11305 </p> @@ -1247,7 +1492,6 @@ <item> <p> Some bugfixes in <c>ct_snmp:</c></p> - <p> <list> <item> ct_snmp will now use the value of the 'agent_vsns' config variable when setting the 'variables' parameter to snmp application agent configuration. @@ -1255,14 +1499,13 @@ supported versions had to be specified twice. </item> <item> Snmp application failed to write notify.conf since ct_snmp gave the notify type as a string instead of an - atom. This has been corrected. </item> </list></p> + atom. This has been corrected. </item> </list> <p> Own Id: OTP-10432</p> </item> <item> <p> Some bugfixes in <c>ct_snmp</c>:</p> - <p> <list> <item> Functions <c>register_users/2</c>, <c>register_agents/2</c> and <c>register_usm_users/2</c>, and the corresponding <c>unregister_*/1</c> functions @@ -1279,7 +1522,7 @@ priv_dir instead of in the configuration dir (priv_dir/conf). This has been corrected. </item> <item> Arguments to <c>register_usm_users/2</c> were faulty - documented. This has been corrected. </item> </list></p> + documented. This has been corrected. </item> </list> <p> Own Id: OTP-10434 Aux Id: kunagi-264 [175] </p> </item> @@ -1343,7 +1586,7 @@ </item> <item> <p> - Update common test modules to handle unicode <list> + Update common test modules to handle unicode:</p> <list> <item> Use UTF-8 encoding for all HTML files, except the HTML version of the test suite generated with erl2html2:convert, which will have the same encoding as @@ -1354,7 +1597,7 @@ unicode:characters_to_list and unicode:characters_to_binary for conversion between binaries and strings instead of binary_to_list and - list_to_binary. </item> </list></p> + list_to_binary. </item> </list> <p> Own Id: OTP-10783</p> </item> @@ -1395,7 +1638,6 @@ <p> The following corrections/changes are done in the cth_surefire hook:</p> - <p> <list> <item> Earlier there would always be a 'properties' element under the 'testsuites' element. This would exist even if there were no 'property' element @@ -1428,7 +1670,7 @@ </item> <item> A new option named 'url_base' is added for this hook. If this option is used, a new attribute named 'url' will be added to the 'testcase' and 'testsuite' - elements. </item> </list></p> + elements. </item> </list> <p> Own Id: OTP-10589</p> </item> diff --git a/lib/common_test/doc/src/part.xml b/lib/common_test/doc/src/part.xml index 0f4c448787..41e74e57c6 100644 --- a/lib/common_test/doc/src/part.xml +++ b/lib/common_test/doc/src/part.xml @@ -31,40 +31,9 @@ </header> <description> - <p><em>Common Test</em> is a portable application for automated - testing. It is suitable for black-box testing of target - systems of any type (i.e. not necessarily implemented in Erlang), - as well as for white-box testing of Erlang/OTP programs. - Black-box testing is performed via standard O&M - interfaces (such as SNMP, HTTP, Corba, Telnet, etc) and, - if required, via user specific interfaces (often called test - ports). White-box testing of Erlang/OTP programs is easily - accomplished by calling the target API functions directly - from the test case functions. Common Test also integrates - usage of the OTP cover tool for code coverage analysis of - Erlang/OTP programs.</p> - - <p>Common Test executes test suite programs automatically, - without operator interaction. Test progress and results is - printed to logs on HTML format, easily browsed with a standard - web browser. Common Test also sends notifications about progress - and results via an OTP event manager to event handlers plugged - in to the system. This way users can integrate their own - programs for e.g. logging, database storing or supervision with - Common Test.</p> - - <p>Common Test provides libraries that contain useful support - functions to fill various testing needs and requirements. - There is for example support for flexible test declarations - by means of so called test specifications. There is also support - for central configuration and control of multiple - independent test sessions (towards different target systems) - running in parallel.</p> - - <p>Common Test is implemented as a framework based on the OTP Test - Server application.</p> </description> + <xi:include href="introduction.xml"/> <xi:include href="basics_chapter.xml"/> <xi:include href="getting_started_chapter.xml"/> <xi:include href="install_chapter.xml"/> diff --git a/lib/common_test/doc/src/ref_man.xml b/lib/common_test/doc/src/ref_man.xml index f98e2475a9..19960bfea7 100644 --- a/lib/common_test/doc/src/ref_man.xml +++ b/lib/common_test/doc/src/ref_man.xml @@ -30,43 +30,10 @@ <file>ref_man.xml</file> </header> <description> - <p><em>Common Test</em> is a portable application for automated - testing. It is suitable for black-box testing of target - systems of any type (i.e. not necessarily implemented in Erlang), - as well as for white-box testing of Erlang/OTP programs. - Black-box testing is performed via standard O&M - interfaces (such as SNMP, HTTP, Corba, Telnet, etc) and, - if required, via user specific interfaces (often called test - ports). White-box testing of Erlang/OTP programs is easily - accomplished by calling the target API functions directly - from the test case functions. Common Test also integrates - usage of the OTP cover tool for code coverage analysis of - Erlang/OTP programs.</p> - - <p>Common Test executes test suite programs automatically, - without operator interaction. Test progress and results is - printed to logs on HTML format, easily browsed with a standard - web browser. Common Test also sends notifications about progress - and results via an OTP event manager to event handlers plugged - in to the system. This way users can integrate their own - programs for e.g. logging, database storing or supervision with - Common Test.</p> - - <p>Common Test provides libraries that contain useful support - functions to fill various testing needs and requirements. - There is for example support for flexible test declarations - by means of so called test specifications. There is also support - for central configuration and control of multiple - independent test sessions (towards different target systems) - running in parallel.</p> - - <p>Common Test is implemented as a framework based on the OTP Test - Server application.</p> </description> + <xi:include href="common_test_app.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"/> <xi:include href="ct_master.xml"/> <xi:include href="ct_cover.xml"/> @@ -83,6 +50,3 @@ </application> - - - diff --git a/lib/common_test/doc/src/run_test_chapter.xml b/lib/common_test/doc/src/run_test_chapter.xml index d80453fc98..e5e217ca1d 100644 --- a/lib/common_test/doc/src/run_test_chapter.xml +++ b/lib/common_test/doc/src/run_test_chapter.xml @@ -33,95 +33,96 @@ <section> <title>Using the Common Test Framework</title> - <p>The Common Test Framework provides a high level - operator interface for testing. It adds the following features to - the Erlang/OTP Test Server:</p> - - <list> - <item>Automatic compilation of test suites (and help modules).</item> - <item>Creation of additional HTML pages for better overview.</item> - <item>Single command interface for running all available tests.</item> + <p>The <c>Common Test</c> framework provides a high-level + operator interface for testing, providing the following features:</p> + + <list type="bulleted"> + <item>Automatic compilation of test suites (and help modules)</item> + <item>Creation of extra HTML pages for improved overview.</item> + <item>Single-command interface for running all available tests</item> <item>Handling of configuration files specifying data related to - the System Under Test (and any other variable data).</item> + the System Under Test (SUT) (and any other variable data)</item> <item>Mode for running multiple independent test sessions in parallel with - central control and configuration.</item> + central control and configuration</item> </list> </section> <section> - <title>Automatic compilation of test suites and help modules</title> - <p>When Common Test starts, it will automatically attempt to compile any + <title>Automatic Compilation of Test Suites and Help Modules</title> + <p>When <c>Common Test</c> starts, it automatically attempts to compile any suites included in the specified tests. If particular - suites have been specified, only those suites will be compiled. If a - particular test object directory has been specified (meaning all suites - in this directory should be part of the test), Common Test runs - make:all/1 in the directory to compile the suites.</p> + suites are specified, only those suites are compiled. If a + particular test object directory is specified (meaning all suites + in this directory are to be part of the test), <c>Common Test</c> runs + function <c>make:all/1</c> in the directory to compile the suites.</p> - <p>If compilation should fail for one or more suites, the compilation errors - are printed to tty and the operator is asked if the test run should proceed + <p>If compilation fails for one or more suites, the compilation errors + are printed to tty and the operator is asked if the test run is to proceed without the missing suites, or be aborted. If the operator chooses to proceed, - it is noted in the HTML log which tests have missing suites. If Common Test is - unable to prompt the user after compilation failure (if Common Test doesn't - control stdin), the test run will proceed automatically without the missing - suites. This behaviour can however be modified with the + the tests having missing suites are noted in the HTML log. If <c>Common Test</c> is + unable to prompt the user after compilation failure (if <c>Common Test</c> does not + control <c>stdin</c>), the test run proceeds automatically without the missing + suites. This behavior can however be modified with the <c><![CDATA[ct_run]]></c> flag <c><![CDATA[-abort_if_missing_suites]]></c>, - or the <c><![CDATA[ct:run_test/1]]></c> option + or the <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso> option <c><![CDATA[{abort_if_missing_suites,TrueOrFalse}]]></c>. If - <c><![CDATA[abort_if_missing_suites]]></c> is set (to true), the test run - will stop immediately if some suites fail to compile.</p> - - <p>Any help module (i.e. regular Erlang module with name not ending with - "_SUITE") that resides in the same test object directory as a suite - which is part of the test, will also be automatically compiled. A help - module will not be mistaken for a test suite (unless it has a "_SUITE" - name of course). All help modules in a particular test object directory - are compiled no matter if all or only particular suites in the directory + <c><![CDATA[abort_if_missing_suites]]></c> is set to <c>true</c>, the test run + stops immediately if some suites fail to compile.</p> + + <p>Any help module (that is, regular Erlang module with name not ending with + "_SUITE") that resides in the same test object directory as a suite, + which is part of the test, is also automatically compiled. A help + module is not mistaken for a test suite (unless it has a "_SUITE" name). + All help modules in a particular test object directory + are compiled, no matter if all or only particular suites in the directory are part of the test.</p> <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[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> + locations than the test directory, these include directories can be specified + by using flag <c><![CDATA[-include]]></c> with + <seealso marker="ct_run"><c>ct_run</c></seealso>, + or option <c><![CDATA[include]]></c> with <c><![CDATA[ct:run_test/1]]></c>. + Also, an include path can be specified with an OS + environment variable, <c><![CDATA[CT_INCLUDE_PATH]]></c>.</p> + <p><em>Example (bash):</em></p> <p><c>$ export CT_INCLUDE_PATH=~testuser/common_suite_files/include:~testuser/common_lib_files/include</c></p> - <p>Common Test will pass all include directories (specified either with the - <c><![CDATA[include]]></c> flag/option, or the <c><![CDATA[CT_INCLUDE_PATH]]></c> - variable, or both) to the compiler.</p> + <p><c>Common Test</c> passes all include directories (specified either with flag/option + <c><![CDATA[include]]></c>, or variable <c><![CDATA[CT_INCLUDE_PATH]]></c> + , or both, to the compiler.</p> - <p>It is also possible to specify include directories in test specifications - (see below).</p> + <p>Include directories can also be specified in test specifications, + see <seealso marker="#test_specifications">Test Specifications</seealso>.</p> - <p>If the user wants to run all test suites for a test object (or OTP application) - by specifying only the top directory (e.g. with the <c>dir</c> start flag/option), - Common Test will primarily look for test suite modules in a subdirectory named - <c>test</c>. If this subdirectory doesn't exist, the specified top directory - is assumed to be the actual test directory, and test suites will be read from + <p>If the user wants to run all test suites for a test object (or an OTP application) + by specifying only the top directory (for example, with start flag/option <c>dir</c>), + <c>Common Test</c> primarily looks for test suite modules in a subdirectory named + <c>test</c>. If this subdirectory does not exist, the specified top directory + is assumed to be the test directory, and test suites are read from 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[ct_run]]></c>, or - the <c><![CDATA[{auto_compile,false}]]></c> option with + <p>To disable the automatic compilation feature, use flag + <c><![CDATA[-no_auto_compile]]></c> with <c><![CDATA[ct_run]]></c>, or + option <c><![CDATA[{auto_compile,false}]]></c> with <c><![CDATA[ct:run_test/1]]></c>. With automatic compilation disabled, the user is responsible for compiling the test suite modules - (and any help modules) before the test run. If the modules can not be loaded - from the local file system during startup of Common Test, the user needs to - pre-load the modules before starting the test. Common Test will only verify - that the specified test suites exist (i.e. that they are, or can be, loaded). - This is useful e.g. if the test suites are transferred and loaded as binaries via - RPC from a remote node.</p> + (and any help modules) before the test run. If the modules cannot be loaded + from the local file system during startup of <c>Common Test</c>, the user must + preload the modules before starting the test. <c>Common Test</c> only verifies + that the specified test suites exist (that is, that they are, or can be, loaded). + This is useful, for example, if the test suites are transferred and loaded as + binaries through RPC from a remote node.</p> </section> <section> <marker id="ct_run"></marker> - <title>Running tests from the OS command line</title> + <title>Running Tests from the OS Command Line</title> - <p>The <c>ct_run</c> program can be used for running tests from - the OS command line, e.g. + <p>The <seealso marker="ct_run"><c>ct_run</c></seealso> program can be used + for running tests from the OS command line, for example, as follows: </p> - <list> + <list type="bulleted"> <item><c><![CDATA[ct_run -config <configfilenames> -dir <dirs>]]></c></item> <item><c><![CDATA[ct_run -config <configfilenames> -suite <suiteswithfullpath>]]></c> </item> @@ -130,824 +131,924 @@ <item><c><![CDATA[ct_run -config <configfilenames> -suite <suitewithfullpath> -group <groups> -case <casenames>]]></c></item> </list> - <p>Examples:</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><em>Examples:</em></p> + <pre> + $ ct_run -config $CFGS/sys1.cfg $CFGS/sys2.cfg -dir $SYS1_TEST $SYS2_TEST + $ ct_run -userconfig ct_config_xml $CFGS/sys1.xml $CFGS/sys2.xml -dir $SYS1_TEST $SYS2_TEST + $ ct_run -suite $SYS1_TEST/setup_SUITE $SYS2_TEST/config_SUITE + $ ct_run -suite $SYS1_TEST/setup_SUITE -case start stop + $ ct_run -suite $SYS1_TEST/setup_SUITE -group installation -case start stop</pre> - <p>It is also possible to combine the <c>dir</c>, <c>suite</c> and <c>group/case</c> flags. E.g, to run - <c>x_SUITE</c> and <c>y_SUITE</c> in directory <c>testdir</c>:</p> - - <p><c>$ ct_run -dir ./testdir -suite x_SUITE y_SUITE</c></p> - - <p>This has the same effect as calling:</p> - - <p><c>$ ct_run -suite ./testdir/x_SUITE ./testdir/y_SUITE</c></p> - - <p>For more details on <seealso marker="run_test_chapter#group_execution">test case group execution</seealso>, please see below.</p> - - <p>Other flags that may be used with <c>ct_run</c>:</p> - <list> - <item><c><![CDATA[-help]]></c>, lists all available start flags.</item> - <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 - in the overview HTML log files.</item> - <item><c>-refresh_logs</c>, refreshes the top level HTML index files.</item> - <item><c>-vts</c>, start web based GUI (see below).</item> - <item><c>-shell</c>, start interactive shell mode (see below).</item> - <item><c>-step [step_opts]</c>, step through test cases using the Erlang Debugger (see below).</item> - <item><c><![CDATA[-spec <testspecs>]]></c>, use test specification as input (see below).</item> - <item><c>-allow_user_terms</c>, allows user specific terms in a test specification (see below).</item> - <item><c>-silent_connections [conn_types]</c>, tells Common Test to suppress printouts for - specified connections (see below).</item> - <item><c><![CDATA[-stylesheet <css_file>]]></c>, points out a user HTML style sheet (see below).</item> - <item><c><![CDATA[-cover <cover_cfg_file>]]></c>, to perform code coverage test (see - <seealso marker="cover_chapter#cover">Code Coverage Analysis</seealso>).</item> - <item><c><![CDATA[-cover_stop <bool>]]></c>, to specify if the cover tool shall be stopped after the test is completed (see - <seealso marker="cover_chapter#cover_stop">Code Coverage Analysis</seealso>).</item> - <item><c><![CDATA[-event_handler <event_handlers>]]></c>, to install - <seealso marker="event_handler_chapter#event_handling">event handlers</seealso>.</item> - <item><c><![CDATA[-event_handler_init <event_handlers>]]></c>, to install - <seealso marker="event_handler_chapter#event_handling">event handlers</seealso> including start arguments.</item> - <item><c><![CDATA[-ct_hooks <ct_hooks>]]></c>, to install - <seealso marker="ct_hooks_chapter#installing">Common Test Hooks</seealso> including start arguments.</item> - <item><c><![CDATA[-enable_builtin_hooks <bool>]]></c>, to enable/disable - <seealso marker="ct_hooks_chapter#builtin_cths">Built-in Common Test Hooks</seealso>. Default is <c>true</c>.</item> - <item><c><![CDATA[-include]]></c>, specifies include directories (see above).</item> - <item><c><![CDATA[-no_auto_compile]]></c>, disables the automatic test suite compilation feature (see above).</item> - <item><c><![CDATA[-abort_if_missing_suites]]></c>, aborts the test run if one or more suites fail to compile (see above).</item> - <item><c><![CDATA[-multiply_timetraps <n>]]></c>, extends <seealso marker="write_test_chapter#timetraps">timetrap - timeout</seealso> values.</item> - <item><c><![CDATA[-scale_timetraps <bool>]]></c>, enables automatic <seealso marker="write_test_chapter#timetraps">timetrap - timeout</seealso> scaling.</item> - <item><c><![CDATA[-repeat <n>]]></c>, tells Common Test to repeat the tests n times (see below).</item> - <item><c><![CDATA[-duration <time>]]></c>, tells Common Test to repeat the tests for duration of time (see below).</item> - <item><c><![CDATA[-until <stop_time>]]></c>, tells Common Test to repeat the tests until stop_time (see below).</item> - <item><c>-force_stop [skip_rest]</c>, on timeout, the test run will be aborted when current test job is finished. If <c>skip_rest</c> is provided the rest of the test cases in the current test job will be skipped (see below).</item> - <item><c><![CDATA[-decrypt_key <key>]]></c>, provides a decryption key for - <seealso marker="config_file_chapter#encrypted_config_files">encrypted configuration files</seealso>.</item> - <item><c><![CDATA[-decrypt_file <key_file>]]></c>, points out a file containing a decryption key for - <seealso marker="config_file_chapter#encrypted_config_files">encrypted configuration files</seealso>.</item> - <item><c><![CDATA[-basic_html]]></c>, switches off html enhancements that might not be compatible with older browsers.</item> - <item><c><![CDATA[-logopts <opts>]]></c>, makes it possible to modify aspects of the logging behaviour, see - <seealso marker="run_test_chapter#logopts">Log options</seealso> below.</item> - <item><c><![CDATA[-verbosity <levels>]]></c>, sets <seealso marker="write_test_chapter#logging">verbosity levels - for printouts</seealso>.</item> - </list> + <p>The flags <c>dir</c>, <c>suite</c>, and <c>group/case</c> can be combined. + For example, to run <c>x_SUITE</c> and <c>y_SUITE</c> + in directory <c>testdir</c>, as follows:</p> + <pre> + $ ct_run -dir ./testdir -suite x_SUITE y_SUITE</pre> + + <p>This has the same effect as the following:</p> + <pre> + $ ct_run -suite ./testdir/x_SUITE ./testdir/y_SUITE</pre> + + <p>For details, see + <seealso marker="run_test_chapter#group_execution">Test Case Group Execution</seealso>.</p> + + <p>The following flags can also be used with + <seealso marker="ct_run"><c>ct_run</c></seealso>:</p> + <taglist> + <tag><c><![CDATA[-help]]></c></tag> + <item><p>Lists all available start flags.</p></item> + + <tag><c><![CDATA[-logdir <dir>]]></c></tag> + <item><p>Specifies where the HTML log files are to be written.</p></item> + + <tag><c><![CDATA[-label <name_of_test_run>]]></c></tag> + <item><p>Associates the test run with a name that gets printed + in the overview HTML log files.</p></item> + + <tag><c>-refresh_logs</c></tag> + <item><p>Refreshes the top-level HTML index files.</p></item> + + <tag><c>-vts</c></tag> + <item><p>Starts web-based GUI (described later).</p></item> + + <tag><c>-shell</c></tag> + <item><p>Starts interactive shell mode (described later).</p></item> + + <tag><c>-step [step_opts]</c></tag> + <item><p>Steps through test cases using the Erlang Debugger (described later).</p></item> + + <tag><c><![CDATA[-spec <testspecs>]]></c></tag> + <item><p>Uses test specification as input (described later).</p></item> + + <tag><c>-allow_user_terms</c></tag> + <item><p>Allows user-specific terms in a test specification (described later).</p></item> + + <tag><c>-silent_connections [conn_types]</c></tag> + <item><p>, tells <c>Common Test</c> to suppress printouts for + specified connections (described later).</p></item> + + <tag><c><![CDATA[-stylesheet <css_file>]]></c></tag> + <item><p>Points out a user HTML style sheet (described later).</p></item> + + <tag><c><![CDATA[-cover <cover_cfg_file>]]></c></tag> + <item><p>To perform code coverage test (see + <seealso marker="cover_chapter#cover">Code Coverage Analysis</seealso>).</p></item> + + <tag><c><![CDATA[-cover_stop <bool>]]></c></tag> + <item><p>To specify if the <c>cover</c> tool is to be stopped + after the test is completed (see + <seealso marker="cover_chapter#cover_stop">Code Coverage Analysis</seealso>).</p></item> + + <tag><c><![CDATA[-event_handler <event_handlers>]]></c></tag> + <item><p>To install + <seealso marker="event_handler_chapter#event_handling">event handlers</seealso>.</p></item> + + <tag><c><![CDATA[-event_handler_init <event_handlers>]]></c></tag> + <item><p>To install + <seealso marker="event_handler_chapter#event_handling">event handlers</seealso> + including start arguments.</p></item> + + <tag><c><![CDATA[-ct_hooks <ct_hooks>]]></c></tag> + <item><p>To install + <seealso marker="ct_hooks_chapter#installing">Common Test Hooks</seealso> + including start arguments.</p></item> - <note><p>Directories passed to Common Test may have either relative or absolute paths.</p></note> + <tag><c><![CDATA[-enable_builtin_hooks <bool>]]></c></tag> + <item><p>To enable or disable + <seealso marker="ct_hooks_chapter#builtin_cths">Built-in Common Test Hooks</seealso>. + Default is <c>true</c>.</p></item> - <note><p>Arbitrary start flags to the Erlang Runtime System may also be passed as + <tag><c><![CDATA[-include]]></c></tag> + <item><p>Specifies include directories (described earlier).</p></item> + + <tag><c><![CDATA[-no_auto_compile]]></c></tag> + <item><p>Disables the automatic test suite compilation feature (described earlier).</p></item> + + <tag><c><![CDATA[-abort_if_missing_suites]]></c></tag> + <item><p>Aborts the test run if one or more suites fail to compile (described earlier).</p></item> + + <tag><c><![CDATA[-multiply_timetraps <n>]]></c></tag> + <item><p>Extends <seealso marker="write_test_chapter#timetraps">timetrap + time-out</seealso> values.</p></item> + + <tag><c><![CDATA[-scale_timetraps <bool>]]></c></tag> + <item><p>Enables automatic <seealso marker="write_test_chapter#timetraps">timetrap + time-out</seealso> scaling.</p></item> + + <tag><c><![CDATA[-repeat <n>]]></c></tag> + <item><p>Tells <c>Common Test</c> to repeat the tests <c>n</c> times (described later).</p></item> + + <tag><c><![CDATA[-duration <time>]]></c></tag> + <item><p>Tells <c>Common Test</c> to repeat the tests for duration of time (described later).</p></item> + + <tag><c><![CDATA[-until <stop_time>]]></c></tag> + <item><p>Tells <c>Common Test</c> to repeat the tests until <c>stop_time</c> (described later).</p></item> + + <tag><c>-force_stop [skip_rest]</c></tag> + <item><p>On time-out, the test run is aborted when the current test job is finished. If <c>skip_rest</c> + is provided, the remaining test cases in the current test job are skipped (described later).</p></item> + + <tag><c><![CDATA[-decrypt_key <key>]]></c></tag> + <item><p>Provides a decryption key for + <seealso marker="config_file_chapter#encrypted_config_files">encrypted configuration files</seealso>.</p></item> + + <tag><c><![CDATA[-decrypt_file <key_file>]]></c></tag> + <item><p>Points out a file containing a decryption key for + <seealso marker="config_file_chapter#encrypted_config_files">encrypted configuration files</seealso>.</p></item> + + <tag><c><![CDATA[-basic_html]]></c></tag> + <item><p>Switches off HTML enhancements that can be incompatible with older browsers.</p></item> + + <tag><c><![CDATA[-logopts <opts>]]></c></tag> + <item><p>Enables modification of the logging behavior, see + <seealso marker="run_test_chapter#logopts">Log options</seealso>.</p></item> + + <tag><c><![CDATA[-verbosity <levels>]]></c></tag> + <item><p>Sets <seealso marker="write_test_chapter#logging">verbosity levels + for printouts</seealso>.</p></item> + + <tag><c><![CDATA[-no_esc_chars]]></c></tag> + <item><p>Disables automatic escaping of special HTML characters. + See the <seealso marker="write_test_chapter#logging">Logging chapter</seealso>.</p></item> + </taglist> + + <note><p>Directories passed to <c>Common Test</c> can have either relative or absolute paths.</p></note> + + <note><p>Any start flags to the Erlang runtime system (application <c>ERTS</c>) can also be passed as 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 + pass directories to be added to the Erlang code server search path + with flag <c>-pa</c> or <c>-pz</c>. 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> + than the test suite directories, these <c>help/lib</c> directories are preferably + added to the code path this way.</p> + <p><em>Example:</em></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> + <p>The absolute path of directory <c>chat_server/ebin</c> + is here passed to the code server. This is essential because relative + paths are stored by the code server as relative, and <c>Common Test</c> changes + the current working directory of <c>ERTS</c> during the test run.</p> </note> <p>The <c>ct_run</c> program sets the exit status before shutting down. The following values are defined:</p> - <list> - <item><c>0</c> indicates a successful testrun, i.e. one without failed or auto skipped test cases.</item> - <item><c>1</c> indicates that one or more test cases have failed, or have been auto skipped.</item> - <item><c>2</c> indicates that the test execution has failed because of e.g. compilation errors, an - illegal return value from an info function, etc.</item> + <list type="bulleted"> + <item><c>0</c> indicates a successful testrun, that is, without failed or auto-skipped test cases.</item> + <item><c>1</c> indicates that one or more test cases have failed, or have been auto-skipped.</item> + <item><c>2</c> indicates that the test execution has failed because of, for example, compilation errors, or an + illegal return value from an information function.</item> </list> - <p>If auto skipped test cases should not affect the exit status, you may change the default - behaviour using start flag:</p> - <pre>-exit_status ignore_config</pre> + <p>If auto-skipped test cases do not affect the exit status. The default + behavior can be changed using start flag:</p> + <pre> + -exit_status ignore_config</pre> - <note><p>Executing <c>ct_run</c> without start flags, is equal to the command: + <note><p>Executing <c>ct_run</c> without start flags is equal to the command: <c>ct_run -dir ./</c></p></note> - <p>For more information about the <c>ct_run</c> program, see the - <seealso marker="ct_run">Reference Manual</seealso> and the - <seealso marker="install_chapter#general">Installation</seealso> chapter. + <p>For more information about the <c>ct_run</c> program, see module + <seealso marker="ct_run"><c>ct_run</c></seealso> and section + <seealso marker="install_chapter#general">Installation</seealso>. </p> </section> <section> - <title>Running tests from the Erlang shell or from an Erlang program</title> + <marker id="erlang_shell_or_program"></marker> + <title>Running Tests from the Erlang Shell or from an Erlang Program</title> - <p>Common Test provides an Erlang API for running tests. The main (and most - flexible) function for specifying and executing tests is called + <p><c>Common Test</c> provides an Erlang API for running tests. The main + (and most flexible) function for specifying and executing tests is <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso>. - This function takes the same start parameters as - the <seealso marker="run_test_chapter#ct_run"><c>ct_run</c></seealso> - 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>ct_run</c> like:</p> + It takes the same start parameters as + <seealso marker="run_test_chapter#ct_run"><c>ct_run</c></seealso>, + but the flags are instead specified as options in a list of key-value tuples. + For example, a test specified with <c>ct_run</c> as follows:</p> <p><c>$ ct_run -suite ./my_SUITE -logdir ./results</c></p> <p>is with <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso> specified as:</p> <p><c>1> ct:run_test([{suite,"./my_SUITE"},{logdir,"./results"}]).</c></p> - <p>The function returns the test result, represented by the tuple: + <p>The function returns the test result, represented by the tuple <c>{Ok,Failed,{UserSkipped,AutoSkipped}}</c>, where each element is an - integer. If test execution fails, the function returns the tuple: + integer. If test execution fails, the function returns the tuple <c>{error,Reason}</c>, where the term <c>Reason</c> explains the failure.</p> - <p>The default start option <c>{dir,Cwd}</c> (run all suites in the current + <p>The default start option <c>{dir,Cwd}</c> (to run all suites in the current working directory) is used if the function is called with an empty list of options.</p> <section> - <title>Releasing the Erlang shell</title> - <p>During execution of tests, started with + <title>Releasing the Erlang Shell</title> + <p>During execution of tests started with <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso>, - the Erlang shell process, controlling stdin, will remain the top - level process of the Common Test system of processes. The result - is that the Erlang shell is not available for interaction during - the test run. If this is not desirable, maybe because the shell is needed - for debugging purposes or for interaction with the SUT during test - execution, you may set the <c>release_shell</c> start option to + the Erlang shell process, controlling <c>stdin</c>, remains the top-level + process of the <c>Common Test</c> system of processes. Consequently, + the Erlang shell is not available for interaction during + the test run. If this is not desirable, for example, because the shell + is needed for debugging purposes or for interaction with the SUT during test + execution, set start option <c>release_shell</c> to <c>true</c> (in the call to <c>ct:run_test/1</c> or by - using the corresponding test specification term, see below). This will - make Common Test release the shell immediately after the test suite + using the corresponding test specification term, described later). This + makes <c>Common Test</c> release the shell immediately after the test suite compilation stage. To accomplish this, a test runner process - is spawned to take control of the test execution, and the effect is that + is spawned to take control of the test execution. The effect is that <c>ct:run_test/1</c> returns the pid of this process rather than the - test result - which instead is printed to tty at the end of the test run.</p> - <note><p>Note that in order to use the - <seealso marker="ct#break-1"><c>ct:break/1/2</c></seealso> and - <seealso marker="ct#continue-0"><c>ct:continue/0/1</c></seealso> functions, + test result, which instead is printed to tty at the end of the test run.</p> + <note><p>To use the functions + <seealso marker="ct#break-1"><c>ct:break/1,2</c></seealso> and + <seealso marker="ct#continue-0"><c>ct:continue/0,1</c></seealso>, <c>release_shell</c> <em>must</em> be set to <c>true</c>.</p></note> </section> - <p>For detailed documentation about - <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso>, - please see the - <seealso marker="ct#run_test-1"><c>ct</c></seealso> manual page.</p> + <p>For details, see + <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso> manual page.</p> </section> <section> <marker id="group_execution"></marker> - <title>Test case group execution</title> + <title>Test Case Group Execution</title> <p>With the <c>ct_run</c> flag, or <c>ct:run_test/1</c> option <c>group</c>, one or more test case groups can be specified, optionally in combination - with specific test cases. The syntax for specifying groups is as follows - (on the command line):</p> + with specific test cases. The syntax for specifying groups on the command line + is as follows:</p> <pre> - <![CDATA[$ ct_run -group <group_names_or_paths> [-case <cases>]]]></pre> - <p>or (in the Erlang shell):</p> + <![CDATA[$ ct_run -group <group_names_or_paths> [-case <cases>]]]></pre> + <p>The syntax in the Erlang shell is as follows:</p> <pre> - <![CDATA[1> ct:run_test([{group,GroupsNamesOrPaths}, {case,Cases}]).]]></pre> + <![CDATA[1> ct:run_test([{group,GroupsNamesOrPaths}, {case,Cases}]).]]></pre> - <p>The <c>group_names_or_paths</c> parameter specifies either one - or more group names and/or one or more group paths. At start up, - Common Test will search for matching groups in the group definitions - tree (i.e. the list returned from <c>Suite:groups/0</c>, please see the - <seealso marker="write_test_chapter#test_case_groups">Test case groups</seealso> - chapter for details). - Given a group name, say <c>g</c>, Common Test will search for all paths - that lead to <c>g</c>. By path here we mean a sequence of nested groups, - all of which have to be followed in order to get from the top level - group to <c>g</c>. Actually, what Common Test needs to do in order to - execute the test cases in group <c>g</c>, is to call the - <c>init_per_group/2</c> function for each group in the path to - <c>g</c>, as well as all corresponding <c>end_per_group/2</c> - functions afterwards. The obvious reason for this is that the configuration + <p>Parameter <c>group_names_or_paths</c> specifies one + or more group names and/or one or more group paths. At startup, + <c>Common Test</c> searches for matching groups in the group definitions + tree (that is, the list returned from <c>Suite:groups/0</c>; for details, see section + <seealso marker="write_test_chapter#test_case_groups">Test Case Groups</seealso>. + </p> + + <p>Given a group name, say <c>g</c>, <c>Common Test</c> searches for all paths + leading to <c>g</c>. By path is meant a sequence of nested groups, + which must be followed to get from the top-level + group to <c>g</c>. To execute the test cases in group <c>g</c>, + <c>Common Test</c> must call the <c>init_per_group/2</c> function for + each group in the path to <c>g</c>, and all corresponding <c>end_per_group/2</c> + functions afterwards. This is because the configuration of a test case in <c>g</c> (and its <c>Config</c> input data) depends on <c>init_per_testcase(TestCase, Config)</c> and its return value, which in turn depends on <c>init_per_group(g, Config)</c> and its return value, which in turn depends on <c>init_per_group/2</c> of the group above - <c>g</c>, etc, all the way up to the top level group.</p> + <c>g</c>, and so on, all the way up to the top-level group.</p> - <p>As you may have already realized, this means that if there is more than - one way to locate a group (and its test cases) in a path, the result of the - group search operation is a number of tests, all of which will be performed. - Common Test actually interprets a group specification that consists of a - single name this way:</p> + <p>This means that if there is more than one way to locate a group + (and its test cases) in a path, the result of the group search operation + is a number of tests, all of which are to be performed. + <c>Common Test</c> interprets a group specification that consists of a + single name as follows:</p> <p>"Search and find all paths in the group definitions tree that lead - to the specified group and, for each path, create a test which (1) executes - all configuration functions in the path to the specified group, then (2) - executes all - or all matching - test cases in this group, as well as (3) - all - or all matching - test cases in all sub groups of the group". - </p> + to the specified group and, for each path, create a test that does the following, + in order:</p> + <list type="ordered"> + <item>Executes all configuration functions in the path to the specified group.</item> + <item>Executes all, or all matching, test cases in this group.</item> + <item>Executes all, or all matching, test cases in all subgroups of the group."</item> + </list> - <p>It is also possible for the user to specify a specific group path with - the <c>group_names_or_paths</c> parameter. With this type of specification it's - possible to avoid execution of unwanted groups (in otherwise matching paths), - and/or the execution of sub groups. The syntax of the group path is a list of - group names in the path, e.g. on the command line: + <p>The user can specify a specific group path with + parameter <c>group_names_or_paths</c>. With this type of specification + execution of unwanted groups (in otherwise matching paths), + and/or the execution of subgroups can be avoided. The command line syntax of the + group path is a list of group names in the path, for example: </p> <p><c>$ ct_run -suite "./x_SUITE" -group [g1,g3,g4] -case tc1 tc5</c></p> - <p>or similarly in the Erlang shell (requires a list within the groups list):</p> + <p>The syntax in the Erlang shell is as follows (requires a list within the groups list):</p> <p><c>1> ct:run_test([{suite,"./x_SUITE"}, {group,[[g1,g3,g4]]}, {testcase,[tc1,tc5]}]).</c></p> - <p>The last group in the specified path will be the terminating group in - the test, i.e. no sub groups following this group will be executed. In the - example above, <c>g4</c> is the terminating group, hence Common Test will - execute a test that calls all init configuration functions in the path to - <c>g4</c>, i.e. <c>g1..g3..g4</c>. It will then call test cases <c>tc1</c> - and <c>tc5</c> in <c>g4</c> and finally all end configuration functions in order - <c>g4..g3..g1</c>.</p> + <p>The last group in the specified path is the terminating group in + the test, that is, no subgroups following this group are executed. In the + previous example, <c>g4</c> is the terminating group. Hence, <c>Common Test</c> + executes a test that calls all <c>init</c> configuration functions in the path to + <c>g4</c>, that is, <c>g1..g3..g4</c>. It then calls test cases <c>tc1</c> + and <c>tc5</c> in <c>g4</c>, and finally all <c>end</c> configuration functions + in order <c>g4..g3..g1</c>.</p> - <p>Note that the group path specification doesn't necessarily + <note><p>The group path specification does not necessarily have to include <em>all</em> groups in the path to the terminating group. - Common Test will search for all matching paths if given an incomplete group - path.</p> + <c>Common Test</c> searches for all matching paths if an incomplete + group path is specified.</p></note> + + <note><p>Group names and group paths can be combined with parameter + <c>group_names_or_paths</c>. Each element is treated as an individual specification + in combination with parameter <c>cases</c>. + The following examples illustrates this.</p></note> + + <p><em>Examples:</em></p> + <pre> + -module(x_SUITE). + ... + %% The group definitions: + groups() -> + [{top1,[],[tc11,tc12, + {sub11,[],[tc12,tc13]}, + {sub12,[],[tc14,tc15, + {sub121,[],[tc12,tc16]}]}]}, + + {top2,[],[{group,sub21},{group,sub22}]}, + {sub21,[],[tc21,{group,sub2X2}]}, + {sub22,[],[{group,sub221},tc21,tc22,{group,sub2X2}]}, + {sub221,[],[tc21,tc23]}, + {sub2X2,[],[tc21,tc24]}].</pre> + + <p>The following executes two tests, one for all cases and all subgroups + under <c>top1</c>, and one for all under <c>top2</c>:</p> + <pre> + $ ct_run -suite "x_SUITE" -group all + 1> ct:run_test([{suite,"x_SUITE"}, {group,all}]).</pre> + <p>Using <c>-group top1 top2</c>, or <c>{group,[top1,top2]}</c> gives the same result.</p> + + <p>The following executes one test for all cases and subgroups under <c>top1</c>:</p> + <pre> + $ ct_run -suite "x_SUITE" -group top1 + 1> ct:run_test([{suite,"x_SUITE"}, {group,[top1]}]).</pre> + + <p>The following runs a test executing <c>tc12</c> in <c>top1</c> and any subgroup + under <c>top1</c> where it can be found (<c>sub11</c> and <c>sub121</c>):</p> + <pre> + $ ct_run -suite "x_SUITE" -group top1 -case tc12 + 1> ct:run_test([{suite,"x_SUITE"}, {group,[top1]}, {testcase,[tc12]}]).</pre> + + <p>The following executes <c>tc12</c> <em>only</em> in group <c>top1</c>:</p> + <pre> + $ ct_run -suite "x_SUITE" -group [top1] -case tc12 + 1> ct:run_test([{suite,"x_SUITE"}, {group,[[top1]]}, {testcase,[tc12]}]).</pre> - <p>Note also that it's possible to combine group names and group paths with the - <c>group_names_or_paths</c> parameter. Each element is treated as - an individual specification in combination with the <c>cases</c> parameter. - See examples below.</p> + <p>The following searches <c>top1</c> and all its subgroups for <c>tc16</c> resulting + in that this test case executes in group <c>sub121</c>:</p> + <pre> + $ ct_run -suite "x_SUITE" -group top1 -case tc16 + 1> ct:run_test([{suite,"x_SUITE"}, {group,[top1]}, {testcase,[tc16]}]).</pre> + <p>Using the specific path <c>-group [sub121]</c> or <c>{group,[[sub121]]}</c> gives + the same result in this example.</p> - <p>Examples:</p> + <p>The following executes two tests, one including all cases and subgroups under + <c>sub12</c>, and one with <em>only</em> the test cases in <c>sub12</c>:</p> <pre> - -module(x_SUITE). - ... - %% The group definitions: - groups() -> - [{top1,[],[tc11,tc12, - {sub11,[],[tc12,tc13]}, - {sub12,[],[tc14,tc15, - {sub121,[],[tc12,tc16]}]}]}, - - {top2,[],[{group,sub21},{group,sub22}]}, - {sub21,[],[tc21,{group,sub2X2}]}, - {sub22,[],[{group,sub221},tc21,tc22,{group,sub2X2}]}, - {sub221,[],[tc21,tc23]}, - {sub2X2,[],[tc21,tc24]}]. - </pre> - <br></br> - <p><c>$ ct_run -suite "x_SUITE" -group all</c></p> - <p><c>1> ct:run_test([{suite,"x_SUITE"}, {group,all}]).</c></p> - <p>Two tests will be executed, one for all cases and all sub groups under <c>top1</c>, - and one for all under <c>top2</c>. (We would get the same result with - <c>-group top1 top2</c>, or <c>{group,[top1,top2]}</c>.</p> - <br></br> - <p><c>$ ct_run -suite "x_SUITE" -group top1</c></p> - <p><c>1> ct:run_test([{suite,"x_SUITE"}, {group,[top1]}]).</c></p> - <p>This will execute one test for all cases and sub groups under <c>top1</c>.</p> - <br></br> - <p><c>$ ct_run -suite "x_SUITE" -group top1 -case tc12</c></p> - <p><c>1> ct:run_test([{suite,"x_SUITE"}, {group,[top1]}, {testcase,[tc12]}]).</c></p> - <p>This will run a test that executes <c>tc12</c> in <c>top1</c> and any sub group - under <c>top1</c> where it can be found (<c>sub11</c> and <c>sub121</c>).</p> - <br></br> - <p><c>$ ct_run -suite "x_SUITE" -group [top1] -case tc12</c></p> - <p><c>1> ct:run_test([{suite,"x_SUITE"}, {group,[[top1]]}, {testcase,[tc12]}]).</c></p> - <p>This will execute <c>tc12</c> <em>only</em> in group <c>top1</c>.</p> - <br></br> - <p><c>$ ct_run -suite "x_SUITE" -group top1 -case tc16</c></p> - <p><c>1> ct:run_test([{suite,"x_SUITE"}, {group,[top1]}, {testcase,[tc16]}]).</c></p> - <p>This will search <c>top1</c> and all its sub groups for <c>tc16</c> and the result - will be that this test case executes in group <c>sub121</c>. (The specific path: - <c>-group [sub121]</c> or <c>{group,[[sub121]]}</c>, would have given - us the same result in this example).</p> - <br></br> - <p><c>$ ct_run -suite "x_SUITE" -group sub12 [sub12]</c></p> - <p><c>1> ct:run_test([{suite,"x_SUITE"}, {group,[sub12,[sub12]]}]).</c></p> - <p>This will execute two tests, one that includes all cases and sub groups under - <c>sub12</c>, and one with <em>only</em> the test cases in <c>sub12</c>.</p> - <br></br> - <p><c>$ ct_run -suite "x_SUITE" -group sub2X2</c></p> - <p><c>1> ct:run_test([{suite,"x_SUITE"}, {group,[sub2X2]}]).</c></p> - <p>In this example, Common Test will find and execute two tests, one for the path from - <c>top2</c> to <c>sub2X2</c> via <c>sub21</c>, and one from <c>top2</c> to <c>sub2X2</c> - via <c>sub22</c>.</p> - <br></br> - <p><c>$ ct_run -suite "x_SUITE" -group [sub21,sub2X2]</c></p> - <p><c>1> ct:run_test([{suite,"x_SUITE"}, {group,[[sub21,sub2X2]]}]).</c></p> - <p>Here, by specifying the unique path: <c>top2 -> sub21 -> sub2X2</c>, only one test - is executed. The second possible path from <c>top2</c> to <c>sub2X2</c> (above) - will be discarded.</p> - <br></br> - <p><c>$ ct_run -suite "x_SUITE" -group [sub22] -case tc22 tc21</c></p> - <p><c>1> ct:run_test([{suite,"x_SUITE"}, {group,[[sub22]]}, {testcase,[tc22,tc21]}]).</c></p> - <p>In this example only the test cases for <c>sub22</c> will be executed, and in - reverse order compared to the group definition.</p> - <br></br> - - <p>If a test case that belongs to a group (according to the group definition), is executed - without a group specification, i.e. simply by means of (command line):</p> + $ ct_run -suite "x_SUITE" -group sub12 [sub12] + 1> ct:run_test([{suite,"x_SUITE"}, {group,[sub12,[sub12]]}]).</pre> + + <p>In the following example, <c>Common Test</c> finds and executes two tests, + one for the path from <c>top2</c> to <c>sub2X2</c> through <c>sub21</c>, + and one from <c>top2</c> to <c>sub2X2</c> through <c>sub22</c>:</p> + <pre> + $ ct_run -suite "x_SUITE" -group sub2X2 + 1> ct:run_test([{suite,"x_SUITE"}, {group,[sub2X2]}]).</pre> + + <p>In the following example, by specifying the unique path <c>top2 -> sub21 -> sub2X2</c>, + only one test is executed. The second possible path, from <c>top2</c> to <c>sub2X2</c> + (from the former example) is discarded:</p> + <pre> + $ ct_run -suite "x_SUITE" -group [sub21,sub2X2] + 1> ct:run_test([{suite,"x_SUITE"}, {group,[[sub21,sub2X2]]}]).</pre> + + <p>The following executes only the test cases for <c>sub22</c> and in reverse order + compared to the group definition:</p> + <pre> + $ ct_run -suite "x_SUITE" -group [sub22] -case tc22 tc21 + 1> ct:run_test([{suite,"x_SUITE"}, {group,[[sub22]]}, {testcase,[tc22,tc21]}]).</pre> + + <p>If a test case belonging to a group (according to the group definition) is executed + without a group specification, that is, simply by + (using the command line):</p> <p><c>$ ct_run -suite "my_SUITE" -case my_tc</c></p> - <p>or (Erlang shell):</p> + <p>or (using the Erlang shell):</p> <p><c>1> ct:run_test([{suite,"my_SUITE"}, {testcase,my_tc}]).</c></p> - <p>then Common Test ignores the group definition and executes the test case in the scope of the - test suite only (no group configuration functions are called).</p> + <p>then <c>Common Test</c> ignores the group definition and executes the test case + in the scope of the test suite only (no group configuration functions are called).</p> - <p>The group specification feature, exactly as it has been presented in this section, can also + <p>The group specification feature, as presented in this section, can also be used in <seealso marker="run_test_chapter#test_specifications">Test - Specifications</seealso> (with some extra features added). Please see below.</p> + Specifications</seealso> (with some extra features added).</p> </section> <section> - <title>Running the interactive shell mode</title> + <title>Running the Interactive Shell Mode</title> - <p>You can start Common Test in an interactive shell mode where no - automatic testing is performed. Instead, in this mode, Common Test + <p>You can start <c>Common Test</c> in an interactive shell mode where no + automatic testing is performed. Instead, <c>Common Test</c> starts its utility processes, installs configuration data (if any), and waits for the user to call functions (typically test case support functions) from the Erlang shell.</p> - <p>The shell mode is useful e.g. for debugging test suites, for analysing + <p>The shell mode is useful, for example, for debugging test suites, analyzing and debugging the SUT during "simulated" test case execution, and - for trying out various operations during test suite development.</p> - - <p>To invoke the interactive shell mode, you can start an Erlang shell - manually and call <seealso marker="ct#install-1"><c>ct:install/1</c></seealso> to install any configuration - data you might need (use <c>[]</c> as argument otherwise), then - call <seealso marker="ct#start_interactive-0"><c>ct:start_interactive/0</c></seealso> to start Common Test. If you use - 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> + trying out various operations during test suite development.</p> + + <p>To start the interactive shell mode, start an Erlang shell + manually and call <seealso marker="ct#install-1"><c>ct:install/1</c></seealso> + to install any configuration data you might need (use <c>[]</c> as argument otherwise). + Then call <seealso marker="ct#start_interactive-0"><c>ct:start_interactive/0</c></seealso> + to start <c>Common Test</c>.</p> + + <p>If you use the <c>ct_run</c> program, you can start + the Erlang shell and <c>Common Test</c> in one go by using the flag <c>-shell</c> and, + optionally, flag <c>-config</c> and/or <c>-userconfig</c>.</p> + <p><em>Examples:</em></p> + <list type="bulleted"> <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>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 - config files will be available.</p> - - <p>If any functions using "required config data" (e.g. ct_telnet or - ct_ftp functions) are to be called from the erlang shell, config - data must first be required with <seealso marker="ct#require-1"><c> - ct:require/1/2</c></seealso>. This is - equivalent to a <c>require</c> statement in the <seealso - marker="write_test_chapter#suite">Test Suite Info - Function</seealso> or in the <seealso - marker="write_test_chapter#info_function">Test Case Info - Function</seealso>.</p> + <p>If no configuration file is specified with command <c>ct_run</c>, + a warning is displayed. If <c>Common Test</c> has been run from the same + directory earlier, the same configuration file(s) are used again. If <c>Common Test</c> + has not been run from this directory before, no configuration files are available.</p> - <p>Example:</p> + <p>If any functions using "required configuration data" (for example, functions + <c>ct_telnet</c> or <c>ct_ftp</c>) are to be called from the Erlang shell, first require + configuration data with <seealso marker="ct#require-1"><c> + ct:require/1,2</c></seealso>. This is equivalent to a <c>require</c> statement + in the <seealso marker="write_test_chapter#suite">Test Suite Information Function</seealso> + or in the <seealso marker="write_test_chapter#info_function">Test Case Information Function</seealso>.</p> + + <p><em>Example:</em></p> <pre> - 1> ct:require(unix_telnet, unix). - ok - 2> ct_telnet:open(unix_telnet). - {ok,<0.105.0>} - 4> ct_telnet:cmd(unix_telnet, "ls ."). - {ok,["ls .","file1 ...",...]} - </pre> + 1> ct:require(unix_telnet, unix). + ok + 2> ct_telnet:open(unix_telnet). + {ok,<0.105.0>} + 4> ct_telnet:cmd(unix_telnet, "ls ."). + {ok,["ls .","file1 ...",...]}</pre> - <p>Everything that Common Test normally prints in the test case logs, - will in the interactive mode be written to a log named - <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>ct_run</c>. Currently, specifying a different - root directory for the logs than the current working directory, + <p>Everything that <c>Common Test</c> normally prints in the test case logs, + are in the interactive mode written to a log named <c>ctlog.html</c> + in directory <c><![CDATA[ct_run.<timestamp>]]></c>. A link to this + file is available in the file named <c>last_interactive.html</c> in the + directory from which you execute <c>ct_run</c>. Specifying a different + root directory for the logs than the current working directory is not supported.</p> - <p>If you wish to exit the interactive mode (e.g. to start an - automated test run with <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso>), call the function - <seealso marker="ct#stop_interactive-0"><c>ct:stop_interactive/0</c></seealso>. This shuts down the - running <c>ct</c> application. Associations between + <p>If you wish to exit the interactive mode (for example, to start an automated + test run with <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso>), + call function + <seealso marker="ct#stop_interactive-0"><c>ct:stop_interactive/0</c></seealso>. + This shuts down the running <c>ct</c> application. Associations between configuration names and data created with <c>require</c> are - consequently deleted. <seealso marker="ct#start_interactive-0"><c>ct:start_interactive/0</c></seealso> will get you - back into interactive mode, but the previous state is not restored.</p> + consequently deleted. Function + <seealso marker="ct#start_interactive-0"><c>ct:start_interactive/0</c></seealso> + takes you back into interactive mode, but the previous state is not restored.</p> </section> <section> - <title>Step by step execution of test cases with the Erlang Debugger</title> + <title>Step-by-Step Execution of Test Cases with the Erlang Debugger</title> - <p>By means of <c>ct_run -step [opts]</c>, or by passing the - <c>{step,Opts}</c> option to <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso>, it is possible - to get the Erlang Debugger started automatically and use its - graphical interface to investigate the state of the current test - case and to execute it step by step and/or set execution breakpoints.</p> - <p>If no extra options are given with the <c>step</c> flag/option, - breakpoints will be set automatically on the test cases that - are to be executed by Common Test, and those functions only. If - the step option <c>config</c> is specified, breakpoints will - also be initially set on the configuration functions in the suite, i.e. + <p>Using <c>ct_run -step [opts]</c>, or by passing option <c>{step,Opts}</c> + to <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso>, + the following is possible:</p> + <list type="bulleted"> + <item>Get the Erlang Debugger started automatically.</item> + <item>Use its graphical interface to investigate the state of the current test case.</item> + <item>Execute the test case step-by-step and/or set execution breakpoints.</item> + </list> + <p>If no extra options are specified with flag/option <c>step</c>, + breakpoints are set automatically on the test cases that + are to be executed by <c>Common Test</c>, and those functions only. If + step option <c>config</c> is specified, breakpoints are also initially + set on the configuration functions in the suite, that is, <c>init_per_suite/1</c>, <c>end_per_suite/1</c>, <c>init_per_group/2</c>, <c>end_per_group/2</c>, <c>init_per_testcase/2</c> and <c>end_per_testcase/2</c>.</p> - <p>Common Test enables the Debugger auto attach feature, which means + <p><c>Common Test</c> enables the Debugger auto-attach feature, which means that for every new interpreted test case function that starts to execute, - a new trace window will automatically pop up. (This is because each test + a new trace window automatically pops up (as each test case executes on a dedicated Erlang process). Whenever a new test case starts, - Common Test will attempt to close the inactive trace window of the previous - test case. However, if you prefer that Common Test leaves inactive trace - windows, use the <c>keep_inactive</c> option.</p> - <p>The step functionality can be used together with the <c>suite</c> and - the <c>suite</c> + <c>case/testcase</c> flag/option, but not together - with <c>dir</c>.</p> + <c>Common Test</c> attempts to close the inactive trace window of the previous + test case. However, if you prefer <c>Common Test</c> to leave inactive trace + windows, use option <c>keep_inactive</c>.</p> + <p>The step functionality can be used together with flag/option <c>suite</c> and + <c>suite</c> + <c>case/testcase</c>, but not together with <c>dir</c>.</p> </section> <section> <marker id="test_specifications"></marker> <title>Test Specifications</title> <section> - <title>General description</title> - <p>The most flexible way to specify what to test, is to use a so - called test specification. A test specification is a sequence of + <title>General Description</title> + <p>The most flexible way to specify what to test, is to use a + test specification, which is a sequence of Erlang terms. The terms are normally declared in one or more text files (see <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso>), but - may also be passed to Common Test on the form of a list (see + can also be passed to <c>Common Test</c> on the form of a list (see <seealso marker="ct#run_testspec-1"><c>ct:run_testspec/1</c></seealso>). 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>ct_run -label</c>), evaluate arbitrary expressions - before starting the test, import configuration data (similar to - <c>ct_run -config/-userconfig</c>), specify the top level HTML log - directory (similar to <c>ct_run -logdir</c>), enable code coverage - analysis (similar to <c>ct_run -cover</c>), install Common Test Hooks - (similar to <c>ct_run -ch_hooks</c>), install event_handler plugins - (similar to <c>ct_run -event_handler</c>), specify include directories - that should be passed to the compiler for automatic compilation - (similar to <c>ct_run -include</c>), disable the auto compilation - feature (similar to <c>ct_run -no_auto_compile</c>), set verbosity - levels (similar to <c>ct_run -verbosity</c>), and more.</p> - <p>Configuration terms can be combined with <c>ct_run</c> start flags, - or <c>ct:run_test/1</c> options. The result will for some flags/options - and terms be that the values are merged (e.g. configuration files, - include directories, verbosity levels, silent connections), and for + + <p>With configuration terms it is, for example, possible to do the following:</p> + <list type="bulleted"> + <item>Label the test run (similar to <c>ct_run -label</c>).</item> + <item>Evaluate any expressions before starting the test.</item> + <item>Import configuration data (similar to <c>ct_run -config/-userconfig</c>).</item> + <item>Specify the top-level HTML log directory (similar to <c>ct_run -logdir</c>).</item> + <item>Enable code coverage analysis (similar to <c>ct_run -cover</c>).</item> + <item>Install <c>Common Test Hooks</c> (similar to <c>ct_run -ch_hooks</c>).</item> + <item>Install <c>event_handler</c> plugins (similar to <c>ct_run -event_handler</c>).</item> + <item>Specify include directories to be passed to the compiler for + automatic compilation (similar to <c>ct_run -include</c>).</item> + <item>Disable the auto-compilation feature (similar to <c>ct_run -no_auto_compile</c>).</item> + <item>Set verbosity levels (similar to <c>ct_run -verbosity</c>).</item> + </list> + + <p>Configuration terms can be combined with <c>ct_run</c> start flags + or <c>ct:run_test/1</c> options. The result is, for some flags/options + and terms, that the values are merged (for example, configuration files, + include directories, verbosity levels, and silent connections) and for others that the start flags/options override the test specification - terms (e.g. log directory, label, style sheet, auto compilation).</p> - <p>With test specification terms it is possible to state exactly - which tests should run and in which order. A test term specifies + terms (for example, log directory, label, style sheet, and auto-compilation).</p> + + <p>With test specification terms, it is possible to state exactly + which tests to run and in which order. A test term specifies either one or more suites, one or more test case groups (possibly nested), or one or more test cases in a group (or in multiple groups) or in a suite.</p> - <p>An arbitrary number of test terms may be declared in sequence. - Common Test will by default compile the terms into one or more tests - to be performed in one resulting test run. Note that a term that - specifies a set of test cases will "swallow" one that only - specifies a subset of these cases. E.g. the result of merging - one term that specifies that all cases in suite S should be + + <p>Any number of test terms can be declared in sequence. + <c>Common Test</c> compiles by default the terms into one or more tests + to be performed in one resulting test run. A term that + specifies a set of test cases "swallows" one that only + specifies a subset of these cases. For example, the result of merging + one term specifying that all cases in suite S are to be executed, with another term specifying only test case X and Y in S, is a test of all cases in S. However, if a term specifying test case X and Y in S is merged with a term specifying case Z - in S, the result is a test of X, Y and Z in S. To disable this - behaviour, i.e. to instead perform each test sequentially in a "script-like" - manner, the term <c>merge_tests</c> can be set to <c>false</c> in - the test specification.</p> + in S, the result is a test of X, Y, and Z in S. To disable this + behavior, that is, to instead perform each test sequentially in a + "script-like" manner, set term <c>merge_tests</c> to <c>false</c> + in the test specification.</p> + <p>A test term can also specify one or more test suites, groups, - or test cases to be skipped. Skipped suites, groups and cases - are not executed and show up in the HTML log files as - SKIPPED.</p> + or test cases to be skipped. Skipped suites, groups, and cases + are not executed and show up in the HTML log files as <c>SKIPPED</c>.</p> </section> <section> - <title>Using multiple test specification files</title> + <title>Using Multiple Test Specification Files</title> - <p>When multiple test specification files are given at startup (either + <p>When multiple test specification files are specified at startup (either with <c>ct_run -spec file1 file2 ...</c> or <c>ct:run_test([{spec, [File1,File2,...]}])</c>), - Common Test will either execute one test run per specification file, or - join the files and perform all tests within one single test run. The first - behaviour is the default one. The latter requires that the start - flag/option <c>join_specs</c> is provided, e.g. + <c>Common Test</c> either executes one test run per specification file, + or joins the files and performs all tests within one single test run. + The first behavior is the default one. The latter requires that start + flag/option <c>join_specs</c> is provided, for example, <c>run_test -spec ./my_tests1.ts ./my_tests2.ts -join_specs</c>.</p> <p>Joining a number of specifications, or running them separately, can - also be accomplished with (and may be combined with) test specification - file inclusion, described next.</p> + also be accomplished with (and can be combined with) test specification + file inclusion.</p> </section> <section> - <title>Test specification file inclusion</title> - <p>With the <c>specs</c> term (see syntax below), it's possible to have - a test specification include other specifications. An included - specification may either be joined with the source specification, - or used to produce a separate test run (like with the <c>join_specs</c> - start flag/option above). Example:</p> + <title>Test Specification File Inclusion</title> + <p>With the term <c>specs</c>, a test specification can include + other specifications. An included specification can either be joined + with the source specification or used to produce a separate test run + (as with start flag/option <c>join_specs</c> above).</p> + <p><em>Example:</em></p> + <pre> - %% In specification file "a.spec" - {specs, join, ["b.spec", "c.spec"]}. - {specs, separate, ["d.spec", "e.spec"]}. - %% Config and test terms follow - ...</pre> + %% In specification file "a.spec" + {specs, join, ["b.spec", "c.spec"]}. + {specs, separate, ["d.spec", "e.spec"]}. + %% Config and test terms follow + ...</pre> + <p>In this example, the test terms defined in files "b.spec" and "c.spec" - will be joined with the terms in the source specification "a.spec" + are joined with the terms in source specification "a.spec" (if any). The inclusion of specifications "d.spec" and - "e.spec" will result in two separate, and independent, test runs (i.e. - one for each included specification).</p> - <p>Note that the <c>join</c> option does not imply that the test terms - will be merged (see <c>merge_tests</c> above), only that all tests are - executed in one single test run.</p> + "e.spec" results in two separate, and independent, test runs + (one for each included specification).</p> + + <p>Option <c>join</c> does not imply that the test terms + are merged, only that all tests are executed in one single test run.</p> + <p>Joined specifications share common configuration settings, such as the list of <c>config</c> files or <c>include</c> directories. - For configuration that can not be combined, such as settings for <c>logdir</c> + For configurations that cannot be combined, such as settings for <c>logdir</c> or <c>verbosity</c>, it is up to the user to ensure there are no clashes when the test specifications are joined. Specifications included with - the <c>separate</c> option, do not share configuration settings with the - source specification. This is useful e.g. if there are clashing - configuration settings in included specifications, making it impossible - to join them.</p> + option <c>separate</c> do not share configuration settings with the + source specification. This is useful, for example, if there are clashing + configuration settings in included specifications, making it them impossible + to join.</p> + <p>If <c>{merge_tests,true}</c> is set in the source specification - (which is the default setting), terms in joined specifications will be + (which is the default setting), terms in joined specifications are merged with terms in the source specification (according to the - description of <c>merge_tests</c> above).</p> - <p>Note that it is always the <c>merge_tests</c> setting in the source + description of <c>merge_tests</c> earlier).</p> + + <p>Notice that it is always the <c>merge_tests</c> setting in the source specification that is used when joined with other specifications. - Say e.g. that a source specification A, with tests TA1 and TA2, has - <c>{merge_tests,false}</c> set, and it includes another specification, + Say, for example, that a source specification A, with tests TA1 and TA2, has + <c>{merge_tests,false}</c> set, and that it includes another specification, B, with tests TB1 and TB2, that has <c>{merge_tests,true}</c> set. - The result will be that the test series: <c>TA1,TA2,merge(TB1,TB2)</c>, - is executed. The opposite <c>merge_tests</c> settings would result in the - following the test series: <c>merge(merge(TA1,TA2),TB1,TB2)</c>.</p> - <p>The <c>specs</c> term may of course be used to nest specifications, - i.e. have one specification include other specifications, which in turn - include others, etc.</p> + The result is that the test series <c>TA1,TA2,merge(TB1,TB2)</c> + is executed. The opposite <c>merge_tests</c> settings would result in + the test series <c>merge(merge(TA1,TA2),TB1,TB2)</c>.</p> + + <p>The term <c>specs</c> can be used to nest specifications, + that is, have one specification include other specifications, which in turn + include others, and so no</p> </section> <section> - <title>Test case groups</title> + <title>Test Case Groups</title> <p>When a test case group is specified, the resulting test - executes the <c>init_per_group</c> function, followed by all test - cases and sub groups (including their configuration functions), and - finally the <c>end_per_group</c> function. Also if particular + executes function <c>init_per_group</c>, followed by all test + cases and subgroups (including their configuration functions), and + finally function <c>end_per_group</c>. Also, if particular test cases in a group are specified, <c>init_per_group</c> - and <c>end_per_group</c> for the group in question are - called. If a group which is defined (in <c>Suite:group/0</c>) to - be a sub group of another group, is specified (or if particular test - cases of a sub group are), Common Test will call the configuration - functions for the top level groups as well as for the sub group + and <c>end_per_group</c>, for the group in question, are + called. If a group defined (in <c>Suite:group/0</c>) as + a subgroup of another group, is specified (or if particular test + cases of a subgroup are), <c>Common Test</c> calls the configuration + functions for the top-level groups and for the subgroup in question (making it possible to pass configuration data all the way from <c>init_per_suite</c> down to the test cases in the - sub group).</p> - <p>The test specification utilizes the same mechanism for specifying - test case groups by means of names and paths, as explained in the - <seealso marker="run_test_chapter#group_execution">Group Execution</seealso> - section above, with the addition of the <c>GroupSpec</c> element - described next.</p> - <p>The <c>GroupSpec</c> element makes it possible to specify - group execution properties that will override those in the - group definition (i.e. in <c>groups/0</c>). Execution properties for - sub-groups may be overridden as well. This feature makes it possible to + subgroup).</p> + + <p>The test specification uses the same mechanism for specifying + test case groups through names and paths, as explained in section + <seealso marker="run_test_chapter#group_execution">Test Case Group Execution</seealso>, + with the addition of element <c>GroupSpec</c>.</p> + + <p>Element <c>GroupSpec</c> makes it possible to specify + group execution properties that overrides those in the + group definition (that is, in <c>groups/0</c>). Execution properties for + subgroups might be overridden as well. This feature makes it possible to change properties of groups at the time of execution, - without even having to edit the test suite. The very same - feature is available for <c>group</c> elements in the <c>Suite:all/0</c> - list. Therefore, more detailed documentation, and examples, can be - found in the <seealso marker="write_test_chapter#test_case_groups"> - Test case groups</seealso> chapter.</p> + without having to edit the test suite. The same feature is available for + <c>group</c> elements in the <c>Suite:all/0</c> list. For details and examples, + see section <seealso marker="write_test_chapter#test_case_groups"> + Test Case Groups</seealso>.</p> </section> <section> - <title>Test specification syntax</title> - - <p>Below is the test specification syntax. Test specifications can - be used to run tests both in a single test host environment and - in a distributed Common Test environment (Large Scale - Testing). The node parameters in the <c>init</c> term are only - relevant in the latter (see the - <seealso marker="ct_master_chapter#test_specifications">Large - Scale Testing</seealso> chapter for information). For more information - about the various terms, please see the corresponding sections in the - User's Guide, such as e.g. the - <seealso marker="run_test_chapter#ct_run"><c>ct_run</c> + <title>Test Specification Syntax</title> + + <p>Test specifications can be used to run tests both in a single + test host environment and in a distributed <c>Common Test</c> environment + (Large Scale Testing). The node parameters in term <c>init</c> are only + relevant in the latter (see section + <seealso marker="ct_master_chapter#test_specifications">Test Specifications</seealso> + in Large Scale Testing). For details about the various terms, see the + corresponding sections in the User's Guide, for example, the following: + </p> + <list type="bulleted"> + <item>The <seealso marker="run_test_chapter#ct_run"><c>ct_run</c> program</seealso> for an overview of available start flags - (since most flags have a corresponding configuration term), and - more detailed explanation of e.g. - <seealso marker="write_test_chapter#logging">Logging</seealso> - (for the <c>verbosity</c>, <c>stylesheet</c> and <c>basic_html</c> terms), - <seealso marker="config_file_chapter#top">External Configuration Data</seealso> - (for the <c>config</c> and <c>userconfig</c> terms), - <seealso marker="event_handler_chapter#event_handling">Event - Handling</seealso> (for the <c>event_handler</c> term), - <seealso marker="ct_hooks_chapter#installing">Common Test Hooks</seealso> - (for the <c>ct_hooks</c> term), etc.</p> - </section> - - <p>Config terms:</p> + (as most flags have a corresponding configuration term)</item> + <item><seealso marker="write_test_chapter#logging">Logging</seealso> + (for terms <c>verbosity</c>, <c>stylesheet</c>, <c>basic_html</c> and <c>esc_chars</c>)</item> + <item><seealso marker="config_file_chapter#top">External Configuration Data</seealso> + (for terms <c>config</c> and <c>userconfig</c>)</item> + <item><seealso marker="event_handler_chapter#event_handling">Event + Handling</seealso> (for the <c>event_handler</c> term)</item> + <item><seealso marker="ct_hooks_chapter#installing">Common Test Hooks</seealso> + (for term <c>ct_hooks</c>)</item> + </list> + + <p><em>Configuration terms:</em></p> <pre> - {merge_tests, Bool}. - - {define, Constant, Value}. - - {specs, InclSpecsOption, TestSpecs}. - - {node, NodeAlias, Node}. - - {init, InitOptions}. - {init, [NodeAlias], InitOptions}. - - {label, Label}. - {label, NodeRefs, Label}. - - {verbosity, VerbosityLevels}. - {verbosity, NodeRefs, VerbosityLevels}. - - {stylesheet, CSSFile}. - {stylesheet, NodeRefs, CSSFile}. - - {silent_connections, ConnTypes}. - {silent_connections, NodeRefs, ConnTypes}. - - {multiply_timetraps, N}. - {multiply_timetraps, NodeRefs, N}. - - {scale_timetraps, Bool}. - {scale_timetraps, NodeRefs, Bool}. - - {cover, CoverSpecFile}. - {cover, NodeRefs, CoverSpecFile}. - - {cover_stop, Bool}. - {cover_stop, NodeRefs, Bool}. - - {include, IncludeDirs}. - {include, NodeRefs, IncludeDirs}. - - {auto_compile, Bool}, - {auto_compile, NodeRefs, Bool}, - - {abort_if_missing_suites, Bool}, - {abort_if_missing_suites, NodeRefs, Bool}, + {merge_tests, Bool}. - {config, ConfigFiles}. - {config, ConfigDir, ConfigBaseNames}. - {config, NodeRefs, ConfigFiles}. - {config, NodeRefs, ConfigDir, ConfigBaseNames}. - - {userconfig, {CallbackModule, ConfigStrings}}. - {userconfig, NodeRefs, {CallbackModule, ConfigStrings}}. - - {logdir, LogDir}. - {logdir, NodeRefs, LogDir}. - - {logopts, LogOpts}. - {logopts, NodeRefs, LogOpts}. - - {create_priv_dir, PrivDirOption}. - {create_priv_dir, NodeRefs, PrivDirOption}. - - {event_handler, EventHandlers}. - {event_handler, NodeRefs, EventHandlers}. - {event_handler, EventHandlers, InitArgs}. - {event_handler, NodeRefs, EventHandlers, InitArgs}. - - {ct_hooks, CTHModules}. - {ct_hooks, NodeRefs, CTHModules}. - - {enable_builtin_hooks, Bool}. - - {basic_html, Bool}. - {basic_html, NodeRefs, Bool}. - - {release_shell, Bool}.</pre> + {define, Constant, Value}. + + {specs, InclSpecsOption, TestSpecs}. + + {node, NodeAlias, Node}. + + {init, InitOptions}. + {init, [NodeAlias], InitOptions}. + + {label, Label}. + {label, NodeRefs, Label}. + + {verbosity, VerbosityLevels}. + {verbosity, NodeRefs, VerbosityLevels}. + + {stylesheet, CSSFile}. + {stylesheet, NodeRefs, CSSFile}. + + {silent_connections, ConnTypes}. + {silent_connections, NodeRefs, ConnTypes}. + + {multiply_timetraps, N}. + {multiply_timetraps, NodeRefs, N}. + + {scale_timetraps, Bool}. + {scale_timetraps, NodeRefs, Bool}. + + {cover, CoverSpecFile}. + {cover, NodeRefs, CoverSpecFile}. + + {cover_stop, Bool}. + {cover_stop, NodeRefs, Bool}. + + {include, IncludeDirs}. + {include, NodeRefs, IncludeDirs}. + + {auto_compile, Bool}, + {auto_compile, NodeRefs, Bool}, + + {abort_if_missing_suites, Bool}, + {abort_if_missing_suites, NodeRefs, Bool}, + + {config, ConfigFiles}. + {config, ConfigDir, ConfigBaseNames}. + {config, NodeRefs, ConfigFiles}. + {config, NodeRefs, ConfigDir, ConfigBaseNames}. + + {userconfig, {CallbackModule, ConfigStrings}}. + {userconfig, NodeRefs, {CallbackModule, ConfigStrings}}. + + {logdir, LogDir}. + {logdir, NodeRefs, LogDir}. + + {logopts, LogOpts}. + {logopts, NodeRefs, LogOpts}. + + {create_priv_dir, PrivDirOption}. + {create_priv_dir, NodeRefs, PrivDirOption}. + + {event_handler, EventHandlers}. + {event_handler, NodeRefs, EventHandlers}. + {event_handler, EventHandlers, InitArgs}. + {event_handler, NodeRefs, EventHandlers, InitArgs}. + + {ct_hooks, CTHModules}. + {ct_hooks, NodeRefs, CTHModules}. + + {enable_builtin_hooks, Bool}. + + {basic_html, Bool}. + {basic_html, NodeRefs, Bool}. + + {esc_chars, Bool}. + {esc_chars, NodeRefs, Bool}. + + {release_shell, Bool}.</pre> - <p>Test terms:</p> + <p><em>Test terms:</em></p> <pre> - {suites, Dir, Suites}. - {suites, NodeRefs, Dir, Suites}. - - {groups, Dir, Suite, Groups}. - {groups, NodeRefs, Dir, Suite, Groups}. - - {groups, Dir, Suite, Groups, {cases,Cases}}. - {groups, NodeRefs, Dir, Suite, Groups, {cases,Cases}}. - - {cases, Dir, Suite, Cases}. - {cases, NodeRefs, Dir, Suite, Cases}. - - {skip_suites, Dir, Suites, Comment}. - {skip_suites, NodeRefs, Dir, Suites, Comment}. - - {skip_groups, Dir, Suite, GroupNames, Comment}. - {skip_groups, NodeRefs, Dir, Suite, GroupNames, Comment}. - - {skip_cases, Dir, Suite, Cases, Comment}. - {skip_cases, NodeRefs, Dir, Suite, Cases, Comment}.</pre> - - <p>Types:</p> + {suites, Dir, Suites}. + {suites, NodeRefs, Dir, Suites}. + + {groups, Dir, Suite, Groups}. + {groups, NodeRefs, Dir, Suite, Groups}. + + {groups, Dir, Suite, Groups, {cases,Cases}}. + {groups, NodeRefs, Dir, Suite, Groups, {cases,Cases}}. + + {cases, Dir, Suite, Cases}. + {cases, NodeRefs, Dir, Suite, Cases}. + + {skip_suites, Dir, Suites, Comment}. + {skip_suites, NodeRefs, Dir, Suites, Comment}. + + {skip_groups, Dir, Suite, GroupNames, Comment}. + {skip_groups, NodeRefs, Dir, Suite, GroupNames, Comment}. + + {skip_cases, Dir, Suite, Cases, Comment}. + {skip_cases, NodeRefs, Dir, Suite, Cases, Comment}.</pre> + + <marker id="types"></marker> + <p><em>Types:</em></p> <pre> - Bool = true | false - Constant = atom() - Value = term() - InclSpecsOption = join | separate - TestSpecs = string() | [string()] - NodeAlias = atom() - Node = node() - NodeRef = NodeAlias | Node | master - NodeRefs = all_nodes | [NodeRef] | NodeRef - InitOptions = term() - Label = atom() | string() - VerbosityLevels = integer() | [{Category,integer()}] - Category = atom() - CSSFile = string() - ConnTypes = all | [atom()] - N = integer() - CoverSpecFile = string() - IncludeDirs = string() | [string()] - ConfigFiles = string() | [string()] - ConfigDir = string() - ConfigBaseNames = string() | [string()] - CallbackModule = atom() - ConfigStrings = string() | [string()] - LogDir = string() - LogOpts = [term()] - PrivDirOption = auto_per_run | auto_per_tc | manual_per_tc - EventHandlers = atom() | [atom()] - InitArgs = [term()] - CTHModules = [CTHModule | - {CTHModule, CTHInitArgs} | - {CTHModule, CTHInitArgs, CTHPriority}] - CTHModule = atom() - CTHInitArgs = term() - Dir = string() - Suites = atom() | [atom()] | all - Suite = atom() - Groups = GroupPath | [GroupPath] | GroupSpec | [GroupSpec] | all - GroupPath = [GroupName] - GroupSpec = GroupName | {GroupName,Properties} | {GroupName,Properties,GroupSpec} - GroupName = atom() - GroupNames = GroupName | [GroupName] - Cases = atom() | [atom()] | all - Comment = string() | ""</pre> - - <section> - <p>The difference between the <c>config</c> terms above, is that with + Bool = true | false + Constant = atom() + Value = term() + InclSpecsOption = join | separate + TestSpecs = string() | [string()] + NodeAlias = atom() + Node = node() + NodeRef = NodeAlias | Node | master + NodeRefs = all_nodes | [NodeRef] | NodeRef + InitOptions = term() + Label = atom() | string() + VerbosityLevels = integer() | [{Category,integer()}] + Category = atom() + CSSFile = string() + ConnTypes = all | [atom()] + N = integer() + CoverSpecFile = string() + IncludeDirs = string() | [string()] + ConfigFiles = string() | [string()] + ConfigDir = string() + ConfigBaseNames = string() | [string()] + CallbackModule = atom() + ConfigStrings = string() | [string()] + LogDir = string() + LogOpts = [term()] + PrivDirOption = auto_per_run | auto_per_tc | manual_per_tc + EventHandlers = atom() | [atom()] + InitArgs = [term()] + CTHModules = [CTHModule | + {CTHModule, CTHInitArgs} | + {CTHModule, CTHInitArgs, CTHPriority}] + CTHModule = atom() + CTHInitArgs = term() + Dir = string() + Suites = atom() | [atom()] | all + Suite = atom() + Groups = GroupPath | [GroupPath] | GroupSpec | [GroupSpec] | all + GroupPath = [GroupName] + GroupSpec = GroupName | {GroupName,Properties} | {GroupName,Properties,GroupSpec} + GroupName = atom() + GroupNames = GroupName | [GroupName] + Cases = atom() | [atom()] | all + Comment = string() | ""</pre> + + <p>The difference between the <c>config</c> terms above is that with <c>ConfigDir</c>, <c>ConfigBaseNames</c> is a list of base names, - i.e. without directory paths. <c>ConfigFiles</c> must be full names, - including paths. E.g, these two terms have the same meaning:</p> + that is, without directory paths. <c>ConfigFiles</c> must be full names, + including paths. For example, the following two terms have the same meaning:</p> <pre> - {config, ["/home/testuser/tests/config/nodeA.cfg", - "/home/testuser/tests/config/nodeB.cfg"]}. - - {config, "/home/testuser/tests/config", ["nodeA.cfg","nodeB.cfg"]}.</pre> + {config, ["/home/testuser/tests/config/nodeA.cfg", + "/home/testuser/tests/config/nodeB.cfg"]}. + + {config, "/home/testuser/tests/config", ["nodeA.cfg","nodeB.cfg"]}.</pre> - <note><p>Any relative paths specified in the test specification, will be - relative to the directory which contains the test specification file, if + <note><p>Any relative paths, specified in the test specification, are + relative to the directory containing the test specification file if <c>ct_run -spec TestSpecFile ...</c> or <c>ct:run:test([{spec,TestSpecFile},...])</c> - executes the test. The path will be relative to the top level log directory, if + executes the test.</p> + <p>The path is relative to the top-level log directory if <c>ct:run:testspec(TestSpec)</c> executes the test.</p></note> </section> <section> <title>Constants</title> - <p>The <c>define</c> term introduces a constant, which is used to - replace the name <c>Constant</c> with <c>Value</c>, wherever it's found in - the test specification. This replacement happens during an initial iteration - through the test specification. Constants may be used anywhere in the test - specification, e.g. in arbitrary lists and tuples, and even in strings - and inside the value part of other constant definitions! A constant can + <p>The term <c>define</c> introduces a constant that is used to + replace the name <c>Constant</c> with <c>Value</c>, wherever it is found in + the test specification. This replacement occurs during an initial iteration + through the test specification. Constants can be used anywhere in the test + specification, for example, in any lists and tuples, and even in strings + and inside the value part of other constant definitions. A constant can also be part of a node name, but that is the only place where a constant can be part of an atom.</p> <note><p>For the sake of readability, the name of the constant must always - begin with an upper case letter, or a <c>$</c>, <c>?</c>, or <c>_</c>. - This also means that it must always be single quoted (obviously, since - the constant name is actually an atom, not text).</p></note> + begin with an uppercase letter, or a <c>$</c>, <c>?</c>, or <c>_</c>. + This means that it must always be single quoted (as the constant name is + an atom, not text).</p></note> <p>The main benefit of constants is that they can be used to reduce the size - (and avoid repetition) of long strings, such as file paths. Compare these - terms:</p> + (and avoid repetition) of long strings, such as file paths.</p> + <p><em>Examples:</em></p> <pre> - %% 1a. no constant - {config, "/home/testuser/tests/config", ["nodeA.cfg","nodeB.cfg"]}. - {suites, "/home/testuser/tests/suites", all}. - - %% 1b. with constant - {define, 'TESTDIR', "/home/testuser/tests"}. - {config, "'TESTDIR'/config", ["nodeA.cfg","nodeB.cfg"]}. - {suites, "'TESTDIR'/suites", all}. - - %% 2a. no constants - {config, [testnode@host1, testnode@host2], "../config", ["nodeA.cfg","nodeB.cfg"]}. - {suites, [testnode@host1, testnode@host2], "../suites", [x_SUITE, y_SUITE]}. - - %% 2b. with constants - {define, 'NODE', testnode}. - {define, 'NODES', ['NODE'@host1, 'NODE'@host2]}. - {config, 'NODES', "../config", ["nodeA.cfg","nodeB.cfg"]}. - {suites, 'NODES', "../suites", [x_SUITE, y_SUITE]}.</pre> + %% 1a. no constant + {config, "/home/testuser/tests/config", ["nodeA.cfg","nodeB.cfg"]}. + {suites, "/home/testuser/tests/suites", all}. + + %% 1b. with constant + {define, 'TESTDIR', "/home/testuser/tests"}. + {config, "'TESTDIR'/config", ["nodeA.cfg","nodeB.cfg"]}. + {suites, "'TESTDIR'/suites", all}. + + %% 2a. no constants + {config, [testnode@host1, testnode@host2], "../config", ["nodeA.cfg","nodeB.cfg"]}. + {suites, [testnode@host1, testnode@host2], "../suites", [x_SUITE, y_SUITE]}. + + %% 2b. with constants + {define, 'NODE', testnode}. + {define, 'NODES', ['NODE'@host1, 'NODE'@host2]}. + {config, 'NODES', "../config", ["nodeA.cfg","nodeB.cfg"]}. + {suites, 'NODES', "../suites", [x_SUITE, y_SUITE]}.</pre> <p>Constants make the test specification term <c>alias</c>, in previous - versions of Common Test, redundant. This term has been deprecated but will - remain supported in upcoming Common Test releases. Replacing <c>alias</c> - terms with <c>define</c> is strongly recommended though! Here's an example - of such a replacement:</p> + versions of <c>Common Test</c>, redundant. This term is deprecated but + remains supported in upcoming <c>Common Test</c> releases. Replacing <c>alias</c> + terms with <c>define</c> is strongly recommended though. An example + of such replacement follows:</p> <pre> - %% using the old alias term - {config, "/home/testuser/tests/config/nodeA.cfg"}. - {alias, suite_dir, "/home/testuser/tests/suites"}. - {groups, suite_dir, x_SUITE, group1}. - - %% replacing with constants - {define, 'TestDir', "/home/testuser/tests"}. - {define, 'CfgDir', "'TestDir'/config"}. - {define, 'SuiteDir', "'TestDir'/suites"}. - {config, 'CfgDir', "nodeA.cfg"}. - {groups, 'SuiteDir', x_SUITE, group1}.</pre> + %% using the old alias term + {config, "/home/testuser/tests/config/nodeA.cfg"}. + {alias, suite_dir, "/home/testuser/tests/suites"}. + {groups, suite_dir, x_SUITE, group1}. + + %% replacing with constants + {define, 'TestDir', "/home/testuser/tests"}. + {define, 'CfgDir', "'TestDir'/config"}. + {define, 'SuiteDir', "'TestDir'/suites"}. + {config, 'CfgDir', "nodeA.cfg"}. + {groups, 'SuiteDir', x_SUITE, group1}.</pre> - <p>Actually, constants could well replace the <c>node</c> term too, but - this still has declarative value, mainly when used in combination - with <c>NodeRefs == all_nodes</c> (see types above).</p> + <p>Constants can well replace term <c>node</c> also, but + this still has a declarative value, mainly when used in combination + with <c>NodeRefs == all_nodes</c> + (see <seealso marker="#types">Types</seealso>).</p> </section> <section> @@ -955,104 +1056,104 @@ <p>Here follows a simple test specification example:</p> <pre> - {define, 'Top', "/home/test"}. - {define, 'T1', "'Top'/t1"}. - {define, 'T2', "'Top'/t2"}. - {define, 'T3', "'Top'/t3"}. - {define, 'CfgFile', "config.cfg"}. - - {logdir, "'Top'/logs"}. - - {config, ["'T1'/'CfgFile'", "'T2'/'CfgFile'", "'T3'/'CfgFile'"]}. - - {suites, 'T1', all}. - {skip_suites, 'T1', [t1B_SUITE,t1D_SUITE], "Not implemented"}. - {skip_cases, 'T1', t1A_SUITE, [test3,test4], "Irrelevant"}. - {skip_cases, 'T1', t1C_SUITE, [test1], "Ignore"}. - - {suites, 'T2', [t2B_SUITE,t2C_SUITE]}. - {cases, 'T2', t2A_SUITE, [test4,test1,test7]}. - - {skip_suites, 'T3', all, "Not implemented"}.</pre> + {define, 'Top', "/home/test"}. + {define, 'T1', "'Top'/t1"}. + {define, 'T2', "'Top'/t2"}. + {define, 'T3', "'Top'/t3"}. + {define, 'CfgFile', "config.cfg"}. + + {logdir, "'Top'/logs"}. + + {config, ["'T1'/'CfgFile'", "'T2'/'CfgFile'", "'T3'/'CfgFile'"]}. + + {suites, 'T1', all}. + {skip_suites, 'T1', [t1B_SUITE,t1D_SUITE], "Not implemented"}. + {skip_cases, 'T1', t1A_SUITE, [test3,test4], "Irrelevant"}. + {skip_cases, 'T1', t1C_SUITE, [test1], "Ignore"}. + + {suites, 'T2', [t2B_SUITE,t2C_SUITE]}. + {cases, 'T2', t2A_SUITE, [test4,test1,test7]}. + + {skip_suites, 'T3', all, "Not implemented"}.</pre> <p>The example specifies the following:</p> - <list> - <item>The specified logdir directory will be used for storing + <list type="bulleted"> + <item>The specified <c>logdir</c> directory is used for storing the HTML log files (in subdirectories tagged with node name, - date and time).</item> - <item>The variables in the specified test system config files will be + date, and time).</item> + <item>The variables in the specified test system configuration files are imported for the test.</item> - <item>The first test to run includes all suites for system t1. Excluded from - the test are however the t1B and t1D suites. Also test cases test3 and - test4 in t1A as well as the test1 case in t1C are excluded from - the test.</item> - <item>Secondly, the test for system t2 should run. The included suites are - t2B and t2C. Included are also test cases test4, test1 and test7 in suite - t2A. Note that the test cases will be executed in the specified order.</item> - <item>Lastly, all suites for systems t3 are to be completely skipped and this - should be explicitly noted in the log files.</item> + <item>The first test to run includes all suites for system <c>t1</c>. + Suites <c>t1B</c> and <c>t1D</c> are excluded from the test. Test cases + <c>test3</c> and <c>test4</c> in <c>t1A</c> and <c>test1</c> case in <c>t1C</c> + are also excluded from the test.</item> + <item>The second test to run is for system <c>t2</c>. The included suites are + <c>t2B</c> and <c>t2C</c>. Test cases <c>test4</c>, <c>test1</c>, and <c>test7</c> in suite + <c>t2A</c> are also included. The test cases are executed in the specified order.</item> + <item>The last test to run is for system <c>t3</c>. Here, all suites are skipped and this + is explicitly noted in the log files.</item> </list> </section> <section> - <title>The init term</title> - <p>With the <c>init</c> term it's possible to specify initialization options - for nodes defined in the test specification. Currently, there are options - to start the node and/or to evaluate any function on the node. - See the <seealso marker="ct_master_chapter#ct_slave">Automatic startup of - the test target nodes</seealso> chapter for details.</p> + <title>The init Term</title> + <p>With term <c>init</c> it is possible to specify initialization options + for nodes defined in the test specification. There are options + to start the node and to evaluate any function on the node. + For details, see section <seealso marker="ct_master_chapter#ct_slave">Automatic Startup of + Test Target Nodes</seealso> in section Using Common Test for Large Scale Testing.</p> </section> <section> - <title>User specific terms</title> - <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>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. + <title>User-Specific Terms</title> + <p>The user can provide a test specification including (for <c>Common Test</c>) + unrecognizable terms. If this is desired, use flag <c>-allow_user_terms</c> + when starting tests with <c>ct_run</c>. This forces <c>Common Test</c> to ignore + unrecognizable terms. In this mode, <c>Common Test</c> is not able to check the + specification for errors as efficiently as if the scanner runs in default mode. If <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso> is used - for starting the tests, the relaxed scanner - mode is enabled by means of the tuple: <c>{allow_user_terms,true}</c></p> + for starting the tests, the relaxed scanner mode is enabled by tuple + <c>{allow_user_terms,true}</c>.</p> </section> <section> - <title>Reading test specification terms</title> - <p>It's possible to look up terms in the current test specification - (i.e. the spec that's been used to configure and run the current test). - The function <c>get_testspec_terms()</c> returns a list of all test spec - terms (both config- and test terms) and <c>get_testspec_terms(Tags)</c> - returns the term (or a list of terms) matching the tag (or tags) in - <c>Tags</c>.</p> + <title>Reading Test Specification Terms</title> + <p>Terms in the current test specification + (that is, the specification that has been used to configure and run the current test) + can be looked up. + The function <seealso marker="ct#get_testspec_terms-0"><c>get_testspec_terms()</c></seealso> + returns a list of all test specification terms (both configuration terms and test terms), + and <c>get_testspec_terms(Tags)</c> returns the term (or a list of terms) matching the + tag (or tags) in <c>Tags</c>.</p> <p>For example, in the test specification:</p> <pre> - ... - {label, my_server_smoke_test}. - {config, "../../my_server_setup.cfg"}. - {config, "../../my_server_interface.cfg"}. - ...</pre> - <p>And in e.g. a test suite or a CT hook function:</p> + ... + {label, my_server_smoke_test}. + {config, "../../my_server_setup.cfg"}. + {config, "../../my_server_interface.cfg"}. + ...</pre> + <p>And in, for example, a test suite or a <c>Common Test Hook</c> function:</p> <pre> - ... - [{label,[{_Node,TestType}]}, {config,CfgFiles}] = - ct:get_testspec_terms([label,config]), + ... + [{label,[{_Node,TestType}]}, {config,CfgFiles}] = + ct:get_testspec_terms([label,config]), - [verify_my_server_cfg(TestType, CfgFile) || {Node,CfgFile} <- CfgFiles, - Node == node()]; - ...</pre> + [verify_my_server_cfg(TestType, CfgFile) || {Node,CfgFile} <- CfgFiles, + Node == node()]; + ...</pre> </section> </section> <section> - <title>Running tests from the Web based GUI</title> + <title>Running Tests from the Web-Based GUI</title> - <p>The web based GUI, VTS, is started with the + <p>The web-based GUI, Virtual Test Server (VTS), is started with the <seealso marker="run_test_chapter#ct_run"><c>ct_run</c></seealso> - 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 - when starting the web based GUI. + program. From the GUI, you can load configuration files and select + directories, suites, and cases to run. You can also state the + configuration files, directories, suites, and cases on the command line + when starting the web-based GUI. </p> - - <list> + <p><em>Examples:</em></p> + <list type="bulleted"> <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> @@ -1062,454 +1163,464 @@ <p>From the GUI you can run tests and view the result and the logs. </p> - <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 + <p><c>ct_run -vts</c> tries to open the <c>Common Test</c> start + page in an existing web browser window, or start the browser if it is + not running. Which browser to start can be specified with the browser start command option:</p> <p><c><![CDATA[ct_run -vts -browser <browser_start_cmd>]]></c></p> - <p>Example:</p> + <p><em>Example:</em></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. - If Common Test fails to start a browser automatically, or <c>'none'</c> is - specified as the value for -browser (i.e. <c>-browser none</c>), start your - favourite browser manually and type in the URL that Common Test + + <note><p>The browser must run as a separate OS process, otherwise VTS hangs.</p></note> + + <p>If no specific browser start command is specified, Firefox is + the default browser on Unix platforms, and Internet Explorer on Windows. + If <c>Common Test</c> fails to start a browser automatically, or <c>none</c> is + specified as the value for <c>-browser</c> (that is, <c>-browser none</c>), start your + favourite browser manually and type the URL that <c>Common Test</c> displays in the shell.</p> </section> <section> <marker id="log_files"></marker> - <title>Log files</title> + <title>Log Files</title> <p>As the execution of the test suites proceed, events are logged in - four different ways:</p> + the following four different ways:</p> - <list> - <item>Text to the operator's console.</item> - <item>Suite related information is sent to the major log file.</item> - <item>Case related information is sent to the minor log file.</item> - <item>The HTML overview log file gets updated with test results.</item> + <list type="bulleted"> + <item>Text to the operator console.</item> + <item>Suite-related information is sent to the major log file.</item> + <item>Case-related information is sent to the minor log file.</item> + <item>The HTML overview log file is updated with test results.</item> <item>A link to all runs executed from a certain directory is written in - the log named "all_runs.html" and direct links to all tests (the - latest results) are written to the top level "index.html".</item> + the log named <c>all_runs.html</c> and direct links to all tests (the + latest results) are written to the top-level <c>index.html</c>.</item> </list> - <p>Typically the operator, who may run hundreds or thousands of - test cases, doesn't want to fill the console with details - about, or printouts from, the specific test cases. By default, the - operator will only see:</p> + <p>Typically the operator, possibly running hundreds or thousands of + test cases, does not want to fill the console with details + about, or printouts from, specific test cases. By default, the + operator only sees the following:</p> - <list> + <list type="bulleted"> <item>A confirmation that the test has started and information about how - many test cases will be executed totally.</item> + many test cases are executed in total.</item> <item>A small note about each failed test case.</item> <item>A summary of all the run test cases.</item> - <item>A confirmation that the test run is complete.</item> - <item>Some special information like error reports and progress - reports, printouts written with erlang:display/1, or io:format/3 + <item>A confirmation when the test run is complete.</item> + <item>Some special information, such as error reports, progress + reports, and printouts written with <c>erlang:display/1</c>, or <c>io:format/3</c> specifically addressed to a receiver other than <c>standard_io</c> - (e.g. the default group leader process 'user').</item> + (for example, the default group leader process <c>user</c>).</item> </list> - <p>If/when the operator wants to dig deeper into the general results, or - the result of a specific test case, he should do so by - following the links in the HTML presentation and take a look in the - major or minor log files. The "all_runs.html" page is a practical - starting point usually. It's located in <c>logdir</c> and contains - a link to each test run including a quick overview (date and time, - node name, number of tests, test names and test result totals).</p> + <p>To dig deeper into the general results, or + the result of a specific test case, the operator can do so by + following the links in the HTML presentation and read the + major or minor log files. The "all_runs.html" page is a good + starting point. It is located in <c>logdir</c> and contains + a link to each test run, including a quick overview (with date and time, + node name, number of tests, test names, and test result totals).</p> - <p>An "index.html" page is written for each test run (i.e. stored in - the "ct_run" directory tagged with node name, date and time). This - file gives a short overview of all individual tests performed in the - same test run. The test names follow this convention:</p> - <list> - <item><em>TopLevelDir.TestDir</em> (all suites in TestDir executed)</item> - <item><em>TopLevelDir.TestDir:suites</em> (specific suites were executed)</item> - <item><em>TopLevelDir.TestDir.Suite</em> (all cases in Suite executed)</item> - <item><em>TopLevelDir.TestDir.Suite:cases</em> (specific test cases were executed)</item> - <item><em>TopLevelDir.TestDir.Suite.Case</em> (only Case was executed)</item> + <p>An "index.html" page is written for each test run (that is, stored in + the <c>ct_run</c> directory tagged with node name, date, and time). This + file provides an overview of all individual tests performed in the + same test run. The test names follow the following convention:</p> + <list type="bulleted"> + <item><c>TopLevelDir.TestDir</c> (all suites in <c>TestDir</c> executed)</item> + <item><c>TopLevelDir.TestDir:suites</c> (specific suites executed)</item> + <item><c>TopLevelDir.TestDir.Suite</c> (all cases in <c>Suite</c> executed)</item> + <item><c>TopLevelDir.TestDir.Suite:cases</c> (specific test cases executed)</item> + <item><c>TopLevelDir.TestDir.Suite.Case</c> (only <c>Case</c> executed)</item> </list> - <p>On the test run index page there is a link to the Common Test + <p>The "test run index" page includes a link to the <c>Common Test</c> Framework Log file in which information about imported configuration data and general test progress is written. This log file is useful to get snapshot information about the test - run during execution. It can also be very helpful when + run during execution. It can also be helpful when analyzing test results or debugging test suites.</p> - <p>On the test run index page it is noted if a test has missing - suites (i.e. suites that Common Test has failed to + <p>The "test run index" page indicates if a test has missing + suites (that is, suites that <c>Common Test</c> failed to compile). Names of the missing suites can be found in the - Common Test Framework Log file.</p> + <c>Common Test</c> Framework Log file.</p> <p>The major log file shows a detailed report of the test run. It includes test suite and test case names, execution time, the - exact reason for failures etc. The information is available in both + exact reason for failures, and so on. The information is available in both a file with textual and with HTML representation. The HTML file shows a - summary which gives a good overview of the test run. It also has links + summary that gives a good overview of the test run. It also has links to each individual test case log file for quick viewing with an HTML browser.</p> <p>The minor log files contain full details of every single test - case, each one in a separate file. This way, it should be + case, each in a separate file. This way, it is straightforward to compare the latest results to that of previous - test runs, even if the set of test cases changes. If SASL is running, - its logs will also be printed to the current minor log file by the + test runs, even if the set of test cases changes. If application <c>SASL</c> + is running, its logs are also printed to the current minor log file by the <seealso marker="common_test:ct_hooks_chapter#builtin_cths"> cth_log_redirect built-in hook</seealso>. </p> - <p>The full name of the minor log file (i.e. the name of the file + <p>The full name of the minor log file (that is, the name of the file including the absolute directory path) can be read during execution - of the test case. It comes as value in the tuple + of the test case. It comes as value in tuple <c>{tc_logfile,LogFileName}</c> in the <c>Config</c> list (which means it - can also be read by a pre- or post Common Test hook function). Also, + can also be read by a pre- or post <c>Common Test Hook</c> function). Also, at the start of a test case, this data is sent with an event - to any installed event handler. Please see the - <seealso marker="event_handler_chapter#event_handling">Event Handling</seealso> - chapter for details. + to any installed event handler. For details, see section + <seealso marker="event_handler_chapter#event_handling">Event Handling</seealso>. </p> - - <p>Which information goes where is user configurable via the - test server controller. Three threshold values determine what - comes out on screen, and in the major or minor log files. See - the OTP Test Server manual for information. The contents that - goes to the HTML log file is fixed however and cannot be altered.</p> - - <p>The log files are written continously during a test run and links are - always created initially when a test starts. This makes it possible - to follow test progress simply by refreshing pages in the HTML browser. + + <p>The log files are written continuously during a test run and links are + always created initially when a test starts. Thevtest progress can therefore + be followed simply by refreshing pages in the HTML browser. Statistics totals are not presented until a test is complete however.</p> <section> <marker id="logopts"></marker> - <title>Log options</title> - <p>With the <c>logopts</c> start flag, it's possible to specify - options that modify some aspects of the logging behaviour. - Currently, the following options are available:</p> - <list> - <item><c>no_src</c></item> - <item><c>no_nl</c></item> - </list> - <p>With <c>no_src</c>, the html version of the test suite source - code will not be generated during the test run (and consequently - not be available in the log file system).</p> - <p>With <c>no_nl</c>, Common Test will not add a newline character - (\n) to the end of an output string that it receives from a call to e.g. - <c>io:format/2</c>, and which it prints to the test case log.</p> + <title>Log Options</title> + <p>With start flag <c>logopts</c> options that modify some aspects + of the logging behavior can be specified. + The following options are available:</p> + <taglist> + <tag><c>no_src</c></tag> + <item><p>The HTML version of the test suite source code is not + generated during the test run (and is consequently not available + in the log file system).</p></item> + <tag><c>no_nl</c></tag> + <item><p><c>Common Test</c> does not add a newline character <c>(\n)</c> + to the end of an output string that it receives from a call to, for example, + <c>io:format/2</c>, and which it prints to the test case log.</p></item> + </taglist> + <p>For example, if a test is started with:</p> <p><c>$ ct_run -suite my_SUITE -logopts no_src</c></p> <p>then printouts during the test made by successive calls to <c>io:format("x")</c>, - will appear in the test case log as:</p> + appears in the test case log as:</p> <p><c>xxx</c></p> - <p>instead of each <c>x</c> printed on a new line, which is the default behaviour.</p> + <p>instead of each <c>x</c> printed on a new line, which is the default behavior.</p> </section> <section> <marker id="table_sorting"></marker> - <title>Sorting HTML table columns</title> - <p>By clicking the name in the column header of any table (e.g. "Ok", "Case", "Time", etc), - the table rows are sorted in whatever order makes sense for the type of value (e.g. - numerical for "Ok" or "Time", and alphabetical for "Case"). The sorting is performed - by means of JavaScript code, automatically inserted into the HTML log files. Common Test - uses the <url href="http://jquery.com">jQuery</url> library and the - <url href="http://tablesorter.com">tablesorter</url> plugin, with customized sorting - functions, for this implementation.</p> + <title>Sorting HTML Table Columns</title> + <p>By clicking the name in the column header of any table + (for example, "Ok", "Case", "Time", and so on), the table rows are sorted + in whatever order makes sense for the type of value (for example, + numerical for "Ok" or "Time", and alphabetical for "Case"). The sorting is + performed through JavaScript code, automatically inserted into the HTML + log files. <c>Common Test</c> uses the <url href="http://jquery.com">jQuery</url> + library and the + <url href="http://tablesorter.com">tablesorter</url> plugin, + with customized sorting functions, for this implementation.</p> </section> <section> <title>The Unexpected I/O Log</title> - <p>On the test suites overview page you find a link to the Unexpected I/O Log. - In this log, Common Test saves printouts made with - <c>ct:log/2</c> and <c>ct:pal/2</c>, as well as captured system error- and - progress reports, that cannot be associated with particular test cases and - therefore cannot be written to individual test case log files. This happens e.g. - if a log printout is made from an external process (not a test case process), - or if an error- or progress report comes in, during a short interval while Common - Test is not executing a test case or configuration function, <em>or</em> while - Common Test is currently executing a parallell test case group.</p> + <p>The test suites overview page includes a link to the Unexpected I/O Log. + In this log, <c>Common Test</c> saves printouts made with + <seealso marker="ct#log-2"><c>ct:log/2</c></seealso> and + <seealso marker="ct#pal-2"><c>ct:pal/2</c></seealso>, as well as captured system + error- and progress reports, which cannot be associated with particular test cases and + therefore cannot be written to individual test case log files. This occurs, + for example, if a log printout is made from an external process (not a test + case process), <em>or</em> if an error- or progress report comes in, during a short + interval while <c>Common Test</c> is not executing a test case or configuration + function, <em>or</em> while <c>Common Test</c> is currently executing a parallel + test case group.</p> </section> <section> <marker id="pre_post_test_io_log"></marker> <title>The Pre- and Post Test I/O Log</title> - <p>On the Common Test Framework Log page you find links to the so called - Pre- and Post Test I/O Log. In this log, Common Test saves printouts made with - <c>ct:log/2</c> and <c>ct:pal/2</c>, as well as captured system error- - and progress reports, that take place before - and after - the actual test run. + <p>The <c>Common Test</c> Framework Log page includes links to the + Pre- and Post Test I/O Log. In this log, <c>Common Test</c> saves printouts made + with <c>ct:log/2</c> and <c>ct:pal/2</c>, as well as captured system error- + and progress reports, which take place before, and after, the test run. Examples of this are printouts from a CT hook init- or terminate function, or progress reports generated when an OTP application is started from a CT hook - init function. Another example is an error report generated due to + init function. Another example is an error report generated because of a failure when an external application is stopped from a CT hook terminate function. All information in these examples ends up in the Pre- and Post Test I/O Log. For more information on how to synchronize test runs with external user - applications, please see the + applications, see section <seealso marker="ct_hooks_chapter#synchronizing">Synchronizing</seealso> - section in the Common Test Hooks chapter.</p> - <p>Note that logging to file with <c>ct:log/2</c> or <c>ct:pal/2</c> - only works when Common Test is running. Printouts with <c>ct:pal/2</c> - are however always displayed on screen.</p> + in section Common Test Hooks.</p> + <note><p>Logging to file with <c>ct:log/2</c> or <c>ct:pal/2</c> + only works when <c>Common Test</c> is running. Printouts with <c>ct:pal/2</c> + are however always displayed on screen.</p></note> </section> </section> <section> <marker id="html_stylesheet"></marker> <title>HTML Style Sheets</title> - <p>Common Test uses an HTML Style Sheet (CSS file) to control the look of - the HTML log files generated during test runs. If, for some reason, the - log files are not displayed correctly in the browser of your - choice, or you prefer a more primitive ("pre Common Test v1.6") look - of the logs, use the start flag/option:</p> - <pre>basic_html</pre> - <p>This disables the use of Style Sheets, as well as JavaScripts (see - table sorting above).</p> + <p><c>Common Test</c> uses an HTML Style Sheet (CSS file) to control the look of + the HTML log files generated during test runs. If the log files are not + displayed correctly in the browser of your choice, or you prefer a more + primitive ("pre <c>Common Test</c> v1.6") look of the logs, use the start + flag/option:</p> + <pre> + basic_html</pre> + <p>This disables the use of style sheets and JavaScripts (see + <seealso marker="#table_sorting">Sorting HTML Table Columns</seealso>).</p> - <p>Common Test includes an <em>optional</em> feature to allow + <p><c>Common Test</c> includes an <em>optional</em> feature to allow user HTML style sheets for customizing printouts. The functions in <c>ct</c> that print to a test case HTML log file (<c>log/3</c> and <c>pal/3</c>) accept <c>Category</c> - as first argument. With this argument it's possible to - specify a category that can be mapped to a selector in a CSS - definition. This is useful especially for coloring text + as first argument. With this argument a category can be specified + that can be mapped to a selector in a CSS + definition. This is useful, especially for coloring text differently depending on the type of (or reason for) the printout. Say you want one color for test system configuration information, a different one for test system - state information and finally one for errors detected by the - test case functions. The corresponding style sheet may - look like this:</p> + state information, and finally one for errors detected by the + test case functions. The corresponding style sheet can + look as follows:</p> <pre> - div.sys_config { background:blue; color:white } - div.sys_state { background:yellow; color:black } - div.error { background:red; color:white }</pre> + div.sys_config { background:blue; color:white } + div.sys_state { background:yellow; color:black } + div.error { background:red; color:white }</pre> - <p>To install the CSS file (Common Test inlines the definition in the - HTML code), the name may be provided when executing <c>ct_run</c>. - Example:</p> + <p>To install the CSS file (<c>Common Test</c> inlines the definition in the + HTML code), the name can be provided when executing <c>ct_run</c>.</p> + <p><em>Example:</em></p> <pre> - $ ct_run -dir $TEST/prog -stylesheet $TEST/styles/test_categories.css</pre> + $ 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 + <p>Categories in a CSS file installed with flag <c>-stylesheet</c> are on a global test level in the sense that they can be used in any - suite which is part of the test run.</p> + suite that is part of the test run.</p> - <p>It is also possible to install style sheets on a per suite and - per test case basis. Example:</p> + <p>Style sheets can also be installed on a per suite and + per test case basis.</p> + <p><em>Example:</em></p> <pre> - -module(my_SUITE). - ... - suite() -> [..., {stylesheet,"suite_categories.css"}, ...]. - ... - my_testcase(_) -> - ... - ct:log(sys_config, "Test node version: ~p", [VersionInfo]), - ... - ct:log(sys_state, "Connections: ~p", [ConnectionInfo]), - ... - ct:pal(error, "Error ~p detected! Info: ~p", [SomeFault,ErrorInfo]), - ct:fail(SomeFault).</pre> + -module(my_SUITE). + ... + suite() -> [..., {stylesheet,"suite_categories.css"}, ...]. + ... + my_testcase(_) -> + ... + ct:log(sys_config, "Test node version: ~p", [VersionInfo]), + ... + ct:log(sys_state, "Connections: ~p", [ConnectionInfo]), + ... + ct:pal(error, "Error ~p detected! Info: ~p", [SomeFault,ErrorInfo]), + ct:fail(SomeFault).</pre> <p>If the style sheet is installed as in this example, the categories are private to the suite in question. They can be used by all test cases in the - suite, but can not be used by other suites. A suite private style sheet, - if specified, will be used in favour of a global style sheet (one specified - with the <c>-stylesheet</c> flag). A stylesheet tuple (as returned by <c>suite/0</c> - above) can also be returned from a test case info function. In this case the + suite, but cannot be used by other suites. A suite private style sheet, + if specified, is used in favor of a global style sheet (one specified + with flag <c>-stylesheet</c>). A stylesheet tuple (as returned by <c>suite/0</c> + above) can also be returned from a test case information function. In this case the categories specified in the style sheet can only be used in that particular - test case. A test case private style sheet is used in favour of a suite or + test case. A test case private style sheet is used in favor of a suite or global level style sheet. </p> <p>In a tuple <c>{stylesheet,CSSFile}</c>, if <c>CSSFile</c> is specified - with a path, e.g. <c>"$TEST/styles/categories.css"</c>, this full - name will be used to locate the file. If only the file name is specified - however, e.g. "categories.css", then the CSS file is assumed to be located - in the data directory, <c>data_dir</c>, of the suite. The latter usage is - recommended since it is portable compared to hard coding path names in the - suite!</p> - - <p>The <c>Category</c> argument in the example above may have the + with a path, for example, <c>"$TEST/styles/categories.css"</c>, this full + name is used to locate the file. However, if only the file name is specified, + for example, <c>categories.css</c>, the CSS file is assumed to be located + in the data directory, <c>data_dir</c>, of the suite. The latter use is + recommended, as it is portable compared to hard coding path names in the + suite.</p> + + <p>Argument <c>Category</c> in the previous example can have the value (atom) <c>sys_config</c> (white on blue), <c>sys_state</c> - (black on yellow) or <c>error</c> (white on red).</p> + (black on yellow), or <c>error</c> (white on red).</p> </section> <section> <marker id="repeating_tests"></marker> - <title>Repeating tests</title> - <p>You can order Common Test to repeat the tests you specify. You can choose - to repeat tests a certain number of times, repeat tests for a specific period of time, + <title>Repeating Tests</title> + <p>You can order <c>Common Test</c> to repeat the tests you specify. You can choose + to repeat tests a number of times, repeat tests for a specific period of time, or repeat tests until a particular stop time is reached. If repetition is controlled by - 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>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> - <item><c>-duration DurTime ({duration,DurTime})</c>, where <c>DurTime</c> is the duration, see below.</item> - <item><c>-until StopTime ({until,StopTime})</c>, where <c>StopTime</c> is finish time, see below.</item> + time, an action for <c>Common Test</c> to take upon time-out can be specified. + Either <c>Common Test</c> performs all tests in the current run + before stopping, or it stops when the current test job is finished. Repetition + can be activated by <c>ct_run</c> start flags, or tuples in the <c>ct:run:test/1</c> + option list argument. The flags (options in parentheses) are the following:</p> + <list type="bulleted"> + <item><c>-repeat N ({repeat,N})</c>, where <c>N</c> is a positive integer</item> + <item><c>-duration DurTime ({duration,DurTime})</c>, where <c>DurTime</c> is the duration</item> + <item><c>-until StopTime ({until,StopTime})</c>, where <c>StopTime</c> is finish time</item> <item><c>-force_stop ({force_stop,true})</c></item> <item><c>-force_stop skip_rest ({force_stop,skip_rest})</c></item> </list> - <p>The duration time, <c>DurTime</c>, is specified as <c>HHMMSS</c>. Example: - <c>-duration 012030</c> or <c>{duration,"012030"}</c>, means the tests will - be executed and (if time allows) repeated, until timeout occurs after 1 h, 20 min - and 30 secs. - <c>StopTime</c> can be specified as <c>HHMMSS</c> and is then interpreted as a time today - (or possibly tomorrow). <c>StopTime</c> can also be specified as <c>YYMoMoDDHHMMSS</c>. - Example: <c>-until 071001120000</c> or <c>{until,"071001120000"}</c>, which means the tests - will be executed and (if time allows) repeated, until 12 o'clock on the 1st of Oct 2007.</p> - - <p>When timeout occurs, Common Test will never abort the ongoing test case, since - this might leave the system under test in an undefined, and possibly bad, state. - Instead Common Test will by default finish the current test - run before stopping. If the <c>force_stop</c> flag is - given, Common Test will stop as soon as the current test job - is finished, and if the <c>force_stop</c> flag is given with - <c>skip_rest</c> Common Test will only complete the current - test case and skip the rest of the tests in the test job. - Note that since Common Test always finishes off at least the - current test case, - the time specified with <c>duration</c> or <c>until</c> is never definitive!</p> - - <p>Log files from every single repeated test run is saved in normal Common Test fashion (see above). - Common Test may later support an optional feature to only store the last (and possibly - the first) set of logs of repeated test runs, but for now the user must be careful not - to run out of disk space if tests are repeated during long periods of time.</p> - - <p>Note that for each test run that is part of a repeated session, information about the - particular test run is printed in the Common Test Framework Log. There you can read - the repetition number, remaining time, etc.</p> - - <p>Example 1:</p> + <taglist> + <tag><c>DurTime</c></tag> + <item><p>The duration time is specified as <c>HHMMSS</c>, for example, <c>-duration 012030</c> + or <c>{duration,"012030"}</c></p>, which means that the tests are executed and + (if time allows) repeated until time-out occurs after 1 hour, 20 minutes, and 30 seconds. + </item> + <tag><c>StopTime</c></tag> + <item><p>The finish time can be specified as <c>HHMMSS</c> and is then interpreted as a + time today (or possibly tomorrow), but can also be specified as <c>YYMoMoDDHHMMSS</c>, + for example, <c>-until 071001120000</c> or <c>{until,"071001120000"}</c>. This means + that the tests are executed and (if time allows) repeated, until 12 o'clock on the 1st + of October 2007.</p> + </item> + </taglist> + + <p>When time-out occurs, <c>Common Test</c> never aborts the ongoing test case, + as this can leave the SUT in an undefined, and possibly bad, state. + Instead <c>Common Test</c>, by default, finishes the current test + run before stopping. If flag <c>force_stop</c> is + specified, <c>Common Test</c> stops when the current test job + is finished. If flag <c>force_stop</c> is specified with + <c>skip_rest</c>, <c>Common Test</c> only completes the current + test case and skips the remaining tests in the test job.</p> + <note><p>As <c>Common Test</c> always finishes at least the current test case, + the time specified with <c>duration</c> or <c>until</c> is never definitive.</p></note> + + <p>Log files from every repeated test run is saved in normal <c>Common Test</c> + fashion (described earlier).</p> + <p><c>Common Test</c> might later support an optional feature to only store the last (and possibly + the first) set of logs of repeated test runs, but for now the user must be careful not + to run out of disk space if tests are repeated during long periods of time.</p> + + <p>For each test run that is part of a repeated session, information about the + particular test run is printed in the <c>Common Test</c> Framework Log. The information + includes the repetition number, remaining time, and so on.</p> + + <p><em>Example 1:</em></p> <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). - When the timeout occurs, Common Test will stop as soon as the current job is finished - (because of the <c>force_stop</c> flag). As a result, the specified test run might be - aborted after the to1 test and before the to2 test.</p> - - <p>Example 2:</p> + $ ct_run -dir $TEST_ROOT/to1 $TEST_ROOT/to2 -duration 001000 -force_stop</pre> + + <p>Here, the suites in test directory <c>to1</c>, followed by the suites in <c>to2</c>, are + executed in one test run. A time-out event occurs after 10 minutes. As long as there is + time left, <c>Common Test</c> repeats the test run (that is, starting over with test <c>to1</c>). + After time-out, <c>Common Test</c> stops when the current job is finished + (because of flag <c>force_stop</c>). As a result, the specified test run can be + aborted after test <c>to1</c> and before test <c>to2</c>.</p> + + <p><em>Example 2:</em></p> <pre> - $ ct_run -dir $TEST_ROOT/to1 $TEST_ROOT/to2 -duration 001000 -forces_stop skip_rest</pre> - <p>Here the same test run as in Example 1, but with the - <c>force_stop</c> flag set to <c>skip_rest</c>. If the timeout - occurs while executing tests in directory to1, the rest of the - test cases in to1 will be skipped and then the test will be - aborted without running the tests in to2 another time. If the - timeout occurs while executing tests in directory to2, then the - rest of the test cases in to2 will be skipped and then the test - will be aborted.</p> - - <p>Example 3:</p> + $ ct_run -dir $TEST_ROOT/to1 $TEST_ROOT/to2 -duration 001000 -forces_stop skip_rest</pre> + + <p>Here, the same tests as in Example 1 are run, but with flag <c>force_stop</c> set to + <c>skip_rest</c>. If time-out occurs while executing tests in directory <c>to1</c>, + the remaining test cases in <c>to1</c> are skipped and the test is aborted without + running the tests in <c>to2</c> another time. If time-out occurs while executing + tests in directory <c>to2</c>, the remaining test cases in <c>to2</c> are skipped and + the test is aborted.</p> + + <p><em>Example 3:</em></p> <pre> - $ date - Fri Sep 28 15:00:00 MEST 2007 - - $ 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 - will always both be executed in the same test run).</p> + $ date + Fri Sep 28 15:00:00 MEST 2007 + + $ ct_run -dir $TEST_ROOT/to1 $TEST_ROOT/to2 -until 160000</pre> + + <p>Here, the same test run as in the previous examples are executed (and possibly repeated). + However, when the time-out occurs, after 1 hour, <c>Common Test</c> finishes the entire + test run before stopping (that is, both <c>to1</c> and <c>to2</c> are always executed in + the same test run).</p> - <p>Example 4:</p> + <p><em>Example 4:</em></p> <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> + $ ct_run -dir $TEST_ROOT/to1 $TEST_ROOT/to2 -repeat 5</pre> + + <p>Here, the test run, including both the <c>to1</c> and the <c>to2</c> test, is repeated + five times.</p> - <note><p>This feature should not be confused with the <c>repeat</c> property of a test + <note><p>Do not confuse this feature with the <c>repeat</c> property of a test case group. The options described here are used to repeat execution of entire test runs, while the <c>repeat</c> property of a test case group makes it possible to repeat execution of sets of test cases within a suite. For more information about the latter, - see the <seealso marker="write_test_chapter#test_case_groups">Writing Test Suites</seealso> - chapter.</p></note> + see section <seealso marker="write_test_chapter#test_case_groups">Test Case Groups </seealso> + in section Writing Test Suites.</p></note> </section> <section> <marker id="silent_connections"></marker> <title>Silent Connections</title> - <p>The protocol handling processes in Common Test, implemented by ct_telnet, - ct_ssh, ct_ftp etc, do verbose printing to the test case logs. This can be switched off - by means of the <c>-silent_connections</c> flag:</p> + <p>The protocol handling processes in <c>Common Test</c>, implemented by <c>ct_telnet</c>, + <c>ct_ssh</c>, <c>ct_ftp</c>, and so on, do verbose printing to the test case logs. + This can be switched off with flag <c>-silent_connections</c>:</p> <pre> - ct_run -silent_connections [conn_types] - </pre> + ct_run -silent_connections [conn_types]</pre> - <p>where <c>conn_types</c> specifies <c>ssh, telnet, ftp, rpc</c> and/or <c>snmp</c>.</p> + <p>Here, <c>conn_types</c> specifies SSH, Telnet, FTP, RPC, and/or SNMP.</p> - <p>Example:</p> + <p><em>Example 1:</em></p> <pre> - ct_run ... -silent_connections ssh telnet</pre> - <p>switches off logging for ssh and telnet connections.</p> + ct_run ... -silent_connections ssh telnet</pre> + <p>This switches off logging for SSH and Telnet connections.</p> + + <p><em>Example 2:</em></p> <pre> - ct_run ... -silent_connections</pre> - <p>switches off logging for all connection types.</p> + ct_run ... -silent_connections</pre> + <p>This switches off logging for all connection types.</p> - <p>Fatal communication error and reconnection attempts will always be printed even - if logging has been suppressed for the connection type in question. However, operations - such as sending and receiving data will be performed silently.</p> + <p>Fatal communication error and reconnection attempts are always printed, even if + logging has been suppressed for the connection type in question. However, operations + such as sending and receiving data are performed silently.</p> - <p>It is possible to also specify <c>silent_connections</c> in a test suite. This is + <p><c>silent_connections</c> can also be specified in a test suite. This is accomplished by returning a tuple, <c>{silent_connections,ConnTypes}</c>, in the - <c>suite/0</c> or test case info list. If <c>ConnTypes</c> is a list of atoms - (<c>ssh, telnet, ftp, rpc</c> and/or <c>snmp</c>), output for any corresponding connections - will be suppressed. Full logging is per default enabled for any connection of type not + <c>suite/0</c> or test case information list. If <c>ConnTypes</c> is a list of atoms + (SSH, Telnet, FTP, RPC and/or SNMP), output for any corresponding connections + are suppressed. Full logging is by default enabled for any connection of type not specified in <c>ConnTypes</c>. Hence, if <c>ConnTypes</c> is the empty list, logging is enabled for all connections.</p> - <p>Example:</p> + <p><em>Example 3:</em></p> <pre> - - -module(my_SUITE). + -module(my_SUITE). - suite() -> [..., {silent_connections,[telnet,ssh]}, ...]. + suite() -> [..., {silent_connections,[telnet,ssh]}, ...]. - ... + ... - my_testcase1() -> - [{silent_connections,[ssh]}]. + my_testcase1() -> + [{silent_connections,[ssh]}]. - my_testcase1(_) -> - ... + my_testcase1(_) -> + ... - my_testcase2(_) -> - ... - </pre> + my_testcase2(_) -> + ...</pre> - <p>In this example, <c>suite/0</c> tells Common Test to suppress - printouts from telnet and ssh connections. This is valid for + <p>In this example, <c>suite/0</c> tells <c>Common Test</c> to suppress + printouts from Telnet and SSH connections. This is valid for all test cases. However, <c>my_testcase1/0</c> specifies that - for this test case, only ssh should be silent. The result is - that <c>my_testcase1</c> will get telnet info (if any) printed - in the log, but not ssh info. <c>my_testcase2</c> will get no - info from either connection printed.</p> + for this test case, only SSH is to be silent. The result is + that <c>my_testcase1</c> gets Telnet information (if any) printed + in the log, but not SSH information. <c>my_testcase2</c> gets no + information from either connection printed.</p> - <p><c>silent_connections</c> may also be specified with a term + <p><c>silent_connections</c> can also be specified with a term in a test specification - (see <seealso marker="run_test_chapter#test_specifications">Test - Specifications</seealso>). Connections provided with the - <c>silent_connections</c> start flag/option, will be merged with - any connections listed in the test specification.</p> + (see section <seealso marker="run_test_chapter#test_specifications">Test + Specifications</seealso> in section Running Tests and Analyzing Results). + Connections provided with start flag/option <c>silent_connections</c> + are merged with any connections listed in the test specification.</p> - <p>The <c>silent_connections</c> start flag/option and test - specification term, overrides any settings made by the info functions + <p>Start flag/option <c>silent_connections</c> and the test + specification term override any settings made by the information functions inside the test suite.</p> - <note><p>Note that in the current Common Test version, the - <c>silent_connections</c> feature only works for telnet - and ssh connections! Support for other connection types will be added - in future Common Test versions.</p></note> + <note><p>In the current <c>Common Test</c> version, the + <c>silent_connections</c> feature only works for Telnet + and SSH connections. Support for other connection types can be added + in future <c>Common Test</c> versions.</p></note> </section> </chapter> diff --git a/lib/common_test/doc/src/test_structure_chapter.xml b/lib/common_test/doc/src/test_structure_chapter.xml index d5b92b163f..8076244928 100644 --- a/lib/common_test/doc/src/test_structure_chapter.xml +++ b/lib/common_test/doc/src/test_structure_chapter.xml @@ -31,167 +31,167 @@ </header> <section> - <title>Test structure</title> + <title>General</title> <p>A test is performed by running one or more test suites. A test suite - consists of test cases (as well as configuration functions and info - functions). Test cases may be grouped in so called test case groups. + consists of test cases, configuration functions, and information + functions. Test cases can be grouped in so called test case groups. A test suite is an Erlang module and test cases are implemented as Erlang functions. Test suites are stored in test directories.</p> </section> <section> - <title>Skipping test cases</title> + <marker id="skipping_test_cases"></marker> + <title>Skipping Test Cases</title> - <p>It is possible to skip certain test cases, for example if you - know beforehand that a specific test case fails. This might be - functionality which isn't yet implemented, a bug that is known but - not yet fixed or some functionality which doesn't work or isn't + <p>Certain test cases can be skipped, for example, if you + know beforehand that a specific test case fails. The reason can be + functionality that is not yet implemented, a bug that is known but + not yet fixed, or some functionality that does not work or is not applicable on a specific platform.</p> - <p>There are several different ways to state that one or more - test cases should be skipped:</p> - <list> + <p>Test cases can be skipped in the following ways:</p> + <list type="bulleted"> <item>Using <c>skip_suites</c> and <c>skip_cases</c> terms in <seealso marker="run_test_chapter#test_specifications">test specifications</seealso>. </item> - <item>Returning <c>{skip,Reason}</c> from the - <c>init_per_testcase/2</c> or <c>init_per_suite/1</c> functions.</item> + <item>Returning <c>{skip,Reason}</c> from function + <seealso marker="common_test#Module:init_per_testcase-2"><c>init_per_testcase/2</c></seealso> or + <seealso marker="common_test#Module:init_per_suite-1"><c>init_per_suite/1</c></seealso>.</item> <item>Returning <c>{skip,Reason}</c> from the execution clause - of the test case.</item> + of the test case. The execution clause is called, so the author + must ensure that the test case does not run.</item> </list> - <p>The latter of course means that the execution clause is - actually called, so the author must make sure that the test case - does not run.</p> - - <p>When a test case is skipped, it will be noted as <c>SKIPPED</c> + <p>When a test case is skipped, it is noted as <c>SKIPPED</c> in the HTML log.</p> </section> <section> - <title>Definition of terms</title> + <title>Definition of Terms</title> <taglist> - <tag><em>Auto skipped test case</em></tag> + <tag><em>Auto-skipped test case</em></tag> <item> - When a configuration function fails (i.e. terminates unexpectedly), - the test cases that depend on the configuration function will be - skipped automatically by Common Test. The status of the test cases - is then "auto skipped". Test cases are also auto skipped by - Common Test if required configuration data is not available at - runtime. + <p>When a configuration function fails (that is, terminates unexpectedly), + the test cases depending on the configuration function are + skipped automatically by <c>Common Test</c>. The status of the test cases + is then "auto-skipped". Test cases are also "auto-skipped" by + <c>Common Test</c> if the required configuration data is unavailable at + runtime.</p> </item> <tag><em>Configuration function</em></tag> <item> - A function in a test suite that is meant to be used for + <p>A function in a test suite that is meant to be used for setting up, cleaning up, and/or verifying the state and - environment on the SUT (System Under Test) and/or the Common Test + environment on the System Under Test (SUT) and/or the <c>Common Test</c> host node, so that a test case (or a set of test cases) can - execute correctly. + execute correctly.</p> </item> <tag><em>Configuration file</em></tag> <item> - A file that contains data related to a test and/or an SUT - (System Under Test), e.g. protocol server addresses, client - login details, hardware interface addresses, etc - any data - that should be handled as variable in the suite and not - be hardcoded. + <p>A file containing data related to a test and/or an SUT, + for example, protocol server addresses, client + login details, and hardware interface addresses. That is, any data + that is to be handled as variable in the suite and not + be hard-coded.</p> </item> <tag><em>Configuration variable</em></tag> <item> - A name (an Erlang atom) associated with a data value read from - a configuration file. + <p>A name (an Erlang atom) associated with a data value read from + a configuration file.</p> </item> - <tag><em>data_dir</em></tag> + <tag><c>data_dir</c></tag> <item> - Data directory for a test suite. This directory contains - any files used by the test suite, e.g. additional Erlang - modules, binaries or data files. + <p>Data directory for a test suite. This directory contains + any files used by the test suite, for example, extra Erlang + modules, binaries, or data files.</p> </item> - <tag><em>Info function</em></tag> + <tag><em>Information function</em></tag> <item> - A function in a test suite that returns a list of properties - (read by the Common Test server) that describes the conditions - for executing the test cases in the suite. + <p>A function in a test suite that returns a list of properties + (read by the <c>Common Test</c> server) that describes the conditions + for executing the test cases in the suite.</p> </item> <tag><em>Major log file</em></tag> <item> - An overview and summary log file for one or more test suites. + <p>An overview and summary log file for one or more test suites.</p> </item> <tag><em>Minor log file</em></tag> <item> - A log file for one particular test case. Also called the - test case log file. + <p>A log file for one particular test case. Also called the + test case log file.</p> </item> - <tag><em>priv_dir</em></tag> + + <tag><c>priv_dir</c></tag> <item> - Private directory for a test suite. This directory should - be used when the test suite needs to write to files. + <p>Private directory for a test suite. This directory is to + be used when the test suite needs to write to files.</p> </item> - <tag><em>ct_run</em></tag> + <tag><c>ct_run</c></tag> <item> - The name of an executable program that may be + <p>The name of an executable program that can be used as an interface for specifying and running - tests with Common Test. + tests with <c>Common Test</c>.</p> </item> <tag><em>Test case</em></tag> <item> - A single test included in a test suite. A test case is - implemented as a function in a test suite module. + <p>A single test included in a test suite. A test case is + implemented as a function in a test suite module.</p> </item> <tag><em>Test case group</em></tag> <item> - A set of test cases that share configuration functions and - execution properties. The execution properties specify whether - the test cases in the group should be executed in random order, - in parallel, in sequence, and if the execution of the group - should be repeated. Test case groups may also be nested (i.e. a - group may, besides test cases, contain sub-groups). + <p>A set of test cases sharing configuration functions and + execution properties. The execution properties specify if + the test cases in the group are to be executed in random order, + in parallel, or in sequence, and if the execution of the group + is be repeated. Test case groups can also be nested. That is, + a group can, besides test cases, contain subgroups.</p> </item> <tag><em>Test suite</em></tag> <item> - An erlang module containing a collection of test cases for - a specific functional area. + <p>An Erlang module containing a collection of test cases for + a specific functional area.</p> </item> <tag><em>Test directory</em></tag> <item> - A directory that contains one or more test suite modules, i.e. - a group of test suites. + <p>A directory containing one or more test suite modules, + that is, a group of test suites.</p> </item> - <tag><em>The Config argument</em></tag> + <tag><em>Argument</em> <c>Config</c></tag> <item> - A list of key-value tuples (i.e. a property list) containing + <p>A list of key-value tuples (that is, a property list) containing runtime configuration data passed from the configuration - functions to the test cases. + functions to the test cases.</p> </item> - <tag><em>User skipped test case</em></tag> + <tag><em>User-skipped test case</em></tag> <item> - This is the status of a test case that has been explicitly - skipped in any of the ways described in the "Skipping test cases" - section above. + <p>The status of a test case explicitly skipped in any of + the ways described in section + <seealso marker="#skipping_test_cases">Skipping Test Cases</seealso>. + </p> </item> diff --git a/lib/common_test/doc/src/unix_telnet.xml b/lib/common_test/doc/src/unix_telnet.xml new file mode 100644 index 0000000000..a064a222d6 --- /dev/null +++ b/lib/common_test/doc/src/unix_telnet.xml @@ -0,0 +1,135 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2010</year><year>2012</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + </legalnotice> + + <title>unix_telnet</title> + <prepared></prepared> + <responsible></responsible> + <docno></docno> + <approved></approved> + <checked></checked> + <date></date> + <rev>A</rev> + <file>unix_telnet.xml</file> + </header> + <module>unix_telnet</module> + <modulesummary>Callback module for ct_telnet, for connecting to a Telnet + server on a UNIX host.</modulesummary> + + <description> + + <p>Callback module for + <seealso marker="ct_telnet"><c>ct_telnet</c></seealso>, + for connecting to a Telnet server on a UNIX host.</p> + + <p>It requires the following entry in the configuration file:</p> + + <pre> + {unix,[{telnet,HostNameOrIpAddress}, + {port,PortNum}, % optional + {username,UserName}, + {password,Password}, + {keep_alive,Bool}]}. % optional</pre> + + <p>To communicate through Telnet to the host specified by + <c>HostNameOrIpAddress</c>, use the interface functions in + <seealso marker="ct_telnet"><c>ct_telnet</c></seealso>, for example, + <c>open(Name)</c> and <c>cmd(Name,Cmd)</c>.</p> + + <p><c>Name</c> is the name you allocated to the Unix host in your + <c>require</c> statement, for example:</p> + + <pre> + suite() -> [{require,Name,{unix,[telnet]}}].</pre> + + <p>or</p> + + <pre> + ct:require(Name,{unix,[telnet]}).</pre> + + <p>The "keep alive" activity (that is, that <c>Common Test</c> sends NOP + to the server every 10 seconds if the connection is idle) can be + enabled or disabled for one particular connection as described here. + It can be disabled for all connections using <c>telnet_settings</c> + (see <seealso marker="ct_telnet"><c>ct_telnet</c></seealso>).</p> + + <p>The <c>{port,PortNum}</c> tuple is optional and if omitted, default + Telnet port 23 is used. Also the <c>keep_alive</c> tuple is optional, + and the value defauls to <c>true</c> (enabled).</p> + </description> + + <funcs> + <func> + <name>connect(ConnName, Ip, Port, Timeout, KeepAlive, TCPNoDelay, Extra) -> {ok, Handle} | {error, Reason}</name> + <fsummary>Callback for ct_telnet.erl.</fsummary> + <type> + <v>ConnName = target_name()</v> + <v>Ip = string() | {integer(), integer(), integer(), integer()}</v> + <v>Port = integer()</v> + <v>Timeout = integer()</v> + <v>KeepAlive = bool()</v> + <v>TCPNoDelay = bool()</v> + <v>Extra = target_name() | {Username, Password}</v> + <v>Username = string()</v> + <v>Password = string()</v> + <v>Handle = handle()</v> + <v>Reason = term()</v> + </type> + <desc><marker id="connect-6"/> + <p>Callback for <c>ct_telnet.erl</c>.</p> + + <p>Setup Telnet connection to a Unix host.</p> + + <p>For <c>target_name()</c>, see + <seealso marker="ct"><c>ct</c></seealso>. For <c>handle()</c>, see + <seealso marker="ct_telnet"><c>ct_telnet</c></seealso>.</p> + </desc> + </func> + + <func> + <name>get_prompt_regexp() -> PromptRegexp</name> + <fsummary>Callback for ct_telnet.erl.</fsummary> + <type> + <v>PromptRegexp = prompt_regexp()</v> + </type> + <desc><marker id="get_prompt_regexp-0"/> + <p>Callback for <c>ct_telnet.erl</c>.</p> + + <p>Returns a suitable <c>regexp</c> string matching common prompts + for users on Unix hosts.</p> + + <p>For <c>prompt_regexp()</c>, see + <seealso marker="ct_telnet"><c>ct_telnet</c></seealso>.</p> + </desc> + </func> + </funcs> + + <section> + <title>See Also</title> + <p><seealso marker="ct"><c>ct</c></seealso>, + <seealso marker="ct_telnet"><c>ct_telnet</c></seealso></p> + </section> + +</erlref> + + diff --git a/lib/common_test/doc/src/why_test_chapter.xml b/lib/common_test/doc/src/why_test_chapter.xml index 15eb1aaed4..ff6000628b 100644 --- a/lib/common_test/doc/src/why_test_chapter.xml +++ b/lib/common_test/doc/src/why_test_chapter.xml @@ -22,7 +22,7 @@ </legalnotice> - <title>Some thoughts about testing</title> + <title>Some Thoughts about Testing</title> <prepared>Siri Hansen</prepared> <docno></docno> <date></date> @@ -34,54 +34,53 @@ <section> <title>Goals</title> - <p>It's not possible to prove that a program is correct by + <p>It is not possible to prove that a program is correct by testing. On the contrary, it has been formally proven that it is impossible to prove programs in general by testing. Theoretical - program proofs or plain examination of code may be viable options - for those that wish to certify that a program is correct. The test + program proofs or plain examination of code can be viable options + for those wishing to certify that a program is correct. The test server, as it is based on testing, cannot be used for certification. Its intended use is instead to (cost effectively) <em>find bugs</em>. A successful test suite is one that reveals a - bug. If a test suite results in Ok, then we know very little that - we didn't know before.</p> + bug. If a test suite results in OK, then we know very little that + we did not know before.</p> </section> <section> - <title>What to test?</title> + <title>What to Test</title> <p> There are many kinds of test suites. Some concentrate on calling every function or command (in the documented way) in a certain interface. - Some other do the same, but uses all kinds of illegal - parameters, and verifies that the server stays alive and rejects + Some others do the same, but use all kinds of illegal + parameters, and verify that the server stays alive and rejects the requests with reasonable error codes. Some test suites simulate an application (typically consisting of a few modules of - an application), some try to do tricky requests in general, some + an application), some try to do tricky requests in general, and some test suites even test internal functions with help of special - load-modules on target.</p> + Load Modules on target.</p> - <p>Another interesting category of test suites are the ones that - check that fixed bugs don't reoccur. When a bugfix is introduced, - a test case that checks for that specific bug should be written - and submitted to the affected test suite(s).</p> + <p>Another interesting category of test suites is the one + checking that fixed bugs do not reoccur. When a bugfix is introduced, + a test case that checks for that specific bug is written + and submitted to the affected test suites.</p> <p>Aim for finding bugs. Write whatever test that has the highest probability of finding a bug, now or in the future. Concentrate - more on the critical parts. Bugs in critical subsystems are a lot + more on the critical parts. Bugs in critical subsystems are much more expensive than others.</p> <p>Aim for functionality testing rather than implementation details. Implementation details change quite often, and the test - suites should be long lived. Often implementation details differ + suites are to be long lived. Implementation details often differ on different platforms and versions. If implementation details - have to be tested, try to factor them out into separate test - cases. Later on these test cases may be rewritten, or just - skipped.</p> + must be tested, try to factor them out into separate test + cases. These test cases can later be rewritten or skipped.</p> - <p>Also, aim for testing everything once, no less, no more. It's - not effective having every test case fail just because one + <p>Also, aim for testing everything once, no less, no more. It is + not effective having every test case fail only because one function in the interface changed.</p> </section> diff --git a/lib/common_test/doc/src/write_test_chapter.xml b/lib/common_test/doc/src/write_test_chapter.xml index 1f5650651f..a7a652d506 100644 --- a/lib/common_test/doc/src/write_test_chapter.xml +++ b/lib/common_test/doc/src/write_test_chapter.xml @@ -32,84 +32,88 @@ <section> <marker id="intro"></marker> - <title>Support for test suite authors</title> + <title>Support for Test Suite Authors</title> - <p>The <c>ct</c> module provides the main interface for writing - test cases. This includes e.g:</p> + <p>The <seealso marker="ct"><c>ct</c></seealso> module provides the main + interface for writing test cases. This includes for example, the following:</p> - <list> + <list type="bulleted"> <item>Functions for printing and logging</item> <item>Functions for reading configuration data</item> <item>Function for terminating a test case with error reason</item> <item>Function for adding comments to the HTML overview page</item> </list> - <p>Please see the reference manual for the <c>ct</c> - module for details about these functions.</p> + <p>For details about these functions, see module <seealso marker="ct"><c>ct</c></seealso>.</p> - <p>The CT application also includes other modules named - <c><![CDATA[ct_<component>]]></c> that + <p>The <c>Common Test</c> application also includes other modules named + <c><![CDATA[ct_<component>]]></c>, which provide various support, mainly simplified use of communication - protocols such as rpc, snmp, ftp, telnet, etc.</p> + protocols such as RPC, SNMP, FTP, Telnet, and others.</p> </section> <section> - <title>Test suites</title> + <title>Test Suites</title> <p>A test suite is an ordinary Erlang module that contains test cases. It is recommended that the module has a name on the form <c>*_SUITE.erl</c>. Otherwise, the directory and auto compilation - function in CT will not be able to locate it (at least not per default). + function in <c>Common Test</c> cannot locate it (at least not by default). </p> <p>It is also recommended that the <c>ct.hrl</c> header file is included in all test suite modules. </p> - <p>Each test suite module must export the function <c>all/0</c> + <p>Each test suite module must export function + <seealso marker="common_test#Module:all-0"><c>all/0</c></seealso>, which returns the list of all test case groups and test cases to be executed in that module. </p> - <p>The callback functions that the test suite should implement, and - which will be described in more detail below, are - all listed in the <seealso marker="common_test">common_test - reference manual page</seealso>. + <p>The callback functions to be implemented by the test suite are + all listed in module <seealso marker="common_test">common_test + </seealso>. They are also described in more detail later in this User's Guide. </p> </section> <section> - <title>Init and end per suite</title> + <title>Init and End per Suite</title> - <p>Each test suite module may contain the optional configuration functions - <c>init_per_suite/1</c> and <c>end_per_suite/1</c>. If the init function - is defined, so must the end function be. + <p>Each test suite module can contain the optional configuration functions + <seealso marker="common_test#Module:init_per_suite-1"><c>init_per_suite/1</c></seealso> + and <seealso marker="common_test#Module:end_per_suite-1"><c>end_per_suite/1</c></seealso>. + If the init function is defined, so must the end function be. </p> - <p>If it exists, <c>init_per_suite</c> is called initially before the - test cases are executed. It typically contains initializations that are - common for all test cases in the suite, and that are only to be - performed once. It is recommended to be used for setting up and - verifying state and environment on the SUT (System Under Test) and/or - the CT host node, so that the test cases in the suite will execute - correctly. Examples of initial configuration operations: Opening a connection - to the SUT, initializing a database, running an installation script, etc. + <p>If <c>init_per_suite</c> exists, it is called initially before the + test cases are executed. It typically contains initializations common + for all test cases in the suite, which are only to be performed once. + <c>init_per_suite</c> is recommended for setting up and verifying state + and environment on the System Under Test (SUT) or the <c>Common Test</c> + host node, or both, so that the test cases in the suite executes correctly. + The following are examples of initial configuration operations: </p> + <list type="bulleted"> + <item>Opening a connection to the SUT</item> + <item>Initializing a database</item> + <item>Running an installation script</item> + </list> <p><c>end_per_suite</c> is called as the final stage of the test suite execution (after the last test case has finished). The function is meant to be used for cleaning up after <c>init_per_suite</c>. </p> - <p><c>init_per_suite</c> and <c>end_per_suite</c> will execute on dedicated + <p><c>init_per_suite</c> and <c>end_per_suite</c> execute on dedicated Erlang processes, just like the test cases do. The result of these functions - is however not included in the test run statistics of successful, failed and + is however not included in the test run statistics of successful, failed, and skipped cases. </p> - <p>The argument to <c>init_per_suite</c> is <c>Config</c>, the + <p>The argument to <c>init_per_suite</c> is <c>Config</c>, that is, the same key-value list of runtime configuration data that each test case takes as input argument. <c>init_per_suite</c> can modify this parameter with information that the test cases need. The possibly modified <c>Config</c> @@ -117,671 +121,683 @@ </p> <p>If <c>init_per_suite</c> fails, all test cases in the test - suite will be skipped automatically (so called <em>auto skipped</em>), + suite are skipped automatically (so called <em>auto skipped</em>), including <c>end_per_suite</c>. </p> - <p>Note that if <c>init_per_suite</c> and <c>end_per_suite</c> do not exist - in the suite, Common Test calls dummy functions (with the same names) - instead, so that output generated by hook functions may be saved to the log - files for these dummies - (see the <seealso marker="ct_hooks_chapter#manipulating">Common Test Hooks</seealso> - chapter for more information). + <p>Notice that if <c>init_per_suite</c> and <c>end_per_suite</c> do not exist + in the suite, <c>Common Test</c> calls dummy functions (with the same names) + instead, so that output generated by hook functions can be saved to the log + files for these dummies. For details, see + <seealso marker="ct_hooks_chapter#manipulating">Common Test Hooks</seealso>. </p> </section> <section> <marker id="per_testcase"/> - <title>Init and end per test case</title> + <title>Init and End per Test Case</title> <p>Each test suite module can contain the optional configuration functions - <c>init_per_testcase/2</c> and <c>end_per_testcase/2</c>. If the init function - is defined, so must the end function be.</p> + <seealso marker="common_test#Module:init_per_testcase-2"><c>init_per_testcase/2</c></seealso> + and <seealso marker="common_test#Module:end_per_testcase-2"><c>end_per_testcase/2</c></seealso>. + If the init function is defined, so must the end function be.</p> - <p>If it exists, <c>init_per_testcase</c> is called before each - test case in the suite. It typically contains initialization which - must be done for each test case (analogue to <c>init_per_suite</c> for the + <p>If <c>init_per_testcase</c> exists, it is called before each + test case in the suite. It typically contains initialization that + must be done for each test case (analog to <c>init_per_suite</c> for the suite).</p> <p><c>end_per_testcase/2</c> is called after each test case has - finished, giving the opportunity to perform clean-up after - <c>init_per_testcase</c>.</p> + finished, enabling cleanup after <c>init_per_testcase</c>.</p> <p>The first argument to these functions is the name of the test case. This value can be used with pattern matching in function clauses or conditional expressions to choose different initialization and cleanup - routines for different test cases, or perform the same routine for a number of, + routines for different test cases, or perform the same routine for many, or all, test cases.</p> <p>The second argument is the <c>Config</c> key-value list of runtime configuration data, which has the same value as the list returned by - <c>init_per_suite</c>. <c>init_per_testcase/2</c> may modify this - parameter or return it as is. The return value of <c>init_per_testcase/2</c> - is passed as the <c>Config</c> parameter to the test case itself.</p> + <c>init_per_suite</c>. <c>init_per_testcase/2</c> can modify this + parameter or return it "as is". The return value of <c>init_per_testcase/2</c> + is passed as parameter <c>Config</c> to the test case itself.</p> <p>The return value of <c>end_per_testcase/2</c> is ignored by the test server, with exception of the - <seealso marker="dependencies_chapter#save_config">save_config</seealso> + <seealso marker="dependencies_chapter#save_config"><c>save_config</c></seealso> and <c>fail</c> tuple.</p> - <p>It is possible in <c>end_per_testcase</c> to check if the - test case was successful or not (which consequently may determine - how cleanup should be performed). This is done by reading the value - tagged with <c>tc_status</c> from <c>Config</c>. The value is either - <c>ok</c>, <c>{failed,Reason}</c> (where <c>Reason</c> is <c>timetrap_timeout</c>, - info from <c>exit/1</c>, or details of a run-time error), or - <c>{skipped,Reason}</c> (where Reason is a user specific term). + <p><c>end_per_testcase</c> can check if the test case was successful. + (which in turn can determine how cleanup is to be performed). + This is done by reading the value tagged with <c>tc_status</c> from + <c>Config</c>. The value is one of the following: </p> - - <p>The <c>end_per_testcase/2</c> function is called even after a - test case terminates due to a call to <seealso marker="ct#abort_current_testcase-1"><c>ct:abort_current_testcase/1</c></seealso>, - or after a timetrap timeout. However, <c>end_per_testcase</c> - will then execute on a different process than the test case - function, and in this situation, <c>end_per_testcase</c> will - not be able to change the reason for test case termination by - returning <c>{fail,Reason}</c>, nor will it be able to save data with - <c>{save_config,Data}</c>.</p> - - <p>If <c>init_per_testcase</c> crashes, the test case itself gets skipped - automatically (so called <em>auto skipped</em>). If <c>init_per_testcase</c> - returns a tuple <c>{skip,Reason}</c>, also then the test case gets skipped - (so called <em>user skipped</em>). It is also possible, by returning a tuple - <c>{fail,Reason}</c> from <c>init_per_testcase</c>, to mark the test case - as failed without actually executing it. + <list type="bulleted"> + <item> + <p><c>ok</c></p> + </item> + <item> + <p><c>{failed,Reason}</c></p> + <p>where <c>Reason</c> is <c>timetrap_timeout</c>, information from <c>exit/1</c>, + or details of a runtime error</p></item> + <item> + <p><c>{skipped,Reason}</c></p> + <p>where <c>Reason</c> is a user-specific term</p></item> + </list> + + <p>Function <c>end_per_testcase/2</c> is even called if a + test case terminates because of a call to + <seealso marker="ct#abort_current_testcase-1"><c>ct:abort_current_testcase/1</c></seealso>, + or after a timetrap time-out. However, <c>end_per_testcase</c> + then executes on a different process than the test case + function. In this situation, <c>end_per_testcase</c> cannot + change the reason for test case termination by returning <c>{fail,Reason}</c> + or save data with <c>{save_config,Data}</c>.</p> + + <p>The test case is skipped in the following two cases: </p> + <list type="bulleted"> + <item>If <c>init_per_testcase</c> crashes (called <em>auto skipped</em>).</item> + <item>If <c>init_per_testcase</c> returns a tuple <c>{skip,Reason}</c> + (called <em>user skipped</em>).</item> + </list> + <p>The test case can also be marked as failed without executing it + by returning a tuple <c>{fail,Reason}</c> from <c>init_per_testcase</c>.</p> + <note><p>If <c>init_per_testcase</c> crashes, or returns <c>{skip,Reason}</c> - or <c>{fail,Reason}</c>, the <c>end_per_testcase</c> function is not called. + or <c>{fail,Reason}</c>, function <c>end_per_testcase</c> is not called. </p></note> <p>If it is determined during execution of <c>end_per_testcase</c> that - the status of a successful test case should be changed to failed, - <c>end_per_testcase</c> may return the tuple: <c>{fail,Reason}</c> + the status of a successful test case is to be changed to failed, + <c>end_per_testcase</c> can return the tuple <c>{fail,Reason}</c> (where <c>Reason</c> describes why the test case fails).</p> - <p><c>init_per_testcase</c> and <c>end_per_testcase</c> execute on the - same Erlang process as the test case and printouts from these - configuration functions can be found in the test case log file.</p> + <p>As <c>init_per_testcase</c> and <c>end_per_testcase</c> execute on the + same Erlang process as the test case, printouts from these + configuration functions are included in the test case log file.</p> </section> <section> <marker id="test_cases"></marker> - <title>Test cases</title> + <title>Test Cases</title> <p>The smallest unit that the test server is concerned with is a - test case. Each test case can actually test many things, for - example make several calls to the same interface function with + test case. Each test case can test many things, for + example, make several calls to the same interface function with different parameters. </p> - <p>It is possible to choose to put many or few tests into each test - case. What exactly each test case does is of course up to the - author, but here are some things to keep in mind: + <p>The author can choose to put many or few tests into each test + case. Some things to keep in mind follows: </p> - - <p>Having many small test cases tend to result in extra, and possibly + <list type="bulleted"> + <item><p>Many small test cases tend to result in extra, and possibly duplicated code, as well as slow test execution because of - large overhead for initializations and cleanups. Duplicated - code should be avoided, e.g. by means of common help functions, or - the resulting suite will be difficult to read and understand, and + large overhead for initializations and cleanups. Avoid duplicated + code, for example, by using common help functions. Otherwise, + the resulting suite becomes difficult to read and understand, and expensive to maintain. - </p> - - <p>Larger test cases make it harder to tell what went wrong if it - fails, and large portions of test code will potentially be skipped - when errors occur. Furthermore, readability and maintainability suffers - when test cases become too large and extensive. Also, the resulting log - files may not reflect very well the number of tests that have - actually been performed. - </p> + </p></item> + <item><p>Larger test cases make it harder to tell what went wrong if it + fails. Also, large portions of test code risk being skipped + when errors occur.</p> + </item> + <item><p>Readability and maintainability suffer + when test cases become too large and extensive. It is not certain + that the resulting log files reflect very well the number of tests + performed. + </p></item> + </list> <p>The test case function takes one argument, <c>Config</c>, which contains configuration information such as <c>data_dir</c> and - <c>priv_dir</c>. (See <seealso marker="#data_priv_dir">Data and - Private Directories</seealso> for more information about these). - The value of <c>Config</c> at the time of the call, is the same - as the return value from <c>init_per_testcase</c>, see above. + <c>priv_dir</c>. (For details about these, see section + <seealso marker="#data_priv_dir">Data and Private Directories</seealso>. + The value of <c>Config</c> at the time of the call, is the same + as the return value from <c>init_per_testcase</c>, mentioned earlier. </p> - <note><p>The test case function argument <c>Config</c> should not be - confused with the information that can be retrieved from + <note><p>The test case function argument <c>Config</c> is not to be + confused with the information that can be retrieved from the configuration files (using <seealso marker="ct#get_config-1"><c> - ct:get_config/1/2</c></seealso>). The Config argument - should be used for runtime configuration of the test suite and the - test cases, while configuration files should typically contain data + ct:get_config/1/2</c></seealso>). The test case argument <c>Config</c> + is to be used for runtime configuration of the test suite and the + test cases, while configuration files are to contain data related to the SUT. These two types of configuration data are handled - differently!</p></note> + differently.</p></note> - <p>Since the <c>Config</c> parameter is a list of key-value tuples, i.e. - a data type generally called a property list, it can be handled by means of the - <c>proplists</c> module in the OTP <c>stdlib</c>. A value can for example - be searched for and returned with the <c>proplists:get_value/2</c> function. - Also, or alternatively, you might want to look in the general <c>lists</c> module, - also in <c>stdlib</c>, for useful functions. Normally, the only operations you - ever perform on <c>Config</c> is insert (adding a tuple to the head of the list) - and lookup. Common Test provides a simple macro named <c>?config</c>, which returns - a value of an item in <c>Config</c> given the key (exactly like + <p>As parameter <c>Config</c> is a list of key-value tuples, that is, + a data type called a property list, it can be handled by the + <seealso marker="stdlib:proplists"><c>stdlib:proplists</c></seealso> module. + A value can, for example, be searched for and returned with function + <seealso marker="stdlib:proplists#get_value-2"><c>proplists:get_value/2</c></seealso>. + Also, or alternatively, the general <seealso marker="stdlib:lists"><c>stdlib:lists</c></seealso> + module contains useful functions. Normally, the only operations + performed on <c>Config</c> is insert (adding a tuple to the head of the list) + and lookup. <c>Common Test</c> provides a simple macro named <c>?config</c>, + which returns a value of an item in <c>Config</c> given the key (exactly like <c>proplists:get_value</c>). Example: <c>PrivDir = ?config(priv_dir, Config)</c>. </p> <p>If the test case function crashes or exits purposely, it is considered - <em>failed</em>. If it returns a value (no matter what actual value) it is + <em>failed</em>. If it returns a value (no matter what value), it is considered successful. An exception to this rule is the return value <c>{skip,Reason}</c>. If this tuple is returned, the test case is considered - skipped and gets logged as such.</p> + skipped and is logged as such.</p> <p>If the test case returns the tuple <c>{comment,Comment}</c>, the case - is considered successful and <c>Comment</c> is printed out in the overview - log file. This is by the way equal to calling <c>ct:comment(Comment)</c>. + is considered successful and <c>Comment</c> is printed in the overview + log file. This is equal to calling + <seealso marker="ct#comment-1"><c>ct:comment(Comment)</c></seealso>. </p> </section> <section> <marker id="info_function"></marker> - <title>Test case info function</title> + <title>Test Case Information Function</title> - <p>For each test case function there can be an additional function - with the same name but with no arguments. This is the test case - info function. The test case info function is expected to return a - list of tagged tuples that specifies various properties regarding the - test case. + <p>For each test case function there can be an extra function + with the same name but without arguments. This is the test case + information function. It is expected to return a list of tagged + tuples that specifies various properties regarding the test case. </p> <p>The following tags have special meaning:</p> <taglist> - <tag><em><c>timetrap</c></em></tag> + <tag><c>timetrap</c></tag> <item> <p> - Set the maximum time the test case is allowed to execute. If - the timetrap time is exceeded, the test case fails with - reason <c>timetrap_timeout</c>. Note that <c>init_per_testcase</c> + Sets the maximum time the test case is allowed to execute. If + this time is exceeded, the test case fails with + reason <c>timetrap_timeout</c>. Notice that <c>init_per_testcase</c> and <c>end_per_testcase</c> are included in the timetrap time. - Please see the <seealso marker="write_test_chapter#timetraps">Timetrap</seealso> - section for more details. + For details, see section + <seealso marker="write_test_chapter#timetraps">Timetrap Time-Outs</seealso>. </p> </item> - <tag><em><c>userdata</c></em></tag> + <tag><c>userdata</c></tag> <item> <p> - Use this to specify arbitrary data related to the testcase. This - data can be retrieved at any time using the <seealso marker="ct#userdata-3"><c>ct:userdata/3</c></seealso> + Specifies any data related to the test case. This + data can be retrieved at any time using the + <seealso marker="ct#userdata-3"><c>ct:userdata/3</c></seealso> utility function. </p> </item> - <tag><em><c>silent_connections</c></em></tag> + <tag><c>silent_connections</c></tag> <item> <p> - Please see the - <seealso marker="run_test_chapter#silent_connections">Silent Connections</seealso> - chapter for details. + For details, see section + <seealso marker="run_test_chapter#silent_connections">Silent Connections</seealso>. </p> </item> - <tag><em><c>require</c></em></tag> + <tag><c>require</c></tag> <item> <p> - Use this to specify configuration variables that are required by the + Specifies configuration variables required by the test case. If the required configuration variables are not found in any of the test system configuration files, the test case is skipped.</p> <p> - It is also possible to give a required variable a default value that will + A required variable can also be given a default value to be used if the variable is not found in any configuration file. To specify - a default value, add a tuple on the form: - <c>{default_config,ConfigVariableName,Value}</c> to the test case info list + a default value, add a tuple on the form + <c>{default_config,ConfigVariableName,Value}</c> to the test case information list (the position in the list is irrelevant). - Examples:</p> + </p> + <p><em>Examples:</em></p> <pre> - testcase1() -> - [{require, ftp}, - {default_config, ftp, [{ftp, "my_ftp_host"}, - {username, "aladdin"}, - {password, "sesame"}]}}].</pre> + testcase1() -> + [{require, ftp}, + {default_config, ftp, [{ftp, "my_ftp_host"}, + {username, "aladdin"}, + {password, "sesame"}]}}].</pre> <pre> - testcase2() -> - [{require, unix_telnet, unix}, - {require, {unix, [telnet, username, password]}}, - {default_config, unix, [{telnet, "my_telnet_host"}, - {username, "aladdin"}, - {password, "sesame"}]}}].</pre> + testcase2() -> + [{require, unix_telnet, unix}, + {require, {unix, [telnet, username, password]}}, + {default_config, unix, [{telnet, "my_telnet_host"}, + {username, "aladdin"}, + {password, "sesame"}]}}].</pre> </item> </taglist> - <p>See the <seealso marker="config_file_chapter#require_config_data">Config files</seealso> - chapter and the <seealso marker="ct#require-1"><c> - ct:require/1/2</c></seealso> function in the - <seealso marker="ct">ct</seealso> reference manual for more information about - <c>require</c>.</p> + <p>For more information about <c>require</c>, see section + <seealso marker="config_file_chapter#require_config_data"> + Requiring and Reading Configuration Data</seealso> + in section External Configuration Data and function + <seealso marker="ct#require-1"><c>ct:require/1/2</c></seealso>.</p> <note><p>Specifying a default value for a required variable can result - in a test case always getting executed. This might not be a desired behaviour!</p> + in a test case always getting executed. This might not be a desired behavior.</p> </note> - <p>If <c>timetrap</c> and/or <c>require</c> is not set specifically for - a particular test case, default values specified by the <c>suite/0</c> - function are used. + <p>If <c>timetrap</c> or <c>require</c>, or both, is not set specifically for + a particular test case, default values specified by function + <seealso marker="common_test#Module:suite-0"><c>suite/0</c></seealso> + are used. </p> - <p>Other tags than the ones mentioned above will simply be ignored by - the test server. + <p>Tags other than the earlier mentioned are ignored by the test server. </p> <p> - Example of a test case info function: + An example of a test case information function follows: </p> <pre> - reboot_node() -> - [ - {timetrap,{seconds,60}}, - {require,interfaces}, - {userdata, - [{description,"System Upgrade: RpuAddition Normal RebootNode"}, - {fts,"http://someserver.ericsson.se/test_doc4711.pdf"}]} - ].</pre> + reboot_node() -> + [ + {timetrap,{seconds,60}}, + {require,interfaces}, + {userdata, + [{description,"System Upgrade: RpuAddition Normal RebootNode"}, + {fts,"http://someserver.ericsson.se/test_doc4711.pdf"}]} + ].</pre> </section> <section> <marker id="suite"></marker> - <title>Test suite info function</title> - - <p>The <c>suite/0</c> function can be used in a test suite - module to e.g. set a default <c>timetrap</c> value and to - <c>require</c> external configuration data. If a test case-, or - group info function also specifies any of the info tags, it - overrides the default values set by <c>suite/0</c>. See the test - case info function above, and group info function below, for more - details. + <title>Test Suite Information Function</title> + + <p>Function <seealso marker="common_test#Module:suite-0"><c>suite/0</c></seealso> + can, for example, be used in a test suite module to set a default + <c>timetrap</c> value and to <c>require</c> external configuration data. + If a test case, or a group information function also specifies any of the information tags, it + overrides the default values set by <c>suite/0</c>. For details, + see + <seealso marker="#info_function">Test Case Information Function</seealso> and + <seealso marker="#test_case_groups">Test Case Groups</seealso>. </p> - <p>Other options that may be specified with the suite info list are:</p> - <list> + <p>The following options can also be specified with the suite information list:</p> + <list type="bulleted"> <item><c>stylesheet</c>, - see <seealso marker="run_test_chapter#html_stylesheet">HTML Style Sheets</seealso>.</item> + see <seealso marker="run_test_chapter#html_stylesheet">HTML Style Sheets</seealso></item> <item><c>userdata</c>, - see <seealso marker="#info_function">Test case info function</seealso>.</item> + see <seealso marker="#info_function">Test Case Information Function</seealso></item> <item><c>silent_connections</c>, - see <seealso marker="run_test_chapter#silent_connections">Silent Connections</seealso>.</item> + see <seealso marker="run_test_chapter#silent_connections">Silent Connections</seealso></item> </list> <p> - Example of the suite info function: + An example of the suite information function follows: </p> <pre> - suite() -> - [ - {timetrap,{minutes,10}}, - {require,global_names}, - {userdata,[{info,"This suite tests database transactions."}]}, - {silent_connections,[telnet]}, - {stylesheet,"db_testing.css"} - ].</pre> + suite() -> + [ + {timetrap,{minutes,10}}, + {require,global_names}, + {userdata,[{info,"This suite tests database transactions."}]}, + {silent_connections,[telnet]}, + {stylesheet,"db_testing.css"} + ].</pre> </section> <section> <marker id="test_case_groups"></marker> - <title>Test case groups</title> - <p>A test case group is a set of test cases that share configuration + <title>Test Case Groups</title> + <p>A test case group is a set of test cases sharing configuration functions and execution properties. Test case groups are defined by - means of the <c>groups/0</c> function according to the following syntax:</p> + function + <seealso marker="common_test#Module:groups-0"><c>groups/0</c></seealso> + according to the following syntax:</p> <pre> - groups() -> GroupDefs + groups() -> GroupDefs - Types: + Types: - GroupDefs = [GroupDef] - GroupDef = {GroupName,Properties,GroupsAndTestCases} - GroupName = atom() - GroupsAndTestCases = [GroupDef | {group,GroupName} | TestCase] - TestCase = atom()</pre> + GroupDefs = [GroupDef] + GroupDef = {GroupName,Properties,GroupsAndTestCases} + GroupName = atom() + GroupsAndTestCases = [GroupDef | {group,GroupName} | TestCase] + TestCase = atom()</pre> - <p><c>GroupName</c> is the name of the group and should be unique within - the test suite module. Groups may be nested, and this is accomplished - simply by including a group definition within the <c>GroupsAndTestCases</c> - list of another group. <c>Properties</c> is the list of execution - properties for the group. The possible values are:</p> + <p><c>GroupName</c> is the name of the group and must be unique within + the test suite module. Groups can be nested, by including a group definition + within the <c>GroupsAndTestCases</c> list of another group. + <c>Properties</c> is the list of execution + properties for the group. The possible values are as follows:</p> <pre> - Properties = [parallel | sequence | Shuffle | {RepeatType,N}] - Shuffle = shuffle | {shuffle,Seed} - Seed = {integer(),integer(),integer()} - RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | - repeat_until_any_ok | repeat_until_any_fail - N = integer() | forever</pre> - - <p>If the <c>parallel</c> property is specified, Common Test will execute - all test cases in the group in parallel. If <c>sequence</c> is specified, - the cases will be executed in a sequence, as described in the chapter - <seealso marker="dependencies_chapter#sequences">Dependencies between - test cases and suites</seealso>. If <c>shuffle</c> is specified, the cases - in the group will be executed in random order. The <c>repeat</c> property - orders Common Test to repeat execution of the cases in the group a given - number of times, or until any, or all, cases fail or succeed.</p> - - <p>Example:</p> + Properties = [parallel | sequence | Shuffle | {RepeatType,N}] + Shuffle = shuffle | {shuffle,Seed} + Seed = {integer(),integer(),integer()} + RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | + repeat_until_any_ok | repeat_until_any_fail + N = integer() | forever</pre> + + <p><em>Explanations:</em></p> + <taglist> + <tag><c>parallel</c></tag> + <item><p><c>Common Test</c> executes all test cases in the group in parallel.</p></item> + <tag><c>sequence</c></tag> + <item><p>The cases are executed in a sequence as described in section + <seealso marker="dependencies_chapter#sequences">Sequences</seealso> in section + Dependencies Between Test Cases and Suites.</p></item> + <tag><c>shuffle</c></tag> + <item><p>The cases in the group are executed in random order.</p></item> + <tag><c>repeat</c></tag> + <item><p>Orders <c>Common Test</c> to repeat execution of the cases in the + group a given number of times, or until any, or all, cases fail or succeed.</p></item> + </taglist> + + <p><em>Example:</em></p> <pre> - groups() -> [{group1, [parallel], [test1a,test1b]}, - {group2, [shuffle,sequence], [test2a,test2b,test2c]}].</pre> + groups() -> [{group1, [parallel], [test1a,test1b]}, + {group2, [shuffle,sequence], [test2a,test2b,test2c]}].</pre> - <p>To specify in which order groups should be executed (also with respect - to test cases that are not part of any group), tuples on the form - <c>{group,GroupName}</c> should be added to the <c>all/0</c> list. Example:</p> + <p>To specify in which order groups are to be executed (also with respect + to test cases that are not part of any group), add tuples on the form + <c>{group,GroupName}</c> to the <c>all/0</c> list.</p> + <p><em>Example:</em></p> <pre> - all() -> [testcase1, {group,group1}, testcase2, {group,group2}].</pre> + all() -> [testcase1, {group,group1}, testcase2, {group,group2}].</pre> - <p>It is also possible to specify execution properties with a group - tuple in <c>all/0</c>: <c>{group,GroupName,Properties}</c>. These - properties will override those specified in the group definition (see - <c>groups/0</c> above). This way, it's possible to run the same set of tests, + <p>Execution properties with a group tuple in + <c>all/0</c>: <c>{group,GroupName,Properties}</c> can also be specified. + These properties override those specified in the group definition (see + <c>groups/0</c> earlier). This way, the same set of tests can be run, but with different properties, without having to make copies of the group definition in question.</p> - <p>If a group contains sub-groups, the execution properties for these may + <p>If a group contains subgroups, the execution properties for these can also be specified in the group tuple: - <c>{group,GroupName,Properties,SubGroups}</c>, where <c>SubGroups</c> - is a list of tuples, <c>{GroupName,Properties}</c>, or - <c>{GroupName,Properties,SubGroups}</c>, representing the sub-groups. - Any sub-groups defined in <c>group/0</c> for a group, that are not specified - in the <c>SubGroups</c> list, will simply execute with their pre-defined + <c>{group,GroupName,Properties,SubGroups}</c> + Where, <c>SubGroups</c> is a list of tuples, <c>{GroupName,Properties}</c> or + <c>{GroupName,Properties,SubGroups}</c> representing the subgroups. + Any subgroups defined in <c>group/0</c> for a group, that are not specified + in the <c>SubGroups</c> list, executes with their predefined properties.</p> - <p>Example:</p> + <p><em>Example:</em></p> <pre> - groups() -> {tests1, [], [{tests2, [], [t2a,t2b]}, - {tests3, [], [t31,t3b]}]}.</pre> - <p>To execute group 'tests1' twice with different properties for 'tests2' + groups() -> {tests1, [], [{tests2, [], [t2a,t2b]}, + {tests3, [], [t31,t3b]}]}.</pre> + <p>To execute group <c>tests1</c> twice with different properties for <c>tests2</c> each time:</p> <pre> - all() -> - [{group, tests1, default, [{tests2, [parallel]}]}, - {group, tests1, default, [{tests2, [shuffle,{repeat,10}]}]}].</pre> - <p>Note that this is equivalent to this specification:</p> + all() -> + [{group, tests1, default, [{tests2, [parallel]}]}, + {group, tests1, default, [{tests2, [shuffle,{repeat,10}]}]}].</pre> + <p>This is equivalent to the following specification:</p> <pre> - all() -> - [{group, tests1, default, [{tests2, [parallel]}, - {tests3, default}]}, - {group, tests1, default, [{tests2, [shuffle,{repeat,10}]}, - {tests3, default}]}].</pre> - <p>The value <c>default</c> states that the pre-defined properties - should be used.</p> - <p>Here's an example of how to override properties in a scenario + all() -> + [{group, tests1, default, [{tests2, [parallel]}, + {tests3, default}]}, + {group, tests1, default, [{tests2, [shuffle,{repeat,10}]}, + {tests3, default}]}].</pre> + <p>Value <c>default</c> states that the predefined properties + are to be used.</p> + <p>The following example shows how to override properties in a scenario with deeply nested groups:</p> <pre> - groups() -> - [{tests1, [], [{group, tests2}]}, - {tests2, [], [{group, tests3}]}, - {tests3, [{repeat,2}], [t3a,t3b,t3c]}]. - - all() -> - [{group, tests1, default, - [{tests2, default, - [{tests3, [parallel,{repeat,100}]}]}]}].</pre> - - <p>The syntax described above may also be used in Test Specifications - in order to change properties of groups at the time of execution, - without even having to edit the test suite (please see the - <seealso marker="run_test_chapter#test_specifications">Test - Specifications</seealso> chapter for more info).</p> - - <p>As illustrated above, properties may be combined. If e.g. - <c>shuffle</c>, <c>repeat_until_any_fail</c> and <c>sequence</c> - are all specified, the test cases in the group will be executed + groups() -> + [{tests1, [], [{group, tests2}]}, + {tests2, [], [{group, tests3}]}, + {tests3, [{repeat,2}], [t3a,t3b,t3c]}]. + + all() -> + [{group, tests1, default, + [{tests2, default, + [{tests3, [parallel,{repeat,100}]}]}]}].</pre> + + <p>The described syntax can also be used in test specifications + to change group properties at the time of execution, + without having to edit the test suite. For more information, see + section <seealso marker="run_test_chapter#test_specifications">Test + Specifications</seealso> in section Running Tests and Analyzing Results.</p> + + <p>As illustrated, properties can be combined. If, for example, + <c>shuffle</c>, <c>repeat_until_any_fail</c>, and <c>sequence</c> + are all specified, the test cases in the group are executed repeatedly, and in random order, until a test case fails. Then - execution is immediately stopped and the rest of the cases skipped.</p> + execution is immediately stopped and the remaining cases are skipped.</p> <p>Before execution of a group begins, the configuration function - <c>init_per_group(GroupName, Config)</c> is called. The list of tuples - returned from this function is passed to the test cases in the usual - manner by means of the <c>Config</c> argument. <c>init_per_group/2</c> - is meant to be used for initializations common for the test cases in the - group. After execution of the group is finished, the - <c>end_per_group(GroupName, Config</c> function is called. This function - is meant to be used for cleaning up after <c>init_per_group/2</c>.</p> + <seealso marker="common_test#Module:init_per_group-2"><c>init_per_group(GroupName, Config)</c></seealso> + is called. The list of tuples returned from this function is passed to the + test cases in the usual manner by argument <c>Config</c>. + <c>init_per_group/2</c> is meant to be used for initializations common + for the test cases in the group. After execution of the group is finished, function + <seealso marker="common_test#Module:end_per_group-2"><c>end_per_group(GroupName, Config)</c></seealso> + is called. This function is meant to be used for cleaning up after + <c>init_per_group/2</c>.</p> <p>Whenever a group is executed, if <c>init_per_group</c> and - <c>end_per_group</c> do not exist in the suite, Common Test calls + <c>end_per_group</c> do not exist in the suite, <c>Common Test</c> calls dummy functions (with the same names) instead. Output generated by - hook functions will be saved to the log files for these dummies - (see the <seealso marker="ct_hooks_chapter#manipulating">Common Test - Hooks</seealso> chapter for more information). + hook functions are saved to the log files for these dummies. + For more information, see section + <seealso marker="ct_hooks_chapter#manipulating">Manipulating Tests</seealso> + in section Common Test Hooks. </p> <note><p><c>init_per_testcase/2</c> and <c>end_per_testcase/2</c> are always called for each individual test case, no matter if the case belongs to a group or not.</p></note> - <p>The properties for a group is always printed on the top of the HTML log - for <c>init_per_group/2</c>. Also, the total execution time for a group - can be found at the bottom of the log for <c>end_per_group/2</c>.</p> + <p>The properties for a group are always printed in the top of the HTML log + for <c>init_per_group/2</c>. The total execution time for a group is + included at the bottom of the log for <c>end_per_group/2</c>.</p> - <p>Test case groups may be nested so that sets of groups can be + <p>Test case groups can be nested so sets of groups can be configured with the same <c>init_per_group/2</c> and <c>end_per_group/2</c> - functions. Nested groups may be defined by including a group definition, - or a group name reference, in the test case list of another group. Example:</p> + functions. Nested groups can be defined by including a group definition, + or a group name reference, in the test case list of another group.</p> + <p><em>Example:</em></p> <pre> - groups() -> [{group1, [shuffle], [test1a, - {group2, [], [test2a,test2b]}, - test1b]}, - {group3, [], [{group,group4}, - {group,group5}]}, - {group4, [parallel], [test4a,test4b]}, - {group5, [sequence], [test5a,test5b,test5c]}].</pre> - - <p>In the example above, if <c>all/0</c> would return group name references - in this order: <c>[{group,group1},{group,group3}]</c>, the order of the - configuration functions and test cases will be the following (note that + groups() -> [{group1, [shuffle], [test1a, + {group2, [], [test2a,test2b]}, + test1b]}, + {group3, [], [{group,group4}, + {group,group5}]}, + {group4, [parallel], [test4a,test4b]}, + {group5, [sequence], [test5a,test5b,test5c]}].</pre> + + <p>In the previous example, if <c>all/0</c> returns group name references + in the order <c>[{group,group1},{group,group3}]</c>, the order of the + configuration functions and test cases becomes the following (notice that <c>init_per_testcase/2</c> and <c>end_per_testcase/2:</c> are also always called, but not included in this example for simplification):</p> <pre> -- init_per_group(group1, Config) -> Config1 (*) - --- test1a(Config1) - --- init_per_group(group2, Config1) -> Config2 - ---- test2a(Config2), test2b(Config2) - --- end_per_group(group2, Config2) - --- test1b(Config1) - -- end_per_group(group1, Config1) - -- init_per_group(group3, Config) -> Config3 - --- init_per_group(group4, Config3) -> Config4 - ---- test4a(Config4), test4b(Config4) (**) - --- end_per_group(group4, Config4) - --- init_per_group(group5, Config3) -> Config5 - ---- test5a(Config5), test5b(Config5), test5c(Config5) - --- end_per_group(group5, Config5) - -- end_per_group(group3, Config3) - - - (*) The order of test case test1a, test1b and group2 is not actually - defined since group1 has a shuffle property. - - (**) These cases are not executed in order, but in parallel.</pre> - - <p>Properties are not inherited from top level groups to nested - sub-groups. E.g, in the example above, the test cases in <c>group2</c> - will not be executed in random order (which is the property of - <c>group1</c>).</p> + init_per_group(group1, Config) -> Config1 (*) + test1a(Config1) + init_per_group(group2, Config1) -> Config2 + test2a(Config2), test2b(Config2) + end_per_group(group2, Config2) + test1b(Config1) + end_per_group(group1, Config1) + init_per_group(group3, Config) -> Config3 + init_per_group(group4, Config3) -> Config4 + test4a(Config4), test4b(Config4) (**) + end_per_group(group4, Config4) + init_per_group(group5, Config3) -> Config5 + test5a(Config5), test5b(Config5), test5c(Config5) + end_per_group(group5, Config5) + end_per_group(group3, Config3)</pre> + + <p>(*) The order of test case <c>test1a</c>, <c>test1b</c>, and <c>group2</c> is + undefined, as <c>group1</c> has a shuffle property.</p> + <p>(**) These cases are not executed in order, but in parallel.</p> + <p>Properties are not inherited from top-level groups to nested + subgroups. For instance, in the previous example, the test cases in <c>group2</c> + are not executed in random order (which is the property of <c>group1</c>).</p> </section> <section> - <title>The parallel property and nested groups</title> - <p>If a group has a parallel property, its test cases will be spawned - simultaneously and get executed in parallel. A test case is not allowed - to execute in parallel with <c>end_per_group/2</c> however, which means - that the time it takes to execute a parallel group is equal to the + <title>Parallel Property and Nested Groups</title> + <p>If a group has a parallel property, its test cases are spawned + simultaneously and get executed in parallel. However, a test case is not + allowed to execute in parallel with <c>end_per_group/2</c>, which means + that the time to execute a parallel group is equal to the execution time of the slowest test case in the group. A negative side effect of running test cases in parallel is that the HTML summary pages - are not updated with links to the individual test case logs until the - <c>end_per_group/2</c> function for the group has finished.</p> + are not updated with links to the individual test case logs until function + <c>end_per_group/2</c> for the group has finished.</p> - <p>A group nested under a parallel group will start executing in parallel + <p>A group nested under a parallel group starts executing in parallel with previous (parallel) test cases (no matter what properties the nested - group has). Since, however, test cases are never executed in parallel with - <c>init_per_group/2</c> or <c>end_per_group/2</c> of the same group, it's - only after a nested group has finished that any remaining parallel cases - in the previous group get spawned.</p> + group has). However, as test cases are never executed in parallel with + <c>init_per_group/2</c> or <c>end_per_group/2</c> of the same group, it is + only after a nested group has finished that remaining parallel cases + in the previous group become spawned.</p> </section> <section> - <title>Parallel test cases and IO</title> - <p>A parallel test case has a private IO server as its group leader. - (Please see the Erlang Run-Time System Application documentation for - a description of the group leader concept). The - central IO server process that handles the output from regular test - cases and configuration functions, does not respond to IO messages + <title>Parallel Test Cases and I/O</title> + <p>A parallel test case has a private I/O server as its group leader. + (For a description of the group leader concept, see + <seealso marker="erts:index"><c>ERTS</c></seealso>). + The central I/O server process, which handles the output from + regular test cases and configuration functions, does not respond to I/O messages during execution of parallel groups. This is important to understand - in order to avoid certain traps, like this one:</p> - <p>If a process, <c>P</c>, is spawned during execution of e.g. - <c>init_per_suite/1</c>, it will inherit the group leader of the - <c>init_per_suite</c> process. This group leader is the central IO server - process mentioned above. If, at a later time, <em>during parallel test case + to avoid certain traps, like the following:</p> + <p>If a process, <c>P</c>, is spawned during execution of, for example, + <c>init_per_suite/1</c>, it inherits the group leader of the + <c>init_per_suite</c> process. This group leader is the central I/O server + process mentioned earlier. If, at a later time, <em>during parallel test case execution</em>, some event triggers process <c>P</c> to call - <c>io:format/1/2</c>, that call will never return (since the group leader - is in a non-responsive state) and cause <c>P</c> to hang. + <c>io:format/1/2</c>, that call never returns (as the group leader + is in a non-responsive state) and causes <c>P</c> to hang. </p> </section> <section> - <title>Repeated groups</title> + <title>Repeated Groups</title> <marker id="repeated_groups"></marker> - <p>A test case group may be repeated a certain number of times + <p>A test case group can be repeated a certain number of times (specified by an integer) or indefinitely (specified by <c>forever</c>). - The repetition may also be stopped prematurely if any or all cases - fail or succeed, i.e. if the property <c>repeat_until_any_fail</c>, + The repetition can also be stopped too early if any or all cases + fail or succeed, that is, if any of the properties <c>repeat_until_any_fail</c>, <c>repeat_until_any_ok</c>, <c>repeat_until_all_fail</c>, or <c>repeat_until_all_ok</c> is used. If the basic <c>repeat</c> property is used, status of test cases is irrelevant for the repeat operation.</p> - <p>It is possible to return the status of a sub-group (ok or - failed), to affect the execution of the group on the level above. + <p>The status of a subgroup can be returned (<c>ok</c> or + <c>failed</c>), to affect the execution of the group on the level above. This is accomplished by, in <c>end_per_group/2</c>, looking up the value of <c>tc_group_properties</c> in the <c>Config</c> list and checking the - result of the test cases in the group. If status <c>failed</c> should be - returned from the group as a result, <c>end_per_group/2</c> should return - the value <c>{return_group_result,failed}</c>. The status of a sub-group - is taken into account by Common Test when evaluating if execution of a - group should be repeated or not (unless the basic <c>repeat</c> + result of the test cases in the group. If status <c>failed</c> is to be + returned from the group as a result, <c>end_per_group/2</c> is to return + the value <c>{return_group_result,failed}</c>. The status of a subgroup + is taken into account by <c>Common Test</c> when evaluating if execution of a + group is to be repeated or not (unless the basic <c>repeat</c> property is used).</p> - <p>The <c>tc_group_properties</c> value is a list of status tuples, - each with the key <c>ok</c>, <c>skipped</c> and <c>failed</c>. The - value of a status tuple is a list containing names of test cases + <p>The value of <c>tc_group_properties</c> is a list of status tuples, + each with the key <c>ok</c>, <c>skipped</c>, and <c>failed</c>. The + value of a status tuple is a list with names of test cases that have been executed with the corresponding status as result.</p> - <p>Here's an example of how to return the status from a group:</p> + <p>The following is an example of how to return the status from a group:</p> <pre> - end_per_group(_Group, Config) -> - Status = ?config(tc_group_result, Config), - case proplists:get_value(failed, Status) of - [] -> % no failed cases - {return_group_result,ok}; - _Failed -> % one or more failed - {return_group_result,failed} - end.</pre> - - <p>It is also possible in <c>end_per_group/2</c> to check the status of - a sub-group (maybe to determine what status the current group should also - return). This is as simple as illustrated in the example above, only the - name of the group is stored in a tuple <c>{group_result,GroupName}</c>, - which can be searched for in the status lists. Example:</p> + end_per_group(_Group, Config) -> + Status = ?config(tc_group_result, Config), + case proplists:get_value(failed, Status) of + [] -> % no failed cases + {return_group_result,ok}; + _Failed -> % one or more failed + {return_group_result,failed} + end.</pre> + + <p>It is also possible, in <c>end_per_group/2</c>, to check the status of + a subgroup (maybe to determine what status the current group is to + return). This is as simple as illustrated in the previous example, only the + group name is stored in a tuple <c>{group_result,GroupName}</c>, + which can be searched for in the status lists.</p> + <p><em>Example:</em></p> <pre> - end_per_group(group1, Config) -> - Status = ?config(tc_group_result, Config), - Failed = proplists:get_value(failed, Status), - case lists:member({group_result,group2}, Failed) of - true -> - {return_group_result,failed}; - false -> - {return_group_result,ok} - end; - ...</pre> + end_per_group(group1, Config) -> + Status = ?config(tc_group_result, Config), + Failed = proplists:get_value(failed, Status), + case lists:member({group_result,group2}, Failed) of + true -> + {return_group_result,failed}; + false -> + {return_group_result,ok} + end; + ...</pre> <note><p>When a test case group is repeated, the configuration - functions, <c>init_per_group/2</c> and <c>end_per_group/2</c>, are + functions <c>init_per_group/2</c> and <c>end_per_group/2</c> are also always called with each repetition.</p></note> </section> <section> - <title>Shuffled test case order</title> - <p>The order that test cases in a group are executed, is under normal + <title>Shuffled Test Case Order</title> + <p>The order in which test cases in a group are executed is under normal circumstances the same as the order specified in the test case list - in the group definition. With the <c>shuffle</c> property set, however, - Common Test will instead execute the test cases in random order.</p> + in the group definition. With property <c>shuffle</c> set, however, + <c>Common Test</c> instead executes the test cases in random order.</p> - <p>The user may provide a seed value (a tuple of three integers) with - the shuffle property: <c>{shuffle,Seed}</c>. This way, the same shuffling + <p>You can provide a seed value (a tuple of three integers) with + the shuffle property <c>{shuffle,Seed}</c>. This way, the same shuffling order can be created every time the group is executed. If no seed value - is given, Common Test creates a "random" seed for the shuffling operation - (using the return value of <c>erlang:now()</c>). The seed value is always + is specified, <c>Common Test</c> creates a "random" seed for the shuffling operation + (using the return value of <c>erlang:timestamp/0</c>). The seed value is always printed to the <c>init_per_group/2</c> log file so that it can be used to recreate the same execution order in a subsequent test run.</p> - <note><p>If a shuffled test case group is repeated, the seed will not - be reset in between turns.</p></note> + <note><p>If a shuffled test case group is repeated, the seed is not + reset between turns.</p></note> - <p>If a sub-group is specified in a group with a <c>shuffle</c> property, - the execution order of this sub-group in relation to the test cases - (and other sub-groups) in the group, is also random. The order of the - test cases in the sub-group is however not random (unless, of course, the - sub-group also has a <c>shuffle</c> property).</p> + <p>If a subgroup is specified in a group with a <c>shuffle</c> property, + the execution order of this subgroup in relation to the test cases + (and other subgroups) in the group, is random. The order of the + test cases in the subgroup is however not random (unless the + subgroup has a <c>shuffle</c> property).</p> </section> <section> <marker id="group_info"></marker> - <title>Group info function</title> + <title>Group Information Function</title> - <p>The test case group info function, <c>group(GroupName)</c>, - serves the same purpose as the suite- and test case info - functions previously described in this chapter. The scope for - the group info, however, is all test cases and sub-groups in the + <p>The test case group information function, <c>group(GroupName)</c>, + serves the same purpose as the suite- and test case information + functions previously described. However, the scope for + the group information function, is all test cases and subgroups in the group in question (<c>GroupName</c>).</p> - <p>Example:</p> + <p><em>Example:</em></p> <pre> - group(connection_tests) -> - [{require,login_data}, - {timetrap,1000}].</pre> + group(connection_tests) -> + [{require,login_data}, + {timetrap,1000}].</pre> - <p>The group info properties override those set with the - suite info function, and may in turn be overridden by test - case info properties. Please see the test case info - function above for a list of valid info properties and more - general information.</p> + <p>The group information properties override those set with the + suite information function, and can in turn be overridden by test + case information properties. For a list of valid information properties + and more general information, see the + <seealso marker="#info_function">Test Case Information Function</seealso>. + </p> </section> <section> - <title>Info functions for init- and end-configuration</title> - <p>It is possible to use info functions also for the <c>init_per_suite</c>, - <c>end_per_suite</c>, <c>init_per_group</c>, and <c>end_per_group</c> - functions, and it works the same way as with info functions - for test cases (see above). This is useful e.g. for setting - timetraps and requiring external configuration data relevant - only for the configuration function in question (without - affecting properties set for groups and test cases in the suite).</p> - - <p>The info function <c>init/end_per_suite()</c> is called for - <c>init/end_per_suite(Config)</c>, and info function + <title>Information Functions for Init- and End-Configuration</title> + <p>Information functions can also be used for functions <c>init_per_suite</c>, + <c>end_per_suite</c>, <c>init_per_group</c>, and <c>end_per_group</c>, + and they work the same way as with the + <seealso marker="#info_function">Test Case Information Function</seealso>. + This is useful, for example, for setting timetraps and requiring + external configuration data relevant only for the configuration + function in question (without affecting properties set for groups + and test cases in the suite).</p> + + <p>The information function <c>init/end_per_suite()</c> is called for + <c>init/end_per_suite(Config)</c>, and information function <c>init/end_per_group(GroupName)</c> is called for - <c>init/end_per_group(GroupName,Config)</c>. Info functions - can not be used with <c>init/end_per_testcase(TestCase, Config)</c>, - however, since these configuration functions execute on the test case process - and will use the same properties as the test case (i.e. the properties - set by the test case info function, <c>TestCase()</c>). Please see the test case - info function above for a list of valid info properties and more - general information. + <c>init/end_per_group(GroupName,Config)</c>. However, information functions + cannot be used with <c>init/end_per_testcase(TestCase, Config)</c>, + as these configuration functions execute on the test case process + and use the same properties as the test case (that is, the properties + set by the test case information function, <c>TestCase()</c>). For a list + of valid information properties and more general information, see the + <seealso marker="#info_function">Test Case Information Function</seealso>. </p> </section> @@ -789,77 +805,67 @@ <marker id="data_priv_dir"></marker> <title>Data and Private Directories</title> - <p>The data directory, <c>data_dir</c>, is the directory where the - test module has its own files needed for the testing. The name - of the <c>data_dir</c> is the the name of the test suite followed - by <c>"_data"</c>. For example, - <c>"some_path/foo_SUITE.beam"</c> has the data directory + <p>In the data directory, <c>data_dir</c>, the test module has + its own files needed for the testing. The name of <c>data_dir</c> + is the the name of the test suite followed by <c>"_data"</c>. + For example, <c>"some_path/foo_SUITE.beam"</c> has the data directory <c>"some_path/foo_SUITE_data/"</c>. Use this directory for portability, - i.e. to avoid hardcoding directory names in your suite. Since the data - directory is stored in the same directory as your test suite, you should - be able to rely on its existence at runtime, even if the path to your + that is, to avoid hardcoding directory names in your suite. As the data + directory is stored in the same directory as your test suite, you can + rely on its existence at runtime, even if the path to your test suite directory has changed between test suite implementation and execution. </p> - -<!-- - <p> - When using the Common Test framework <c>ct</c>, automatic - compilation of code in the data directory can be obtained by - placing a makefile source called Makefile.src in the data - directory. Makefile.src will be converted to a valid makefile by - <c>ct</c> when the test suite is run. See the reference manual for - the <c>ct</c> module for details about the syntax of Makefile.src. - </p> ---> <p> <c>priv_dir</c> is the private directory for the test cases. - This directory may be used whenever a test case (or configuration function) + This directory can be used whenever a test case (or configuration function) needs to write something to file. The name of the private directory is - generated by Common Test, which also creates the directory. + generated by <c>Common Test</c>, which also creates the directory. </p> - <p>By default, Common Test creates one central private directory - per test run that all test cases share. This may not always be suitable, - especially if the same test cases are executed multiple times during - a test run (e.g. if they belong to a test case group with repeat - property), and there's a risk that files in the private directory get - overwritten. Under these circumstances, it's possible to configure - Common Test to create one dedicated private directory per - test case and execution instead. This is accomplished by means of - the flag/option: <c>create_priv_dir</c> (to be used with the - <c>ct_run</c> program, the <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso> function, or + <p>By default, <c>Common Test</c> creates one central private directory + per test run, shared by all test cases. This is not always suitable. + Especially if the same test cases are executed multiple times during + a test run (that is, if they belong to a test case group with property + <c>repeat</c>) and there is a risk that files in the private directory get + overwritten. Under these circumstances, <c>Common Test</c> can be + configured to create one dedicated private directory per + test case and execution instead. This is accomplished with + the flag/option <c>create_priv_dir</c> (to be used with the + <seealso marker="ct_run"><c>ct_run</c></seealso> program, the + <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso> function, or as test specification term). There are three possible values - for this option: + for this option as follows: </p> - <list> + <list type="bulleted"> <item><c>auto_per_run</c></item> <item><c>auto_per_tc</c></item> <item><c>manual_per_tc</c></item> </list> <p> - The first value indicates the default priv_dir behaviour, i.e. + The first value indicates the default <c>priv_dir</c> behavior, that is, one private directory created per test run. The two latter - values tell Common Test to generate a unique test directory name + values tell <c>Common Test</c> to generate a unique test directory name per test case and execution. If the auto version is used, <em>all</em> - private directories will be created automatically. This can obviously - become very inefficient for test runs with many test cases and/or - repetitions. Therefore, in case the manual version is instead used, the - test case must tell Common Test to create priv_dir when it needs it. - It does this by calling the function <seealso marker="ct#make_priv_dir-0"><c>ct:make_priv_dir/0</c></seealso>. + private directories are created automatically. This can become very + inefficient for test runs with many test cases or repetitions, or both. + Therefore, if the manual version is used instead, the test case must tell + <c>Common Test</c> to create <c>priv_dir</c> when it needs it. + It does this by calling the function + <seealso marker="ct#make_priv_dir-0"><c>ct:make_priv_dir/0</c></seealso>. </p> - <note><p>You should not depend on current working directory for - reading and writing data files since this is not portable. All + <note><p>Do not depend on the current working directory for + reading and writing data files, as this is not portable. All scratch files are to be written in the <c>priv_dir</c> and all - data files should be located in <c>data_dir</c>. Note also that - the Common Test server sets current working directory to the test case - log directory at the start of every case. + data files are to be located in <c>data_dir</c>. Also, + the <c>Common Test</c> server sets the current working directory to + the test case log directory at the start of every case. </p></note> </section> <section> - <title>Execution environment</title> + <title>Execution Environment</title> <p>Each test case is executed by a dedicated Erlang process. The process is spawned when the test case starts, and terminated when @@ -876,236 +882,269 @@ <section> <marker id="timetraps"></marker> - <title>Timetrap timeouts</title> + <title>Timetrap Time-Outs</title> <p>The default time limit for a test case is 30 minutes, unless a <c>timetrap</c> is specified either by the suite-, group-, - or test case info function. The timetrap timeout value defined by - <c>suite/0</c> is the value that will be used for each test case - in the suite (as well as for the configuration functions + or test case information function. The timetrap time-out value defined by + <c>suite/0</c> is the value that is used for each test case + in the suite (and for the configuration functions <c>init_per_suite/1</c>, <c>end_per_suite/1</c>, <c>init_per_group/2</c>, and <c>end_per_group/2</c>). A timetrap value defined by <c>group(GroupName)</c> overrides one defined by <c>suite()</c> - and will be used for each test case in group <c>GroupName</c>, and any - of its sub-groups. If a timetrap value is defined by <c>group/1</c> - for a sub-group, it overrides that of its higher level groups. Timetrap - values set by individual test cases (by means of the test case info + and is used for each test case in group <c>GroupName</c>, and any + of its subgroups. If a timetrap value is defined by <c>group/1</c> + for a subgroup, it overrides that of its higher level groups. Timetrap + values set by individual test cases (by the test case information function) override both group- and suite- level timetraps.</p> - <p>It is also possible to dynamically set/reset a timetrap during the - excution of a test case, or configuration function. This is done by calling - <seealso marker="ct#timetrap-1"><c>ct:timetrap/1</c></seealso>. This function cancels the current timetrap - and starts a new one (that stays active until timeout, or end of the - current function).</p> + <p>A timetrap can also be set or reset dynamically during the + execution of a test case, or configuration function. + This is done by calling + <seealso marker="ct#timetrap-1"><c>ct:timetrap/1</c></seealso>. + This function cancels the current timetrap and starts a new one + (that stays active until time-out, or end of the current function).</p> <p>Timetrap values can be extended with a multiplier value specified at - startup with the <c>multiply_timetraps</c> option. It is also possible - to let the test server decide to scale up timetrap timeout values - automatically, e.g. if tools such as cover or trace are running during - the test. This feature is disabled by default and can be enabled with - the <c>scale_timetraps</c> start option.</p> + startup with option <c>multiply_timetraps</c>. It is also possible + to let the test server decide to scale up timetrap time-out values + automatically. That is, if tools such as <c>cover</c> or <c>trace</c> + are running during the test. This feature is disabled by default and + can be enabled with start option <c>scale_timetraps</c>.</p> <p>If a test case needs to suspend itself for a time that also gets multipled by <c>multiply_timetraps</c> (and possibly also scaled up if - <c>scale_timetraps</c> is enabled), the function <seealso marker="ct#sleep-1"><c>ct:sleep/1</c></seealso> - may be used (instead of e.g. <c>timer:sleep/1</c>).</p> + <c>scale_timetraps</c> is enabled), the function + <seealso marker="ct#sleep-1"><c>ct:sleep/1</c></seealso> + can be used (instead of, for example, <c>timer:sleep/1</c>).</p> - <p>A function (<c>fun/0</c> or <c>MFA</c>) may be specified as - timetrap value in the suite-, group- and test case info function, as - well as argument to the <seealso marker="ct#timetrap-1"><c>ct:timetrap/1</c></seealso> function. Examples:</p> + <p>A function (<c>fun/0</c> or <c>{Mod,Func,Args}</c> (MFA) tuple) can be + specified as timetrap value in the suite-, group- and test case information + function, and as argument to function + <seealso marker="ct#timetrap-1"><c>ct:timetrap/1</c></seealso>.</p> + <p><em>Examples:</em></p> <p><c>{timetrap,{my_test_utils,timetrap,[?MODULE,system_start]}}</c></p> <p><c>ct:timetrap(fun() -> my_timetrap(TestCaseName, Config) end)</c></p> - <p>The user timetrap function may be used for two things:</p> - <list> - <item>To act as a timetrap - the timeout is triggered when the + <p>The user timetrap function can be used for two things as follows:</p> + <list type="bulleted"> + <item>To act as a timetrap. The time-out is triggered when the function returns.</item> <item>To return a timetrap time value (other than a function).</item> </list> <p>Before execution of the timetrap function (which is performed - on a parallel, dedicated timetrap process), Common Test cancels + on a parallel, dedicated timetrap process), <c>Common Test</c> cancels any previously set timer for the test case or configuration function. - When the timetrap function returns, the timeout is triggered, <em>unless</em> + When the timetrap function returns, the time-out is triggered, <em>unless</em> the return value is a valid timetrap time, such as an integer, - or a <c>{SecMinOrHourTag,Time}</c> tuple (see the - <seealso marker="common_test">common_test reference manual</seealso> for - details). If a time value is returned, a new timetrap is started - to generate a timeout after the specified time.</p> + or a <c>{SecMinOrHourTag,Time}</c> tuple (for details, see module + <seealso marker="common_test">common_test</seealso>). If a time value + is returned, a new timetrap is started to generate a time-out after + the specified time.</p> - <p>The user timetrap function may of course return a time value after a delay, - and if so, the effective timetrap time is the delay time <em>plus</em> the + <p>The user timetrap function can return a time value after a delay. + The effective timetrap time is then the delay time <em>plus</em> the returned time.</p> </section> <section> <marker id="logging"></marker> - <title>Logging - categories and verbosity levels</title> - <p>Common Test provides three main functions for printing strings:</p> - <list> - <item><c>ct:log(Category, Importance, Format, Args)</c></item> - <item><c>ct:print(Category, Importance, Format, Args)</c></item> - <item><c>ct:pal(Category, Importance, Format, Args)</c></item> + <title>Logging - Categories and Verbosity Levels</title> + <p><c>Common Test</c> provides the following three main functions for + printing strings:</p> + <list type="bulleted"> + <item><c>ct:log(Category, Importance, Format, FormatArgs, Opts)</c></item> + <item><c>ct:print(Category, Importance, Format, FormatArgs)</c></item> + <item><c>ct:pal(Category, Importance, Format, FormatArgs)</c></item> </list> - <p>The <c>log/1/2/3/4</c> function will print a string to the test case - log file. The <c>print/1/2/3/4</c> function will print the string to screen, - and the <c>pal/1/2/3/4</c> function will print the same string both to file and - screen. (The functions are documented in the <c>ct</c> reference manual).</p> - - <p>The optional <c>Category</c> argument may be used to categorize the - log printout, and categories can be used for two things:</p> - <list> + <p>The <seealso marker="ct#log-1"><c>log/1,2,3,4,5</c></seealso> function + prints a string to the test case log file. + The <seealso marker="ct#print-1"><c>print/1,2,3,4</c></seealso> function + prints the string to screen. + The <seealso marker="ct#pal-1"><c>pal/1,2,3,4</c></seealso> function + prints the same string both to file and screen. The functions are described + in module <seealso marker="ct">ct</seealso>. + </p> + + <p>The optional <c>Category</c> argument can be used to categorize the + log printout. Categories can be used for two things as follows:</p> + <list type="bulleted"> <item>To compare the importance of the printout to a specific - verbosity level, and</item> - <item>to format the printout according to a user specific HTML + verbosity level.</item> + <item>To format the printout according to a user-specific HTML Style Sheet (CSS).</item> </list> - <p>The <c>Importance</c> argument specifies a level of importance - which, compared to a verbosity level (general and/or set per category), - determines if the printout should be visible or not. <c>Importance</c> - is an arbitrary integer in the range 0..99. Pre-defined constants + <p>Argument <c>Importance</c> specifies a level of importance + that, compared to a verbosity level (general and/or set per category), + determines if the printout is to be visible. <c>Importance</c> + is any integer in the range 0..99. Predefined constants exist in the <c>ct.hrl</c> header file. The default importance level, - <c>?STD_IMPORTANCE</c> (used if the <c>Importance</c> argument is not - provided), is 50. This is also the importance used for standard IO, e.g. - from printouts made with <c>io:format/2</c>, <c>io:put_chars/1</c>, etc.</p> + <c>?STD_IMPORTANCE</c> (used if argument <c>Importance</c> is not + provided), is 50. This is also the importance used for standard I/O, + for example, from printouts made with <c>io:format/2</c>, + <c>io:put_chars/1</c>, and so on.</p> - <p><c>Importance</c> is compared to a verbosity level set by means of the + <p><c>Importance</c> is compared to a verbosity level set by the <c>verbosity</c> start flag/option. The verbosity level can be set per - category and/or generally. The default verbosity level, <c>?STD_VERBOSITY</c>, - is 50, i.e. all standard IO gets printed. If a lower verbosity level is set, - standard IO printouts will be ignored. Common Test performs the following test:</p> - <pre>Importance >= (100-VerbosityLevel)</pre> + category or generally, or both. The default verbosity level, + <c>?STD_VERBOSITY</c>, is 50, that is, all standard I/O gets printed. + If a lower verbosity level is set, standard I/O printouts are ignored. + <c>Common Test</c> performs the following test:</p> + <pre> + Importance >= (100-VerbosityLevel)</pre> <p>This also means that verbosity level 0 effectively turns all logging off - (with the exception of printouts made by Common Test itself).</p> + (except from printouts made by <c>Common Test</c> itself).</p> <p>The general verbosity level is not associated with any particular - category. This level sets the threshold for the standard IO printouts, - uncategorized <c>ct:log/print/pal</c> printouts, as well as + category. This level sets the threshold for the standard I/O printouts, + uncategorized <c>ct:log/print/pal</c> printouts, and printouts for categories with undefined verbosity level.</p> - <p>Example:</p> - <pre> - Some printouts during test case execution: - - io:format("1. Standard IO, importance = ~w~n", [?STD_IMPORTANCE]), - ct:log("2. Uncategorized, importance = ~w", [?STD_IMPORTANCE]), - ct:log(info, "3. Categorized info, importance = ~w", [?STD_IMPORTANCE]]), - ct:log(info, ?LOW_IMPORTANCE, "4. Categorized info, importance = ~w", [?LOW_IMPORTANCE]), - ct:log(error, "5. Categorized error, importance = ~w", [?HI_IMPORTANCE]), - ct:log(error, ?HI_IMPORTANCE, "6. Categorized error, importance = ~w", [?MAX_IMPORTANCE]), - - If starting the test without specifying any verbosity levels: - - $ ct_run ... - - the following gets printed: - - 1. Standard IO, importance = 50 - 2. Uncategorized, importance = 50 - 3. Categorized info, importance = 50 - 5. Categorized error, importance = 75 - 6. Categorized error, importance = 99 - - If starting the test with: - - $ ct_run -verbosity 1 and info 75 - - the following gets printed: - - 3. Categorized info, importance = 50 - 4. Categorized info, importance = 25 - 6. Categorized error, importance = 99</pre> - - <p>How categories can be mapped to CSS tags is documented in the - <seealso marker="run_test_chapter#html_stylesheet">Running Tests</seealso> - chapter.</p> - - <p>The <c>Format</c> and <c>Args</c> arguments in <c>ct:log/print/pal</c> are - always passed on to the <c>io:format/3</c> function in <c>stdlib</c> - (please see the <c>io</c> manual page for details).</p> + <p><em>Examples:</em></p> + <p>Some printouts during test case execution:</p> + <pre> + io:format("1. Standard IO, importance = ~w~n", [?STD_IMPORTANCE]), + ct:log("2. Uncategorized, importance = ~w", [?STD_IMPORTANCE]), + ct:log(info, "3. Categorized info, importance = ~w", [?STD_IMPORTANCE]]), + ct:log(info, ?LOW_IMPORTANCE, "4. Categorized info, importance = ~w", [?LOW_IMPORTANCE]), + ct:log(error, "5. Categorized error, importance = ~w", [?HI_IMPORTANCE]), + ct:log(error, ?HI_IMPORTANCE, "6. Categorized error, importance = ~w", [?MAX_IMPORTANCE]),</pre> + + <p>If starting the test without specifying any verbosity levels as follows:</p> + <pre> + $ ct_run ...</pre> + <p>the following is printed:</p> + <pre> + 1. Standard IO, importance = 50 + 2. Uncategorized, importance = 50 + 3. Categorized info, importance = 50 + 5. Categorized error, importance = 75 + 6. Categorized error, importance = 99</pre> + + <p>If starting the test with:</p> + <pre> + $ ct_run -verbosity 1 and info 75</pre> + <p>the following is printed:</p> + <pre> + 3. Categorized info, importance = 50 + 4. Categorized info, importance = 25 + 6. Categorized error, importance = 99</pre> + + <p>The arguments <c>Format</c> and <c>FormatArgs</c> in <c>ct:log/print/pal</c> are + always passed on to the <c>stdlib</c> function <c>io:format/3</c> (For details, + see the <seealso marker="stdlib:io"><c>stdlib:io</c></seealso> manual page).</p> + + <p><c>ct:pal/4</c> and <c>ct:log/5</c> add headers to strings being printed to the + log file. The strings are also wrapped in div tags with a CSS class + attribute, so that stylesheet formatting can be applied. To disable this feature for + a printout (i.e. to get a result similar to using <c>io:format/2</c>), + call <c>ct:log/5</c> with the <c>no_css</c> option.</p> + + <p>How categories can be mapped to CSS tags is documented in section + <seealso marker="run_test_chapter#html_stylesheet">HTML Style Sheets</seealso> + in section Running Tests and Analyzing Results.</p> - <p>For more information about log files, please see the - <seealso marker="run_test_chapter#log_files">Running Tests</seealso> chapter.</p> + <p>Common Test will escape special HTML characters (<, > and &) in printouts + to the log file made with <c>ct:pal/4</c> and <c>io:format/2</c>. In order to print + strings with HTML tags to the log, use the <c>ct:log/3,4,5</c> function. The character + escaping feature is per default disabled for <c>ct:log/3,4,5</c> but can be enabled with + the <c>esc_chars</c> option in the <c>Opts</c> list, see <seealso marker="ct#log-5"> + <c>ct:log/3,4,5</c></seealso>.</p> + + <p>If the character escaping feature needs to be disabled (typically for backwards + compatibility reasons), use the <c>ct_run</c> start flag <c>-no_esc_chars</c>, or the + <c>ct:run_test/1</c> start option <c>{esc_chars,Bool}</c> (this start option is also + supported in test specifications).</p> + + <p>For more information about log files, see section + <seealso marker="run_test_chapter#log_files">Log Files</seealso> + in section Running Tests and Analyzing Results.</p> </section> <section> - <title>Illegal dependencies</title> + <title>Illegal Dependencies</title> <p>Even though it is highly efficient to write test suites with - the Common Test framework, there will surely be mistakes made, - mainly due to illegal dependencies. Noted below are some of the + the <c>Common Test</c> framework, mistakes can be made, + mainly because of illegal dependencies. Some of the more frequent mistakes from our own experience with running the - Erlang/OTP test suites.</p> + Erlang/OTP test suites follows:</p> - <list> - <item>Depending on current directory, and writing there:<br></br> + <list type="bulleted"> + <item><p>Depending on current directory, and writing there:</p> <p>This is a common error in test suites. It is assumed that - the current directory is the same as what the author used as + the current directory is the same as the author used as current directory when the test case was developed. Many test cases even try to write scratch files to this directory. Instead - <c>data_dir</c> and <c>priv_dir</c> should be used to locate + <c>data_dir</c> and <c>priv_dir</c> are to be used to locate data and for writing scratch files. </p> </item> - <item>Depending on execution order:<br></br> + <item><p>Depending on execution order:</p> - <p>During development of test suites, no assumption should preferrably - be made about the execution order of the test cases or suites. - E.g. a test case should not assume that a server it depends on, - has already been started by a previous test case. There are - several reasons for this: - </p> - <p>Firstly, the user/operator may specify the order at will, and maybe - a different execution order is more relevant or efficient on - some particular occasion. Secondly, if the user specifies a whole - directory of test suites for his/her test, the order the suites are - executed will depend on how the files are listed by the operating - system, which varies between systems. Thirdly, if a user - wishes to run only a subset of a test suite, there is no way - one test case could successfully depend on another. + <p>During development of test suites, make no assumptions on the + execution order of the test cases or suites. For example, a test + case must not assume that a server it depends on is already + started by a previous test case. Reasons for this follows: </p> + <list type="bulleted"> + <item>The user/operator can specify the order at will, and maybe + a different execution order is sometimes more relevant or + efficient.</item> + <item>If the user specifies a whole directory of test suites + for the test, the execution order of the suites depends on + how the files are listed by the operating system, which varies + between systems.</item> + <item>If a user wants to run only a subset of a test suite, + there is no way one test case could successfully depend on + another.</item> + </list> </item> - <item>Depending on Unix:<br></br> + <item><p>Depending on Unix:</p> - <p>Running unix commands through <c>os:cmd</c> are likely - not to work on non-unix platforms. + <p>Running Unix commands through <c>os:cmd</c> are likely + not to work on non-Unix platforms. </p> </item> - <item>Nested test cases:<br></br> + <item><p>Nested test cases:</p> - <p>Invoking a test case from another not only tests the same - thing twice, but also makes it harder to follow what exactly - is being tested. Also, if the called test case fails for some - reason, so will the caller. This way one error gives cause to - several error reports, which is less than ideal. + <p>Starting a test case from another not only tests the same + thing twice, but also makes it harder to follow what is being + tested. Also, if the called test case fails for some + reason, so do the caller. This way, one error gives cause to + several error reports, which is to be avoided. </p> - <p>Functionality common for many test case functions may be implemented - in common help functions. If these functions are useful for test cases - across suites, put the help functions into common help modules. + <p>Functionality common for many test case functions can be + implemented in common help functions. If these functions are + useful for test cases across suites, put the help functions + into common help modules. </p> </item> - <item>Failure to crash or exit when things go wrong:<br></br> + <item><p>Failure to crash or exit when things go wrong:</p> <p>Making requests without checking that the return value - indicates success may be ok if the test case will fail at a - later stage, but it is never acceptable just to print an error - message (into the log file) and return successfully. Such test cases - do harm since they create a false sense of security when overviewing - the test results. + indicates success can be OK if the test case fails + later, but it is never acceptable just to print an error + message (into the log file) and return successfully. Such test + cases do harm, as they create a false sense of security when + overviewing the test results. </p> </item> - <item>Messing up for subsequent test cases:<br></br> + <item><p>Messing up for subsequent test cases:</p> - <p>Test cases should restore as much of the execution - environment as possible, so that the subsequent test cases will - not crash because of execution order of the test cases. - The function <c>end_per_testcase</c> is suitable for this. + <p>Test cases are to restore as much of the execution + environment as possible, so that subsequent test cases + do not crash because of their execution order. + The function + <seealso marker="common_test#Module:end_per_testcase-2"><c>end_per_testcase</c></seealso> + is suitable for this. </p> </item> </list> diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl index 7958a349b4..22941668f2 100644 --- a/lib/common_test/src/ct.erl +++ b/lib/common_test/src/ct.erl @@ -64,7 +64,8 @@ -export([require/1, require/2, get_config/1, get_config/2, get_config/3, reload_config/1, - log/1, log/2, log/3, log/4, + escape_chars/1, escape_chars/2, + log/1, log/2, log/3, log/4, log/5, print/1, print/2, print/3, print/4, pal/1, pal/2, pal/3, pal/4, capture_start/0, capture_stop/0, capture_get/0, capture_get/1, @@ -160,9 +161,9 @@ run(TestDirs) -> %%% {repeat,N} | {duration,DurTime} | {until,StopTime} | %%% {force_stop,ForceStop} | {decrypt,DecryptKeyOrFile} | %%% {refresh_logs,LogDir} | {logopts,LogOpts} | -%%% {verbosity,VLevels} | {basic_html,Bool} | -%%% {ct_hooks, CTHs} | {enable_builtin_hooks,Bool} | -%%% {release_shell,Bool} +%%% {verbosity,VLevels} | {basic_html,Bool} | +%%% {esc_chars,Bool} | {ct_hooks, CTHs} | +%%% {enable_builtin_hooks,Bool} | {release_shell,Bool} %%% TestDirs = [string()] | string() %%% Suites = [string()] | [atom()] | string() | atom() %%% Cases = [atom()] | atom() @@ -509,44 +510,88 @@ get_testspec_terms(Tags) -> %%%----------------------------------------------------------------- +%%% @spec escape_chars(IoList1) -> IoList2 | {error,Reason} +%%% IoList1 = iolist() +%%% IoList2 = iolist() +%%% +%%% @doc Escape special characters to be printed in html log +%%% +escape_chars(IoList) -> + ct_logs:escape_chars(IoList). + +%%%----------------------------------------------------------------- +%%% @spec escape_chars(Format, Args) -> IoList | {error,Reason} +%%% Format = string() +%%% Args = list() +%%% +%%% @doc Escape special characters to be printed in html log +%%% +escape_chars(Format, Args) -> + try io_lib:format(Format, Args) of + IoList -> + ct_logs:escape_chars(IoList) + catch + _:Reason -> + {error,Reason} + end. + +%%%----------------------------------------------------------------- %%% @spec log(Format) -> ok -%%% @equiv log(default,50,Format,[]) +%%% @equiv log(default,50,Format,[],[]) log(Format) -> - log(default,?STD_IMPORTANCE,Format,[]). + log(default,?STD_IMPORTANCE,Format,[],[]). %%%----------------------------------------------------------------- %%% @spec log(X1,X2) -> ok %%% X1 = Category | Importance | Format %%% X2 = Format | Args -%%% @equiv log(Category,Importance,Format,Args) +%%% @equiv log(Category,Importance,Format,Args,[]) log(X1,X2) -> {Category,Importance,Format,Args} = if is_atom(X1) -> {X1,?STD_IMPORTANCE,X2,[]}; is_integer(X1) -> {default,X1,X2,[]}; is_list(X1) -> {default,?STD_IMPORTANCE,X1,X2} end, - log(Category,Importance,Format,Args). + log(Category,Importance,Format,Args,[]). %%%----------------------------------------------------------------- %%% @spec log(X1,X2,X3) -> ok +%%% X1 = Category | Importance | Format +%%% X2 = Importance | Format | Args +%%% X3 = Format | Args | Opts +%%% @equiv log(Category,Importance,Format,Args,Opts) +log(X1,X2,X3) -> + {Category,Importance,Format,Args,Opts} = + if is_atom(X1), is_integer(X2) -> {X1,X2,X3,[],[]}; + is_atom(X1), is_list(X2) -> {X1,?STD_IMPORTANCE,X2,X3,[]}; + is_integer(X1) -> {default,X1,X2,X3,[]}; + is_list(X1), is_list(X2) -> {default,?STD_IMPORTANCE,X1,X2,X3} + end, + log(Category,Importance,Format,Args,Opts). + +%%%----------------------------------------------------------------- +%%% @spec log(X1,X2,X3,X4) -> ok %%% X1 = Category | Importance %%% X2 = Importance | Format %%% X3 = Format | Args -%%% @equiv log(Category,Importance,Format,Args) -log(X1,X2,X3) -> - {Category,Importance,Format,Args} = - if is_atom(X1), is_integer(X2) -> {X1,X2,X3,[]}; - is_atom(X1), is_list(X2) -> {X1,?STD_IMPORTANCE,X2,X3}; - is_integer(X1) -> {default,X1,X2,X3} +%%% X4 = Args | Opts +%%% @equiv log(Category,Importance,Format,Args,Opts) +log(X1,X2,X3,X4) -> + {Category,Importance,Format,Args,Opts} = + if is_atom(X1), is_integer(X2) -> {X1,X2,X3,X4,[]}; + is_atom(X1), is_list(X2) -> {X1,?STD_IMPORTANCE,X2,X3,X4}; + is_integer(X1) -> {default,X1,X2,X3,X4} end, - log(Category,Importance,Format,Args). + log(Category,Importance,Format,Args,Opts). %%%----------------------------------------------------------------- -%%% @spec log(Category,Importance,Format,Args) -> ok +%%% @spec log(Category,Importance,Format,Args,Opts) -> ok %%% Category = atom() %%% Importance = integer() %%% Format = string() %%% Args = list() +%%% Opts = [Opt] +%%% Opt = esc_chars | no_css %%% %%% @doc Printout from a test case to the log file. %%% @@ -558,8 +603,8 @@ log(X1,X2,X3) -> %%% and default value for <c>Args</c> is <c>[]</c>.</p> %%% <p>Please see the User's Guide for details on <c>Category</c> %%% and <c>Importance</c>.</p> -log(Category,Importance,Format,Args) -> - ct_logs:tc_log(Category,Importance,Format,Args). +log(Category,Importance,Format,Args,Opts) -> + ct_logs:tc_log(Category,Importance,Format,Args,Opts). %%%----------------------------------------------------------------- diff --git a/lib/common_test/src/ct_conn_log_h.erl b/lib/common_test/src/ct_conn_log_h.erl index 2dd4fdac05..034906a3ba 100644 --- a/lib/common_test/src/ct_conn_log_h.erl +++ b/lib/common_test/src/ct_conn_log_h.erl @@ -104,40 +104,63 @@ terminate(_,#state{logs=Logs}) -> %%%----------------------------------------------------------------- %%% Writing reports write_report(_Time,#conn_log{header=false,module=ConnMod}=Info,Data,GL,State) -> - {LogType,Fd} = get_log(Info,GL,State), - io:format(Fd,"~n~ts",[format_data(ConnMod,LogType,Data)]); + case get_log(Info,GL,State) of + {silent,_,_} -> + ok; + {LogType,Dest,Fd} -> + Str = if LogType == html, Dest == gl -> ["$tc_html","~n~ts"]; + true -> "~n~ts" + end, + io:format(Fd,Str,[format_data(ConnMod,LogType,Data)]) + end; write_report(Time,#conn_log{module=ConnMod}=Info,Data,GL,State) -> - {LogType,Fd} = get_log(Info,GL,State), - io:format(Fd,"~n~ts~ts~ts",[format_head(ConnMod,LogType,Time), - format_title(LogType,Info), - format_data(ConnMod,LogType,Data)]). + case get_log(Info,GL,State) of + {silent,_,_} -> + ok; + {LogType,Dest,Fd} -> + case format_data(ConnMod,LogType,Data) of + [] when Info#conn_log.action==send; Info#conn_log.action==recv -> + ok; + FormattedData -> + Str = if LogType == html, Dest == gl -> + ["$tc_html","~n~ts~ts~ts"]; + true -> + "~n~ts~ts~ts" + end, + io:format(Fd,Str,[format_head(ConnMod,LogType,Time), + format_title(LogType,Info), + FormattedData]) + end + end. write_error(Time,#conn_log{module=ConnMod}=Info,Report,GL,State) -> case get_log(Info,GL,State) of - {html,_} -> + {LogType,_,_} when LogType==html; LogType==silent -> %% The error will anyway be written in the html log by the %% sasl error handler, so don't write it again. ok; - {LogType,Fd} -> - io:format(Fd,"~n~ts~ts~ts", - [format_head(ConnMod,LogType,Time," ERROR"), - format_title(LogType,Info), - format_error(LogType,Report)]) + {LogType,Dest,Fd} -> + Str = if LogType == html, Dest == gl -> ["$tc_html","~n~ts~ts~ts"]; + true -> "~n~ts~ts~ts" + end, + io:format(Fd,Str,[format_head(ConnMod,LogType,Time," ERROR"), + format_title(LogType,Info), + format_error(LogType,Report)]) end. get_log(Info,GL,State) -> case proplists:get_value(GL,State#state.logs) of undefined -> - {html,State#state.default_gl}; + {html,gl,State#state.default_gl}; ConnLogs -> case proplists:get_value(Info#conn_log.module,ConnLogs) of {html,_} -> - {html,GL}; + {html,gl,GL}; {LogType,Fds} -> - {LogType,get_fd(Info,Fds)}; + {LogType,file,get_fd(Info,Fds)}; undefined -> - {html,GL} + {html,gl,GL} end end. diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl index f792269c41..19a3a51b88 100644 --- a/lib/common_test/src/ct_framework.erl +++ b/lib/common_test/src/ct_framework.erl @@ -28,7 +28,7 @@ -export([init_tc/3, end_tc/3, end_tc/4, get_suite/2, get_all_cases/1]). -export([report/2, warn/1, error_notification/4]). --export([get_logopts/0, format_comment/1, get_html_wrapper/4]). +-export([get_log_dir/0, get_logopts/0, format_comment/1, get_html_wrapper/4]). -export([error_in_suite/1, init_per_suite/1, end_per_suite/1, init_per_group/2, end_per_group/2]). @@ -52,9 +52,23 @@ %%% %%% @doc Test server framework callback, called by the test_server %%% when a new test case is started. -init_tc(Mod,Func,Config) -> +init_tc(Mod,EPTC={end_per_testcase,_},[Config]) -> %% in case Mod == ct_framework, lookup the suite name Suite = get_suite_name(Mod, Config), + case ct_hooks:init_tc(Suite,EPTC,Config) of + NewConfig when is_list(NewConfig) -> + {ok,[NewConfig]}; + Other-> + Other + end; + +init_tc(Mod,Func0,Args) -> + %% in case Mod == ct_framework, lookup the suite name + Suite = get_suite_name(Mod, Args), + {Func,HookFunc} = case Func0 of + {init_per_testcase,F} -> {F,Func0}; + _ -> {Func0,Func0} + end, %% check if previous testcase was interpreted and has left %% a "dead" trace window behind - if so, kill it @@ -86,7 +100,7 @@ init_tc(Mod,Func,Config) -> end, [create]), case ct_util:read_suite_data({seq,Suite,Func}) of undefined -> - init_tc1(Mod,Suite,Func,Config); + init_tc1(Mod,Suite,Func,HookFunc,Args); Seq when is_atom(Seq) -> case ct_util:read_suite_data({seq,Suite,Seq}) of [Func|TCs] -> % this is the 1st case in Seq @@ -102,27 +116,27 @@ init_tc(Mod,Func,Config) -> _ -> ok end, - init_tc1(Mod,Suite,Func,Config); + init_tc1(Mod,Suite,Func,HookFunc,Args); {failed,Seq,BadFunc} -> {auto_skip,{sequence_failed,Seq,BadFunc}} end end - end. + end. -init_tc1(?MODULE,_,error_in_suite,[Config0]) when is_list(Config0) -> +init_tc1(?MODULE,_,error_in_suite,_,[Config0]) when is_list(Config0) -> ct_logs:init_tc(false), ct_event:notify(#event{name=tc_start, node=node(), data={?MODULE,error_in_suite}}), - ct_suite_init(?MODULE, error_in_suite, [], Config0), - case ?val(error, Config0) of + ct_suite_init(?MODULE,error_in_suite,[],Config0), + case ?val(error,Config0) of undefined -> {fail,"unknown_error_in_suite"}; Reason -> {fail,Reason} end; -init_tc1(Mod,Suite,Func,[Config0]) when is_list(Config0) -> +init_tc1(Mod,Suite,Func,HookFunc,[Config0]) when is_list(Config0) -> Config1 = case ct_util:read_suite_data(last_saved_config) of {{Suite,LastFunc},SavedConfig} -> % last testcase @@ -156,11 +170,13 @@ init_tc1(Mod,Suite,Func,[Config0]) when is_list(Config0) -> %% testcase info function (these should only survive the %% testcase, not the whole suite) FuncSpec = group_or_func(Func,Config0), - if is_tuple(FuncSpec) -> % group - ok; - true -> - ct_config:delete_default_config(testcase) - end, + HookFunc1 = + if is_tuple(FuncSpec) -> % group + FuncSpec; + true -> + ct_config:delete_default_config(testcase), + HookFunc + end, Initialize = fun() -> ct_logs:init_tc(false), ct_event:notify(#event{name=tc_start, @@ -184,14 +200,15 @@ init_tc1(Mod,Suite,Func,[Config0]) when is_list(Config0) -> Initialize(), {fail,Reason}; _ -> - init_tc2(Mod,Suite,Func,SuiteInfo,MergeResult,Config) + init_tc2(Mod,Suite,Func,HookFunc1, + SuiteInfo,MergeResult,Config) end end; -init_tc1(_Mod,_Suite,_Func,Args) -> +init_tc1(_Mod,_Suite,_Func,_HookFunc,Args) -> {ok,Args}. -init_tc2(Mod,Suite,Func,SuiteInfo,MergeResult,Config) -> +init_tc2(Mod,Suite,Func,HookFunc,SuiteInfo,MergeResult,Config) -> %% timetrap must be handled before require MergedInfo = timetrap_first(MergeResult, [], []), %% tell logger to use specified style sheet @@ -238,7 +255,7 @@ init_tc2(Mod,Suite,Func,SuiteInfo,MergeResult,Config) -> {ok,PostInitHook,Config1} -> case get('$test_server_framework_test') of undefined -> - ct_suite_init(Suite, FuncSpec, PostInitHook, Config1); + ct_suite_init(Suite,HookFunc,PostInitHook,Config1); Fun -> PostInitHookResult = do_post_init_hook(PostInitHook, Config1), @@ -251,16 +268,16 @@ init_tc2(Mod,Suite,Func,SuiteInfo,MergeResult,Config) -> end end. -ct_suite_init(Suite, FuncSpec, PostInitHook, Config) when is_list(Config) -> - case ct_hooks:init_tc(Suite, FuncSpec, Config) of +ct_suite_init(Suite,HookFunc,PostInitHook,Config) when is_list(Config) -> + case ct_hooks:init_tc(Suite,HookFunc,Config) of NewConfig when is_list(NewConfig) -> - PostInitHookResult = do_post_init_hook(PostInitHook, NewConfig), + PostInitHookResult = do_post_init_hook(PostInitHook,NewConfig), {ok, [PostInitHookResult ++ NewConfig]}; Else -> Else end. -do_post_init_hook(PostInitHook, Config) -> +do_post_init_hook(PostInitHook,Config) -> lists:flatmap(fun({Tag,Fun}) -> case lists:keysearch(Tag,1,Config) of {value,_} -> @@ -657,9 +674,23 @@ end_tc(Mod,Func,{TCPid,Result,[Args]}, Return) when is_pid(TCPid) -> end_tc(Mod,Func,{Result,[Args]}, Return) -> end_tc(Mod,Func,self(),Result,Args,Return). -end_tc(Mod,Func,TCPid,Result,Args,Return) -> +end_tc(Mod,IPTC={init_per_testcase,_Func},_TCPid,Result,Args,Return) -> + %% in case Mod == ct_framework, lookup the suite name + Suite = get_suite_name(Mod, Args), + case ct_hooks:end_tc(Suite,IPTC,Args,Result,Return) of + '$ct_no_change' -> + ok; + HookResult -> + HookResult + end; + +end_tc(Mod,Func0,TCPid,Result,Args,Return) -> %% in case Mod == ct_framework, lookup the suite name Suite = get_suite_name(Mod, Args), + {EPTC,Func} = case Func0 of + {end_per_testcase,F} -> {true,F}; + _ -> {false,Func0} + end, test_server:timetrap_cancel(), @@ -686,11 +717,15 @@ end_tc(Mod,Func,TCPid,Result,Args,Return) -> end, ct_util:delete_suite_data(last_saved_config), - FuncSpec = group_or_func(Func,Args), - + {FuncSpec,HookFunc} = + if not EPTC -> + FS = group_or_func(Func,Args), + {FS,FS}; + true -> + {Func,Func0} + end, {Result1,FinalNotify} = - case ct_hooks:end_tc( - Suite, FuncSpec, Args, Result, Return) of + case ct_hooks:end_tc(Suite,HookFunc,Args,Result,Return) of '$ct_no_change' -> {ok,Result}; HookResult -> @@ -831,13 +866,13 @@ tag(_Other) -> %%% <code>Func</code> in suite <code>Mod</code> crashing. %%% <code>Error</code> specifies the reason for failing. error_notification(Mod,Func,_Args,{Error,Loc}) -> - ErrSpec = case Error of + ErrorSpec = case Error of {What={_E,_R},Trace} when is_list(Trace) -> What; What -> What end, - ErrStr = case ErrSpec of + ErrorStr = case ErrorSpec of {badmatch,Descr} -> Descr1 = lists:flatten(io_lib:format("~P",[Descr,10])), if length(Descr1) > 50 -> @@ -859,7 +894,8 @@ error_notification(Mod,Func,_Args,{Error,Loc}) -> Other -> io_lib:format("~P", [Other,5]) end, - ErrorHtml = "<font color=\"brown\">" ++ ErrStr ++ "</font>", + ErrorHtml = + "<font color=\"brown\">" ++ ct_logs:escape_chars(ErrorStr) ++ "</font>", case {Mod,Error} of %% some notifications come from the main test_server process %% and for these cases the existing comment may not be modified @@ -887,41 +923,43 @@ error_notification(Mod,Func,_Args,{Error,Loc}) -> end end, - PrintErr = fun(ErrFormat, ErrArgs) -> + PrintError = fun(ErrorFormat, ErrorArgs) -> Div = "~n- - - - - - - - - - - - - - - - - - - " "- - - - - - - - - - - - - - - - - - - - -~n", - io:format(user, lists:concat([Div,ErrFormat,Div,"~n"]), - ErrArgs), + ErrorStr2 = io_lib:format(ErrorFormat, ErrorArgs), + io:format(user, lists:concat([Div,ErrorStr2,Div,"~n"]), + []), Link = "\n\n<a href=\"#end\">" "Full error description and stacktrace" "</a>", + ErrorHtml2 = ct_logs:escape_chars(ErrorStr2), ct_logs:tc_log(ct_error_notify, ?MAX_IMPORTANCE, "CT Error Notification", - ErrFormat++Link, ErrArgs) + ErrorHtml2++Link, [], []) end, case Loc of [{?MODULE,error_in_suite}] -> - PrintErr("Error in suite detected: ~ts", [ErrStr]); + PrintError("Error in suite detected: ~ts", [ErrorStr]); R when R == unknown; R == undefined -> - PrintErr("Error detected: ~ts", [ErrStr]); + PrintError("Error detected: ~ts", [ErrorStr]); %% if a function specified by all/0 does not exist, we %% pick up undef here - [{LastMod,LastFunc}|_] when ErrStr == "undef" -> - PrintErr("~w:~w could not be executed~nReason: ~ts", - [LastMod,LastFunc,ErrStr]); + [{LastMod,LastFunc}|_] when ErrorStr == "undef" -> + PrintError("~w:~w could not be executed~nReason: ~ts", + [LastMod,LastFunc,ErrorStr]); [{LastMod,LastFunc}|_] -> - PrintErr("~w:~w failed~nReason: ~ts", [LastMod,LastFunc,ErrStr]); + PrintError("~w:~w failed~nReason: ~ts", [LastMod,LastFunc,ErrorStr]); [{LastMod,LastFunc,LastLine}|_] -> %% print error to console, we are only %% interested in the last executed expression - PrintErr("~w:~w failed on line ~w~nReason: ~ts", - [LastMod,LastFunc,LastLine,ErrStr]), + PrintError("~w:~w failed on line ~w~nReason: ~ts", + [LastMod,LastFunc,LastLine,ErrorStr]), case ct_util:read_suite_data({seq,Mod,Func}) of undefined -> @@ -1480,3 +1518,8 @@ get_html_wrapper(TestName, PrintLabel, Cwd, TableCols) -> get_html_wrapper(TestName, PrintLabel, Cwd, TableCols, Encoding) -> ct_logs:get_ts_html_wrapper(TestName, PrintLabel, Cwd, TableCols, Encoding). + +%%%----------------------------------------------------------------- +%%% @spec get_log_dir() -> {ok,LogDir} +get_log_dir() -> + ct_logs:get_log_dir(true). diff --git a/lib/common_test/src/ct_gen_conn.erl b/lib/common_test/src/ct_gen_conn.erl index e46fd77383..e28c89ab1d 100644 --- a/lib/common_test/src/ct_gen_conn.erl +++ b/lib/common_test/src/ct_gen_conn.erl @@ -27,7 +27,7 @@ -export([start/4, stop/1, get_conn_pid/1, check_opts/1]). -export([call/2, call/3, return/2, do_within_time/2]). --export([log/3, start_log/1, cont_log/2, end_log/0]). +-export([log/3, start_log/1, cont_log/2, cont_log_no_timestamp/2, end_log/0]). %%---------------------------------------------------------------------- %% Exported types @@ -175,6 +175,14 @@ cont_log(Format,Args) -> log(cont_log,[Format,Args]). %%%----------------------------------------------------------------- +%%% @spec cont_log_no_timestamp(Format,Args) -> ok +%%% +%%% @doc Log activities on the current connection (tool-internal use only). +%%% @see ct_logs:cont_log/2 +cont_log_no_timestamp(Format,Args) -> + log(cont_log_no_timestamp,[Format,Args]). + +%%%----------------------------------------------------------------- %%% @spec end_log() -> ok %%% %%% @doc Log activities on the current connection (tool-internal use only). diff --git a/lib/common_test/src/ct_groups.erl b/lib/common_test/src/ct_groups.erl index 7636f15f59..899d2bfb5a 100644 --- a/lib/common_test/src/ct_groups.erl +++ b/lib/common_test/src/ct_groups.erl @@ -81,7 +81,7 @@ find(Mod, all, all, [{Name,Props,Tests} | Gs], Known, Defs, _) find(Mod, all, TCs, [{Name,Props,Tests} | Gs], Known, Defs, _) when is_atom(Name), is_list(Props), is_list(Tests) -> cyclic_test(Mod, Name, Known), - Tests1 = rm_unwanted_tcs(Tests, TCs, []), + Tests1 = modify_tc_list(Tests, TCs, []), trim(make_conf(Mod, Name, Props, find(Mod, all, TCs, Tests1, [Name | Known], Defs, true))) ++ @@ -91,7 +91,7 @@ find(Mod, all, TCs, [{Name,Props,Tests} | Gs], Known, Defs, _) find(Mod, [Name|GrNames]=SPath, TCs, [{Name,Props,Tests} | Gs], Known, Defs, FindAll) when is_atom(Name), is_list(Props), is_list(Tests) -> cyclic_test(Mod, Name, Known), - Tests1 = rm_unwanted_tcs(Tests, TCs, GrNames), + Tests1 = modify_tc_list(Tests, TCs, GrNames), trim(make_conf(Mod, Name, Props, find(Mod, GrNames, TCs, Tests1, [Name|Known], Defs, FindAll))) ++ @@ -133,7 +133,7 @@ find(_Mod, [_|_], _TCs, [], _Known, _Defs, _) -> find(Mod, GrNames, TCs, [{Name,Props,Tests} | Gs], Known, Defs, FindAll) when is_atom(Name), is_list(Props), is_list(Tests) -> cyclic_test(Mod, Name, Known), - Tests1 = rm_unwanted_tcs(Tests, TCs, GrNames), + Tests1 = modify_tc_list(Tests, TCs, GrNames), trim(make_conf(Mod, Name, Props, find(Mod, GrNames, TCs, Tests1, [Name|Known], Defs, FindAll))) ++ @@ -284,70 +284,57 @@ trim_test(Test) -> %% GrNames is [] if the terminating group has been found. From %% that point, all specified test should be included (as well as %% sub groups for deeper search). -rm_unwanted_tcs(Tests, all, []) -> - Tests; - -rm_unwanted_tcs(Tests, TCs, []) -> - sort_tests(lists:flatmap(fun(Test) when is_tuple(Test), - (size(Test) > 2) -> - [Test]; - (Test={group,_}) -> - [Test]; - (Test={_M,TC}) -> - case lists:member(TC, TCs) of - true -> [Test]; - false -> [] - end; - (Test) when is_atom(Test) -> - case lists:keysearch(Test, 2, TCs) of - {value,_} -> - [Test]; - _ -> - case lists:member(Test, TCs) of - true -> [Test]; - false -> [] - end - end; - (Test) -> [Test] - end, Tests), TCs); - -rm_unwanted_tcs(Tests, _TCs, _) -> - [Test || Test <- Tests, not is_atom(Test)]. - -%% make sure the order of tests is according to the order in TCs -sort_tests(Tests, TCs) when is_list(TCs)-> - lists:sort(fun(T1, T2) -> - case {is_tc(T1),is_tc(T2)} of - {true,true} -> - (position(T1, TCs) =< - position(T2, TCs)); - {false,true} -> - (position(T2, TCs) == (length(TCs)+1)); - _ -> true - - end - end, Tests); -sort_tests(Tests, _) -> - Tests. - -is_tc(T) when is_atom(T) -> true; -is_tc({group,_}) -> false; -is_tc({_M,T}) when is_atom(T) -> true; -is_tc(_) -> false. - -position(T, TCs) -> - position(T, TCs, 1). - -position(T, [T|_TCs], Pos) -> - Pos; -position(T, [{_,T}|_TCs], Pos) -> - Pos; -position({M,T}, [T|_TCs], Pos) when M /= group -> - Pos; -position(T, [_|TCs], Pos) -> - position(T, TCs, Pos+1); -position(_, [], Pos) -> - Pos. +modify_tc_list(GrSpecTs, all, []) -> + GrSpecTs; + +modify_tc_list(GrSpecTs, TSCs, []) -> + modify_tc_list1(GrSpecTs, TSCs); + +modify_tc_list(GrSpecTs, _TSCs, _) -> + [Test || Test <- GrSpecTs, not is_atom(Test)]. + +modify_tc_list1(GrSpecTs, TSCs) -> + %% remove all cases in group tc list that should not be executed + GrSpecTs1 = + lists:flatmap(fun(Test) when is_tuple(Test), + (size(Test) > 2) -> + [Test]; + (Test={group,_}) -> + [Test]; + (Test={_M,TC}) -> + case lists:member(TC, TSCs) of + true -> [Test]; + false -> [] + end; + (Test) when is_atom(Test) -> + case lists:keysearch(Test, 2, TSCs) of + {value,_} -> + [Test]; + _ -> + case lists:member(Test, TSCs) of + true -> [Test]; + false -> [] + end + end; + (Test) -> [Test] + end, GrSpecTs), + {TSCs2,GrSpecTs3} = + lists:foldr( + fun(TC, {TSCs1,GrSpecTs2}) -> + case lists:member(TC,GrSpecTs1) of + true -> + {[TC|TSCs1],lists:delete(TC,GrSpecTs2)}; + false -> + case lists:keysearch(TC, 2, GrSpecTs) of + {value,Test} -> + {[Test|TSCs1], + lists:keydelete(TC, 2, GrSpecTs2)}; + false -> + {TSCs1,GrSpecTs2} + end + end + end, {[],GrSpecTs1}, TSCs), + TSCs2 ++ GrSpecTs3. %%%----------------------------------------------------------------- diff --git a/lib/common_test/src/ct_hooks.erl b/lib/common_test/src/ct_hooks.erl index 86d18696dc..90f36cbdc2 100644 --- a/lib/common_test/src/ct_hooks.erl +++ b/lib/common_test/src/ct_hooks.erl @@ -67,6 +67,8 @@ terminate(Hooks) -> %% tests. -spec init_tc(Mod :: atom(), FuncSpec :: atom() | + {ConfigFunc :: init_per_testcase | end_per_testcase, + TestCase :: atom()} | {ConfigFunc :: init_per_group | end_per_group, GroupName :: atom(), Properties :: list()}, @@ -93,13 +95,19 @@ init_tc(Mod, {init_per_group, GroupName, Properties}, Config) -> call(fun call_generic/3, Config, [pre_init_per_group, GroupName]); init_tc(_Mod, {end_per_group, GroupName, _}, Config) -> call(fun call_generic/3, Config, [pre_end_per_group, GroupName]); -init_tc(_Mod, TC, Config) -> +init_tc(_Mod, {init_per_testcase,TC}, Config) -> + call(fun call_generic/3, Config, [pre_init_per_testcase, TC]); +init_tc(_Mod, {end_per_testcase,TC}, Config) -> + call(fun call_generic/3, Config, [pre_end_per_testcase, TC]); +init_tc(_Mod, TC = error_in_suite, Config) -> call(fun call_generic/3, Config, [pre_init_per_testcase, TC]). %% @doc Called as each test case is completed. This includes all configuration %% tests. -spec end_tc(Mod :: atom(), - FuncSpec :: atom() | + FuncSpec :: atom() | + {ConfigFunc :: init_per_testcase | end_per_testcase, + TestCase :: atom()} | {ConfigFunc :: init_per_group | end_per_group, GroupName :: atom(), Properties :: list()}, @@ -126,10 +134,17 @@ end_tc(Mod, {end_per_group, GroupName, Properties}, Config, Result, _Return) -> [post_end_per_group, GroupName, Config], '$ct_no_change'), maybe_stop_locker(Mod, GroupName, Properties), Res; -end_tc(_Mod, TC, Config, Result, _Return) -> +end_tc(_Mod, {init_per_testcase,TC}, Config, Result, _Return) -> + call(fun call_generic/3, Result, [post_init_per_testcase, TC, Config], + '$ct_no_change'); +end_tc(_Mod, {end_per_testcase,TC}, Config, Result, _Return) -> + call(fun call_generic/3, Result, [post_end_per_testcase, TC, Config], + '$ct_no_change'); +end_tc(_Mod, TC = error_in_suite, Config, Result, _Return) -> call(fun call_generic/3, Result, [post_end_per_testcase, TC, Config], '$ct_no_change'). + %% Case = TestCase | {TestCase,GroupName} on_tc_skip(How, {Suite, Case, Reason}) -> call(fun call_cleanup/3, {How, Reason}, [on_tc_skip, Suite, Case]). @@ -244,6 +259,8 @@ remove(_, Else) -> %% Translate scopes, i.e. init_per_group,group1 -> end_per_group,group1 etc scope([pre_init_per_testcase, TC|_]) -> + [post_init_per_testcase, TC]; +scope([pre_end_per_testcase, TC|_]) -> [post_end_per_testcase, TC]; scope([pre_init_per_group, GroupName|_]) -> [post_end_per_group, GroupName]; @@ -317,7 +334,8 @@ get_hooks() -> %% If we are doing a cleanup call i.e. {post,pre}_end_per_*, all priorities %% are reversed. Probably want to make this sorting algorithm pluginable %% as some point... -resort(Calls,Hooks,[F|_R]) when F == post_end_per_testcase; +resort(Calls,Hooks,[F|_R]) when F == pre_end_per_testcase; + F == post_end_per_testcase; F == pre_end_per_group; F == post_end_per_group; F == pre_end_per_suite; @@ -367,10 +385,10 @@ pos(Id,[_|Rest],Num) -> catch_apply(M,F,A, Default) -> try - apply(M,F,A) + erlang:apply(M,F,A) catch _:Reason -> case erlang:get_stacktrace() of - %% Return the default if it was the CTH module which did not have the function. + %% Return the default if it was the CTH module which did not have the function. [{M,F,A,_}|_] when Reason == undef -> Default; Trace -> diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl index 78081380e7..d87d26e5ba 100644 --- a/lib/common_test/src/ct_logs.erl +++ b/lib/common_test/src/ct_logs.erl @@ -32,20 +32,22 @@ -export([init/2, close/2, init_tc/1, end_tc/1]). -export([register_groupleader/2, unregister_groupleader/1]). -export([get_log_dir/0, get_log_dir/1]). --export([log/3, start_log/1, cont_log/2, end_log/0]). +-export([log/3, start_log/1, cont_log/2, cont_log_no_timestamp/2, end_log/0]). -export([set_stylesheet/2, clear_stylesheet/1]). -export([add_external_logs/1, add_link/3]). -export([make_last_run_index/0]). -export([make_all_suites_index/1,make_all_runs_index/1]). --export([get_ts_html_wrapper/5]). +-export([get_ts_html_wrapper/5, escape_chars/1]). -export([xhtml/2, locate_priv_file/1, make_relative/1]). -export([insert_javascript/1]). -export([uri/1]). %% Logging stuff directly from testcase --export([tc_log/3, tc_log/4, tc_log/5, tc_log_async/3, tc_log_async/5, +-export([tc_log/3, tc_log/4, tc_log/5, tc_log/6, + tc_log_async/3, tc_log_async/5, tc_print/3, tc_print/4, - tc_pal/3, tc_pal/4, ct_log/3, basic_html/0]). + tc_pal/3, tc_pal/4, ct_log/3, + basic_html/0]). %% Simulate logger process for use without ct environment running -export([simulate/0]). @@ -267,7 +269,7 @@ cast(Msg) -> %%% <p>This function is called by ct_framework:init_tc/3</p> init_tc(RefreshLog) -> call({init_tc,self(),group_leader(),RefreshLog}), - io:format(xhtml("", "<br />")), + io:format(["$tc_html",xhtml("", "<br />")]), ok. %%%----------------------------------------------------------------- @@ -314,9 +316,10 @@ unregister_groupleader(Pid) -> %%% data to log (as in <code>io:format(Format,Args)</code>).</p> log(Heading,Format,Args) -> cast({log,sync,self(),group_leader(),ct_internal,?MAX_IMPORTANCE, - [{int_header(),[log_timestamp(?now),Heading]}, + [{hd,int_header(),[log_timestamp(?now),Heading]}, {Format,Args}, - {int_footer(),[]}]}), + {ft,int_footer(),[]}], + true}), ok. %%%----------------------------------------------------------------- @@ -336,7 +339,7 @@ log(Heading,Format,Args) -> %%% @see end_log/0 start_log(Heading) -> cast({log,sync,self(),group_leader(),ct_internal,?MAX_IMPORTANCE, - [{int_header(),[log_timestamp(?now),Heading]}]}), + [{hd,int_header(),[log_timestamp(?now),Heading]}],false}), ok. %%%----------------------------------------------------------------- @@ -351,7 +354,21 @@ cont_log([],[]) -> cont_log(Format,Args) -> maybe_log_timestamp(), cast({log,sync,self(),group_leader(),ct_internal,?MAX_IMPORTANCE, - [{Format,Args}]}), + [{Format,Args}],true}), + ok. + +%%%----------------------------------------------------------------- +%%% @spec cont_log_no_timestamp(Format,Args) -> ok +%%% +%%% @doc Adds information about an activity (tool-internal use only). +%%% +%%% @see start_log/1 +%%% @see end_log/0 +cont_log_no_timestamp([],[]) -> + ok; +cont_log_no_timestamp(Format,Args) -> + cast({log,sync,self(),group_leader(),ct_internal,?MAX_IMPORTANCE, + [{Format,Args}],true}), ok. %%%----------------------------------------------------------------- @@ -363,7 +380,7 @@ cont_log(Format,Args) -> %%% @see cont_log/2 end_log() -> cast({log,sync,self(),group_leader(),ct_internal,?MAX_IMPORTANCE, - [{int_footer(), []}]}), + [{ft,int_footer(), []}],false}), ok. @@ -400,32 +417,46 @@ add_link(Heading,File,Type) -> %%% @spec tc_log(Category,Format,Args) -> ok %%% @equiv tc_log(Category,?STD_IMPORTANCE,Format,Args) tc_log(Category,Format,Args) -> - tc_log(Category,?STD_IMPORTANCE,Format,Args). + tc_log(Category,?STD_IMPORTANCE,"User",Format,Args,[]). %%%----------------------------------------------------------------- %%% @spec tc_log(Category,Importance,Format,Args) -> ok %%% @equiv tc_log(Category,Importance,"User",Format,Args) tc_log(Category,Importance,Format,Args) -> - tc_log(Category,Importance,"User",Format,Args). + tc_log(Category,Importance,"User",Format,Args,[]). %%%----------------------------------------------------------------- -%%% @spec tc_log(Category,Importance,Printer,Format,Args) -> ok +%%% @spec tc_log(Category,Importance,Format,Args) -> ok +%%% @equiv tc_log(Category,Importance,"User",Format,Args) +tc_log(Category,Importance,Format,Args,Opts) -> + tc_log(Category,Importance,"User",Format,Args,Opts). + +%%%----------------------------------------------------------------- +%%% @spec tc_log(Category,Importance,Printer,Format,Args,Opts) -> ok %%% Category = atom() %%% Importance = integer() %%% Printer = string() %%% Format = string() %%% Args = list() +%%% Opts = list() %%% %%% @doc Printout from a testcase. %%% %%% <p>This function is called by <code>ct</code> when logging %%% stuff directly from a testcase (i.e. not from within the CT %%% framework).</p> -tc_log(Category,Importance,Printer,Format,Args) -> - cast({log,sync,self(),group_leader(),Category,Importance, - [{div_header(Category,Printer),[]}, - {Format,Args}, - {div_footer(),[]}]}), +tc_log(Category,Importance,Printer,Format,Args,Opts) -> + Data = + case lists:member(no_css, Opts) of + true -> + [{Format,Args}]; + false -> + [{hd,div_header(Category,Printer),[]}, + {Format,Args}, + {ft,div_footer(),[]}] + end, + cast({log,sync,self(),group_leader(),Category,Importance,Data, + lists:member(esc_chars, Opts)}), ok. %%%----------------------------------------------------------------- @@ -451,9 +482,10 @@ tc_log_async(Category,Format,Args) -> %%% asks ct_logs for an html wrapper.</p> tc_log_async(Category,Importance,Printer,Format,Args) -> cast({log,async,self(),group_leader(),Category,Importance, - [{div_header(Category,Printer),[]}, + [{hd,div_header(Category,Printer),[]}, {Format,Args}, - {div_footer(),[]}]}), + {ft,div_footer(),[]}], + true}), ok. %%%----------------------------------------------------------------- %%% @spec tc_print(Category,Format,Args) @@ -522,44 +554,45 @@ tc_pal(Category,Format,Args) -> tc_pal(Category,Importance,Format,Args) -> tc_print(Category,Importance,Format,Args), cast({log,sync,self(),group_leader(),Category,Importance, - [{div_header(Category),[]}, + [{hd,div_header(Category),[]}, {Format,Args}, - {div_footer(),[]}]}), + {ft,div_footer(),[]}], + true}), ok. %%%----------------------------------------------------------------- -%%% @spec ct_pal(Category,Format,Args) -> ok +%%% @spec ct_log(Category,Format,Args) -> ok %%% Category = atom() %%% Format = string() %%% Args = list() %%% -%%% @doc Print and log to the ct framework log +%%% @doc Print to the ct framework log %%% %%% <p>This function is called by internal ct functions to %%% force logging to the ct framework log</p> ct_log(Category,Format,Args) -> - cast({ct_log,[{div_header(Category),[]}, + cast({ct_log,[{hd,div_header(Category),[]}, {Format,Args}, - {div_footer(),[]}]}), + {ft,div_footer(),[]}], + true}), ok. %%%================================================================= %%% Internal functions int_header() -> - "<div class=\"ct_internal\"><b>*** CT ~s *** ~ts</b>". + "</pre>\n<div class=\"ct_internal\"><pre><b>*** CT ~s *** ~ts</b>". int_footer() -> - "</div>". + "</pre></div>\n<pre>". div_header(Class) -> div_header(Class,"User"). div_header(Class,Printer) -> - "\n<div class=\"" ++ atom_to_list(Class) ++ "\"><b>*** " ++ Printer ++ - " " ++ log_timestamp(?now) ++ " ***</b>". + "\n</pre>\n<div class=\"" ++ atom_to_list(Class) ++ "\"><pre><b>*** " + ++ Printer ++ " " ++ log_timestamp(?now) ++ " ***</b>". div_footer() -> - "</div>". - + "</pre></div>\n<pre>". maybe_log_timestamp() -> {MS,S,US} = ?now, @@ -568,7 +601,7 @@ maybe_log_timestamp() -> ok; _ -> cast({log,sync,self(),group_leader(),ct_internal,?MAX_IMPORTANCE, - [{"<i>~s</i>",[log_timestamp({MS,S,US})]}]}) + [{hd,"<i>~s</i>",[log_timestamp({MS,S,US})]}],false}) end. log_timestamp({MS,S,US}) -> @@ -589,7 +622,8 @@ log_timestamp({MS,S,US}) -> ct_log_fd, tc_groupleaders, stylesheet, - async_print_jobs}). + async_print_jobs, + tc_esc_chars}). logger(Parent, Mode, Verbosity) -> register(?MODULE,self()), @@ -708,14 +742,18 @@ logger(Parent, Mode, Verbosity) -> end end || {Cat,VLvl} <- Verbosity], io:nl(CtLogFd), - + TcEscChars = case application:get_env(common_test, esc_chars) of + {ok,ECBool} -> ECBool; + _ -> true + end, logger_loop(#logger_state{parent=Parent, log_dir=AbsDir, start_time=Time, orig_GL=group_leader(), ct_log_fd=CtLogFd, tc_groupleaders=[], - async_print_jobs=[]}). + async_print_jobs=[], + tc_esc_chars=TcEscChars}). copy_priv_files([SrcF | SrcFs], [DestF | DestFs]) -> case file:copy(SrcF, DestF) of @@ -729,7 +767,7 @@ copy_priv_files([], []) -> logger_loop(State) -> receive - {log,SyncOrAsync,Pid,GL,Category,Importance,List} -> + {log,SyncOrAsync,Pid,GL,Category,Importance,Content,EscChars} -> VLvl = case Category of ct_internal -> ?MAX_VERBOSITY; @@ -741,20 +779,21 @@ logger_loop(State) -> end, if Importance >= (100-VLvl) -> CtLogFd = State#logger_state.ct_log_fd, + DoEscChars = State#logger_state.tc_esc_chars and EscChars, case get_groupleader(Pid, GL, State) of {tc_log,TCGL,TCGLs} -> case erlang:is_process_alive(TCGL) of true -> State1 = print_to_log(SyncOrAsync, Pid, - Category, - TCGL, List, State), + Category, TCGL, Content, + DoEscChars, State), logger_loop(State1#logger_state{ tc_groupleaders = TCGLs}); false -> %% Group leader is dead, so write to the %% CtLog or unexpected_io log instead - unexpected_io(Pid,Category,Importance, - List,CtLogFd), + unexpected_io(Pid, Category, Importance, + Content, CtLogFd, DoEscChars), logger_loop(State) end; @@ -762,7 +801,8 @@ logger_loop(State) -> %% If category is ct_internal then write %% to ct_log, else write to unexpected_io %% log - unexpected_io(Pid,Category,Importance,List,CtLogFd), + unexpected_io(Pid, Category, Importance, Content, + CtLogFd, DoEscChars), logger_loop(State#logger_state{ tc_groupleaders = TCGLs}) end; @@ -773,7 +813,7 @@ logger_loop(State) -> %% make sure no IO for this test case from the %% CT logger gets rejected test_server:permit_io(GL, self()), - print_style(GL, State#logger_state.stylesheet), + print_style(GL,GL,State#logger_state.stylesheet), set_evmgr_gl(GL), TCGLs = add_tc_gl(TCPid,GL,State), if not RefreshLog -> @@ -818,10 +858,17 @@ logger_loop(State) -> logger_loop(State); {clear_stylesheet,_} -> logger_loop(State#logger_state{stylesheet = undefined}); - {ct_log, List} -> + {ct_log,Content,EscChars} -> + Str = lists:map(fun({_HdOrFt,Str,Args}) -> + [io_lib:format(Str,Args),io_lib:nl()]; + ({Str,Args}) when EscChars -> + Io = io_lib:format(Str,Args), + [escape_chars(Io),io_lib:nl()]; + ({Str,Args}) -> + [io_lib:format(Str,Args),io_lib:nl()] + end, Content), Fd = State#logger_state.ct_log_fd, - [begin io:format(Fd,Str,Args),io:nl(Fd) end || - {Str,Args} <- List], + io:format(Fd, "~ts", [Str]), logger_loop(State); {'DOWN',Ref,_,_Pid,_} -> %% there might be print jobs executing in parallel with ct_logs @@ -843,45 +890,79 @@ logger_loop(State) -> ok end. -create_io_fun(FromPid, CtLogFd) -> +create_io_fun(FromPid, CtLogFd, EscChars) -> %% we have to build one io-list of all strings %% before printing, or other io printouts (made in %% parallel) may get printed between this header %% and footer - fun({Str,Args}, IoList) -> - case catch io_lib:format(Str,Args) of - {'EXIT',_Reason} -> + fun(FormatData, IoList) -> + {Escapable,Str,Args} = + case FormatData of + {_HdOrFt,S,A} -> {false,S,A}; + {S,A} -> {true,S,A} + end, + try io_lib:format(Str, Args) of + IoStr when Escapable, EscChars, IoList == [] -> + escape_chars(IoStr); + IoStr when Escapable, EscChars -> + [IoList,"\n",escape_chars(IoStr)]; + IoStr when IoList == [] -> + IoStr; + IoStr -> + [IoList,"\n",IoStr] + catch + _:_Reason -> io:format(CtLogFd, "Logging fails! Str: ~p, Args: ~p~n", [Str,Args]), %% stop the testcase, we need to see the fault exit(FromPid, {log_printout_error,Str,Args}), - []; - IoStr when IoList == [] -> - [IoStr]; - IoStr -> - [IoList,"\n",IoStr] + [] end end. -print_to_log(sync, FromPid, Category, TCGL, List, State) -> +escape_chars([Bin | Io]) when is_binary(Bin) -> + [Bin | escape_chars(Io)]; +escape_chars([List | Io]) when is_list(List) -> + [escape_chars(List) | escape_chars(Io)]; +escape_chars([$< | Io]) -> + ["<" | escape_chars(Io)]; +escape_chars([$> | Io]) -> + [">" | escape_chars(Io)]; +escape_chars([$& | Io]) -> + ["&" | escape_chars(Io)]; +escape_chars([Char | Io]) when is_integer(Char) -> + [Char | escape_chars(Io)]; +escape_chars([]) -> + []; +escape_chars(Bin) -> + Bin. + +print_to_log(sync, FromPid, Category, TCGL, Content, EscChars, State) -> %% in some situations (exceptions), the printout is made from the %% test server IO process and there's no valid group leader to send to CtLogFd = State#logger_state.ct_log_fd, if FromPid /= TCGL -> - IoFun = create_io_fun(FromPid, CtLogFd), - io:format(TCGL,"~ts", [lists:foldl(IoFun, [], List)]); + IoFun = create_io_fun(FromPid, CtLogFd, EscChars), + IoList = lists:foldl(IoFun, [], Content), + try io:format(TCGL,["$tc_html","~ts"], [IoList]) of + ok -> ok + catch + _:_ -> + io:format(TCGL,"~ts", [IoList]) + end; true -> - unexpected_io(FromPid,Category,?MAX_IMPORTANCE,List,CtLogFd) + unexpected_io(FromPid, Category, ?MAX_IMPORTANCE, Content, + CtLogFd, EscChars) end, State; -print_to_log(async, FromPid, Category, TCGL, List, State) -> +print_to_log(async, FromPid, Category, TCGL, Content, EscChars, State) -> %% in some situations (exceptions), the printout is made from the %% test server IO process and there's no valid group leader to send to CtLogFd = State#logger_state.ct_log_fd, Printer = if FromPid /= TCGL -> - IoFun = create_io_fun(FromPid, CtLogFd), + IoFun = create_io_fun(FromPid, CtLogFd, EscChars), fun() -> test_server:permit_io(TCGL, self()), @@ -894,25 +975,28 @@ print_to_log(async, FromPid, Category, TCGL, List, State) -> case erlang:is_process_alive(TCGL) of true -> - try io:format(TCGL, "~ts", - [lists:foldl(IoFun,[],List)]) of + try io:format(TCGL, ["$tc_html","~ts"], + [lists:foldl(IoFun,[],Content)]) of _ -> ok catch _:terminated -> unexpected_io(FromPid, Category, ?MAX_IMPORTANCE, - List, CtLogFd) + Content, CtLogFd, EscChars); + _:_ -> + io:format(TCGL, "~ts", + [lists:foldl(IoFun,[],Content)]) end; false -> unexpected_io(FromPid, Category, ?MAX_IMPORTANCE, - List, CtLogFd) + Content, CtLogFd, EscChars) end end; true -> fun() -> unexpected_io(FromPid, Category, ?MAX_IMPORTANCE, - List, CtLogFd) + Content, CtLogFd, EscChars) end end, case State#logger_state.async_print_jobs of @@ -1042,26 +1126,27 @@ open_ctlog(MiscIoName) -> "View I/O logged after the test run</a></li>\n</ul>\n", [MiscIoName,MiscIoName]), - print_style(Fd,undefined), + print_style(Fd,group_leader(),undefined), io:format(Fd, xhtml("<br><h2>Progress Log</h2>\n<pre>\n", "<br />\n<h4>PROGRESS LOG</h4>\n<pre>\n"), []), Fd. -print_style(Fd,undefined) -> +print_style(Fd,GL,undefined) -> case basic_html() of true -> - io:format(Fd, - "<style>\n" - "div.ct_internal { background:lightgrey; color:black; }\n" - "div.default { background:lightgreen; color:black; }\n" - "</style>\n", - []); + Style = "<style>\n + div.ct_internal { background:lightgrey; color:black; }\n + div.default { background:lightgreen; color:black; }\n + </style>\n", + if Fd == GL -> io:format(["$tc_html",Style], []); + true -> io:format(Fd, Style, []) + end; _ -> ok end; -print_style(Fd,StyleSheet) -> +print_style(Fd,GL,StyleSheet) -> case file:read_file(StyleSheet) of {ok,Bin} -> Str = b2s(Bin,encoding(StyleSheet)), @@ -1074,29 +1159,30 @@ print_style(Fd,StyleSheet) -> N1 -> N1 end, if (Pos0 == 0) and (Pos1 /= 0) -> - print_style_error(Fd,StyleSheet,missing_style_start_tag); + print_style_error(Fd,GL,StyleSheet,missing_style_start_tag); (Pos0 /= 0) and (Pos1 == 0) -> - print_style_error(Fd,StyleSheet,missing_style_end_tag); + print_style_error(Fd,GL,StyleSheet,missing_style_end_tag); Pos0 /= 0 -> Style = string:sub_string(Str,Pos0,Pos1+7), - io:format(Fd,"~ts\n",[Style]); + if Fd == GL -> io:format(Fd,["$tc_html","~ts\n"],[Style]); + true -> io:format(Fd,"~ts\n",[Style]) + end; Pos0 == 0 -> - io:format(Fd,"<style>~ts</style>\n",[Str]) + if Fd == GL -> io:format(Fd,["$tc_html","<style>\n~ts</style>\n"],[Str]); + true -> io:format(Fd,"<style>\n~ts</style>\n",[Str]) + end end; {error,Reason} -> - print_style_error(Fd,StyleSheet,Reason) + print_style_error(Fd,GL,StyleSheet,Reason) end. -%% Simple link version, doesn't work with all browsers unfortunately. :-( -%% print_style(Fd, StyleSheet) -> -%% io:format(Fd, -%% "<link href=~p rel=\"stylesheet\" type=\"text/css\">", -%% [StyleSheet]). - -print_style_error(Fd,StyleSheet,Reason) -> - io:format(Fd,"\n<!-- Failed to load stylesheet ~ts: ~p -->\n", - [StyleSheet,Reason]), - print_style(Fd,undefined). +print_style_error(Fd,GL,StyleSheet,Reason) -> + IO = io_lib:format("\n<!-- Failed to load stylesheet ~ts: ~p -->\n", + [StyleSheet,Reason]), + if Fd == GL -> io:format(Fd,["$tc_html",IO],[]); + true -> io:format(Fd,IO,[]) + end, + print_style(Fd,GL,undefined). close_ctlog(Fd) -> io:format(Fd, "\n</pre>\n", []), @@ -1364,11 +1450,11 @@ total_row(Success, Fail, UserSkip, AutoSkip, NotBuilt, All) -> [xhtml("<tr valign=top>\n", ["</tbody>\n<tfoot>\n<tr class=\"",odd_or_even(),"\">\n"]), "<td><b>Total</b></td>\n", Label, TimestampCell, - "<td align=right><b>",integer_to_list(Success),"<b></td>\n", - "<td align=right><b>",integer_to_list(Fail),"<b></td>\n", + "<td align=right><b>",integer_to_list(Success),"</b></td>\n", + "<td align=right><b>",integer_to_list(Fail),"</b></td>\n", "<td align=right>",integer_to_list(AllSkip), " (",UserSkipStr,"/",AutoSkipStr,")</td>\n", - "<td align=right><b>",integer_to_list(NotBuilt),"<b></td>\n", + "<td align=right><b>",integer_to_list(NotBuilt),"</b></td>\n", AllInfo, "</tr>\n", xhtml("","</tfoot>\n")]. @@ -1560,10 +1646,12 @@ header1(Title, SubTitle, TableCols) -> "<!-- autogenerated by '"++atom_to_list(?MODULE)++"' -->\n", "<head>\n", "<title>" ++ Title ++ " " ++ SubTitle ++ "</title>\n", - "<meta http-equiv=\"cache-control\" content=\"no-cache\">\n", - "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">\n", + "<meta http-equiv=\"cache-control\" content=\"no-cache\"></meta>\n", + "<meta http-equiv=\"content-type\" content=\"text/html; " + "charset=utf-8\"></meta>\n", xhtml("", - ["<link rel=\"stylesheet\" href=\"",uri(CSSFile),"\" type=\"text/css\">\n"]), + ["<link rel=\"stylesheet\" href=\"",uri(CSSFile), + "\" type=\"text/css\"></link>\n"]), xhtml("", ["<script type=\"text/javascript\" src=\"",JQueryFile, "\"></script>\n"]), @@ -1610,7 +1698,7 @@ footer() -> "Copyright © ", year(), " <a href=\"http://www.erlang.org\">Open Telecom Platform</a>", xhtml("<br>\n", "<br />\n"), - "Updated: <!date>", current_time(), "<!/date>", + "Updated: <!--date-->", current_time(), "<!--/date-->", xhtml("<br>\n", "<br />\n"), xhtml("</font></p>\n", "</div>\n"), "</center>\n" @@ -1985,9 +2073,9 @@ interactive_link() -> "<!-- autogenerated by '"++atom_to_list(?MODULE)++"' -->\n", "<head>\n", "<title>Last interactive run</title>\n", - "<meta http-equiv=\"cache-control\" content=\"no-cache\">\n", + "<meta http-equiv=\"cache-control\" content=\"no-cache\"></meta>\n", "<meta http-equiv=\"content-type\" content=\"text/html; " - "charset=utf-8\">\n", + "charset=utf-8\"></meta>\n", "</head>\n", "<body>\n", "Log from last interactive run: <a href=\"",uri(CtLog),"\">", @@ -2846,8 +2934,12 @@ simulate() -> simulate_logger_loop() -> receive - {log,_,_,_,_,_,List} -> - S = [[io_lib:format(Str,Args),io_lib:nl()] || {Str,Args} <- List], + {log,_,_,_,_,_,Content,_} -> + S = lists:map(fun({_,Str,Args}) -> + [io_lib:format(Str,Args),io_lib:nl()]; + ({Str,Args}) -> + [io_lib:format(Str,Args),io_lib:nl()] + end, Content), io:format("~ts",[S]), simulate_logger_loop(); stop -> @@ -3053,15 +3145,15 @@ get_ts_html_wrapper(TestName, Logdir, PrintLabel, Cwd, TableCols, Encoding) -> "Copyright © ", year(), " <a href=\"http://www.erlang.org\">", "Open Telecom Platform</a><br>\n", - "Updated: <!date>", current_time(), "<!/date>", + "Updated: <!--date-->", current_time(), "<!--/date-->", "<br>\n</font></p>\n"], {basic_html, ["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n", "<html>\n", "<head><title>", TestName1, "</title>\n", - "<meta http-equiv=\"cache-control\" content=\"no-cache\">\n", + "<meta http-equiv=\"cache-control\" content=\"no-cache\"></meta>\n", "<meta http-equiv=\"content-type\" content=\"text/html; charset=", - html_encoding(Encoding),"\">\n", + html_encoding(Encoding),"\"></meta>\n", "</head>\n", "<body", Bgr, " bgcolor=\"white\" text=\"black\" ", "link=\"blue\" vlink=\"purple\" alink=\"red\">\n", @@ -3078,7 +3170,7 @@ get_ts_html_wrapper(TestName, Logdir, PrintLabel, Cwd, TableCols, Encoding) -> "Copyright © ", year(), " <a href=\"http://www.erlang.org\">", "Open Telecom Platform</a><br />\n", - "Updated: <!date>", current_time(), "<!/date>", + "Updated: <!--date-->", current_time(), "<!--/date-->", "<br />\n</div>\n"], CSSFile = xhtml(fun() -> "" end, @@ -3105,9 +3197,11 @@ get_ts_html_wrapper(TestName, Logdir, PrintLabel, Cwd, TableCols, Encoding) -> "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n", "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n", "<head>\n<title>", TestName1, "</title>\n", - "<meta http-equiv=\"cache-control\" content=\"no-cache\">\n", - "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">\n", - "<link rel=\"stylesheet\" href=\"", uri(CSSFile), "\" type=\"text/css\">\n", + "<meta http-equiv=\"cache-control\" content=\"no-cache\"></meta>\n", + "<meta http-equiv=\"content-type\" content=\"text/html; ", + "charset=utf-8\"></meta>\n", + "<link rel=\"stylesheet\" href=\"", uri(CSSFile), + "\" type=\"text/css\"></link>\n", "<script type=\"text/javascript\" src=\"", JQueryFile, "\"></script>\n", "<script type=\"text/javascript\" src=\"", TableSorterFile, "\"></script>\n"] ++ TableSorterScript ++ ["</head>\n","<body>\n", LabelStr, "\n"], @@ -3233,11 +3327,11 @@ html_encoding(latin1) -> html_encoding(utf8) -> "utf-8". -unexpected_io(Pid,ct_internal,_Importance,List,CtLogFd) -> - IoFun = create_io_fun(Pid,CtLogFd), - io:format(CtLogFd, "~ts", [lists:foldl(IoFun, [], List)]); -unexpected_io(Pid,_Category,_Importance,List,CtLogFd) -> - IoFun = create_io_fun(Pid,CtLogFd), - Data = io_lib:format("~ts", [lists:foldl(IoFun, [], List)]), +unexpected_io(Pid, ct_internal, _Importance, Content, CtLogFd, EscChars) -> + IoFun = create_io_fun(Pid, CtLogFd, EscChars), + io:format(CtLogFd, "~ts", [lists:foldl(IoFun, [], Content)]); +unexpected_io(Pid, _Category, _Importance, Content, CtLogFd, EscChars) -> + IoFun = create_io_fun(Pid, CtLogFd, EscChars), + Data = io_lib:format("~ts", [lists:foldl(IoFun, [], Content)]), test_server_io:print_unexpected(Data), ok. diff --git a/lib/common_test/src/ct_master.erl b/lib/common_test/src/ct_master.erl index 228daf459b..d24edad2eb 100644 --- a/lib/common_test/src/ct_master.erl +++ b/lib/common_test/src/ct_master.erl @@ -27,7 +27,7 @@ -export([run_on_node/2,run_on_node/3]). -export([run_test/1,run_test/2]). -export([get_event_mgr_ref/0]). --export([basic_html/1]). +-export([basic_html/1,esc_chars/1]). -export([abort/0,abort/1,progress/0]). @@ -317,6 +317,16 @@ basic_html(Bool) -> ok. %%%----------------------------------------------------------------- +%%% @spec esc_chars(Bool) -> ok +%%% Bool = true | false +%%% +%%% @doc If set to false, the ct_master logs will be written without +%%% special characters being escaped in the HTML logs. +esc_chars(Bool) -> + application:set_env(common_test_master, esc_chars, Bool), + ok. + +%%%----------------------------------------------------------------- %%% MASTER, runs on central controlling node. %%%----------------------------------------------------------------- start_master(NodeOptsList) -> diff --git a/lib/common_test/src/ct_master_logs.erl b/lib/common_test/src/ct_master_logs.erl index 2adced42ae..54190a8254 100644 --- a/lib/common_test/src/ct_master_logs.erl +++ b/lib/common_test/src/ct_master_logs.erl @@ -238,9 +238,9 @@ config_table1([]) -> ["</tbody>\n</table>\n"]. int_header() -> - "<div class=\"ct_internal\"><b>*** CT MASTER ~s *** ~ts</b>". + "</pre>\n<div class=\"ct_internal\"><pre><b>*** CT MASTER ~s *** ~ts</b>". int_footer() -> - "</div>". + "</pre></div>\n<pre>". %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% NodeDir Index functions %%% @@ -387,11 +387,12 @@ header(Title, TableCols) -> "<!-- autogenerated by '"++atom_to_list(?MODULE)++"' -->\n", "<head>\n", "<title>" ++ Title ++ "</title>\n", - "<meta http-equiv=\"cache-control\" content=\"no-cache\">\n", - "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">\n", + "<meta http-equiv=\"cache-control\" content=\"no-cache\"></meta>\n", + "<meta http-equiv=\"content-type\" content=\"text/html; ", + "charset=utf-8\"></meta>\n", xhtml("", ["<link rel=\"stylesheet\" href=\"",ct_logs:uri(CSSFile), - "\" type=\"text/css\">"]), + "\" type=\"text/css\"></link>\n"]), xhtml("", ["<script type=\"text/javascript\" src=\"",JQueryFile, "\"></script>\n"]), @@ -419,7 +420,7 @@ footer() -> "Copyright © ", year(), " <a href=\"http://www.erlang.org\">Open Telecom Platform</a>", xhtml("<br>\n", "<br />\n"), - "Updated: <!date>", current_time(), "<!/date>", + "Updated: <!--date-->", current_time(), "<--!/date-->", xhtml("<br>\n", "<br />\n"), xhtml("</font></p>\n", "</div>\n"), "</center>\n" diff --git a/lib/common_test/src/ct_netconfc.erl b/lib/common_test/src/ct_netconfc.erl index 0de7bf03af..8812514ad9 100644 --- a/lib/common_test/src/ct_netconfc.erl +++ b/lib/common_test/src/ct_netconfc.erl @@ -234,7 +234,6 @@ %% Internal defines %%---------------------------------------------------------------------- -define(APPLICATION,?MODULE). --define(VALID_SSH_OPTS,[user, password, user_dir]). -define(DEFAULT_STREAM,"NETCONF"). -define(error(ConnName,Report), @@ -264,6 +263,7 @@ session_id, msg_id = 1, hello_status, + no_end_tag_buff = <<>>, buff = <<>>, pending = [], % [#pending] event_receiver}).% pid @@ -1170,7 +1170,7 @@ handle_msg({Ref,timeout},#state{pending=Pending} = State) -> end, %% Halfhearted try to get in correct state, this matches %% the implementation before this patch - {R,State#state{pending=Pending1, buff= <<>>}}. + {R,State#state{pending=Pending1, no_end_tag_buff= <<>>, buff= <<>>}}. %% @private %% Called by ct_util_server to close registered connections before terminate. @@ -1205,7 +1205,7 @@ call(Client, Msg, Timeout, WaitStop) -> {error,no_such_client}; {error,{process_down,Pid,normal}} when WaitStop -> %% This will happen when server closes connection - %% before clien received rpc-reply on + %% before client received rpc-reply on %% close-session. ok; {error,{process_down,Pid,normal}} -> @@ -1256,13 +1256,11 @@ check_options([{port,Port}|T], Host, _, #options{} = Options) -> check_options([{timeout, Timeout}|T], Host, Port, Options) when is_integer(Timeout); Timeout==infinity -> check_options(T, Host, Port, Options#options{timeout = Timeout}); -check_options([{X,_}=Opt|T], Host, Port, #options{ssh=SshOpts}=Options) -> - case lists:member(X,?VALID_SSH_OPTS) of - true -> - check_options(T, Host, Port, Options#options{ssh=[Opt|SshOpts]}); - false -> - {error, {invalid_option, Opt}} - end. +check_options([{timeout, _} = Opt|_T], _Host, _Port, _Options) -> + {error, {invalid_option, Opt}}; +check_options([Opt|T], Host, Port, #options{ssh=SshOpts}=Options) -> + %% Option verified by ssh + check_options(T, Host, Port, Options#options{ssh=[Opt|SshOpts]}). %%%----------------------------------------------------------------- set_request_timer(infinity) -> @@ -1272,6 +1270,14 @@ set_request_timer(T) -> {ok,TRef} = timer:send_after(T,{Ref,timeout}), {Ref,TRef}. +%%%----------------------------------------------------------------- +cancel_request_timer(undefined,undefined) -> + ok; +cancel_request_timer(Ref,TRef) -> + _ = timer:cancel(TRef), + receive {Ref,timeout} -> ok + after 0 -> ok + end. %%%----------------------------------------------------------------- client_hello(Options) when is_list(Options) -> @@ -1364,17 +1370,37 @@ to_xml_doc(Simple) -> %%%----------------------------------------------------------------- %%% Parse and handle received XML data -handle_data(NewData,#state{connection=Connection,buff=Buff0} = State0) -> +%%% Two buffers are used: +%%% * 'no_end_tag_buff' contains data that is checked and does not +%%% contain any (part of an) end tag. +%%% * 'buff' contains all other saved data - it may or may not +%%% include (a part of) an end tag. +%%% The reason for this is to avoid running binary:split/3 multiple +%%% times on the same data when it does not contain an end tag. This +%%% can be a considerable optimation in the case when a lot of data is +%%% received (e.g. when fetching all data from a node) and the data is +%%% sent in multiple ssh packages. +handle_data(NewData,#state{connection=Connection} = State0) -> log(Connection,recv,NewData), - Data = append_wo_initial_nl(Buff0,NewData), - case binary:split(Data,[?END_TAG],[]) of + NoEndTag0 = State0#state.no_end_tag_buff, + Buff0 = State0#state.buff, + Data = <<Buff0/binary, NewData/binary>>, + case binary:split(Data,?END_TAG,[]) of [_NoEndTagFound] -> - {noreply, State0#state{buff=Data}}; - [FirstMsg,Buff1] -> + NoEndTagSize = case byte_size(Data) of + Sz when Sz<5 -> 0; + Sz -> Sz-5 + end, + <<NoEndTag1:NoEndTagSize/binary,Buff/binary>> = Data, + NoEndTag = <<NoEndTag0/binary,NoEndTag1/binary>>, + {noreply, State0#state{no_end_tag_buff=NoEndTag, buff=Buff}}; + [FirstMsg0,Buff1] -> + FirstMsg = remove_initial_nl(<<NoEndTag0/binary,FirstMsg0/binary>>), SaxArgs = [{event_fun,fun sax_event/3}, {event_state,[]}], case xmerl_sax_parser:stream(FirstMsg, SaxArgs) of {ok, Simple, _Thrash} -> - case decode(Simple, State0#state{buff=Buff1}) of + case decode(Simple, State0#state{no_end_tag_buff= <<>>, + buff=Buff1}) of {noreply, #state{buff=Buff} = State} when Buff =/= <<>> -> %% Recurse if we have more data in buffer handle_data(<<>>, State); @@ -1386,17 +1412,18 @@ handle_data(NewData,#state{connection=Connection,buff=Buff0} = State0) -> [{parse_error,Reason}, {buffer, Buff0}, {new_data,NewData}]), - handle_error(Reason, State0#state{buff= <<>>}) + handle_error(Reason, State0#state{no_end_tag_buff= <<>>, + buff= <<>>}) end end. + %% xml does not accept a leading nl and some netconf server add a nl after %% each ?END_TAG, ignore them -append_wo_initial_nl(<<>>,NewData) -> NewData; -append_wo_initial_nl(<<"\n", Data/binary>>, NewData) -> - append_wo_initial_nl(Data, NewData); -append_wo_initial_nl(Data, NewData) -> - <<Data/binary, NewData/binary>>. +remove_initial_nl(<<"\n", Data/binary>>) -> + remove_initial_nl(Data); +remove_initial_nl(Data) -> + Data. handle_error(Reason, State) -> Pending1 = case State#state.pending of @@ -1404,9 +1431,9 @@ handle_error(Reason, State) -> Pending -> %% Assuming the first request gets the %% first answer - P=#pending{tref=TRef,caller=Caller} = + P=#pending{tref=TRef,ref=Ref,caller=Caller} = lists:last(Pending), - _ = timer:cancel(TRef), + cancel_request_timer(Ref,TRef), Reason1 = {failed_to_parse_received_data,Reason}, ct_gen_conn:return(Caller,{error,Reason1}), lists:delete(P,Pending) @@ -1492,8 +1519,8 @@ decode({Tag,Attrs,_}=E, #state{connection=Connection,pending=Pending}=State) -> {error,Reason} -> {noreply,State#state{hello_status = {error,Reason}}} end; - #pending{tref=TRef,caller=Caller} -> - _ = timer:cancel(TRef), + #pending{tref=TRef,ref=Ref,caller=Caller} -> + cancel_request_timer(Ref,TRef), case decode_hello(E) of {ok,SessionId,Capabilities} -> ct_gen_conn:return(Caller,ok), @@ -1519,9 +1546,8 @@ decode({Tag,Attrs,_}=E, #state{connection=Connection,pending=Pending}=State) -> %% there is just one pending that matches (i.e. has %% undefined msg_id and op) case [P || P = #pending{msg_id=undefined,op=undefined} <- Pending] of - [#pending{tref=TRef, - caller=Caller}] -> - _ = timer:cancel(TRef), + [#pending{tref=TRef,ref=Ref,caller=Caller}] -> + cancel_request_timer(Ref,TRef), ct_gen_conn:return(Caller,E), {noreply,State#state{pending=[]}}; _ -> @@ -1542,8 +1568,8 @@ get_msg_id(Attrs) -> decode_rpc_reply(MsgId,{_,Attrs,Content0}=E,#state{pending=Pending} = State) -> case lists:keytake(MsgId,#pending.msg_id,Pending) of - {value, #pending{tref=TRef,op=Op,caller=Caller}, Pending1} -> - _ = timer:cancel(TRef), + {value, #pending{tref=TRef,ref=Ref,op=Op,caller=Caller}, Pending1} -> + cancel_request_timer(Ref,TRef), Content = forward_xmlns_attr(Attrs,Content0), {CallerReply,{ServerReply,State2}} = do_decode_rpc_reply(Op,Content,State#state{pending=Pending1}), @@ -1555,10 +1581,11 @@ decode_rpc_reply(MsgId,{_,Attrs,Content0}=E,#state{pending=Pending} = State) -> %% pending that matches (i.e. has undefined msg_id and op) case [P || P = #pending{msg_id=undefined,op=undefined} <- Pending] of [#pending{tref=TRef, + ref=Ref, msg_id=undefined, op=undefined, caller=Caller}] -> - _ = timer:cancel(TRef), + cancel_request_timer(Ref,TRef), ct_gen_conn:return(Caller,E), {noreply,State#state{pending=[]}}; _ -> @@ -1762,9 +1789,14 @@ format_data(How,Data) -> do_format_data(raw,Data) -> io_lib:format("~n~ts~n",[hide_password(Data)]); do_format_data(pretty,Data) -> - io_lib:format("~n~ts~n",[indent(Data)]); + maybe_io_lib_format(indent(Data)); do_format_data(html,Data) -> - io_lib:format("~n~ts~n",[html_format(Data)]). + maybe_io_lib_format(html_format(Data)). + +maybe_io_lib_format(<<>>) -> + []; +maybe_io_lib_format(String) -> + io_lib:format("~n~ts~n",[String]). %%%----------------------------------------------------------------- %%% Hide password elements from XML data @@ -1803,13 +1835,21 @@ indent1("<?"++Rest1,Indent1) -> Line++indent1(Rest2,Indent2); indent1("</"++Rest1,Indent1) -> %% Stop tag - {Line,Rest2,Indent2} = indent_line1(Rest1,Indent1,[$/,$<]), - "\n"++Line++indent1(Rest2,Indent2); + case indent_line1(Rest1,Indent1,[$/,$<]) of + {[],[],_} -> + []; + {Line,Rest2,Indent2} -> + "\n"++Line++indent1(Rest2,Indent2) + end; indent1("<"++Rest1,Indent1) -> %% Start- or empty tag put(tag,get_tag(Rest1)), - {Line,Rest2,Indent2} = indent_line(Rest1,Indent1,[$<]), - "\n"++Line++indent1(Rest2,Indent2); + case indent_line(Rest1,Indent1,[$<]) of + {[],[],_} -> + []; + {Line,Rest2,Indent2} -> + "\n"++Line++indent1(Rest2,Indent2) + end; indent1([H|T],Indent) -> [H|indent1(T,Indent)]; indent1([],_Indent) -> diff --git a/lib/common_test/src/ct_release_test.erl b/lib/common_test/src/ct_release_test.erl index 6438ea01c1..5d7e945cc3 100644 --- a/lib/common_test/src/ct_release_test.erl +++ b/lib/common_test/src/ct_release_test.erl @@ -131,7 +131,7 @@ -include_lib("kernel/include/file.hrl"). %%----------------------------------------------------------------- --define(testnode, otp_upgrade). +-define(testnode, 'ct_release_test-upgrade'). -define(exclude_apps, [hipe, typer, dialyzer]). % never include these apps %%----------------------------------------------------------------- @@ -304,7 +304,13 @@ upgrade(Apps,Level,Callback,Config) -> %% Note, we will not reach this if the test fails with a %% timetrap timeout in the test suite! Thus we can have %% hanging nodes... - Nodes = nodes(), + Nodes = lists:filter(fun(Node) -> + case atom_to_list(Node) of + "ct_release_test-" ++_ -> true; + _ -> false + end + end, + nodes()), [rpc:call(Node,erlang,halt,[]) || Node <- Nodes] end. @@ -328,7 +334,14 @@ upgrade(Apps,Level,Callback,Config) -> %% ct_release_test:cleanup(Config).''' %% cleanup(Config) -> - Nodes = [node_name(?testnode)|nodes()], + AllNodes = [node_name(?testnode)|nodes()], + Nodes = lists:filter(fun(Node) -> + case atom_to_list(Node) of + "ct_release_test-" ++_ -> true; + _ -> false + end + end, + AllNodes), [rpc:call(Node,erlang,halt,[]) || Node <- Nodes], Config. @@ -455,9 +468,9 @@ get_rels(minor) -> {CurrentMajor,Current}. init_upgrade_test(FromVsn,ToVsn,OldRel) -> - OtpRel = list_to_atom("otp-"++FromVsn), + Name = list_to_atom("ct_release_test-otp-"++FromVsn), ct:log("Starting node to fetch application versions to upgrade from"), - {ok,Node} = test_server:start_node(OtpRel,peer,[{erl,[OldRel]}]), + {ok,Node} = test_server:start_node(Name,peer,[{erl,[OldRel]}]), {Apps,Path} = fetch_all_apps(Node), test_server:stop_node(Node), {FromVsn,ToVsn,Apps,Path}. @@ -723,7 +736,7 @@ do_callback(Node,Mod,Func,Args) -> ct:log("~p:~p/~w returned: ~p",[Mod,Func,length(Args),R]), case R of {badrpc,Error} -> - test_server:fail({test_upgrade_callback,Mod,Func,Args,Error}); + throw({fail,{test_upgrade_callback,Mod,Func,Args,Error}}); NewState -> NewState end. diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl index ae91601f67..a0f9f47b41 100644 --- a/lib/common_test/src/ct_run.erl +++ b/lib/common_test/src/ct_run.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2014. All Rights Reserved. +%% Copyright Ericsson AB 2004-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -65,6 +65,7 @@ logdir, logopts = [], basic_html, + esc_chars = true, verbosity = [], config = [], event_handlers = [], @@ -346,6 +347,15 @@ script_start1(Parent, Args) -> application:set_env(common_test, basic_html, true), true end, + %% esc_chars - used by ct_logs + EscChars = case proplists:get_value(no_esc_chars, Args) of + undefined -> + application:set_env(common_test, esc_chars, true), + undefined; + _ -> + application:set_env(common_test, esc_chars, false), + false + end, %% disable_log_cache - used by ct_logs case proplists:get_value(disable_log_cache, Args) of undefined -> @@ -359,6 +369,7 @@ script_start1(Parent, Args) -> cover = Cover, cover_stop = CoverStop, logdir = LogDir, logopts = LogOpts, basic_html = BasicHtml, + esc_chars = EscChars, verbosity = Verbosity, event_handlers = EvHandlers, ct_hooks = CTHooks, @@ -587,6 +598,17 @@ combine_test_opts(TS, Specs, Opts) -> BHBool end, + EscChars = + case choose_val(Opts#opts.esc_chars, + TSOpts#opts.esc_chars) of + undefined -> + true; + ECBool -> + application:set_env(common_test, esc_chars, + ECBool), + ECBool + end, + Opts#opts{label = Label, profile = Profile, testspec_files = Specs, @@ -595,6 +617,7 @@ combine_test_opts(TS, Specs, Opts) -> logdir = which(logdir, LogDir), logopts = AllLogOpts, basic_html = BasicHtml, + esc_chars = EscChars, verbosity = AllVerbosity, silent_connections = AllSilentConns, config = TSOpts#opts.config, @@ -795,6 +818,7 @@ script_usage() -> "\n\t [-scale_timetraps]" "\n\t [-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc]" "\n\t [-basic_html]" + "\n\t [-no_esc_chars]" "\n\t [-repeat N] |" "\n\t [-duration HHMMSS [-force_stop [skip_rest]]] |" "\n\t [-until [YYMoMoDD]HHMMSS [-force_stop [skip_rest]]]" @@ -822,6 +846,7 @@ script_usage() -> "\n\t [-scale_timetraps]" "\n\t [-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc]" "\n\t [-basic_html]" + "\n\t [-no_esc_chars]" "\n\t [-repeat N] |" "\n\t [-duration HHMMSS [-force_stop [skip_rest]]] |" "\n\t [-until [YYMoMoDD]HHMMSS [-force_stop [skip_rest]]]\n\n"), @@ -847,7 +872,8 @@ script_usage() -> "\n\t [-multiply_timetraps N]" "\n\t [-scale_timetraps]" "\n\t [-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc]" - "\n\t [-basic_html]\n\n"). + "\n\t [-basic_html]" + "\n\t [-no_esc_chars]\n\n"). %%%----------------------------------------------------------------- %%% @hidden @@ -909,7 +935,7 @@ run_test(StartOpt) when is_tuple(StartOpt) -> run_test([StartOpt]); run_test(StartOpts) when is_list(StartOpts) -> - CTPid = spawn(fun() -> run_test1(StartOpts) end), + CTPid = spawn(run_test1_fun(StartOpts)), Ref = monitor(process, CTPid), receive {'DOWN',Ref,process,CTPid,{user_error,Error}} -> @@ -918,6 +944,11 @@ run_test(StartOpts) when is_list(StartOpts) -> Other end. +-spec run_test1_fun(_) -> fun(() -> no_return()). + +run_test1_fun(StartOpts) -> + fun() -> run_test1(StartOpts) end. + run_test1(StartOpts) when is_list(StartOpts) -> case proplists:get_value(refresh_logs, StartOpts) of undefined -> @@ -1084,7 +1115,17 @@ run_test2(StartOpts) -> application:set_env(common_test, basic_html, BasicHtmlBool), BasicHtmlBool end, - + %% esc_chars - used by ct_logs + EscChars = + case proplists:get_value(esc_chars, StartOpts) of + undefined -> + application:set_env(common_test, esc_chars, true), + undefined; + EscCharsBool -> + application:set_env(common_test, esc_chars, EscCharsBool), + EscCharsBool + end, + %% disable_log_cache - used by ct_logs case proplists:get_value(disable_log_cache, StartOpts) of undefined -> application:set_env(common_test, disable_log_cache, false); @@ -1099,6 +1140,7 @@ run_test2(StartOpts) -> cover = Cover, cover_stop = CoverStop, step = Step, logdir = LogDir, logopts = LogOpts, basic_html = BasicHtml, + esc_chars = EscChars, config = CfgFiles, verbosity = Verbosity, event_handlers = EvHandlers, @@ -1369,7 +1411,7 @@ run_dir(Opts = #opts{logdir = LogDir, %%% @equiv ct:run_testspec/1 %%%----------------------------------------------------------------- run_testspec(TestSpec) -> - CTPid = spawn(fun() -> run_testspec1(TestSpec) end), + CTPid = spawn(run_testspec1_fun(TestSpec)), Ref = monitor(process, CTPid), receive {'DOWN',Ref,process,CTPid,{user_error,Error}} -> @@ -1378,6 +1420,11 @@ run_testspec(TestSpec) -> Other end. +-spec run_testspec1_fun(_) -> fun(() -> no_return()). + +run_testspec1_fun(TestSpec) -> + fun() -> run_testspec1(TestSpec) end. + run_testspec1(TestSpec) -> {ok,Cwd} = file:get_cwd(), io:format("~nCommon Test starting (cwd is ~ts)~n~n", [Cwd]), @@ -1435,6 +1482,7 @@ get_data_for_node(#testspec{label = Labels, logdir = LogDirs, logopts = LogOptsList, basic_html = BHs, + esc_chars = EscChs, stylesheet = SSs, verbosity = VLvls, silent_connections = SilentConnsList, @@ -1462,6 +1510,7 @@ get_data_for_node(#testspec{label = Labels, LOs -> LOs end, BasicHtml = proplists:get_value(Node, BHs), + EscChars = proplists:get_value(Node, EscChs), Stylesheet = proplists:get_value(Node, SSs), Verbosity = case proplists:get_value(Node, VLvls) of undefined -> []; @@ -1488,6 +1537,7 @@ get_data_for_node(#testspec{label = Labels, logdir = LogDir, logopts = LogOpts, basic_html = BasicHtml, + esc_chars = EscChars, stylesheet = Stylesheet, verbosity = Verbosity, silent_connections = SilentConns, @@ -1771,7 +1821,18 @@ compile_and_run(Tests, Skip, Opts, Args) -> {Tests1,Skip1} -> ReleaseSh = proplists:get_value(release_shell, Args), ct_util:set_testdata({release_shell,ReleaseSh}), - possibly_spawn(ReleaseSh == true, Tests1, Skip1, Opts) + TestResult = + possibly_spawn(ReleaseSh == true, Tests1, Skip1, Opts), + case TestResult of + {Ok,Errors,Skipped} -> + NoOfMakeErrors = + lists:foldl(fun({_,BadMods}, X) -> + X + length(BadMods) + end, 0, SuiteMakeErrors), + {Ok,Errors+NoOfMakeErrors,Skipped}; + ErrorResult -> + ErrorResult + end catch _:BadFormat -> {error,BadFormat} @@ -2034,6 +2095,13 @@ final_tests1([{TestDir,Suite,GrsOrCs}|Tests], Final, Skip, Bad) when ({skipped,Group,TCs}) -> [ct_groups:make_conf(TestDir, Suite, Group, [skipped], TCs)]; + ({skipped,TC}) -> + case lists:member(TC, GrsOrCs) of + true -> + []; + false -> + [TC] + end; ({GrSpec = {GroupName,_},TCs}) -> Props = [{override,GrSpec}], [ct_groups:make_conf(TestDir, Suite, @@ -2073,7 +2141,9 @@ final_skip([], Final) -> continue([], _) -> true; -continue(_MakeErrors, AbortIfMissingSuites) -> +continue(_MakeErrors, true) -> + false; +continue(_MakeErrors, _AbortIfMissingSuites) -> io:nl(), OldGl = group_leader(), case set_group_leader_same_as_shell() of @@ -2101,11 +2171,10 @@ continue(_MakeErrors, AbortIfMissingSuites) -> true end; false -> % no shell process to use - not AbortIfMissingSuites + true end. set_group_leader_same_as_shell() -> - %%! Locate the shell process... UGLY!!! GS2or3 = fun(P) -> case process_info(P,initial_call) of {initial_call,{group,server,X}} when X == 2 ; X == 3 -> @@ -2153,10 +2222,18 @@ do_run_test(Tests, Skip, Opts0) -> %% test_server needs to know the include path too InclPath = case application:get_env(common_test, include) of {ok,Incls} -> Incls; - _ -> [] + _ -> [] end, application:set_env(test_server, include, InclPath), + %% copy the escape characters setting to test_server + EscChars = + case application:get_env(common_test, esc_chars) of + {ok,ECBool} -> ECBool; + _ -> true + end, + application:set_env(test_server, esc_chars, EscChars), + test_server_ctrl:start_link(local), %% let test_server expand the test tuples and count no of cases @@ -3042,6 +3119,10 @@ opts2args(EnvStartOpts) -> [{basic_html,[]}]; ({basic_html,false}) -> []; + ({esc_chars,false}) -> + [{no_esc_chars,[]}]; + ({esc_chars,true}) -> + []; ({event_handler,EH}) when is_atom(EH) -> [{event_handler,[atom_to_list(EH)]}]; ({event_handler,EHs}) when is_list(EHs) -> diff --git a/lib/common_test/src/ct_slave.erl b/lib/common_test/src/ct_slave.erl index 32a1ff4dbc..3ad3937548 100644 --- a/lib/common_test/src/ct_slave.erl +++ b/lib/common_test/src/ct_slave.erl @@ -1,7 +1,7 @@ %%-------------------------------------------------------------------- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2013. All Rights Reserved. +%% Copyright Ericsson AB 2010-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -134,7 +134,7 @@ start(Host, Node) -> %%% executed after startup of the node. Note that all used modules should be %%% present in the code path on the <code>Host</code>.</p> %%% -%%% <p>The timeouts are applied as follows: +%%% <p>The timeouts are applied as follows:</p> %%% <list> %%% <item> %%% <code>BootTimeout</code> - time to start the Erlang node, in seconds. @@ -154,7 +154,7 @@ start(Host, Node) -> %%% If this timeout occurs, the result %%% <code>{error, startup_timeout, NodeName}</code> is returned. %%% </item> -%%% </list></p> +%%% </list> %%% %%% <p>Option <code>monitor_master</code> specifies, if the slave node should be %%% stopped in case of master node stop. Defaults to false.</p> @@ -170,7 +170,7 @@ start(Host, Node) -> %%% <p>Option <code>env</code> specifies a list of environment variables %%% that will extended the environment.</p> %%% -%%% <p>Special return values are: +%%% <p>Special return values are:</p> %%% <list> %%% <item><code>{error, already_started, NodeName}</code> - if the node with %%% the given name is already started on a given host;</item> @@ -179,7 +179,7 @@ start(Host, Node) -> %%% <item><code>{error, not_alive, NodeName}</code> - if node on which the %%% <code>ct_slave:start/3</code> is called, is not alive. Note that %%% <code>NodeName</code> is the name of current node in this case.</item> -%%% </list></p> +%%% </list> %%% start(Host, Node, Opts) -> ENode = enodename(Host, Node), @@ -315,7 +315,7 @@ enodename(Host, Node) -> do_start(Host, Node, Options) -> ENode = enodename(Host, Node), Functions = - lists:concat([[{ct_slave, slave_started, [ENode, self()]}], + lists:append([[{ct_slave, slave_started, [ENode, self()]}], Options#options.startup_functions, [{ct_slave, slave_ready, [ENode, self()]}]]), Functions2 = if diff --git a/lib/common_test/src/ct_snmp.erl b/lib/common_test/src/ct_snmp.erl index 95098bdaca..bb0167eb22 100644 --- a/lib/common_test/src/ct_snmp.erl +++ b/lib/common_test/src/ct_snmp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2012. All Rights Reserved. +%% Copyright Ericsson AB 2004-2015. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ %%% @doc Common Test user interface module for the OTP snmp application %%% -%%% The purpose of this module is to make snmp configuration easier for +%%% <p>The purpose of this module is to make snmp configuration easier for %%% the test case writer. Many test cases can use default values for common %%% operations and then no snmp configuration files need to be supplied. When %%% it is necessary to change particular configuration parameters, a subset @@ -31,7 +31,7 @@ %%% To simplify the test suite, Common Test keeps track %%% of some of the snmp manager information. This way the test suite doesn't %%% have to handle as many input parameters as it would if it had to interface the -%%% OTP snmp manager directly. +%%% OTP snmp manager directly.</p> %%% %%% <p> The following snmp manager and agent parameters are configurable: </p> %%% @@ -326,9 +326,9 @@ set_info(Config) -> %%% @doc Register the manager entity (=user) responsible for specific agent(s). %%% Corresponds to making an entry in users.conf. %%% -%%% This function will try to register the given users, without +%%% <p>This function will try to register the given users, without %%% checking if any of them already exist. In order to change an -%%% already registered user, the user must first be unregistered. +%%% already registered user, the user must first be unregistered.</p> register_users(MgrAgentConfName, Users) -> case setup_users(Users) of ok -> @@ -351,10 +351,10 @@ register_users(MgrAgentConfName, Users) -> %%% @doc Explicitly instruct the manager to handle this agent. %%% Corresponds to making an entry in agents.conf %%% -%%% This function will try to register the given managed agents, +%%% <p>This function will try to register the given managed agents, %%% without checking if any of them already exist. In order to change %%% an already registered managed agent, the agent must first be -%%% unregistered. +%%% unregistered.</p> register_agents(MgrAgentConfName, ManagedAgents) -> case setup_managed_agents(MgrAgentConfName,ManagedAgents) of ok -> @@ -378,9 +378,9 @@ register_agents(MgrAgentConfName, ManagedAgents) -> %%% @doc Explicitly instruct the manager to handle this USM user. %%% Corresponds to making an entry in usm.conf %%% -%%% This function will try to register the given users, without +%%% <p>This function will try to register the given users, without %%% checking if any of them already exist. In order to change an -%%% already registered user, the user must first be unregistered. +%%% already registered user, the user must first be unregistered.</p> register_usm_users(MgrAgentConfName, UsmUsers) -> EngineID = ct:get_config({MgrAgentConfName, engine_id}, ?ENGINE_ID), case setup_usm_users(UsmUsers, EngineID) of diff --git a/lib/common_test/src/ct_telnet.erl b/lib/common_test/src/ct_telnet.erl index e9487e94db..715eb1bbbd 100644 --- a/lib/common_test/src/ct_telnet.erl +++ b/lib/common_test/src/ct_telnet.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2014. All Rights Reserved. +%% Copyright Ericsson AB 2003-2015. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -42,7 +42,8 @@ %% {reconnection_interval,Millisec}, %% {keep_alive,Bool}, %% {poll_limit,N}, -%% {poll_interval,Millisec}]}.</pre> +%% {poll_interval,Millisec}, +%% {tcp_nodelay,Bool}]}.</pre> %% <p><code>Millisec = integer(), N = integer()</code></p> %% <p>Enter the <code>telnet_settings</code> term in a configuration %% file included in the test and ct_telnet will retrieve the information @@ -182,7 +183,8 @@ conn_to=?DEFAULT_TIMEOUT, com_to=?DEFAULT_TIMEOUT, reconns=?RECONNS, - reconn_int=?RECONN_TIMEOUT}). + reconn_int=?RECONN_TIMEOUT, + tcp_nodelay=false}). %%%----------------------------------------------------------------- %%% @spec open(Name) -> {ok,Handle} | {error,Reason} @@ -327,16 +329,16 @@ cmd(Connection,Cmd) -> %%% Reason = term() %%% @doc Send a command via telnet and wait for prompt. %%% -%%% This function will by default add a newline to the end of the +%%% <p>This function will by default add a newline to the end of the %%% given command. If this is not desired, the option %%% `{newline,false}' can be used. This is necessary, for example, %%% when sending telnet command sequences (prefixed with the -%%% Interprete As Command, IAC, character). +%%% Interprete As Command, IAC, character).</p> %%% -%%% The option `timeout' specifies how long the client shall wait for +%%% <p>The option `timeout' specifies how long the client shall wait for %%% prompt. If the time expires, the function returns %%% `{error,timeout}'. See the module description for information -%%% about the default value for the command timeout. +%%% about the default value for the command timeout.</p> cmd(Connection,Cmd,Opts) when is_list(Opts) -> case check_cmd_opts(Opts) of ok -> @@ -378,7 +380,7 @@ cmdf(Connection,CmdFormat,Args) -> %%% @doc Send a telnet command and wait for prompt %%% (uses a format string and list of arguments to build the command). %%% -%%% See {@link cmd/3} further description. +%%% <p>See {@link cmd/3} further description.</p> cmdf(Connection,CmdFormat,Args,Opts) when is_list(Args) -> Cmd = lists:flatten(io_lib:format(CmdFormat,Args)), cmd(Connection,Cmd,Opts). @@ -602,8 +604,18 @@ init(Name,{Ip,Port,Type},{TargetMod,KeepAlive,Extra}) -> Settings -> set_telnet_defaults(Settings,#state{}) end, - case catch TargetMod:connect(Name,Ip,Port,S0#state.conn_to, - KeepAlive,Extra) of + %% Handle old user versions of TargetMod + code:ensure_loaded(TargetMod), + try + case erlang:function_exported(TargetMod,connect,7) of + true -> + TargetMod:connect(Name,Ip,Port,S0#state.conn_to, + KeepAlive,S0#state.tcp_nodelay,Extra); + false -> + TargetMod:connect(Name,Ip,Port,S0#state.conn_to, + KeepAlive,Extra) + end + of {ok,TelnPid} -> put({ct_telnet_pid2name,TelnPid},Name), S1 = S0#state{host=Ip, @@ -625,15 +637,18 @@ init(Name,{Ip,Port,Type},{TargetMod,KeepAlive,Extra}) -> "Connection timeout: ~p\n" "Keep alive: ~w\n" "Poll limit: ~w\n" - "Poll interval: ~w", + "Poll interval: ~w\n" + "TCP nodelay: ~w", [Ip,Port,S1#state.com_to,S1#state.reconns, S1#state.reconn_int,S1#state.conn_to,KeepAlive, - S1#state.poll_limit,S1#state.poll_interval]), + S1#state.poll_limit,S1#state.poll_interval, + S1#state.tcp_nodelay]), {ok,TelnPid,S1}; - {'EXIT',Reason} -> - {error,Reason}; Error -> Error + catch + _:Reason -> + {error,Reason} end. type(telnet) -> ip; @@ -653,6 +668,8 @@ set_telnet_defaults([{poll_limit,PL}|Ss],S) -> set_telnet_defaults(Ss,S#state{poll_limit=PL}); set_telnet_defaults([{poll_interval,PI}|Ss],S) -> set_telnet_defaults(Ss,S#state{poll_interval=PI}); +set_telnet_defaults([{tcp_nodelay,NoDelay}|Ss],S) -> + set_telnet_defaults(Ss,S#state{tcp_nodelay=NoDelay}); set_telnet_defaults([Unknown|Ss],S) -> force_log(S,error, "Bad element in telnet_settings: ~p",[Unknown]), @@ -794,8 +811,17 @@ reconnect(Ip,Port,N,State=#state{name=Name, keep_alive=KeepAlive, extra=Extra, conn_to=ConnTo, - reconn_int=ReconnInt}) -> - case TargetMod:connect(Name,Ip,Port,ConnTo,KeepAlive,Extra) of + reconn_int=ReconnInt, + tcp_nodelay=NoDelay}) -> + %% Handle old user versions of TargetMod + ConnResult = + case erlang:function_exported(TargetMod,connect,7) of + true -> + TargetMod:connect(Name,Ip,Port,ConnTo,KeepAlive,NoDelay,Extra); + false -> + TargetMod:connect(Name,Ip,Port,ConnTo,KeepAlive,Extra) + end, + case ConnResult of {ok,NewPid} -> put({ct_telnet_pid2name,NewPid},Name), {ok, NewPid, State#state{teln_pid=NewPid}}; @@ -928,7 +954,7 @@ log(#state{name=Name,teln_pid=TelnPid,host=Host,port=Port}, true -> ok; false -> - ct_gen_conn:cont_log(String,Args) + ct_gen_conn:cont_log_no_timestamp(String,Args) end; ForcePrint == true -> @@ -939,7 +965,7 @@ log(#state{name=Name,teln_pid=TelnPid,host=Host,port=Port}, %% called ct_gen_conn:log(heading(Action,Name1),String,Args); false -> - ct_gen_conn:cont_log(String,Args) + ct_gen_conn:cont_log_no_timestamp(String,Args) end end end. @@ -1198,7 +1224,6 @@ teln_expect1(Name,Pid,Data,Pattern,Acc,EO=#eo{idle_timeout=IdleTO, EOMod = if TotalTO /= infinity -> EO#eo{total_timeout=trunc(TotalTO)}; true -> EO end, - ExpectFun = case EOMod#eo.seq of true -> fun() -> seq_expect(Name,Pid,Data,Pattern,Acc,EOMod) @@ -1221,38 +1246,34 @@ teln_expect1(Name,Pid,Data,Pattern,Acc,EO=#eo{idle_timeout=IdleTO, true -> IdleTO end, + {PatOrPats1,Acc1,Rest1} = case NotFinished of + {nomatch,Rest0} -> + %% one expect + {Pattern,[],Rest0}; + {continue,Pats0,Acc0,Rest0} -> + %% sequence + {Pats0,Acc0,Rest0} + end, case timer:tc(ct_gen_conn, do_within_time, [Fun,BreakAfter]) of - {_,{error,Reason}} -> + {_,{error,Reason}} -> %% A timeout will occur when the telnet connection %% is idle for EO#eo.idle_timeout milliseconds. + if Rest1 /= [] -> + log(name_or_pid(Name,Pid)," ~ts",[Rest1]); + true -> + ok + end, {error,Reason}; {_,{ok,Data1}} when TotalTO == infinity -> - case NotFinished of - {nomatch,Rest} -> - %% One expect - teln_expect1(Name,Pid,Rest++Data1, - Pattern,[],EOMod); - {continue,Patterns1,Acc1,Rest} -> - %% Sequence - teln_expect1(Name,Pid,Rest++Data1, - Patterns1,Acc1,EOMod) - end; + teln_expect1(Name,Pid,Rest1++Data1,PatOrPats1,Acc1,EOMod); {Elapsed,{ok,Data1}} -> TVal = TotalTO - (Elapsed/1000), if TVal =< 0 -> {error,timeout}; true -> EO1 = EO#eo{total_timeout = TVal}, - case NotFinished of - {nomatch,Rest} -> - %% One expect - teln_expect1(Name,Pid,Rest++Data1, - Pattern,[],EO1); - {continue,Patterns1,Acc1,Rest} -> - %% Sequence - teln_expect1(Name,Pid,Rest++Data1, - Patterns1,Acc1,EO1) - end + teln_expect1(Name,Pid,Rest1++Data1, + PatOrPats1,Acc1,EO1) end end end. @@ -1390,14 +1411,14 @@ match_lines(Name,Pid,Data,Patterns,EO) -> case one_line(Data,[]) of {noline,Rest} when FoundPrompt=/=false -> %% This is the line including the prompt - case match_line(Name,Pid,Rest,Patterns,FoundPrompt,EO) of + case match_line(Name,Pid,Rest,Patterns,FoundPrompt,false,EO) of nomatch -> {nomatch,prompt}; {Tag,Match} -> {Tag,Match,[]} end; {noline,Rest} when EO#eo.prompt_check==false -> - case match_line(Name,Pid,Rest,Patterns,false,EO) of + case match_line(Name,Pid,Rest,Patterns,false,false,EO) of nomatch -> {nomatch,Rest}; {Tag,Match} -> @@ -1406,7 +1427,7 @@ match_lines(Name,Pid,Data,Patterns,EO) -> {noline,Rest} -> {nomatch,Rest}; {Line,Rest} -> - case match_line(Name,Pid,Line,Patterns,false,EO) of + case match_line(Name,Pid,Line,Patterns,false,true,EO) of nomatch -> match_lines(Name,Pid,Rest,Patterns,EO); {Tag,Match} -> @@ -1414,45 +1435,50 @@ match_lines(Name,Pid,Data,Patterns,EO) -> end end. - %% For one line, match each pattern -match_line(Name,Pid,Line,Patterns,FoundPrompt,EO) -> - match_line(Name,Pid,Line,Patterns,FoundPrompt,EO,match). +match_line(Name,Pid,Line,Patterns,FoundPrompt,Terminated,EO) -> + match_line(Name,Pid,Line,Patterns,FoundPrompt,Terminated,EO,match). -match_line(Name,Pid,Line,[prompt|Patterns],false,EO,RetTag) -> - match_line(Name,Pid,Line,Patterns,false,EO,RetTag); -match_line(Name,Pid,Line,[prompt|_Patterns],FoundPrompt,_EO,RetTag) -> +match_line(Name,Pid,Line,[prompt|Patterns],false,Term,EO,RetTag) -> + match_line(Name,Pid,Line,Patterns,false,Term,EO,RetTag); +match_line(Name,Pid,Line,[prompt|_Patterns],FoundPrompt,_Term,_EO,RetTag) -> log(name_or_pid(Name,Pid)," ~ts",[Line]), log(name_or_pid(Name,Pid),"PROMPT: ~ts",[FoundPrompt]), {RetTag,{prompt,FoundPrompt}}; -match_line(Name,Pid,Line,[{prompt,PromptType}|_Patterns],FoundPrompt,_EO,RetTag) - when PromptType==FoundPrompt -> +match_line(Name,Pid,Line,[{prompt,PromptType}|_Patterns],FoundPrompt,_Term, + _EO,RetTag) when PromptType==FoundPrompt -> log(name_or_pid(Name,Pid)," ~ts",[Line]), log(name_or_pid(Name,Pid),"PROMPT: ~ts",[FoundPrompt]), {RetTag,{prompt,FoundPrompt}}; -match_line(Name,Pid,Line,[{prompt,PromptType}|Patterns],FoundPrompt,EO,RetTag) +match_line(Name,Pid,Line,[{prompt,PromptType}|Patterns],FoundPrompt,Term, + EO,RetTag) when PromptType=/=FoundPrompt -> - match_line(Name,Pid,Line,Patterns,FoundPrompt,EO,RetTag); -match_line(Name,Pid,Line,[{Tag,Pattern}|Patterns],FoundPrompt,EO,RetTag) -> + match_line(Name,Pid,Line,Patterns,FoundPrompt,Term,EO,RetTag); +match_line(Name,Pid,Line,[{Tag,Pattern}|Patterns],FoundPrompt,Term,EO,RetTag) -> case re:run(Line,Pattern,[{capture,all,list}]) of nomatch -> - match_line(Name,Pid,Line,Patterns,FoundPrompt,EO,RetTag); + match_line(Name,Pid,Line,Patterns,FoundPrompt,Term,EO,RetTag); {match,Match} -> log(name_or_pid(Name,Pid),"MATCH: ~ts",[Line]), {RetTag,{Tag,Match}} end; -match_line(Name,Pid,Line,[Pattern|Patterns],FoundPrompt,EO,RetTag) -> +match_line(Name,Pid,Line,[Pattern|Patterns],FoundPrompt,Term,EO,RetTag) -> case re:run(Line,Pattern,[{capture,all,list}]) of nomatch -> - match_line(Name,Pid,Line,Patterns,FoundPrompt,EO,RetTag); + match_line(Name,Pid,Line,Patterns,FoundPrompt,Term,EO,RetTag); {match,Match} -> log(name_or_pid(Name,Pid),"MATCH: ~ts",[Line]), {RetTag,Match} end; -match_line(Name,Pid,Line,[],FoundPrompt,EO,match) -> - match_line(Name,Pid,Line,EO#eo.haltpatterns,FoundPrompt,EO,halt); -match_line(Name,Pid,Line,[],_FoundPrompt,_EO,halt) -> +match_line(Name,Pid,Line,[],FoundPrompt,Term,EO,match) -> + match_line(Name,Pid,Line,EO#eo.haltpatterns,FoundPrompt,Term,EO,halt); +%% print any terminated line that can not be matched +match_line(Name,Pid,Line,[],_FoundPrompt,true,_EO,halt) -> log(name_or_pid(Name,Pid)," ~ts",[Line]), + nomatch; +%% if there's no line termination, Line is saved as Rest (above) and will +%% be printed later +match_line(_Name,_Pid,_Line,[],_FoundPrompt,false,_EO,halt) -> nomatch. one_line([$\n|Rest],Line) -> diff --git a/lib/common_test/src/ct_telnet_client.erl b/lib/common_test/src/ct_telnet_client.erl index 99d683244c..bdab456cfa 100644 --- a/lib/common_test/src/ct_telnet_client.erl +++ b/lib/common_test/src/ct_telnet_client.erl @@ -35,7 +35,7 @@ %%-define(debug, true). --export([open/2, open/3, open/4, open/5, close/1]). +-export([open/2, open/3, open/4, open/5, open/6, close/1]). -export([send_data/2, send_data/3, get_data/1]). -define(TELNET_PORT, 23). @@ -70,19 +70,22 @@ -record(state,{conn_name, get_data, keep_alive=true, log_pos=1}). open(Server, ConnName) -> - open(Server, ?TELNET_PORT, ?OPEN_TIMEOUT, true, ConnName). + open(Server, ?TELNET_PORT, ?OPEN_TIMEOUT, true, false, ConnName). open(Server, Port, ConnName) -> - open(Server, Port, ?OPEN_TIMEOUT, true, ConnName). + open(Server, Port, ?OPEN_TIMEOUT, true, false, ConnName). open(Server, Port, Timeout, ConnName) -> - open(Server, Port, Timeout, true, ConnName). + open(Server, Port, Timeout, true, false, ConnName). open(Server, Port, Timeout, KeepAlive, ConnName) -> + open(Server, Port, Timeout, KeepAlive, false, ConnName). + +open(Server, Port, Timeout, KeepAlive, NoDelay, ConnName) -> Self = self(), Pid = spawn(fun() -> init(Self, Server, Port, Timeout, - KeepAlive, ConnName) + KeepAlive, NoDelay, ConnName) end), receive {open,Pid} -> @@ -114,8 +117,8 @@ get_data(Pid) -> %%%----------------------------------------------------------------- %%% Internal functions -init(Parent, Server, Port, Timeout, KeepAlive, ConnName) -> - case gen_tcp:connect(Server, Port, [list,{packet,0},{nodelay,true}], Timeout) of +init(Parent, Server, Port, Timeout, KeepAlive, NoDelay, ConnName) -> + case gen_tcp:connect(Server, Port, [list,{packet,0},{nodelay,NoDelay}], Timeout) of {ok,Sock} -> dbg("~p connected to: ~p (port: ~w, keep_alive: ~w)\n", [ConnName,Server,Port,KeepAlive]), diff --git a/lib/common_test/src/ct_testspec.erl b/lib/common_test/src/ct_testspec.erl index 5d5448f352..61d8f49dcc 100644 --- a/lib/common_test/src/ct_testspec.erl +++ b/lib/common_test/src/ct_testspec.erl @@ -70,13 +70,17 @@ prepare_tests(TestSpec) when is_record(TestSpec,testspec) -> Tests = TestSpec#testspec.tests, %% Sort Tests into "flat" Run and Skip lists (not sorted per node). {Run,Skip} = get_run_and_skip(Tests,[],[]), + %% Create initial list of {Node,{Run,Skip}} tuples NodeList = lists:map(fun(N) -> {N,{[],[]}} end, list_nodes(TestSpec)), + %% Get all Run tests sorted per node basis. NodeList1 = run_per_node(Run,NodeList, - TestSpec#testspec.merge_tests), + TestSpec#testspec.merge_tests), + %% Get all Skip entries sorted per node basis. NodeList2 = skip_per_node(Skip,NodeList1), + %% Change representation. Result= lists:map(fun({Node,{Run1,Skip1}}) -> @@ -103,7 +107,7 @@ run_per_node([{{Node,Dir},Test}|Ts],Result,MergeTests) -> true -> merge_tests(Dir,Test,Run) end, - run_per_node(Ts,insert_in_order({Node,{Run1,Skip}},Result), + run_per_node(Ts,insert_in_order({Node,{Run1,Skip}},Result,replace), MergeTests); run_per_node([],Result,_) -> Result. @@ -140,7 +144,7 @@ merge_suites(Dir,Test,[]) -> skip_per_node([{{Node,Dir},Test}|Ts],Result) -> {value,{Node,{Run,Skip}}} = lists:keysearch(Node,1,Result), Skip1 = [{Dir,Test}|Skip], - skip_per_node(Ts,insert_in_order({Node,{Run,Skip1}},Result)); + skip_per_node(Ts,insert_in_order({Node,{Run,Skip1}},Result,replace)); skip_per_node([],Result) -> Result. @@ -156,7 +160,7 @@ skip_per_node([],Result) -> %% %% Skip entry: {Suites,Comment} or {Suite,Cases,Comment} %% -get_run_and_skip([{{Node,Dir},Suites}|Tests],Run,Skip) -> +get_run_and_skip([{{Node,Dir},Suites}|Tests],Run,Skip) -> TestDir = ct_util:get_testdir(Dir,catch element(1,hd(Suites))), case lists:keysearch(all,1,Suites) of {value,_} -> % all Suites in Dir @@ -183,18 +187,33 @@ prepare_suites(Node,Dir,[{Suite,Cases}|Suites],Run,Skip) -> [[{{Node,Dir},{Suite,all}}]|Run], [Skipped|Skip]); false -> - {RL,SL} = prepare_cases(Node,Dir,Suite,Cases), - prepare_suites(Node,Dir,Suites,[RL|Run],[SL|Skip]) + {Run1,Skip1} = prepare_cases(Node,Dir,Suite,Cases,Run,Skip), + prepare_suites(Node,Dir,Suites,Run1,Skip1) end; prepare_suites(_Node,_Dir,[],Run,Skip) -> {lists:flatten(lists:reverse(Run)), lists:flatten(lists:reverse(Skip))}. -prepare_cases(Node,Dir,Suite,Cases) -> +prepare_cases(Node,Dir,Suite,Cases,Run,Skip) -> case get_skipped_cases(Node,Dir,Suite,Cases) of - SkipAll=[{{Node,Dir},{Suite,_Cmt}}] -> % all cases to be skipped - %% note: this adds an 'all' test even if only skip is specified - {[{{Node,Dir},{Suite,all}}],SkipAll}; + [SkipAll={{Node,Dir},{Suite,_Cmt}}] -> % all cases to be skipped + case lists:any(fun({{N,D},{S,all}}) when N == Node, + D == Dir, + S == Suite -> + true; + ({{N,D},{S,Cs}}) when N == Node, + D == Dir, + S == Suite -> + lists:member(all,Cs); + (_) -> false + end, lists:flatten(Run)) of + true -> + {Run,[SkipAll|Skip]}; + false -> + %% note: this adds an 'all' test even if + %% only skip is specified + {[{{Node,Dir},{Suite,all}}|Run],[SkipAll|Skip]} + end; Skipped -> %% note: this adds a test even if only skip is specified PrepC = lists:foldr(fun({{G,Cs},{skip,_Cmt}}, Acc) when @@ -210,11 +229,11 @@ prepare_cases(Node,Dir,Suite,Cases) -> true -> Acc; false -> - [C|Acc] + [{skipped,C}|Acc] end; (C,Acc) -> [C|Acc] end, [], Cases), - {{{Node,Dir},{Suite,PrepC}},Skipped} + {[{{Node,Dir},{Suite,PrepC}}|Run],[Skipped|Skip]} end. get_skipped_suites(Node,Dir,Suites) -> @@ -431,6 +450,7 @@ collect_tests({Replace,Terms},TestSpec=#testspec{alias=As,nodes=Ns},Relaxed) -> merge_tests = MergeTestsDef}), TestSpec2 = get_all_nodes(Terms2,TestSpec1), {Terms3, TestSpec3} = filter_init_terms(Terms2, [], TestSpec2), + add_tests(Terms3,TestSpec3). %% replace names (atoms) in the testspec matching those in 'define' terms by @@ -1126,8 +1146,9 @@ should_be_added(Tag,Node,_Data,Spec) -> if %% list terms *without* possible duplicates here Tag == logdir; Tag == logopts; - Tag == basic_html; Tag == label; - Tag == auto_compile; Tag == abort_if_missing_suites; + Tag == basic_html; Tag == esc_chars; + Tag == label; Tag == auto_compile; + Tag == abort_if_missing_suites; Tag == stylesheet; Tag == verbosity; Tag == silent_connections -> lists:keymember(ref2node(Node,Spec#testspec.nodes),1, @@ -1257,7 +1278,7 @@ insert_groups1(Suite,Groups,Suites0) -> Suites0; {value,{Suite,GrAndCases0}} -> GrAndCases = insert_groups2(Groups,GrAndCases0), - insert_in_order({Suite,GrAndCases},Suites0); + insert_in_order({Suite,GrAndCases},Suites0,replace); false -> insert_in_order({Suite,Groups},Suites0) end. @@ -1282,7 +1303,7 @@ insert_cases(Node,Dir,Suite,Cases,Tests,false) when is_list(Cases) -> insert_cases(Node,Dir,Suite,Cases,Tests,true) when is_list(Cases) -> {Tests1,Done} = lists:foldr(fun(All={{N,D},[{all,_}]},{Merged,_}) when N == Node, - D == Dir -> + D == Dir -> {[All|Merged],true}; ({{N,D},Suites0},{Merged,_}) when N == Node, D == Dir -> @@ -1312,7 +1333,7 @@ insert_cases1(Suite,Cases,Suites0) -> Suites0; {value,{Suite,Cases0}} -> Cases1 = insert_in_order(Cases,Cases0), - insert_in_order({Suite,Cases1},Suites0); + insert_in_order({Suite,Cases1},Suites0,replace); false -> insert_in_order({Suite,Cases},Suites0) end. @@ -1369,9 +1390,9 @@ skip_groups1(Suite,Groups,Cmt,Suites0) -> case lists:keysearch(Suite,1,Suites0) of {value,{Suite,GrAndCases0}} -> GrAndCases1 = GrAndCases0 ++ SkipGroups, - insert_in_order({Suite,GrAndCases1},Suites0); + insert_in_order({Suite,GrAndCases1},Suites0,replace); false -> - insert_in_order({Suite,SkipGroups},Suites0) + insert_in_order({Suite,SkipGroups},Suites0,replace) end. skip_cases(Node,Dir,Suite,Cases,Cmt,Tests,false) when is_list(Cases) -> @@ -1380,7 +1401,7 @@ skip_cases(Node,Dir,Suite,Cases,Cmt,Tests,false) when is_list(Cases) -> skip_cases(Node,Dir,Suite,Cases,Cmt,Tests,true) when is_list(Cases) -> {Tests1,Done} = lists:foldr(fun({{N,D},Suites0},{Merged,_}) when N == Node, - D == Dir -> + D == Dir -> Suites1 = skip_cases1(Suite,Cases,Cmt,Suites0), {[{{N,D},Suites1}|Merged],true}; (T,{Merged,Match}) -> @@ -1401,32 +1422,55 @@ skip_cases1(Suite,Cases,Cmt,Suites0) -> case lists:keysearch(Suite,1,Suites0) of {value,{Suite,Cases0}} -> Cases1 = Cases0 ++ SkipCases, - insert_in_order({Suite,Cases1},Suites0); + insert_in_order({Suite,Cases1},Suites0,replace); false -> - insert_in_order({Suite,SkipCases},Suites0) + case Suites0 of + [{all,_}=All|Skips]-> + [All|Skips++[{Suite,SkipCases}]]; + _ -> + insert_in_order({Suite,SkipCases},Suites0,replace) + end end. append(Elem, List) -> List ++ [Elem]. -insert_in_order([E|Es],List) -> - List1 = insert_elem(E,List,[]), - insert_in_order(Es,List1); -insert_in_order([],List) -> +insert_in_order(Elems,Dest) -> + insert_in_order1(Elems,Dest,false). + +insert_in_order(Elems,Dest,replace) -> + insert_in_order1(Elems,Dest,true). + +insert_in_order1([_E|Es],all,Replace) -> + insert_in_order1(Es,all,Replace); + +insert_in_order1([E|Es],List,Replace) -> + List1 = insert_elem(E,List,[],Replace), + insert_in_order1(Es,List1,Replace); +insert_in_order1([],List,_Replace) -> List; -insert_in_order(E,List) -> - insert_elem(E,List,[]). +insert_in_order1(E,List,Replace) -> + insert_elem(E,List,[],Replace). + -%% replace an existing entry (same key) or add last in list -insert_elem({Key,_}=E,[{Key,_}|Rest],SoFar) -> +insert_elem({Key,_}=E,[{Key,_}|Rest],SoFar,true) -> lists:reverse([E|SoFar]) ++ Rest; -insert_elem({E,_},[E|Rest],SoFar) -> +insert_elem({E,_},[E|Rest],SoFar,true) -> lists:reverse([E|SoFar]) ++ Rest; -insert_elem(E,[E|Rest],SoFar) -> +insert_elem(E,[E|Rest],SoFar,true) -> + lists:reverse([E|SoFar]) ++ Rest; + +insert_elem({all,_}=E,_,SoFar,_Replace) -> + lists:reverse([E|SoFar]); +insert_elem(_E,[all|_],SoFar,_Replace) -> + lists:reverse(SoFar); +insert_elem(_E,[{all,_}],SoFar,_Replace) -> + lists:reverse(SoFar); +insert_elem({Key,_}=E,[{Key,[]}|Rest],SoFar,_Replace) -> lists:reverse([E|SoFar]) ++ Rest; -insert_elem(E,[E1|Rest],SoFar) -> - insert_elem(E,Rest,[E1|SoFar]); -insert_elem(E,[],SoFar) -> +insert_elem(E,[E1|Rest],SoFar,Replace) -> + insert_elem(E,Rest,[E1|SoFar],Replace); +insert_elem(E,[],SoFar,_Replace) -> lists:reverse([E|SoFar]). ref2node(all_nodes,_Refs) -> @@ -1501,6 +1545,8 @@ valid_terms() -> {logopts,3}, {basic_html,2}, {basic_html,3}, + {esc_chars,2}, + {esc_chars,3}, {verbosity,2}, {verbosity,3}, {silent_connections,2}, diff --git a/lib/common_test/src/ct_util.erl b/lib/common_test/src/ct_util.erl index 445fce1db8..3561a0a2d3 100644 --- a/lib/common_test/src/ct_util.erl +++ b/lib/common_test/src/ct_util.erl @@ -459,6 +459,7 @@ loop(Mode,TestData,StartDir) -> error:badarg -> [] end, ct_hooks:terminate(Callbacks), + close_connections(ets:tab2list(?conn_table)), ets:delete(?conn_table), ets:delete(?board_table), @@ -485,6 +486,8 @@ loop(Mode,TestData,StartDir) -> {'EXIT',Pid,Reason} -> case ets:lookup(?conn_table,Pid) of [#conn{address=A,callback=CB}] -> + ErrorStr = io_lib:format("~tp", [Reason]), + ErrorHtml = ct_logs:escape_chars(ErrorStr), %% A connection crashed - remove the connection but don't die ct_logs:tc_log_async(ct_error_notify, ?MAX_IMPORTANCE, @@ -492,8 +495,8 @@ loop(Mode,TestData,StartDir) -> "Connection process died: " "Pid: ~w, Address: ~p, " "Callback: ~w\n" - "Reason: ~p\n\n", - [Pid,A,CB,Reason]), + "Reason: ~ts\n\n", + [Pid,A,CB,ErrorHtml]), catch CB:close(Pid), %% in case CB:close failed to do this: unregister_connection(Pid), diff --git a/lib/common_test/src/ct_util.hrl b/lib/common_test/src/ct_util.hrl index 2c1954c2b3..bdfe2041a5 100644 --- a/lib/common_test/src/ct_util.hrl +++ b/lib/common_test/src/ct_util.hrl @@ -37,6 +37,7 @@ logdir=["."], logopts=[], basic_html=[], + esc_chars=[], verbosity=[], silent_connections=[], cover=[], diff --git a/lib/common_test/src/cth_conn_log.erl b/lib/common_test/src/cth_conn_log.erl index 9b3dc0b5f1..954b4239af 100644 --- a/lib/common_test/src/cth_conn_log.erl +++ b/lib/common_test/src/cth_conn_log.erl @@ -132,7 +132,7 @@ pre_init_per_testcase(TestCase,Config,CthState) -> [S,ct_logs:uri(L),filename:basename(L)]) || {S,L} <- Ls] ++ "</table>", - io:format(Str,[]), + ct:log(Str,[],[no_css]), {ConnMod,{LogType,Ls}}; _ -> {ConnMod,{LogType,[]}} diff --git a/lib/common_test/src/cth_log_redirect.erl b/lib/common_test/src/cth_log_redirect.erl index e6970a2bad..780fbea79a 100644 --- a/lib/common_test/src/cth_log_redirect.erl +++ b/lib/common_test/src/cth_log_redirect.erl @@ -30,7 +30,8 @@ pre_init_per_suite/3, pre_end_per_suite/3, post_end_per_suite/4, pre_init_per_group/3, post_init_per_group/4, pre_end_per_group/3, post_end_per_group/4, - pre_init_per_testcase/3, post_end_per_testcase/4]). + pre_init_per_testcase/3, post_init_per_testcase/4, + pre_end_per_testcase/3, post_end_per_testcase/4]). %% Event handler Callbacks -export([init/1, @@ -89,6 +90,12 @@ pre_init_per_testcase(TC, Config, State) -> set_curr_func(TC, Config), {Config, State}. +post_init_per_testcase(_TC, _Config, Return, State) -> + {Return, State}. + +pre_end_per_testcase(_TC, Config, State) -> + {Config, State}. + post_end_per_testcase(_TC, _Config, Result, State) -> %% Make sure that the event queue is flushed %% before ending this test case. @@ -123,7 +130,14 @@ handle_event(Event, #eh_state{log_func = LogFunc} = State) -> tag_event(Event)), if is_list(SReport) -> SaslHeader = format_header(State), - ct_logs:LogFunc(sasl, ?STD_IMPORTANCE, SaslHeader, SReport, []); + case LogFunc of + tc_log -> + ct_logs:tc_log(sasl, ?STD_IMPORTANCE, + SaslHeader, SReport, [], []); + tc_log_async -> + ct_logs:tc_log_async(sasl, ?STD_IMPORTANCE, + SaslHeader, SReport, []) + end; true -> %% Report is an atom if no logging is to be done ignore end @@ -132,7 +146,14 @@ handle_event(Event, #eh_state{log_func = LogFunc} = State) -> tag_event(Event),io_lib), if is_list(EReport) -> ErrHeader = format_header(State), - ct_logs:LogFunc(error_logger, ?STD_IMPORTANCE, ErrHeader, EReport, []); + case LogFunc of + tc_log -> + ct_logs:tc_log(error_logger, ?STD_IMPORTANCE, + ErrHeader, EReport, [], []); + tc_log_async -> + ct_logs:tc_log_async(error_logger, ?STD_IMPORTANCE, + ErrHeader, EReport, []) + end; true -> %% Report is an atom if no logging is to be done ignore end, diff --git a/lib/common_test/src/cth_surefire.erl b/lib/common_test/src/cth_surefire.erl index 31a8e1c076..d6e855c02c 100644 --- a/lib/common_test/src/cth_surefire.erl +++ b/lib/common_test/src/cth_surefire.erl @@ -82,7 +82,8 @@ init(Path, Opts) -> url_base = proplists:get_value(url_base,Opts), timer = ?now }. -pre_init_per_suite(Suite,SkipOrFail,State) when is_tuple(SkipOrFail) -> +pre_init_per_suite(Suite,SkipOrFail,#state{ test_cases = [] } = State) + when is_tuple(SkipOrFail) -> {SkipOrFail, init_tc(State#state{curr_suite = Suite, curr_suite_ts = ?now}, SkipOrFail) }; diff --git a/lib/common_test/src/unix_telnet.erl b/lib/common_test/src/unix_telnet.erl index e5b3058999..2fc585735d 100644 --- a/lib/common_test/src/unix_telnet.erl +++ b/lib/common_test/src/unix_telnet.erl @@ -27,7 +27,8 @@ %%% {port,PortNum}, % optional %%% {username,UserName}, %%% {password,Password}, -%%% {keep_alive,Bool}]}. % optional</pre> +%%% {keep_alive,Bool}, % optional +%%% {tcp_nodely,Bool}]} % optional</pre> %%% %%% <p>To communicate via telnet to the host specified by %%% <code>HostNameOrIpAddress</code>, use the interface functions in @@ -55,7 +56,7 @@ -compile(export_all). %% Callbacks for ct_telnet.erl --export([connect/6,get_prompt_regexp/0]). +-export([connect/7,get_prompt_regexp/0]). -import(ct_telnet,[start_gen_log/1,log/4,end_gen_log/0]). -define(username,"login: "). @@ -82,6 +83,7 @@ get_prompt_regexp() -> %%% Port = integer() %%% Timeout = integer() %%% KeepAlive = bool() +%%% TCPNoDelay = bool() %%% Extra = ct:target_name() | {Username,Password} %%% Username = string() %%% Password = string() @@ -91,25 +93,25 @@ get_prompt_regexp() -> %%% @doc Callback for ct_telnet.erl. %%% %%% <p>Setup telnet connection to a unix host.</p> -connect(ConnName,Ip,Port,Timeout,KeepAlive,Extra) -> +connect(ConnName,Ip,Port,Timeout,KeepAlive,TCPNoDelay,Extra) -> case Extra of {Username,Password} -> - connect1(ConnName,Ip,Port,Timeout,KeepAlive, + connect1(ConnName,Ip,Port,Timeout,KeepAlive,TCPNoDelay, Username,Password); KeyOrName -> case get_username_and_password(KeyOrName) of {ok,{Username,Password}} -> - connect1(ConnName,Ip,Port,Timeout,KeepAlive, + connect1(ConnName,Ip,Port,Timeout,KeepAlive,TCPNoDelay, Username,Password); Error -> Error end end. -connect1(Name,Ip,Port,Timeout,KeepAlive,Username,Password) -> +connect1(Name,Ip,Port,Timeout,KeepAlive,TCPNoDelay,Username,Password) -> start_gen_log("unix_telnet connect"), Result = - case ct_telnet_client:open(Ip,Port,Timeout,KeepAlive,Name) of + case ct_telnet_client:open(Ip,Port,Timeout,KeepAlive,TCPNoDelay,Name) of {ok,Pid} -> case ct_telnet:silent_teln_expect(Name,Pid,[], [prompt],?prx,[]) of diff --git a/lib/common_test/test/Makefile b/lib/common_test/test/Makefile index ff4495b104..a1cead4550 100644 --- a/lib/common_test/test/Makefile +++ b/lib/common_test/test/Makefile @@ -65,7 +65,8 @@ MODULES= \ ct_cover_nomerge_SUITE \ ct_groups_search_SUITE \ ct_surefire_SUITE \ - ct_telnet_SUITE + ct_telnet_SUITE \ + ct_release_test_SUITE ERL_FILES= $(MODULES:%=%.erl) diff --git a/lib/common_test/test/ct_error_SUITE.erl b/lib/common_test/test/ct_error_SUITE.erl index 8326705575..53cfbd7118 100644 --- a/lib/common_test/test/ct_error_SUITE.erl +++ b/lib/common_test/test/ct_error_SUITE.erl @@ -728,23 +728,25 @@ test_events(lib_error) -> {lib_error_1_SUITE,no_lines_throw,{failed,{error,{thrown,catch_me_if_u_can}}}}}, {?eh,test_stats,{0,8,{0,0}}}, {?eh,tc_start,{lib_error_1_SUITE,init_tc_error}}, - {?eh,tc_done,{lib_error_1_SUITE,init_tc_error,ok}}, - {?eh,test_stats,{1,8,{0,0}}}, + {?eh,tc_done,{ct_framework,init_tc, + {framework_error,{{badmatch,[1,2]},'_'}}}}, + {?eh,test_stats,{0,9,{0,0}}}, {?eh,tc_start,{lib_error_1_SUITE,init_tc_exit}}, - {?eh,tc_done,{lib_error_1_SUITE,init_tc_exit,ok}}, - {?eh,test_stats,{2,8,{0,0}}}, + {?eh,tc_done,{ct_framework,init_tc,{framework_error,byebye}}}, + {?eh,test_stats,{0,10,{0,0}}}, {?eh,tc_start,{lib_error_1_SUITE,init_tc_throw}}, - {?eh,tc_done,{lib_error_1_SUITE,init_tc_throw,ok}}, - {?eh,test_stats,{3,8,{0,0}}}, + {?eh,tc_done,{ct_framework,init_tc,{framework_error,catch_me_if_u_can}}}, + {?eh,test_stats,{0,11,{0,0}}}, {?eh,tc_start,{lib_error_1_SUITE,end_tc_error}}, - {?eh,tc_done,{lib_error_1_SUITE,end_tc_error,ok}}, - {?eh,test_stats,{3,9,{0,0}}}, + {?eh,tc_done,{ct_framework,end_tc, + {framework_error,{{badmatch,[1,2]},'_'}}}}, + {?eh,test_stats,{0,12,{0,0}}}, {?eh,tc_start,{lib_error_1_SUITE,end_tc_exit}}, - {?eh,tc_done,{lib_error_1_SUITE,end_tc_exit,ok}}, - {?eh,test_stats,{3,10,{0,0}}}, + {?eh,tc_done,{ct_framework,end_tc,{framework_error,byebye}}}, + {?eh,test_stats,{0,13,{0,0}}}, {?eh,tc_start,{lib_error_1_SUITE,end_tc_throw}}, - {?eh,tc_done,{lib_error_1_SUITE,end_tc_throw,ok}}, - {?eh,test_stats,{3,11,{0,0}}}, + {?eh,tc_done,{ct_framework,end_tc,{framework_error,catch_me_if_u_can}}}, + {?eh,test_stats,{0,14,{0,0}}}, {?eh,tc_start,{lib_error_1_SUITE,end_per_suite}}, {?eh,tc_done,{lib_error_1_SUITE,end_per_suite,ok}}, {?eh,test_done,{'DEF','STOP_TIME'}}, diff --git a/lib/common_test/test/ct_error_SUITE_data/error/test/lib_error_1_SUITE.erl b/lib/common_test/test/ct_error_SUITE_data/error/test/lib_error_1_SUITE.erl index 658c7e8232..6f1b391ae6 100644 --- a/lib/common_test/test/ct_error_SUITE_data/error/test/lib_error_1_SUITE.erl +++ b/lib/common_test/test/ct_error_SUITE_data/error/test/lib_error_1_SUITE.erl @@ -152,23 +152,32 @@ no_lines_throw(_) -> lib_no_lines:do_throw(), ok. -init_tc_error(_) -> +init_tc_error() -> put('$test_server_framework_test', fun(init_tc, _Default) -> lib_no_lines:do_error(), ok; (_, Default) -> Default - end), ok. + end), []. -init_tc_exit(_) -> +init_tc_error(_) -> + ok. + +init_tc_exit() -> put('$test_server_framework_test', fun(init_tc, _Default) -> lib_no_lines:do_exit(), ok; (_, Default) -> Default - end), ok. + end), []. -init_tc_throw(_) -> +init_tc_exit(_) -> + ok. + +init_tc_throw() -> put('$test_server_framework_test', fun(init_tc, _Default) -> lib_no_lines:do_throw(), ok; (_, Default) -> Default - end), ok. + end), []. + +init_tc_throw(_) -> + ok. end_tc_error(_) -> put('$test_server_framework_test', diff --git a/lib/common_test/test/ct_hooks_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE.erl index f00b2bbb43..8353f5936c 100644 --- a/lib/common_test/test/ct_hooks_SUITE.erl +++ b/lib/common_test/test/ct_hooks_SUITE.erl @@ -324,6 +324,8 @@ test_events(one_empty_cth) -> {?eh,tc_start,{ct_cth_empty_SUITE,test_case}}, {?eh,cth,{empty_cth,pre_init_per_testcase,[test_case,'$proplist',[]]}}, + {?eh,cth,{empty_cth,post_init_per_testcase,[test_case,'$proplist','_',[]]}}, + {?eh,cth,{empty_cth,pre_end_per_testcase,[test_case,'$proplist',[]]}}, {?eh,cth,{empty_cth,post_end_per_testcase,[test_case,'$proplist','_',[]]}}, {?eh,tc_done,{ct_cth_empty_SUITE,test_case,ok}}, diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/crash_init_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/crash_init_cth.erl index 3b2fd4b3c0..023f6440c2 100644 --- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/crash_init_cth.erl +++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/crash_init_cth.erl @@ -1,8 +1,8 @@ -%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
-%%
+%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at @@ -14,22 +14,22 @@ %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. -%%
-%% %CopyrightEnd%
-%%
-
-
--module(crash_init_cth).
-
-
--include_lib("common_test/src/ct_util.hrl").
--include_lib("common_test/include/ct_event.hrl").
-
-
-%% CT Hooks
--export([init/2]).
-
-init(Id, Opts) ->
- empty_cth:init(Id, Opts),
- exit(diediedie).
-
+%% +%% %CopyrightEnd% +%% + + +-module(crash_init_cth). + + +-include_lib("common_test/src/ct_util.hrl"). +-include_lib("common_test/include/ct_event.hrl"). + + +%% CT Hooks +-export([init/2]). + +init(Id, Opts) -> + empty_cth:init(Id, Opts), + exit(diediedie). + diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_cth_empty_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_cth_empty_SUITE.erl index be2ade0715..c443700dde 100644 --- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_cth_empty_SUITE.erl +++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_cth_empty_SUITE.erl @@ -1,8 +1,8 @@ -%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
-%%
+%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at @@ -14,35 +14,36 @@ %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. -%%
-%% %CopyrightEnd%
-%%
-
--module(ct_cth_empty_SUITE).
-
--suite_defaults([{timetrap, {minutes, 10}}]).
-
-%% Note: This directive should only be used in test suites.
--compile(export_all).
-
--include("ct.hrl").
-
-%% Test server callback functions
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_testcase(_TestCase, Config) ->
- Config.
-
-end_per_testcase(_TestCase, _Config) ->
- ok.
-
-all() ->
- [test_case].
-
-%% Test cases starts here.
-test_case(Config) when is_list(Config) ->
- ok.
+%% +%% %CopyrightEnd% +%% + +-module(ct_cth_empty_SUITE). + +-suite_defaults([{timetrap, {minutes, 10}}]). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include("ct.hrl"). + +%% Test server callback functions +init_per_suite(Config) -> + Config. + +end_per_suite(_Config) -> + ok. + +init_per_testcase(_TestCase, Config) -> + Config. + +end_per_testcase(_TestCase, _Config) -> + ok. + +all() -> + [test_case]. + +%% Test cases starts here. +test_case(Config) when is_list(Config) -> + ok. + diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_update_config_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_update_config_SUITE.erl index 9a924a66ac..5e4df0b3c2 100644 --- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_update_config_SUITE.erl +++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_update_config_SUITE.erl @@ -1,8 +1,8 @@ -%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
-%%
+%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at @@ -14,46 +14,46 @@ %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. -%%
-%% %CopyrightEnd%
-%%
-
--module(ct_update_config_SUITE).
-
--suite_defaults([{timetrap, {minutes, 10}}]).
-
-%% Note: This directive should only be used in test suites.
--compile(export_all).
-
--include("ct.hrl").
-
--define(now, os:timestamp()).
-
-%% Test server callback functions
-init_per_suite(Config) ->
- [{init_per_suite,?now}|Config].
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_testcase(_TestCase, Config) ->
- [{init_per_testcase,?now}|Config].
-
-end_per_testcase(_TestCase, _Config) ->
- ok.
-
-init_per_group(GroupName, Config) ->
- [{init_per_group,?now}|Config].
-
-end_per_group(GroupName, Config) ->
- ok.
-
-all() ->
- [{group,group1}].
-
-groups() ->
- [{group1,[],[test_case]}].
-
-%% Test cases starts here.
-test_case(Config) when is_list(Config) ->
- ok.
+%% +%% %CopyrightEnd% +%% + +-module(ct_update_config_SUITE). + +-suite_defaults([{timetrap, {minutes, 10}}]). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include("ct.hrl"). + +-define(now, ct_test_support:unique_timestamp()). + +%% Test server callback functions +init_per_suite(Config) -> + [{init_per_suite,?now}|Config]. + +end_per_suite(_Config) -> + ok. + +init_per_testcase(_TestCase, Config) -> + [{init_per_testcase,?now}|Config]. + +end_per_testcase(_TestCase, _Config) -> + ok. + +init_per_group(GroupName, Config) -> + [{init_per_group,?now}|Config]. + +end_per_group(GroupName, Config) -> + ok. + +all() -> + [{group,group1}]. + +groups() -> + [{group1,[],[test_case]}]. + +%% Test cases starts here. +test_case(Config) when is_list(Config) -> + ok. diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl index f223f031d7..8b64ff8060 100644 --- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl +++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl @@ -50,6 +50,8 @@ -export([post_end_per_group/4]). -export([pre_init_per_testcase/3]). +-export([post_init_per_testcase/4]). +-export([pre_end_per_testcase/3]). -export([post_end_per_testcase/4]). -export([on_tc_fail/3]). @@ -88,7 +90,7 @@ id(Opts) -> gen_event:notify(?CT_EVMGR_REF, #event{ name = cth, node = node(), data = {?MODULE, id, [Opts]}}), ct:log("~w:id called", [?MODULE]), - os:timestamp(). + ct_test_support:unique_timestamp(). %% @doc Called before init_per_suite is called. Note that this callback is %% only called if the CTH is added before init_per_suite is run (eg. in a test @@ -208,7 +210,7 @@ post_end_per_group(Group,Config,Return,State) -> ct:log("~w:post_end_per_group(~w) called", [?MODULE,Group]), {Return, State}. -%% @doc Called before each test case. +%% @doc Called before init_per_testcase/2 for each test case. %% You can change the config in this function. -spec pre_init_per_testcase(TC :: atom(), Config :: config(), @@ -222,8 +224,36 @@ pre_init_per_testcase(TC,Config,State) -> ct:log("~w:pre_init_per_testcase(~w) called", [?MODULE,TC]), {Config, State}. -%% @doc Called after each test case. Note that the config cannot be -%% changed here, only the status of the test case. +%% @doc Called after init_per_testcase/2, and before the test case. +-spec post_init_per_testcase(TC :: atom(), + Config :: config(), + Return :: config() | skip_or_fail(), + State :: #state{}) -> + {config() | skip_or_fail(), NewState :: #state{}}. +post_init_per_testcase(TC,Config,Return,State) -> + gen_event:notify( + ?CT_EVMGR_REF, #event{ name = cth, node = node(), + data = {?MODULE, post_init_per_testcase, + [TC,Config,Return,State]}}), + ct:log("~w:post_init_per_testcase(~w) called", [?MODULE,TC]), + {Return, State}. + +%% @doc Called before end_per_testacse/2. No skip or fail allowed here, +%% only config additions. +-spec pre_end_per_testcase(TC :: atom(), + Config :: config(), + State :: #state{}) -> + {config(), NewState :: #state{}}. +pre_end_per_testcase(TC,Config,State) -> + gen_event:notify( + ?CT_EVMGR_REF, #event{ name = cth, node = node(), + data = {?MODULE, pre_end_per_testcase, + [TC,Config,State]}}), + ct:log("~w:pre_end_per_testcase(~w) called", [?MODULE,TC]), + {Config, State}. + +%% @doc Called after end_per_testcase/2 for each test case. Note that +%% the config cannot be changed here, only the status of the test case. -spec post_end_per_testcase(TC :: atom(), Config :: config(), Return :: term(), diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/fail_pre_suite_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/fail_pre_suite_cth.erl index 98e4548864..a79f4d4541 100644 --- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/fail_pre_suite_cth.erl +++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/fail_pre_suite_cth.erl @@ -1,8 +1,8 @@ -%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
-%%
+%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at @@ -14,60 +14,66 @@ %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. -%%
-%% %CopyrightEnd%
-%%
-
-
--module(fail_pre_suite_cth).
-
-
--include_lib("common_test/src/ct_util.hrl").
--include_lib("common_test/include/ct_event.hrl").
-
-
-%% CT Hooks
--compile(export_all).
-
-init(Id, Opts) ->
- empty_cth:init(Id, Opts).
-
-pre_init_per_suite(Suite, Config, State) ->
- empty_cth:pre_init_per_suite(Suite,Config,State),
- {{fail, "Test failure"}, State}.
-
-post_init_per_suite(Suite,Config,Return,State) ->
- empty_cth:post_init_per_suite(Suite,Config,Return,State).
-
-pre_end_per_suite(Suite,Config,State) ->
- empty_cth:pre_end_per_suite(Suite,Config,State).
-
-post_end_per_suite(Suite,Config,Return,State) ->
- empty_cth:post_end_per_suite(Suite,Config,Return,State).
-
-pre_init_per_group(Group,Config,State) ->
- empty_cth:pre_init_per_group(Group,Config,State).
-
-post_init_per_group(Group,Config,Return,State) ->
- empty_cth:post_init_per_group(Group,Config,Return,State).
-
-pre_end_per_group(Group,Config,State) ->
- empty_cth:pre_end_per_group(Group,Config,State).
-
-post_end_per_group(Group,Config,Return,State) ->
- empty_cth:post_end_per_group(Group,Config,Return,State).
-
-pre_init_per_testcase(TC,Config,State) ->
- empty_cth:pre_init_per_testcase(TC,Config,State).
-
-post_end_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_end_per_testcase(TC,Config,Return,State).
-
-on_tc_fail(TC, Reason, State) ->
- empty_cth:on_tc_fail(TC,Reason,State).
-
-on_tc_skip(TC, Reason, State) ->
- empty_cth:on_tc_skip(TC,Reason,State).
-
-terminate(State) ->
- empty_cth:terminate(State).
+%% +%% %CopyrightEnd% +%% + + +-module(fail_pre_suite_cth). + + +-include_lib("common_test/src/ct_util.hrl"). +-include_lib("common_test/include/ct_event.hrl"). + + +%% CT Hooks +-compile(export_all). + +init(Id, Opts) -> + empty_cth:init(Id, Opts). + +pre_init_per_suite(Suite, Config, State) -> + empty_cth:pre_init_per_suite(Suite,Config,State), + {{fail, "Test failure"}, State}. + +post_init_per_suite(Suite,Config,Return,State) -> + empty_cth:post_init_per_suite(Suite,Config,Return,State). + +pre_end_per_suite(Suite,Config,State) -> + empty_cth:pre_end_per_suite(Suite,Config,State). + +post_end_per_suite(Suite,Config,Return,State) -> + empty_cth:post_end_per_suite(Suite,Config,Return,State). + +pre_init_per_group(Group,Config,State) -> + empty_cth:pre_init_per_group(Group,Config,State). + +post_init_per_group(Group,Config,Return,State) -> + empty_cth:post_init_per_group(Group,Config,Return,State). + +pre_end_per_group(Group,Config,State) -> + empty_cth:pre_end_per_group(Group,Config,State). + +post_end_per_group(Group,Config,Return,State) -> + empty_cth:post_end_per_group(Group,Config,Return,State). + +pre_init_per_testcase(TC,Config,State) -> + empty_cth:pre_init_per_testcase(TC,Config,State). + +post_init_per_testcase(TC,Config,Return,State) -> + empty_cth:post_init_per_testcase(TC,Config,Return,State). + +pre_end_per_testcase(TC,Config,State) -> + empty_cth:pre_end_per_testcase(TC,Config,State). + +post_end_per_testcase(TC,Config,Return,State) -> + empty_cth:post_end_per_testcase(TC,Config,Return,State). + +on_tc_fail(TC, Reason, State) -> + empty_cth:on_tc_fail(TC,Reason,State). + +on_tc_skip(TC, Reason, State) -> + empty_cth:on_tc_skip(TC,Reason,State). + +terminate(State) -> + empty_cth:terminate(State). diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/minimal_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/minimal_cth.erl index 8898a54b8d..a084423cf3 100644 --- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/minimal_cth.erl +++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/minimal_cth.erl @@ -1,8 +1,8 @@ -%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
-%%
+%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at @@ -14,21 +14,21 @@ %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. -%%
-%% %CopyrightEnd%
-%%
-
-
--module(minimal_cth).
-
-
--include_lib("common_test/src/ct_util.hrl").
--include_lib("common_test/include/ct_event.hrl").
-
-
-%% CT Hooks
--export([init/2]).
-
-init(Id, Opts) ->
- empty_cth:init(Id, Opts).
-
+%% +%% %CopyrightEnd% +%% + + +-module(minimal_cth). + + +-include_lib("common_test/src/ct_util.hrl"). +-include_lib("common_test/include/ct_event.hrl"). + + +%% CT Hooks +-export([init/2]). + +init(Id, Opts) -> + empty_cth:init(Id, Opts). + diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/minimal_terminate_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/minimal_terminate_cth.erl index 2414da0683..7895c43aeb 100644 --- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/minimal_terminate_cth.erl +++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/minimal_terminate_cth.erl @@ -1,8 +1,8 @@ -%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
-%%
+%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at @@ -14,30 +14,30 @@ %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. -%%
-%% %CopyrightEnd%
-%%
-
-
--module(minimal_terminate_cth).
-
-
--include_lib("common_test/src/ct_util.hrl").
--include_lib("common_test/include/ct_event.hrl").
-
-
-%% CT Hooks
--export([init/2]).
--export([terminate/1]).
--export([on_tc_skip/3]).
-
-init(Id, Opts) ->
- empty_cth:init(Id, Opts).
-
-on_tc_skip(TC, Reason, State) ->
- empty_cth:on_tc_skip(TC,Reason,State).
-
-terminate(State) ->
- empty_cth:terminate(State).
-
-
+%% +%% %CopyrightEnd% +%% + + +-module(minimal_terminate_cth). + + +-include_lib("common_test/src/ct_util.hrl"). +-include_lib("common_test/include/ct_event.hrl"). + + +%% CT Hooks +-export([init/2]). +-export([terminate/1]). +-export([on_tc_skip/3]). + +init(Id, Opts) -> + empty_cth:init(Id, Opts). + +on_tc_skip(TC, Reason, State) -> + empty_cth:on_tc_skip(TC,Reason,State). + +terminate(State) -> + empty_cth:terminate(State). + + diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/prio_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/prio_cth.erl index 0f6ef7c596..72d6d186ed 100644 --- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/prio_cth.erl +++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/prio_cth.erl @@ -1,8 +1,8 @@ -%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
-%%
+%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at @@ -14,62 +14,68 @@ %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. -%%
-%% %CopyrightEnd%
-%%
-
-
--module(prio_cth).
-
-
--include_lib("common_test/src/ct_util.hrl").
-
-
-%% CT Hooks
--compile(export_all).
-
-id(Opts) ->
- empty_cth:id(Opts).
-
-init(Id, Opts) ->
- {ok, [Prio|_] = State} = empty_cth:init(Id, Opts),
- {ok, State, Prio}.
-
-pre_init_per_suite(Suite, Config, State) ->
- empty_cth:pre_init_per_suite(Suite,Config,State).
-
-post_init_per_suite(Suite,Config,Return,State) ->
- empty_cth:post_init_per_suite(Suite,Config,Return,State).
-
-pre_end_per_suite(Suite,Config,State) ->
- empty_cth:pre_end_per_suite(Suite,Config,State).
-
-post_end_per_suite(Suite,Config,Return,State) ->
- empty_cth:post_end_per_suite(Suite,Config,Return,State).
-
-pre_init_per_group(Group,Config,State) ->
- empty_cth:pre_init_per_group(Group,Config,State).
-
-post_init_per_group(Group,Config,Return,State) ->
- empty_cth:post_init_per_group(Group,Config,Return,State).
-
-pre_end_per_group(Group,Config,State) ->
- empty_cth:pre_end_per_group(Group,Config,State).
-
-post_end_per_group(Group,Config,Return,State) ->
- empty_cth:post_end_per_group(Group,Config,Return,State).
-
-pre_init_per_testcase(TC,Config,State) ->
- empty_cth:pre_init_per_testcase(TC,Config,State).
-
-post_end_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_end_per_testcase(TC,Config,Return,State).
-
-on_tc_fail(TC, Reason, State) ->
- empty_cth:on_tc_fail(TC,Reason,State).
-
-on_tc_skip(TC, Reason, State) ->
- empty_cth:on_tc_skip(TC,Reason,State).
-
-terminate(State) ->
- empty_cth:terminate(State).
+%% +%% %CopyrightEnd% +%% + + +-module(prio_cth). + + +-include_lib("common_test/src/ct_util.hrl"). + + +%% CT Hooks +-compile(export_all). + +id(Opts) -> + empty_cth:id(Opts). + +init(Id, Opts) -> + {ok, [Prio|_] = State} = empty_cth:init(Id, Opts), + {ok, State, Prio}. + +pre_init_per_suite(Suite, Config, State) -> + empty_cth:pre_init_per_suite(Suite,Config,State). + +post_init_per_suite(Suite,Config,Return,State) -> + empty_cth:post_init_per_suite(Suite,Config,Return,State). + +pre_end_per_suite(Suite,Config,State) -> + empty_cth:pre_end_per_suite(Suite,Config,State). + +post_end_per_suite(Suite,Config,Return,State) -> + empty_cth:post_end_per_suite(Suite,Config,Return,State). + +pre_init_per_group(Group,Config,State) -> + empty_cth:pre_init_per_group(Group,Config,State). + +post_init_per_group(Group,Config,Return,State) -> + empty_cth:post_init_per_group(Group,Config,Return,State). + +pre_end_per_group(Group,Config,State) -> + empty_cth:pre_end_per_group(Group,Config,State). + +post_end_per_group(Group,Config,Return,State) -> + empty_cth:post_end_per_group(Group,Config,Return,State). + +pre_init_per_testcase(TC,Config,State) -> + empty_cth:pre_init_per_testcase(TC,Config,State). + +post_init_per_testcase(TC,Config,Return,State) -> + empty_cth:post_init_per_testcase(TC,Config,Return,State). + +pre_end_per_testcase(TC,Config,State) -> + empty_cth:pre_end_per_testcase(TC,Config,State). + +post_end_per_testcase(TC,Config,Return,State) -> + empty_cth:post_end_per_testcase(TC,Config,Return,State). + +on_tc_fail(TC, Reason, State) -> + empty_cth:on_tc_fail(TC,Reason,State). + +on_tc_skip(TC, Reason, State) -> + empty_cth:on_tc_skip(TC,Reason,State). + +terminate(State) -> + empty_cth:terminate(State). diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/recover_post_suite_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/recover_post_suite_cth.erl index dfb696bcb9..cf484d3cd7 100644 --- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/recover_post_suite_cth.erl +++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/recover_post_suite_cth.erl @@ -1,8 +1,8 @@ -%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
-%%
+%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at @@ -14,62 +14,68 @@ %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. -%%
-%% %CopyrightEnd%
-%%
-
-
--module(recover_post_suite_cth).
-
-
--include_lib("common_test/src/ct_util.hrl").
--include_lib("common_test/include/ct_event.hrl").
-
-
-%% CT Hooks
--compile(export_all).
-
-init(Id, Opts) ->
- empty_cth:init(Id, Opts).
-
-pre_init_per_suite(Suite, Config, State) ->
- empty_cth:pre_init_per_suite(Suite,Config,State).
-
-post_init_per_suite(Suite,Config,{'EXIT',Reason} = Return,State) ->
- empty_cth:post_init_per_suite(Suite,Config,Return,State),
- {lists:keydelete(tc_status,1,Config),State};
-post_init_per_suite(Suite,Config,Return,State) ->
- empty_cth:post_init_per_suite(Suite,Config,Return,State).
-
-pre_end_per_suite(Suite,Config,State) ->
- empty_cth:pre_end_per_suite(Suite,Config,State).
-
-post_end_per_suite(Suite,Config,Return,State) ->
- empty_cth:post_end_per_suite(Suite,Config,Return,State).
-
-pre_init_per_group(Group,Config,State) ->
- empty_cth:pre_init_per_group(Group,Config,State).
-
-post_init_per_group(Group,Config,Return,State) ->
- empty_cth:post_init_per_group(Group,Config,Return,State).
-
-pre_end_per_group(Group,Config,State) ->
- empty_cth:pre_end_per_group(Group,Config,State).
-
-post_end_per_group(Group,Config,Return,State) ->
- empty_cth:post_end_per_group(Group,Config,Return,State).
-
-pre_init_per_testcase(TC,Config,State) ->
- empty_cth:pre_init_per_testcase(TC,Config,State).
-
-post_end_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_end_per_testcase(TC,Config,Return,State).
-
-on_tc_fail(TC, Reason, State) ->
- empty_cth:on_tc_fail(TC,Reason,State).
-
-on_tc_skip(TC, Reason, State) ->
- empty_cth:on_tc_skip(TC,Reason,State).
-
-terminate(State) ->
- empty_cth:terminate(State).
+%% +%% %CopyrightEnd% +%% + + +-module(recover_post_suite_cth). + + +-include_lib("common_test/src/ct_util.hrl"). +-include_lib("common_test/include/ct_event.hrl"). + + +%% CT Hooks +-compile(export_all). + +init(Id, Opts) -> + empty_cth:init(Id, Opts). + +pre_init_per_suite(Suite, Config, State) -> + empty_cth:pre_init_per_suite(Suite,Config,State). + +post_init_per_suite(Suite,Config,{'EXIT',Reason} = Return,State) -> + empty_cth:post_init_per_suite(Suite,Config,Return,State), + {lists:keydelete(tc_status,1,Config),State}; +post_init_per_suite(Suite,Config,Return,State) -> + empty_cth:post_init_per_suite(Suite,Config,Return,State). + +pre_end_per_suite(Suite,Config,State) -> + empty_cth:pre_end_per_suite(Suite,Config,State). + +post_end_per_suite(Suite,Config,Return,State) -> + empty_cth:post_end_per_suite(Suite,Config,Return,State). + +pre_init_per_group(Group,Config,State) -> + empty_cth:pre_init_per_group(Group,Config,State). + +post_init_per_group(Group,Config,Return,State) -> + empty_cth:post_init_per_group(Group,Config,Return,State). + +pre_end_per_group(Group,Config,State) -> + empty_cth:pre_end_per_group(Group,Config,State). + +post_end_per_group(Group,Config,Return,State) -> + empty_cth:post_end_per_group(Group,Config,Return,State). + +pre_init_per_testcase(TC,Config,State) -> + empty_cth:pre_init_per_testcase(TC,Config,State). + +post_init_per_testcase(TC,Config,Return,State) -> + empty_cth:post_init_per_testcase(TC,Config,Return,State). + +pre_end_per_testcase(TC,Config,State) -> + empty_cth:pre_end_per_testcase(TC,Config,State). + +post_end_per_testcase(TC,Config,Return,State) -> + empty_cth:post_end_per_testcase(TC,Config,Return,State). + +on_tc_fail(TC, Reason, State) -> + empty_cth:on_tc_fail(TC,Reason,State). + +on_tc_skip(TC, Reason, State) -> + empty_cth:on_tc_skip(TC,Reason,State). + +terminate(State) -> + empty_cth:terminate(State). diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/same_id_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/same_id_cth.erl index 50b220d093..60615d97fc 100644 --- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/same_id_cth.erl +++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/same_id_cth.erl @@ -1,8 +1,8 @@ -%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
-%%
+%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at @@ -14,63 +14,69 @@ %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. -%%
-%% %CopyrightEnd%
-%%
-
-
--module(same_id_cth).
-
-
--include_lib("common_test/src/ct_util.hrl").
--include_lib("common_test/include/ct_event.hrl").
-
-
-%% CT Hooks
--compile(export_all).
-
-id(Opts) ->
- empty_cth:id(Opts),
- ?MODULE.
-
-init(Id, Opts) ->
- empty_cth:init(Id, Opts).
-
-pre_init_per_suite(Suite, Config, State) ->
- empty_cth:pre_init_per_suite(Suite,Config,State).
-
-post_init_per_suite(Suite,Config,Return,State) ->
- empty_cth:post_init_per_suite(Suite,Config,Return,State).
-
-pre_end_per_suite(Suite,Config,State) ->
- empty_cth:pre_end_per_suite(Suite,Config,State).
-
-post_end_per_suite(Suite,Config,Return,State) ->
- empty_cth:post_end_per_suite(Suite,Config,Return,State).
-
-pre_init_per_group(Group,Config,State) ->
- empty_cth:pre_init_per_group(Group,Config,State).
-
-post_init_per_group(Group,Config,Return,State) ->
- empty_cth:post_init_per_group(Group,Config,Return,State).
-
-pre_end_per_group(Group,Config,State) ->
- empty_cth:pre_end_per_group(Group,Config,State).
-
-post_end_per_group(Group,Config,Return,State) ->
- empty_cth:post_end_per_group(Group,Config,Return,State).
-
-pre_init_per_testcase(TC,Config,State) ->
- empty_cth:pre_init_per_testcase(TC,Config,State).
-
-post_end_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_end_per_testcase(TC,Config,Return,State).
-
-on_tc_fail(TC, Reason, State) ->
- empty_cth:on_tc_fail(TC,Reason,State).
-
-on_tc_skip(TC, Reason, State) ->
- empty_cth:on_tc_skip(TC,Reason,State).
-
-terminate(State) ->
- empty_cth:terminate(State).
+%% +%% %CopyrightEnd% +%% + + +-module(same_id_cth). + + +-include_lib("common_test/src/ct_util.hrl"). +-include_lib("common_test/include/ct_event.hrl"). + + +%% CT Hooks +-compile(export_all). + +id(Opts) -> + empty_cth:id(Opts), + ?MODULE. + +init(Id, Opts) -> + empty_cth:init(Id, Opts). + +pre_init_per_suite(Suite, Config, State) -> + empty_cth:pre_init_per_suite(Suite,Config,State). + +post_init_per_suite(Suite,Config,Return,State) -> + empty_cth:post_init_per_suite(Suite,Config,Return,State). + +pre_end_per_suite(Suite,Config,State) -> + empty_cth:pre_end_per_suite(Suite,Config,State). + +post_end_per_suite(Suite,Config,Return,State) -> + empty_cth:post_end_per_suite(Suite,Config,Return,State). + +pre_init_per_group(Group,Config,State) -> + empty_cth:pre_init_per_group(Group,Config,State). + +post_init_per_group(Group,Config,Return,State) -> + empty_cth:post_init_per_group(Group,Config,Return,State). + +pre_end_per_group(Group,Config,State) -> + empty_cth:pre_end_per_group(Group,Config,State). + +post_end_per_group(Group,Config,Return,State) -> + empty_cth:post_end_per_group(Group,Config,Return,State). + +pre_init_per_testcase(TC,Config,State) -> + empty_cth:pre_init_per_testcase(TC,Config,State). + +post_init_per_testcase(TC,Config,Return,State) -> + empty_cth:post_init_per_testcase(TC,Config,Return,State). + +pre_end_per_testcase(TC,Config,State) -> + empty_cth:pre_end_per_testcase(TC,Config,State). + +post_end_per_testcase(TC,Config,Return,State) -> + empty_cth:post_end_per_testcase(TC,Config,Return,State). + +on_tc_fail(TC, Reason, State) -> + empty_cth:on_tc_fail(TC,Reason,State). + +on_tc_skip(TC, Reason, State) -> + empty_cth:on_tc_skip(TC,Reason,State). + +terminate(State) -> + empty_cth:terminate(State). diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_post_suite_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_post_suite_cth.erl index d8332f77f6..56163e730c 100644 --- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_post_suite_cth.erl +++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_post_suite_cth.erl @@ -1,8 +1,8 @@ -%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
-%%
+%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at @@ -14,60 +14,66 @@ %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. -%%
-%% %CopyrightEnd%
-%%
-
-
--module(skip_post_suite_cth).
-
-
--include_lib("common_test/src/ct_util.hrl").
--include_lib("common_test/include/ct_event.hrl").
-
-
-%% CT Hooks
--compile(export_all).
-
-init(Id, Opts) ->
- empty_cth:init(Id, Opts).
-
-pre_init_per_suite(Suite, Config, State) ->
- empty_cth:pre_init_per_suite(Suite,Config,State).
-
-post_init_per_suite(Suite,Config,Return,State) ->
- empty_cth:post_init_per_suite(Suite,Config,Return,State),
- {{skip, "Test skip"}, State}.
-
-pre_end_per_suite(Suite,Config,State) ->
- empty_cth:pre_end_per_suite(Suite,Config,State).
-
-post_end_per_suite(Suite,Config,Return,State) ->
- empty_cth:post_end_per_suite(Suite,Config,Return,State).
-
-pre_init_per_group(Group,Config,State) ->
- empty_cth:pre_init_per_group(Group,Config,State).
-
-post_init_per_group(Group,Config,Return,State) ->
- empty_cth:post_init_per_group(Group,Config,Return,State).
-
-pre_end_per_group(Group,Config,State) ->
- empty_cth:pre_end_per_group(Group,Config,State).
-
-post_end_per_group(Group,Config,Return,State) ->
- empty_cth:post_end_per_group(Group,Config,Return,State).
-
-pre_init_per_testcase(TC,Config,State) ->
- empty_cth:pre_init_per_testcase(TC,Config,State).
-
-post_end_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_end_per_testcase(TC,Config,Return,State).
-
-on_tc_fail(TC, Reason, State) ->
- empty_cth:on_tc_fail(TC,Reason,State).
-
-on_tc_skip(TC, Reason, State) ->
- empty_cth:on_tc_skip(TC,Reason,State).
-
-terminate(State) ->
- empty_cth:terminate(State).
+%% +%% %CopyrightEnd% +%% + + +-module(skip_post_suite_cth). + + +-include_lib("common_test/src/ct_util.hrl"). +-include_lib("common_test/include/ct_event.hrl"). + + +%% CT Hooks +-compile(export_all). + +init(Id, Opts) -> + empty_cth:init(Id, Opts). + +pre_init_per_suite(Suite, Config, State) -> + empty_cth:pre_init_per_suite(Suite,Config,State). + +post_init_per_suite(Suite,Config,Return,State) -> + empty_cth:post_init_per_suite(Suite,Config,Return,State), + {{skip, "Test skip"}, State}. + +pre_end_per_suite(Suite,Config,State) -> + empty_cth:pre_end_per_suite(Suite,Config,State). + +post_end_per_suite(Suite,Config,Return,State) -> + empty_cth:post_end_per_suite(Suite,Config,Return,State). + +pre_init_per_group(Group,Config,State) -> + empty_cth:pre_init_per_group(Group,Config,State). + +post_init_per_group(Group,Config,Return,State) -> + empty_cth:post_init_per_group(Group,Config,Return,State). + +pre_end_per_group(Group,Config,State) -> + empty_cth:pre_end_per_group(Group,Config,State). + +post_end_per_group(Group,Config,Return,State) -> + empty_cth:post_end_per_group(Group,Config,Return,State). + +pre_init_per_testcase(TC,Config,State) -> + empty_cth:pre_init_per_testcase(TC,Config,State). + +post_init_per_testcase(TC,Config,Return,State) -> + empty_cth:post_init_per_testcase(TC,Config,Return,State). + +pre_end_per_testcase(TC,Config,State) -> + empty_cth:pre_end_per_testcase(TC,Config,State). + +post_end_per_testcase(TC,Config,Return,State) -> + empty_cth:post_end_per_testcase(TC,Config,Return,State). + +on_tc_fail(TC, Reason, State) -> + empty_cth:on_tc_fail(TC,Reason,State). + +on_tc_skip(TC, Reason, State) -> + empty_cth:on_tc_skip(TC,Reason,State). + +terminate(State) -> + empty_cth:terminate(State). diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_pre_end_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_pre_end_cth.erl index 3c490c9fea..deb622b316 100644 --- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_pre_end_cth.erl +++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_pre_end_cth.erl @@ -1,8 +1,8 @@ -%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
-%%
+%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at @@ -14,62 +14,68 @@ %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. -%%
-%% %CopyrightEnd%
-%%
-
-
--module(skip_pre_end_cth).
-
-
--include_lib("common_test/src/ct_util.hrl").
--include_lib("common_test/include/ct_event.hrl").
-
-
-%% CT Hooks
--compile(export_all).
-
-init(Id, Opts) ->
- empty_cth:init(Id, Opts).
-
-
-pre_init_per_suite(Suite, Config, State) ->
- empty_cth:pre_init_per_suite(Suite,Config,State).
-
-post_init_per_suite(Suite,Config,Return,State) ->
- empty_cth:post_init_per_suite(Suite,Config,Return,State).
-
-pre_end_per_suite(Suite,Config,State) ->
- empty_cth:pre_end_per_suite(Suite,Config,State),
- {{skip, "Test skip"}, State}.
-
-post_end_per_suite(Suite,Config,Return,State) ->
- empty_cth:post_end_per_suite(Suite,Config,Return,State).
-
-pre_init_per_group(Group,Config,State) ->
- empty_cth:pre_init_per_group(Group,Config,State).
-
-post_init_per_group(Group,Config,Return,State) ->
- empty_cth:post_init_per_group(Group,Config,Return,State).
-
-pre_end_per_group(Group,Config,State) ->
- empty_cth:pre_end_per_group(Group,Config,State),
- {{skip, "Test skip"}, State}.
-
-post_end_per_group(Group,Config,Return,State) ->
- empty_cth:post_end_per_group(Group,Config,Return,State).
-
-pre_init_per_testcase(TC,Config,State) ->
- empty_cth:pre_init_per_testcase(TC,Config,State).
-
-post_end_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_end_per_testcase(TC,Config,Return,State).
-
-on_tc_fail(TC, Reason, State) ->
- empty_cth:on_tc_fail(TC,Reason,State).
-
-on_tc_skip(TC, Reason, State) ->
- empty_cth:on_tc_skip(TC,Reason,State).
-
-terminate(State) ->
- empty_cth:terminate(State).
+%% +%% %CopyrightEnd% +%% + + +-module(skip_pre_end_cth). + + +-include_lib("common_test/src/ct_util.hrl"). +-include_lib("common_test/include/ct_event.hrl"). + + +%% CT Hooks +-compile(export_all). + +init(Id, Opts) -> + empty_cth:init(Id, Opts). + + +pre_init_per_suite(Suite, Config, State) -> + empty_cth:pre_init_per_suite(Suite,Config,State). + +post_init_per_suite(Suite,Config,Return,State) -> + empty_cth:post_init_per_suite(Suite,Config,Return,State). + +pre_end_per_suite(Suite,Config,State) -> + empty_cth:pre_end_per_suite(Suite,Config,State), + {{skip, "Test skip"}, State}. + +post_end_per_suite(Suite,Config,Return,State) -> + empty_cth:post_end_per_suite(Suite,Config,Return,State). + +pre_init_per_group(Group,Config,State) -> + empty_cth:pre_init_per_group(Group,Config,State). + +post_init_per_group(Group,Config,Return,State) -> + empty_cth:post_init_per_group(Group,Config,Return,State). + +pre_end_per_group(Group,Config,State) -> + empty_cth:pre_end_per_group(Group,Config,State), + {{skip, "Test skip"}, State}. + +post_end_per_group(Group,Config,Return,State) -> + empty_cth:post_end_per_group(Group,Config,Return,State). + +pre_init_per_testcase(TC,Config,State) -> + empty_cth:pre_init_per_testcase(TC,Config,State). + +post_init_per_testcase(TC,Config,Return,State) -> + empty_cth:post_init_per_testcase(TC,Config,Return,State). + +pre_end_per_testcase(TC,Config,State) -> + empty_cth:pre_end_per_testcase(TC,Config,State). + +post_end_per_testcase(TC,Config,Return,State) -> + empty_cth:post_end_per_testcase(TC,Config,Return,State). + +on_tc_fail(TC, Reason, State) -> + empty_cth:on_tc_fail(TC,Reason,State). + +on_tc_skip(TC, Reason, State) -> + empty_cth:on_tc_skip(TC,Reason,State). + +terminate(State) -> + empty_cth:terminate(State). diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_pre_suite_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_pre_suite_cth.erl index 3ef08ff4e1..ea1d485700 100644 --- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_pre_suite_cth.erl +++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/skip_pre_suite_cth.erl @@ -1,8 +1,8 @@ -%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
-%%
+%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at @@ -14,61 +14,67 @@ %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. -%%
-%% %CopyrightEnd%
-%%
-
-
--module(skip_pre_suite_cth).
-
-
--include_lib("common_test/src/ct_util.hrl").
--include_lib("common_test/include/ct_event.hrl").
-
-
-%% CT Hooks
--compile(export_all).
-
-init(Id, Opts) ->
- empty_cth:init(Id, Opts).
-
-
-pre_init_per_suite(Suite, Config, State) ->
- empty_cth:pre_init_per_suite(Suite,Config,State),
- {{skip, "Test skip"}, State}.
-
-post_init_per_suite(Suite,Config,Return,State) ->
- empty_cth:post_init_per_suite(Suite,Config,Return,State).
-
-pre_end_per_suite(Suite,Config,State) ->
- empty_cth:pre_end_per_suite(Suite,Config,State).
-
-post_end_per_suite(Suite,Config,Return,State) ->
- empty_cth:post_end_per_suite(Suite,Config,Return,State).
-
-pre_init_per_group(Group,Config,State) ->
- empty_cth:pre_init_per_group(Group,Config,State).
-
-post_init_per_group(Group,Config,Return,State) ->
- empty_cth:post_init_per_group(Group,Config,Return,State).
-
-pre_end_per_group(Group,Config,State) ->
- empty_cth:pre_end_per_group(Group,Config,State).
-
-post_end_per_group(Group,Config,Return,State) ->
- empty_cth:post_end_per_group(Group,Config,Return,State).
-
-pre_init_per_testcase(TC,Config,State) ->
- empty_cth:pre_init_per_testcase(TC,Config,State).
-
-post_end_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_end_per_testcase(TC,Config,Return,State).
-
-on_tc_fail(TC, Reason, State) ->
- empty_cth:on_tc_fail(TC,Reason,State).
-
-on_tc_skip(TC, Reason, State) ->
- empty_cth:on_tc_skip(TC,Reason,State).
-
-terminate(State) ->
- empty_cth:terminate(State).
+%% +%% %CopyrightEnd% +%% + + +-module(skip_pre_suite_cth). + + +-include_lib("common_test/src/ct_util.hrl"). +-include_lib("common_test/include/ct_event.hrl"). + + +%% CT Hooks +-compile(export_all). + +init(Id, Opts) -> + empty_cth:init(Id, Opts). + + +pre_init_per_suite(Suite, Config, State) -> + empty_cth:pre_init_per_suite(Suite,Config,State), + {{skip, "Test skip"}, State}. + +post_init_per_suite(Suite,Config,Return,State) -> + empty_cth:post_init_per_suite(Suite,Config,Return,State). + +pre_end_per_suite(Suite,Config,State) -> + empty_cth:pre_end_per_suite(Suite,Config,State). + +post_end_per_suite(Suite,Config,Return,State) -> + empty_cth:post_end_per_suite(Suite,Config,Return,State). + +pre_init_per_group(Group,Config,State) -> + empty_cth:pre_init_per_group(Group,Config,State). + +post_init_per_group(Group,Config,Return,State) -> + empty_cth:post_init_per_group(Group,Config,Return,State). + +pre_end_per_group(Group,Config,State) -> + empty_cth:pre_end_per_group(Group,Config,State). + +post_end_per_group(Group,Config,Return,State) -> + empty_cth:post_end_per_group(Group,Config,Return,State). + +pre_init_per_testcase(TC,Config,State) -> + empty_cth:pre_init_per_testcase(TC,Config,State). + +post_init_per_testcase(TC,Config,Return,State) -> + empty_cth:post_init_per_testcase(TC,Config,Return,State). + +pre_end_per_testcase(TC,Config,State) -> + empty_cth:pre_end_per_testcase(TC,Config,State). + +post_end_per_testcase(TC,Config,Return,State) -> + empty_cth:post_end_per_testcase(TC,Config,Return,State). + +on_tc_fail(TC, Reason, State) -> + empty_cth:on_tc_fail(TC,Reason,State). + +on_tc_skip(TC, Reason, State) -> + empty_cth:on_tc_skip(TC,Reason,State). + +terminate(State) -> + empty_cth:terminate(State). diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/state_update_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/state_update_cth.erl index 338336a140..c2135bbbee 100644 --- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/state_update_cth.erl +++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/state_update_cth.erl @@ -1,8 +1,8 @@ -%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
-%%
+%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at @@ -14,71 +14,79 @@ %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. -%%
-%% %CopyrightEnd%
-%%
-
-
--module(state_update_cth).
-
-
--include_lib("common_test/src/ct_util.hrl").
--include_lib("common_test/include/ct_event.hrl").
-
-%% CT Hooks
--compile(export_all).
-
-init(Id, Opts) ->
- State = empty_cth:init(Id, Opts),
- {ok, [init|State]}.
-
-pre_init_per_suite(Suite, Config, State) ->
- empty_cth:pre_init_per_suite(Suite,Config,State),
- {Config, [pre_init_per_suite|State]}.
-
-post_init_per_suite(Suite,Config,Return,State) ->
- empty_cth:post_init_per_suite(Suite,Config,Return,State),
- {Config, [post_init_per_suite|State]}.
-
-pre_end_per_suite(Suite,Config,State) ->
- empty_cth:pre_end_per_suite(Suite,Config,State),
- {Config, [pre_end_per_suite|State]}.
-
-post_end_per_suite(Suite,Config,Return,State) ->
- empty_cth:post_end_per_suite(Suite,Config,Return,State),
- {Return, [post_end_per_suite|State]}.
-
-pre_init_per_group(Group,Config,State) ->
- empty_cth:pre_init_per_group(Group,Config,State),
- {Config, [pre_init_per_group|State]}.
-
-post_init_per_group(Group,Config,Return,State) ->
- empty_cth:post_init_per_group(Group,Config,Return,State),
- {Return, [post_init_per_group|State]}.
-
-pre_end_per_group(Group,Config,State) ->
- empty_cth:pre_end_per_group(Group,Config,State),
- {Config, [pre_end_per_group|State]}.
-
-post_end_per_group(Group,Config,Return,State) ->
- empty_cth:post_end_per_group(Group,Config,Return,State),
- {Return, [post_end_per_group|State]}.
-
-pre_init_per_testcase(TC,Config,State) ->
- empty_cth:pre_init_per_testcase(TC,Config,State),
- {Config, [pre_init_per_testcase|State]}.
-
-post_end_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_end_per_testcase(TC,Config,Return,State),
- {Return, [post_end_per_testcase|State]}.
-
-on_tc_fail(TC, Reason, State) ->
- empty_cth:on_tc_fail(TC,Reason,State),
- [on_tc_fail|State].
-
-on_tc_skip(TC, Reason, State) ->
- empty_cth:on_tc_skip(TC,Reason,State),
- [on_tc_skip|State].
-
-terminate(State) ->
- empty_cth:terminate(State).
+%% +%% %CopyrightEnd% +%% + + +-module(state_update_cth). + + +-include_lib("common_test/src/ct_util.hrl"). +-include_lib("common_test/include/ct_event.hrl"). + +%% CT Hooks +-compile(export_all). + +init(Id, Opts) -> + State = empty_cth:init(Id, Opts), + {ok, [init|State]}. + +pre_init_per_suite(Suite, Config, State) -> + empty_cth:pre_init_per_suite(Suite,Config,State), + {Config, [pre_init_per_suite|State]}. + +post_init_per_suite(Suite,Config,Return,State) -> + empty_cth:post_init_per_suite(Suite,Config,Return,State), + {Config, [post_init_per_suite|State]}. + +pre_end_per_suite(Suite,Config,State) -> + empty_cth:pre_end_per_suite(Suite,Config,State), + {Config, [pre_end_per_suite|State]}. + +post_end_per_suite(Suite,Config,Return,State) -> + empty_cth:post_end_per_suite(Suite,Config,Return,State), + {Return, [post_end_per_suite|State]}. + +pre_init_per_group(Group,Config,State) -> + empty_cth:pre_init_per_group(Group,Config,State), + {Config, [pre_init_per_group|State]}. + +post_init_per_group(Group,Config,Return,State) -> + empty_cth:post_init_per_group(Group,Config,Return,State), + {Return, [post_init_per_group|State]}. + +pre_end_per_group(Group,Config,State) -> + empty_cth:pre_end_per_group(Group,Config,State), + {Config, [pre_end_per_group|State]}. + +post_end_per_group(Group,Config,Return,State) -> + empty_cth:post_end_per_group(Group,Config,Return,State), + {Return, [post_end_per_group|State]}. + +pre_init_per_testcase(TC,Config,State) -> + empty_cth:pre_init_per_testcase(TC,Config,State), + {Config, [pre_init_per_testcase|State]}. + +post_init_per_testcase(TC,Config,Return,State) -> + empty_cth:post_init_per_testcase(TC,Config,Return,State), + {Return, [post_init_per_testcase|State]}. + +pre_end_per_testcase(TC,Config,State) -> + empty_cth:pre_end_per_testcase(TC,Config,State), + {Config, [pre_end_per_testcase|State]}. + +post_end_per_testcase(TC,Config,Return,State) -> + empty_cth:post_end_per_testcase(TC,Config,Return,State), + {Return, [post_end_per_testcase|State]}. + +on_tc_fail(TC, Reason, State) -> + empty_cth:on_tc_fail(TC,Reason,State), + [on_tc_fail|State]. + +on_tc_skip(TC, Reason, State) -> + empty_cth:on_tc_skip(TC,Reason,State), + [on_tc_skip|State]. + +terminate(State) -> + empty_cth:terminate(State). diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/undef_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/undef_cth.erl index da43d56c12..5ac4bdddf8 100644 --- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/undef_cth.erl +++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/undef_cth.erl @@ -1,8 +1,8 @@ -%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
-%%
+%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at @@ -14,59 +14,65 @@ %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. -%%
-%% %CopyrightEnd%
-%%
-
-
--module(undef_cth).
-
-
--include_lib("common_test/src/ct_util.hrl").
--include_lib("common_test/include/ct_event.hrl").
-
-
-%% CT Hooks
--compile(export_all).
-
-init(Id, Opts) ->
- empty_cth:init(Id, Opts).
-
-pre_init_per_suite(_Suite, _Config, _State) ->
- lists:flaten([1,2,[3,4]]).
-
-post_init_per_suite(Suite,Config,Return,State) ->
- empty_cth:post_init_per_suite(Suite,Config,Return,State).
-
-pre_end_per_suite(Suite,Config,State) ->
- empty_cth:pre_end_per_suite(Suite,Config,State).
-
-post_end_per_suite(Suite,Config,Return,State) ->
- empty_cth:post_end_per_suite(Suite,Config,Return,State).
-
-pre_init_per_group(Group,Config,State) ->
- empty_cth:pre_init_per_group(Group,Config,State).
-
-post_init_per_group(Group,Config,Return,State) ->
- empty_cth:post_init_per_group(Group,Config,Return,State).
-
-pre_end_per_group(Group,Config,State) ->
- empty_cth:pre_end_per_group(Group,Config,State).
-
-post_end_per_group(Group,Config,Return,State) ->
- empty_cth:post_end_per_group(Group,Config,Return,State).
-
-pre_init_per_testcase(TC,Config,State) ->
- empty_cth:pre_init_per_testcase(TC,Config,State).
-
-post_end_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_end_per_testcase(TC,Config,Return,State).
-
-on_tc_fail(TC, Reason, State) ->
- empty_cth:on_tc_fail(TC,Reason,State).
-
-on_tc_skip(TC, Reason, State) ->
- empty_cth:on_tc_skip(TC,Reason,State).
-
-terminate(State) ->
- empty_cth:terminate(State).
+%% +%% %CopyrightEnd% +%% + + +-module(undef_cth). + + +-include_lib("common_test/src/ct_util.hrl"). +-include_lib("common_test/include/ct_event.hrl"). + + +%% CT Hooks +-compile(export_all). + +init(Id, Opts) -> + empty_cth:init(Id, Opts). + +pre_init_per_suite(_Suite, _Config, _State) -> + lists:flaten([1,2,[3,4]]). + +post_init_per_suite(Suite,Config,Return,State) -> + empty_cth:post_init_per_suite(Suite,Config,Return,State). + +pre_end_per_suite(Suite,Config,State) -> + empty_cth:pre_end_per_suite(Suite,Config,State). + +post_end_per_suite(Suite,Config,Return,State) -> + empty_cth:post_end_per_suite(Suite,Config,Return,State). + +pre_init_per_group(Group,Config,State) -> + empty_cth:pre_init_per_group(Group,Config,State). + +post_init_per_group(Group,Config,Return,State) -> + empty_cth:post_init_per_group(Group,Config,Return,State). + +pre_end_per_group(Group,Config,State) -> + empty_cth:pre_end_per_group(Group,Config,State). + +post_end_per_group(Group,Config,Return,State) -> + empty_cth:post_end_per_group(Group,Config,Return,State). + +pre_init_per_testcase(TC,Config,State) -> + empty_cth:pre_init_per_testcase(TC,Config,State). + +post_init_per_testcase(TC,Config,Return,State) -> + empty_cth:post_init_per_testcase(TC,Config,Return,State). + +pre_end_per_testcase(TC,Config,State) -> + empty_cth:pre_end_per_testcase(TC,Config,State). + +post_end_per_testcase(TC,Config,Return,State) -> + empty_cth:post_end_per_testcase(TC,Config,Return,State). + +on_tc_fail(TC, Reason, State) -> + empty_cth:on_tc_fail(TC,Reason,State). + +on_tc_skip(TC, Reason, State) -> + empty_cth:on_tc_skip(TC,Reason,State). + +terminate(State) -> + empty_cth:terminate(State). diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/update_config_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/update_config_cth.erl index 0202201eed..928bedfed1 100644 --- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/update_config_cth.erl +++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/update_config_cth.erl @@ -1,8 +1,8 @@ -%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
-%%
+%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at @@ -14,71 +14,79 @@ %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. -%%
-%% %CopyrightEnd%
-%%
-
-
--module(update_config_cth).
-
-
--include_lib("common_test/src/ct_util.hrl").
--include_lib("common_test/include/ct_event.hrl").
-
--define(now, os:timestamp()).
-
-%% CT Hooks
--compile(export_all).
-
-init(Id, Opts) ->
- empty_cth:init(Id, Opts).
-
-pre_init_per_suite(Suite, Config, State) ->
- empty_cth:pre_init_per_suite(Suite,Config,State),
- {[{pre_init_per_suite,?now}|Config],State}.
-
-post_init_per_suite(Suite,Config,Return,State) ->
- empty_cth:post_init_per_suite(Suite,Config,Return,State),
- {[{post_init_per_suite,?now}|Return],State}.
-
-pre_end_per_suite(Suite,Config,State) ->
- empty_cth:pre_end_per_suite(Suite,Config,State),
- {[{pre_end_per_suite,?now}|Config],State}.
-
-post_end_per_suite(Suite,Config,Return,State) ->
- empty_cth:post_end_per_suite(Suite,Config,Return,State),
- NewConfig = [{post_end_per_suite,?now}|Config],
- {NewConfig,NewConfig}.
-
-pre_init_per_group(Group,Config,State) ->
- empty_cth:pre_init_per_group(Group,Config,State),
- {[{pre_init_per_group,?now}|Config],State}.
-
-post_init_per_group(Group,Config,Return,State) ->
- empty_cth:post_init_per_group(Group,Config,Return,State),
- {[{post_init_per_group,?now}|Return],State}.
-
-pre_end_per_group(Group,Config,State) ->
- empty_cth:pre_end_per_group(Group,Config,State),
- {[{pre_end_per_group,?now}|Config],State}.
-
-post_end_per_group(Group,Config,Return,State) ->
- empty_cth:post_end_per_group(Group,Config,Return,State),
- {[{post_end_per_group,?now}|Config],State}.
-
-pre_init_per_testcase(TC,Config,State) ->
- empty_cth:pre_init_per_testcase(TC,Config,State),
- {[{pre_init_per_testcase,?now}|Config],State}.
-
-post_end_per_testcase(TC,Config,Return,State) ->
- empty_cth:post_end_per_testcase(TC,Config,Return,State),
- {[{post_end_per_testcase,?now}|Config],State}.
-
-on_tc_fail(TC, Reason, State) ->
- empty_cth:on_tc_fail(TC,Reason,State).
-
-on_tc_skip(TC, Reason, State) ->
- empty_cth:on_tc_skip(TC,Reason,State).
-
-terminate(State) ->
- empty_cth:terminate(State).
+%% +%% %CopyrightEnd% +%% + + +-module(update_config_cth). + + +-include_lib("common_test/src/ct_util.hrl"). +-include_lib("common_test/include/ct_event.hrl"). + +-define(now, ct_test_support:unique_timestamp()). + +%% CT Hooks +-compile(export_all). + +init(Id, Opts) -> + empty_cth:init(Id, Opts). + +pre_init_per_suite(Suite, Config, State) -> + empty_cth:pre_init_per_suite(Suite,Config,State), + {[{pre_init_per_suite,?now}|Config],State}. + +post_init_per_suite(Suite,Config,Return,State) -> + empty_cth:post_init_per_suite(Suite,Config,Return,State), + {[{post_init_per_suite,?now}|Return],State}. + +pre_end_per_suite(Suite,Config,State) -> + empty_cth:pre_end_per_suite(Suite,Config,State), + {[{pre_end_per_suite,?now}|Config],State}. + +post_end_per_suite(Suite,Config,Return,State) -> + empty_cth:post_end_per_suite(Suite,Config,Return,State), + NewConfig = [{post_end_per_suite,?now}|Config], + {NewConfig,NewConfig}. + +pre_init_per_group(Group,Config,State) -> + empty_cth:pre_init_per_group(Group,Config,State), + {[{pre_init_per_group,?now}|Config],State}. + +post_init_per_group(Group,Config,Return,State) -> + empty_cth:post_init_per_group(Group,Config,Return,State), + {[{post_init_per_group,?now}|Return],State}. + +pre_end_per_group(Group,Config,State) -> + empty_cth:pre_end_per_group(Group,Config,State), + {[{pre_end_per_group,?now}|Config],State}. + +post_end_per_group(Group,Config,Return,State) -> + empty_cth:post_end_per_group(Group,Config,Return,State), + {[{post_end_per_group,?now}|Config],State}. + +pre_init_per_testcase(TC,Config,State) -> + empty_cth:pre_init_per_testcase(TC,Config,State), + {[{pre_init_per_testcase,?now}|Config],State}. + +post_init_per_testcase(TC,Config,Return,State) -> + empty_cth:post_init_per_testcase(TC,Config,Return,State), + {[{post_init_per_testcase,?now}|Config],State}. + +pre_end_per_testcase(TC,Config,State) -> + empty_cth:pre_end_per_testcase(TC,Config,State), + {[{pre_end_per_testcase,?now}|Config],State}. + +post_end_per_testcase(TC,Config,Return,State) -> + empty_cth:post_end_per_testcase(TC,Config,Return,State), + {[{post_end_per_testcase,?now}|Config],State}. + +on_tc_fail(TC, Reason, State) -> + empty_cth:on_tc_fail(TC,Reason,State). + +on_tc_skip(TC, Reason, State) -> + empty_cth:on_tc_skip(TC,Reason,State). + +terminate(State) -> + empty_cth:terminate(State). diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/verify_config_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/verify_config_cth.erl index 754163abae..1df212f266 100644 --- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/verify_config_cth.erl +++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/verify_config_cth.erl @@ -1,8 +1,8 @@ -%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2010-2012. All Rights Reserved.
-%%
+%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2012. All Rights Reserved. +%% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at @@ -14,118 +14,126 @@ %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. -%%
-%% %CopyrightEnd%
-%%
-
--module(verify_config_cth).
-
--include_lib("common_test/src/ct_util.hrl").
-
-%% CT Hooks
--compile(export_all).
-
--define(val(K, L), proplists:get_value(K, L)).
-
-id(Opts) ->
- ?MODULE.
-
-init(Id, Opts) ->
- {ok, State} = empty_cth:init(Id, Opts),
- {ok, State}.
-
-pre_init_per_suite(Suite, Config, State) ->
- ct_no_config_SUITE = ct:get_config(suite_cfg),
- empty_cth:pre_init_per_suite(Suite,
- [{pre_init_per_suite,true} | Config],
- State).
-
-post_init_per_suite(Suite,Config,Return,State) ->
- true = ?val(pre_init_per_suite, Return),
- ct_no_config_SUITE = ct:get_config(suite_cfg),
- empty_cth:post_init_per_suite(Suite,
- Config,
- [{post_init_per_suite,true} | Return],
- State).
-
-pre_end_per_suite(Suite,Config,State) ->
- true = ?val(post_init_per_suite, Config),
- ct_no_config_SUITE = ct:get_config(suite_cfg),
- empty_cth:pre_end_per_suite(Suite,
- [{pre_end_per_suite,true} | Config],
- State).
-
-post_end_per_suite(Suite,Config,Return,State) ->
- true = ?val(pre_end_per_suite, Config),
- ct_no_config_SUITE = ct:get_config(suite_cfg),
- empty_cth:post_end_per_suite(Suite,Config,Return,State).
-
-pre_init_per_group(Group,Config,State) ->
- true = ?val(post_init_per_suite, Config),
- ct_no_config_SUITE = ct:get_config(suite_cfg),
- test_group = ct:get_config(group_cfg),
- empty_cth:pre_init_per_group(Group,
- [{pre_init_per_group,true} | Config],
- State).
-
-post_init_per_group(Group,Config,Return,State) ->
- true = ?val(pre_init_per_group, Return),
- test_group = ct:get_config(group_cfg),
- empty_cth:post_init_per_group(Group,
- Config,
- [{post_init_per_group,true} | Return],
- State).
-
-pre_end_per_group(Group,Config,State) ->
- true = ?val(post_init_per_group, Config),
- ct_no_config_SUITE = ct:get_config(suite_cfg),
- test_group = ct:get_config(group_cfg),
- empty_cth:pre_end_per_group(Group,
- [{pre_end_per_group,true} | Config],
- State).
-
-post_end_per_group(Group,Config,Return,State) ->
- true = ?val(pre_end_per_group, Config),
- ct_no_config_SUITE = ct:get_config(suite_cfg),
- test_group = ct:get_config(group_cfg),
- empty_cth:post_end_per_group(Group,Config,Return,State).
-
-pre_init_per_testcase(TC,Config,State) ->
- true = ?val(post_init_per_suite, Config),
- case ?val(name, ?val(tc_group_properties, Config)) of
- undefined ->
- ok;
- _ ->
- true = ?val(post_init_per_group, Config),
- test_group = ct:get_config(group_cfg)
- end,
- ct_no_config_SUITE = ct:get_config(suite_cfg),
- CfgKey = list_to_atom(atom_to_list(TC) ++ "_cfg"),
- TC = ct:get_config(CfgKey),
- empty_cth:pre_init_per_testcase(TC,
- [{pre_init_per_testcase,true} | Config],
- State).
-
-post_end_per_testcase(TC,Config,Return,State) ->
- true = ?val(post_init_per_suite, Config),
- true = ?val(pre_init_per_testcase, Config),
- case ?val(name, ?val(tc_group_properties, Config)) of
- undefined ->
- ok;
- _ ->
- true = ?val(post_init_per_group, Config),
- test_group = ct:get_config(group_cfg)
- end,
- ct_no_config_SUITE = ct:get_config(suite_cfg),
- CfgKey = list_to_atom(atom_to_list(TC) ++ "_cfg"),
- TC = ct:get_config(CfgKey),
- empty_cth:post_end_per_testcase(TC,Config,Return,State).
-
-on_tc_fail(TC, Reason, State) ->
- empty_cth:on_tc_fail(TC,Reason,State).
-
-on_tc_skip(TC, Reason, State) ->
- empty_cth:on_tc_skip(TC,Reason,State).
-
-terminate(State) ->
- empty_cth:terminate(State).
+%% +%% %CopyrightEnd% +%% + +-module(verify_config_cth). + +-include_lib("common_test/src/ct_util.hrl"). + +%% CT Hooks +-compile(export_all). + +-define(val(K, L), proplists:get_value(K, L)). + +id(Opts) -> + ?MODULE. + +init(Id, Opts) -> + {ok, State} = empty_cth:init(Id, Opts), + {ok, State}. + +pre_init_per_suite(Suite, Config, State) -> + ct_no_config_SUITE = ct:get_config(suite_cfg), + empty_cth:pre_init_per_suite(Suite, + [{pre_init_per_suite,true} | Config], + State). + +post_init_per_suite(Suite,Config,Return,State) -> + true = ?val(pre_init_per_suite, Return), + ct_no_config_SUITE = ct:get_config(suite_cfg), + empty_cth:post_init_per_suite(Suite, + Config, + [{post_init_per_suite,true} | Return], + State). + +pre_end_per_suite(Suite,Config,State) -> + true = ?val(post_init_per_suite, Config), + ct_no_config_SUITE = ct:get_config(suite_cfg), + empty_cth:pre_end_per_suite(Suite, + [{pre_end_per_suite,true} | Config], + State). + +post_end_per_suite(Suite,Config,Return,State) -> + true = ?val(pre_end_per_suite, Config), + ct_no_config_SUITE = ct:get_config(suite_cfg), + empty_cth:post_end_per_suite(Suite,Config,Return,State). + +pre_init_per_group(Group,Config,State) -> + true = ?val(post_init_per_suite, Config), + ct_no_config_SUITE = ct:get_config(suite_cfg), + test_group = ct:get_config(group_cfg), + empty_cth:pre_init_per_group(Group, + [{pre_init_per_group,true} | Config], + State). + +post_init_per_group(Group,Config,Return,State) -> + true = ?val(pre_init_per_group, Return), + test_group = ct:get_config(group_cfg), + empty_cth:post_init_per_group(Group, + Config, + [{post_init_per_group,true} | Return], + State). + +pre_end_per_group(Group,Config,State) -> + true = ?val(post_init_per_group, Config), + ct_no_config_SUITE = ct:get_config(suite_cfg), + test_group = ct:get_config(group_cfg), + empty_cth:pre_end_per_group(Group, + [{pre_end_per_group,true} | Config], + State). + +post_end_per_group(Group,Config,Return,State) -> + true = ?val(pre_end_per_group, Config), + ct_no_config_SUITE = ct:get_config(suite_cfg), + test_group = ct:get_config(group_cfg), + empty_cth:post_end_per_group(Group,Config,Return,State). + +pre_init_per_testcase(TC,Config,State) -> + true = ?val(post_init_per_suite, Config), + case ?val(name, ?val(tc_group_properties, Config)) of + undefined -> + ok; + _ -> + true = ?val(post_init_per_group, Config), + test_group = ct:get_config(group_cfg) + end, + ct_no_config_SUITE = ct:get_config(suite_cfg), + CfgKey = list_to_atom(atom_to_list(TC) ++ "_cfg"), + TC = ct:get_config(CfgKey), + empty_cth:pre_init_per_testcase(TC, + [{pre_init_per_testcase,true} | Config], + State). + +%%! TODO: Verify Config also in post_init and pre_end! + +post_init_per_testcase(TC,Config,Return,State) -> + empty_cth:post_init_per_testcase(TC,Config,Return,State). + +pre_end_per_testcase(TC,Config,State) -> + empty_cth:pre_end_per_testcase(TC,Config,State). + +post_end_per_testcase(TC,Config,Return,State) -> + true = ?val(post_init_per_suite, Config), + true = ?val(pre_init_per_testcase, Config), + case ?val(name, ?val(tc_group_properties, Config)) of + undefined -> + ok; + _ -> + true = ?val(post_init_per_group, Config), + test_group = ct:get_config(group_cfg) + end, + ct_no_config_SUITE = ct:get_config(suite_cfg), + CfgKey = list_to_atom(atom_to_list(TC) ++ "_cfg"), + TC = ct:get_config(CfgKey), + empty_cth:post_end_per_testcase(TC,Config,Return,State). + +on_tc_fail(TC, Reason, State) -> + empty_cth:on_tc_fail(TC,Reason,State). + +on_tc_skip(TC, Reason, State) -> + empty_cth:on_tc_skip(TC,Reason,State). + +terminate(State) -> + empty_cth:terminate(State). diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/verify_data_dir_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/verify_data_dir_cth.erl index 2c8f7a50aa..7abcea4393 100644 --- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/verify_data_dir_cth.erl +++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/verify_data_dir_cth.erl @@ -1,8 +1,8 @@ -%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2010-2012. All Rights Reserved.
-%%
+%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2012. All Rights Reserved. +%% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at @@ -14,83 +14,91 @@ %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. -%%
-%% %CopyrightEnd%
-%%
-
--module(verify_data_dir_cth).
-
--include_lib("common_test/src/ct_util.hrl").
-
-%% CT Hooks
--compile(export_all).
-
--define(val(K, L), proplists:get_value(K, L)).
-
-check_dirs(State,Config) ->
- DataDirName = ?val(data_dir_name, State),
- %% check priv_dir
- PrivDir = proplists:get_value(priv_dir, Config),
- "log_private" = filename:basename(PrivDir),
- {ok,_} = file:list_dir(PrivDir),
-
- %% check data_dir
- DataDir = proplists:get_value(data_dir, Config),
- DataDirName = filename:basename(DataDir),
- ok.
-
-id(_Opts) ->
- ?MODULE.
-
-init(Id, _Opts) ->
- {ok, _State} = empty_cth:init(Id, []),
- {ok, [{data_dir_name,"ct_data_dir_SUITE_data"}]}.
-
-pre_init_per_suite(Suite,Config,State) ->
- check_dirs(State,Config),
- empty_cth:pre_init_per_suite(Suite,Config,State).
-
-post_init_per_suite(Suite,Config,Return,State) ->
- check_dirs(State,Return),
- empty_cth:post_init_per_suite(Suite,Config,Return,State).
-
-pre_end_per_suite(Suite,Config,State) ->
- check_dirs(State,Config),
- empty_cth:pre_end_per_suite(Suite,Config,State).
-
-post_end_per_suite(Suite,Config,Return,State) ->
- check_dirs(State,Config),
- empty_cth:post_end_per_suite(Suite,Config,Return,State).
-
-pre_init_per_group(Group,Config,State) ->
- check_dirs(State,Config),
- empty_cth:pre_init_per_group(Group,Config,State).
-
-post_init_per_group(Group,Config,Return,State) ->
- check_dirs(State,Return),
- empty_cth:post_init_per_group(Group,Config,Return,State).
-
-pre_end_per_group(Group,Config,State) ->
- check_dirs(State,Config),
- empty_cth:pre_end_per_group(Group,Config,State).
-
-post_end_per_group(Group,Config,Return,State) ->
- check_dirs(State,Config),
- empty_cth:post_end_per_group(Group,Config,Return,State).
-
-pre_init_per_testcase(TC,Config,State) ->
- check_dirs(State,Config),
- empty_cth:pre_init_per_testcase(TC,Config,State).
-
-post_end_per_testcase(TC,Config,Return,State) ->
- check_dirs(State,Config),
- empty_cth:post_end_per_testcase(TC,Config,Return,State).
-
-on_tc_fail(TC, Reason, State) ->
- empty_cth:on_tc_fail(TC,Reason,State).
-
-on_tc_skip(TC, Reason, State) ->
- empty_cth:on_tc_skip(TC,Reason,State).
-
-terminate(State) ->
- empty_cth:terminate(State).
+%% +%% %CopyrightEnd% +%% + +-module(verify_data_dir_cth). + +-include_lib("common_test/src/ct_util.hrl"). + +%% CT Hooks +-compile(export_all). + +-define(val(K, L), proplists:get_value(K, L)). + +check_dirs(State,Config) -> + DataDirName = ?val(data_dir_name, State), + %% check priv_dir + PrivDir = proplists:get_value(priv_dir, Config), + "log_private" = filename:basename(PrivDir), + {ok,_} = file:list_dir(PrivDir), + + %% check data_dir + DataDir = proplists:get_value(data_dir, Config), + DataDirName = filename:basename(DataDir), + ok. + +id(_Opts) -> + ?MODULE. + +init(Id, _Opts) -> + {ok, _State} = empty_cth:init(Id, []), + {ok, [{data_dir_name,"ct_data_dir_SUITE_data"}]}. + +pre_init_per_suite(Suite,Config,State) -> + check_dirs(State,Config), + empty_cth:pre_init_per_suite(Suite,Config,State). + +post_init_per_suite(Suite,Config,Return,State) -> + check_dirs(State,Return), + empty_cth:post_init_per_suite(Suite,Config,Return,State). + +pre_end_per_suite(Suite,Config,State) -> + check_dirs(State,Config), + empty_cth:pre_end_per_suite(Suite,Config,State). + +post_end_per_suite(Suite,Config,Return,State) -> + check_dirs(State,Config), + empty_cth:post_end_per_suite(Suite,Config,Return,State). + +pre_init_per_group(Group,Config,State) -> + check_dirs(State,Config), + empty_cth:pre_init_per_group(Group,Config,State). + +post_init_per_group(Group,Config,Return,State) -> + check_dirs(State,Return), + empty_cth:post_init_per_group(Group,Config,Return,State). + +pre_end_per_group(Group,Config,State) -> + check_dirs(State,Config), + empty_cth:pre_end_per_group(Group,Config,State). + +post_end_per_group(Group,Config,Return,State) -> + check_dirs(State,Config), + empty_cth:post_end_per_group(Group,Config,Return,State). + +pre_init_per_testcase(TC,Config,State) -> + check_dirs(State,Config), + empty_cth:pre_init_per_testcase(TC,Config,State). + +post_init_per_testcase(TC,Config,Return,State) -> + check_dirs(State,Config), + empty_cth:post_init_per_testcase(TC,Config,Return,State). + +pre_end_per_testcase(TC,Config,State) -> + check_dirs(State,Config), + empty_cth:pre_end_per_testcase(TC,Config,State). + +post_end_per_testcase(TC,Config,Return,State) -> + check_dirs(State,Config), + empty_cth:post_end_per_testcase(TC,Config,Return,State). + +on_tc_fail(TC, Reason, State) -> + empty_cth:on_tc_fail(TC,Reason,State). + +on_tc_skip(TC, Reason, State) -> + empty_cth:on_tc_skip(TC,Reason,State). + +terminate(State) -> + empty_cth:terminate(State). diff --git a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl index 64ebfbc463..9d4c798795 100644 --- a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl +++ b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl @@ -36,7 +36,8 @@ -compile(export_all). suite() -> - [{ct_hooks, [{cth_conn_log, + [{timetrap,?default_timeout}, + {ct_hooks, [{cth_conn_log, [{ct_netconfc,[{log_type,html}, %will be overwritten by config {hosts,[my_named_connection,netconf1]}] }] @@ -72,7 +73,9 @@ all() -> invalid_opt, timeout_close_session, get, + get_a_lot, timeout_get, + flush_timeout_get, get_xpath, get_config, get_config_xpath, @@ -96,7 +99,10 @@ all() -> connection_crash, get_event_streams, create_subscription, - receive_event + receive_one_event, + receive_multiple_events, + receive_event_and_rpc, + receive_event_and_rpc_in_chunks ] end. @@ -112,12 +118,9 @@ end_per_group(_GroupName, Config) -> init_per_testcase(_Case, Config) -> ets:delete_all_objects(ns_tab), - Dog = test_server:timetrap(?default_timeout), - [{watchdog, Dog}|Config]. + Config. -end_per_testcase(_Case, Config) -> - Dog=?config(watchdog, Config), - test_server:timetrap_cancel(Dog), +end_per_testcase(_Case, _Config) -> ok. init_per_suite(Config) -> @@ -329,7 +332,8 @@ invalid_opt(Config) -> Opts1 = ?DEFAULT_SSH_OPTS(DataDir) ++ [{timeout,invalidvalue}], {error,{invalid_option,{timeout,invalidvalue}}} = ct_netconfc:open(Opts1), Opts2 = ?DEFAULT_SSH_OPTS(DataDir) ++ [{some_other_opt,true}], - {error,{invalid_option,{some_other_opt,true}}} = ct_netconfc:open(Opts2), + {error,{ssh,could_not_connect_to_server,{options,_}}} = + ct_netconfc:open(Opts2), ok. timeout_close_session(Config) -> @@ -351,6 +355,19 @@ get(Config) -> ?ok = ct_netconfc:close_session(Client), ok. +get_a_lot(Config) -> + DataDir = ?config(data_dir,Config), + {ok,Client} = open_success(DataDir), + Descr = lists:append(lists:duplicate(1000,"Description of myserver! ")), + Server = {server,[{xmlns,"myns"}],[{name,[],["myserver"]}, + {description,[],[Descr]}]}, + Data = lists:duplicate(100,Server), + ?NS:expect_reply('get',{fragmented,{data,Data}}), + {ok,Data} = ct_netconfc:get(Client,{server,[{xmlns,"myns"}],[]}), + ?NS:expect_do_reply('close-session',close,ok), + ?ok = ct_netconfc:close_session(Client), + ok. + timeout_get(Config) -> DataDir = ?config(data_dir,Config), {ok,Client} = open_success(DataDir), @@ -360,6 +377,28 @@ timeout_get(Config) -> ?ok = ct_netconfc:close_session(Client), ok. +%% Test OTP-13008 "ct_netconfc crash when receiving unknown timeout" +%% If the timer expires "at the same time" as the rpc reply is +%% received, the timeout message might already be sent when the timer +%% is cancelled. This test checks that the timeout message is flushed +%% from the message queue. If it isn't, the client crashes and the +%% session can not be closed afterwards. +%% Note that we can only hope that the test case triggers the problem +%% every now and then, as it is very timing dependent... +flush_timeout_get(Config) -> + DataDir = ?config(data_dir,Config), + {ok,Client} = open_success(DataDir), + Data = [{server,[{xmlns,"myns"}],[{name,[],["myserver"]}]}], + ?NS:expect_reply('get',{data,Data}), + timer:sleep(1000), + case ct_netconfc:get(Client,{server,[{xmlns,"myns"}],[]},1) of + {error,timeout} -> ok; % problem not triggered + {ok,Data} -> ok % problem possibly triggered + end, + ?NS:expect_do_reply('close-session',close,ok), + ?ok = ct_netconfc:close_session(Client), + ok. + get_xpath(Config) -> DataDir = ?config(data_dir,Config), {ok,Client} = open_success(DataDir), @@ -929,16 +968,16 @@ create_subscription(Config) -> ok. -receive_event(Config) -> +receive_one_event(Config) -> DataDir = ?config(data_dir,Config), {ok,Client} = open_success(DataDir), ?NS:expect_reply({'create-subscription',[stream]},ok), ?ok = ct_netconfc:create_subscription(Client), - ?NS:hupp(send_event), + ?NS:hupp({send_events,1}), receive - %% Matching ?NS:make_msg(event) + %% Matching ?NS:make_msg({event,_}) {notification,?NETCONF_NOTIF_NAMESPACE_ATTR, [{eventTime,[],[_Time]}, {event,[{xmlns,"http://my.namespaces.com/event"}], @@ -956,6 +995,187 @@ receive_event(Config) -> ok. +receive_multiple_events(Config) -> + DataDir = ?config(data_dir,Config), + {ok,Client} = open_success(DataDir), + ?NS:expect_reply({'create-subscription',[stream]},ok), + ?ok = ct_netconfc:create_subscription(Client), + + ?NS:hupp({send_events,3}), + + receive + %% Matching ?NS:make_msg({event,_}) + {notification,_,_} -> + ok; + Other1 -> + ct:fail({got_unexpected_while_waiting_for_event, Other1}) + after 3000 -> + ct:fail(timeout_waiting_for_event) + end, + receive + %% Matching ?NS:make_msg({event,_}) + {notification,_,_} -> + ok; + Other2 -> + ct:fail({got_unexpected_while_waiting_for_event, Other2}) + after 3000 -> + ct:fail(timeout_waiting_for_event) + end, + receive + %% Matching ?NS:make_msg({event,_}) + {notification,_,_} -> + ok; + Other3 -> + ct:fail({got_unexpected_while_waiting_for_event, Other3}) + after 3000 -> + ct:fail(timeout_waiting_for_event) + end, + + ?NS:expect_do_reply('close-session',close,ok), + ?ok = ct_netconfc:close_session(Client), + + ok. + +receive_event_and_rpc(Config) -> + DataDir = ?config(data_dir,Config), + {ok,Client} = open_success(DataDir), + + ?NS:expect_reply({'create-subscription',[stream]},ok), + ?ok = ct_netconfc:create_subscription(Client), + + %% Construct the data to return from netconf server - one + %% rpc-reply and one notification - to be sent in the same ssh + %% package. + Data = [{servers,[{xmlns,"myns"}],[{server,[],[{name,[],["myserver"]}]}]}], + Rpc = {'rpc-reply',?NETCONF_NAMESPACE_ATTR ++ [{'message-id',"2"}], + [{data,Data}]}, + RpcXml = list_to_binary(xmerl:export_simple_element(Rpc,xmerl_xml)), + + Notification = + {notification,?NETCONF_NOTIF_NAMESPACE_ATTR, + [{eventTime,["2012-06-14T14:50:54+02:00"]}, + {event,[{xmlns,"http://my.namespaces.com/event"}], + [{severity,["major"]}, + {description,["Something terrible happened"]}]}]}, + NotifXml = + list_to_binary(xmerl:export_simple_element(Notification,xmerl_xml)), + + ?NS:expect_reply('get',[RpcXml,NotifXml]), + {ok,Data} = ct_netconfc:get(Client,{server,[{xmlns,"myns"}],[]}), + + receive + {notification,_,_} -> + ok; + Other1 -> + ct:fail({got_unexpected_while_waiting_for_event, Other1}) + after 3000 -> + ct:fail(timeout_waiting_for_event) + end, + + + %% Then do the same again, but now send notification first then + %% the rpc-reply. + Rpc2 = {'rpc-reply',?NETCONF_NAMESPACE_ATTR ++ [{'message-id',"3"}], + [{data,Data}]}, + RpcXml2 = list_to_binary(xmerl:export_simple_element(Rpc2,xmerl_xml)), + ?NS:expect_reply('get',[NotifXml,RpcXml2]), + {ok,Data} = ct_netconfc:get(Client,{server,[{xmlns,"myns"}],[]}), + + receive + {notification,_,_} -> + ok; + Other2 -> + ct:fail({got_unexpected_while_waiting_for_event, Other2}) + after 3000 -> + ct:fail(timeout_waiting_for_event) + end, + + ?NS:expect_do_reply('close-session',close,ok), + ?ok = ct_netconfc:close_session(Client), + + ok. + + +receive_event_and_rpc_in_chunks(Config) -> + DataDir = ?config(data_dir,Config), + {ok,Client} = open_success(DataDir), + + ?NS:expect_reply({'create-subscription',[stream]},ok), + ?ok = ct_netconfc:create_subscription(Client), + + %% Construct the data to return from netconf server + Data = [{servers,[{xmlns,"myns"}], + [{server,[],[{name,[],["server0"]}]}, + {server,[],[{name,[],["server1"]}]}, + {server,[],[{name,[],["server2"]}]}, + {server,[],[{name,[],["server3"]}]}, + {server,[],[{name,[],["server4"]}]}, + {server,[],[{name,[],["server5"]}]}, + {server,[],[{name,[],["server6"]}]}, + {server,[],[{name,[],["server7"]}]}, + {server,[],[{name,[],["server8"]}]}, + {server,[],[{name,[],["server9"]}]}] + }], + Rpc = {'rpc-reply',?NETCONF_NAMESPACE_ATTR ++ [{'message-id',"2"}], + [{data,Data}]}, + RpcXml = list_to_binary(xmerl:export_simple_element(Rpc,xmerl_xml)), + + Notification = + {notification,?NETCONF_NOTIF_NAMESPACE_ATTR, + [{eventTime,["2012-06-14T14:50:54+02:00"]}, + {event,[{xmlns,"http://my.namespaces.com/event"}], + [{severity,["major"]}, + {description,["Something terrible happened"]}]}]}, + NotifXml = + list_to_binary(xmerl:export_simple_element(Notification,xmerl_xml)), + + + %% First part contains a notif, but only parts of the end tag + Part1 = + <<"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", + NotifXml/binary,"\n]]">>, + + %% Second part contains rest of end tag, full rpc-reply and full + %% notif except end tag + Part2 = + <<">]]>\n",RpcXml/binary,"\n",?END_TAG/binary,NotifXml/binary>>, + + %% Third part contains last end tag + Part3 = <<"\n",?END_TAG/binary,"\n">>, + + %% Spawn a process which will wait a bit for the client to send + %% the request (below), then order the server to the chunks of the + %% rpc-reply one by one. + spawn(fun() -> ct:sleep(500),?NS:hupp(send,Part1), + ct:sleep(100),?NS:hupp(send,Part2), + ct:sleep(100),?NS:hupp(send,Part3) + end), + + %% Order server to expect a get - then the process above will make + %% sure the rpc-reply is sent. + ?NS:expect('get'), + {ok,Data} = ct_netconfc:get(Client,{server,[{xmlns,"myns"}],[]}), + + receive + {notification,_,_} -> + ok; + Other1 -> + ct:fail({got_unexpected_while_waiting_for_event, Other1}) + after 3000 -> + ct:fail(timeout_waiting_for_event) + end, + receive + {notification,_,_} -> + ok; + Other2 -> + ct:fail({got_unexpected_while_waiting_for_event, Other2}) + after 3000 -> + ct:fail(timeout_waiting_for_event) + end, + ?NS:expect_do_reply('close-session',close,ok), + ?ok = ct_netconfc:close_session(Client), + ok. + %%%----------------------------------------------------------------- break(_Config) -> diff --git a/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl b/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl index 8c30383343..67827a053f 100644 --- a/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl +++ b/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl @@ -144,8 +144,8 @@ expect_do_reply(SessionId,Expect,Do,Reply) -> %% Hupp the server - i.e. tell it to do something - %% e.g. hupp(send_event) will cause send_event(State) to be called on %% the session channel process. -hupp(send_event) -> - hupp(send,[make_msg(event)]); +hupp({send_events,N}) -> + hupp(send,[make_msg({event,N})]); hupp(kill) -> hupp(1,fun hupp_kill/1,[]). @@ -277,6 +277,18 @@ hupp_kill(State = #session{connection = ConnRef}) -> send({CM,Ch},Data) -> ssh_connection:send(CM, Ch, Data). +%%% Split into many small parts and send to client +send_frag({CM,Ch},Data) -> + Sz = rand:uniform(2000), + case Data of + <<Chunk:Sz/binary,Rest/binary>> -> + ssh_connection:send(CM, Ch, Chunk), + send_frag({CM,Ch},Rest); + Chunk -> + ssh_connection:send(CM, Ch, Chunk) + end. + + %%% Kill ssh connection kill({CM,_Ch}) -> ssh:close(CM). @@ -294,7 +306,7 @@ table_trans(Fun,Args) -> receive {table_trans_done,Result} -> Result - after 5000 -> + after 20000 -> exit(table_trans_timeout) end end. @@ -424,6 +436,9 @@ do(_, undefined) -> reply(_,undefined) -> ?dbg("no reply~n",[]), ok; +reply(ConnRef,{fragmented,Reply}) -> + ?dbg("Reply fragmented: ~p~n",[Reply]), + send_frag(ConnRef,make_msg(Reply)); reply(ConnRef,Reply) -> ?dbg("Reply: ~p~n",[Reply]), send(ConnRef, make_msg(Reply)). @@ -431,9 +446,12 @@ reply(ConnRef,Reply) -> from_simple(Simple) -> unicode_c2b(xmerl:export_simple_element(Simple,xmerl_xml)). -xml(Content) -> - <<"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", - Content/binary,"\n",?END_TAG/binary>>. +xml(Content) when is_binary(Content) -> + xml([Content]); +xml(Content) when is_list(Content) -> + Msgs = [<<Msg/binary,"\n",?END_TAG/binary>> || Msg <- Content], + MsgsBin = list_to_binary(Msgs), + <<"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", MsgsBin/binary>>. rpc_reply(Content) when is_binary(Content) -> MsgId = case erase(msg_id) of @@ -556,15 +574,17 @@ make_msg({ok,Data}) -> make_msg({data,Data}) -> xml(rpc_reply(from_simple({data,Data}))); -make_msg(event) -> - xml(<<"<notification xmlns=\"",?NETCONF_NOTIF_NAMESPACE,"\">" +make_msg({event,N}) -> + Notification = <<"<notification xmlns=\"",?NETCONF_NOTIF_NAMESPACE,"\">" "<eventTime>2012-06-14T14:50:54+02:00</eventTime>" "<event xmlns=\"http://my.namespaces.com/event\">" "<severity>major</severity>" "<description>Something terrible happened</description>" "</event>" - "</notification>">>); -make_msg(Xml) when is_binary(Xml) -> + "</notification>">>, + xml(lists:duplicate(N,Notification)); +make_msg(Xml) when is_binary(Xml) orelse + (is_list(Xml) andalso is_binary(hd(Xml))) -> xml(Xml); make_msg(Simple) when is_tuple(Simple) -> xml(from_simple(Simple)). diff --git a/lib/common_test/test/ct_pre_post_test_io_SUITE.erl b/lib/common_test/test/ct_pre_post_test_io_SUITE.erl index 2994ce4a96..bf3eeee328 100644 --- a/lib/common_test/test/ct_pre_post_test_io_SUITE.erl +++ b/lib/common_test/test/ct_pre_post_test_io_SUITE.erl @@ -44,13 +44,29 @@ %% instance, the tests need to be performed on a separate node (or %% there will be clashes with logging processes etc). %%-------------------------------------------------------------------- +suite() -> + [{ct_hooks,[ts_install_cth]}, + {timetrap,{seconds,120}}]. + +all() -> + [ + pre_post_io + ]. + init_per_suite(Config) -> - DataDir = ?config(data_dir, Config), - CTH = filename:join(DataDir, "cth_ctrl.erl"), - ct:pal("Compiling ~p: ~p", - [CTH,compile:file(CTH,[{outdir,DataDir},debug_info])]), - ct_test_support:init_per_suite([{path_dirs,[DataDir]}, - {start_sasl,true} | Config]). + TTInfo = {_T,{_Scaled,ScaleVal}} = ct:get_timetrap_info(), + ct:pal("Timetrap info = ~w", [TTInfo]), + if ScaleVal > 1 -> + {skip,"Skip on systems running e.g. cover or debug!"}; + ScaleVal =< 1 -> + DataDir = ?config(data_dir, Config), + CTH = filename:join(DataDir, "cth_ctrl.erl"), + ct:pal("Compiling ~p: ~p", + [CTH,compile:file(CTH,[{outdir,DataDir}, + debug_info])]), + ct_test_support:init_per_suite([{path_dirs,[DataDir]}, + {start_sasl,true} | Config]) + end. end_per_suite(Config) -> ct_test_support:end_per_suite(Config). @@ -61,13 +77,6 @@ init_per_testcase(TestCase, Config) -> end_per_testcase(TestCase, Config) -> ct_test_support:end_per_testcase(TestCase, Config). -suite() -> [{ct_hooks,[ts_install_cth]}]. - -all() -> - [ - pre_post_io - ]. - %%-------------------------------------------------------------------- %% TEST CASES %%-------------------------------------------------------------------- @@ -90,31 +99,50 @@ pre_post_io(Config) -> %%!-------------------------------------------------------------------- spawn(fun() -> - ct:pal("CONTROLLER: Started!", []), + ct:pal("CONTROLLER: Starting test run #1...", []), %% --- test run 1 --- - ct:sleep(3000), - ct:pal("CONTROLLER: Handle remote events = true", []), - ok = ct_test_support:ct_rpc({cth_log_redirect, - handle_remote_events, - [true]}, Config), - ct:sleep(2000), - ct:pal("CONTROLLER: Proceeding with test run #1!", []), + try_loop(ct_test_support, ct_rpc, [{cth_log_redirect, + handle_remote_events, + [true]}, Config], 3000), + CTLoggerPid1 = ct_test_support:ct_rpc({erlang,whereis, + [ct_logs]}, Config), + ct:pal("CONTROLLER: Logger = ~w~nHandle remote events = true", + [CTLoggerPid1]), + ct:sleep(5000), + ct:pal("CONTROLLER: Proceeding with test run #1...", []), ok = ct_test_support:ct_rpc({cth_ctrl,proceed,[]}, Config), ct:sleep(6000), - ct:pal("CONTROLLER: Proceeding with shutdown #1!", []), + ct:pal("CONTROLLER: Proceeding with shutdown #1...", []), ok = ct_test_support:ct_rpc({cth_ctrl,proceed,[]}, Config), + try_loop(fun() -> + false = ct_test_support:ct_rpc({erlang, + is_process_alive, + [CTLoggerPid1]}, + Config) + end, 3000), + ct:pal("CONTROLLER: Shutdown #1 complete!", []), + ct:pal("CONTROLLER: Starting test run #2...", []), %% --- test run 2 --- - ct:sleep(3000), - ct:pal("CONTROLLER: Handle remote events = true", []), - ok = ct_test_support:ct_rpc({cth_log_redirect, - handle_remote_events, - [true]}, Config), - ct:sleep(2000), - ct:pal("CONTROLLER: Proceeding with test run #2!", []), + try_loop(ct_test_support, ct_rpc, [{cth_log_redirect, + handle_remote_events, + [true]}, Config], 3000), + CTLoggerPid2 = ct_test_support:ct_rpc({erlang,whereis, + [ct_logs]}, Config), + ct:pal("CONTROLLER: Logger = ~w~nHandle remote events = true", + [CTLoggerPid2]), + ct:sleep(5000), + ct:pal("CONTROLLER: Proceeding with test run #2...", []), ok = ct_test_support:ct_rpc({cth_ctrl,proceed,[]}, Config), ct:sleep(6000), - ct:pal("CONTROLLER: Proceeding with shutdown #2!", []), - ok = ct_test_support:ct_rpc({cth_ctrl,proceed,[]}, Config) + ct:pal("CONTROLLER: Proceeding with shutdown #2...", []), + ok = ct_test_support:ct_rpc({cth_ctrl,proceed,[]}, Config), + try_loop(fun() -> + false = ct_test_support:ct_rpc({erlang, + is_process_alive, + [CTLoggerPid2]}, + Config) + end, 3000), + ct:pal("CONTROLLER: Shutdown #2 complete!", []) end), ct_test_support:run(Opts, Config), Events = ct_test_support:get_events(ERPid, Config), @@ -157,7 +185,7 @@ pre_post_io(Config) -> Counters end, {pre,0,0,0,0}, Ts), [_|Counters] = tuple_to_list(PrePostIOEntries), - ct:log("Entries in the Pre/Post Test IO Log: ~p", [Counters]), + ct:pal("Entries in the Pre/Post Test IO Log: ~w", [Counters]), case [C || C <- Counters, C < 2] of [] -> ok; @@ -183,7 +211,7 @@ pre_post_io(Config) -> [LogN,ErrN+1]; (_, Counters) -> Counters end, [0,0], Ts), - ct:log("Entries in the Unexpected IO Log: ~p", [UnexpIOEntries]), + ct:log("Entries in the Unexpected IO Log: ~w", [UnexpIOEntries]), case [N || N <- UnexpIOEntries, N < 2] of [] -> ok; @@ -208,6 +236,38 @@ setup(Test, Config) -> reformat(Events, EH) -> ct_test_support:reformat(Events, EH). +try_loop(_Fun, 0) -> + ct:pal("WARNING! Fun never succeeded!", []), + gave_up; +try_loop(Fun, N) -> + try Fun() of + {error,_} -> + timer:sleep(10), + try_loop(Fun, N-1); + Result -> + Result + catch + _:_What -> + timer:sleep(10), + try_loop(Fun, N-1) + end. + +try_loop(M, F, _A, 0) -> + ct:pal("WARNING! ~w:~w never succeeded!", [M,F]), + gave_up; +try_loop(M, F, A, N) -> + try apply(M, F, A) of + {error,_} -> + timer:sleep(10), + try_loop(M, F, A, N-1); + Result -> + Result + catch + _:_ -> + timer:sleep(10), + try_loop(M, F, A, N-1) + end. + %%%----------------------------------------------------------------- %%% TEST EVENTS %%%----------------------------------------------------------------- diff --git a/lib/common_test/test/ct_pre_post_test_io_SUITE_data/cth_ctrl.erl b/lib/common_test/test/ct_pre_post_test_io_SUITE_data/cth_ctrl.erl index b8595b40b9..66a950c178 100644 --- a/lib/common_test/test/ct_pre_post_test_io_SUITE_data/cth_ctrl.erl +++ b/lib/common_test/test/ct_pre_post_test_io_SUITE_data/cth_ctrl.erl @@ -53,8 +53,7 @@ init(_Id, _Opts) -> receive {?MODULE,proceed} -> ok after - 10000 -> - ok + 10000 -> ok end, {ok,[],ct_last}. @@ -66,8 +65,7 @@ terminate(_State) -> receive {?MODULE,proceed} -> ok after - 10000 -> - ok + 10000 -> ok end, stop_external_logger(cth_logger), stop_dispatcher(), @@ -94,7 +92,7 @@ init_logger(Name) -> logger_loop(N) -> ct:log("Logger iteration: ~p", [N]), error_logger:error_report(N), - timer:sleep(250), + timer:sleep(100), logger_loop(N+1). %%%----------------------------------------------------------------- diff --git a/lib/common_test/test/ct_release_test_SUITE.erl b/lib/common_test/test/ct_release_test_SUITE.erl new file mode 100644 index 0000000000..66d07155ac --- /dev/null +++ b/lib/common_test/test/ct_release_test_SUITE.erl @@ -0,0 +1,190 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2009-2014. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +%%%------------------------------------------------------------------- +%%% File: ct_release_test_SUITE +%%% +%%% Description: +%%% Test ct_release_test module +%%% +%%%------------------------------------------------------------------- +-module(ct_release_test_SUITE). + +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("common_test/include/ct_event.hrl"). + +-define(eh, ct_test_support_eh). +-define(suite, release_test_SUITE). + +%%-------------------------------------------------------------------- +%% TEST SERVER CALLBACK FUNCTIONS +%%-------------------------------------------------------------------- + +%%-------------------------------------------------------------------- +%% Description: Since Common Test starts another Test Server +%% instance, the tests need to be performed on a separate node (or +%% there will be clashes with logging processes etc). +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + case os:type() of + {win32,_} -> + {skipped, "Upgrade tests do currently not work on windows"}; + _ -> + ct_test_support:init_per_suite(Config) + end. + +end_per_suite(Config) -> + ct_test_support:end_per_suite(Config). + +init_per_testcase(TestCase, Config) -> + ct_test_support:init_per_testcase(TestCase, Config). + +end_per_testcase(TestCase, Config) -> + ct_test_support:end_per_testcase(TestCase, Config). + +suite() -> [{ct_hooks,[ts_install_cth]}]. + +all() -> + [ + minor, + major, + major_fail_init, + major_fail_upgraded, + major_fail_downgraded, + major_fail_no_init + ]. + +%%-------------------------------------------------------------------- +%% TEST CASES +%%-------------------------------------------------------------------- + +%%%----------------------------------------------------------------- +%%% +minor(Config) when is_list(Config) -> + {Suite,Cfg} = setup1(Config), + {Opts,ERPid} = setup([{suite,Suite}, + {testcase,minor}, + {label,minor}|Cfg], Config), + execute(minor, Opts, ERPid, Config). + +major(Config) when is_list(Config) -> + {Suite,Cfg} = setup1(Config), + {Opts,ERPid} = setup([{suite,Suite}, + {testcase,major}, + {label,major}|Cfg], Config), + execute(major, Opts, ERPid, Config). + +major_fail_init(Config) when is_list(Config) -> + {Suite,Cfg} = setup1(Config), + {Opts,ERPid} = setup([{suite,Suite}, + {testcase,major_fail_init}, + {label,major_fail_init}|Cfg], Config), + execute(major_fail_init, Opts, ERPid, Config). + +major_fail_upgraded(Config) when is_list(Config) -> + {Suite,Cfg} = setup1(Config), + {Opts,ERPid} = setup([{suite,Suite}, + {testcase,major_fail_upgraded}, + {label,major_fail_upgraded}|Cfg], Config), + execute(major_fail_upgraded, Opts, ERPid, Config). + +major_fail_downgraded(Config) when is_list(Config) -> + {Suite,Cfg} = setup1(Config), + {Opts,ERPid} = setup([{suite,Suite}, + {testcase,major_fail_downgraded}, + {label,major_fail_downgraded}|Cfg], Config), + execute(major_fail_downgraded, Opts, ERPid, Config). + +major_fail_no_init(Config) when is_list(Config) -> + {Suite,Cfg} = setup1(Config), + {Opts,ERPid} = setup([{suite,Suite}, + {testcase,major_fail_no_init}, + {label,major_fail_no_init}|Cfg], Config), + execute(major_fail_no_init, Opts, ERPid, Config). + + +%%%----------------------------------------------------------------- +%%% HELP FUNCTIONS +%%%----------------------------------------------------------------- +setup1(Config) -> + DataDir = ?config(data_dir, Config), + Suite = filename:join(DataDir, atom_to_list(?suite)), + Cfg = case ct:get_config(otp_releases) of + undefined -> + []; + Rels -> + CfgFile = filename:join(DataDir, "release_test.cfg"), + file:write_file(CfgFile, + io_lib:format("{otp_releases,~p}.",[Rels])), + [{config,CfgFile}] + end, + {Suite,Cfg}. + +setup(Test, Config) -> + Opts0 = ct_test_support:get_opts(Config), + Level = ?config(trace_level, Config), + EvHArgs = [{cbm,ct_test_support},{trace_level,Level}], + Opts = Opts0 ++ [{event_handler,{?eh,EvHArgs}}|Test], + ERPid = ct_test_support:start_event_receiver(Config), + {Opts,ERPid}. + +execute(Name, Opts, ERPid, Config) -> + ok = ct_test_support:run(Opts, Config), + Events = ct_test_support:get_events(ERPid, Config), + + ct_test_support:log_events(Name, + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), + + verify_events(Name,Events,Config). + +reformat(Events, EH) -> + ct_test_support:reformat(Events, EH). + +%%%----------------------------------------------------------------- +%%% TEST EVENTS +%%%----------------------------------------------------------------- +verify_events(TC,Events,Config) -> + Ok = expected_events(TC,ok), + case ct_test_support:verify_events(Ok, Events, Config) of + ok -> + ok; + {event_not_found,{?eh,tc_done,{_Suite,TC,ok}}}=R1 -> + ct:log("Did not find 'ok', checking if skipped...",[]), + Skipped = expected_events(TC,{skipped,"Old release not available"}), + case ct_test_support:verify_events(Skipped, Events, Config) of + ok -> + {skipped,"Old release not available"}; + R2 -> + ct:log("Did not find skipped case either: ~n~p",[R2]), + exit(R1) + end + end. + +expected_events(TC,Result) -> + OneTest = + [{?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,tc_done,{?suite,TC,Result}}, + {?eh,stop_logging,[]}], + %% 2 tests (ct:run_test + script_start) is default + OneTest ++ OneTest. diff --git a/lib/common_test/test/ct_release_test_SUITE_data/release_test_SUITE.erl b/lib/common_test/test/ct_release_test_SUITE_data/release_test_SUITE.erl new file mode 100644 index 0000000000..04c92be0d1 --- /dev/null +++ b/lib/common_test/test/ct_release_test_SUITE_data/release_test_SUITE.erl @@ -0,0 +1,118 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2015. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% +%%%---------------------------------------------------------------- +%%% Purpose: Test the support for application upgrade/code_change test +%%%----------------------------------------------------------------- +-module(release_test_SUITE). +-include_lib("common_test/include/ct.hrl"). + +-compile(export_all). + +-define(APP,runtime_tools). % "randomly" selected 'application under test' + +%% +%% all/1 +%% +all() -> + [minor, + major, + major_fail_init, + major_fail_upgraded, + major_fail_downgraded, + major_fail_no_init]. + +init_per_suite(Config) -> + Config. + +end_per_suite(_Config) -> + ok. + +init_per_testcase(major_fail_no_init, Config) -> + Config; +init_per_testcase(_Case, Config) -> + ct_release_test:init(Config). +end_per_testcase(_Case, Config) -> + ct_release_test:cleanup(Config). + +%%%----------------------------------------------------------------- +%%% Test cases +minor(Config) -> + ct_release_test:upgrade(?APP,minor,{?MODULE,[]},Config). + +major(Config) -> + ct_release_test:upgrade(?APP,major,{?MODULE,[]},Config). + +major_fail_init(Config) -> + try ct_release_test:upgrade(?APP,major,{?MODULE,fail_init},Config) + catch exit:{test_case_failed, + {test_upgrade_callback,_Mod,_Func,_Args, + {'EXIT',{test_case_failed,upgrade_init_failed}}}} -> + ok + end. + +major_fail_upgraded(Config) -> + try ct_release_test:upgrade(?APP,major,{?MODULE,fail_upgraded},Config) + catch exit:{test_case_failed, + {test_upgrade_callback,_Mod,_Func,_Args, + {'EXIT',{test_case_failed,upgrade_upgraded_failed}}}} -> + ok + end. + +major_fail_downgraded(Config) -> + try ct_release_test:upgrade(?APP,major,{?MODULE,fail_downgraded},Config) + catch exit:{test_case_failed, + {test_upgrade_callback,_Mod,_Func,_Args, + {'EXIT',{test_case_failed,upgrade_downgraded_failed}}}} -> + ok + end. + +major_fail_no_init(Config) -> + try ct_release_test:upgrade(?APP,major,[],Config) + catch exit:{test_case_failed,"ct_release_test:init/1 not run"} -> + ok + end. + +%%%----------------------------------------------------------------- +%%% ct_release_test callbacks + +%% Version numbers are checked by ct_release_test, so there is nothing +%% more to check here... +upgrade_init(CtData,fail_init) -> + ct:fail(upgrade_init_failed); +upgrade_init(CtData,State) -> + {ok,{FromVsn,ToVsn}} = ct_release_test:get_app_vsns(CtData,?APP), + case ct_release_test:get_appup(CtData,?APP) of + {ok,{FromVsn,ToVsn,UpInstrs,DownInstrs}} -> + io:format("Upgrade/downgrade ~p: ~p <--> ~p~n" + "Upgrade instructions: ~p~n" + "Downgrade instructions: ~p", + [?APP,FromVsn,ToVsn,UpInstrs,DownInstrs]); + {error,{vsn_not_found,_}} when FromVsn==ToVsn -> + io:format("No upgrade test for ~p, same version",[?APP]) + end, + State. +upgrade_upgraded(CtData,fail_upgraded) -> + ct:fail(upgrade_upgraded_failed); +upgrade_upgraded(_CtData,State) -> + State. +upgrade_downgraded(CtData,fail_downgraded) -> + ct:fail(upgrade_downgraded_failed); +upgrade_downgraded(_CtData,State) -> + State. diff --git a/lib/common_test/test/ct_surefire_SUITE.erl b/lib/common_test/test/ct_surefire_SUITE.erl index 82ab1c19bb..922978fc4b 100644 --- a/lib/common_test/test/ct_surefire_SUITE.erl +++ b/lib/common_test/test/ct_surefire_SUITE.erl @@ -49,8 +49,11 @@ %% there will be clashes with logging processes etc). %%-------------------------------------------------------------------- init_per_suite(Config) -> - Config1 = ct_test_support:init_per_suite(Config), - Config1. + DataDir = ?config(data_dir,Config), + Hook = "fail_pre_init_per_suite.erl", + io:format("Compiling ~p: ~p~n", + [Hook, compile:file(Hook,[{outdir,DataDir},debug_info])]), + ct_test_support:init_per_suite([{path_dirs,[DataDir]}|Config]). end_per_suite(Config) -> ct_test_support:end_per_suite(Config). @@ -69,7 +72,8 @@ all() -> absolute_path, relative_path, url, - logdir + logdir, + fail_pre_init_per_suite ]. %%-------------------------------------------------------------------- @@ -107,6 +111,14 @@ logdir(Config) when is_list(Config) -> Path = "logdir.xml", run(logdir,[{cth_surefire,[{path,Path}]}],Path,Config,[{logdir,MyLogDir}]). +fail_pre_init_per_suite(Config) when is_list(Config) -> + DataDir = ?config(data_dir,Config), + Suites = [filename:join(DataDir,"pass_SUITE"), + filename:join(DataDir,"fail_SUITE")], + Path = "fail_pre_init_per_suite.xml", + run(fail_pre_init_per_suite,[fail_pre_init_per_suite, + {cth_surefire,[{path,Path}]}],Path,Config,[],Suites). + %%%----------------------------------------------------------------- %%% HELP FUNCTIONS %%%----------------------------------------------------------------- @@ -115,6 +127,8 @@ run(Case,CTHs,Report,Config) -> run(Case,CTHs,Report,Config,ExtraOpts) -> DataDir = ?config(data_dir, Config), Suite = filename:join(DataDir, "surefire_SUITE"), + run(Case,CTHs,Report,Config,ExtraOpts,Suite). +run(Case,CTHs,Report,Config,ExtraOpts,Suite) -> {Opts,ERPid} = setup([{suite,Suite},{ct_hooks,CTHs},{label,Case}|ExtraOpts], Config), ok = execute(Case, Opts, ERPid, Config), @@ -142,7 +156,6 @@ setup(Test, Config) -> execute(Name, Opts, ERPid, Config) -> ok = ct_test_support:run(Opts, Config), Events = ct_test_support:get_events(ERPid, Config), - ct_test_support:log_events(Name, reformat(Events, ?eh), ?config(priv_dir, Config), @@ -166,10 +179,30 @@ events_to_check(_, 0) -> events_to_check(Test, N) -> test_events(Test) ++ events_to_check(Test, N-1). -test_events(_) -> - [{?eh,start_logging,'_'}, - {?eh,start_info,{1,1,9}}, - {?eh,tc_start,{surefire_SUITE,init_per_suite}}, +test_suite_events(fail_SUITE, TestStat) -> + [{?eh,tc_start,{ct_framework,init_per_suite}}, + {?eh,tc_done,{ct_framework,init_per_suite, + {failed,{error,pre_init_per_suite}}}}, + {?eh,tc_auto_skip, + {fail_SUITE,test_case, + {failed,{ct_framework,init_per_suite,{failed,pre_init_per_suite}}}}}, + {?eh,test_stats,TestStat}, + {?eh,tc_auto_skip, + {ct_framework,end_per_suite, + {failed,{ct_framework,init_per_suite,{failed,pre_init_per_suite}}}}}]. + +test_suite_events(fail_SUITE) -> + test_suite_events(fail_SUITE, {0,0,{0,1}}); +test_suite_events(pass_SUITE) -> + [{?eh,tc_start,{ct_framework,init_per_suite}}, + {?eh,tc_done,{ct_framework,init_per_suite,ok}}, + {?eh,tc_start,{pass_SUITE,test_case}}, + {?eh,tc_done,{pass_SUITE,test_case,ok}}, + {?eh,test_stats,{1,0,{0,0}}}, + {?eh,tc_start,{ct_framework,end_per_suite}}, + {?eh,tc_done,{ct_framework,end_per_suite,ok}}]; +test_suite_events(_) -> + [{?eh,tc_start,{surefire_SUITE,init_per_suite}}, {?eh,tc_done,{surefire_SUITE,init_per_suite,ok}}, {?eh,tc_start,{surefire_SUITE,tc_ok}}, {?eh,tc_done,{surefire_SUITE,tc_ok,ok}}, @@ -216,9 +249,18 @@ test_events(_) -> {surefire_SUITE,init_per_group, {'EXIT',all_cases_should_be_skipped}}}}}], {?eh,tc_start,{surefire_SUITE,end_per_suite}}, - {?eh,tc_done,{surefire_SUITE,end_per_suite,ok}}, - {?eh,stop_logging,[]}]. - + {?eh,tc_done,{surefire_SUITE,end_per_suite,ok}}]. + +test_events(fail_pre_init_per_suite) -> + [{?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,start_info,{2,2,2}}] ++ + test_suite_events(pass_SUITE) ++ + test_suite_events(fail_SUITE, {1,0,{0,1}}) ++ + [{?eh,stop_logging,[]}]; +test_events(Test) -> + [{?eh,start_logging,'_'}, {?eh,start_info,{1,1,9}}] ++ + test_suite_events(Test) ++ + [{?eh,stop_logging,[]}]. %%%----------------------------------------------------------------- %%% Check generated xml log files @@ -251,9 +293,9 @@ do_check_xml(Case,[Xml|Xmls]) -> {E,_} = xmerl_scan:file(Xml), Expected = events_to_result(lists:flatten(test_events(Case))), ParseResult = testsuites(Case,E), - ct:log("Expecting: ~p~n",[[Expected]]), + ct:log("Expecting: ~p~n",[Expected]), ct:log("Actual : ~p~n",[ParseResult]), - [Expected] = ParseResult, + Expected = ParseResult, do_check_xml(Case,Xmls); do_check_xml(_,[]) -> ok. @@ -265,7 +307,8 @@ testsuites(Case,#xmlElement{name=testsuites,content=TS}) -> testsuite(Case,TS). testsuite(Case,[#xmlElement{name=testsuite,content=TC,attributes=A}|TS]) -> - {ET,EF,ES} = events_to_numbers(lists:flatten(test_events(Case))), + TestSuiteEvents = test_suite_events(get_ts_name(A)), + {ET,EF,ES} = events_to_numbers(lists:flatten(TestSuiteEvents)), {T,E,F,S} = get_numbers_from_attrs(A,false,false,false,false), ct:log("Expecting total:~p, error:~p, failure:~p, skipped:~p~n",[ET,0,EF,ES]), ct:log("Actual total:~p, error:~p, failure:~p, skipped:~p~n",[T,E,F,S]), @@ -318,14 +361,32 @@ failed_or_skipped([]) -> %% Testsuites = [Testsuite] %% Testsuite = [Testcase] %% Testcase = [] | [f] | [s], indicating ok, failed and skipped respectively -events_to_result([{?eh,tc_done,{_Suite,_Case,R}}|E]) -> - [result(R)|events_to_result(E)]; -events_to_result([{?eh,tc_auto_skip,_}|E]) -> - [[s]|events_to_result(E)]; -events_to_result([_|E]) -> - events_to_result(E); -events_to_result([]) -> - []. +events_to_result(E) -> + events_to_result(E, []). + +events_to_result([{?eh,tc_auto_skip,{_Suite,init_per_suite,_}}|E], Result) -> + {Suite,Rest} = events_to_result1(E), + events_to_result(Rest, [[[s]|Suite]|Result]); +events_to_result([{?eh,tc_done,{_Suite,init_per_suite,R}}|E], Result) -> + {Suite,Rest} = events_to_result1(E), + events_to_result(Rest, [[result(R)|Suite]|Result]); +events_to_result([_|E], Result) -> + events_to_result(E, Result); +events_to_result([], Result) -> + Result. + +events_to_result1([{?eh,tc_auto_skip,{_Suite, end_per_suite,_}}|E]) -> + {[[s]],E}; +events_to_result1([{?eh,tc_done,{_Suite, end_per_suite,R}}|E]) -> + {[result(R)],E}; +events_to_result1([{?eh,tc_done,{_Suite,_Case,R}}|E]) -> + {Suite,Rest} = events_to_result1(E), + {[result(R)|Suite],Rest}; +events_to_result1([{?eh,tc_auto_skip,_}|E]) -> + {Suite,Rest} = events_to_result1(E), + {[[s]|Suite],Rest}; +events_to_result1([_|E]) -> + events_to_result1(E). result(ok) ->[]; result({skipped,_}) -> [s]; @@ -374,3 +435,7 @@ del_files(Dir,[F0|Fs] ) -> end; del_files(_,[]) -> ok. + +get_ts_name(Attributes) -> + {_,name,_,_,_,_,_,_,Name,_} = lists:keyfind(name, 2, Attributes), + list_to_atom(Name). diff --git a/lib/ssh/src/ssh_math.erl b/lib/common_test/test/ct_surefire_SUITE_data/fail_SUITE.erl index cace85bc93..3f5f42c054 100644 --- a/lib/ssh/src/ssh_math.erl +++ b/lib/common_test/test/ct_surefire_SUITE_data/fail_SUITE.erl @@ -1,7 +1,6 @@ -%% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2013. All Rights Reserved. +%% Copyright Ericsson AB 2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -17,26 +16,13 @@ %% %% %CopyrightEnd% %% +-module(fail_SUITE). +-include_lib("common_test/include/ct.hrl"). -%% - -%%% Description: SSH math utilities - --module(ssh_math). - --export([ipow/3]). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% -%% INTEGER utils -%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% calculate A^B mod M -ipow(A, B, M) when M > 0, B >= 0 -> - crypto:bytes_to_integer(crypto:mod_pow(A, B, M)). - - - +-export([all/0, test_case/1]). +all() -> + [test_case]. +test_case(_Config) -> + ok. diff --git a/lib/common_test/test/ct_surefire_SUITE_data/fail_pre_init_per_suite.erl b/lib/common_test/test/ct_surefire_SUITE_data/fail_pre_init_per_suite.erl new file mode 100644 index 0000000000..ff278db378 --- /dev/null +++ b/lib/common_test/test/ct_surefire_SUITE_data/fail_pre_init_per_suite.erl @@ -0,0 +1,47 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2016. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +%%% This tests that the correct XML is produced when pre_init_per_suite +%%% fails in a hook +-module(fail_pre_init_per_suite). + +%% CT Hooks +-export([init/2, pre_init_per_suite/3]). + +-type config() :: proplists:proplist(). +-type reason() :: term(). +-type skip_or_fail() :: skip | auto_skip | fail | 'EXIT'. + +-record(state, {}). + +-spec init(Id :: term(), Opts :: proplists:proplist()) -> + {ok, proplists:proplist()}. +init(_Id, Opts) -> + {ok, Opts}. + +-spec pre_init_per_suite(Suite :: atom(), + Config :: config(), + State :: #state{}) -> + {config() | {skip_or_fail(), reason()}, NewState :: #state{}}. +pre_init_per_suite(fail_SUITE, _Config, State) -> + {{fail, pre_init_per_suite}, State}; +pre_init_per_suite(_Suite, Config, State) -> + {Config, State}. + diff --git a/lib/common_test/test/ct_surefire_SUITE_data/pass_SUITE.erl b/lib/common_test/test/ct_surefire_SUITE_data/pass_SUITE.erl new file mode 100644 index 0000000000..74ed5b730e --- /dev/null +++ b/lib/common_test/test/ct_surefire_SUITE_data/pass_SUITE.erl @@ -0,0 +1,28 @@ +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2016. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% +-module(pass_SUITE). +-include_lib("common_test/include/ct.hrl"). + +-export([all/0, test_case/1]). + +all() -> + [test_case]. + +test_case(_Config) -> + ok. diff --git a/lib/common_test/test/ct_test_support.erl b/lib/common_test/test/ct_test_support.erl index 248ec6c4df..493fa82c79 100644 --- a/lib/common_test/test/ct_test_support.erl +++ b/lib/common_test/test/ct_test_support.erl @@ -43,6 +43,8 @@ -export([random_error/1]). +-export([unique_timestamp/0]). + -include_lib("kernel/include/file.hrl"). %%%----------------------------------------------------------------- @@ -110,7 +112,8 @@ start_slave(NodeName, Config, Level) -> undefined -> []; Ds -> Ds end, - PathDirs = [PrivDir,TSDir | AddPathDirs], + TestSupDir = filename:dirname(code:which(?MODULE)), + PathDirs = [PrivDir,TSDir,TestSupDir | AddPathDirs], [true = rpc:call(CTNode, code, add_patha, [D]) || D <- PathDirs], test_server:format(Level, "Dirs added to code path (on ~w):~n", [CTNode]), @@ -1228,8 +1231,8 @@ log_events(TC, Events, EvLogDir, Opts) -> file:close(Dev), FullLogFile = join_abs_dirs(proplists:get_value(net_dir, Opts), LogFile), - io:format("Events written to logfile: <a href=\"file://~s\">~s</a>~n", - [FullLogFile,FullLogFile]), + ct:log("Events written to logfile: <a href=\"file://~s\">~s</a>~n", + [FullLogFile,FullLogFile],[no_css]), io:format(user, "Events written to logfile: ~p~n", [LogFile]). log_events1(Evs, Dev, "") -> @@ -1430,7 +1433,21 @@ rm_files([F | Fs]) -> end; rm_files([]) -> ok. - + +unique_timestamp() -> + unique_timestamp(os:timestamp(), 100000). + +unique_timestamp(TS, 0) -> + TS; +unique_timestamp(TS0, N) -> + case os:timestamp() of + TS0 -> + timer:sleep(1), + unique_timestamp(TS0, N-1); + TS1 -> + TS1 + end. + %%%----------------------------------------------------------------- %%% slave_stop(Node) -> diff --git a/lib/common_test/vsn.mk b/lib/common_test/vsn.mk index ff2bd20ab3..c6e5148716 100644 --- a/lib/common_test/vsn.mk +++ b/lib/common_test/vsn.mk @@ -1 +1 @@ -COMMON_TEST_VSN = 1.11 +COMMON_TEST_VSN = 1.12.1.1 diff --git a/lib/compiler/doc/src/notes.xml b/lib/compiler/doc/src/notes.xml index 6db8d19b5a..8ed71db54a 100644 --- a/lib/compiler/doc/src/notes.xml +++ b/lib/compiler/doc/src/notes.xml @@ -32,6 +32,98 @@ <p>This document describes the changes made to the Compiler application.</p> +<section><title>Compiler 6.0.3</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + An complicated guard expression in a function call could + crash the compiler. (Thanks to Thomas Arts for reporting + this bug.)</p> + <p> + Own Id: OTP-13208</p> + </item> + <item> + <p>Constructing a map in a guard in a catch could crash + the compiler. (Thanks to Thomas Arts for reporting this + bug.)</p> + <p> + Own Id: OTP-13223</p> + </item> + <item> + <p>Updating a fun as if it were a map would cause the + compiler to crash. (Thanks to Thomas Arts for reporting + this bug.)</p> + <p> + Own Id: OTP-13231</p> + </item> + <item> + <p> + Fix pretty printing of Core Maps</p> + <p> + Literal maps could cause Dialyzer to crash when pretty + printing the results.</p> + <p> + Own Id: OTP-13238</p> + </item> + <item> + <p> + A complex combination of bit syntax matching operations + would cause an internal consistency check failure during + compilation. (Thanks to Jose Valim for reporting this + bug.)</p> + <p> + Own Id: OTP-13309</p> + </item> + </list> + </section> + +</section> + +<section><title>Compiler 6.0.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix cerl_trees:label/2 bug with map K/V swap</p> + <p> + Own Id: OTP-13091</p> + </item> + <item> + <p> + Warnings produced when the '<c>bin_opt_info</c>' option + was given could sometimes lack filenames and line + numbers. (Thanks to José Valim for reporting this bug.)</p> + <p> + Own Id: OTP-13113</p> + </item> + </list> + </section> + +</section> + +<section><title>Compiler 6.0.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix <c>get_map_elements</c> register corruption</p> + <p> + Instruction <c>get_map_elements</c> might destroy target + registers when the fail-label is taken. Only seen for + patterns with two, and only two, target registers. + Specifically if we copy one register and then jump.</p> + <p> + Own Id: OTP-12967</p> + </item> + </list> + </section> + +</section> + <section><title>Compiler 6.0</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -438,22 +530,28 @@ <p> EEP43: New data type - Maps</p> <p> - With Maps you may for instance: <taglist> <item><c>M0 = - #{ a => 1, b => 2}, % create - associations</c></item> <item><c>M1 = M0#{ a := 10 }, % - update values</c></item> <item><c>M2 = M1#{ "hi" => - "hello"}, % add new associations</c></item> <item><c>#{ - "hi" := V1, a := V2, b := V3} = M2. % match keys with - values</c></item> </taglist></p> + With Maps you may for instance:</p> + <taglist> + <tag/> <item><c>M0 = #{ a => 1, b => 2}, % create + associations</c></item> + <tag/><item><c>M1 = M0#{ a := 10 }, % update values</c></item> + <tag/><item><c>M2 = M1#{ "hi" => + "hello"}, % add new associations</c></item> + <tag/><item><c>#{ "hi" := V1, a := V2, b := V3} = M2. + % match keys with values</c></item> + </taglist> <p> For information on how to use Maps please see Map Expressions in the <seealso marker="doc/reference_manual:expressions#map_expressions"> Reference Manual</seealso>.</p> <p> The current implementation is without the following - features: <taglist> <item>No variable keys</item> - <item>No single value access</item> <item>No map - comprehensions</item> </taglist></p> + features:</p> + <taglist> + <tag/><item>No variable keys</item> + <tag/><item>No single value access</item> + <tag/><item>No map comprehensions</item> + </taglist> <p> Note that Maps is <em>experimental</em> during OTP 17.0.</p> <p> diff --git a/lib/compiler/src/beam_block.erl b/lib/compiler/src/beam_block.erl index 2def3de7f3..0321b1c07b 100644 --- a/lib/compiler/src/beam_block.erl +++ b/lib/compiler/src/beam_block.erl @@ -251,7 +251,9 @@ opt([{set,_,_,{line,_}}=Line1, {set,[D2],[{integer,Idx2},Reg],{bif,element,{f,0}}}=I2|Is]) when Idx1 < Idx2, D1 =/= D2, D1 =/= Reg, D2 =/= Reg -> opt([Line2,I2,Line1,I1|Is]); -opt([{set,Ds0,Ss,Op}|Is0]) -> +opt([{set,[_|_],_Ss,{get_map_elements,_F}}=I|Is]) -> + [I|opt(Is)]; +opt([{set,Ds0,Ss,Op}|Is0]) -> {Ds,Is} = opt_moves(Ds0, Is0), [{set,Ds,Ss,Op}|opt(Is)]; opt([{'%live',_,_}=I|Is]) -> diff --git a/lib/compiler/src/beam_bool.erl b/lib/compiler/src/beam_bool.erl index 14b6381230..d14be83496 100644 --- a/lib/compiler/src/beam_bool.erl +++ b/lib/compiler/src/beam_bool.erl @@ -142,11 +142,6 @@ bopt_block(Reg, Fail, OldIs, [{block,Bl0}|Acc0], St0) -> throw:not_boolean_expr -> failed; - %% The block contains a 'move' instruction that could - %% not be handled. - throw:move -> - failed; - %% The optimization is not safe. (A register %% used by the instructions following the %% optimized code is either not assigned a @@ -215,37 +210,14 @@ ensure_opt_safe(Bl, NewCode, OldIs, Fail, PrecedingCode, St) -> false -> throw(all_registers_not_killed); true -> ok end, - Same = assigned_same_value(Bl, NewCode), MustBeUnused = ordsets:subtract(ordsets:union(NotSet, NewDst), - ordsets:union(MustBeKilled, Same)), + MustBeKilled), case none_used(MustBeUnused, OldIs, Fail, St) of false -> throw(registers_used); true -> ok end, ok. -%% assigned_same_value(OldCode, NewCodeReversed) -> [DestinationRegs] -%% Return an ordset with a list of all y registers that are always -%% assigned the same value in the old and new code. Currently, we -%% are very conservative in that we only consider identical move -%% instructions in the same order. -%% -assigned_same_value(Old, New) -> - case reverse(New) of - [{block,Bl}|_] -> - assigned_same_value(Old, Bl, []); - _ -> - ordsets:new() - end. - -assigned_same_value([{set,[{y,_}=D],[S],move}|T1], - [{set,[{y,_}=D],[S],move}|T2], Acc) -> - assigned_same_value(T1, T2, [D|Acc]); -assigned_same_value(_, _, Acc) -> - ordsets:from_list(Acc). - -update_fail_label([{set,_,_,move}=I|Is], Fail, Acc) -> - update_fail_label(Is, Fail, [I|Acc]); update_fail_label([{set,Ds,As,{bif,N,{f,_}}}|Is], Fail, Acc) -> update_fail_label(Is, Fail, [{set,Ds,As,{bif,N,{f,Fail}}}|Acc]); update_fail_label([{set,Ds,As,{alloc,Regs,{gc_bif,N,{f,_}}}}|Is], Fail, Acc) -> @@ -314,8 +286,6 @@ split_block_1(Is, Fail, ProhibitFailLabel) -> end end. -split_block_2([{set,_,_,move}=I|Is], Fail, Acc) -> - split_block_2(Is, Fail, [I|Acc]); split_block_2([{set,[_],_,{bif,_,{f,Fail}}}=I|Is], Fail, Acc) -> split_block_2(Is, Fail, [I|Acc]); split_block_2([{set,[_],_,{alloc,_,{gc_bif,_,{f,Fail}}}}=I|Is], Fail, Acc) -> @@ -343,8 +313,6 @@ dst_regs([{set,[D],_,{bif,_,{f,_}}}|Is], Acc) -> dst_regs(Is, [D|Acc]); dst_regs([{set,[D],_,{alloc,_,{gc_bif,_,{f,_}}}}|Is], Acc) -> dst_regs(Is, [D|Acc]); -dst_regs([{set,[D],_,move}|Is], Acc) -> - dst_regs(Is, [D|Acc]); dst_regs([_|Is], Acc) -> dst_regs(Is, Acc); dst_regs([], Acc) -> ordsets:from_list(Acc). @@ -411,13 +379,6 @@ bopt_tree([{protected,[Dst],Code,_}|Is], Forest0, Pre) -> _Res -> throw(not_boolean_expr) end; -bopt_tree([{set,[Dst],[Src],move}=Move|Is], Forest, Pre) -> - case {Src,Dst} of - {{tmp,_},_} -> throw(move); - {_,{tmp,_}} -> throw(move); - _ -> ok - end, - bopt_tree(Is, Forest, [Move|Pre]); bopt_tree([{set,[Dst],As,{bif,N,_}}=Bif|Is], Forest0, Pre) -> Ar = length(As), case safe_bool_op(N, Ar) of @@ -589,10 +550,6 @@ free_variables(Is) -> E = gb_sets:empty(), free_vars_1(Is, E, E, E). -free_vars_1([{set,Ds,As,move}|Is], F0, N0, A) -> - F = gb_sets:union(F0, gb_sets:difference(var_list(As), N0)), - N = gb_sets:union(N0, var_list(Ds)), - free_vars_1(Is, F, N, A); free_vars_1([{set,Ds,As,{bif,_,_}}|Is], F0, N0, A) -> F = gb_sets:union(F0, gb_sets:difference(var_list(As), N0)), N = gb_sets:union(N0, var_list(Ds)), @@ -632,8 +589,6 @@ free_vars_regs(X) -> [{x,X-1}|free_vars_regs(X-1)]. rename_regs(Is, Regs) -> rename_regs(Is, Regs, []). -rename_regs([{set,_,_,move}=I|Is], Regs, Acc) -> - rename_regs(Is, Regs, [I|Acc]); rename_regs([{set,[Dst0],Ss0,{alloc,_,Info}}|Is], Regs0, Acc) -> Live = live_regs(Regs0), Ss = rename_sources(Ss0, Regs0), @@ -737,8 +692,7 @@ ssa_assign({x,_}=R, #ssa{sub=Sub0}=Ssa0) -> Sub1 = gb_trees:update(R, NewReg, Sub0), Sub = gb_trees:insert(NewReg, NewReg, Sub1), Ssa#ssa{sub=Sub} - end; -ssa_assign(_, Ssa) -> Ssa. + end. ssa_sub_list(List, Sub) -> [ssa_sub(E, Sub) || E <- List]. diff --git a/lib/compiler/src/beam_bsm.erl b/lib/compiler/src/beam_bsm.erl index 4f76350269..62356928ae 100644 --- a/lib/compiler/src/beam_bsm.erl +++ b/lib/compiler/src/beam_bsm.erl @@ -421,7 +421,8 @@ btb_follow_branches([], _, D) -> D. btb_follow_branch(0, _Regs, D) -> D; btb_follow_branch(Lbl, Regs, #btb{ok_br=Br0,index=Li}=D) -> - case gb_sets:is_member(Lbl, Br0) of + Key = {Lbl,Regs}, + case gb_sets:is_member(Key, Br0) of true -> %% We have already followed this branch and it was OK. D; @@ -432,7 +433,7 @@ btb_follow_branch(Lbl, Regs, #btb{ok_br=Br0,index=Li}=D) -> btb_reaches_match_1(Is, Regs, D), %% Since we got back, this branch is OK. - D#btb{ok_br=gb_sets:insert(Lbl, Br),must_not_save=MustNotSave, + D#btb{ok_br=gb_sets:insert(Key, Br),must_not_save=MustNotSave, must_save=MustSave} end. diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl index 942d69a756..6004f1974e 100644 --- a/lib/compiler/src/beam_validator.erl +++ b/lib/compiler/src/beam_validator.erl @@ -758,10 +758,20 @@ valfun_4(_, _) -> verify_get_map(Fail, Src, List, Vst0) -> assert_type(map, Src, Vst0), - Vst1 = branch_state(Fail, Vst0), + Vst1 = foldl(fun(D, Vsti) -> + case is_reg_defined(D,Vsti) of + true -> set_type_reg(term,D,Vsti); + false -> Vsti + end + end, Vst0, extract_map_vals(List)), + Vst2 = branch_state(Fail, Vst1), Keys = extract_map_keys(List), assert_unique_map_keys(Keys), - verify_get_map_pair(List,Vst0,Vst1). + verify_get_map_pair(List,Vst0,Vst2). + +extract_map_vals([_Key,Val|T]) -> + [Val|extract_map_vals(T)]; +extract_map_vals([]) -> []. extract_map_keys([Key,_Val|T]) -> [Key|extract_map_keys(T)]; @@ -1093,6 +1103,17 @@ set_catch_end({y,Y}, #vst{current=#st{y=Ys0}=St}=Vst) -> Ys = gb_trees:update(Y, initialized, Ys0), Vst#vst{current=St#st{y=Ys}}. + +is_reg_defined({x,_}=Reg, Vst) -> is_type_defined_x(Reg, Vst); +is_reg_defined({y,_}=Reg, Vst) -> is_type_defined_y(Reg, Vst); +is_reg_defined(V, #vst{}) -> error({not_a_register, V}). + +is_type_defined_x({x,X}, #vst{current=#st{x=Xs}}) -> + gb_trees:is_defined(X,Xs). + +is_type_defined_y({y,Y}, #vst{current=#st{y=Ys}}) -> + gb_trees:is_defined(Y,Ys). + assert_term(Src, Vst) -> get_term_type(Src, Vst), ok. diff --git a/lib/compiler/src/cerl.erl b/lib/compiler/src/cerl.erl index 010327b5e3..e7a2b8177a 100644 --- a/lib/compiler/src/cerl.erl +++ b/lib/compiler/src/cerl.erl @@ -1598,13 +1598,20 @@ is_c_map(#c_literal{val = V}) when is_map(V) -> is_c_map(_) -> false. --spec map_es(c_map()) -> [c_map_pair()]. +-spec map_es(c_map() | c_literal()) -> [c_map_pair()]. +map_es(#c_literal{anno=As,val=M}) when is_map(M) -> + [ann_c_map_pair(As, + #c_literal{anno=As,val='assoc'}, + #c_literal{anno=As,val=K}, + #c_literal{anno=As,val=V}) || {K,V} <- maps:to_list(M)]; map_es(#c_map{es = Es}) -> Es. --spec map_arg(c_map()) -> c_map() | c_literal(). +-spec map_arg(c_map() | c_literal()) -> c_map() | c_literal(). +map_arg(#c_literal{anno=As,val=M}) when is_map(M) -> + #c_literal{anno=As,val=#{}}; map_arg(#c_map{arg=M}) -> M. diff --git a/lib/compiler/src/cerl_trees.erl b/lib/compiler/src/cerl_trees.erl index 2c9b72a30b..58bb18e34a 100644 --- a/lib/compiler/src/cerl_trees.erl +++ b/lib/compiler/src/cerl_trees.erl @@ -731,8 +731,8 @@ label(T, N, Env) -> {ann_c_map(As, M, Ts), N3}; map_pair -> {Op, N1} = label(map_pair_op(T), N, Env), - {Val, N2} = label(map_pair_key(T), N1, Env), - {Key, N3} = label(map_pair_val(T), N2, Env), + {Key, N2} = label(map_pair_key(T), N1, Env), + {Val, N3} = label(map_pair_val(T), N2, Env), {As, N4} = label_ann(T, N3), {ann_c_map_pair(As,Op,Key,Val), N4}; 'let' -> diff --git a/lib/compiler/src/genop.tab b/lib/compiler/src/genop.tab index 8124729b35..3a877f2403 100755 --- a/lib/compiler/src/genop.tab +++ b/lib/compiler/src/genop.tab @@ -45,7 +45,7 @@ BEAM_FORMAT_NUMBER=0 ## Save the next instruction as the return address in the CP register. 4: call/2 -## @spec call_last Arity Label Dellocate +## @spec call_last Arity Label Deallocate ## @doc Deallocate and do a tail recursive call to the function at Label. ## Do not update the CP register. ## Before the call deallocate Deallocate words of stack. @@ -137,7 +137,7 @@ BEAM_FORMAT_NUMBER=0 # Sending & receiving. # ## @spec send -## @doc Send argument in x(0) as a message to the destination process in x(0). +## @doc Send argument in x(1) as a message to the destination process in x(0). ## The message in x(1) ends up as the result of the send in x(0). 20: send/0 @@ -164,12 +164,12 @@ BEAM_FORMAT_NUMBER=0 25: wait/1 ## @spec wait_timeout Lable Time -## @doc Sets up a timeout of Time milllisecons and saves the address of the +## @doc Sets up a timeout of Time milliseconds and saves the address of the ## following instruction as the entry point if the timeout triggers. 26: wait_timeout/2 # -# Arithmethic opcodes. +# Arithmetic opcodes. # 27: -m_plus/4 28: -m_minus/4 @@ -316,7 +316,7 @@ BEAM_FORMAT_NUMBER=0 66: get_tuple_element/3 ## @spec set_tuple_element NewElement Tuple Position -## @doc Update the element at postition Position of the tuple Tuple +## @doc Update the element at position Position of the tuple Tuple ## with the new element NewElement. 67: set_tuple_element/3 diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl index 27d023d067..65699ccda9 100644 --- a/lib/compiler/src/sys_core_fold.erl +++ b/lib/compiler/src/sys_core_fold.erl @@ -3091,12 +3091,12 @@ bsm_ensure_no_partition_2([#c_var{name=V}|Ps], N, G, Vstate, S) -> bsm_ensure_no_partition_2([_|Ps], N, G, _, S) -> bsm_ensure_no_partition_2(Ps, N-1, G, bin_argument_order, S). -bsm_ensure_no_partition_after([#c_clause{pats=Ps}|Cs], Pos) -> +bsm_ensure_no_partition_after([#c_clause{pats=Ps}=C|Cs], Pos) -> case nth(Pos, Ps) of #c_var{} -> bsm_ensure_no_partition_after(Cs, Pos); - P -> - bsm_problem(P, bin_partition) + _ -> + bsm_problem(C, bin_partition) end; bsm_ensure_no_partition_after([], _) -> ok. diff --git a/lib/compiler/src/v3_codegen.erl b/lib/compiler/src/v3_codegen.erl index 34c67b16ca..2a89305f4d 100644 --- a/lib/compiler/src/v3_codegen.erl +++ b/lib/compiler/src/v3_codegen.erl @@ -1327,12 +1327,13 @@ bif_cg(Bif, As, [{var,V}], Le, Vdb, Bef, St0) -> %% that we save any variable that will be live after this BIF call. MayFail = not erl_bifs:is_safe(erlang, Bif, length(As)), - {Sis,Int0} = case St0#cg.in_catch andalso - St0#cg.bfail =:= 0 andalso - MayFail of - true -> adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb); - false -> {[],Bef} - end, + {Sis,Int0} = + case MayFail of + true -> + maybe_adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb, St0); + false -> + {[],Bef} + end, Int1 = clear_dead(Int0, Le#l.i, Vdb), Reg = put_reg(V, Int1#sr.reg), Int = Int1#sr{reg=Reg}, @@ -1363,11 +1364,7 @@ gc_bif_cg(Bif, As, [{var,V}], Le, Vdb, Bef, St0) -> %% Currently, we are somewhat pessimistic in %% that we save any variable that will be live after this BIF call. - {Sis,Int0} = - case St0#cg.in_catch andalso St0#cg.bfail =:= 0 of - true -> adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb); - false -> {[],Bef} - end, + {Sis,Int0} = maybe_adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb, St0), Int1 = clear_dead(Int0, Le#l.i, Vdb), Reg = put_reg(V, Int1#sr.reg), @@ -1512,8 +1509,7 @@ set_cg([{var,R}], {cons,Es}, Le, Vdb, Bef, St) -> Int1 = Int0#sr{reg=put_reg(R, Int0#sr.reg)}, Ret = fetch_reg(R, Int1#sr.reg), {[{put_list,S1,S2,Ret}], Int1, St}; -set_cg([{var,R}], {binary,Segs}, Le, Vdb, Bef, - #cg{in_catch=InCatch, bfail=Bfail}=St) -> +set_cg([{var,R}], {binary,Segs}, Le, Vdb, Bef, #cg{bfail=Bfail}=St) -> %% At run-time, binaries are constructed in three stages: %% 1) First the size of the binary is calculated. %% 2) Then the binary is allocated. @@ -1532,11 +1528,7 @@ set_cg([{var,R}], {binary,Segs}, Le, Vdb, Bef, %% First generate the code that constructs each field. Fail = {f,Bfail}, PutCode = cg_bin_put(Segs, Fail, Bef), - {Sis,Int1} = - case InCatch of - true -> adjust_stack(Int0, Le#l.i, Le#l.i+1, Vdb); - false -> {[],Int0} - end, + {Sis,Int1} = maybe_adjust_stack(Int0, Le#l.i, Le#l.i+1, Vdb, St), MaxRegs = max_reg(Bef#sr.reg), Aft = clear_dead(Int1, Le#l.i, Vdb), @@ -1545,14 +1537,11 @@ set_cg([{var,R}], {binary,Segs}, Le, Vdb, Bef, {Sis++Code,Aft,St}; % Map single variable key set_cg([{var,R}], {map,Op,Map,[{map_pair,{var,_}=K,V}]}, Le, Vdb, Bef, - #cg{in_catch=InCatch,bfail=Bfail}=St) -> + #cg{bfail=Bfail}=St) -> Fail = {f,Bfail}, - {Sis,Int0} = - case InCatch of - true -> adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb); - false -> {[],Bef} - end, + {Sis,Int0} = maybe_adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb, St), + SrcReg = cg_reg_arg(Map,Int0), Line = line(Le#l.a), @@ -1573,17 +1562,13 @@ set_cg([{var,R}], {map,Op,Map,[{map_pair,{var,_}=K,V}]}, Le, Vdb, Bef, % Map (possibly) multiple literal keys set_cg([{var,R}], {map,Op,Map,Es}, Le, Vdb, Bef, - #cg{in_catch=InCatch,bfail=Bfail}=St) -> + #cg{bfail=Bfail}=St) -> %% assert key literals [] = [Var||{map_pair,{var,_}=Var,_} <- Es], Fail = {f,Bfail}, - {Sis,Int0} = - case InCatch of - true -> adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb); - false -> {[],Bef} - end, + {Sis,Int0} = maybe_adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb, St), SrcReg = cg_reg_arg(Map,Int0), Line = line(Le#l.a), @@ -2038,6 +2023,19 @@ trim_free([R|Rs0]) -> end; trim_free([]) -> []. +%% maybe_adjust_stack(Bef, FirstBefore, LastFrom, Vdb, St) -> {[Ainstr],Aft}. +%% Adjust the stack, but only if the code is inside a catch and not +%% inside a guard. Use this funtion before instructions that may +%% cause an exception. + +maybe_adjust_stack(Bef, Fb, Lf, Vdb, St) -> + case St of + #cg{in_catch=true,bfail=0} -> + adjust_stack(Bef, Fb, Lf, Vdb); + #cg{} -> + {[],Bef} + end. + %% adjust_stack(Bef, FirstBefore, LastFrom, Vdb) -> {[Ainstr],Aft}. %% Do complete stack adjustment by compressing stack and adding %% variables to be saved. Try to optimise ordering on stack by diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl index 0941ad5dd5..7d93e2ae16 100644 --- a/lib/compiler/src/v3_core.erl +++ b/lib/compiler/src/v3_core.erl @@ -804,7 +804,7 @@ map_op(map_field_assoc) -> #c_literal{val=assoc}; map_op(map_field_exact) -> #c_literal{val=exact}. is_valid_map_src(#c_literal{val = M}) when is_map(M) -> true; -is_valid_map_src(#c_var{}) -> true; +is_valid_map_src(#c_var{}=Var) -> not cerl:is_c_fname(Var); is_valid_map_src(_) -> false. %% try_exception([ExcpClause], St) -> {[ExcpVar],Handler,St}. diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl index 6e138b0a43..7fb0a16540 100644 --- a/lib/compiler/test/bs_match_SUITE.erl +++ b/lib/compiler/test/bs_match_SUITE.erl @@ -36,7 +36,8 @@ match_string/1,zero_width/1,bad_size/1,haystack/1, cover_beam_bool/1,matched_out_size/1,follow_fail_branch/1, no_partition/1,calling_a_binary/1,binary_in_map/1, - match_string_opt/1]). + match_string_opt/1,map_and_binary/1, + unsafe_branch_caching/1]). -export([coverage_id/1,coverage_external_ignore/2]). @@ -62,7 +63,8 @@ groups() -> otp_7498,match_string,zero_width,bad_size,haystack, cover_beam_bool,matched_out_size,follow_fail_branch, no_partition,calling_a_binary,binary_in_map, - match_string_opt]}]. + match_string_opt,map_and_binary, + unsafe_branch_caching]}]. init_per_suite(Config) -> @@ -1225,6 +1227,50 @@ match_string_opt(Config) when is_list(Config) -> do_match_string_opt({<<1>>,{v,V}}=T) -> {x,V,T}. +%% If 'bin_opt_info' was given the warning would lack filename +%% and line number. + +map_and_binary(_Config) -> + {<<"10">>,<<"37">>,<<"am">>} = do_map_and_binary(<<"10:37am">>), + Map1 = #{time => "noon"}, + {ok,Map1} = do_map_and_binary(Map1), + Map2 = #{hour => 8, min => 42}, + {8,42,Map2} = do_map_and_binary(Map2), + ok. + +do_map_and_binary(<<Hour:2/bytes, $:, Min:2/bytes, Rest/binary>>) -> + {Hour, Min, Rest}; +do_map_and_binary(#{time := _} = T) -> + {ok, T}; +do_map_and_binary(#{hour := Hour, min := Min} = T) -> + {Hour, Min, T}. + +%% Unsafe caching of branch outcomes in beam_bsm would cause the +%% delayed creation of sub-binaries optimization to be applied even +%% when it was unsafe. + +unsafe_branch_caching(_Config) -> + <<>> = do_unsafe_branch_caching(<<42,1>>), + <<>> = do_unsafe_branch_caching(<<42,2>>), + <<>> = do_unsafe_branch_caching(<<42,3>>), + <<17,18>> = do_unsafe_branch_caching(<<42,3,17,18>>), + <<>> = do_unsafe_branch_caching(<<1,3,42,2>>), + + ok. + +do_unsafe_branch_caching(<<Code/integer, Bin/binary>>) -> + <<C1/integer, B1/binary>> = Bin, + case C1 of + X when X =:= 1 orelse X =:= 2 -> + Bin2 = <<>>; + _ -> + Bin2 = B1 + end, + case Code of + 1 -> do_unsafe_branch_caching(Bin2); + _ -> Bin2 + end. + check(F, R) -> R = F(). diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl index df401ccc2b..cbdd9ce8cd 100644 --- a/lib/compiler/test/compile_SUITE.erl +++ b/lib/compiler/test/compile_SUITE.erl @@ -31,7 +31,9 @@ other_output/1, encrypted_abstr/1, bad_record_use1/1, bad_record_use2/1, strict_record/1, missing_testheap/1, cover/1, env/1, core/1, asm/1, - sys_pre_attributes/1, dialyzer/1]). + sys_pre_attributes/1, dialyzer/1, + warnings/1 + ]). -export([init/3]). @@ -48,7 +50,7 @@ all() -> other_output, encrypted_abstr, {group, bad_record_use}, strict_record, missing_testheap, cover, env, core, asm, - sys_pre_attributes, dialyzer]. + sys_pre_attributes, dialyzer, warnings]. groups() -> [{bad_record_use, [], @@ -895,6 +897,44 @@ dialyzer(Config) -> [{a,b,c}] = M:M(), ok. + +%% Test that warnings contain filenames and line numbers. +warnings(_Config) -> + TestDir = filename:dirname(code:which(?MODULE)), + Files = filelib:wildcard(filename:join(TestDir, "*.erl")), + test_lib:p_run(fun do_warnings/1, Files). + +do_warnings(F) -> + {ok,_,_,Ws} = compile:file(F, [binary,bin_opt_info,return]), + do_warnings_1(Ws, F). + +do_warnings_1([{"no_file",Ws}|_], F) -> + io:format("~s:\nMissing file for warnings: ~p\n", + [F,Ws]), + error; +do_warnings_1([{Name,Ws}|T], F) -> + case filename:extension(Name) of + ".erl" -> + do_warnings_2(Ws, T, F); + _ -> + io:format("~s:\nNo .erl extension\n", [F]), + error + end; +do_warnings_1([], _) -> ok. + +do_warnings_2([{Int,_,_}=W|T], Next, F) -> + if + is_integer(Int) -> + do_warnings_2(T, Next, F); + true -> + io:format("~s:\nMissing line number: ~p\n", + [F,W]), + error + end; +do_warnings_2([], Next, F) -> + do_warnings_1(Next, F). + + %%% %%% Utilities. %%% diff --git a/lib/compiler/test/guard_SUITE.erl b/lib/compiler/test/guard_SUITE.erl index b3b67155b3..47eb1ba78b 100644 --- a/lib/compiler/test/guard_SUITE.erl +++ b/lib/compiler/test/guard_SUITE.erl @@ -34,7 +34,8 @@ tricky/1,rel_ops/1,rel_op_combinations/1,literal_type_tests/1, basic_andalso_orelse/1,traverse_dcd/1, check_qlc_hrl/1,andalso_semi/1,t_tuple_size/1,binary_part/1, - bad_constants/1,bad_guards/1]). + bad_constants/1,bad_guards/1,scotland/1, + guard_in_catch/1]). suite() -> [{ct_hooks,[ts_install_cth]}]. @@ -52,7 +53,7 @@ groups() -> rel_ops,rel_op_combinations, literal_type_tests,basic_andalso_orelse,traverse_dcd, check_qlc_hrl,andalso_semi,t_tuple_size,binary_part, - bad_constants,bad_guards]}]. + bad_constants,bad_guards,scotland,guard_in_catch]}]. init_per_suite(Config) -> Config. @@ -1831,6 +1832,80 @@ bad_guards_2(M, [_]) when M#{a := 0, b => 0}, map_size(M) -> bad_guards_3(M, [_]) when is_map(M) andalso M#{a := 0, b => 0}, length(M) -> ok. +%% beam_bool would remove the initialization of {y,0}. +%% (Thanks to Thomas Arts and QuickCheck.) + +scotland(_Config) -> + million = do_scotland(placed), + {'EXIT',{{badmatch,placed},_}} = (catch do_scotland(false)), + {'EXIT',{{badmatch,placed},_}} = (catch do_scotland(true)), + {'EXIT',{{badmatch,placed},_}} = (catch do_scotland(echo)), + ok. + +do_scotland(Echo) -> + found(case Echo of + Echo when true; Echo, Echo, Echo -> + Echo; + echo -> + [] + end, + Echo = placed). + +found(_, _) -> million. + +%% Building maps in a guard in a 'catch' would crash v3_codegen. + +guard_in_catch(_Config) -> + {'EXIT',{if_clause,_}} = do_guard_in_catch_map_1(#{}), + {'EXIT',{if_clause,_}} = do_guard_in_catch_map_1(#{a=>b}), + {'EXIT',{if_clause,_}} = do_guard_in_catch_map_1(atom), + + {'EXIT',{if_clause,_}} = do_guard_in_catch_map_2(#{}), + {'EXIT',{if_clause,_}} = do_guard_in_catch_map_2(#{a=>b}), + {'EXIT',{if_clause,_}} = do_guard_in_catch_map_2(atom), + + {'EXIT',{if_clause,_}} = (catch do_guard_in_catch_map_3()), + + {'EXIT',{if_clause,_}} = do_guard_in_catch_bin(42), + {'EXIT',{if_clause,_}} = do_guard_in_catch_bin(<<1,2,3>>), + {'EXIT',{if_clause,_}} = do_guard_in_catch_bin(atom), + {'EXIT',{if_clause,_}} = do_guard_in_catch_bin(#{}), + + ok. + +do_guard_in_catch_map_1(From) -> + catch + if + From#{[] => sufficient} -> + saint + end. + +do_guard_in_catch_map_2(From) -> + catch + if + From#{From => sufficient} -> + saint + end. + +do_guard_in_catch_map_3() -> + try + if [] -> solo end + catch + Friendly when Friendly#{0 => []} -> minutes + after + membership + end. + +do_guard_in_catch_bin(From) -> + %% Would not crash v3_codegen, but there would be an unnecessary + %% 'move' to a Y register. + catch + if + <<From:32>> -> + saint + end. + + %% Call this function to turn off constant propagation. id(I) -> I. diff --git a/lib/compiler/test/map_SUITE.erl b/lib/compiler/test/map_SUITE.erl index abc12a359d..cff3b5deb4 100644 --- a/lib/compiler/test/map_SUITE.erl +++ b/lib/compiler/test/map_SUITE.erl @@ -63,7 +63,10 @@ %% errors in 17.0-rc1 t_update_values/1, t_expand_map_update/1, - t_export/1 + t_export/1, + + %% errors in 18 + t_register_corruption/1 ]). suite() -> []. @@ -108,11 +111,13 @@ all() -> t_build_and_match_nil, t_build_and_match_structure, - %% errors in 17.0-rc1 t_update_values, t_expand_map_update, - t_export + t_export, + + %% errors in 18 + t_register_corruption ]. groups() -> []. @@ -878,6 +883,9 @@ t_update_map_expressions(Config) when is_list(Config) -> %% Error cases. {'EXIT',{{badmap,<<>>},_}} = (catch (id(<<>>))#{ a := 42, b => 2 }), {'EXIT',{{badmap,[]},_}} = (catch (id([]))#{ a := 42, b => 2 }), + {'EXIT',{{badmap,_},_}} = + (catch (fun t_update_map_expressions/1)#{u => 42}), + ok. @@ -1827,6 +1835,53 @@ map_guard_sequence_mixed(K1,K2,M) -> #{ K1 := 1, c := 6, K2 := 8, h := 3} -> 6 end. +%% register corruption discovered in 18 due to +%% get_map_elements might destroys registers when fail-label is taken. +%% Only seen when patterns have two targets, +%% specifically: we copy one register, and then jump. +%% {test,is_map,{f,5},[{x,1}]}. +%% +%% {get_map_elements,{f,7},{x,1},{list,[{atom,a},{x,1},{atom,b},{x,2}]}}. +%% %% if 'a' exists but not 'b' {x,1} is overwritten, jump {f,7} +%% +%% {move,{integer,1},{x,0}}. +%% {call_only,3,{f,10}}. +%% +%% {label,7}. +%% {get_map_elements,{f,8},{x,1},{list,[{atom,b},{x,2}]}}. +%% %% {x,1} (src) is now corrupt +%% +%% {move,{x,0},{x,1}}. +%% {move,{integer,2},{x,0}}. +%% {call_only,3,{f,10}}. +%% +%% Only happens in beam_block opt_move pass with two destinations. + +t_register_corruption(Config) when is_list(Config) -> + M = #{a=> <<"value">>, c=>3}, + {3,wanted,<<"value">>} = register_corruption_bar(M,wanted), + {3,wanted,<<"value">>} = register_corruption_foo(wanted,M), + ok. + +register_corruption_foo(A,#{a := V1, b := V2}) -> + register_corruption_dummy_call(1,V1,V2); +register_corruption_foo(A,#{b := V}) -> + register_corruption_dummy_call(2,A,V); +register_corruption_foo(A,#{a := V}) -> + register_corruption_dummy_call(3,A,V). + +register_corruption_bar(M,A) -> + case M of + #{a := V1, b := V2} -> + register_corruption_dummy_call(1,V1,V2); + #{b := V} -> + register_corruption_dummy_call(2,A,V); + #{a := V} -> + register_corruption_dummy_call(3,A,V) + end. + + +register_corruption_dummy_call(A,B,C) -> {A,B,C}. t_frequency_table(Config) when is_list(Config) -> diff --git a/lib/compiler/vsn.mk b/lib/compiler/vsn.mk index 69f71ba5dd..c83455240d 100644 --- a/lib/compiler/vsn.mk +++ b/lib/compiler/vsn.mk @@ -1 +1 @@ -COMPILER_VSN = 6.0 +COMPILER_VSN = 6.0.3 diff --git a/lib/cosNotification/doc/src/notes.xml b/lib/cosNotification/doc/src/notes.xml index d7e8101164..f896d219b5 100644 --- a/lib/cosNotification/doc/src/notes.xml +++ b/lib/cosNotification/doc/src/notes.xml @@ -32,7 +32,21 @@ <file>notes.xml</file> </header> - <section><title>cosNotification 1.2</title> + <section><title>cosNotification 1.2.1</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> Suppress Dialyzer warnings. </p> + <p> + Own Id: OTP-12862</p> + </item> + </list> + </section> + +</section> + +<section><title>cosNotification 1.2</title> <section><title>Improvements and New Features</title> <list> diff --git a/lib/cosNotification/src/CosNotifyFilter_Filter_impl.erl b/lib/cosNotification/src/CosNotifyFilter_Filter_impl.erl index 75510ebeca..0f997049e0 100644 --- a/lib/cosNotification/src/CosNotifyFilter_Filter_impl.erl +++ b/lib/cosNotification/src/CosNotifyFilter_Filter_impl.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% Copyright Ericsson AB 1999-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -336,6 +336,7 @@ match_structured(_,_,What) -> %% Returns : boolean() | %% {'EXCEPTION', CosNotifyFilter::UnsupportedFilterableData} %%----------------------------------------------------------- +-spec match_typed(_, _, _) -> no_return(). match_typed(_OE_THIS, _State, _Data) -> corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_NO}). diff --git a/lib/cosNotification/src/CosNotifyFilter_MappingFilter_impl.erl b/lib/cosNotification/src/CosNotifyFilter_MappingFilter_impl.erl index 3718664674..03c0e03be6 100644 --- a/lib/cosNotification/src/CosNotifyFilter_MappingFilter_impl.erl +++ b/lib/cosNotification/src/CosNotifyFilter_MappingFilter_impl.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% Copyright Ericsson AB 1999-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -298,6 +298,7 @@ match_structured(_,_,_) -> %% Returns : boolean() , #any{} (out-type) | %% {'EXCEPTION', CosNotifyFilter::UnsupportedFilterableData} %%----------------------------------------------------------- +-spec match_typed(_, _, _) -> no_return(). match_typed(_OE_THIS, _State, _Data) -> corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_NO}). diff --git a/lib/cosNotification/vsn.mk b/lib/cosNotification/vsn.mk index c1affdf0de..07b9bf474b 100644 --- a/lib/cosNotification/vsn.mk +++ b/lib/cosNotification/vsn.mk @@ -1,2 +1,2 @@ -COSNOTIFICATION_VSN = 1.2 +COSNOTIFICATION_VSN = 1.2.1 diff --git a/lib/cosTime/doc/src/notes.xml b/lib/cosTime/doc/src/notes.xml index cf842af81f..bf75f7f617 100644 --- a/lib/cosTime/doc/src/notes.xml +++ b/lib/cosTime/doc/src/notes.xml @@ -33,7 +33,21 @@ <file>notes.xml</file> </header> - <section><title>cosTime 1.2</title> + <section><title>cosTime 1.2.1</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> Suppress Dialyzer warnings. </p> + <p> + Own Id: OTP-12862</p> + </item> + </list> + </section> + +</section> + +<section><title>cosTime 1.2</title> <section><title>Improvements and New Features</title> <list> diff --git a/lib/cosTime/src/CosTime_TimeService_impl.erl b/lib/cosTime/src/CosTime_TimeService_impl.erl index f139998f42..72c65757ad 100644 --- a/lib/cosTime/src/CosTime_TimeService_impl.erl +++ b/lib/cosTime/src/CosTime_TimeService_impl.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% Copyright Ericsson AB 2000-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -107,6 +107,7 @@ universal_time(OE_THIS, State) -> %% Arguments: %% Returns : {'EXCEPTION", #'CosTime_TimeUnavailable'{}} %%----------------------------------------------------------- +-spec secure_universal_time(_, _) -> no_return(). secure_universal_time(_OE_THIS, _State) -> corba:raise(#'CosTime_TimeUnavailable'{}). diff --git a/lib/cosTime/vsn.mk b/lib/cosTime/vsn.mk index 32416f0087..39b457b53b 100644 --- a/lib/cosTime/vsn.mk +++ b/lib/cosTime/vsn.mk @@ -1,2 +1,2 @@ -COSTIME_VSN = 1.2 +COSTIME_VSN = 1.2.1 diff --git a/lib/cosTransactions/doc/src/notes.xml b/lib/cosTransactions/doc/src/notes.xml index cb45f8ed5e..76d14962b7 100644 --- a/lib/cosTransactions/doc/src/notes.xml +++ b/lib/cosTransactions/doc/src/notes.xml @@ -33,7 +33,21 @@ <file>notes.xml</file> </header> - <section><title>cosTransactions 1.3</title> + <section><title>cosTransactions 1.3.1</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> Suppress Dialyzer warnings. </p> + <p> + Own Id: OTP-12862</p> + </item> + </list> + </section> + +</section> + +<section><title>cosTransactions 1.3</title> <section><title>Improvements and New Features</title> <list> diff --git a/lib/cosTransactions/src/CosTransactions_TransactionFactory_impl.erl b/lib/cosTransactions/src/CosTransactions_TransactionFactory_impl.erl index e0d14299a3..e24bcb9a04 100644 --- a/lib/cosTransactions/src/CosTransactions_TransactionFactory_impl.erl +++ b/lib/cosTransactions/src/CosTransactions_TransactionFactory_impl.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2015. All Rights Reserved. +%% Copyright Ericsson AB 1999-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -169,6 +169,7 @@ create(_Self, _State, _TimeOut) -> %% Effect : %%------------------------------------------------------------ +-spec recreate(_, _, _) -> no_return(). recreate(_Self, _State, #'CosTransactions_PropagationContext'{current = _C}) -> corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_YES}). %recreate(Self, State, #'CosTransactions_PropagationContext'{current = C}) -> diff --git a/lib/cosTransactions/src/ETraP_Server_impl.erl b/lib/cosTransactions/src/ETraP_Server_impl.erl index 7b451e1762..5c7b5f6350 100644 --- a/lib/cosTransactions/src/ETraP_Server_impl.erl +++ b/lib/cosTransactions/src/ETraP_Server_impl.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2015. All Rights Reserved. +%% Copyright Ericsson AB 1999-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -675,6 +675,7 @@ is_same_transaction(Self, {Env, Local}, Coordinator) -> %% Effect : %%------------------------------------------------------------ +-spec is_related_transaction(_, _, _) -> no_return(). is_related_transaction(_Self, {_Env, _Local}, _Coordinator) -> corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_YES}). % type_check(?tr_get_typeCheck(Env), ?tr_Coordinator, @@ -689,6 +690,7 @@ is_related_transaction(_Self, {_Env, _Local}, _Coordinator) -> %% Effect : %%------------------------------------------------------------ +-spec is_ancestor_transaction(_, _, _) -> no_return(). is_ancestor_transaction(_Self, {_Env, _Local}, _Coordinator) -> corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_YES}). % type_check(?tr_get_typeCheck(Env), ?tr_Coordinator, @@ -826,6 +828,7 @@ register_subtran_aware(Self, {Env, Local}, SubTrAwareResource) -> %% Effect : %%------------------------------------------------------------ +-spec register_synchronization(_, _, _) -> no_return(). register_synchronization(_Self, {_Env, _Local}, _Synchronization) -> corba:raise(#'CosTransactions_SynchronizationUnavailable'{}). @@ -950,6 +953,7 @@ create_subtransaction(Self, {Env, Local}) -> %% Effect : %%------------------------------------------------------------ +-spec get_txcontext(_, _) -> no_return(). get_txcontext(_Self, {_Env, _Local}) -> corba:raise(#'CosTransactions_Unavailable'{}). diff --git a/lib/cosTransactions/vsn.mk b/lib/cosTransactions/vsn.mk index 929f8c73d1..3a18cae384 100644 --- a/lib/cosTransactions/vsn.mk +++ b/lib/cosTransactions/vsn.mk @@ -1 +1 @@ -COSTRANSACTIONS_VSN = 1.3 +COSTRANSACTIONS_VSN = 1.3.1 diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 9de8dc74c2..4966701e41 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -2042,6 +2042,7 @@ static ERL_NIF_TERM aes_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM a ErlNifBinary key_bin, data_bin; AES_KEY aes_key; int i; + int j; unsigned char* ret_ptr; ERL_NIF_TERM ret; @@ -2064,7 +2065,9 @@ static ERL_NIF_TERM aes_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM a } ret_ptr = enif_make_new_binary(env, data_bin.size, &ret); - AES_ecb_encrypt(data_bin.data, ret_ptr, &aes_key, i); + for (j = 0; j < data_bin.size; j += 16) { + AES_ecb_encrypt(data_bin.data+j, ret_ptr+j, &aes_key, i); + } CONSUME_REDS(env,data_bin); return ret; } @@ -3566,6 +3569,9 @@ static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg) } else goto out_err; + if (!group) + goto out_err; + if (enif_inspect_binary(env, prime[2], &seed)) { EC_GROUP_set_seed(group, seed.data, seed.size); } diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml index 385a583883..563a090e98 100644 --- a/lib/crypto/doc/src/crypto.xml +++ b/lib/crypto/doc/src/crypto.xml @@ -66,29 +66,29 @@ <section> <title>DATA TYPES </title> - <p><code>key_value() = integer() | binary() </code></p> + <code>key_value() = integer() | binary() </code> <p>Always <c>binary()</c> when used as return value</p> - <p><code>rsa_public() = [key_value()] = [E, N] </code></p> + <code>rsa_public() = [key_value()] = [E, N] </code> <p> Where E is the public exponent and N is public modulus. </p> - <p><code>rsa_private() = [key_value()] = [E, N, D] | [E, N, D, P1, P2, E1, E2, C] </code></p> + <code>rsa_private() = [key_value()] = [E, N, D] | [E, N, D, P1, P2, E1, E2, C] </code> <p>Where E is the public exponent, N is public modulus and D is the private exponent.The longer key format contains redundant information that will make the calculation faster. P1,P2 are first and second prime factors. E1,E2 are first and second exponents. C is the CRT coefficient. Terminology is taken from <url href="http://www.ietf.org/rfc/rfc3477.txt"> RFC 3447</url>.</p> - <p><code>dss_public() = [key_value()] = [P, Q, G, Y] </code></p> + <code>dss_public() = [key_value()] = [P, Q, G, Y] </code> <p>Where P, Q and G are the dss parameters and Y is the public key.</p> - <p><code>dss_private() = [key_value()] = [P, Q, G, X] </code></p> + <code>dss_private() = [key_value()] = [P, Q, G, X] </code> <p>Where P, Q and G are the dss parameters and X is the private key.</p> - <p><code>srp_public() = key_value() </code></p> + <code>srp_public() = key_value() </code> <p>Where is <c>A</c> or <c>B</c> from <url href="http://srp.stanford.edu/design.html">SRP design</url></p> - <p><code>srp_private() = key_value() </code></p> + <code>srp_private() = key_value() </code> <p>Where is <c>a</c> or <c>b</c> from <url href="http://srp.stanford.edu/design.html">SRP design</url></p> <p>Where Verifier is <c>v</c>, Generator is <c>g</c> and Prime is<c> N</c>, DerivedKey is <c>X</c>, and Scrambler is @@ -96,29 +96,29 @@ Version = '3' | '6' | '6a' </p> - <p><code>dh_public() = key_value() </code></p> + <code>dh_public() = key_value() </code> - <p><code>dh_private() = key_value() </code></p> + <code>dh_private() = key_value() </code> - <p><code>dh_params() = [key_value()] = [P, G] </code></p> + <code>dh_params() = [key_value()] = [P, G] </code> - <p><code>ecdh_public() = key_value() </code></p> + <code>ecdh_public() = key_value() </code> - <p><code>ecdh_private() = key_value() </code></p> + <code>ecdh_private() = key_value() </code> - <p><code>ecdh_params() = ec_named_curve() | ec_explicit_curve()</code></p> + <code>ecdh_params() = ec_named_curve() | ec_explicit_curve()</code> - <p><code>ec_explicit_curve() = - {ec_field(), Prime :: key_value(), Point :: key_value(), Order :: integer(), CoFactor :: none | integer()} </code></p> + <code>ec_explicit_curve() = + {ec_field(), Prime :: key_value(), Point :: key_value(), Order :: integer(), CoFactor :: none | integer()} </code> - <p><code>ec_field() = {prime_field, Prime :: integer()} | - {characteristic_two_field, M :: integer(), Basis :: ec_basis()}</code></p> + <code>ec_field() = {prime_field, Prime :: integer()} | + {characteristic_two_field, M :: integer(), Basis :: ec_basis()}</code> - <p><code>ec_basis() = {tpbasis, K :: non_neg_integer()} | + <code>ec_basis() = {tpbasis, K :: non_neg_integer()} | {ppbasis, K1 :: non_neg_integer(), K2 :: non_neg_integer(), K3 :: non_neg_integer()} | - onbasis</code></p> + onbasis</code> - <p><code>ec_named_curve() -> + <code>ec_named_curve() -> sect571r1| sect571k1| sect409r1| sect409k1| secp521r1| secp384r1| secp224r1| secp224k1| secp192k1| secp160r2| secp128r2| secp128r1| sect233r1| sect233k1| sect193r2| sect193r1| sect131r2| sect131r1| sect283r1| sect283k1| sect163r2| secp256k1| secp160k1| secp160r1| @@ -128,42 +128,42 @@ brainpoolP224t1| brainpoolP256r1| brainpoolP256t1| brainpoolP320r1| brainpoolP320t1| brainpoolP384r1| brainpoolP384t1| brainpoolP512r1| brainpoolP512t1 </code> - Note that the <em>sect</em> curves are GF2m (characteristic two) curves and are only supported if the + <p>Note that the <em>sect</em> curves are GF2m (characteristic two) curves and are only supported if the underlying OpenSSL has support for them. See also <seealso marker="#supports-0">crypto:supports/0</seealso> </p> - <p><code>stream_cipher() = rc4 | aes_ctr </code></p> + <code>stream_cipher() = rc4 | aes_ctr </code> - <p><code>block_cipher() = aes_cbc128 | aes_cfb8 | aes_cfb128 | aes_ige256 | blowfish_cbc | + <code>block_cipher() = aes_cbc128 | aes_cfb8 | aes_cfb128 | aes_ige256 | blowfish_cbc | blowfish_cfb64 | des_cbc | des_cfb | des3_cbc | des3_cbf - | des_ede3 | rc2_cbc </code></p> + | des_ede3 | rc2_cbc </code> - <p><code>aead_cipher() = aes_gcm | chacha20_poly1305 </code></p> + <code>aead_cipher() = aes_gcm | chacha20_poly1305 </code> - <p><code>stream_key() = aes_key() | rc4_key() </code></p> + <code>stream_key() = aes_key() | rc4_key() </code> - <p><code>block_key() = aes_key() | blowfish_key() | des_key()| des3_key() </code></p> + <code>block_key() = aes_key() | blowfish_key() | des_key()| des3_key() </code> - <p><code>aes_key() = iodata() </code> Key length is 128, 192 or 256 bits</p> + <code>aes_key() = iodata() </code> <p>Key length is 128, 192 or 256 bits</p> - <p><code>rc4_key() = iodata() </code> Variable key length from 8 bits up to 2048 bits (usually between 40 and 256)</p> + <code>rc4_key() = iodata() </code> <p>Variable key length from 8 bits up to 2048 bits (usually between 40 and 256)</p> - <p><code>blowfish_key() = iodata() </code> Variable key length from 32 bits up to 448 bits</p> + <code>blowfish_key() = iodata() </code> <p>Variable key length from 32 bits up to 448 bits</p> - <p><code>des_key() = iodata() </code> Key length is 64 bits (in CBC mode only 8 bits are used)</p> + <code>des_key() = iodata() </code> <p>Key length is 64 bits (in CBC mode only 8 bits are used)</p> - <p><code>des3_key() = [binary(), binary(), binary()] </code> Each key part is 64 bits (in CBC mode only 8 bits are used)</p> + <code>des3_key() = [binary(), binary(), binary()] </code> <p>Each key part is 64 bits (in CBC mode only 8 bits are used)</p> - <p><code>digest_type() = md5 | sha | sha224 | sha256 | sha384 | sha512</code></p> + <code>digest_type() = md5 | sha | sha224 | sha256 | sha384 | sha512</code> - <p><code> hash_algorithms() = md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512 </code> md4 is also supported for hash_init/1 and hash/2. + <code> hash_algorithms() = md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512 </code> <p>md4 is also supported for hash_init/1 and hash/2. Note that both md4 and md5 are recommended only for compatibility with existing applications. </p> - <p><code> cipher_algorithms() = des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 | - blowfish_cbc | blowfish_cfb64 | aes_cbc128 | aes_cfb8 | aes_cfb128| aes_cbc256 | aes_ige256 | aes_gcm | chacha20_poly1305 | rc2_cbc | aes_ctr| rc4 </code> </p> - <p><code> public_key_algorithms() = rsa |dss | ecdsa | dh | ecdh | ec_gf2m</code> - Note that ec_gf2m is not strictly a public key algorithm, but a restriction on what curves are supported + <code> cipher_algorithms() = des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 | + blowfish_cbc | blowfish_cfb64 | aes_cbc128 | aes_cfb8 | aes_cfb128| aes_cbc256 | aes_ige256 | aes_gcm | chacha20_poly1305 | rc2_cbc | aes_ctr| rc4 </code> + <code> public_key_algorithms() = rsa |dss | ecdsa | dh | ecdh | ec_gf2m</code> + <p>Note that ec_gf2m is not strictly a public key algorithm, but a restriction on what curves are supported with ecdsa and ecdh. </p> @@ -381,8 +381,8 @@ </type> <desc> <p>Computes a HMAC of type <c>Type</c> from <c>Data</c> using - <c>Key</c> as the authentication key.</p> <c>MacLength</c> - will limit the size of the resultant <c>Mac</c>. + <c>Key</c> as the authentication key.</p> <p><c>MacLength</c> + will limit the size of the resultant <c>Mac</c>.</p> </desc> </func> @@ -601,8 +601,11 @@ </type> <desc> <p>Generates N bytes randomly uniform 0..255, and returns the - result in a binary. Uses the <c>crypto</c> library pseudo-random - number generator.</p> + result in a binary. Uses the <c>crypto</c> library pseudo-random + number generator.</p> + <p>This function is not recommended for cryptographic purposes. + Please use <seealso marker="#strong_rand_bytes/1"> + strong_rand_bytes/1</seealso> instead.</p> </desc> </func> @@ -617,7 +620,7 @@ RAND_seed function from openssl. Only use this if the system you are running on does not have enough "randomness" built in. Normally this is when <seealso marker="#strong_rand_bytes/1"> - stong_rand_bytes/1</seealso> returns <c>low_entropy</c></p> + strong_rand_bytes/1</seealso> returns <c>low_entropy</c></p> </desc> </func> @@ -650,7 +653,7 @@ <p>Creates a digital signature.</p> <p>Algorithm <c>dss</c> can only be used together with digest type <c>sha</c>.</p> - See also <seealso marker="public_key:public_key#sign-3">public_key:sign/3</seealso> + <p>See also <seealso marker="public_key:public_key#sign-3">public_key:sign/3</seealso>.</p> </desc> </func> @@ -710,7 +713,7 @@ </type> <desc> <p>Initializes the state for use in streaming AES encryption using Counter mode (CTR). - <c>Key</c> is the AES key and must be either 128, 192, or 256 bts long. <c>IVec</c> is + <c>Key</c> is the AES key and must be either 128, 192, or 256 bits long. <c>IVec</c> is an arbitrary initializing vector of 128 bits (16 bytes). This state is for use with <seealso marker="#stream_encrypt-2">stream_encrypt</seealso> and <seealso marker="#stream_decrypt-2">stream_decrypt</seealso>.</p> @@ -802,7 +805,7 @@ <p>Algorithm <c>dss</c> can only be used together with digest type <c>sha</c>.</p> - See also <seealso marker="public_key:public_key#verify-4">public_key:verify/4</seealso> + <p>See also <seealso marker="public_key:public_key#verify-4">public_key:verify/4</seealso>.</p> </desc> </func> diff --git a/lib/crypto/doc/src/notes.xml b/lib/crypto/doc/src/notes.xml index e2b90eca75..0138eb6ad2 100644 --- a/lib/crypto/doc/src/notes.xml +++ b/lib/crypto/doc/src/notes.xml @@ -31,6 +31,60 @@ </header> <p>This document describes the changes made to the Crypto application.</p> +<section><title>Crypto 3.6.3</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix bug for <c>aes_ecb</c> block crypto when data is + larger than 16 bytes.</p> + <p> + Own Id: OTP-13249</p> + </item> + <item> + <p> + Improve portability of ECC tests in Crypto and SSL for + "exotic" OpenSSL versions.</p> + <p> + Own Id: OTP-13311</p> + </item> + </list> + </section> + +</section> + +<section><title>Crypto 3.6.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Small documentation fixes</p> + <p> + Own Id: OTP-13017</p> + </item> + </list> + </section> + +</section> + +<section><title>Crypto 3.6.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Make <c>crypto:ec_curves/0</c> return empty list if + elliptic curve is not supported at all.</p> + <p> + Own Id: OTP-12944</p> + </item> + </list> + </section> + +</section> + <section><title>Crypto 3.6</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/crypto/src/crypto_ec_curves.erl b/lib/crypto/src/crypto_ec_curves.erl index fe17643d96..002b03b80c 100644 --- a/lib/crypto/src/crypto_ec_curves.erl +++ b/lib/crypto/src/crypto_ec_curves.erl @@ -4,11 +4,13 @@ curves() -> CryptoSupport = crypto:supports(), - HasGF2m = proplists:get_bool(ec_gf2m, proplists:get_value(public_keys, CryptoSupport)), - prime_curves() ++ characteristic_two_curves(HasGF2m). + PubKeys = proplists:get_value(public_keys, CryptoSupport), + HasEC = proplists:get_bool(ecdh, PubKeys), + HasGF2m = proplists:get_bool(ec_gf2m, PubKeys), + prime_curves(HasEC) ++ characteristic_two_curves(HasGF2m). -prime_curves() -> +prime_curves(true) -> [secp112r1,secp112r2,secp128r1,secp128r2,secp160k1,secp160r1,secp160r2, secp192r1,secp192k1,secp224k1,secp224r1,secp256k1,secp256r1,secp384r1, secp521r1,prime192v1,prime192v2,prime192v3,prime239v1,prime239v2,prime239v3, @@ -16,7 +18,9 @@ prime_curves() -> brainpoolP160r1,brainpoolP160t1,brainpoolP192r1,brainpoolP192t1, brainpoolP224r1,brainpoolP224t1,brainpoolP256r1,brainpoolP256t1, brainpoolP320r1,brainpoolP320t1,brainpoolP384r1,brainpoolP384t1, - brainpoolP512r1,brainpoolP512t1]. + brainpoolP512r1,brainpoolP512t1]; +prime_curves(_) -> + []. characteristic_two_curves(true) -> [sect113r1,sect113r2,sect131r1,sect131r2,sect163k1,sect163r1, diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index e84f5e1075..307fc4b019 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -1301,7 +1301,23 @@ aes_ecb() -> <<"0000000000000000">>}, {aes_ecb, <<"FEDCBA9876543210">>, - <<"FFFFFFFFFFFFFFFF">>} + <<"FFFFFFFFFFFFFFFF">>}, + %% AES ECB test vectors from http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + %% F.1.1 ECB-AES128.Encrypt, F.1.2 ECB-AES128.Decrypt + {aes_ecb, + hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"), + hexstr2bin("6bc1bee22e409f96e93d7e117393172a" + "ae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411e5fbc1191a0a52ef" + "f69f2445df4f9b17ad2b417be66c3710")}, + %% F.1.5 ECB-AES256.Encrypt, F.1.6 ECB-AES256.Decrypt + {aes_ecb, + hexstr2bin("603deb1015ca71be2b73aef0857d7781" + "1f352c073b6108d72d9810a30914dff4"), + hexstr2bin("6bc1bee22e409f96e93d7e117393172a" + "ae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411e5fbc1191a0a52ef" + "f69f2445df4f9b17ad2b417be66c3710")} ]. aes_ige256() -> @@ -1885,7 +1901,7 @@ dss_params() -> 18320614775012672475365915366944922415598782131828709277168615511695849821411624805195787607930033958243224786899641459701930253094446221381818858674389863050420226114787005820357372837321561754462061849169568607689530279303056075793886577588606958623645901271866346406773590024901668622321064384483571751669]. ec_key_named() -> - Curve = secp112r2, + Curve = hd(crypto:ec_curves()), {D2_pub, D2_priv} = crypto:generate_key(ecdh, Curve), {[D2_priv, Curve], [D2_pub, Curve]}. @@ -2054,88 +2070,94 @@ srp(ClientPrivate, Generator, Prime, Version, Verifier, ServerPublic, ServerPriv SessionKey}. ecdh() -> %% http://csrc.nist.gov/groups/STM/cavp/ - [{ecdh, hexstr2point("42ea6dd9969dd2a61fea1aac7f8e98edcc896c6e55857cc0", "dfbe5d7c61fac88b11811bde328e8a0d12bf01a9d204b523"), - hexstr2bin("f17d3fea367b74d340851ca4270dcb24c271f445bed9d527"), - secp192r1, - hexstr2bin("803d8ab2e5b6e6fca715737c3a82f7ce3c783124f6d51cd0")}, - {ecdh, hexstr2point("deb5712fa027ac8d2f22c455ccb73a91e17b6512b5e030e7", "7e2690a02cc9b28708431a29fb54b87b1f0c14e011ac2125"), - hexstr2bin("56e853349d96fe4c442448dacb7cf92bb7a95dcf574a9bd5"), - secp192r1, - hexstr2bin("c208847568b98835d7312cef1f97f7aa298283152313c29d")}, - {ecdh, hexstr2point("af33cd0629bc7e996320a3f40368f74de8704fa37b8fab69abaae280", "882092ccbba7930f419a8a4f9bb16978bbc3838729992559a6f2e2d7"), - hexstr2bin("8346a60fc6f293ca5a0d2af68ba71d1dd389e5e40837942df3e43cbd"), - secp224r1, - hexstr2bin("7d96f9a3bd3c05cf5cc37feb8b9d5209d5c2597464dec3e9983743e8")}, - {ecdh, hexstr2point("13bfcd4f8e9442393cab8fb46b9f0566c226b22b37076976f0617a46", "eeb2427529b288c63c2f8963c1e473df2fca6caa90d52e2f8db56dd4"), - hexstr2bin("043cb216f4b72cdf7629d63720a54aee0c99eb32d74477dac0c2f73d"), - secp224r1, - hexstr2bin("ee93ce06b89ff72009e858c68eb708e7bc79ee0300f73bed69bbca09")}, - {ecdh, hexstr2point("700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287", "db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac"), - hexstr2bin("7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534"), - secp256r1, - hexstr2bin("46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b")}, - {ecdh, hexstr2point("809f04289c64348c01515eb03d5ce7ac1a8cb9498f5caa50197e58d43a86a7ae", "b29d84e811197f25eba8f5194092cb6ff440e26d4421011372461f579271cda3"), - hexstr2bin("38f65d6dce47676044d58ce5139582d568f64bb16098d179dbab07741dd5caf5"), - secp256r1, - hexstr2bin("057d636096cb80b67a8c038c890e887d1adfa4195e9b3ce241c8a778c59cda67")}, - {ecdh, hexstr2point("a7c76b970c3b5fe8b05d2838ae04ab47697b9eaf52e764592efda27fe7513272734466b400091adbf2d68c58e0c50066", "ac68f19f2e1cb879aed43a9969b91a0839c4c38a49749b661efedf243451915ed0905a32b060992b468c64766fc8437a"), - hexstr2bin("3cc3122a68f0d95027ad38c067916ba0eb8c38894d22e1b15618b6818a661774ad463b205da88cf699ab4d43c9cf98a1"), - secp384r1, - hexstr2bin("5f9d29dc5e31a163060356213669c8ce132e22f57c9a04f40ba7fcead493b457e5621e766c40a2e3d4d6a04b25e533f1")}, - {ecdh, hexstr2point("30f43fcf2b6b00de53f624f1543090681839717d53c7c955d1d69efaf0349b7363acb447240101cbb3af6641ce4b88e0", "25e46c0c54f0162a77efcc27b6ea792002ae2ba82714299c860857a68153ab62e525ec0530d81b5aa15897981e858757"), - hexstr2bin("92860c21bde06165f8e900c687f8ef0a05d14f290b3f07d8b3a8cc6404366e5d5119cd6d03fb12dc58e89f13df9cd783"), - secp384r1, - hexstr2bin("a23742a2c267d7425fda94b93f93bbcc24791ac51cd8fd501a238d40812f4cbfc59aac9520d758cf789c76300c69d2ff")}, - {ecdh, hexstr2point("00685a48e86c79f0f0875f7bc18d25eb5fc8c0b07e5da4f4370f3a9490340854334b1e1b87fa395464c60626124a4e70d0f785601d37c09870ebf176666877a2046d", "01ba52c56fc8776d9e8f5db4f0cc27636d0b741bbe05400697942e80b739884a83bde99e0f6716939e632bc8986fa18dccd443a348b6c3e522497955a4f3c302f676"), - hexstr2bin("017eecc07ab4b329068fba65e56a1f8890aa935e57134ae0ffcce802735151f4eac6564f6ee9974c5e6887a1fefee5743ae2241bfeb95d5ce31ddcb6f9edb4d6fc47"), - secp521r1, - hexstr2bin("005fc70477c3e63bc3954bd0df3ea0d1f41ee21746ed95fc5e1fdf90930d5e136672d72cc770742d1711c3c3a4c334a0ad9759436a4d3c5bf6e74b9578fac148c831")}, - {ecdh, hexstr2point("01df277c152108349bc34d539ee0cf06b24f5d3500677b4445453ccc21409453aafb8a72a0be9ebe54d12270aa51b3ab7f316aa5e74a951c5e53f74cd95fc29aee7a", "013d52f33a9f3c14384d1587fa8abe7aed74bc33749ad9c570b471776422c7d4505d9b0a96b3bfac041e4c6a6990ae7f700e5b4a6640229112deafa0cd8bb0d089b0"), - hexstr2bin("00816f19c1fb10ef94d4a1d81c156ec3d1de08b66761f03f06ee4bb9dcebbbfe1eaa1ed49a6a990838d8ed318c14d74cc872f95d05d07ad50f621ceb620cd905cfb8"), - secp521r1, - hexstr2bin("000b3920ac830ade812c8f96805da2236e002acbbf13596a9ab254d44d0e91b6255ebf1229f366fb5a05c5884ef46032c26d42189273ca4efa4c3db6bd12a6853759")}, - - %% RFC-6954, Appendix A - {ecdh, hexstr2point("A9C21A569759DA95E0387041184261440327AFE33141CA04B82DC92E", - "98A0F75FBBF61D8E58AE5511B2BCDBE8E549B31E37069A2825F590C1"), - hexstr2bin("6060552303899E2140715816C45B57D9B42204FB6A5BF5BEAC10DB00"), - brainpoolP224r1, - hexstr2bin("1A4BFE705445120C8E3E026699054104510D119757B74D5FE2462C66")}, - {ecdh, hexstr2point("034A56C550FF88056144E6DD56070F54B0135976B5BF77827313F36B", - "75165AD99347DC86CAAB1CBB579E198EAF88DC35F927B358AA683681"), - hexstr2bin("39F155483CEE191FBECFE9C81D8AB1A03CDA6790E7184ACE44BCA161"), - brainpoolP224r1, - hexstr2bin("1A4BFE705445120C8E3E026699054104510D119757B74D5FE2462C66")}, - {ecdh, hexstr2point("44106E913F92BC02A1705D9953A8414DB95E1AAA49E81D9E85F929A8E3100BE5", - "8AB4846F11CACCB73CE49CBDD120F5A900A69FD32C272223F789EF10EB089BDC"), - hexstr2bin("55E40BC41E37E3E2AD25C3C6654511FFA8474A91A0032087593852D3E7D76BD3"), - brainpoolP256r1, - hexstr2bin("89AFC39D41D3B327814B80940B042590F96556EC91E6AE7939BCE31F3A18BF2B")}, - {ecdh, hexstr2point("8D2D688C6CF93E1160AD04CC4429117DC2C41825E1E9FCA0ADDD34E6F1B39F7B", - "990C57520812BE512641E47034832106BC7D3E8DD0E4C7F1136D7006547CEC6A"), - hexstr2bin("81DB1EE100150FF2EA338D708271BE38300CB54241D79950F77B063039804F1D"), - brainpoolP256r1, - hexstr2bin("89AFC39D41D3B327814B80940B042590F96556EC91E6AE7939BCE31F3A18BF2B")}, - {ecdh, hexstr2point("68B665DD91C195800650CDD363C625F4E742E8134667B767B1B476793588F885AB698C852D4A6E77A252D6380FCAF068", - "55BC91A39C9EC01DEE36017B7D673A931236D2F1F5C83942D049E3FA20607493E0D038FF2FD30C2AB67D15C85F7FAA59"), - hexstr2bin("032640BC6003C59260F7250C3DB58CE647F98E1260ACCE4ACDA3DD869F74E01F8BA5E0324309DB6A9831497ABAC96670"), - brainpoolP384r1, - hexstr2bin("0BD9D3A7EA0B3D519D09D8E48D0785FB744A6B355E6304BC51C229FBBCE239BBADF6403715C35D4FB2A5444F575D4F42")}, - {ecdh, hexstr2point("4D44326F269A597A5B58BBA565DA5556ED7FD9A8A9EB76C25F46DB69D19DC8CE6AD18E404B15738B2086DF37E71D1EB4", - "62D692136DE56CBE93BF5FA3188EF58BC8A3A0EC6C1E151A21038A42E9185329B5B275903D192F8D4E1F32FE9CC78C48"), - hexstr2bin("1E20F5E048A5886F1F157C74E91BDE2B98C8B52D58E5003D57053FC4B0BD65D6F15EB5D1EE1610DF870795143627D042"), - brainpoolP384r1, - hexstr2bin("0BD9D3A7EA0B3D519D09D8E48D0785FB744A6B355E6304BC51C229FBBCE239BBADF6403715C35D4FB2A5444F575D4F42")}, - {ecdh, hexstr2point("0A420517E406AAC0ACDCE90FCD71487718D3B953EFD7FBEC5F7F27E28C6149999397E91E029E06457DB2D3E640668B392C2A7E737A7F0BF04436D11640FD09FD", - "72E6882E8DB28AAD36237CD25D580DB23783961C8DC52DFA2EC138AD472A0FCEF3887CF62B623B2A87DE5C588301EA3E5FC269B373B60724F5E82A6AD147FDE7"), - hexstr2bin("230E18E1BCC88A362FA54E4EA3902009292F7F8033624FD471B5D8ACE49D12CFABBC19963DAB8E2F1EBA00BFFB29E4D72D13F2224562F405CB80503666B25429"), - brainpoolP512r1, - hexstr2bin("A7927098655F1F9976FA50A9D566865DC530331846381C87256BAF3226244B76D36403C024D7BBF0AA0803EAFF405D3D24F11A9B5C0BEF679FE1454B21C4CD1F")}, - {ecdh, hexstr2point("9D45F66DE5D67E2E6DB6E93A59CE0BB48106097FF78A081DE781CDB31FCE8CCBAAEA8DD4320C4119F1E9CD437A2EAB3731FA9668AB268D871DEDA55A5473199F", - "2FDC313095BCDD5FB3A91636F07A959C8E86B5636A1E930E8396049CB481961D365CC11453A06C719835475B12CB52FC3C383BCE35E27EF194512B71876285FA"), - hexstr2bin("16302FF0DBBB5A8D733DAB7141C1B45ACBC8715939677F6A56850A38BD87BD59B09E80279609FF333EB9D4C061231FB26F92EEB04982A5F1D1764CAD57665422"), - brainpoolP512r1, - hexstr2bin("A7927098655F1F9976FA50A9D566865DC530331846381C87256BAF3226244B76D36403C024D7BBF0AA0803EAFF405D3D24F11A9B5C0BEF679FE1454B21C4CD1F")}]. + Curves = crypto:ec_curves(), + TestCases = + [{ecdh, hexstr2point("42ea6dd9969dd2a61fea1aac7f8e98edcc896c6e55857cc0", "dfbe5d7c61fac88b11811bde328e8a0d12bf01a9d204b523"), + hexstr2bin("f17d3fea367b74d340851ca4270dcb24c271f445bed9d527"), + secp192r1, + hexstr2bin("803d8ab2e5b6e6fca715737c3a82f7ce3c783124f6d51cd0")}, + {ecdh, hexstr2point("deb5712fa027ac8d2f22c455ccb73a91e17b6512b5e030e7", "7e2690a02cc9b28708431a29fb54b87b1f0c14e011ac2125"), + hexstr2bin("56e853349d96fe4c442448dacb7cf92bb7a95dcf574a9bd5"), + secp192r1, + hexstr2bin("c208847568b98835d7312cef1f97f7aa298283152313c29d")}, + {ecdh, hexstr2point("af33cd0629bc7e996320a3f40368f74de8704fa37b8fab69abaae280", "882092ccbba7930f419a8a4f9bb16978bbc3838729992559a6f2e2d7"), + hexstr2bin("8346a60fc6f293ca5a0d2af68ba71d1dd389e5e40837942df3e43cbd"), + secp224r1, + hexstr2bin("7d96f9a3bd3c05cf5cc37feb8b9d5209d5c2597464dec3e9983743e8")}, + {ecdh, hexstr2point("13bfcd4f8e9442393cab8fb46b9f0566c226b22b37076976f0617a46", "eeb2427529b288c63c2f8963c1e473df2fca6caa90d52e2f8db56dd4"), + hexstr2bin("043cb216f4b72cdf7629d63720a54aee0c99eb32d74477dac0c2f73d"), + secp224r1, + hexstr2bin("ee93ce06b89ff72009e858c68eb708e7bc79ee0300f73bed69bbca09")}, + {ecdh, hexstr2point("700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287", "db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac"), + hexstr2bin("7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534"), + secp256r1, + hexstr2bin("46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b")}, + {ecdh, hexstr2point("809f04289c64348c01515eb03d5ce7ac1a8cb9498f5caa50197e58d43a86a7ae", "b29d84e811197f25eba8f5194092cb6ff440e26d4421011372461f579271cda3"), + hexstr2bin("38f65d6dce47676044d58ce5139582d568f64bb16098d179dbab07741dd5caf5"), + secp256r1, + hexstr2bin("057d636096cb80b67a8c038c890e887d1adfa4195e9b3ce241c8a778c59cda67")}, + {ecdh, hexstr2point("a7c76b970c3b5fe8b05d2838ae04ab47697b9eaf52e764592efda27fe7513272734466b400091adbf2d68c58e0c50066", "ac68f19f2e1cb879aed43a9969b91a0839c4c38a49749b661efedf243451915ed0905a32b060992b468c64766fc8437a"), + hexstr2bin("3cc3122a68f0d95027ad38c067916ba0eb8c38894d22e1b15618b6818a661774ad463b205da88cf699ab4d43c9cf98a1"), + secp384r1, + hexstr2bin("5f9d29dc5e31a163060356213669c8ce132e22f57c9a04f40ba7fcead493b457e5621e766c40a2e3d4d6a04b25e533f1")}, + {ecdh, hexstr2point("30f43fcf2b6b00de53f624f1543090681839717d53c7c955d1d69efaf0349b7363acb447240101cbb3af6641ce4b88e0", "25e46c0c54f0162a77efcc27b6ea792002ae2ba82714299c860857a68153ab62e525ec0530d81b5aa15897981e858757"), + hexstr2bin("92860c21bde06165f8e900c687f8ef0a05d14f290b3f07d8b3a8cc6404366e5d5119cd6d03fb12dc58e89f13df9cd783"), + secp384r1, + hexstr2bin("a23742a2c267d7425fda94b93f93bbcc24791ac51cd8fd501a238d40812f4cbfc59aac9520d758cf789c76300c69d2ff")}, + {ecdh, hexstr2point("00685a48e86c79f0f0875f7bc18d25eb5fc8c0b07e5da4f4370f3a9490340854334b1e1b87fa395464c60626124a4e70d0f785601d37c09870ebf176666877a2046d", "01ba52c56fc8776d9e8f5db4f0cc27636d0b741bbe05400697942e80b739884a83bde99e0f6716939e632bc8986fa18dccd443a348b6c3e522497955a4f3c302f676"), + hexstr2bin("017eecc07ab4b329068fba65e56a1f8890aa935e57134ae0ffcce802735151f4eac6564f6ee9974c5e6887a1fefee5743ae2241bfeb95d5ce31ddcb6f9edb4d6fc47"), + secp521r1, + hexstr2bin("005fc70477c3e63bc3954bd0df3ea0d1f41ee21746ed95fc5e1fdf90930d5e136672d72cc770742d1711c3c3a4c334a0ad9759436a4d3c5bf6e74b9578fac148c831")}, + {ecdh, hexstr2point("01df277c152108349bc34d539ee0cf06b24f5d3500677b4445453ccc21409453aafb8a72a0be9ebe54d12270aa51b3ab7f316aa5e74a951c5e53f74cd95fc29aee7a", "013d52f33a9f3c14384d1587fa8abe7aed74bc33749ad9c570b471776422c7d4505d9b0a96b3bfac041e4c6a6990ae7f700e5b4a6640229112deafa0cd8bb0d089b0"), + hexstr2bin("00816f19c1fb10ef94d4a1d81c156ec3d1de08b66761f03f06ee4bb9dcebbbfe1eaa1ed49a6a990838d8ed318c14d74cc872f95d05d07ad50f621ceb620cd905cfb8"), + secp521r1, + hexstr2bin("000b3920ac830ade812c8f96805da2236e002acbbf13596a9ab254d44d0e91b6255ebf1229f366fb5a05c5884ef46032c26d42189273ca4efa4c3db6bd12a6853759")}, + + %% RFC-6954, Appendix A + {ecdh, hexstr2point("A9C21A569759DA95E0387041184261440327AFE33141CA04B82DC92E", + "98A0F75FBBF61D8E58AE5511B2BCDBE8E549B31E37069A2825F590C1"), + hexstr2bin("6060552303899E2140715816C45B57D9B42204FB6A5BF5BEAC10DB00"), + brainpoolP224r1, + hexstr2bin("1A4BFE705445120C8E3E026699054104510D119757B74D5FE2462C66")}, + {ecdh, hexstr2point("034A56C550FF88056144E6DD56070F54B0135976B5BF77827313F36B", + "75165AD99347DC86CAAB1CBB579E198EAF88DC35F927B358AA683681"), + hexstr2bin("39F155483CEE191FBECFE9C81D8AB1A03CDA6790E7184ACE44BCA161"), + brainpoolP224r1, + hexstr2bin("1A4BFE705445120C8E3E026699054104510D119757B74D5FE2462C66")}, + {ecdh, hexstr2point("44106E913F92BC02A1705D9953A8414DB95E1AAA49E81D9E85F929A8E3100BE5", + "8AB4846F11CACCB73CE49CBDD120F5A900A69FD32C272223F789EF10EB089BDC"), + hexstr2bin("55E40BC41E37E3E2AD25C3C6654511FFA8474A91A0032087593852D3E7D76BD3"), + brainpoolP256r1, + hexstr2bin("89AFC39D41D3B327814B80940B042590F96556EC91E6AE7939BCE31F3A18BF2B")}, + {ecdh, hexstr2point("8D2D688C6CF93E1160AD04CC4429117DC2C41825E1E9FCA0ADDD34E6F1B39F7B", + "990C57520812BE512641E47034832106BC7D3E8DD0E4C7F1136D7006547CEC6A"), + hexstr2bin("81DB1EE100150FF2EA338D708271BE38300CB54241D79950F77B063039804F1D"), + brainpoolP256r1, + hexstr2bin("89AFC39D41D3B327814B80940B042590F96556EC91E6AE7939BCE31F3A18BF2B")}, + {ecdh, hexstr2point("68B665DD91C195800650CDD363C625F4E742E8134667B767B1B476793588F885AB698C852D4A6E77A252D6380FCAF068", + "55BC91A39C9EC01DEE36017B7D673A931236D2F1F5C83942D049E3FA20607493E0D038FF2FD30C2AB67D15C85F7FAA59"), + hexstr2bin("032640BC6003C59260F7250C3DB58CE647F98E1260ACCE4ACDA3DD869F74E01F8BA5E0324309DB6A9831497ABAC96670"), + brainpoolP384r1, + hexstr2bin("0BD9D3A7EA0B3D519D09D8E48D0785FB744A6B355E6304BC51C229FBBCE239BBADF6403715C35D4FB2A5444F575D4F42")}, + {ecdh, hexstr2point("4D44326F269A597A5B58BBA565DA5556ED7FD9A8A9EB76C25F46DB69D19DC8CE6AD18E404B15738B2086DF37E71D1EB4", + "62D692136DE56CBE93BF5FA3188EF58BC8A3A0EC6C1E151A21038A42E9185329B5B275903D192F8D4E1F32FE9CC78C48"), + hexstr2bin("1E20F5E048A5886F1F157C74E91BDE2B98C8B52D58E5003D57053FC4B0BD65D6F15EB5D1EE1610DF870795143627D042"), + brainpoolP384r1, + hexstr2bin("0BD9D3A7EA0B3D519D09D8E48D0785FB744A6B355E6304BC51C229FBBCE239BBADF6403715C35D4FB2A5444F575D4F42")}, + {ecdh, hexstr2point("0A420517E406AAC0ACDCE90FCD71487718D3B953EFD7FBEC5F7F27E28C6149999397E91E029E06457DB2D3E640668B392C2A7E737A7F0BF04436D11640FD09FD", + "72E6882E8DB28AAD36237CD25D580DB23783961C8DC52DFA2EC138AD472A0FCEF3887CF62B623B2A87DE5C588301EA3E5FC269B373B60724F5E82A6AD147FDE7"), + hexstr2bin("230E18E1BCC88A362FA54E4EA3902009292F7F8033624FD471B5D8ACE49D12CFABBC19963DAB8E2F1EBA00BFFB29E4D72D13F2224562F405CB80503666B25429"), + brainpoolP512r1, + hexstr2bin("A7927098655F1F9976FA50A9D566865DC530331846381C87256BAF3226244B76D36403C024D7BBF0AA0803EAFF405D3D24F11A9B5C0BEF679FE1454B21C4CD1F")}, + {ecdh, hexstr2point("9D45F66DE5D67E2E6DB6E93A59CE0BB48106097FF78A081DE781CDB31FCE8CCBAAEA8DD4320C4119F1E9CD437A2EAB3731FA9668AB268D871DEDA55A5473199F", + "2FDC313095BCDD5FB3A91636F07A959C8E86B5636A1E930E8396049CB481961D365CC11453A06C719835475B12CB52FC3C383BCE35E27EF194512B71876285FA"), + hexstr2bin("16302FF0DBBB5A8D733DAB7141C1B45ACBC8715939677F6A56850A38BD87BD59B09E80279609FF333EB9D4C061231FB26F92EEB04982A5F1D1764CAD57665422"), + brainpoolP512r1, + hexstr2bin("A7927098655F1F9976FA50A9D566865DC530331846381C87256BAF3226244B76D36403C024D7BBF0AA0803EAFF405D3D24F11A9B5C0BEF679FE1454B21C4CD1F")}], + lists:filter(fun ({_Type, _Pub, _Priv, Curve, _SharedSecret}) -> + lists:member(Curve, Curves) + end, + TestCases). dh() -> {dh, 0087761979513264537414556992123116644042638206717762626089877284926656954974893442000747478454809111207351620687968672207938731607963470779396984752680274820156266685080223616226905101126463253150237669547023934604953898814222890239130021414026118792251620881355456432549881723310342870016961804255746630219, 2}. @@ -2162,18 +2184,24 @@ ecc() -> %% information about the curves see %% http://csrc.nist.gov/encryption/dss/ecdsa/NISTReCur.pdf %% - [{ecdh,secp192r1,1, - hexstr2point("188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012", - "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811")}, - {ecdh,secp192r1,2, - hexstr2point("DAFEBF5828783F2AD35534631588A3F629A70FB16982A888", - "DD6BDA0D993DA0FA46B27BBC141B868F59331AFA5C7E93AB")}, - {ecdh,secp192r1,3, - hexstr2point("76E32A2557599E6EDCD283201FB2B9AADFD0D359CBB263DA", - "782C37E372BA4520AA62E0FED121D49EF3B543660CFD05FD")}, - {ecdh,secp192r1,4, - hexstr2point("35433907297CC378B0015703374729D7A4FE46647084E4BA", - "A2649984F2135C301EA3ACB0776CD4F125389B311DB3BE32")}]. + Curves = crypto:ec_curves(), + TestCases = + [{ecdh,secp192r1,1, + hexstr2point("188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012", + "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811")}, + {ecdh,secp192r1,2, + hexstr2point("DAFEBF5828783F2AD35534631588A3F629A70FB16982A888", + "DD6BDA0D993DA0FA46B27BBC141B868F59331AFA5C7E93AB")}, + {ecdh,secp192r1,3, + hexstr2point("76E32A2557599E6EDCD283201FB2B9AADFD0D359CBB263DA", + "782C37E372BA4520AA62E0FED121D49EF3B543660CFD05FD")}, + {ecdh,secp192r1,4, + hexstr2point("35433907297CC378B0015703374729D7A4FE46647084E4BA", + "A2649984F2135C301EA3ACB0776CD4F125389B311DB3BE32")}], + lists:filter(fun ({_Type, Curve, _Priv, _Pub}) -> + lists:member(Curve, Curves) + end, + TestCases). no_padding() -> Public = [_, Mod] = rsa_public(), diff --git a/lib/crypto/test/old_crypto_SUITE.erl b/lib/crypto/test/old_crypto_SUITE.erl index b5894b070d..1e7f3a1438 100644 --- a/lib/crypto/test/old_crypto_SUITE.erl +++ b/lib/crypto/test/old_crypto_SUITE.erl @@ -1888,48 +1888,12 @@ ec(Config) when is_list(Config) -> ec_do() -> %% test for a name curve - {D2_pub, D2_priv} = crypto:generate_key(ecdh, secp112r2), - PrivECDH = [D2_priv, secp112r2], - PubECDH = [D2_pub, secp112r2], + NamedCurve = hd(crypto:ec_curves()), + {D2_pub, D2_priv} = crypto:generate_key(ecdh, NamedCurve), + PrivECDH = [D2_priv, NamedCurve], + PubECDH = [D2_pub, NamedCurve], %%TODO: find a published test case for a EC key - %% test for a full specified curve and public key, - %% taken from csca-germany_013_self_signed_cer.pem - PubKey = <<16#04, 16#4a, 16#94, 16#49, 16#81, 16#77, 16#9d, 16#df, - 16#1d, 16#a5, 16#e7, 16#c5, 16#27, 16#e2, 16#7d, 16#24, - 16#71, 16#a9, 16#28, 16#eb, 16#4d, 16#7b, 16#67, 16#75, - 16#ae, 16#09, 16#0a, 16#51, 16#45, 16#19, 16#9b, 16#d4, - 16#7e, 16#a0, 16#81, 16#e5, 16#5e, 16#d4, 16#a4, 16#3f, - 16#60, 16#7c, 16#6a, 16#50, 16#ee, 16#36, 16#41, 16#8a, - 16#87, 16#ff, 16#cd, 16#a6, 16#10, 16#39, 16#ca, 16#95, - 16#76, 16#7d, 16#ae, 16#ca, 16#c3, 16#44, 16#3f, 16#e3, 16#2c>>, - <<P:264/integer>> = <<16#00, 16#a9, 16#fb, 16#57, 16#db, 16#a1, 16#ee, 16#a9, - 16#bc, 16#3e, 16#66, 16#0a, 16#90, 16#9d, 16#83, 16#8d, - 16#72, 16#6e, 16#3b, 16#f6, 16#23, 16#d5, 16#26, 16#20, - 16#28, 16#20, 16#13, 16#48, 16#1d, 16#1f, 16#6e, 16#53, 16#77>>, - <<A:256/integer>> = <<16#7d, 16#5a, 16#09, 16#75, 16#fc, 16#2c, 16#30, 16#57, - 16#ee, 16#f6, 16#75, 16#30, 16#41, 16#7a, 16#ff, 16#e7, - 16#fb, 16#80, 16#55, 16#c1, 16#26, 16#dc, 16#5c, 16#6c, - 16#e9, 16#4a, 16#4b, 16#44, 16#f3, 16#30, 16#b5, 16#d9>>, - <<B:256/integer>> = <<16#26, 16#dc, 16#5c, 16#6c, 16#e9, 16#4a, 16#4b, 16#44, - 16#f3, 16#30, 16#b5, 16#d9, 16#bb, 16#d7, 16#7c, 16#bf, - 16#95, 16#84, 16#16, 16#29, 16#5c, 16#f7, 16#e1, 16#ce, - 16#6b, 16#cc, 16#dc, 16#18, 16#ff, 16#8c, 16#07, 16#b6>>, - BasePoint = <<16#04, 16#8b, 16#d2, 16#ae, 16#b9, 16#cb, 16#7e, 16#57, - 16#cb, 16#2c, 16#4b, 16#48, 16#2f, 16#fc, 16#81, 16#b7, - 16#af, 16#b9, 16#de, 16#27, 16#e1, 16#e3, 16#bd, 16#23, - 16#c2, 16#3a, 16#44, 16#53, 16#bd, 16#9a, 16#ce, 16#32, - 16#62, 16#54, 16#7e, 16#f8, 16#35, 16#c3, 16#da, 16#c4, - 16#fd, 16#97, 16#f8, 16#46, 16#1a, 16#14, 16#61, 16#1d, - 16#c9, 16#c2, 16#77, 16#45, 16#13, 16#2d, 16#ed, 16#8e, - 16#54, 16#5c, 16#1d, 16#54, 16#c7, 16#2f, 16#04, 16#69, 16#97>>, - <<Order:264/integer>> = <<16#00, 16#a9, 16#fb, 16#57, 16#db, 16#a1, 16#ee, 16#a9, - 16#bc, 16#3e, 16#66, 16#0a, 16#90, 16#9d, 16#83, 16#8d, - 16#71, 16#8c, 16#39, 16#7a, 16#a3, 16#b5, 16#61, 16#a6, - 16#f7, 16#90, 16#1e, 16#0e, 16#82, 16#97, 16#48, 16#56, 16#a7>>, - CoFactor = 1, - Curve = {{prime_field,P},{A,B,none},BasePoint, Order,CoFactor}, - Msg = <<99,234,6,64,190,237,201,99,80,248,58,40,70,45,149,218,5,246,242,63>>, Sign = crypto:sign(ecdsa, sha, Msg, PrivECDH), ?line true = crypto:verify(ecdsa, sha, Msg, Sign, PubECDH), diff --git a/lib/crypto/vsn.mk b/lib/crypto/vsn.mk index 55b1b3e8c4..6dcb28ec8a 100644 --- a/lib/crypto/vsn.mk +++ b/lib/crypto/vsn.mk @@ -1 +1 @@ -CRYPTO_VSN = 3.6 +CRYPTO_VSN = 3.6.3 diff --git a/lib/debugger/doc/src/book.xml b/lib/debugger/doc/src/book.xml index 071a04eb61..5424ef2c04 100644 --- a/lib/debugger/doc/src/book.xml +++ b/lib/debugger/doc/src/book.xml @@ -47,4 +47,3 @@ <index/> </book> - diff --git a/lib/debugger/doc/src/debugger.xml b/lib/debugger/doc/src/debugger.xml index 15d498d5ae..1ecdbcd064 100644 --- a/lib/debugger/doc/src/debugger.xml +++ b/lib/debugger/doc/src/debugger.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2002</year><year>2013</year> + <year>2002</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -29,7 +29,7 @@ <rev></rev> </header> <module>debugger</module> - <modulesummary>Erlang Debugger</modulesummary> + <modulesummary>Erlang Debugger.</modulesummary> <description> <p>Erlang Debugger for debugging and testing of Erlang programs.</p> </description> @@ -48,14 +48,14 @@ <desc> <p>Starts Debugger.</p> - <p>If given a file name as argument, Debugger will try to load - its settings from this file. Refer to Debugger User's Guide - for more information about settings.</p> + <p>If a filename is specified as argument, Debugger tries to load + its settings from this file. For details about settings, see + the User's Guide.</p> - <p>If given <c>local</c> as argument, Debugger will interpret - code only at the current node. If given <c>global</c> as - argument, Debugger will interpret code at all known nodes, - this is the default.</p> + <p>If <c>local</c> is specified as argument, Debugger interprets + code only at the current node. If <c>global</c> is specified as + argument, Debugger interprets code at all known nodes, this + is the default.</p> </desc> </func> @@ -67,11 +67,9 @@ <v>Args = [term()]</v> </type> <desc> - <p>This function can be used to debug a single process. - The module <c>Module</c> is interpreted and - <c>apply(Module,Name,Args)</c> is called. This will open an - Attach Process window, refer to Debugger User's Guide for - more information.</p> + <p>Debugs a single process. The module <c>Module</c> is interpreted + and <c>apply(Module,Name,Args)</c> is called. This opens an + Attach Process window. For details, see the User's Guide.</p> </desc> </func> </funcs> diff --git a/lib/debugger/doc/src/debugger_chapter.xml b/lib/debugger/doc/src/debugger_chapter.xml index 98fe4ae377..45dfdb3776 100644 --- a/lib/debugger/doc/src/debugger_chapter.xml +++ b/lib/debugger/doc/src/debugger_chapter.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>1997</year><year>2013</year> + <year>1997</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -31,97 +31,92 @@ </header> <section> - <title>Introduction</title> + <title>Getting Started</title> - <p><em>Debugger</em> is a graphical user interface for the Erlang - interpreter, which can be used for debugging and testing of - Erlang programs. For example, breakpoints can be set, code can be - single stepped and variable values can be displayed and changed. - </p> + <p>To use Debugger, the basic steps are as follows:</p> - <p>The Erlang interpreter can also be accessed via the interface - module <c>int</c>, see <seealso marker="int">int(3)</seealso>. - </p> + <p><em>Step 1.</em> Start Debugger by calling + <c>debugger:start()</c>.</p> - <p><em>Warning:</em> Note that the Debugger at some point might - start tracing on the processes which execute the interpreted - code. This means that a conflict will occur if tracing by other - means is started on any of these processes.</p> - </section> + <p>The <seealso marker="#monitor">Monitor window</seealso> is + displayed with information about all debugged processes, + interpreted modules, and selected options. Initially there are + normally no debugged processes. First, it must be specified which + modules that are to be <em>debugged</em> (also called + <em>interpreted</em>). Proceed as follows:</p> - <section> - <title>Getting Started with Debugger</title> + <p><em>Step 2.</em> Select <em>Module > Interpret...</em> in the + Monitor window.</p> - <p>Start Debugger by calling <c>debugger:start()</c>. It will start - the <seealso marker="#monitor">Monitor window</seealso> showing - information about all debugged processes, interpreted modules and - selected options.</p> + <p>The <seealso marker="#interpret">Interpret Modules window</seealso> + is displayed.</p> - <p>Initially there are normally no debugged processes. First, it - must be specified which modules should be <em>debugged</em>, or - <em>interpreted</em> as it is also called. This is done by - choosing <em>Module->Interpret...</em> in the Monitor window and - then selecting the appropriate modules from the - <seealso marker="#interpret">Interpret Dialog window</seealso>. - </p> + <p><em>Step 3.</em> Select the appropriate modules from the Interpret + Dialog window.</p> <note> - <p>Only modules compiled with the option <c>debug_info</c> set - can be interpreted. Non-interpretable modules are shown within - parenthesis in the Interpret Dialog window.</p> + <p>Only modules compiled with option <c>debug_info</c> set can be + interpreted. Non-interpretable modules are displayed within + parenthesis in the Interpret Modules window.</p> </note> - <p>When a module is interpreted, it can be viewed in a - <seealso marker="#view">View Module window</seealso>. This is done - by selecting the module from the <em>Module->module->View</em> - menu. The contents of the source file is shown and it is possible - to set <seealso marker="#breakpoints">breakpoints</seealso>.</p> - - <p>Now the program that should be debugged can be started. This is - done the normal way from the Erlang shell. All processes executing - code in interpreted modules will be displayed in the Monitor - window. It is possible to <em>attach</em> to one of these - processes, by double-clicking it, or by selecting the process and - then choosing <em>Process->Attach</em>.</p> - - <p>Attaching to a process will result in a - <seealso marker="#attach">Attach Process window</seealso> being - opened for this process. From the Attach Process window, it is - possible to control the process execution, inspect variable - values, set breakpoints etc.</p> + <p><em>Step 4.</em> In the Monitor window, select + <em>Module > the module to be interpreted > View</em>.</p> + + <p>The contents of the source file is displayed in the + <seealso marker="#view">View Module window</seealso>.</p> + + <p><em>Step 5.</em> Set the + <seealso marker="#breakpoints">breakpoints</seealso>, if any.</p> + + <p><em>Step 6.</em> Start the program to be debugged. This is done + the normal way from the Erlang shell.</p> + + <p>All processes executing code in interpreted modules are displayed + in the Monitor window.</p> + + <p><em>Step 7.</em> To <em>attach</em> to one of these processes, + double-click it, or select the process and then choose + <em>Process > Attach</em>. Attaching to a process opens an + <seealso marker="#attach">Attach Process window</seealso> for this + process.</p> + + <p><em>Step 8.</em> From the Attach Process window, you can control + the process execution, inspect variable values, set breakpoints, + and so on.</p> </section> <section> <marker id="breakpoints"/> - <title>Breakpoints and Break Dialogue Windows</title> + <title>Breakpoints and Break Dialog Windows</title> <p>Once the appropriate modules are interpreted, breakpoints can be set at relevant locations in the source code. Breakpoints are specified on a line basis. When a process reaches a breakpoint, - it stops and waits for commands (step, skip, continue,...) from - the user.</p> + it stops and waits for commands (<em>Step</em>, <em>Skip</em>, + <em>Continue</em> ...) from the user.</p> <note> <p>When a process reaches a breakpoint, only that process is - stopped. Other processes are not affected.</p> + stopped. Other processes are not affected.</p> </note> - <p>Breakpoints are created and deleted using the Break menu of - the Monitor window, View Module window and Attach Process window. - </p> + <p>Breakpoints are created and deleted using the <em>Break</em> menu of + either the Monitor window, View Module window, or Attach Process + window.</p> <section> <title>Executable Lines</title> - <p>To have effect, a breakpoint must be set at an - <em>executable line</em>, which is a line of code containing an - executable expression such as a matching or a function call. - A blank line or a line containing a comment, function head or - pattern in a <c>case</c>- or <c>receive</c> statement is not - executable.</p> + <p>To have an effect, a breakpoint must be set at an + <em>executable line</em>, which is a line of code containing an + executable expression such as a matching or a function call. + A blank line or a line containing a comment, function head, or + pattern in a <c>case</c> statement or <c>receive</c> statement is not + executable.</p> - <p>In the example below, lines number 2, 4, 6, 8 and 11 are - executable lines:</p> + <p>In the following example, lines 2, 4, 6, 8, and 11 are + executable lines:</p> <pre> 1: is_loaded(Module,Compiled) -> 2: case get_file(Module,Compiled) of @@ -141,17 +136,15 @@ <title>Status and Trigger Action</title> <p>A breakpoint can be either <em>active</em> or - <em>inactive</em>. Inactive breakpoints are ignored.</p> - - <p>Each breakpoint has a <em>trigger action</em> which specifies - what should happen when a process has reached it (and stopped): - </p> - <list> - <item><em>enable</em> Breakpoint should remain active (default). - </item> - <item><em>disable</em> Breakpoint should be made inactive. - </item> - <item><em>delete</em> Breakpoint should be deleted.</item> + <em>inactive</em>. Inactive breakpoints are ignored.</p> + + <p>Each breakpoint has a <em>trigger action</em> that specifies + what is to happen when a process has reached it (and stopped):</p> + <list type="bulleted"> + <item><em>Enable</em> - Breakpoint is to remain active (default). + </item> + <item><em>Disable</em> - Breakpoint is to be made inactive.</item> + <item><em>Delete</em> - Breakpoint is to be deleted.</item> </list> </section> @@ -161,54 +154,56 @@ <p>A line breakpoint is created at a certain line in a module.</p> <image file="images/line_break_dialog.jpg"> - <icaption>The Line Break Dialog Window.</icaption> + <icaption>Line Break Dialog Window</icaption> </image> - <p>Right-clicking the Module entry will open a popup menu from - which the appropriate module can be selected.</p> + <p>Right-click the <em>Module</em> entry to open a popup menu from + which the appropriate module can be selected.</p> - <p>A line breakpoint can also be created (and deleted) by - double-clicking the line when the module is displayed in - the View Module or Attach Process window.</p> + <p>A line breakpoint can also be created (and deleted) by + double-clicking the line when the module is displayed in + the View Module window or Attach Process window.</p> </section> <section> <title>Conditional Breakpoints</title> <p>A conditional breakpoint is created at a certain line in - the module, but a process reaching the breakpoint will stop - only if a given condition is true.</p> + the module, but a process reaching the breakpoint stops + only if a specified condition is true.</p> <p>The condition is specified by the user as a module name - <c>CModule</c> and a function name <c>CFunction</c>. When a - process reaches the breakpoint, - <c>CModule:CFunction(Bindings)</c> will be evaluated. If and - only if this function call returns <c>true</c>, the process - will stop. If the function call returns <c>false</c>, - the breakpoint will be silently ignored.</p> - - <p><c>Bindings</c> is a list of variable bindings. Use - the function <c>int:get_binding(Variable,Bindings)</c> to - retrieve the value of <c>Variable</c> (given as an atom). - The function returns <c>unbound</c> or <c>{value,Value}</c>.</p> + <c>CModule</c> and a function name <c>CFunction</c>. When a + process reaches the breakpoint, + <c>CModule:CFunction(Bindings)</c> is evaluated. If and + only if this function call returns <c>true</c>, the process + stops. If the function call returns <c>false</c>, + the breakpoint is silently ignored.</p> + + <p><c>Bindings</c> is a list of variable bindings. To retrieve the + value of <c>Variable</c> (given as an atom), use function + <seealso marker="int#get_binding/2"><c>int:get_binding(Variable,Bindings)</c></seealso>. + The function returns <c>unbound</c> or <c>{value,Value}</c>.</p> <image file="images/cond_break_dialog.jpg"> - <icaption>The Conditional Break Dialog Window.</icaption> + <icaption>Conditional Break Dialog Window</icaption> </image> - <p>Right-clicking the Module entry will open a popup menu from - which the appropriate module can be selected.</p> + <p>Right-click the <em>Module</em> entry to open a popup menu from + which the appropriate module can be selected.</p> - <p>Example: A conditional breakpoint calling - <c>c_test:c_break/1</c> is added at line 6 in the module + <p><em>Example:</em></p> + + <p>A conditional breakpoint calling + <c>c_test:c_break/1</c> is added at line 6 in module <c>fact</c>. Each time the breakpoint is reached, the function is - called, and when <c>N</c> is equal to 3 it returns <c>true</c>, - and the process stops.</p> - + called. When <c>N</c> is equal to 3, the function returns + <c>true</c> and the process stops.</p> + <p>Extract from <c>fact.erl</c>:</p> <pre> -5. fac(0) -> 1; -6. fac(N) when N > 0, is_integer(N) -> N * fac(N-1).</pre> +5. fac(0) -> 1; +6. fac(N) when N > 0, is_integer(N) -> N * fac(N-1).</pre> <p>Definition of <c>c_test:c_break/1</c>:</p> <pre> @@ -228,18 +223,18 @@ c_break(Bindings) -> <title>Function Breakpoints</title> <p>A function breakpoint is a set of line breakpoints, one at - the first line of each clause in the given function.</p> + the first line of each clause in the specified function.</p> <image file="images/function_break_dialog.jpg"> - <icaption>The Function Break Dialog Window.</icaption> + <icaption>Function Break Dialog Window</icaption> </image> - <p>Right-clicking the Module entry will open a popup menu from - which the appropriate module can be selected.</p> + <p>To open a popup menu from which the appropriate module can be + selected, right-click the <em>Module</em> entry.</p> - <p>Clicking the Ok button (or 'Return' or 'Tab') when a module - name has been given, will bring up all functions of the module - in the listbox.</p> + <p>To bring up all functions of the module in the listbox, + click the <em>OK</em> button (or press the <em>Return</em> + or <em>Tab</em> key) when a module name has been specified,.</p> </section> </section> @@ -249,7 +244,7 @@ c_break(Bindings) -> <p>The Erlang emulator keeps track of a <em>stack trace</em>, information about recent function calls. This information is - used, for example, if an error occurs:</p> + used if an error occurs, for example:</p> <pre> 1> <input>catch a+1.</input> {'EXIT',{badarith,[{erlang,'+',[a,1],[]}, @@ -259,602 +254,597 @@ c_break(Bindings) -> {shell,eval_exprs,7,[{file,"shell.erl"},{line,629}]}, {shell,eval_loop,3,[{file,"shell.erl"},{line,614}]}]}}</pre> - <p>See the Erlang Reference Manual, - <seealso marker="doc/reference_manual:errors"> - Errors and Error Handling</seealso>, - for more information about the stack trace.</p> + <p>For details about the stack trace, see section + <seealso marker="doc/reference_manual:errors">Errors and Error Handling</seealso> + in the Erlang Reference Manual.</p> - <p>The Debugger emulates the stack trace by keeping track of recently + <p>Debugger emulates the stack trace by keeping track of recently called interpreted functions. (The real stack trace cannot be - used, as it shows which functions of the Debugger have been - called, rather than which interpreted functions).</p> + used, as it shows which functions of Debugger have been + called, rather than which interpreted functions.)</p> <p>This information can be used to traverse the chain of function - calls, using the 'Up' and 'Down' buttons of - <seealso marker="#attach">the Attach Process window</seealso>. - </p> + calls, using the <em>Up</em> and <em>Down</em> buttons in the + <seealso marker="#attach">Attach Process window</seealso>.</p> - <p>By default, the Debugger only saves information about recursive + <p>By default, Debugger only saves information about recursive function calls, that is, function calls that have not yet returned - a value (option 'Stack On, No Tail').</p> + a value (option <em>Stack On, No Tail</em>).</p> <p>Sometimes, however, it can be useful to save all calls, even - tail-recursive calls. That can be done with the 'Stack On, Tail' - option. Note that this option will consume more memory and slow - down execution of interpreted functions when there are many - tail-recursive calls. - </p> - - <p>It is also possible to turn off the Debugger stack trace - facility ('Stack Off'). <em>Note:</em> If an error occurs, in this - case the stack trace will be empty.</p> - - <p>See the section about <seealso marker="#monitor">the Monitor - Window</seealso> for information about how to change the stack - trace option.</p> + tail-recursive calls. This is done with option + <em>Stack On, Tail</em>. Notice that this option consumes more + memory and slows down execution of interpreted functions when there + are many tail-recursive calls.</p> + + <p>To turn off the Debugger stack trace facility, select option + <em>Stack Off</em>.</p> + + <note> + <p>If an error occurs, the stack trace becomes empty in this + case.</p> + </note> + + <p>For information about how to change the stack trace option, see + section <seealso marker="#monitor">Monitor Window</seealso>.</p> </section> <section> <marker id="monitor"/> - <title>The Monitor Window</title> + <title>Monitor Window</title> + + <p>The Monitor window is the main window of Debugger and displays the + following:</p> - <p>The Monitor window is the main window of Debugger and shows a - listbox containing the names of all interpreted modules - (double-clicking a module brings up the View Module window), - which options are selected, and information about all debugged - processes, that is all processes which have been/are executing - code in interpreted modules.</p> + <list type="bulleted"> + <item><p>A listbox containing the names of all interpreted + modules</p> + <p>Double-clicking a module brings up the View Module window.</p> + </item> + <item><p>Which options are selected</p></item> + <item><p>Information about all debugged processes, that is, all + processes that have been or are executing code in interpreted + modules</p></item> + </list> <image file="images/monitor.jpg"> - <icaption>The Monitor Window.</icaption> + <icaption>Monitor Window</icaption> </image> - <p>The Auto Attach buttons, Stack Trace label, Back Trace Size - label, and Strings button show some options set, see - <seealso marker="#options">Options Menu</seealso> for further - information about these options.</p> + <p>The <em>Auto Attach</em> boxes, <em>Stack Trace</em> label, + <em>Back Trace Size</em> label, and <em>Strings</em> box display + some options set. For details about these options, see section + <seealso marker="#options">Options Menu</seealso>.</p> <section> <title>Process Grid</title> - <taglist> <tag><em>Pid</em></tag> <item><p>The process identifier.</p></item> - + <tag><em>Initial Call</em></tag> <item><p>The first call to an interpreted function by this - process. (<c>Module:Function/Arity</c>)</p></item> + process. (<c>Module:Function/Arity</c>)</p></item> <tag><em>Name</em></tag> - <item><p>The registered name, if any. If a registered name does - not show up, it may be that the Debugger received - information about the process before the name had been - registered. Try selecting <em>Edit->Refresh</em>.</p></item> + <item><p>The registered name, if any. If a registered name is not + displayed, it can be that Debugger received information about + the process before the name was registered. Try selecting + <em>Edit > Refresh</em>.</p></item> <tag><em>Status</em></tag> <item><p>The current status, one of the following:</p> <taglist> <tag><em>idle</em></tag> - <item><p>The interpreted function call has returned a value, - and the process is no longer executing interpreted code. - </p></item> + <item><p>The interpreted function call has returned a value, and + the process is no longer executing interpreted code.</p></item> <tag><em>running</em></tag> <item><p>The process is running.</p></item> - + <tag><em>waiting</em></tag> <item><p>The process is waiting in a <c>receive</c> - statement.</p></item> - + statement.</p></item> + <tag><em>break</em></tag> <item><p>The process is stopped at a breakpoint.</p></item> - + <tag><em>exit</em></tag> <item><p>The process has terminated.</p></item> - + <tag><em>no_conn</em></tag> <item><p>There is no connection to the node where - the process is located.</p></item> + the process is located.</p></item> </taglist> </item> <tag><em>Information</em></tag> - <item><p>Additional information, if any. If the process is - stopped at a breakpoint, the field contains information - about the location <c>{Module,Line}</c>. If the process has - terminated, the field contains the exit reason.</p></item> + <item><p>More information, if any. If the process is + stopped at a breakpoint, the field contains information + about the location <c>{Module,Line}</c>. If the process has + terminated, the field contains the exit reason.</p></item> </taglist> </section> <section> - <title>The File Menu</title> - + <title>File Menu</title> + <taglist> <tag><em>Load Settings...</em></tag> - <item> - <p>Try to load and restore Debugger settings from a file - previously saved using <em>Save Settings...</em>, see below. - Any errors are silently ignored. - <em>Note:</em> Settings saved by Erlang R16B01 or later - cannot be read by Erlang R16B or earlier.</p> + <item><p>Tries to load and restore Debugger settings from a file + previously saved using <em>Save Settings...</em> (see below). + Any errors are silently ignored.</p> + <p>Notice that settings saved by Erlang/OTP R16B01 or later + cannot be read by Erlang/OTP R16B or earlier.</p> </item> - + <tag><em>Save Settings...</em></tag> - <item><p>Save Debugger settings to a file. The settings include - the set of interpreted files, breakpoints, and the selected - options. The settings can be restored in a later Debugger - session using <em>Load Settings...</em>, see above. - Any errors are silently ignored.</p> + <item><p>Saves Debugger settings to a file. The settings include + the set of interpreted files, breakpoints, and the selected + options. The settings can be restored in a later Debugger + session using <em>Load Settings...</em> (see above). + Any errors are silently ignored.</p> </item> - + <tag><em>Exit</em></tag> - <item><p>Stop Debugger.</p></item> + <item><p>Stops Debugger.</p></item> </taglist> </section> <section> - <title>The Edit Menu</title> + <title>Edit Menu</title> <taglist> <tag><em>Refresh</em></tag> - <item><p>Update information about debugged processes. Removes - information about all terminated processes from the window, - and also closes all Attach Process windows for terminated - processes.</p></item> + <item><p>Updates information about debugged processes. Information + about all terminated processes are removed from the window. All + Attach Process windows for terminated processes are closed.</p></item> <tag><em>Kill All</em></tag> - <item><p>Terminate all processes listed in the window using - <c>exit(Pid,kill)</c>.</p></item> + <item><p>Terminates all processes listed in the window using + <c>exit(Pid,kill)</c>.</p></item> </taglist> </section> <section> - <title>The Module Menu</title> + <title>Module Menu</title> <taglist> <tag><em>Interpret...</em></tag> - <item><p>Open the <seealso marker="#interpret">Interpret Dialog - window</seealso> where new modules to be interpreted can - be specified.</p></item> - + <item><p>Opens the + <seealso marker="#interpret">Interpret Modules window</seealso>, + where new modules to be interpreted can be specified.</p></item> + <tag><em>Delete All</em></tag> - <item><p>Stop interpreting all modules. Processes executing in - interpreted modules will terminate.</p></item> + <item><p>Stops interpreting all modules. Processes executing in + interpreted modules terminate.</p></item> </taglist> <p>For each interpreted module, a corresponding entry is added to - the Module menu, with the following submenu:</p> + the <em>Module</em> menu, with the following submenu:</p> <taglist> <tag><em>Delete</em></tag> - <item><p>Stop interpreting the selected module. Processes - executing in this module will terminate.</p></item> - + <item><p>Stops interpreting the selected module. Processes + executing in this module terminate.</p></item> + <tag><em>View</em></tag> - <item><p>Open a <seealso marker="#view">View Module - window</seealso> showing the contents of the selected - module.</p></item> + <item><p>Opens a + <seealso marker="#view">View Module window</seealso>, displaying the + contents of the selected module.</p></item> </taglist> </section> <section> - <title>The Process Menu</title> + <title>Process Menu</title> <p>The following menu items apply to the currently selected - process, provided it is stopped at a breakpoint. See the chapter - about the <seealso marker="#attach">Attach Process - window</seealso> for more information.</p> + process, provided it is stopped at a breakpoint (for details, see + section + <seealso marker="#attach">Attach Process window</seealso>):</p> <taglist> <tag><em>Step</em></tag><item></item> <tag><em>Next</em></tag><item></item> <tag><em>Continue</em></tag><item></item> <tag><em>Finish</em></tag><item></item> </taglist> + <p>The following menu items apply to the currently selected - process.</p> + process:</p> <taglist> <tag><em>Attach</em></tag> - <item><p>Attach to the process and open a - <seealso marker="#attach">Attach Process window</seealso>. - </p></item> - + <item><p>Attaches to the process and open an + <seealso marker="#attach">Attach Process window</seealso>.</p></item> + <tag><em>Kill</em></tag> - <item><p>Terminate the process using <c>exit(Pid,kill)</c>.</p> - </item> + <item><p>Terminates the process using <c>exit(Pid,kill)</c>.</p></item> </taglist> </section> - <section> - <title>The Break Menu</title> - <p>The items in this menu are used to create and delete - breakpoints. - See the <seealso marker="#breakpoints">Breakpoints</seealso> - chapter for more information.</p> + <section> + <title>Break Menu</title> + <p>The items in this menu are used to create and delete breakpoints. + For details, see section + <seealso marker="#breakpoints">Breakpoints</seealso>.</p> + <taglist> <tag><em>Line Break...</em></tag> - <item><p>Set a line breakpoint.</p></item> + <item><p>Sets a line breakpoint.</p></item> <tag><em>Conditional Break...</em></tag> - <item><p>Set a conditional breakpoint.</p></item> + <item><p>Sets a conditional breakpoint.</p></item> <tag><em>Function Break...</em></tag> - <item><p>Set a function breakpoint.</p></item> + <item><p>Sets a function breakpoint.</p></item> <tag><em>Enable All</em></tag> - <item><p>Enable all breakpoints.</p></item> + <item><p>Enables all breakpoints.</p></item> <tag><em>Disable All</em></tag> - <item><p>Disable all breakpoints.</p></item> + <item><p>Disables all breakpoints.</p></item> - <tag><em>Delete All</em></tag> - <item><p>Remove all breakpoints.</p></item> + <tag><em>Delete All</em></tag> + <item><p>Removes all breakpoints.</p></item> </taglist> - <p>For each breakpoint, a corresponding entry is added to - the Break - menu, from which it is possible to disable/enable or delete - the breakpoint, and to change its trigger action.</p> + <p>For each breakpoint, a corresponding entry is added to the + <em>Break</em> menu, from which it is possible to disable, enable, + or delete the breakpoint, and to change its trigger action.</p> </section> <section> <marker id="options"/> - <title>The Options Menu</title> + <title>Options Menu</title> <taglist> <tag><em>Trace Window</em></tag> - <item><p>Set which areas should be visible in - an <seealso marker="#attach">Attach Process - window</seealso>. Does not affect already existing - Attach Process windows.</p> + <item><p>Sets the areas to be visible in an + <seealso marker="#attach">Attach Process window</seealso>. + Does not affect existing Attach Process windows.</p> </item> <tag><em>Auto Attach</em></tag> - <item><p>Set at which events a debugged process should be - automatically attached to. Affects existing debugged - processes.</p> - <list> - <item><em>First Call</em> - the first time a process calls a - function in an interpreted module.</item> - <item><em>On Exit</em> - at process termination.</item> - <item><em>On Break</em> - when a process reaches a - breakpoint.</item> + <item><p>Sets the events a debugged process is to be attached + to automatically. Affects existing debugged processes.</p> + <list type="bulleted"> + <item><p><em>First Call</em> - The first time a process calls + a function in an interpreted module.</p></item> + <item><p><em>On Exit</em> - At process termination.</p></item> + <item><p><em>On Break</em> - When a process reaches a + breakpoint.</p></item> </list> </item> <tag><em>Stack Trace</em></tag> - <item><p>Set stack trace option, see section + <item><p>Sets the stack trace option, see section <seealso marker="#stack_trace">Stack Trace</seealso>. Does not - affect already existing debugged processes.</p> - <list> - <item><em>Stack On, Tail</em> - save information about all - current calls.</item> - <item><em>Stack On, No Tail</em> - save information about + affect existing debugged processes.</p> + <list type="bulleted"> + <item><p><em>Stack On, Tail</em> - Saves information about all + current calls.</p></item> + <item><p><em>Stack On, No Tail</em> - Saves information about current calls, discarding previous information when a tail - recursive call is made.</item> - <item><em>Stack Off</em> - do not save any information about - current calls.</item> + recursive call is made.</p></item> + <item><p><em>Stack Off</em> - Does not save any information about + current calls.</p></item> </list> </item> <tag><em>Strings</em></tag> - <item><p>Set which integer lists should be printed as strings. - Does not affect already existing debugged processes.</p> - <list> - - <item><em>Use range of +pc flag</em> - use the printable - character range set by the - <seealso marker="erts:erl#printable_character_range"> - <c>erl(1)</c></seealso> flag <c>+pc</c>. - </item> + <item><p>Sets the integer lists to be printed as strings. + Does not affect existing debugged processes.</p> + <list type="bulleted"> + <item><p><em>Use range of +pc flag</em> - Uses the printable + character range set by the <c>erl(1)</c> flag + <seealso marker="erts:erl#printable_character_range"><c>+pc</c></seealso>.</p> + </item> </list> </item> <tag><em>Back Trace Size...</em></tag> - <item><p>Set how many call frames should be fetched when - inspecting the call stack from the Attach Process window. - Does not affect already existing Attach Process windows.</p> + <item><p>Sets how many call frames to be fetched when + inspecting the call stack from the Attach Process window. + Does not affect existing Attach Process windows.</p> </item> </taglist> </section> <section> - <title>The Windows Menu</title> + <title>Windows Menu</title> <p>Contains a menu item for each open Debugger window. Selecting - one of the items will raise the corresponding window.</p> + one of the items raises the corresponding window.</p> </section> <section> - <title>The Help Menu</title> + <title>Help Menu</title> <taglist> <tag><em>Help</em></tag> - <item><p>View the Debugger documentation. Currently this - function requires a web browser to be up and running.</p></item> + <item><p>Shows the Debugger documentation. This function requires a + web browser.</p></item> </taglist> </section> </section> - + <section> <marker id="interpret"/> - <title>The Interpret Dialog Window</title> + <title>Interpret Modules Window</title> - <p>The interpret dialog module is used for selecting which modules - to interpret. Initially, the window shows the modules (<c>erl</c> - files) and subdirectories of the current working directory.</p> + <p>The Interpret Modules window is used for selecting which modules + to interpret. Initially, the window displays the modules (<c>erl</c> + files) and subdirectories of the current working directory.</p> - <p>Interpretable modules are modules for which a BEAM file, compiled - with the option <c>debug_info</c> set, can be found in the same + <p>Interpretable modules are modules for which a <c>.beam</c> file, + compiled with option <c>debug_info</c> set, is located in the same directory as the source code, or in an <c>ebin</c> directory next to it.</p> - <p>Modules, for which the above requirements are not fulfilled, are - not interpretable and are therefore displayed within parentheses. - </p> + <p>Modules for which these requirements are not fulfilled are + not interpretable and are therefore displayed within parentheses.</p> - <p>The <c>debug_info</c> option causes <em>debug information</em> or - <em>abstract code</em> to be added to the BEAM file. This will - increase the size of the file, and also makes it possible to + <p>Option <c>debug_info</c> causes <em>debug information</em> or + <em>abstract code</em> to be added to the <c>.beam</c> file. + This increases the file size and makes it possible to reconstruct the source code. It is therefore recommended not to include debug information in code aimed for target systems.</p> <p>An example of how to compile code with debug information using - <c>erlc</c>:<br/> - <c>% erlc +debug_info module.erl</c></p> - + <c>erlc</c>:</p> + <pre> +% erlc +debug_info module.erl</pre> + <p>An example of how to compile code with debug information from - the Erlang shell:<br/> - <c>4> c(module, debug_info).</c></p> - + the Erlang shell:</p> + <pre> +4> c(module, debug_info).</pre> + <image file="images/interpret.jpg"> - <icaption>The Interpret Dialog Window.</icaption> + <icaption>Interpret Modules Window</icaption> </image> - <p>Browse the file hierarchy and interpret the appropriate modules - by selecting a module name and pressing <em>Choose</em> (or - carriage return), or by double clicking the module name. - Interpreted modules have the type <c>erl src</c>. - </p> + <p>To browse the file hierarchy and interpret the appropriate modules, + either select a module name and click <em>Choose</em> (or + press carriage return), or double-click the module name. + Interpreted modules have the type <c>erl src</c>.</p> - <p>Pressing <em>All</em> will interpret all displayed modules in - the chosen directory.</p> + <p>To interpret all displayed modules in the chosen directory, click + <em>All</em>.</p> - <p>Pressing <em>Done</em> will close the window.</p> + <p>To close the window, click <em>Done</em>.</p> <note> - <p>When the Debugger is started in global mode (which is - the default, see - <seealso marker="debugger:debugger#start/0">debugger:start/0</seealso>), - modules added (or deleted) for interpretation will be added (or - deleted) on all known Erlang nodes.</p> + <p>When Debugger is started in global mode (which is the default, see + <seealso marker="debugger#start/0">debugger:start/0</seealso>), + modules added (or deleted) for interpretation are added (or + deleted) on all known Erlang nodes.</p> </note> </section> <section> <marker id="attach"/> - <title>The Attach Process Window</title> + <title>Attach Process Window</title> - <p>From an Attach Process window the user can interact with a + <p>From an Attach Process window, you can interact with a debugged process. One window is opened for each process that has - been attached to. Note that when attaching to a process, its - execution is automatically stopped. - </p> + been attached to. Notice that when attaching to a process, its + execution is automatically stopped.</p> <image file="images/attach.jpg"> - <icaption>The Attach Process Window.</icaption> + <icaption>Attach Process Window</icaption> </image> - <p>The window is divided into five parts:</p> - <list> - <item><p>The Code area, showing the code being executed. The code - is indented and each line is prefixed with its line number. - If the process execution is stopped, the current line is - marked with <em>--></em>. An existing break point at a line - is marked with a stop symbol. In the example above, - the execution has been stopped at line 6, before - the execution of <c>fac/1</c>.</p> - <p>Active breakpoints are shown in red, while inactive - breakpoints are shown in blue.</p> + <p>The window is divided into the following five parts:</p> + <list type="bulleted"> + <item><p>The Code area, displaying the code being executed. The code + is indented and each line is prefixed with its line number. + If the process execution is stopped, the current line is + marked with <c>--></c>. An existing break point at a line + is marked with a stop symbol. In the example shown in the + illustration, the execution stopped at line 6, before + the execution of <c>fac/1</c>.</p> + + <p>Active breakpoints are displayed in red and inactive + breakpoints in blue.</p> </item> - <item>The Button area, with buttons for quick access to frequently - used functions in the Process menu.</item> - <item>The Evaluator area, where the user can evaluate functions - within the context of the debugged process, provided that - process execution has been stopped.</item> - <item>The Bindings area, showing all variables bindings. - Clicking on a variable name will result in the value being - displayed in the Evaluator area. - Double-clicking on a variable name will open a window where - the variable value may be edited. Note however that pid, - reference, binary or port values can not be edited. + + <item><p>The Button area, with buttons for quick access to frequently + used functions in the <em>Process</em> menu.</p></item> + + <item><p>The Evaluator area, where you can evaluate functions + within the context of the debugged process, if that + process execution is stopped.</p></item> + + <item><p>The Bindings area, displaying all variables bindings. If you + click a variable name, the value is displayed in the Evaluator area. + Double-click a variable name to open a window where + the variable value can be edited. Notice however that pid, + reference, binary, or port values cannot be edited.</p> </item> - <item><p>The Trace area, showing a trace output for the process. - </p> + + <item><p>The Trace area, which displays a trace output for the + process.</p> <taglist> - <tag><c>++ (N) <L></c></tag> - <item>Function call, where <c>N</c> is the call level and - <c>L</c> the line number.</item> + <tag><c>++ (N) <L></c></tag> + <item><p>Function call, where <c>N</c> is the call level and + <c>L</c> the line number.</p></item> - <tag><c>-- (N)</c></tag> - <item>Function return value.</item> + <tag><c>-- (N)</c></tag> + <item><p>Function return value</p>.</item> - <tag><c>==> Pid : Msg</c></tag> - <item>The message <c>Msg</c> is sent to process <c>Pid</c>. - </item> + <tag><c>==> Pid : Msg</c></tag> + <item><p>The message <c>Msg</c> is sent to process + <c>Pid</c>.</p></item> - <tag><c><![CDATA[<== Msg]]></c></tag> - <item>The message <c>Msg</c> is received.</item> + <tag><c><![CDATA[<== Msg]]></c></tag> + <item><p>The message <c>Msg</c> is received.</p></item> - <tag><c>++ (N) receive</c></tag> - <item>Waiting in a <c>receive</c>.</item> + <tag><c>++ (N) receive</c></tag> + <item><p>Waiting in a <c>receive</c>.</p></item> - <tag><c>++ (N) receive with timeout</c></tag> - <item>Waiting in a <c>receive...after</c>.</item> - </taglist> + <tag><c>++ (N) receive with timeout</c></tag> + <item><p>Waiting in a <c>receive...after</c>.</p></item> + </taglist> - <p>Also the back trace, a summary of the current function calls - on the stack, is displayed in the Trace area.</p> + <p>The Trace area also displays Back Trace, a summary of the + current function calls on the stack.</p> </item> </list> - <p>It is configurable using the Options menu which areas should - be shown or hidden. By default, all areas except the Trace area - are shown.</p> + <p>Using the <em>Options</em> menu, you can set which areas to be + displayed. By default, all areas except the Trace area are displayed.</p> <section> - <title>The File Menu</title> + <title>File Menu</title> <taglist> <tag><em>Close</em></tag> - <item><p>Close this window and detach from the process.</p> + <item><p>Closes this window and detach from the process.</p> </item> </taglist> </section> <section> - <title>The Edit Menu</title> + <title>Edit Menu</title> <taglist> <tag><em>Go to line...</em></tag> - <item><p>Go to a specified line number.</p></item> + <item><p>Goes to a specified line number.</p></item> <tag><em>Search...</em></tag> - <item><p>Search for a specified string.</p></item> + <item><p>Searches for a specified string.</p></item> </taglist> </section> <section> - <title>The Process Menu</title> + <title>Process Menu</title> <taglist> <tag><em>Step</em></tag> - <item><p>Execute the current line of code, stepping into any + <item><p>Executes the current code line, stepping into any (interpreted) function calls.</p></item> <tag><em>Next</em></tag> - <item><p>Execute the current line of code and stop at the next + <item><p>Executes the current code line and stop at the next line.</p></item> <tag><em>Continue</em></tag> - <item><p>Continue the execution.</p></item> + <item><p>Continues the execution.</p></item> <tag><em>Finish</em></tag> - <item><p>Continue the execution until the current function + <item><p>Continues the execution until the current function returns.</p></item> <tag><em>Skip</em></tag> - <item><p>Skip the current line of code and stop at the next + <item><p>Skips the current code line and stop at the next line. If used on the last line in a function body, - the function will return <c>skipped</c>.</p></item> + the function returns <c>skipped</c>.</p></item> <tag><em>Time Out</em></tag> - <item><p>Simulate a timeout when executing a + <item><p>Simulates a time-out when executing a <c>receive...after</c> statement.</p></item> <tag><em>Stop</em></tag> - <item><p>Stop the execution of a running process, that is, make - the process stop as at a breakpoint. The command will take + <item><p>Stops the execution of a running process, that is, make + the process stop at a breakpoint. The command takes effect (visibly) the next time the process receives a message.</p></item> <tag><em>Where</em></tag> - <item><p>Make sure the current location of the execution is + <item><p>Verifies that the current location of the execution is visible in the code area.</p></item> <tag><em>Kill</em></tag> - <item><p>Terminate the process using <c>exit(Pid,kill)</c>.</p> + <item><p>Terminates the process using <c>exit(Pid,kill)</c>.</p> </item> <tag><em>Messages</em></tag> - <item><p>Inspect the message queue of the process. The queue is - printed in the evaluator area.</p></item> + <item><p>Inspects the message queue of the process. The queue is + displayed in the Evaluator area.</p></item> <tag><em>Back Trace</em></tag> - <item><p>Display the back trace of the process, a summary of - the current function calls on the stack, in the trace area. - Requires that the Trace area is visible and that the stack - trace option is 'Stack On, Tail' or 'Stack On, No Tail'.</p> + <item><p>Displays the back trace of the process, a summary of + the current function calls on the stack, in the Trace area. + Requires that the Trace area is visible and that the Stack + Trace option is <em>Stack On, Tail</em> or + <em>Stack On, No Tail</em>.</p> </item> <tag><em>Up</em></tag> - <item><p>Inspect the previous function call on the stack, + <item><p>Inspects the previous function call on the stack, showing the location and variable bindings.</p></item> <tag><em>Down</em></tag> - <item><p>Inspect the next function call on the stack, showing + <item><p>Inspects the next function call on the stack, showing the location and variable bindings.</p></item> </taglist> </section> <section> - <title>The Options Menu</title> + <title>Options Menu</title> <taglist> <tag><em>Trace Window</em></tag> - <item><p>Set which areas should be visible. Does not affect - other Attach Process windows.</p> - </item> + <item><p>Sets which areas are to be visible. Does not affect + other Attach Process windows.</p></item> <tag><em>Stack Trace</em></tag> - <item><p>Same as in <seealso marker="#monitor">the Monitor - window</seealso>, but only affects the debugged - process the window is attached to.</p> - </item> + <item><p>Same as in the <seealso marker="#monitor">Monitor + window</seealso>, but only affects the debugged + process the window is attached to.</p></item> <tag><em>Strings</em></tag> - <item><p>Same as in <seealso marker="#monitor">the Monitor - window</seealso>, but only affects the debugged - process the window is attached to.</p> - </item> + <item><p>Same as in the <seealso marker="#monitor">Monitor + window</seealso>, but only affects the debugged + process the window is attached to.</p></item> <tag><em>Back Trace Size...</em></tag> - <item><p>Set how many call frames should be fetched when + <item><p>Sets how many call frames are to be fetched when inspecting the call stack. Does not affect other Attach - Process windows.</p> - </item> + Process windows.</p></item> </taglist> </section> <section> - <title>Break, Windows and Help Menus</title> + <title>Break, Windows, and Help Menus</title> - <p>The Break, Windows and Help menus look the same as in - the Monitor window, see the chapter - <seealso marker="#monitor">The Monitor Window</seealso>, except - that the Breaks menu apply to the local breakpoints only.</p> + <p>The <em>Break</em>, <em>Windows</em>, and <em>Help</em> menus + are the same as in the + <seealso marker="#monitor">Monitor Window</seealso>, except + that the <em>Breaks</em> menu applies only to local + breakpoints.</p> </section> </section> <section> <marker id="view"/> - <title>The View Module Window</title> + <title>View Module Window</title> - <p>The View Module window shows the contents of an interpreted + <p>The View Module window displays the contents of an interpreted module and makes it possible to set breakpoints.</p> <image file="images/view.jpg"> - <icaption>The View Module Window.</icaption> + <icaption>View Module Window</icaption> </image> <p>The source code is indented and each line is prefixed with its line number.</p> - <p>Clicking a line will highlight it and select it to be the target - of the breakpoint functions available from the Break menu. - Doubleclicking a line will set a line breakpoint on that line. - Doubleclicking a line with an existing breakpoint will remove - the breakpoint.</p> + <p>Clicking a line highlights it and selects it to be the target + of the breakpoint functions available from the <em>Break</em> menu. + To set a line breakpoint on a line, double-click it. + To remove the breakpoint, double-click the line with an existing + breakpoint.</p> <p>Breakpoints are marked with a stop symbol.</p> <section> <title>File and Edit Menus</title> - <p>The File and Edit menus look the same as in the Attach Process - window, see the chapter <seealso marker="#attach">The Attach - Process Window</seealso>.</p> + <p>The <em>File</em> and <em>Edit</em> menus are the same as in the + <seealso marker="#attach">Attach Process Window</seealso>.</p> </section> <section> - <title>Break, Windows and Help Menus</title> + <title>Break, Windows, and Help Menus</title> - <p>The Break, Windows and Help menus look the same as in - the Monitor window, see the chapter - <seealso marker="#monitor">The Monitor Window</seealso>, except - that the Breaks menu apply to the local breakpoints only.</p> + <p>The <em>Break</em>, <em>Windows</em>, and <em>Help</em> menus + are the same as in the + <seealso marker="#monitor">Monitor Window</seealso>, except + that the <em>Break</em> menu applies only to local breakpoints.</p> </section> </section> @@ -862,14 +852,14 @@ c_break(Bindings) -> <title>Performance</title> <p>Execution of interpreted code is naturally slower than for - regularly compiled modules. Using the Debugger also increases + regularly compiled modules. Using Debugger also increases the number of processes in the system, as for each debugged process another process (the meta process) is created.</p> - <p>It is also worth to keep in mind that programs with timers may + <p>It is also worth to keep in mind that programs with timers can behave differently when debugged. This is especially true when - stopping the execution of a process, for example at a - breakpoint. Timeouts can then occur in other processes that + stopping the execution of a process (for example, at a + breakpoint). Time-outs can then occur in other processes that continue execution as normal.</p> </section> @@ -878,8 +868,8 @@ c_break(Bindings) -> <p>Code loading works almost as usual, except that interpreted modules are also stored in a database and debugged processes - uses only this stored code. Re-interpreting an interpreted - module will result in the new version being stored as well, but + use only this stored code. Reinterpreting an interpreted + module results in the new version being stored as well, but does not affect existing processes executing an older version of the code. This means that the code replacement mechanism of Erlang does not work for debugged processes.</p> @@ -888,22 +878,24 @@ c_break(Bindings) -> <section> <title>Debugging Remote Nodes</title> - <p>By using <c>debugger:start/1</c>, it can be specified if Debugger - should be started in local or global mode.</p> + <p>By using + <seealso marker="debugger#start/1">debugger:start/1</seealso>, + you can specify if Debugger is to be started in local or global + mode:</p> <pre> debugger:start(local | global)</pre> - <p>If no argument is provided, Debugger is started in global mode. - </p> + + <p>If no argument is provided, Debugger starts in global mode.</p> <p>In local mode, code is interpreted only at the current node. In global mode, code is interpreted at all known nodes. Processes - at other nodes executing interpreted code will automatically be - shown in the Monitor window and can be attached to like any other + at other nodes executing interpreted code are automatically + displayed in the Monitor window and can be attached to like any other debugged process.</p> - <p>It is possible, but definitely not recommended to start Debugger - in global mode on more than one node in a network, as they will - interfere with each other leading to inconsistent behaviour.</p> + <p>It is possible, but definitely not recommended, to start Debugger + in global mode on more than one node in a network, as the nodes + interfere with each other, leading to inconsistent behavior.</p> </section> </chapter> diff --git a/lib/debugger/doc/src/i.xml b/lib/debugger/doc/src/i.xml index 9ceba94b44..db89f23494 100644 --- a/lib/debugger/doc/src/i.xml +++ b/lib/debugger/doc/src/i.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1998</year><year>2013</year> + <year>1998</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -29,35 +29,36 @@ <rev></rev> </header> <module>i</module> - <modulesummary>Debugger/Interpreter Interface</modulesummary> + <modulesummary>Debugger/Interpreter Interface.</modulesummary> <description> - <p>The module <c>i</c> provides short forms for some of + <p>The <c>i</c> module provides short forms for some of the functions used by the graphical Debugger and some of - the functions in the <c>int</c> module, the Erlang interpreter. - </p> + the functions in module + <seealso marker="int"><c>int</c></seealso>, the Erlang interpreter.</p> <p>This module also provides facilities for displaying status information about interpreted processes and break points.</p> <p>It is possible to attach to interpreted processes by giving the corresponding process identity only. By default, an attachment - window pops up. Processes at other Erlang nodes can be + window is displayed. Processes at other Erlang nodes can be attached manually or automatically.</p> - <p>By preference, these functions can be included in the module - <c>shell_default</c>. By default, they are.</p> + <p>By preference, these functions can be included in module + <seealso marker="stdlib:shell_default"><c>stdlib:shell_default</c></seealso>. + By default, they are included in that module.</p> </description> <funcs> <func> <name>im() -> pid()</name> - <fsummary>Start a graphical monitor</fsummary> + <fsummary>Start a graphical monitor.</fsummary> <desc> <p>Starts a new graphical monitor. This is the Monitor window, - the main window of the Debugger. All of the Debugger and + the main window of Debugger. All the Debugger and interpreter functionality is accessed from the Monitor window. - The Monitor window displays the status of all processes that - have been/are executing interpreted modules.</p> + This window displays the status of all processes that + have been or are executing interpreted modules.</p> </desc> </func> @@ -66,7 +67,7 @@ <name>ii(AbsModule) -> {module, Module} | error</name> <name>ini(AbsModules) -> ok</name> <name>ini(AbsModule) -> {module, Module} | error</name> - <fsummary>Interpret a module</fsummary> + <fsummary>Interpret a module.</fsummary> <type> <v>AbsModules = [AbsModule]</v> <v>AbsModule = Module | File</v> @@ -85,7 +86,7 @@ <func> <name>iq(AbsModule) -> ok</name> <name>inq(AbsModule) -> ok</name> - <fsummary>Stop interpreting a module</fsummary> + <fsummary>Stop interpreting a module.</fsummary> <type> <v>AbsModule = Module | File</v> <v> Module = atom()</v> @@ -110,28 +111,27 @@ <func> <name>ip() -> ok</name> - <fsummary>Make a printout of the current status of all interpreted - processes</fsummary> + <fsummary>Print the current status of all interpreted + processes.</fsummary> <desc> - <p>Makes a printout of the current status of all interpreted - processes.</p> + <p>Prints the current status of all interpreted processes.</p> </desc> </func> <func> <name>ic() -> ok</name> <fsummary>Clear information about processes executing interpreted - code</fsummary> + code.</fsummary> <desc> <p>Clears information about processes executing interpreted code - byt removing all information about terminated processes.</p> + by removing all information about terminated processes.</p> </desc> </func> <func> <name>iaa(Flags) -> true</name> <name>iaa(Flags, Function) -> true</name> - <fsummary>Set when and how to attach to a process</fsummary> + <fsummary>Set when and how to attach to a process.</fsummary> <type> <v>Flags = [init | break | exit]</v> <v>Function = {Module,Name,Args}</v> @@ -139,42 +139,41 @@ <v> Args = [term()]</v> </type> <desc> - <p>Sets when and how to automatically attach to a debugged - process, see + <p>Sets when and how to attach to a debugged process + automatically, see <seealso marker="int#auto_attach/0">int:auto_attach/2</seealso>. <c>Function</c> defaults to the standard function used by - the Debugger.</p> + Debugger.</p> </desc> </func> <func> <name>ist(Flag) -> true</name> - <fsummary>Set how to save call frames</fsummary> + <fsummary>Set how to save call frames.</fsummary> <type> <v>Flag = all | no_tail | false</v> </type> <desc> <p>Sets how to save call frames in the stack, see - <seealso marker="int#stack_trace/0">int:stack_trace/1</seealso>. - </p> + <seealso marker="int#stack_trace/0">int:stack_trace/1</seealso>.</p> </desc> </func> <func> <name>ia(Pid) -> ok | no_proc</name> - <fsummary>Attach to a process</fsummary> + <fsummary>Attache to a process.</fsummary> <type> <v>Pid = pid()</v> </type> <desc> - <p>Attaches to the debugged process <c>Pid</c>. A Debugger + <p>Attaches to the debugged process <c>Pid</c>. An Attach Process window is opened for the process.</p> </desc> </func> <func> <name>ia(X,Y,Z) -> ok | no_proc</name> - <fsummary>Attach to a process</fsummary> + <fsummary>Attache to a process.</fsummary> <type> <v>X = Y = Z = int()</v> </type> @@ -186,7 +185,7 @@ <func> <name>ia(Pid, Function) -> ok | no_proc</name> - <fsummary>Attach to a process</fsummary> + <fsummary>Attache to a process.</fsummary> <type> <v>Pid = pid()</v> <v>Function = {Module,Name}</v> @@ -194,14 +193,14 @@ </type> <desc> <p>Attaches to the debugged process <c>Pid</c>. The interpreter - will call <c>spawn(Module, Name, [Pid])</c> (and ignore + calls <c>spawn(Module, Name, [Pid])</c> (and ignores the result).</p> </desc> </func> <func> <name>ia(X,Y,Z, Function) -> ok | no_proc</name> - <fsummary>Attach to a process</fsummary> + <fsummary>Attache to a process.</fsummary> <type> <v>X = Y = Z = int()</v> <v>Function = {Module,Name}</v> @@ -211,15 +210,15 @@ <p>Same as <c>ia(Pid, Function)</c>, where <c>Pid</c> is the result of calling the shell function <c>pid(X,Y,Z)</c>. An attached process is expected to call the unofficial - <c>int:attached(Pid)</c> function and to be able to handle - messages from the interpreter, see <c>dbg_wx_trace.erl</c> for - an example.</p> + function <c>int:attached(Pid)</c> and to be able to handle + messages from the interpreter. For an example, see + <c>dbg_wx_trace.erl</c>.</p> </desc> </func> <func> <name>ib(Module, Line) -> ok | {error, break_exists}</name> - <fsummary>Create a breakpoint</fsummary> + <fsummary>Create a breakpoint.</fsummary> <type> <v>Module = atom()</v> <v>Line = int()</v> @@ -232,20 +231,20 @@ <func> <name>ib(Module, Name, Arity) -> ok | {error, function_not_found} </name> - <fsummary>Create breakpoints in the specified function</fsummary> + <fsummary>Create breakpoints in the specified function.</fsummary> <type> <v>Module = Name = atom()</v> <v>Arity = int()</v> </type> <desc> <p>Creates breakpoints at the first line of every clause of - the <c>Module:Name/Arity</c> function.</p> + function <c>Module:Name/Arity</c>.</p> </desc> </func> <func> <name>ir() -> ok</name> - <fsummary>Delete all breakpoints</fsummary> + <fsummary>Delete all breakpoints.</fsummary> <desc> <p>Deletes all breakpoints.</p> </desc> @@ -253,7 +252,7 @@ <func> <name>ir(Module) -> ok</name> - <fsummary>Delete all breakpoints in a module</fsummary> + <fsummary>Delete all breakpoints in a module.</fsummary> <type> <v>Module = atom()</v> </type> @@ -264,61 +263,57 @@ <func> <name>ir(Module, Line) -> ok</name> - <fsummary>Delete a breakpoint</fsummary> + <fsummary>Delete a breakpoint.</fsummary> <type> <v>Module = atom()</v> <v>Line = int()</v> </type> <desc> - <p>Deletes the breakpoint located at <c>Line</c> in - <c>Module</c>.</p> + <p>Deletes the breakpoint at <c>Line</c> in <c>Module</c>.</p> </desc> </func> <func> <name>ir(Module, Name, Arity) -> ok | {error, function_not_found} </name> - <fsummary>Delete breakpoints from the specified function - </fsummary> + <fsummary>Delete breakpoints from the specified function.</fsummary> <type> <v>Module = Name = atom()</v> <v>Arity = int()</v> </type> <desc> <p>Deletes the breakpoints at the first line of every clause of - the <c>Module:Name/Arity</c> function.</p> + function <c>Module:Name/Arity</c>.</p> </desc> </func> <func> <name>ibd(Module, Line) -> ok</name> - <fsummary>Make a breakpoint inactive</fsummary> + <fsummary>Make a breakpoint inactive.</fsummary> <type> <v>Module = atom()</v> <v>Line = int()</v> </type> <desc> - <p>Makes the breakpoint at <c>Line</c> in <c>Module</c> - inactive.</p> + <p>Makes the breakpoint at <c>Line</c> in <c>Module</c> inactive.</p> </desc> </func> <func> <name>ibe(Module, Line) -> ok</name> - <fsummary>Make a breakpoint active</fsummary> + <fsummary>Make a breakpoint active.</fsummary> <type> <v>Module = atom()</v> <v>Line = int()</v> </type> <desc> - <p>Makes the breakpoint at <c>Line</c> in <c>Module</c> active. - </p> + <p>Makes the breakpoint at <c>Line</c> in <c>Module</c> active.</p> </desc> </func> <func> <name>iba(Module, Line, Action) -> ok</name> - <fsummary>Set the trigger action of a breakpoint</fsummary> + <fsummary>Set the trigger action of a breakpoint.</fsummary> <type> <v>Module = atom()</v> <v>Line = int()</v> @@ -332,7 +327,7 @@ <func> <name>ibc(Module, Line, Function) -> ok</name> - <fsummary>Set the conditional test of a breakpoint</fsummary> + <fsummary>Set the conditional test of a breakpoint.</fsummary> <type> <v>Module = atom()</v> <v>Line = int()</v> @@ -346,46 +341,44 @@ <p>The conditional test is performed by calling <c>Module:Name(Bindings)</c>, where <c>Bindings</c> is the current variable bindings. The function must return - <c>true</c> (break) or <c>false</c> (do not break). Use - <c>int:get_binding(Var, Bindings)</c> to retrieve the value - of a variable <c>Var</c>.</p> + <c>true</c> (break) or <c>false</c> (do not break). + To retrieve the value of a variable <c>Var</c>, use + <seealso marker="int#get_binding/2">int:get_binding(Var, Bindings)</seealso>.</p> </desc> </func> <func> <name>ipb() -> ok</name> - <fsummary>Make a printout of all existing breakpoints</fsummary> + <fsummary>Print all existing breakpoints.</fsummary> <desc> - <p>Makes a printout of all existing breakpoints.</p> + <p>Prints all existing breakpoints.</p> </desc> </func> <func> <name>ipb(Module) -> ok</name> - <fsummary>Make a printout of all breakpoints in a module - </fsummary> + <fsummary>Print all existing breakpoints in a module.</fsummary> <type> <v>Module = atom()</v> </type> <desc> - <p>Makes a printout of all existing breakpoints in - <c>Module</c>.</p> + <p>Prints all existing breakpoints in <c>Module</c>.</p> </desc> </func> <func> <name>iv() -> atom()</name> - <fsummary>Current version number of the interpreter</fsummary> + <fsummary>Return the current version number of the interpreter. + </fsummary> <desc> <p>Returns the current version number of the interpreter. - The same as the version number of the Debugger application. - </p> + Same as the version number of the <c>Debugger</c> application.</p> </desc> </func> <func> <name>help() -> ok</name> - <fsummary>Print help text</fsummary> + <fsummary>Print help text.</fsummary> <desc> <p>Prints help text.</p> </desc> @@ -393,15 +386,8 @@ </funcs> <section> - <title>Usage</title> - - <p>Refer to the Debugger User's Guide for information about - the Debugger.</p> - </section> - - <section> <title>See Also</title> - <p><c>int(3)</c></p> + <p><seealso marker="int"><c>int(3)</c></seealso></p> </section> </erlref> diff --git a/lib/debugger/doc/src/int.xml b/lib/debugger/doc/src/int.xml index ea21d04a07..31e9dfe923 100644 --- a/lib/debugger/doc/src/int.xml +++ b/lib/debugger/doc/src/int.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1998</year><year>2013</year> + <year>1998</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -29,16 +29,16 @@ <rev></rev> </header> <module>int</module> - <modulesummary>Interpreter Interface</modulesummary> + <modulesummary>Interpreter Interface.</modulesummary> <description> <p>The Erlang interpreter provides mechanisms for breakpoints and - stepwise execution of code. It is mainly intended to be used by - the <em>Debugger</em>, see Debugger User's Guide and - <c>debugger(3)</c>.</p> + stepwise execution of code. It is primarily intended to be used by + Debugger, see the User's Guide and + <seealso marker="debugger"><c>debugger(3)</c></seealso>.</p> - <p>From the shell, it is possible to:</p> - <list> - <item>Specify which modules should be interpreted.</item> + <p>The following can be done from the shell:</p> + <list type="bulleted"> + <item>Specify the modules to be interpreted.</item> <item>Specify breakpoints.</item> <item>Monitor the current status of all processes executing code in interpreted modules, also processes at other Erlang nodes. @@ -48,45 +48,48 @@ <p>By <em>attaching to</em> a process executing interpreted code, it is possible to examine variable bindings and order stepwise execution. This is done by sending and receiving information - to/from the process via a third process, called the meta process. - It is possible to implement your own attached process. See + to/from the process through a third process, called the meta + process. You can implement your own attached process. See <c>int.erl</c> for available functions and <c>dbg_wx_trace.erl</c> for possible messages.</p> - <p>The interpreter depends on the Kernel, STDLIB and GS - applications, which means modules belonging to any of these - applications are not allowed to be interpreted as it could lead + <p>The interpreter depends on the Kernel, STDLIB, and + GS applications. This means that modules belonging to any of + these applications are not allowed to be interpreted, as it could lead to a deadlock or emulator crash. This also applies to modules - belonging to the Debugger application itself.</p> + belonging to the Debugger application.</p> </description> <section> + <marker id="int_breakpoints"/> <title>Breakpoints</title> <p>Breakpoints are specified on a line basis. When a process executing code in an interpreted module reaches a breakpoint, it - will stop. This means that that a breakpoint must be set at an - executable line, that is, a line of code containing an executable + stops. This means that a breakpoint must be set at an + executable line, that is, a code line containing an executable expression.</p> - <p>A breakpoint have a status, a trigger action and may have a - condition associated with it. The status is either <em>active</em> - or <em>inactive</em>. An inactive breakpoint is ignored. When a - breakpoint is reached, the trigger action specifies if - the breakpoint should continue to be active (<em>enable</em>), if - it should become inactive (<em>disable</em>), or if it should be - removed (<em>delete</em>). A condition is a tuple - <c>{Module,Name}</c>. When the breakpoint is reached, - <c>Module:Name(Bindings)</c> is called. If this evaluates to - <c>true</c>, execution will stop. If this evaluates to - <c>false</c>, the breakpoint is ignored. <c>Bindings</c> contains - the current variable bindings, use <c>get_binding</c> to retrieve - the value for a given variable.</p> + <p>A breakpoint has the following:</p> + <list type="bulleted"> + <item>A status, which is <em>active</em> or <em>inactive</em>. An + inactive breakpoint is ignored.</item> + <item>A trigger action. When a breakpoint is reached, the trigger + action specifies if the breakpoint is to continue as active + (<em>enable</em>), or to become inactive (<em>disable</em>), or + to be removed (<em>delete</em>).</item> + <item>Optionally an associated condition. A condition is a tuple + <c>{Module,Name}</c>. When the breakpoint is reached, + <c>Module:Name(Bindings)</c> is called. If it evaluates to + <c>true</c>, execution stops. If it evaluates to <c>false</c>, + the breakpoint is ignored. <c>Bindings</c> contains the current + variable bindings. To retrieve the value for a specified variable, + use <c>get_binding</c>.</item> + </list> <p>By default, a breakpoint is active, has trigger action - <c>enable</c> and has no condition associated with it. For more - detailed information about breakpoints, refer to Debugger User's - Guide.</p> + <c>enable</c>, and has no associated condition. For details + about breakpoints, see the User's Guide.</p> </section> <funcs> @@ -95,7 +98,7 @@ <name>i(AbsModules) -> ok</name> <name>ni(AbsModule) -> {module,Module} | error</name> <name>ni(AbsModules) -> ok</name> - <fsummary>Interpret a module</fsummary> + <fsummary>Interpret a module.</fsummary> <type> <v>AbsModules = [AbsModule]</v> <v>AbsModule = Module | File | [Module | File]</v> @@ -107,41 +110,43 @@ the module only at the current node. <c>ni/1</c> interprets the module at all known nodes.</p> - <p>A module may be given by its module name (atom) or by its - file name. If given by its module name, the object code + <p>A module can be specified by its module name (atom) or + filename.</p> + + <p>If specified by its module name, the object code <c>Module.beam</c> is searched for in the current path. The source code <c>Module.erl</c> is searched for first in - the same directory as the object code, then in a <c>src</c> + the same directory as the object code, then in an <c>src</c> directory next to it.</p> - <p>If given by its file name, the file name may include a path - and the <c>.erl</c> extension may be omitted. The object code + <p>If specified by its filename, the filename can include a path + and the <c>.erl</c> extension can be omitted. The object code <c>Module.beam</c> is searched for first in the same directory as the source code, then in an <c>ebin</c> directory next to it, and then in the current path.</p> <note> - <p>The interpreter needs both the source code and the object - code, and the object code <em>must</em> include debug - information. That is, only modules compiled with the option + <p>The interpreter requires both the source code and the object + code. The object code <em>must</em> include debug + information, that is, only modules compiled with option <c>debug_info</c> set can be interpreted.</p> </note> <p>The functions returns <c>{module,Module}</c> if the module - was interpreted, or <c>error</c> if it was not.</p> + was interpreted, otherwise <c>error</c> is returned.</p> - <p>The argument may also be a list of modules/file names, in + <p>The argument can also be a list of modules or filenames, in which case the function tries to interpret each module as - specified above. The function then always returns <c>ok</c>, - but prints some information to stdout if a module could not be - interpreted.</p> + specified earlier. The function then always returns <c>ok</c>, + but prints some information to <c>stdout</c> if a module + cannot be interpreted.</p> </desc> </func> <func> <name>n(AbsModule) -> ok</name> <name>nn(AbsModule) -> ok</name> - <fsummary>Stop interpreting a module</fsummary> + <fsummary>Stop interpreting a module.</fsummary> <type> <v>AbsModule = Module | File | [Module | File]</v> <v> Module = atom()</v> @@ -152,14 +157,14 @@ interpreting the module only at the current node. <c>nn/1</c> stops interpreting the module at all known nodes.</p> - <p>As for <c>i/1</c> and <c>ni/1</c>, a module may be given by - either its module name or its file name.</p> + <p>As for <c>i/1</c> and <c>ni/1</c>, a module can be specified by + its module name or filename.</p> </desc> </func> <func> <name>interpreted() -> [Module]</name> - <fsummary>Get all interpreted modules</fsummary> + <fsummary>Get all interpreted modules.</fsummary> <type> <v>Module = atom()</v> </type> @@ -170,20 +175,20 @@ <func> <name>file(Module) -> File | {error,not_loaded}</name> - <fsummary>Get the file name for an interpreted module</fsummary> + <fsummary>Get the filename for an interpreted module.</fsummary> <type> <v>Module = atom()</v> <v>File = string()</v> </type> <desc> - <p>Returns the source code file name <c>File</c> for an + <p>Returns the source code filename <c>File</c> for an interpreted module <c>Module</c>.</p> </desc> </func> <func> <name>interpretable(AbsModule) -> true | {error,Reason}</name> - <fsummary>Check if a module is possible to interpret</fsummary> + <fsummary>Check if a module can be interpreted.</fsummary> <type> <v>AbsModule = Module | File</v> <v> Module = atom()</v> @@ -193,45 +198,59 @@ <v> App = atom()</v> </type> <desc> - <p>Checks if a module is possible to interpret. The module can - be given by its module name <c>Module</c> or its source file - name <c>File</c>. If given by a module name, the module is - searched for in the code path.</p> - - <p>The function returns <c>true</c> if both source code and - object code for the module is found, the module has been - compiled with the option <c>debug_info</c> set and does not - belong to any of the applications Kernel, STDLIB, GS or - Debugger itself.</p> - - <p>The function returns <c>{error,Reason}</c> if the module for - some reason is not possible to interpret.</p> - - <p><c>Reason</c> is <c>no_src</c> if no source code is found or - <c>no_beam</c> if no object code is found. It is assumed that - the source- and object code are located either in the same - directory, or in <c>src</c> and <c>ebin</c> directories next - to each other.</p> - - <p><c>Reason</c> is <c>no_debug_info</c> if the module has not - been compiled with the option <c>debug_info</c> set.</p> - - <p><c>Reason</c> is <c>badarg</c> if <c>AbsModule</c> is not - found. This could be because the specified file does not - exist, or because <c>code:which/1</c> does not return a - beam file name, which is the case not only for non-existing - modules but also for modules which are preloaded or cover - compiled.</p> - - <p><c>Reason</c> is <c>{app,App}</c> where <c>App</c> is - <c>kernel</c>, <c>stdlib</c>, <c>gs</c> or <c>debugger</c> if - <c>AbsModule</c> belongs to one of these applications.</p> - - <p>Note that the function can return <c>true</c> for a module - which in fact is not interpretable in the case where + <p>Checks if a module can be interpreted. The module can be + specified by its module name <c>Module</c> or its source + filename <c>File</c>. If specified by a module name, the module + is searched for in the code path.</p> + + <p>The function returns <c>true</c> if all of the following + apply:</p> + <list type="bulleted"> + <item>Both source code and object code for the module is + found.</item> + <item>The module has been compiled with option <c>debug_info</c> + set.</item> + <item>The module does not belong to any of the applications + Kernel, STDLIB, GS, or Debugger.</item> + </list> + + <p>The function returns <c>{error,Reason}</c> if the module cannot + be interpreted. <c>Reason</c> can have the following values:</p> + <taglist> + <tag><c>no_src</c></tag> + <item><p>No source code is found. + It is assumed that the source code and object code are located + either in the same directory, or in <c>src</c> and <c>ebin</c> + directories next to each other.</p></item> + + <tag><c>no_beam</c></tag> + <item><p>No object code is found. + It is assumed that the source code and object code are located + either in the same directory, or in <c>src</c> and <c>ebin</c> + directories next to each other.</p></item> + + <tag><c>no_debug_info</c></tag> + <item><p>The module has not been compiled with option + <c>debug_info</c> set.</p></item> + + <tag><c>badarg</c></tag> + <item><p><c>AbsModule</c> is not found. This could be because + the specified file does not exist, or because + <c>code:which/1</c> does not return a BEAM filename, + which is the case not only for non-existing modules but also + for modules that are preloaded or cover-compiled.</p></item> + + <tag><c>{app,App}</c></tag> + <item><p><c>App</c> is <c>kernel</c>, <c>stdlib</c>, <c>gs</c>, + or <c>debugger</c> if <c>AbsModule</c> belongs to one of these + applications.</p></item> + </taglist> + + <p>Notice that the function can return <c>true</c> for a module + that in fact is not interpretable in the case where the module is marked as sticky or resides in a directory - marked as sticky, as this is not discovered until - the interpreter actually tries to load the module.</p> + marked as sticky. The reason is that this is not discovered + until the interpreter tries to load the module.</p> </desc> </func> @@ -239,7 +258,7 @@ <name>auto_attach() -> false | {Flags,Function}</name> <name>auto_attach(false)</name> <name>auto_attach(Flags, Function)</name> - <fsummary>Get/set when and how to attach to a process</fsummary> + <fsummary>Get and set when and how to attach to a process.</fsummary> <type> <v>Flags = [init | break | exit]</v> <v>Function = {Module,Name,Args}</v> @@ -247,24 +266,24 @@ <v> Args = [term()]</v> </type> <desc> - <p>Gets and sets when and how to automatically attach to a + <p>Gets and sets when and how to attach automatically to a process executing code in interpreted modules. <c>false</c> - means never automatically attach, this is the default. + means never attach automatically, this is the default. Otherwise automatic attach is defined by a list of flags and - a function. The following flags may be specified:</p> - <list> - <item><c>init</c> - attach when a process for the very first + a function. The following flags can be specified:</p> + <list type="bulleted"> + <item><c>init</c> - Attach when a process for the first time calls an interpreted function.</item> - <item><c>break</c> - attach whenever a process reaches a + <item><c>break</c> - Attach whenever a process reaches a breakpoint.</item> - <item><c>exit</c> - attach when a process terminates.</item> + <item><c>exit</c> - Attach when a process terminates.</item> </list> <p>When the specified event occurs, the function <c>Function</c> - will be called as:</p> + is called as:</p> <pre> -spawn(Module, Name, [Pid | Args]) - </pre> +spawn(Module, Name, [Pid | Args])</pre> + <p><c>Pid</c> is the pid of the process executing interpreted code.</p> </desc> @@ -273,7 +292,7 @@ spawn(Module, Name, [Pid | Args]) <func> <name>stack_trace() -> Flag</name> <name>stack_trace(Flag)</name> - <fsummary>Get/set if and how to save call frames</fsummary> + <fsummary>Get and set if and how to save call frames.</fsummary> <type> <v>Flag = all | no_tail | false</v> </type> @@ -281,25 +300,30 @@ spawn(Module, Name, [Pid | Args]) <p>Gets and sets how to save call frames in the stack. Saving call frames makes it possible to inspect the call chain of a process, and is also used to emulate the stack trace if an - error (an exception of class error) occurs.</p> - <list> - <item><c>all</c> - save information about all current calls, - that is, function calls that have not yet returned a value. - </item> - <item><c>no_tail</c> - save information about current calls, + error (an exception of class error) occurs. The following + flags can be specified:</p> + <taglist> + <tag><c>all</c></tag> + <item><p>Save information about all current calls, + that is, function calls that have not yet returned a value.</p> + </item> + + <tag><c>no_tail</c></tag> + <item><p>Save information about current calls, but discard previous information when a tail recursive call - is made. This option consumes less memory and may be + is made. This option consumes less memory and can be necessary to use for processes with long lifetimes and many - tail recursive calls. This is the default.</item> - <item><c>false</c> - do not save any information about current - calls.</item> - </list> + tail recursive calls. This is the default.</p></item> + + <tag><c>false</c></tag> + <item><p>Save no information about currentcalls.</p></item> + </taglist> </desc> </func> <func> <name>break(Module, Line) -> ok | {error,break_exists}</name> - <fsummary>Create a breakpoint</fsummary> + <fsummary>Create a breakpoint.</fsummary> <type> <v>Module = atom()</v> <v>Line = int()</v> @@ -311,86 +335,80 @@ spawn(Module, Name, [Pid | Args]) <func> <name>delete_break(Module, Line) -> ok</name> - <fsummary>Delete a breakpoint</fsummary> + <fsummary>Delete a breakpoint.</fsummary> <type> <v>Module = atom()</v> <v>Line = int()</v> </type> <desc> - <p>Deletes the breakpoint located at <c>Line</c> in - <c>Module</c>.</p> + <p>Deletes the breakpoint at <c>Line</c> in <c>Module</c>.</p> </desc> </func> <func> <name>break_in(Module, Name, Arity) -> ok | {error,function_not_found}</name> - <fsummary>Create breakpoints in the specified function</fsummary> + <fsummary>Create breakpoints in the specified function.</fsummary> <type> <v>Module = Name = atom()</v> <v>Arity = int()</v> </type> <desc> <p>Creates a breakpoint at the first line of every clause of - the <c>Module:Name/Arity</c> function.</p> + function <c>Module:Name/Arity</c>.</p> </desc> </func> <func> <name>del_break_in(Module, Name, Arity) -> ok | {error,function_not_found}</name> - <fsummary>Delete breakpoints from the specified function - </fsummary> + <fsummary>Delete breakpoints from the specified function.</fsummary> <type> <v>Module = Name = atom()</v> <v>Arity = int()</v> </type> <desc> <p>Deletes the breakpoints at the first line of every clause of - the <c>Module:Name/Arity</c> function. - </p> + function <c>Module:Name/Arity</c>.</p> </desc> </func> <func> <name>no_break() -> ok</name> <name>no_break(Module) -> ok</name> - <fsummary>Delete all breakpoints</fsummary> + <fsummary>Delete all breakpoints.</fsummary> <desc> - <p>Deletes all breakpoints, or all breakpoints in <c>Module</c>. - </p> + <p>Deletes all breakpoints, or all breakpoints in <c>Module</c>.</p> </desc> </func> <func> <name>disable_break(Module, Line) -> ok</name> - <fsummary>Make a breakpoint inactive</fsummary> + <fsummary>Make a breakpoint inactive.</fsummary> <type> <v>Module = atom()</v> <v>Line = int()</v> </type> <desc> - <p>Makes the breakpoint at <c>Line</c> in <c>Module</c> - inactive.</p> + <p>Makes the breakpoint at <c>Line</c> in <c>Module</c> inactive.</p> </desc> </func> <func> <name>enable_break(Module, Line) -> ok</name> - <fsummary>Make a breakpoint active</fsummary> + <fsummary>Make a breakpoint active.</fsummary> <type> <v>Module = atom()</v> <v>Line = int()</v> </type> <desc> - <p>Makes the breakpoint at <c>Line</c> in <c>Module</c> active. - </p> + <p>Makes the breakpoint at <c>Line</c> in <c>Module</c> active.</p> </desc> </func> <func> <name>action_at_break(Module, Line, Action) -> ok</name> - <fsummary>Set the trigger action of a breakpoint</fsummary> + <fsummary>Set the trigger action of a breakpoint.</fsummary> <type> <v>Module = atom()</v> <v>Line = int()</v> @@ -404,7 +422,7 @@ spawn(Module, Name, [Pid | Args]) <func> <name>test_at_break(Module, Line, Function) -> ok</name> - <fsummary>Set the conditional test of a breakpoint</fsummary> + <fsummary>Set the conditional test of a breakpoint.</fsummary> <type> <v>Module = atom()</v> <v>Line = int()</v> @@ -414,14 +432,14 @@ spawn(Module, Name, [Pid | Args]) <desc> <p>Sets the conditional test of the breakpoint at <c>Line</c> in <c>Module</c> to <c>Function</c>. The function must - fulfill the requirements specified in the section - <em>Breakpoints</em> above.</p> + fulfill the requirements specified in section + <seealso marker="#int_breakpoints">Breakpoints</seealso>.</p> </desc> </func> <func> <name>get_binding(Var, Bindings) -> {value,Value} | unbound</name> - <fsummary>Retrieve a variable binding</fsummary> + <fsummary>Retrieve a variable binding.</fsummary> <type> <v>Var = atom()</v> <v>Bindings = term()</v> @@ -437,7 +455,7 @@ spawn(Module, Name, [Pid | Args]) <func> <name>all_breaks() -> [Break]</name> <name>all_breaks(Module) -> [Break]</name> - <fsummary>Get all breakpoints</fsummary> + <fsummary>Get all breakpoints.</fsummary> <type> <v>Break = {Point,Options}</v> <v> Point = {Module,Line}</v> @@ -451,15 +469,14 @@ spawn(Module, Name, [Pid | Args]) <v> Name = atom()</v> </type> <desc> - <p>Gets all breakpoints, or all breakpoints in <c>Module</c>. - </p> + <p>Gets all breakpoints, or all breakpoints in <c>Module</c>.</p> </desc> </func> <func> <name>snapshot() -> [Snapshot]</name> <fsummary>Get information about all processes executing interpreted - code</fsummary> + code.</fsummary> <type> <v>Snapshot = {Pid, Function, Status, Info}</v> <v> Pid = pid()</v> @@ -475,26 +492,27 @@ spawn(Module, Name, [Pid | Args]) <desc> <p>Gets information about all processes executing interpreted code. </p> - <list> - <item><c>Pid</c> - process identifier.</item> - <item><c>Function</c> - first interpreted function called by + <list type="bulleted"> + <item><c>Pid</c> - Process identifier.</item> + <item><c>Function</c> - First interpreted function called by the process.</item> - <item><c>Status</c> - current status of the process.</item> - <item><c>Info</c> - additional information.</item> + <item><c>Status</c> - Current status of the process.</item> + <item><c>Info</c> - More information.</item> </list> - <p><c>Status</c> is one of:</p> - <list> - <item><c>idle</c> - the process is no longer executing + + <p><c>Status</c> is one of the following:</p> + <list type="bulleted"> + <item><c>idle</c> - The process is no longer executing interpreted code. <c>Info={}</c>.</item> - <item><c>running</c> - the process is running. <c>Info={}</c>. + <item><c>running</c> - The process is running. <c>Info={}</c>. </item> - <item><c>waiting</c> - the process is waiting at a + <item><c>waiting</c> - The process is waiting at a <c>receive</c>. <c>Info={}</c>.</item> - <item><c>break</c> - process execution has been stopped, + <item><c>break</c> - Process execution is stopped, normally at a breakpoint. <c>Info={Module,Line}</c>.</item> - <item><c>exit</c> - the process has terminated. + <item><c>exit</c> - The process is terminated. <c>Info=ExitReason</c>.</item> - <item><c>no_conn</c> - the connection is down to the node + <item><c>no_conn</c> - The connection is down to the node where the process is running. <c>Info={}</c>.</item> </list> </desc> @@ -503,7 +521,7 @@ spawn(Module, Name, [Pid | Args]) <func> <name>clear() -> ok</name> <fsummary>Clear information about processes executing interpreted - code</fsummary> + code.</fsummary> <desc> <p>Clears information about processes executing interpreted code by removing all information about terminated processes.</p> @@ -513,13 +531,13 @@ spawn(Module, Name, [Pid | Args]) <func> <name>continue(Pid) -> ok | {error,not_interpreted}</name> <name>continue(X,Y,Z) -> ok | {error,not_interpreted}</name> - <fsummary>Resume process execution</fsummary> + <fsummary>Resume process execution.</fsummary> <type> <v>Pid = pid()</v> <v>X = Y = Z = int()</v> </type> <desc> - <p>Resume process execution for <c>Pid</c>, or for + <p>Resumes process execution for <c>Pid</c> or <c>c:pid(X,Y,Z)</c>.</p> </desc> </func> diff --git a/lib/debugger/doc/src/introduction.xml b/lib/debugger/doc/src/introduction.xml new file mode 100644 index 0000000000..9f5f279bb0 --- /dev/null +++ b/lib/debugger/doc/src/introduction.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> +<header> + <copyright> + <year>1997</year><year>2013</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + </legalnotice> + + <title>Introduction</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>introduction.xml</file> + </header> + + <section> + <title>Scope</title> + <p>Debugger is a graphical user interface for the Erlang + interpreter, which can be used for debugging and testing of + Erlang programs. For example, breakpoints can be set, code can be + single-stepped and variable values can be displayed and changed. + </p> + + <p>The Erlang interpreter can also be accessed through the interface + module <seealso marker="int"><c>int(3)</c></seealso>. + </p> + + <warning> + <p>Debugger might at some point + start tracing on the processes that execute the interpreted + code. This means that a conflict occurs if tracing by other + means is started on any of these processes.</p> + </warning> + </section> + + <section> + <title>Prerequisites</title> + <p>It is assumed that the reader is familiar with the Erlang + programming language.</p> + <p>Modules to be debugged must include debug information, + for example, <c>erlc +debug_info MODULE.erl</c>.</p> + </section> + +</chapter> + + diff --git a/lib/debugger/doc/src/notes.xml b/lib/debugger/doc/src/notes.xml index 67cfe20d83..6e8cf54ae4 100644 --- a/lib/debugger/doc/src/notes.xml +++ b/lib/debugger/doc/src/notes.xml @@ -33,6 +33,37 @@ <p>This document describes the changes made to the Debugger application.</p> +<section><title>Debugger 4.1.2</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Documentation corrections.</p> + <p> + Own Id: OTP-12994</p> + </item> + </list> + </section> + +</section> + +<section><title>Debugger 4.1.1</title> + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix crash when starting a quick debugging session. Thanks + Alan Duffield.</p> + <p> + Own Id: OTP-12911 Aux Id: seq12906 </p> + </item> + </list> + </section> + +</section> + + <section><title>Debugger 4.1</title> <section><title>Improvements and New Features</title> diff --git a/lib/debugger/doc/src/part.xml b/lib/debugger/doc/src/part.xml index 7515c0ad5b..ce1edbd978 100644 --- a/lib/debugger/doc/src/part.xml +++ b/lib/debugger/doc/src/part.xml @@ -4,7 +4,7 @@ <part xmlns:xi="http://www.w3.org/2001/XInclude"> <header> <copyright> - <year>1997</year><year>2013</year> + <year>1997</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -27,14 +27,10 @@ <docno></docno> <date>1998-05-12</date> <rev>B</rev> - <file>part.sgml</file> + <file>part.xml</file> </header> - <description> - <p><em>Debugger</em> is a graphical tool which can be used for - debugging and testing of Erlang programs. For example, breakpoints - can be set, code can be single stepped and variable values can be - displayed and changed.</p> - </description> + <description></description> + <xi:include href="introduction.xml"/> <xi:include href="debugger_chapter.xml"/> </part> diff --git a/lib/debugger/doc/src/ref_man.xml b/lib/debugger/doc/src/ref_man.xml index 6df9e90c2c..c44f07f912 100644 --- a/lib/debugger/doc/src/ref_man.xml +++ b/lib/debugger/doc/src/ref_man.xml @@ -28,12 +28,7 @@ <date></date> <rev></rev> </header> - <description> - <p><em>Debugger</em> is a graphical tool which can be used for - debugging and testing of Erlang programs. For example, breakpoints - can be set, code can be single stepped and variable values can be - displayed and changed.</p> - </description> + <description></description> <xi:include href="debugger.xml"/> <xi:include href="i.xml"/> <xi:include href="int.xml"/> diff --git a/lib/debugger/src/dbg_icmd.erl b/lib/debugger/src/dbg_icmd.erl index 4c34f253c6..1b274e20ae 100644 --- a/lib/debugger/src/dbg_icmd.erl +++ b/lib/debugger/src/dbg_icmd.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2015. All Rights Reserved. +%% Copyright Ericsson AB 1998-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -267,7 +267,7 @@ handle_int_msg({old_code,Mod}, Status, Bs, #ieval{level=Le,module=M}=Ieval) -> if Status =:= idle, Le =:= 1 -> - erase([Mod|db]), + erase(?DB_REF_KEY(Mod)), put(cache, []); true -> case dbg_istk:in_use_p(Mod, M) of @@ -277,7 +277,7 @@ handle_int_msg({old_code,Mod}, Status, Bs, exit(get(self), kill), dbg_ieval:exception(exit, old_code, Bs, Ieval); false -> - erase([Mod|db]), + erase(?DB_REF_KEY(Mod)), put(cache, []) end end; diff --git a/lib/debugger/src/dbg_ieval.erl b/lib/debugger/src/dbg_ieval.erl index 7ed371a653..f5e079ef7e 100644 --- a/lib/debugger/src/dbg_ieval.erl +++ b/lib/debugger/src/dbg_ieval.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2015. All Rights Reserved. +%% Copyright Ericsson AB 1998-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -560,7 +560,7 @@ get_function(Mod, Name, Args, extern) -> end. db_ref(Mod) -> - case get([Mod|db]) of + case get(?DB_REF_KEY(Mod)) of undefined -> case dbg_iserver:call(get(int), {get_module_db, Mod, get(self)}) of @@ -572,7 +572,7 @@ db_ref(Mod) -> Node =/= node() -> {Node,ModDb}; true -> ModDb end, - put([Mod|db], DbRef), + put(?DB_REF_KEY(Mod), DbRef), DbRef end; DbRef -> diff --git a/lib/debugger/src/dbg_ieval.hrl b/lib/debugger/src/dbg_ieval.hrl index 95d0842b19..ad422a9e4a 100644 --- a/lib/debugger/src/dbg_ieval.hrl +++ b/lib/debugger/src/dbg_ieval.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2011. All Rights Reserved. +%% Copyright Ericsson AB 2005-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -27,3 +27,5 @@ %% (i.e. the next call will leave interpreted code). top = false }). + +-define(DB_REF_KEY(Mod), {Mod,db}). diff --git a/lib/debugger/src/dbg_wx_trace.erl b/lib/debugger/src/dbg_wx_trace.erl index b246c71284..f9c60f9b72 100644 --- a/lib/debugger/src/dbg_wx_trace.erl +++ b/lib/debugger/src/dbg_wx_trace.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2014. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -73,6 +73,10 @@ start(Pid, TraceWin, BackTrace) -> start(Pid, TraceWin, BackTrace, Strings) -> case whereis(dbg_wx_mon) of + undefined -> + Parent = wx:new(), + Env = wx:get_env(), + start(Pid, Env, Parent, TraceWin, BackTrace, Strings); Monitor when is_pid(Monitor) -> Monitor ! {?MODULE, self(), get_env}, receive @@ -807,7 +811,7 @@ gui_show_module(Win, Mod, Line, Mod, _Pid, How) -> dbg_wx_trace_win:mark_line(Win, Line, How); gui_show_module(Win, Mod, Line, _Cm, Pid, How) -> Win2 = case dbg_wx_trace_win:is_shown(Win, Mod) of - {true, Win3} -> Win3; + %% {true, Win3} -> Win3; false -> gui_load_module(Win, Mod, Pid) end, dbg_wx_trace_win:mark_line(Win2, Line, How). diff --git a/lib/debugger/vsn.mk b/lib/debugger/vsn.mk index b6fd4e8e44..cf8ffd3272 100644 --- a/lib/debugger/vsn.mk +++ b/lib/debugger/vsn.mk @@ -1 +1 @@ -DEBUGGER_VSN = 4.1 +DEBUGGER_VSN = 4.1.2 diff --git a/lib/dialyzer/doc/src/notes.xml b/lib/dialyzer/doc/src/notes.xml index 93d3b09f07..4202730eed 100644 --- a/lib/dialyzer/doc/src/notes.xml +++ b/lib/dialyzer/doc/src/notes.xml @@ -32,6 +32,123 @@ <p>This document describes the changes made to the Dialyzer application.</p> +<section><title>Dialyzer 2.9</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> Dialyzer no longer asserts that files and directories + to be removed from a PLT exist. </p> + <p> + Own Id: OTP-13103 Aux Id: ERL-40 </p> + </item> + <item> + <p> Fix a bug concerning parameterized opaque types. </p> + <p> + Own Id: OTP-13237</p> + </item> + <item> + <p> + Fix pretty printing of Core Maps</p> + <p> + Literal maps could cause Dialyzer to crash when pretty + printing the results.</p> + <p> + Own Id: OTP-13238</p> + </item> + <item> + <p> + If a behavior module contains an non-exported function + with the same name as one of the behavior's callbacks, + the callback info was inadvertently deleted from the PLT + as the <c>dialyzer_plt:delete_list/2</c> function was + cleaning up the callback table.</p> + <p> + Own Id: OTP-13287</p> + </item> + <item> + <p> Correct the contract for <c>erlang:byte_size/1</c> + </p> <p> Correct the handling of comparison operators for + map and bit string operands. </p> + <p> + Own Id: OTP-13312</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Dialyzer recognizes calls to <c>M:F/A</c> where <c>M</c>, + <c>F</c>, and <c>A</c> are all literals.</p> + <p> + Own Id: OTP-13217</p> + </item> + </list> + </section> + +</section> + +<section><title>Dialyzer 2.8.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Reintroduce the <c>erlang:make_fun/3</c> BIF in + erl_bif_types.</p> + <p> + Own Id: OTP-13068</p> + </item> + </list> + </section> + +</section> + +<section><title>Dialyzer 2.8.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>Improve the translation of forms to types. </p> + <p> + Own Id: OTP-12865</p> + </item> + <item> + <p> Fix a bug concerning parameterized opaque types. </p> + <p> + Own Id: OTP-12866</p> + </item> + <item> + <p> Fix a bug concerning parameterized opaque types. </p> + <p> + Own Id: OTP-12940</p> + </item> + <item> + <p> Fix bugs concerning <c>erlang:abs/1</c>. </p> + <p> + Own Id: OTP-12948</p> + </item> + <item> + <p> Fix a bug concerning <c>lists:keydelete/3</c> with + union and opaque types. </p> + <p> + Own Id: OTP-12949</p> + </item> + <item> + <p> + Use new function <c>hipe:erts_checksum</c> to get correct + runtime checksum for cached beam files.</p> + <p> + Own Id: OTP-12964 Aux Id: OTP-12963, OTP-12962 </p> + </item> + </list> + </section> + +</section> + <section><title>Dialyzer 2.8</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -405,22 +522,28 @@ <p> EEP43: New data type - Maps</p> <p> - With Maps you may for instance: <taglist> <item><c>M0 = - #{ a => 1, b => 2}, % create - associations</c></item> <item><c>M1 = M0#{ a := 10 }, % - update values</c></item> <item><c>M2 = M1#{ "hi" => - "hello"}, % add new associations</c></item> <item><c>#{ - "hi" := V1, a := V2, b := V3} = M2. % match keys with - values</c></item> </taglist></p> + With Maps you may for instance:</p> + <taglist> + <tag/> <item><c>M0 = #{ a => 1, b => 2}, % create + associations</c></item> + <tag/><item><c>M1 = M0#{ a := 10 }, % update values</c></item> + <tag/><item><c>M2 = M1#{ "hi" => + "hello"}, % add new associations</c></item> + <tag/><item><c>#{ "hi" := V1, a := V2, b := V3} = M2. + % match keys with values</c></item> + </taglist> <p> For information on how to use Maps please see Map Expressions in the <seealso marker="doc/reference_manual:expressions#map_expressions"> Reference Manual</seealso>.</p> <p> The current implementation is without the following - features: <taglist> <item>No variable keys</item> - <item>No single value access</item> <item>No map - comprehensions</item> </taglist></p> + features:</p> + <taglist> + <tag/><item>No variable keys</item> + <tag/><item>No single value access</item> + <tag/><item>No map comprehensions</item> + </taglist> <p> Note that Maps is <em>experimental</em> during OTP 17.0.</p> <p> @@ -734,19 +857,17 @@ Own Id: OTP-9731</p> </item> <item> - <p> <list> <item><p>No warnings for underspecs with remote types</p></item> <item><p> Fix crash in Typer</p></item> <item><p>Fix Dialyzer's warning for its own code</p></item> <item><p>Fix Dialyzer's warnings in HiPE</p></item> <item><p>Add file/line info in a particular Dialyzer crash</p></item> <item><p>Update - inets test results</p></item> </list></p> + inets test results</p></item> </list> <p> Own Id: OTP-9758</p> </item> <item> - <p> <list> <item><p>Correct callback spec in application module</p></item> <item><p>Refine warning about callback specs with extra ranges</p></item> <item><p>Cleanup @@ -757,7 +878,7 @@ analysis</p></item> <item><p>Fix crash in Dialyzer</p></item> <item><p>Variable substitution was not generalizing any unknown variables.</p></item> - </list></p> + </list> <p> Own Id: OTP-9776</p> </item> diff --git a/lib/dialyzer/src/dialyzer.app.src b/lib/dialyzer/src/dialyzer.app.src index 6718178fae..8ac6dc1367 100644 --- a/lib/dialyzer/src/dialyzer.app.src +++ b/lib/dialyzer/src/dialyzer.app.src @@ -47,5 +47,5 @@ {applications, [compiler, gs, hipe, kernel, stdlib, wx]}, {env, []}, {runtime_dependencies, ["wx-1.2","syntax_tools-1.6.14","stdlib-2.5", - "kernel-3.0","hipe-3.10.3","erts-7.0", + "kernel-3.0","hipe-3.13","erts-7.0", "compiler-5.0"]}]}. diff --git a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl index 76b43b6ff0..8537878dfc 100644 --- a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl +++ b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl @@ -93,31 +93,19 @@ loop(#server_state{parent = Parent} = State, send_log(Parent, LogMsg), loop(State, Analysis, ExtCalls); {AnalPid, warnings, Warnings} -> - case Warnings of - [] -> ok; - SendWarnings -> - send_warnings(Parent, SendWarnings) - end, + send_warnings(Parent, Warnings), loop(State, Analysis, ExtCalls); {AnalPid, cserver, CServer, Plt} -> send_codeserver_plt(Parent, CServer, Plt), loop(State, Analysis, ExtCalls); {AnalPid, done, Plt, DocPlt} -> - case ExtCalls =:= none of - true -> - send_analysis_done(Parent, Plt, DocPlt); - false -> - send_ext_calls(Parent, ExtCalls), - send_analysis_done(Parent, Plt, DocPlt) - end; + send_ext_calls(Parent, ExtCalls), + send_analysis_done(Parent, Plt, DocPlt); {AnalPid, ext_calls, NewExtCalls} -> loop(State, Analysis, NewExtCalls); {AnalPid, ext_types, ExtTypes} -> send_ext_types(Parent, ExtTypes), loop(State, Analysis, ExtCalls); - {AnalPid, unknown_behaviours, UnknownBehaviour} -> - send_unknown_behaviours(Parent, UnknownBehaviour), - loop(State, Analysis, ExtCalls); {AnalPid, mod_deps, ModDeps} -> send_mod_deps(Parent, ModDeps), loop(State, Analysis, ExtCalls); @@ -167,9 +155,12 @@ analysis_start(Parent, Analysis, LegalWarnings) -> TmpCServer2 = dialyzer_codeserver:insert_temp_exported_types(MergedExpTypes, TmpCServer1), - TmpCServer3 = dialyzer_utils:process_record_remote_types(TmpCServer2), ?timing(State#analysis_state.timing_server, "remote", - dialyzer_contracts:process_contract_remote_types(TmpCServer3)) + begin + TmpCServer3 = + dialyzer_utils:process_record_remote_types(TmpCServer2), + dialyzer_contracts:process_contract_remote_types(TmpCServer3) + end) catch throw:{error, _ErrorMsg} = Error -> exit(Error) end, @@ -569,6 +560,8 @@ send_analysis_done(Parent, Plt, DocPlt) -> Parent ! {self(), done, Plt, DocPlt}, ok. +send_ext_calls(_Parent, none) -> + ok; send_ext_calls(Parent, ExtCalls) -> Parent ! {self(), ext_calls, ExtCalls}, ok. @@ -577,10 +570,6 @@ send_ext_types(Parent, ExtTypes) -> Parent ! {self(), ext_types, ExtTypes}, ok. -send_unknown_behaviours(Parent, UnknownBehaviours) -> - Parent ! {self(), unknown_behaviours, UnknownBehaviours}, - ok. - send_codeserver_plt(Parent, CServer, Plt ) -> Parent ! {self(), cserver, CServer, Plt}, ok. @@ -621,6 +610,28 @@ find_call_file_and_line(Tree, MFA) -> MFA -> Ann = cerl:get_ann(SubTree), [{get_file(Ann), get_line(Ann)}|Acc]; + {erlang, make_fun, 3} -> + [CA1, CA2, CA3] = cerl:call_args(SubTree), + case + cerl:is_c_atom(CA1) andalso + cerl:is_c_atom(CA2) andalso + cerl:is_c_int(CA3) + of + true -> + case + {cerl:concrete(CA1), + cerl:concrete(CA2), + cerl:concrete(CA3)} + of + MFA -> + Ann = cerl:get_ann(SubTree), + [{get_file(Ann), get_line(Ann)}|Acc]; + _ -> + Acc + end; + false -> + Acc + end; _ -> Acc end; false -> Acc diff --git a/lib/dialyzer/src/dialyzer_callgraph.erl b/lib/dialyzer/src/dialyzer_callgraph.erl index a1cd2015ca..9e53e171c0 100644 --- a/lib/dialyzer/src/dialyzer_callgraph.erl +++ b/lib/dialyzer/src/dialyzer_callgraph.erl @@ -478,14 +478,37 @@ scan_one_core_fun(TopTree, FunName) -> call -> CalleeM = cerl:call_module(Tree), CalleeF = cerl:call_name(Tree), - A = length(cerl:call_args(Tree)), + CalleeArgs = cerl:call_args(Tree), + A = length(CalleeArgs), case (cerl:is_c_atom(CalleeM) andalso cerl:is_c_atom(CalleeF)) of true -> M = cerl:atom_val(CalleeM), F = cerl:atom_val(CalleeF), case erl_bif_types:is_known(M, F, A) of - true -> Acc; + true -> + case {M, F, A} of + {erlang, make_fun, 3} -> + [CA1, CA2, CA3] = CalleeArgs, + case + cerl:is_c_atom(CA1) andalso + cerl:is_c_atom(CA2) andalso + cerl:is_c_int(CA3) + of + true -> + MM = cerl:atom_val(CA1), + FF = cerl:atom_val(CA2), + AA = cerl:int_val(CA3), + case erl_bif_types:is_known(MM, FF, AA) of + true -> Acc; + false -> [{FunName, {MM, FF, AA}}|Acc] + end; + false -> + Acc + end; + _ -> + Acc + end; false -> [{FunName, {M, F, A}}|Acc] end; false -> diff --git a/lib/dialyzer/src/dialyzer_cl.erl b/lib/dialyzer/src/dialyzer_cl.erl index 55302d5869..9354b8007e 100644 --- a/lib/dialyzer/src/dialyzer_cl.erl +++ b/lib/dialyzer/src/dialyzer_cl.erl @@ -49,8 +49,7 @@ plt_info = none :: 'none' | dialyzer_plt:plt_info(), report_mode = normal :: rep_mode(), return_status= ?RET_NOTHING_SUSPICIOUS :: dial_ret(), - stored_warnings = [] :: [raw_warning()], - unknown_behaviours = [] :: [dialyzer_behaviours:behaviour()] + stored_warnings = [] :: [raw_warning()] }). %%-------------------------------------------------------------------- @@ -547,13 +546,13 @@ hc(Mod, Cache) -> hc_cache(Mod) -> CacheBase = cache_base_dir(), - %% Use HiPE architecture and version in directory name, to avoid - %% clashes between incompatible binaries. + %% Use HiPE architecture, version and erts checksum in directory name, + %% to avoid clashes between incompatible binaries. HipeArchVersion = lists:concat( [erlang:system_info(hipe_architecture), "-", hipe:version(), "-", - hipe_bifs:system_crc()]), + hipe:erts_checksum()]), CacheDir = filename:join(CacheBase, HipeArchVersion), OrigBeamFile = code:which(Mod), {ok, {Mod, <<Checksum:128>>}} = beam_lib:md5(OrigBeamFile), @@ -638,9 +637,6 @@ cl_loop(State, LogCache) -> {BackendPid, warnings, Warnings} -> NewState = store_warnings(State, Warnings), cl_loop(NewState, LogCache); - {BackendPid, unknown_behaviours, Behaviours} -> - NewState = store_unknown_behaviours(State, Behaviours), - cl_loop(NewState, LogCache); {BackendPid, done, NewPlt, _NewDocPlt} -> return_value(State, NewPlt); {BackendPid, ext_calls, ExtCalls} -> @@ -683,11 +679,6 @@ format_log_cache(LogCache) -> store_warnings(#cl_state{stored_warnings = StoredWarnings} = St, Warnings) -> St#cl_state{stored_warnings = StoredWarnings ++ Warnings}. --spec store_unknown_behaviours(#cl_state{}, [dialyzer_behaviours:behaviour()]) -> #cl_state{}. - -store_unknown_behaviours(#cl_state{unknown_behaviours = Behs} = St, Beh) -> - St#cl_state{unknown_behaviours = Beh ++ Behs}. - -spec cl_error(string()) -> no_return(). cl_error(Msg) -> @@ -724,7 +715,6 @@ return_value(State = #cl_state{erlang_mode = ErlangMode, print_warnings(State), print_ext_calls(State), print_ext_types(State), - print_unknown_behaviours(State), maybe_close_output_file(State), {RetValue, []}; true -> @@ -737,8 +727,7 @@ unknown_warnings(State = #cl_state{legal_warnings = LegalWarnings}) -> Unknown = case ordsets:is_element(?WARN_UNKNOWN, LegalWarnings) of true -> unknown_functions(State) ++ - unknown_types(State) ++ - unknown_behaviours(State); + unknown_types(State); false -> [] end, WarningInfo = {_Filename = "", _Line = 0, _MorMFA = ''}, @@ -814,48 +803,6 @@ do_print_ext_types(Output, [{M,F,A}|T], Before) -> do_print_ext_types(_, [], _) -> ok. -unknown_behaviours(#cl_state{unknown_behaviours = DupBehaviours, - legal_warnings = LegalWarnings}) -> - case ordsets:is_element(?WARN_BEHAVIOUR, LegalWarnings) of - false -> []; - true -> - Behaviours = lists:usort(DupBehaviours), - [{unknown_behaviour, B} || B <- Behaviours] - end. - -%%print_unknown_behaviours(#cl_state{report_mode = quiet}) -> -%% ok; -print_unknown_behaviours(#cl_state{output = Output, - external_calls = Calls, - external_types = Types, - stored_warnings = Warnings, - unknown_behaviours = DupBehaviours, - legal_warnings = LegalWarnings, - output_format = Format}) -> - case ordsets:is_element(?WARN_BEHAVIOUR, LegalWarnings) - andalso DupBehaviours =/= [] of - false -> ok; - true -> - Behaviours = lists:usort(DupBehaviours), - case Warnings =:= [] andalso Calls =:= [] andalso Types =:= [] of - true -> io:nl(Output); %% Need to do a newline first - false -> ok - end, - {Prompt, Prefix} = - case Format of - formatted -> {"Unknown behaviours:\n"," "}; - raw -> {"%% Unknown behaviours:\n","%% "} - end, - io:put_chars(Output, Prompt), - do_print_unknown_behaviours(Output, Behaviours, Prefix) - end. - -do_print_unknown_behaviours(Output, [B|T], Before) -> - io:format(Output, "~s~p\n", [Before,B]), - do_print_unknown_behaviours(Output, T, Before); -do_print_unknown_behaviours(_, [], _) -> - ok. - print_warnings(#cl_state{stored_warnings = []}) -> ok; print_warnings(#cl_state{output = Output, diff --git a/lib/dialyzer/src/dialyzer_contracts.erl b/lib/dialyzer/src/dialyzer_contracts.erl index 0c29d524b5..7251de8b10 100644 --- a/lib/dialyzer/src/dialyzer_contracts.erl +++ b/lib/dialyzer/src/dialyzer_contracts.erl @@ -46,7 +46,7 @@ -type file_contract() :: {file_line(), #contract{}, Extra :: [_]}. --type plt_contracts() :: [{mfa(), #contract{}}]. % actually, an orddict() +-type plt_contracts() :: orddict:orddict(mfa(), #contract{}). %%----------------------------------------------------------------------- %% Internal record for contracts whose components have not been processed @@ -395,22 +395,21 @@ insert_constraints([], Dict) -> Dict. store_tmp_contract(MFA, FileLine, {TypeSpec, Xtra}, SpecDict, RecordsDict) -> %% io:format("contract from form: ~p\n", [TypeSpec]), - {Module, _, _} = MFA, - TmpContract = contract_from_form(TypeSpec, Module, RecordsDict, FileLine), + TmpContract = contract_from_form(TypeSpec, MFA, RecordsDict, FileLine), %% io:format("contract: ~p\n", [TmpContract]), dict:store(MFA, {FileLine, TmpContract, Xtra}, SpecDict). -contract_from_form(Forms, Module, RecDict, FileLine) -> - {CFuns, Forms1} = contract_from_form(Forms, Module, RecDict, FileLine, [], []), +contract_from_form(Forms, MFA, RecDict, FileLine) -> + {CFuns, Forms1} = contract_from_form(Forms, MFA, RecDict, FileLine, [], []), #tmp_contract{contract_funs = CFuns, forms = Forms1}. -contract_from_form([{type, _, 'fun', [_, _]} = Form | Left], Module, RecDict, +contract_from_form([{type, _, 'fun', [_, _]} = Form | Left], MFA, RecDict, FileLine, TypeAcc, FormAcc) -> TypeFun = fun(ExpTypes, AllRecords) -> NewType = try - from_form_with_check(Form, ExpTypes, Module, AllRecords) + from_form_with_check(Form, ExpTypes, MFA, AllRecords) catch throw:{error, Msg} -> {File, Line} = FileLine, @@ -423,55 +422,55 @@ contract_from_form([{type, _, 'fun', [_, _]} = Form | Left], Module, RecDict, end, NewTypeAcc = [TypeFun | TypeAcc], NewFormAcc = [{Form, []} | FormAcc], - contract_from_form(Left, Module, RecDict, FileLine, NewTypeAcc, NewFormAcc); + contract_from_form(Left, MFA, RecDict, FileLine, NewTypeAcc, NewFormAcc); contract_from_form([{type, _L1, bounded_fun, [{type, _L2, 'fun', [_, _]} = Form, Constr]}| Left], - Module, RecDict, FileLine, TypeAcc, FormAcc) -> + MFA, RecDict, FileLine, TypeAcc, FormAcc) -> TypeFun = fun(ExpTypes, AllRecords) -> {Constr1, VarDict} = - process_constraints(Constr, Module, RecDict, ExpTypes, AllRecords), - NewType = from_form_with_check(Form, ExpTypes, Module, AllRecords, + process_constraints(Constr, MFA, RecDict, ExpTypes, AllRecords), + NewType = from_form_with_check(Form, ExpTypes, MFA, AllRecords, VarDict), NewTypeNoVars = erl_types:subst_all_vars_to_any(NewType), {NewTypeNoVars, Constr1} end, NewTypeAcc = [TypeFun | TypeAcc], NewFormAcc = [{Form, Constr} | FormAcc], - contract_from_form(Left, Module, RecDict, FileLine, NewTypeAcc, NewFormAcc); -contract_from_form([], _Module, _RecDict, _FileLine, TypeAcc, FormAcc) -> + contract_from_form(Left, MFA, RecDict, FileLine, NewTypeAcc, NewFormAcc); +contract_from_form([], _MFA, _RecDict, _FileLine, TypeAcc, FormAcc) -> {lists:reverse(TypeAcc), lists:reverse(FormAcc)}. -process_constraints(Constrs, Module, RecDict, ExpTypes, AllRecords) -> - Init0 = initialize_constraints(Constrs, Module, RecDict, ExpTypes, AllRecords), +process_constraints(Constrs, MFA, RecDict, ExpTypes, AllRecords) -> + Init0 = initialize_constraints(Constrs, MFA, RecDict, ExpTypes, AllRecords), Init = remove_cycles(Init0), - constraints_fixpoint(Init, Module, RecDict, ExpTypes, AllRecords). + constraints_fixpoint(Init, MFA, RecDict, ExpTypes, AllRecords). -initialize_constraints(Constrs, Module, RecDict, ExpTypes, AllRecords) -> - initialize_constraints(Constrs, Module, RecDict, ExpTypes, AllRecords, []). +initialize_constraints(Constrs, MFA, RecDict, ExpTypes, AllRecords) -> + initialize_constraints(Constrs, MFA, RecDict, ExpTypes, AllRecords, []). -initialize_constraints([], _Module, _RecDict, _ExpTypes, _AllRecords, Acc) -> +initialize_constraints([], _MFA, _RecDict, _ExpTypes, _AllRecords, Acc) -> Acc; -initialize_constraints([Constr|Rest], Module, RecDict, ExpTypes, AllRecords, Acc) -> +initialize_constraints([Constr|Rest], MFA, RecDict, ExpTypes, AllRecords, Acc) -> case Constr of {type, _, constraint, [{atom, _, is_subtype}, [Type1, Type2]]} -> - T1 = final_form(Type1, ExpTypes, Module, AllRecords, dict:new()), + T1 = final_form(Type1, ExpTypes, MFA, AllRecords, dict:new()), Entry = {T1, Type2}, - initialize_constraints(Rest, Module, RecDict, ExpTypes, AllRecords, [Entry|Acc]); + initialize_constraints(Rest, MFA, RecDict, ExpTypes, AllRecords, [Entry|Acc]); {type, _, constraint, [{atom,_,Name}, List]} -> N = length(List), throw({error, io_lib:format("Unsupported type guard ~w/~w\n", [Name, N])}) end. -constraints_fixpoint(Constrs, Module, RecDict, ExpTypes, AllRecords) -> +constraints_fixpoint(Constrs, MFA, RecDict, ExpTypes, AllRecords) -> VarDict = - constraints_to_dict(Constrs, Module, RecDict, ExpTypes, AllRecords, dict:new()), - constraints_fixpoint(VarDict, Module, Constrs, RecDict, ExpTypes, AllRecords). + constraints_to_dict(Constrs, MFA, RecDict, ExpTypes, AllRecords, dict:new()), + constraints_fixpoint(VarDict, MFA, Constrs, RecDict, ExpTypes, AllRecords). -constraints_fixpoint(OldVarDict, Module, Constrs, RecDict, ExpTypes, AllRecords) -> +constraints_fixpoint(OldVarDict, MFA, Constrs, RecDict, ExpTypes, AllRecords) -> NewVarDict = - constraints_to_dict(Constrs, Module, RecDict, ExpTypes, AllRecords, OldVarDict), + constraints_to_dict(Constrs, MFA, RecDict, ExpTypes, AllRecords, OldVarDict), case NewVarDict of OldVarDict -> DictFold = @@ -481,33 +480,33 @@ constraints_fixpoint(OldVarDict, Module, Constrs, RecDict, ExpTypes, AllRecords) FinalConstrs = dict:fold(DictFold, [], NewVarDict), {FinalConstrs, NewVarDict}; _Other -> - constraints_fixpoint(NewVarDict, Module, Constrs, RecDict, ExpTypes, AllRecords) + constraints_fixpoint(NewVarDict, MFA, Constrs, RecDict, ExpTypes, AllRecords) end. -final_form(Form, ExpTypes, Module, AllRecords, VarDict) -> - from_form_with_check(Form, ExpTypes, Module, AllRecords, VarDict). +final_form(Form, ExpTypes, MFA, AllRecords, VarDict) -> + from_form_with_check(Form, ExpTypes, MFA, AllRecords, VarDict). -from_form_with_check(Form, ExpTypes, Module, AllRecords) -> - erl_types:t_check_record_fields(Form, ExpTypes, Module, AllRecords), - erl_types:t_from_form(Form, ExpTypes, Module, AllRecords). +from_form_with_check(Form, ExpTypes, MFA, AllRecords) -> + from_form_with_check(Form, ExpTypes, MFA, AllRecords, dict:new()). -from_form_with_check(Form, ExpTypes, Module, AllRecords, VarDict) -> - erl_types:t_check_record_fields(Form, ExpTypes, Module, AllRecords, +from_form_with_check(Form, ExpTypes, MFA, AllRecords, VarDict) -> + Site = {spec, MFA}, + erl_types:t_check_record_fields(Form, ExpTypes, Site, AllRecords, VarDict), - erl_types:t_from_form(Form, ExpTypes, Module, AllRecords, VarDict). + erl_types:t_from_form(Form, ExpTypes, Site, AllRecords, VarDict). -constraints_to_dict(Constrs, Module, RecDict, ExpTypes, AllRecords, VarDict) -> +constraints_to_dict(Constrs, MFA, RecDict, ExpTypes, AllRecords, VarDict) -> Subtypes = - constraints_to_subs(Constrs, Module, RecDict, ExpTypes, AllRecords, VarDict, []), + constraints_to_subs(Constrs, MFA, RecDict, ExpTypes, AllRecords, VarDict, []), insert_constraints(Subtypes, dict:new()). -constraints_to_subs([], _Module, _RecDict, _ExpTypes, _AllRecords, _VarDict, Acc) -> +constraints_to_subs([], _MFA, _RecDict, _ExpTypes, _AllRecords, _VarDict, Acc) -> Acc; -constraints_to_subs([C|Rest], Module, RecDict, ExpTypes, AllRecords, VarDict, Acc) -> +constraints_to_subs([C|Rest], MFA, RecDict, ExpTypes, AllRecords, VarDict, Acc) -> {T1, Form2} = C, - T2 = final_form(Form2, ExpTypes, Module, AllRecords, VarDict), + T2 = final_form(Form2, ExpTypes, MFA, AllRecords, VarDict), NewAcc = [{subtype, T1, T2}|Acc], - constraints_to_subs(Rest, Module, RecDict, ExpTypes, AllRecords, VarDict, NewAcc). + constraints_to_subs(Rest, MFA, RecDict, ExpTypes, AllRecords, VarDict, NewAcc). %% Replaces variables with '_' when necessary to break up cycles among %% the constraints. @@ -630,7 +629,7 @@ get_invalid_contract_warnings_funs([{MFA, {FileLine, Contract, _Xtra}}|Left], {error, {extra_range, ExtraRanges, STRange}} -> Warn = case t_from_forms_without_remote(Contract#contract.forms, - RecDict) of + MFA, RecDict) of {ok, NoRemoteType} -> CRet = erl_types:t_fun_range(NoRemoteType), erl_types:t_is_subtype(ExtraRanges, CRet); @@ -705,7 +704,7 @@ picky_contract_check(CSig0, Sig0, MFA, WarningInfo, Contract, RecDict, Acc) -> end end. -extra_contract_warning({M, F, A}, WarningInfo, Contract, CSig, Sig, RecDict) -> +extra_contract_warning(MFA, WarningInfo, Contract, CSig, Sig, RecDict) -> %% We do not want to depend upon erl_types:t_to_string() possibly %% hiding the contents of opaque types. SigUnopaque = erl_types:t_unopaque(Sig), @@ -717,11 +716,12 @@ extra_contract_warning({M, F, A}, WarningInfo, Contract, CSig, Sig, RecDict) -> %% The only difference is in record fields containing 'undefined' or not. IsUndefRecordFieldsRelated = SigString0 =:= ContractString0, {IsRemoteTypesRelated, SubtypeRelation} = - is_remote_types_related(Contract, CSig, Sig, RecDict), + is_remote_types_related(Contract, CSig, Sig, MFA, RecDict), case IsUndefRecordFieldsRelated orelse IsRemoteTypesRelated of true -> no_warning; false -> + {M, F, A} = MFA, SigString = lists:flatten(dialyzer_utils:format_sig(Sig, RecDict)), ContractString = contract_to_string(Contract), {Tag, Msg} = @@ -739,14 +739,15 @@ extra_contract_warning({M, F, A}, WarningInfo, Contract, CSig, Sig, RecDict) -> {warning, {Tag, WarningInfo, Msg}} end. -is_remote_types_related(Contract, CSig, Sig, RecDict) -> +is_remote_types_related(Contract, CSig, Sig, MFA, RecDict) -> case erl_types:t_is_subtype(CSig, Sig) of true -> {false, contract_is_subtype}; false -> case erl_types:t_is_subtype(Sig, CSig) of true -> - case t_from_forms_without_remote(Contract#contract.forms, RecDict) of + case t_from_forms_without_remote(Contract#contract.forms, MFA, + RecDict) of {ok, NoRemoteTypeSig} -> case blame_remote(CSig, NoRemoteTypeSig, Sig) of true -> @@ -762,13 +763,14 @@ is_remote_types_related(Contract, CSig, Sig, RecDict) -> end end. -t_from_forms_without_remote([{FType, []}], RecDict) -> - Type1 = erl_types:t_from_form_without_remote(FType, RecDict), +t_from_forms_without_remote([{FType, []}], MFA, RecDict) -> + Site = {spec, MFA}, + Type1 = erl_types:t_from_form_without_remote(FType, Site, RecDict), {ok, erl_types:subst_all_vars_to_any(Type1)}; -t_from_forms_without_remote([{_FType, _Constrs}], _RecDict) -> +t_from_forms_without_remote([{_FType, _Constrs}], _MFA, _RecDict) -> %% 'When' constraints unsupported; -t_from_forms_without_remote(_Forms, _RecDict) -> +t_from_forms_without_remote(_Forms, _MFA, _RecDict) -> %% Lots of forms unsupported. diff --git a/lib/dialyzer/src/dialyzer_options.erl b/lib/dialyzer/src/dialyzer_options.erl index ce84c17f43..dd81dd01ed 100644 --- a/lib/dialyzer/src/dialyzer_options.erl +++ b/lib/dialyzer/src/dialyzer_options.erl @@ -72,9 +72,15 @@ preprocess_opts([Opt|Opts]) -> [Opt|preprocess_opts(Opts)]. postprocess_opts(Opts = #options{}) -> + check_file_existence(Opts), Opts1 = check_output_plt(Opts), adapt_get_warnings(Opts1). +check_file_existence(#options{analysis_type = plt_remove}) -> ok; +check_file_existence(#options{files = Files, files_rec = FilesRec}) -> + assert_filenames_exist(Files), + assert_filenames_exist(FilesRec). + check_output_plt(Opts = #options{analysis_type = Mode, from = From, output_plt = OutPLT}) -> case is_plt_mode(Mode) of @@ -126,14 +132,14 @@ build_options([{OptionName, Value} = Term|Rest], Options) -> apps -> OldValues = Options#options.files_rec, AppDirs = get_app_dirs(Value), - assert_filenames(Term, AppDirs), + assert_filenames_form(Term, AppDirs), build_options(Rest, Options#options{files_rec = AppDirs ++ OldValues}); files -> - assert_filenames(Term, Value), + assert_filenames_form(Term, Value), build_options(Rest, Options#options{files = Value}); files_rec -> OldValues = Options#options.files_rec, - assert_filenames(Term, Value), + assert_filenames_form(Term, Value), build_options(Rest, Options#options{files_rec = Value ++ OldValues}); analysis_type -> NewOptions = @@ -210,16 +216,26 @@ get_app_dirs(Apps) when is_list(Apps) -> get_app_dirs(Apps) -> bad_option("Use a list of otp applications", Apps). -assert_filenames(Term, [FileName|Left]) when length(FileName) >= 0 -> +assert_filenames(Term, Files) -> + assert_filenames_form(Term, Files), + assert_filenames_exist(Files). + +assert_filenames_form(Term, [FileName|Left]) when length(FileName) >= 0 -> + assert_filenames_form(Term, Left); +assert_filenames_form(_Term, []) -> + ok; +assert_filenames_form(Term, [_|_]) -> + bad_option("Malformed or non-existing filename", Term). + +assert_filenames_exist([FileName|Left]) -> case filelib:is_file(FileName) orelse filelib:is_dir(FileName) of true -> ok; - false -> bad_option("No such file, directory or application", FileName) + false -> + bad_option("No such file, directory or application", FileName) end, - assert_filenames(Term, Left); -assert_filenames(_Term, []) -> - ok; -assert_filenames(Term, [_|_]) -> - bad_option("Malformed or non-existing filename", Term). + assert_filenames_exist(Left); +assert_filenames_exist([]) -> + ok. assert_filename(FileName) when length(FileName) >= 0 -> ok; diff --git a/lib/dialyzer/src/dialyzer_plt.erl b/lib/dialyzer/src/dialyzer_plt.erl index 634871b2eb..769f26a3df 100644 --- a/lib/dialyzer/src/dialyzer_plt.erl +++ b/lib/dialyzer/src/dialyzer_plt.erl @@ -137,7 +137,7 @@ delete_list(#plt{info = Info, types = Types, #plt{info = table_delete_list(Info, List), types = Types, contracts = table_delete_list(Contracts, List), - callbacks = table_delete_list(Callbacks, List), + callbacks = Callbacks, exported_types = ExpTypes}. -spec insert_contract_list(plt(), dialyzer_contracts:plt_contracts()) -> plt(). diff --git a/lib/dialyzer/src/dialyzer_utils.erl b/lib/dialyzer/src/dialyzer_utils.erl index b585646fde..7fe982a992 100644 --- a/lib/dialyzer/src/dialyzer_utils.erl +++ b/lib/dialyzer/src/dialyzer_utils.erl @@ -304,15 +304,16 @@ process_record_remote_types(CServer) -> RecordFun = fun(Key, Value) -> case Key of - {record, _Name} -> + {record, Name} -> FieldFun = - fun(_Arity, Fields) -> - [{Name, Field, + fun(Arity, Fields) -> + Site = {record, {Module, Name, Arity}}, + [{FieldName, Field, erl_types:t_from_form(Field, TempExpTypes, - Module, + Site, TempRecords1)} - || {Name, Field, _} <- Fields] + || {FieldName, Field, _} <- Fields] end, {FileLine, Fields} = Value, {FileLine, orddict:map(FieldFun, Fields)}; @@ -340,9 +341,10 @@ process_opaque_types(TempRecords, TempExpTypes) -> RecordFun = fun(Key, Value) -> case Key of - {opaque, _Name, _NArgs} -> + {opaque, Name, NArgs} -> {{_Module, _FileLine, Form, _ArgNames}=F, _Type} = Value, - Type = erl_types:t_from_form(Form, TempExpTypes, Module, + Site = {type, {Module, Name, NArgs}}, + Type = erl_types:t_from_form(Form, TempExpTypes, Site, TempRecords), {F, Type}; _Other -> Value @@ -355,25 +357,28 @@ process_opaque_types(TempRecords, TempExpTypes) -> check_record_fields(Records, TempExpTypes) -> CheckFun = fun({Module, Element}) -> - CheckForm = fun(F) -> - erl_types:t_check_record_fields(F, TempExpTypes, - Module, Records) + CheckForm = fun(Form, Site) -> + erl_types:t_check_record_fields(Form, TempExpTypes, + Site, Records) end, ElemFun = fun({Key, Value}) -> case Key of - {record, _Name} -> + {record, Name} -> FieldFun = - fun({_Arity, Fields}) -> - _ = [ok = CheckForm(Field) || {_, Field, _} <- Fields], + fun({Arity, Fields}) -> + Site = {record, {Module, Name, Arity}}, + _ = [ok = CheckForm(Field, Site) || + {_, Field, _} <- Fields], ok end, {FileLine, Fields} = Value, Fun = fun() -> lists:foreach(FieldFun, Fields) end, msg_with_position(Fun, FileLine); - {_OpaqueOrType, _Name, _} -> + {_OpaqueOrType, Name, NArgs} -> + Site = {type, {Module, Name, NArgs}}, {{_Module, FileLine, Form, _ArgNames}, _Type} = Value, - Fun = fun() -> ok = CheckForm(Form) end, + Fun = fun() -> ok = CheckForm(Form, Site) end, msg_with_position(Fun, FileLine) end end, diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/big_external_type.erl b/lib/dialyzer/test/opaque_SUITE_data/src/big_external_type.erl new file mode 100644 index 0000000000..d286a378ed --- /dev/null +++ b/lib/dialyzer/test/opaque_SUITE_data/src/big_external_type.erl @@ -0,0 +1,526 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2001-2015. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +%%% A copy of small_SUITE_data/src/big_external_type.erl, where +%%% abstract_expr() is opaque. The transformation of forms to types is +%%% now much faster than it used to be, for this module. + +-module(big_external_type). + +-export([parse_form/1,parse_exprs/1,parse_term/1]). +-export([normalise/1,tokens/1,tokens/2]). +-export([inop_prec/1,preop_prec/1,func_prec/0,max_prec/0]). + +-export_type([abstract_clause/0, abstract_expr/0, abstract_form/0, + error_info/0]). + +%% Start of Abstract Format + +-type line() :: erl_anno:line(). + +-export_type([af_record_index/0, af_record_field/1, af_record_name/0, + af_field_name/0, af_function_decl/0]). + +-export_type([af_module/0, af_export/0, af_import/0, af_fa_list/0, + af_compile/0, af_file/0, af_record_decl/0, + af_field_decl/0, af_wild_attribute/0, + af_record_update/1, af_catch/0, af_local_call/0, + af_remote_call/0, af_args/0, af_local_function/0, + af_remote_function/0, af_list_comprehension/0, + af_binary_comprehension/0, af_template/0, + af_qualifier_seq/0, af_qualifier/0, af_generator/0, + af_filter/0, af_block/0, af_if/0, af_case/0, af_try/0, + af_clause_seq/0, af_catch_clause_seq/0, af_receive/0, + af_local_fun/0, af_remote_fun/0, af_fun/0, af_query/0, + af_query_access/0, af_clause/0, + af_catch_clause/0, af_catch_pattern/0, af_catch_class/0, + af_body/0, af_guard_seq/0, af_guard/0, af_guard_test/0, + af_record_access/1, af_guard_call/0, + af_remote_guard_call/0, af_pattern/0, af_literal/0, + af_atom/0, af_lit_atom/1, af_integer/0, af_float/0, + af_string/0, af_match/1, af_variable/0, + af_anon_variable/0, af_tuple/1, af_nil/0, af_cons/1, + af_bin/1, af_binelement/1, af_binelement_size/0, + af_binary_op/1, af_binop/0, af_unary_op/1, af_unop/0]). + +-type abstract_form() :: ?MODULE:af_module() + | ?MODULE:af_export() + | ?MODULE:af_import() + | ?MODULE:af_compile() + | ?MODULE:af_file() + | ?MODULE:af_record_decl() + | ?MODULE:af_wild_attribute() + | ?MODULE:af_function_decl(). + +-type af_module() :: {attribute, line(), module, module()}. + +-type af_export() :: {attribute, line(), export, ?MODULE:af_fa_list()}. + +-type af_import() :: {attribute, line(), import, ?MODULE:af_fa_list()}. + +-type af_fa_list() :: [{function(), arity()}]. + +-type af_compile() :: {attribute, line(), compile, any()}. + +-type af_file() :: {attribute, line(), file, {string(), line()}}. + +-type af_record_decl() :: + {attribute, line(), record, ?MODULE:af_record_name(), [?MODULE:af_field_decl()]}. + +-type af_field_decl() :: {record_field, line(), ?MODULE:af_atom()} + | {record_field, line(), ?MODULE:af_atom(), ?MODULE:abstract_expr()}. + +%% Types and specs, among other things... +-type af_wild_attribute() :: {attribute, line(), ?MODULE:af_atom(), any()}. + +-type af_function_decl() :: + {function, line(), function(), arity(), ?MODULE:af_clause_seq()}. + +-opaque abstract_expr() :: ?MODULE:af_literal() + | ?MODULE:af_match(?MODULE:abstract_expr()) + | ?MODULE:af_variable() + | ?MODULE:af_tuple(?MODULE:abstract_expr()) + | ?MODULE:af_nil() + | ?MODULE:af_cons(?MODULE:abstract_expr()) + | ?MODULE:af_bin(?MODULE:abstract_expr()) + | ?MODULE:af_binary_op(?MODULE:abstract_expr()) + | ?MODULE:af_unary_op(?MODULE:abstract_expr()) + | ?MODULE:af_record_access(?MODULE:abstract_expr()) + | ?MODULE:af_record_update(?MODULE:abstract_expr()) + | ?MODULE:af_record_index() + | ?MODULE:af_record_field(?MODULE:abstract_expr()) + | ?MODULE:af_catch() + | ?MODULE:af_local_call() + | ?MODULE:af_remote_call() + | ?MODULE:af_list_comprehension() + | ?MODULE:af_binary_comprehension() + | ?MODULE:af_block() + | ?MODULE:af_if() + | ?MODULE:af_case() + | ?MODULE:af_try() + | ?MODULE:af_receive() + | ?MODULE:af_local_fun() + | ?MODULE:af_remote_fun() + | ?MODULE:af_fun() + | ?MODULE:af_query() + | ?MODULE:af_query_access(). + +-type af_record_update(T) :: {record, + line(), + ?MODULE:abstract_expr(), + ?MODULE:af_record_name(), + [?MODULE:af_record_field(T)]}. + +-type af_catch() :: {'catch', line(), ?MODULE:abstract_expr()}. + +-type af_local_call() :: {call, line(), ?MODULE:af_local_function(), ?MODULE:af_args()}. + +-type af_remote_call() :: {call, line(), ?MODULE:af_remote_function(), ?MODULE:af_args()}. + +-type af_args() :: [?MODULE:abstract_expr()]. + +-type af_local_function() :: ?MODULE:abstract_expr(). + +-type af_remote_function() :: + {remote, line(), ?MODULE:abstract_expr(), ?MODULE:abstract_expr()}. + +-type af_list_comprehension() :: + {lc, line(), ?MODULE:af_template(), ?MODULE:af_qualifier_seq()}. + +-type af_binary_comprehension() :: + {bc, line(), ?MODULE:af_template(), ?MODULE:af_qualifier_seq()}. + +-type af_template() :: ?MODULE:abstract_expr(). + +-type af_qualifier_seq() :: [?MODULE:af_qualifier()]. + +-type af_qualifier() :: ?MODULE:af_generator() | ?MODULE:af_filter(). + +-type af_generator() :: {generate, line(), ?MODULE:af_pattern(), ?MODULE:abstract_expr()} + | {b_generate, line(), ?MODULE:af_pattern(), ?MODULE:abstract_expr()}. + +-type af_filter() :: ?MODULE:abstract_expr(). + +-type af_block() :: {block, line(), ?MODULE:af_body()}. + +-type af_if() :: {'if', line(), ?MODULE:af_clause_seq()}. + +-type af_case() :: {'case', line(), ?MODULE:abstract_expr(), ?MODULE:af_clause_seq()}. + +-type af_try() :: {'try', + line(), + ?MODULE:af_body(), + ?MODULE:af_clause_seq(), + ?MODULE:af_catch_clause_seq(), + ?MODULE:af_body()}. + +-type af_clause_seq() :: [?MODULE:af_clause(), ...]. + +-type af_catch_clause_seq() :: [?MODULE:af_clause(), ...]. + +-type af_receive() :: + {'receive', line(), ?MODULE:af_clause_seq()} + | {'receive', line(), ?MODULE:af_clause_seq(), ?MODULE:abstract_expr(), ?MODULE:af_body()}. + +-type af_local_fun() :: {'fun', line(), {function, function(), arity()}}. + +-type af_remote_fun() :: + {'fun', line(), {function, module(), function(), arity()}} + | {'fun', line(), {function, ?MODULE:af_atom(), ?MODULE:af_atom(), ?MODULE:af_integer()}}. + +-type af_fun() :: {'fun', line(), {clauses, ?MODULE:af_clause_seq()}}. + +-type af_query() :: {'query', line(), ?MODULE:af_list_comprehension()}. + +-type af_query_access() :: + {record_field, line(), ?MODULE:abstract_expr(), ?MODULE:af_field_name()}. + +-type abstract_clause() :: ?MODULE:af_clause() | ?MODULE:af_catch_clause(). + +-type af_clause() :: + {clause, line(), [?MODULE:af_pattern()], ?MODULE:af_guard_seq(), ?MODULE:af_body()}. + +-type af_catch_clause() :: + {clause, line(), [?MODULE:af_catch_pattern()], ?MODULE:af_guard_seq(), ?MODULE:af_body()}. + +-type af_catch_pattern() :: + {?MODULE:af_catch_class(), ?MODULE:af_pattern(), ?MODULE:af_anon_variable()}. + +-type af_catch_class() :: + ?MODULE:af_variable() + | ?MODULE:af_lit_atom(throw) | ?MODULE:af_lit_atom(error) | ?MODULE:af_lit_atom(exit). + +-type af_body() :: [?MODULE:abstract_expr(), ...]. + +-type af_guard_seq() :: [?MODULE:af_guard()]. + +-type af_guard() :: [?MODULE:af_guard_test(), ...]. + +-type af_guard_test() :: ?MODULE:af_literal() + | ?MODULE:af_variable() + | ?MODULE:af_tuple(?MODULE:af_guard_test()) + | ?MODULE:af_nil() + | ?MODULE:af_cons(?MODULE:af_guard_test()) + | ?MODULE:af_bin(?MODULE:af_guard_test()) + | ?MODULE:af_binary_op(?MODULE:af_guard_test()) + | ?MODULE:af_unary_op(?MODULE:af_guard_test()) + | ?MODULE:af_record_access(?MODULE:af_guard_test()) + | ?MODULE:af_record_index() + | ?MODULE:af_record_field(?MODULE:af_guard_test()) + | ?MODULE:af_guard_call() + | ?MODULE:af_remote_guard_call(). + +-type af_record_access(T) :: + {record, line(), ?MODULE:af_record_name(), [?MODULE:af_record_field(T)]}. + +-type af_guard_call() :: {call, line(), function(), [?MODULE:af_guard_test()]}. + +-type af_remote_guard_call() :: + {call, line(), atom(), ?MODULE:af_lit_atom(erlang), [?MODULE:af_guard_test()]}. + +-type af_pattern() :: ?MODULE:af_literal() + | ?MODULE:af_match(?MODULE:af_pattern()) + | ?MODULE:af_variable() + | ?MODULE:af_anon_variable() + | ?MODULE:af_tuple(?MODULE:af_pattern()) + | ?MODULE:af_nil() + | ?MODULE:af_cons(?MODULE:af_pattern()) + | ?MODULE:af_bin(?MODULE:af_pattern()) + | ?MODULE:af_binary_op(?MODULE:af_pattern()) + | ?MODULE:af_unary_op(?MODULE:af_pattern()) + | ?MODULE:af_record_index() + | ?MODULE:af_record_field(?MODULE:af_pattern()). + +-type af_literal() :: ?MODULE:af_atom() | ?MODULE:af_integer() | ?MODULE:af_float() | ?MODULE:af_string(). + +-type af_atom() :: ?MODULE:af_lit_atom(atom()). + +-type af_lit_atom(A) :: {atom, line(), A}. + +-type af_integer() :: {integer, line(), non_neg_integer()}. + +-type af_float() :: {float, line(), float()}. + +-type af_string() :: {string, line(), [byte()]}. + +-type af_match(T) :: {match, line(), T, T}. + +-type af_variable() :: {var, line(), atom()}. + +-type af_anon_variable() :: {var, line(), '_'}. + +-type af_tuple(T) :: {tuple, line(), [T]}. + +-type af_nil() :: {nil, line()}. + +-type af_cons(T) :: {cons, line, T, T}. + +-type af_bin(T) :: {bin, line(), [?MODULE:af_binelement(T)]}. + +-type af_binelement(T) :: {bin_element, + line(), + T, + ?MODULE:af_binelement_size(), + type_specifier_list()}. + +-type af_binelement_size() :: default | ?MODULE:abstract_expr(). + +-type af_binary_op(T) :: {op, line(), T, ?MODULE:af_binop(), T}. + +-type af_binop() :: '/' | '*' | 'div' | 'rem' | 'band' | 'and' | '+' | '-' + | 'bor' | 'bxor' | 'bsl' | 'bsr' | 'or' | 'xor' | '++' + | '--' | '==' | '/=' | '=<' | '<' | '>=' | '>' | '=:=' + | '=/='. + +-type af_unary_op(T) :: {op, line(), ?MODULE:af_unop(), T}. + +-type af_unop() :: '+' | '*' | 'bnot' | 'not'. + +%% See also lib/stdlib/{src/erl_bits.erl,include/erl_bits.hrl}. +-type type_specifier_list() :: default | [type_specifier(), ...]. + +-type type_specifier() :: af_type() + | af_signedness() + | af_endianness() + | af_unit(). + +-type af_type() :: integer + | float + | binary + | bytes + | bitstring + | bits + | utf8 + | utf16 + | utf32. + +-type af_signedness() :: signed | unsigned. + +-type af_endianness() :: big | little | native. + +-type af_unit() :: {unit, 1..256}. + +-type af_record_index() :: + {record_index, line(), af_record_name(), af_field_name()}. + +-type af_record_field(T) :: {record_field, line(), af_field_name(), T}. + +-type af_record_name() :: atom(). + +-type af_field_name() :: atom(). + +%% End of Abstract Format + +-type error_description() :: term(). +-type error_info() :: {erl_anno:line(), module(), error_description()}. +-type token() :: {Tag :: atom(), Line :: erl_anno:line()}. + +%% mkop(Op, Arg) -> {op,Line,Op,Arg}. +%% mkop(Left, Op, Right) -> {op,Line,Op,Left,Right}. + +-define(mkop2(L, OpPos, R), + begin + {Op,Pos} = OpPos, + {op,Pos,Op,L,R} + end). + +-define(mkop1(OpPos, A), + begin + {Op,Pos} = OpPos, + {op,Pos,Op,A} + end). + +%% keep track of line info in tokens +-define(line(Tup), element(2, Tup)). + +%% Entry points compatible to old erl_parse. +%% These really suck and are only here until Calle gets multiple +%% entry points working. + +-spec parse_form(Tokens) -> {ok, AbsForm} | {error, ErrorInfo} when + Tokens :: [token()], + AbsForm :: abstract_form(), + ErrorInfo :: error_info(). +parse_form([{'-',L1},{atom,L2,spec}|Tokens]) -> + parse([{'-',L1},{'spec',L2}|Tokens]); +parse_form([{'-',L1},{atom,L2,callback}|Tokens]) -> + parse([{'-',L1},{'callback',L2}|Tokens]); +parse_form(Tokens) -> + parse(Tokens). + +-spec parse_exprs(Tokens) -> {ok, ExprList} | {error, ErrorInfo} when + Tokens :: [token()], + ExprList :: [abstract_expr()], + ErrorInfo :: error_info(). +parse_exprs(Tokens) -> + case parse([{atom,0,f},{'(',0},{')',0},{'->',0}|Tokens]) of + {ok,{function,_Lf,f,0,[{clause,_Lc,[],[],Exprs}]}} -> + {ok,Exprs}; + {error,_} = Err -> Err + end. + +-spec parse_term(Tokens) -> {ok, Term} | {error, ErrorInfo} when + Tokens :: [token()], + Term :: term(), + ErrorInfo :: error_info(). +parse_term(Tokens) -> + case parse([{atom,0,f},{'(',0},{')',0},{'->',0}|Tokens]) of + {ok,{function,_Lf,f,0,[{clause,_Lc,[],[],[Expr]}]}} -> + try normalise(Expr) of + Term -> {ok,Term} + catch + _:_R -> {error,{?line(Expr),?MODULE,"bad term"}} + end; + {ok,{function,_Lf,f,0,[{clause,_Lc,[],[],[_E1,E2|_Es]}]}} -> + {error,{?line(E2),?MODULE,"bad term"}}; + {error,_} = Err -> Err + end. + +%% Convert between the abstract form of a term and a term. + +-spec normalise(AbsTerm) -> Data when + AbsTerm :: abstract_expr(), + Data :: term(). +normalise({char,_,C}) -> C; +normalise({integer,_,I}) -> I; +normalise({float,_,F}) -> F; +normalise({atom,_,A}) -> A; +normalise({string,_,S}) -> S; +normalise({nil,_}) -> []; +normalise({bin,_,Fs}) -> + {value, B, _} = + eval_bits:expr_grp(Fs, [], + fun(E, _) -> + {value, normalise(E), []} + end, [], true), + B; +normalise({cons,_,Head,Tail}) -> + [normalise(Head)|normalise(Tail)]; +normalise({tuple,_,Args}) -> + list_to_tuple(normalise_list(Args)); +%% Atom dot-notation, as in 'foo.bar.baz' +%% Special case for unary +/-. +normalise({op,_,'+',{char,_,I}}) -> I; +normalise({op,_,'+',{integer,_,I}}) -> I; +normalise({op,_,'+',{float,_,F}}) -> F; +normalise({op,_,'-',{char,_,I}}) -> -I; %Weird, but compatible! +normalise({op,_,'-',{integer,_,I}}) -> -I; +normalise({op,_,'-',{float,_,F}}) -> -F; +normalise(X) -> erlang:error({badarg, X}). + +normalise_list([H|T]) -> + [normalise(H)|normalise_list(T)]; +normalise_list([]) -> + []. + +%% Generate a list of tokens representing the abstract term. + +-spec tokens(AbsTerm) -> Tokens when + AbsTerm :: abstract_expr(), + Tokens :: [token()]. +tokens(Abs) -> + tokens(Abs, []). + +-spec tokens(AbsTerm, MoreTokens) -> Tokens when + AbsTerm :: abstract_expr(), + MoreTokens :: [token()], + Tokens :: [token()]. +tokens({char,L,C}, More) -> [{char,L,C}|More]; +tokens({integer,L,N}, More) -> [{integer,L,N}|More]; +tokens({float,L,F}, More) -> [{float,L,F}|More]; +tokens({atom,L,A}, More) -> [{atom,L,A}|More]; +tokens({var,L,V}, More) -> [{var,L,V}|More]; +tokens({string,L,S}, More) -> [{string,L,S}|More]; +tokens({nil,L}, More) -> [{'[',L},{']',L}|More]; +tokens({cons,L,Head,Tail}, More) -> + [{'[',L}|tokens(Head, tokens_tail(Tail, More))]; +tokens({tuple,L,[]}, More) -> + [{'{',L},{'}',L}|More]; +tokens({tuple,L,[E|Es]}, More) -> + [{'{',L}|tokens(E, tokens_tuple(Es, ?line(E), More))]. + +tokens_tail({cons,L,Head,Tail}, More) -> + [{',',L}|tokens(Head, tokens_tail(Tail, More))]; +tokens_tail({nil,L}, More) -> + [{']',L}|More]; +tokens_tail(Other, More) -> + L = ?line(Other), + [{'|',L}|tokens(Other, [{']',L}|More])]. + +tokens_tuple([E|Es], Line, More) -> + [{',',Line}|tokens(E, tokens_tuple(Es, ?line(E), More))]; +tokens_tuple([], Line, More) -> + [{'}',Line}|More]. + +%% Give the relative precedences of operators. + +inop_prec('=') -> {150,100,100}; +inop_prec('!') -> {150,100,100}; +inop_prec('orelse') -> {160,150,150}; +inop_prec('andalso') -> {200,160,160}; +inop_prec('==') -> {300,200,300}; +inop_prec('/=') -> {300,200,300}; +inop_prec('=<') -> {300,200,300}; +inop_prec('<') -> {300,200,300}; +inop_prec('>=') -> {300,200,300}; +inop_prec('>') -> {300,200,300}; +inop_prec('=:=') -> {300,200,300}; +inop_prec('=/=') -> {300,200,300}; +inop_prec('++') -> {400,300,300}; +inop_prec('--') -> {400,300,300}; +inop_prec('+') -> {400,400,500}; +inop_prec('-') -> {400,400,500}; +inop_prec('bor') -> {400,400,500}; +inop_prec('bxor') -> {400,400,500}; +inop_prec('bsl') -> {400,400,500}; +inop_prec('bsr') -> {400,400,500}; +inop_prec('or') -> {400,400,500}; +inop_prec('xor') -> {400,400,500}; +inop_prec('*') -> {500,500,600}; +inop_prec('/') -> {500,500,600}; +inop_prec('div') -> {500,500,600}; +inop_prec('rem') -> {500,500,600}; +inop_prec('band') -> {500,500,600}; +inop_prec('and') -> {500,500,600}; +inop_prec('#') -> {800,700,800}; +inop_prec(':') -> {900,800,900}; +inop_prec('.') -> {900,900,1000}. + +-type pre_op() :: 'catch' | '+' | '-' | 'bnot' | 'not' | '#'. + +-spec preop_prec(pre_op()) -> {0 | 600 | 700, 100 | 700 | 800}. + +preop_prec('catch') -> {0,100}; +preop_prec('+') -> {600,700}; +preop_prec('-') -> {600,700}; +preop_prec('bnot') -> {600,700}; +preop_prec('not') -> {600,700}; +preop_prec('#') -> {700,800}. + +-spec func_prec() -> {800,700}. + +func_prec() -> {800,700}. + +-spec max_prec() -> 1000. + +max_prec() -> 1000. + +parse(T) -> + bar:foo(T). diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/big_local_type.erl b/lib/dialyzer/test/opaque_SUITE_data/src/big_local_type.erl new file mode 100644 index 0000000000..7daceb5260 --- /dev/null +++ b/lib/dialyzer/test/opaque_SUITE_data/src/big_local_type.erl @@ -0,0 +1,523 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2001-2015. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +%%% A copy of small_SUITE_data/src/big_local_type.erl, where +%%% abstract_expr() is opaque. The transformation of forms to types is +%%% now much faster than it used to be, for this module. + +-module(big_local_type). + +-export([parse_form/1,parse_exprs/1,parse_term/1]). +-export([normalise/1,tokens/1,tokens/2]). +-export([inop_prec/1,preop_prec/1,func_prec/0,max_prec/0]). + +-export_type([abstract_clause/0, abstract_expr/0, abstract_form/0, + error_info/0]). + +%% Start of Abstract Format + +-type line() :: erl_anno:line(). + +-export_type([af_module/0, af_export/0, af_import/0, af_fa_list/0, + af_compile/0, af_file/0, af_record_decl/0, + af_field_decl/0, af_wild_attribute/0, + af_record_update/1, af_catch/0, af_local_call/0, + af_remote_call/0, af_args/0, af_local_function/0, + af_remote_function/0, af_list_comprehension/0, + af_binary_comprehension/0, af_template/0, + af_qualifier_seq/0, af_qualifier/0, af_generator/0, + af_filter/0, af_block/0, af_if/0, af_case/0, af_try/0, + af_clause_seq/0, af_catch_clause_seq/0, af_receive/0, + af_local_fun/0, af_remote_fun/0, af_fun/0, af_query/0, + af_query_access/0, af_clause/0, + af_catch_clause/0, af_catch_pattern/0, af_catch_class/0, + af_body/0, af_guard_seq/0, af_guard/0, af_guard_test/0, + af_record_access/1, af_guard_call/0, + af_remote_guard_call/0, af_pattern/0, af_literal/0, + af_atom/0, af_lit_atom/1, af_integer/0, af_float/0, + af_string/0, af_match/1, af_variable/0, + af_anon_variable/0, af_tuple/1, af_nil/0, af_cons/1, + af_bin/1, af_binelement/1, af_binelement_size/0, + af_binary_op/1, af_binop/0, af_unary_op/1, af_unop/0]). + +-type abstract_form() :: af_module() + | af_export() + | af_import() + | af_compile() + | af_file() + | af_record_decl() + | af_wild_attribute() + | af_function_decl(). + +-type af_module() :: {attribute, line(), module, module()}. + +-type af_export() :: {attribute, line(), export, af_fa_list()}. + +-type af_import() :: {attribute, line(), import, af_fa_list()}. + +-type af_fa_list() :: [{function(), arity()}]. + +-type af_compile() :: {attribute, line(), compile, any()}. + +-type af_file() :: {attribute, line(), file, {string(), line()}}. + +-type af_record_decl() :: + {attribute, line(), record, af_record_name(), [af_field_decl()]}. + +-type af_field_decl() :: {record_field, line(), af_atom()} + | {record_field, line(), af_atom(), abstract_expr()}. + +%% Types and specs, among other things... +-type af_wild_attribute() :: {attribute, line(), af_atom(), any()}. + +-type af_function_decl() :: + {function, line(), function(), arity(), af_clause_seq()}. + +-opaque abstract_expr() :: af_literal() + | af_match(abstract_expr()) + | af_variable() + | af_tuple(abstract_expr()) + | af_nil() + | af_cons(abstract_expr()) + | af_bin(abstract_expr()) + | af_binary_op(abstract_expr()) + | af_unary_op(abstract_expr()) + | af_record_access(abstract_expr()) + | af_record_update(abstract_expr()) + | af_record_index() + | af_record_field(abstract_expr()) + | af_catch() + | af_local_call() + | af_remote_call() + | af_list_comprehension() + | af_binary_comprehension() + | af_block() + | af_if() + | af_case() + | af_try() + | af_receive() + | af_local_fun() + | af_remote_fun() + | af_fun() + | af_query() + | af_query_access(). + +-type af_record_update(T) :: {record, + line(), + abstract_expr(), + af_record_name(), + [af_record_field(T)]}. + +-type af_catch() :: {'catch', line(), abstract_expr()}. + +-type af_local_call() :: {call, line(), af_local_function(), af_args()}. + +-type af_remote_call() :: {call, line(), af_remote_function(), af_args()}. + +-type af_args() :: [abstract_expr()]. + +-type af_local_function() :: abstract_expr(). + +-type af_remote_function() :: + {remote, line(), abstract_expr(), abstract_expr()}. + +-type af_list_comprehension() :: + {lc, line(), af_template(), af_qualifier_seq()}. + +-type af_binary_comprehension() :: + {bc, line(), af_template(), af_qualifier_seq()}. + +-type af_template() :: abstract_expr(). + +-type af_qualifier_seq() :: [af_qualifier()]. + +-type af_qualifier() :: af_generator() | af_filter(). + +-type af_generator() :: {generate, line(), af_pattern(), abstract_expr()} + | {b_generate, line(), af_pattern(), abstract_expr()}. + +-type af_filter() :: abstract_expr(). + +-type af_block() :: {block, line(), af_body()}. + +-type af_if() :: {'if', line(), af_clause_seq()}. + +-type af_case() :: {'case', line(), abstract_expr(), af_clause_seq()}. + +-type af_try() :: {'try', + line(), + af_body(), + af_clause_seq(), + af_catch_clause_seq(), + af_body()}. + +-type af_clause_seq() :: [af_clause(), ...]. + +-type af_catch_clause_seq() :: [af_clause(), ...]. + +-type af_receive() :: + {'receive', line(), af_clause_seq()} + | {'receive', line(), af_clause_seq(), abstract_expr(), af_body()}. + +-type af_local_fun() :: {'fun', line(), {function, function(), arity()}}. + +-type af_remote_fun() :: + {'fun', line(), {function, module(), function(), arity()}} + | {'fun', line(), {function, af_atom(), af_atom(), af_integer()}}. + +-type af_fun() :: {'fun', line(), {clauses, af_clause_seq()}}. + +-type af_query() :: {'query', line(), af_list_comprehension()}. + +-type af_query_access() :: + {record_field, line(), abstract_expr(), af_field_name()}. + +-type abstract_clause() :: af_clause() | af_catch_clause(). + +-type af_clause() :: + {clause, line(), [af_pattern()], af_guard_seq(), af_body()}. + +-type af_catch_clause() :: + {clause, line(), [af_catch_pattern()], af_guard_seq(), af_body()}. + +-type af_catch_pattern() :: + {af_catch_class(), af_pattern(), af_anon_variable()}. + +-type af_catch_class() :: + af_variable() + | af_lit_atom(throw) | af_lit_atom(error) | af_lit_atom(exit). + +-type af_body() :: [abstract_expr(), ...]. + +-type af_guard_seq() :: [af_guard()]. + +-type af_guard() :: [af_guard_test(), ...]. + +-type af_guard_test() :: af_literal() + | af_variable() + | af_tuple(af_guard_test()) + | af_nil() + | af_cons(af_guard_test()) + | af_bin(af_guard_test()) + | af_binary_op(af_guard_test()) + | af_unary_op(af_guard_test()) + | af_record_access(af_guard_test()) + | af_record_index() + | af_record_field(af_guard_test()) + | af_guard_call() + | af_remote_guard_call(). + +-type af_record_access(T) :: + {record, line(), af_record_name(), [af_record_field(T)]}. + +-type af_guard_call() :: {call, line(), function(), [af_guard_test()]}. + +-type af_remote_guard_call() :: + {call, line(), atom(), af_lit_atom(erlang), [af_guard_test()]}. + +-type af_pattern() :: af_literal() + | af_match(af_pattern()) + | af_variable() + | af_anon_variable() + | af_tuple(af_pattern()) + | af_nil() + | af_cons(af_pattern()) + | af_bin(af_pattern()) + | af_binary_op(af_pattern()) + | af_unary_op(af_pattern()) + | af_record_index() + | af_record_field(af_pattern()). + +-type af_literal() :: af_atom() | af_integer() | af_float() | af_string(). + +-type af_atom() :: af_lit_atom(atom()). + +-type af_lit_atom(A) :: {atom, line(), A}. + +-type af_integer() :: {integer, line(), non_neg_integer()}. + +-type af_float() :: {float, line(), float()}. + +-type af_string() :: {string, line(), [byte()]}. + +-type af_match(T) :: {match, line(), T, T}. + +-type af_variable() :: {var, line(), atom()}. + +-type af_anon_variable() :: {var, line(), '_'}. + +-type af_tuple(T) :: {tuple, line(), [T]}. + +-type af_nil() :: {nil, line()}. + +-type af_cons(T) :: {cons, line, T, T}. + +-type af_bin(T) :: {bin, line(), [af_binelement(T)]}. + +-type af_binelement(T) :: {bin_element, + line(), + T, + af_binelement_size(), + type_specifier_list()}. + +-type af_binelement_size() :: default | abstract_expr(). + +-type af_binary_op(T) :: {op, line(), T, af_binop(), T}. + +-type af_binop() :: '/' | '*' | 'div' | 'rem' | 'band' | 'and' | '+' | '-' + | 'bor' | 'bxor' | 'bsl' | 'bsr' | 'or' | 'xor' | '++' + | '--' | '==' | '/=' | '=<' | '<' | '>=' | '>' | '=:=' + | '=/='. + +-type af_unary_op(T) :: {op, line(), af_unop(), T}. + +-type af_unop() :: '+' | '*' | 'bnot' | 'not'. + +%% See also lib/stdlib/{src/erl_bits.erl,include/erl_bits.hrl}. +-type type_specifier_list() :: default | [type_specifier(), ...]. + +-type type_specifier() :: af_type() + | af_signedness() + | af_endianness() + | af_unit(). + +-type af_type() :: integer + | float + | binary + | bytes + | bitstring + | bits + | utf8 + | utf16 + | utf32. + +-type af_signedness() :: signed | unsigned. + +-type af_endianness() :: big | little | native. + +-type af_unit() :: {unit, 1..256}. + +-type af_record_index() :: + {record_index, line(), af_record_name(), af_field_name()}. + +-type af_record_field(T) :: {record_field, line(), af_field_name(), T}. + +-type af_record_name() :: atom(). + +-type af_field_name() :: atom(). + +%% End of Abstract Format + +-type error_description() :: term(). +-type error_info() :: {erl_anno:line(), module(), error_description()}. +-type token() :: {Tag :: atom(), Line :: erl_anno:line()}. + +%% mkop(Op, Arg) -> {op,Line,Op,Arg}. +%% mkop(Left, Op, Right) -> {op,Line,Op,Left,Right}. + +-define(mkop2(L, OpPos, R), + begin + {Op,Pos} = OpPos, + {op,Pos,Op,L,R} + end). + +-define(mkop1(OpPos, A), + begin + {Op,Pos} = OpPos, + {op,Pos,Op,A} + end). + +%% keep track of line info in tokens +-define(line(Tup), element(2, Tup)). + +%% Entry points compatible to old erl_parse. +%% These really suck and are only here until Calle gets multiple +%% entry points working. + +-spec parse_form(Tokens) -> {ok, AbsForm} | {error, ErrorInfo} when + Tokens :: [token()], + AbsForm :: abstract_form(), + ErrorInfo :: error_info(). +parse_form([{'-',L1},{atom,L2,spec}|Tokens]) -> + parse([{'-',L1},{'spec',L2}|Tokens]); +parse_form([{'-',L1},{atom,L2,callback}|Tokens]) -> + parse([{'-',L1},{'callback',L2}|Tokens]); +parse_form(Tokens) -> + parse(Tokens). + +-spec parse_exprs(Tokens) -> {ok, ExprList} | {error, ErrorInfo} when + Tokens :: [token()], + ExprList :: [abstract_expr()], + ErrorInfo :: error_info(). +parse_exprs(Tokens) -> + case parse([{atom,0,f},{'(',0},{')',0},{'->',0}|Tokens]) of + {ok,{function,_Lf,f,0,[{clause,_Lc,[],[],Exprs}]}} -> + {ok,Exprs}; + {error,_} = Err -> Err + end. + +-spec parse_term(Tokens) -> {ok, Term} | {error, ErrorInfo} when + Tokens :: [token()], + Term :: term(), + ErrorInfo :: error_info(). +parse_term(Tokens) -> + case parse([{atom,0,f},{'(',0},{')',0},{'->',0}|Tokens]) of + {ok,{function,_Lf,f,0,[{clause,_Lc,[],[],[Expr]}]}} -> + try normalise(Expr) of + Term -> {ok,Term} + catch + _:_R -> {error,{?line(Expr),?MODULE,"bad term"}} + end; + {ok,{function,_Lf,f,0,[{clause,_Lc,[],[],[_E1,E2|_Es]}]}} -> + {error,{?line(E2),?MODULE,"bad term"}}; + {error,_} = Err -> Err + end. + +%% Convert between the abstract form of a term and a term. + +-spec normalise(AbsTerm) -> Data when + AbsTerm :: abstract_expr(), + Data :: term(). +normalise({char,_,C}) -> C; +normalise({integer,_,I}) -> I; +normalise({float,_,F}) -> F; +normalise({atom,_,A}) -> A; +normalise({string,_,S}) -> S; +normalise({nil,_}) -> []; +normalise({bin,_,Fs}) -> + {value, B, _} = + eval_bits:expr_grp(Fs, [], + fun(E, _) -> + {value, normalise(E), []} + end, [], true), + B; +normalise({cons,_,Head,Tail}) -> + [normalise(Head)|normalise(Tail)]; +normalise({tuple,_,Args}) -> + list_to_tuple(normalise_list(Args)); +%% Atom dot-notation, as in 'foo.bar.baz' +%% Special case for unary +/-. +normalise({op,_,'+',{char,_,I}}) -> I; +normalise({op,_,'+',{integer,_,I}}) -> I; +normalise({op,_,'+',{float,_,F}}) -> F; +normalise({op,_,'-',{char,_,I}}) -> -I; %Weird, but compatible! +normalise({op,_,'-',{integer,_,I}}) -> -I; +normalise({op,_,'-',{float,_,F}}) -> -F; +normalise(X) -> erlang:error({badarg, X}). + +normalise_list([H|T]) -> + [normalise(H)|normalise_list(T)]; +normalise_list([]) -> + []. + +%% Generate a list of tokens representing the abstract term. + +-spec tokens(AbsTerm) -> Tokens when + AbsTerm :: abstract_expr(), + Tokens :: [token()]. +tokens(Abs) -> + tokens(Abs, []). + +-spec tokens(AbsTerm, MoreTokens) -> Tokens when + AbsTerm :: abstract_expr(), + MoreTokens :: [token()], + Tokens :: [token()]. +tokens({char,L,C}, More) -> [{char,L,C}|More]; +tokens({integer,L,N}, More) -> [{integer,L,N}|More]; +tokens({float,L,F}, More) -> [{float,L,F}|More]; +tokens({atom,L,A}, More) -> [{atom,L,A}|More]; +tokens({var,L,V}, More) -> [{var,L,V}|More]; +tokens({string,L,S}, More) -> [{string,L,S}|More]; +tokens({nil,L}, More) -> [{'[',L},{']',L}|More]; +tokens({cons,L,Head,Tail}, More) -> + [{'[',L}|tokens(Head, tokens_tail(Tail, More))]; +tokens({tuple,L,[]}, More) -> + [{'{',L},{'}',L}|More]; +tokens({tuple,L,[E|Es]}, More) -> + [{'{',L}|tokens(E, tokens_tuple(Es, ?line(E), More))]. + +tokens_tail({cons,L,Head,Tail}, More) -> + [{',',L}|tokens(Head, tokens_tail(Tail, More))]; +tokens_tail({nil,L}, More) -> + [{']',L}|More]; +tokens_tail(Other, More) -> + L = ?line(Other), + [{'|',L}|tokens(Other, [{']',L}|More])]. + +tokens_tuple([E|Es], Line, More) -> + [{',',Line}|tokens(E, tokens_tuple(Es, ?line(E), More))]; +tokens_tuple([], Line, More) -> + [{'}',Line}|More]. + +%% Give the relative precedences of operators. + +inop_prec('=') -> {150,100,100}; +inop_prec('!') -> {150,100,100}; +inop_prec('orelse') -> {160,150,150}; +inop_prec('andalso') -> {200,160,160}; +inop_prec('==') -> {300,200,300}; +inop_prec('/=') -> {300,200,300}; +inop_prec('=<') -> {300,200,300}; +inop_prec('<') -> {300,200,300}; +inop_prec('>=') -> {300,200,300}; +inop_prec('>') -> {300,200,300}; +inop_prec('=:=') -> {300,200,300}; +inop_prec('=/=') -> {300,200,300}; +inop_prec('++') -> {400,300,300}; +inop_prec('--') -> {400,300,300}; +inop_prec('+') -> {400,400,500}; +inop_prec('-') -> {400,400,500}; +inop_prec('bor') -> {400,400,500}; +inop_prec('bxor') -> {400,400,500}; +inop_prec('bsl') -> {400,400,500}; +inop_prec('bsr') -> {400,400,500}; +inop_prec('or') -> {400,400,500}; +inop_prec('xor') -> {400,400,500}; +inop_prec('*') -> {500,500,600}; +inop_prec('/') -> {500,500,600}; +inop_prec('div') -> {500,500,600}; +inop_prec('rem') -> {500,500,600}; +inop_prec('band') -> {500,500,600}; +inop_prec('and') -> {500,500,600}; +inop_prec('#') -> {800,700,800}; +inop_prec(':') -> {900,800,900}; +inop_prec('.') -> {900,900,1000}. + +-type pre_op() :: 'catch' | '+' | '-' | 'bnot' | 'not' | '#'. + +-spec preop_prec(pre_op()) -> {0 | 600 | 700, 100 | 700 | 800}. + +preop_prec('catch') -> {0,100}; +preop_prec('+') -> {600,700}; +preop_prec('-') -> {600,700}; +preop_prec('bnot') -> {600,700}; +preop_prec('not') -> {600,700}; +preop_prec('#') -> {700,800}. + +-spec func_prec() -> {800,700}. + +func_prec() -> {800,700}. + +-spec max_prec() -> 1000. + +max_prec() -> 1000. + +parse(T) -> + bar:foo(T). diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/para/myqueue.erl b/lib/dialyzer/test/opaque_SUITE_data/src/para/myqueue.erl new file mode 100644 index 0000000000..0f76680464 --- /dev/null +++ b/lib/dialyzer/test/opaque_SUITE_data/src/para/myqueue.erl @@ -0,0 +1,17 @@ +-module(myqueue). + +-export([new/0, in/2]). + +-record(myqueue, {queue = queue:new() :: queue:queue({integer(), _})}). + +-opaque myqueue(Item) :: #myqueue{queue :: queue:queue({integer(), Item})}. + +-export_type([myqueue/1]). + +-spec new() -> myqueue(_). +new() -> + #myqueue{queue=queue:new()}. + +-spec in(Item, myqueue(Item)) -> myqueue(Item). +in(Item, #myqueue{queue=Q}) -> + #myqueue{queue=queue:in({1, Item}, Q)}. diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/para/myqueue_params.erl b/lib/dialyzer/test/opaque_SUITE_data/src/para/myqueue_params.erl new file mode 100644 index 0000000000..8d766b7804 --- /dev/null +++ b/lib/dialyzer/test/opaque_SUITE_data/src/para/myqueue_params.erl @@ -0,0 +1,15 @@ +-module(myqueue_params). + +-export([new/0, in/2]). + +-record(myqueue_params, {myqueue = myqueue:new() :: myqueue:myqueue(integer())}). + +-type myqueue_params() :: #myqueue_params{myqueue :: + myqueue:myqueue(integer())}. +-spec new() -> myqueue_params(). +new() -> + #myqueue_params{myqueue=myqueue:new()}. + +-spec in(integer(), myqueue_params()) -> myqueue_params(). +in(Item, #myqueue_params{myqueue=Q} = P) when is_integer(Item) -> + P#myqueue_params{myqueue=myqueue:in(Item, Q)}. diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/proper/proper_common.hrl b/lib/dialyzer/test/opaque_SUITE_data/src/proper/proper_common.hrl new file mode 100644 index 0000000000..c10626c5cc --- /dev/null +++ b/lib/dialyzer/test/opaque_SUITE_data/src/proper/proper_common.hrl @@ -0,0 +1,55 @@ +%%% Copyright 2010-2013 Manolis Papadakis <[email protected]>, +%%% Eirini Arvaniti <[email protected]> +%%% and Kostis Sagonas <[email protected]> +%%% +%%% This file is part of PropEr. +%%% +%%% PropEr is free software: you can redistribute it and/or modify +%%% it under the terms of the GNU General Public License as published by +%%% the Free Software Foundation, either version 3 of the License, or +%%% (at your option) any later version. +%%% +%%% PropEr is distributed in the hope that it will be useful, +%%% but WITHOUT ANY WARRANTY; without even the implied warranty of +%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +%%% GNU General Public License for more details. +%%% +%%% You should have received a copy of the GNU General Public License +%%% along with PropEr. If not, see <http://www.gnu.org/licenses/>. + +%%% @copyright 2010-2013 Manolis Papadakis, Eirini Arvaniti and Kostis Sagonas +%%% @version {@version} +%%% @author Manolis Papadakis +%%% @doc Common parts of user and internal header files + + +%%------------------------------------------------------------------------------ +%% Test generation macros +%%------------------------------------------------------------------------------ + +-define(FORALL(X,RawType,Prop), proper:forall(RawType,fun(X) -> Prop end)). +-define(IMPLIES(Pre,Prop), proper:implies(Pre,?DELAY(Prop))). +-define(WHENFAIL(Action,Prop), proper:whenfail(?DELAY(Action),?DELAY(Prop))). +-define(TRAPEXIT(Prop), proper:trapexit(?DELAY(Prop))). +-define(TIMEOUT(Limit,Prop), proper:timeout(Limit,?DELAY(Prop))). +%% TODO: -define(ALWAYS(Tests,Prop), proper:always(Tests,?DELAY(Prop))). +%% TODO: -define(SOMETIMES(Tests,Prop), proper:sometimes(Tests,?DELAY(Prop))). + + +%%------------------------------------------------------------------------------ +%% Generator macros +%%------------------------------------------------------------------------------ + +-define(FORCE(X), (X)()). +-define(DELAY(X), fun() -> X end). +-define(LAZY(X), proper_types:lazy(?DELAY(X))). +-define(SIZED(SizeArg,Gen), proper_types:sized(fun(SizeArg) -> Gen end)). +-define(LET(X,RawType,Gen), proper_types:bind(RawType,fun(X) -> Gen end,false)). +-define(SHRINK(Gen,AltGens), + proper_types:shrinkwith(?DELAY(Gen),?DELAY(AltGens))). +-define(LETSHRINK(Xs,RawType,Gen), + proper_types:bind(RawType,fun(Xs) -> Gen end,true)). +-define(SUCHTHAT(X,RawType,Condition), + proper_types:add_constraint(RawType,fun(X) -> Condition end,true)). +-define(SUCHTHATMAYBE(X,RawType,Condition), + proper_types:add_constraint(RawType,fun(X) -> Condition end,false)). diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/proper/proper_gen.erl b/lib/dialyzer/test/opaque_SUITE_data/src/proper/proper_gen.erl new file mode 100644 index 0000000000..bf627d1373 --- /dev/null +++ b/lib/dialyzer/test/opaque_SUITE_data/src/proper/proper_gen.erl @@ -0,0 +1,624 @@ +%%% Copyright 2010-2013 Manolis Papadakis <[email protected]>, +%%% Eirini Arvaniti <[email protected]> +%%% and Kostis Sagonas <[email protected]> +%%% +%%% This file is part of PropEr. +%%% +%%% PropEr is free software: you can redistribute it and/or modify +%%% it under the terms of the GNU General Public License as published by +%%% the Free Software Foundation, either version 3 of the License, or +%%% (at your option) any later version. +%%% +%%% PropEr is distributed in the hope that it will be useful, +%%% but WITHOUT ANY WARRANTY; without even the implied warranty of +%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +%%% GNU General Public License for more details. +%%% +%%% You should have received a copy of the GNU General Public License +%%% along with PropEr. If not, see <http://www.gnu.org/licenses/>. + +%%% @copyright 2010-2013 Manolis Papadakis, Eirini Arvaniti and Kostis Sagonas +%%% @version {@version} +%%% @author Manolis Papadakis + +%%% @doc Generator subsystem and generators for basic types. +%%% +%%% You can use <a href="#index">these</a> functions to try out the random +%%% instance generation and shrinking subsystems. +%%% +%%% CAUTION: These functions should never be used inside properties. They are +%%% meant for demonstration purposes only. + +-module(proper_gen). +-export([pick/1, pick/2, pick/3, sample/1, sample/3, sampleshrink/1, sampleshrink/2]). + +-export([safe_generate/1]). +-export([generate/1, normal_gen/1, alt_gens/1, clean_instance/1, + get_ret_type/1]). +-export([integer_gen/3, float_gen/3, atom_gen/1, atom_rev/1, binary_gen/1, + binary_rev/1, binary_len_gen/1, bitstring_gen/1, bitstring_rev/1, + bitstring_len_gen/1, list_gen/2, distlist_gen/3, vector_gen/2, + union_gen/1, weighted_union_gen/1, tuple_gen/1, loose_tuple_gen/2, + loose_tuple_rev/2, exactly_gen/1, fixed_list_gen/1, function_gen/2, + any_gen/1, native_type_gen/2, safe_weighted_union_gen/1, + safe_union_gen/1]). + +-export_type([instance/0, imm_instance/0, sized_generator/0, nosize_generator/0, + generator/0, reverse_gen/0, combine_fun/0, alt_gens/0]). + +-include("proper_internal.hrl"). + + +%%----------------------------------------------------------------------------- +%% Types +%%----------------------------------------------------------------------------- + +%% TODO: update imm_instance() when adding more types: be careful when reading +%% anything that returns it +%% @private_type +-type imm_instance() :: proper_types:raw_type() + | instance() + | {'$used', imm_instance(), imm_instance()} + | {'$to_part', imm_instance()}. +-type instance() :: term(). +%% A value produced by the random instance generator. +-type error_reason() :: 'arity_limit' | 'cant_generate' | {'typeserver',term()}. + +%% @private_type +-type sized_generator() :: fun((size()) -> imm_instance()). +%% @private_type +-type typed_sized_generator() :: {'typed', + fun((proper_types:type(),size()) -> + imm_instance())}. +%% @private_type +-type nosize_generator() :: fun(() -> imm_instance()). +%% @private_type +-type typed_nosize_generator() :: {'typed', + fun((proper_types:type()) -> + imm_instance())}. +%% @private_type +-type generator() :: sized_generator() + | typed_sized_generator() + | nosize_generator() + | typed_nosize_generator(). +%% @private_type +-type plain_reverse_gen() :: fun((instance()) -> imm_instance()). +%% @private_type +-type typed_reverse_gen() :: {'typed', + fun((proper_types:type(),instance()) -> + imm_instance())}. +%% @private_type +-type reverse_gen() :: plain_reverse_gen() | typed_reverse_gen(). +%% @private_type +-type combine_fun() :: fun((instance()) -> imm_instance()). +%% @private_type +-type alt_gens() :: fun(() -> [imm_instance()]). +%% @private_type +-type fun_seed() :: {non_neg_integer(),non_neg_integer()}. + + +%%----------------------------------------------------------------------------- +%% Instance generation functions +%%----------------------------------------------------------------------------- + +%% @private +-spec safe_generate(proper_types:raw_type()) -> + {'ok',imm_instance()} | {'error',error_reason()}. +safe_generate(RawType) -> + try generate(RawType) of + ImmInstance -> {ok, ImmInstance} + catch + throw:'$arity_limit' -> {error, arity_limit}; + throw:'$cant_generate' -> {error, cant_generate}; + throw:{'$typeserver',SubReason} -> {error, {typeserver,SubReason}} + end. + +%% @private +-spec generate(proper_types:raw_type()) -> imm_instance(). +generate(RawType) -> + Type = proper_types:cook_outer(RawType), + ok = add_parameters(Type), + Instance = generate(Type, get('$constraint_tries'), none), + ok = remove_parameters(Type), + Instance. + +-spec add_parameters(proper_types:type()) -> 'ok'. +add_parameters(Type) -> + case proper_types:find_prop(parameters, Type) of + {ok, Params} -> + OldParams = erlang:get('$parameters'), + case OldParams of + undefined -> + erlang:put('$parameters', Params); + _ -> + erlang:put('$parameters', Params ++ OldParams) + end, + ok; + _ -> + ok + end. + +-spec remove_parameters(proper_types:type()) -> 'ok'. +remove_parameters(Type) -> + case proper_types:find_prop(parameters, Type) of + {ok, Params} -> + AllParams = erlang:get('$parameters'), + case AllParams of + Params-> + erlang:erase('$parameters'); + _ -> + erlang:put('$parameters', AllParams -- Params) + end, + ok; + _ -> + ok + end. + +-spec generate(proper_types:type(), non_neg_integer(), + 'none' | {'ok',imm_instance()}) -> imm_instance(). +generate(_Type, 0, none) -> + throw('$cant_generate'); +generate(_Type, 0, {ok,Fallback}) -> + Fallback; +generate(Type, TriesLeft, Fallback) -> + ImmInstance = + case proper_types:get_prop(kind, Type) of + constructed -> + PartsType = proper_types:get_prop(parts_type, Type), + Combine = proper_types:get_prop(combine, Type), + ImmParts = generate(PartsType), + Parts = clean_instance(ImmParts), + ImmInstance1 = Combine(Parts), + %% TODO: We can just generate the internal type: if it's not + %% a type, it will turn into an exactly. + ImmInstance2 = + case proper_types:is_raw_type(ImmInstance1) of + true -> generate(ImmInstance1); + false -> ImmInstance1 + end, + {'$used',ImmParts,ImmInstance2}; + _ -> + ImmInstance1 = normal_gen(Type), + case proper_types:is_raw_type(ImmInstance1) of + true -> generate(ImmInstance1); + false -> ImmInstance1 + end + end, + case proper_types:satisfies_all(clean_instance(ImmInstance), Type) of + {_,true} -> ImmInstance; + {true,false} -> generate(Type, TriesLeft - 1, {ok,ImmInstance}); + {false,false} -> generate(Type, TriesLeft - 1, Fallback) + end. + +%% @equiv pick(Type, 10) +-spec pick(Type::proper_types:raw_type()) -> {'ok',instance()} | 'error'. +pick(RawType) -> + pick(RawType, 10). + +%% @equiv pick(Type, Size, now()) +-spec pick(Type::proper_types:raw_type(), size()) -> {'ok', instance()} | 'error'. +pick(RawType, Size) -> + pick(RawType, Size, now()). + +%% @doc Generates a random instance of `Type', of size `Size' with seed `Seed'. +-spec pick(Type::proper_types:raw_type(), size(), seed()) -> + {'ok',instance()} | 'error'. +pick(RawType, Size, Seed) -> + proper:global_state_init_size_seed(Size, Seed), + case clean_instance(safe_generate(RawType)) of + {ok,Instance} = Result -> + Msg = "WARNING: Some garbage has been left in the process registry " + "and the code server~n" + "to allow for the returned function(s) to run normally.~n" + "Please run proper:global_state_erase() when done.~n", + case contains_fun(Instance) of + true -> io:format(Msg, []); + false -> proper:global_state_erase() + end, + Result; + {error,Reason} -> + proper:report_error(Reason, fun io:format/2), + proper:global_state_erase(), + error + end. + +%% @equiv sample(Type, 10, 20) +-spec sample(Type::proper_types:raw_type()) -> 'ok'. +sample(RawType) -> + sample(RawType, 10, 20). + +%% @doc Generates and prints one random instance of `Type' for each size from +%% `StartSize' up to `EndSize'. +-spec sample(Type::proper_types:raw_type(), size(), size()) -> 'ok'. +sample(RawType, StartSize, EndSize) when StartSize =< EndSize -> + Tests = EndSize - StartSize + 1, + Prop = ?FORALL(X, RawType, begin io:format("~p~n",[X]), true end), + Opts = [quiet,{start_size,StartSize},{max_size,EndSize},{numtests,Tests}], + _ = proper:quickcheck(Prop, Opts), + ok. + +%% @equiv sampleshrink(Type, 10) +-spec sampleshrink(Type::proper_types:raw_type()) -> 'ok'. +sampleshrink(RawType) -> + sampleshrink(RawType, 10). + +%% @doc Generates a random instance of `Type', of size `Size', then shrinks it +%% as far as it goes. The value produced on each step of the shrinking process +%% is printed on the screen. +-spec sampleshrink(Type::proper_types:raw_type(), size()) -> 'ok'. +sampleshrink(RawType, Size) -> + proper:global_state_init_size(Size), + Type = proper_types:cook_outer(RawType), + case safe_generate(Type) of + {ok,ImmInstance} -> + Shrunk = keep_shrinking(ImmInstance, [], Type), + PrintInst = fun(I) -> io:format("~p~n",[clean_instance(I)]) end, + lists:foreach(PrintInst, Shrunk); + {error,Reason} -> + proper:report_error(Reason, fun io:format/2) + end, + proper:global_state_erase(), + ok. + +-spec keep_shrinking(imm_instance(), [imm_instance()], proper_types:type()) -> + [imm_instance(),...]. +keep_shrinking(ImmInstance, Acc, Type) -> + case proper_shrink:shrink(ImmInstance, Type, init) of + {[], _NewState} -> + lists:reverse([ImmInstance|Acc]); + {[Shrunk|_Rest], _NewState} -> + keep_shrinking(Shrunk, [ImmInstance|Acc], Type) + end. + +-spec contains_fun(term()) -> boolean(). +contains_fun(List) when is_list(List) -> + proper_arith:safe_any(fun contains_fun/1, List); +contains_fun(Tuple) when is_tuple(Tuple) -> + contains_fun(tuple_to_list(Tuple)); +contains_fun(Fun) when is_function(Fun) -> + true; +contains_fun(_Term) -> + false. + + +%%----------------------------------------------------------------------------- +%% Utility functions +%%----------------------------------------------------------------------------- + +%% @private +-spec normal_gen(proper_types:type()) -> imm_instance(). +normal_gen(Type) -> + case proper_types:get_prop(generator, Type) of + {typed, Gen} -> + if + is_function(Gen, 1) -> Gen(Type); + is_function(Gen, 2) -> Gen(Type, proper:get_size(Type)) + end; + Gen -> + if + is_function(Gen, 0) -> Gen(); + is_function(Gen, 1) -> Gen(proper:get_size(Type)) + end + end. + +%% @private +-spec alt_gens(proper_types:type()) -> [imm_instance()]. +alt_gens(Type) -> + case proper_types:find_prop(alt_gens, Type) of + {ok, AltGens} -> ?FORCE(AltGens); + error -> [] + end. + +%% @private +-spec clean_instance(imm_instance()) -> instance(). +clean_instance({'$used',_ImmParts,ImmInstance}) -> + clean_instance(ImmInstance); +clean_instance({'$to_part',ImmInstance}) -> + clean_instance(ImmInstance); +clean_instance(ImmInstance) -> + if + is_list(ImmInstance) -> + %% CAUTION: this must handle improper lists + proper_arith:safe_map(fun clean_instance/1, ImmInstance); + is_tuple(ImmInstance) -> + proper_arith:tuple_map(fun clean_instance/1, ImmInstance); + true -> + ImmInstance + end. + + +%%----------------------------------------------------------------------------- +%% Basic type generators +%%----------------------------------------------------------------------------- + +%% @private +-spec integer_gen(size(), proper_types:extint(), proper_types:extint()) -> + integer(). +integer_gen(Size, inf, inf) -> + proper_arith:rand_int(Size); +integer_gen(Size, inf, High) -> + High - proper_arith:rand_non_neg_int(Size); +integer_gen(Size, Low, inf) -> + Low + proper_arith:rand_non_neg_int(Size); +integer_gen(Size, Low, High) -> + proper_arith:smart_rand_int(Size, Low, High). + +%% @private +-spec float_gen(size(), proper_types:extnum(), proper_types:extnum()) -> + float(). +float_gen(Size, inf, inf) -> + proper_arith:rand_float(Size); +float_gen(Size, inf, High) -> + High - proper_arith:rand_non_neg_float(Size); +float_gen(Size, Low, inf) -> + Low + proper_arith:rand_non_neg_float(Size); +float_gen(_Size, Low, High) -> + proper_arith:rand_float(Low, High). + +%% @private +-spec atom_gen(size()) -> proper_types:type(). +%% We make sure we never clash with internal atoms by checking that the first +%% character is not '$'. +atom_gen(Size) -> + ?LET(Str, + ?SUCHTHAT(X, + proper_types:resize(Size, + proper_types:list(proper_types:byte())), + X =:= [] orelse hd(X) =/= $$), + list_to_atom(Str)). + +%% @private +-spec atom_rev(atom()) -> imm_instance(). +atom_rev(Atom) -> + {'$used', atom_to_list(Atom), Atom}. + +%% @private +-spec binary_gen(size()) -> proper_types:type(). +binary_gen(Size) -> + ?LET(Bytes, + proper_types:resize(Size, + proper_types:list(proper_types:byte())), + list_to_binary(Bytes)). + +%% @private +-spec binary_rev(binary()) -> imm_instance(). +binary_rev(Binary) -> + {'$used', binary_to_list(Binary), Binary}. + +%% @private +-spec binary_len_gen(length()) -> proper_types:type(). +binary_len_gen(Len) -> + ?LET(Bytes, + proper_types:vector(Len, proper_types:byte()), + list_to_binary(Bytes)). + +%% @private +-spec bitstring_gen(size()) -> proper_types:type(). +bitstring_gen(Size) -> + ?LET({BytesHead, NumBits, TailByte}, + {proper_types:resize(Size,proper_types:binary()), + proper_types:range(0,7), proper_types:range(0,127)}, + <<BytesHead/binary, TailByte:NumBits>>). + +%% @private +-spec bitstring_rev(bitstring()) -> imm_instance(). +bitstring_rev(BitString) -> + List = bitstring_to_list(BitString), + {BytesList, BitsTail} = lists:splitwith(fun erlang:is_integer/1, List), + {NumBits, TailByte} = case BitsTail of + [] -> {0, 0}; + [Bits] -> N = bit_size(Bits), + <<Byte:N>> = Bits, + {N, Byte} + end, + {'$used', + {{'$used',BytesList,list_to_binary(BytesList)}, NumBits, TailByte}, + BitString}. + +%% @private +-spec bitstring_len_gen(length()) -> proper_types:type(). +bitstring_len_gen(Len) -> + BytesLen = Len div 8, + BitsLen = Len rem 8, + ?LET({BytesHead, NumBits, TailByte}, + {proper_types:binary(BytesLen), BitsLen, + proper_types:range(0, 1 bsl BitsLen - 1)}, + <<BytesHead/binary, TailByte:NumBits>>). + +%% @private +-spec list_gen(size(), proper_types:type()) -> [imm_instance()]. +list_gen(Size, ElemType) -> + Len = proper_arith:rand_int(0, Size), + vector_gen(Len, ElemType). + +%% @private +-spec distlist_gen(size(), sized_generator(), boolean()) -> [imm_instance()]. +distlist_gen(RawSize, Gen, NonEmpty) -> + Len = case NonEmpty of + true -> proper_arith:rand_int(1, erlang:max(1,RawSize)); + false -> proper_arith:rand_int(0, RawSize) + end, + Size = case Len of + 1 -> RawSize - 1; + _ -> RawSize + end, + %% TODO: this produces a lot of types: maybe a simple 'div' is sufficient? + Sizes = proper_arith:distribute(Size, Len), + InnerTypes = [Gen(S) || S <- Sizes], + fixed_list_gen(InnerTypes). + +%% @private +-spec vector_gen(length(), proper_types:type()) -> [imm_instance()]. +vector_gen(Len, ElemType) -> + vector_gen_tr(Len, ElemType, []). + +-spec vector_gen_tr(length(), proper_types:type(), [imm_instance()]) -> + [imm_instance()]. +vector_gen_tr(0, _ElemType, AccList) -> + AccList; +vector_gen_tr(Left, ElemType, AccList) -> + vector_gen_tr(Left - 1, ElemType, [generate(ElemType) | AccList]). + +%% @private +-spec union_gen([proper_types:type(),...]) -> imm_instance(). +union_gen(Choices) -> + {_Choice,Type} = proper_arith:rand_choose(Choices), + generate(Type). + +%% @private +-spec weighted_union_gen([{frequency(),proper_types:type()},...]) -> + imm_instance(). +weighted_union_gen(FreqChoices) -> + {_Choice,Type} = proper_arith:freq_choose(FreqChoices), + generate(Type). + +%% @private +-spec safe_union_gen([proper_types:type(),...]) -> imm_instance(). +safe_union_gen(Choices) -> + {Choice,Type} = proper_arith:rand_choose(Choices), + try generate(Type) + catch + error:_ -> + safe_union_gen(proper_arith:list_remove(Choice, Choices)) + end. + +%% @private +-spec safe_weighted_union_gen([{frequency(),proper_types:type()},...]) -> + imm_instance(). +safe_weighted_union_gen(FreqChoices) -> + {Choice,Type} = proper_arith:freq_choose(FreqChoices), + try generate(Type) + catch + error:_ -> + safe_weighted_union_gen(proper_arith:list_remove(Choice, + FreqChoices)) + end. + +%% @private +-spec tuple_gen([proper_types:type()]) -> tuple(). +tuple_gen(Fields) -> + list_to_tuple(fixed_list_gen(Fields)). + +%% @private +-spec loose_tuple_gen(size(), proper_types:type()) -> proper_types:type(). +loose_tuple_gen(Size, ElemType) -> + ?LET(L, + proper_types:resize(Size, proper_types:list(ElemType)), + list_to_tuple(L)). + +%% @private +-spec loose_tuple_rev(tuple(), proper_types:type()) -> imm_instance(). +loose_tuple_rev(Tuple, ElemType) -> + CleanList = tuple_to_list(Tuple), + List = case proper_types:find_prop(reverse_gen, ElemType) of + {ok,{typed, ReverseGen}} -> + [ReverseGen(ElemType,X) || X <- CleanList]; + {ok,ReverseGen} -> [ReverseGen(X) || X <- CleanList]; + error -> CleanList + end, + {'$used', List, Tuple}. + +%% @private +-spec exactly_gen(T) -> T. +exactly_gen(X) -> + X. + +%% @private +-spec fixed_list_gen([proper_types:type()]) -> imm_instance() + ; ({[proper_types:type()],proper_types:type()}) -> + maybe_improper_list(imm_instance(), imm_instance() | []). +fixed_list_gen({ProperHead,ImproperTail}) -> + [generate(F) || F <- ProperHead] ++ generate(ImproperTail); +fixed_list_gen(ProperFields) -> + [generate(F) || F <- ProperFields]. + +%% @private +-spec function_gen(arity(), proper_types:type()) -> function(). +function_gen(Arity, RetType) -> + FunSeed = {proper_arith:rand_int(0, ?SEED_RANGE - 1), + proper_arith:rand_int(0, ?SEED_RANGE - 1)}, + create_fun(Arity, RetType, FunSeed). + +%% @private +-spec any_gen(size()) -> imm_instance(). +any_gen(Size) -> + case get('$any_type') of + undefined -> real_any_gen(Size); + {type,AnyType} -> generate(proper_types:resize(Size, AnyType)) + end. + +-spec real_any_gen(size()) -> imm_instance(). +real_any_gen(0) -> + SimpleTypes = [proper_types:integer(), proper_types:float(), + proper_types:atom()], + union_gen(SimpleTypes); +real_any_gen(Size) -> + FreqChoices = [{?ANY_SIMPLE_PROB,simple}, {?ANY_BINARY_PROB,binary}, + {?ANY_EXPAND_PROB,expand}], + case proper_arith:freq_choose(FreqChoices) of + {_,simple} -> + real_any_gen(0); + {_,binary} -> + generate(proper_types:resize(Size, proper_types:bitstring())); + {_,expand} -> + %% TODO: statistics of produced terms? + NumElems = proper_arith:rand_int(0, Size - 1), + ElemSizes = proper_arith:distribute(Size - 1, NumElems), + ElemTypes = [?LAZY(real_any_gen(S)) || S <- ElemSizes], + case proper_arith:rand_int(1,2) of + 1 -> fixed_list_gen(ElemTypes); + 2 -> tuple_gen(ElemTypes) + end + end. + +%% @private +-spec native_type_gen(mod_name(), string()) -> proper_types:type(). +native_type_gen(Mod, TypeStr) -> + case proper_typeserver:translate_type({Mod,TypeStr}) of + {ok,Type} -> Type; + {error,Reason} -> throw({'$typeserver',Reason}) + end. + + +%%------------------------------------------------------------------------------ +%% Function-generation functions +%%------------------------------------------------------------------------------ + +-spec create_fun(arity(), proper_types:type(), fun_seed()) -> function(). +create_fun(Arity, RetType, FunSeed) -> + Handler = fun(Args) -> function_body(Args, RetType, FunSeed) end, + Err = fun() -> throw('$arity_limit') end, + case Arity of + 0 -> fun() -> Handler([]) end; + _ -> Err() + end. + +%% @private +-spec get_ret_type(function()) -> proper_types:type(). +get_ret_type(Fun) -> + {arity,Arity} = erlang:fun_info(Fun, arity), + put('$get_ret_type', true), + RetType = apply(Fun, lists:duplicate(Arity,dummy)), + erase('$get_ret_type'), + RetType. +-spec function_body([term()], proper_types:type(), fun_seed()) -> + proper_types:type() | instance(). +function_body(Args, RetType, {Seed1,Seed2}) -> + case get('$get_ret_type') of + true -> + RetType; + _ -> + SavedSeed = get(?SEED_NAME), + update_seed({Seed1,Seed2,erlang:phash2(Args,?SEED_RANGE)}), + Ret = clean_instance(generate(RetType)), + put(?SEED_NAME, SavedSeed), + proper_symb:internal_eval(Ret) + end. + +-ifdef(USE_SFMT). +update_seed(Seed) -> + sfmt:seed(Seed). +-else. +update_seed(Seed) -> + put(random_seed, Seed). +-endif. diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/proper/proper_internal.hrl b/lib/dialyzer/test/opaque_SUITE_data/src/proper/proper_internal.hrl new file mode 100644 index 0000000000..c790d7d4db --- /dev/null +++ b/lib/dialyzer/test/opaque_SUITE_data/src/proper/proper_internal.hrl @@ -0,0 +1,92 @@ +%%% Copyright 2010-2013 Manolis Papadakis <[email protected]>, +%%% Eirini Arvaniti <[email protected]> +%%% and Kostis Sagonas <[email protected]> +%%% +%%% This file is part of PropEr. +%%% +%%% PropEr is free software: you can redistribute it and/or modify +%%% it under the terms of the GNU General Public License as published by +%%% the Free Software Foundation, either version 3 of the License, or +%%% (at your option) any later version. +%%% +%%% PropEr is distributed in the hope that it will be useful, +%%% but WITHOUT ANY WARRANTY; without even the implied warranty of +%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +%%% GNU General Public License for more details. +%%% +%%% You should have received a copy of the GNU General Public License +%%% along with PropEr. If not, see <http://www.gnu.org/licenses/>. + +%%% @copyright 2010-2013 Manolis Papadakis, Eirini Arvaniti and Kostis Sagonas +%%% @version {@version} +%%% @author Manolis Papadakis +%%% @doc Internal header file: This header is included in all PropEr source +%%% files. + +-include("proper_common.hrl"). + + +%%------------------------------------------------------------------------------ +%% Activate strip_types parse transform +%%------------------------------------------------------------------------------ + +-ifdef(NO_TYPES). +-compile({parse_transform, strip_types}). +-endif. + +%%------------------------------------------------------------------------------ +%% Random generator selection +%%------------------------------------------------------------------------------ + +-ifdef(USE_SFMT). +-define(RANDOM_MOD, sfmt). +-define(SEED_NAME, sfmt_seed). +-else. +-define(RANDOM_MOD, random). +-define(SEED_NAME, random_seed). +-endif. + +%%------------------------------------------------------------------------------ +%% Macros +%%------------------------------------------------------------------------------ + +-define(PROPERTY_PREFIX, "prop_"). + + +%%------------------------------------------------------------------------------ +%% Constants +%%------------------------------------------------------------------------------ + +-define(SEED_RANGE, 4294967296). +-define(MAX_ARITY, 20). +-define(MAX_TRIES_FACTOR, 5). +-define(ANY_SIMPLE_PROB, 3). +-define(ANY_BINARY_PROB, 1). +-define(ANY_EXPAND_PROB, 8). +-define(SMALL_RANGE_THRESHOLD, 16#FFFF). + + +%%------------------------------------------------------------------------------ +%% Common type aliases +%%------------------------------------------------------------------------------ + +%% TODO: Perhaps these should be moved inside modules. +-type mod_name() :: atom(). +-type fun_name() :: atom(). +-type size() :: non_neg_integer(). +-type length() :: non_neg_integer(). +-type position() :: pos_integer(). +-type frequency() :: pos_integer(). +-type seed() :: {non_neg_integer(), non_neg_integer(), non_neg_integer()}. + +-type abs_form() :: erl_parse:abstract_form(). +-type abs_expr() :: erl_parse:abstract_expr(). +-type abs_clause() :: erl_parse:abstract_clause(). + +%% TODO: Replace these with the appropriate types from stdlib. +-type abs_type() :: term(). +-type abs_rec_field() :: term(). + +-type loose_tuple(T) :: {} | {T} | {T,T} | {T,T,T} | {T,T,T,T} | {T,T,T,T,T} + | {T,T,T,T,T,T} | {T,T,T,T,T,T,T} | {T,T,T,T,T,T,T,T} + | {T,T,T,T,T,T,T,T,T} | {T,T,T,T,T,T,T,T,T,T} | tuple(). diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/proper/proper_types.erl b/lib/dialyzer/test/opaque_SUITE_data/src/proper/proper_types.erl new file mode 100644 index 0000000000..fe83a0ba11 --- /dev/null +++ b/lib/dialyzer/test/opaque_SUITE_data/src/proper/proper_types.erl @@ -0,0 +1,1349 @@ +%%% Copyright 2010-2013 Manolis Papadakis <[email protected]>, +%%% Eirini Arvaniti <[email protected]> +%%% and Kostis Sagonas <[email protected]> +%%% +%%% This file is part of PropEr. +%%% +%%% PropEr is free software: you can redistribute it and/or modify +%%% it under the terms of the GNU General Public License as published by +%%% the Free Software Foundation, either version 3 of the License, or +%%% (at your option) any later version. +%%% +%%% PropEr is distributed in the hope that it will be useful, +%%% but WITHOUT ANY WARRANTY; without even the implied warranty of +%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +%%% GNU General Public License for more details. +%%% +%%% You should have received a copy of the GNU General Public License +%%% along with PropEr. If not, see <http://www.gnu.org/licenses/>. + +%%% @copyright 2010-2013 Manolis Papadakis, Eirini Arvaniti and Kostis Sagonas +%%% @version {@version} +%%% @author Manolis Papadakis + +%%% @doc Type manipulation functions and predefined types. +%%% +%%% == Basic types == +%%% This module defines all the basic types of the PropEr type system as +%%% functions. See the <a href="#index">function index</a> for an overview. +%%% +%%% Types can be combined in tuples or lists to produce other types. Exact +%%% values (such as exact numbers, atoms, binaries and strings) can be combined +%%% with types inside such structures, like in this example of the type of a +%%% tagged tuple: ``{'result', integer()}''. +%%% +%%% When including the PropEr header file, all +%%% <a href="#index">API functions</a> of this module are automatically +%%% imported, unless `PROPER_NO_IMPORTS' is defined. +%%% +%%% == Customized types == +%%% The following operators can be applied to basic types in order to produce +%%% new ones: +%%% +%%% <dl> +%%% <dt>`?LET(<Xs>, <Xs_type>, <In>)'</dt> +%%% <dd>To produce an instance of this type, all appearances of the variables +%%% in `<Xs>' are replaced inside `<In>' by their corresponding values in a +%%% randomly generated instance of `<Xs_type>'. It's OK for the `<In>' part to +%%% evaluate to a type - in that case, an instance of the inner type is +%%% generated recursively.</dd> +%%% <dt>`?SUCHTHAT(<X>, <Type>, <Condition>)'</dt> +%%% <dd>This produces a specialization of `<Type>', which only includes those +%%% members of `<Type>' that satisfy the constraint `<Condition>' - that is, +%%% those members for which the function `fun(<X>) -> <Condition> end' returns +%%% `true'. If the constraint is very strict - that is, only a small +%%% percentage of instances of `<Type>' pass the test - it will take a lot of +%%% tries for the instance generation subsystem to randomly produce a valid +%%% instance. This will result in slower testing, and testing may even be +%%% stopped short, in case the `constraint_tries' limit is reached (see the +%%% "Options" section in the documentation of the {@link proper} module). If +%%% this is the case, it would be more appropriate to generate valid instances +%%% of the specialized type using the `?LET' macro. Also make sure that even +%%% small instances can satisfy the constraint, since PropEr will only try +%%% small instances at the start of testing. If this is not possible, you can +%%% instruct PropEr to start at a larger size, by supplying a suitable value +%%% for the `start_size' option (see the "Options" section in the +%%% documentation of the {@link proper} module).</dd> +%%% <dt>`?SUCHTHATMAYBE(<X>, <Type>, <Condition>)'</dt> +%%% <dd>Equivalent to the `?SUCHTHAT' macro, but the constraint `<Condition>' +%%% is considered non-strict: if the `constraint_tries' limit is reached, the +%%% generator will just return an instance of `<Type>' instead of failing, +%%% even if that instance doesn't satisfy the constraint.</dd> +%%% <dt>`?SHRINK(<Generator>, <List_of_alt_gens>)'</dt> +%%% <dd>This creates a type whose instances are generated by evaluating the +%%% statement block `<Generator>' (this may evaluate to a type, which will +%%% then be generated recursively). If an instance of such a type is to be +%%% shrunk, the generators in `<List_of_alt_gens>' are first run to produce +%%% hopefully simpler instances of the type. Thus, the generators in the +%%% second argument should be simpler than the default. The simplest ones +%%% should be at the front of the list, since those are the generators +%%% preferred by the shrinking subsystem. Like the main `<Generator>', the +%%% alternatives may also evaluate to a type, which is generated recursively. +%%% </dd> +%%% <dt>`?LETSHRINK(<List_of_variables>, <List_of_types>, <Generator>)'</dt> +%%% <dd>This is created by combining a `?LET' and a `?SHRINK' macro. Instances +%%% are generated by applying a randomly generated list of values inside +%%% `<Generator>' (just like a `?LET', with the added constraint that the +%%% variables and types must be provided in a list - alternatively, +%%% `<List_of_types>' may be a list or vector type). When shrinking instances +%%% of such a type, the sub-instances that were combined to produce it are +%%% first tried in place of the failing instance.</dd> +%%% <dt>`?LAZY(<Generator>)'</dt> +%%% <dd>This construct returns a type whose only purpose is to delay the +%%% evaluation of `<Generator>' (`<Generator>' can return a type, which will +%%% be generated recursively). Using this, you can simulate the lazy +%%% generation of instances: +%%% ``` stream() -> ?LAZY(frequency([ {1,[]}, {3,[0|stream()]} ])). ''' +%%% The above type produces lists of zeroes with an average length of 3. Note +%%% that, had we not enclosed the generator with a `?LAZY' macro, the +%%% evaluation would continue indefinitely, due to the eager evaluation of +%%% the Erlang language.</dd> +%%% <dt>`non_empty(<List_or_binary_type>)'</dt> +%%% <dd>See the documentation for {@link non_empty/1}.</dd> +%%% <dt>`noshrink(<Type>)'</dt> +%%% <dd>See the documentation for {@link noshrink/1}.</dd> +%%% <dt>`default(<Default_value>, <Type>)'</dt> +%%% <dd>See the documentation for {@link default/2}.</dd> +%%% <dt>`with_parameter(<Parameter>, <Value>, <Type>)'</dt> +%%% <dd>See the documentation for {@link with_parameter/3}.</dd> +%%% <dt>`with_parameters(<Param_value_pairs>, <Type>)'</dt> +%%% <dd>See the documentation for {@link with_parameters/2}.</dd> +%%% </dl> +%%% +%%% == Size manipulation == +%%% The following operators are related to the `size' parameter, which controls +%%% the maximum size of produced instances. The actual size of a produced +%%% instance is chosen randomly, but can never exceed the value of the `size' +%%% parameter at the moment of generation. A more accurate definition is the +%%% following: the maximum instance of `size S' can never be smaller than the +%%% maximum instance of `size S-1'. The actual size of an instance is measured +%%% differently for each type: the actual size of a list is its length, while +%%% the actual size of a tree may be the number of its internal nodes. Some +%%% types, e.g. unions, have no notion of size, thus their generation is not +%%% influenced by the value of `size'. The `size' parameter starts at 1 and +%%% grows automatically during testing. +%%% +%%% <dl> +%%% <dt>`?SIZED(<S>, <Generator>)'</dt> +%%% <dd>Creates a new type, whose instances are produced by replacing all +%%% appearances of the `<S>' parameter inside the statement block +%%% `<Generator>' with the value of the `size' parameter. It's OK for the +%%% `<Generator>' to return a type - in that case, an instance of the inner +%%% type is generated recursively.</dd> +%%% <dt>`resize(<New_size>, <Type>)'</dt> +%%% <dd>See the documentation for {@link resize/2}.</dd> +%%% </dl> + +-module(proper_types). +-export([is_inst/2, is_inst/3]). + +-export([integer/2, float/2, atom/0, binary/0, binary/1, bitstring/0, + bitstring/1, list/1, vector/2, union/1, weighted_union/1, tuple/1, + loose_tuple/1, exactly/1, fixed_list/1, function/2, any/0, + shrink_list/1, safe_union/1, safe_weighted_union/1]). +-export([integer/0, non_neg_integer/0, pos_integer/0, neg_integer/0, range/2, + float/0, non_neg_float/0, number/0, boolean/0, byte/0, char/0, + list/0, tuple/0, string/0, wunion/1, term/0, timeout/0, arity/0]). +-export([int/0, nat/0, largeint/0, real/0, bool/0, choose/2, elements/1, + oneof/1, frequency/1, return/1, default/2, orderedlist/1, function0/1, + function1/1, function2/1, function3/1, function4/1, + weighted_default/2]). +-export([resize/2, non_empty/1, noshrink/1]). + +-export([cook_outer/1, is_type/1, equal_types/2, is_raw_type/1, to_binary/1, + from_binary/1, get_prop/2, find_prop/2, safe_is_instance/2, + is_instance/2, unwrap/1, weakly/1, strongly/1, satisfies_all/2, + new_type/2, subtype/2]). +-export([lazy/1, sized/1, bind/3, shrinkwith/2, add_constraint/3, + native_type/2, distlist/3, with_parameter/3, with_parameters/2, + parameter/1, parameter/2]). +-export([le/2]). + +-export_type([type/0, raw_type/0, extint/0, extnum/0]). + +-include("proper_internal.hrl"). + + +%%------------------------------------------------------------------------------ +%% Comparison with erl_types +%%------------------------------------------------------------------------------ + +%% Missing types +%% ------------------- +%% will do: +%% records, maybe_improper_list(T,S), nonempty_improper_list(T,S) +%% maybe_improper_list(), maybe_improper_list(T), iolist, iodata +%% don't need: +%% nonempty_{list,string,maybe_improper_list} +%% won't do: +%% pid, port, ref, identifier, none, no_return, module, mfa, node +%% array, dict, digraph, set, gb_tree, gb_set, queue, tid + +%% Missing type information +%% ------------------------ +%% bin types: +%% other unit sizes? what about size info? +%% functions: +%% generally some fun, unspecified number of arguments but specified +%% return type +%% any: +%% doesn't cover functions and improper lists + + +%%------------------------------------------------------------------------------ +%% Type declaration macros +%%------------------------------------------------------------------------------ + +-define(BASIC(PropList), new_type(PropList,basic)). +-define(WRAPPER(PropList), new_type(PropList,wrapper)). +-define(CONSTRUCTED(PropList), new_type(PropList,constructed)). +-define(CONTAINER(PropList), new_type(PropList,container)). +-define(SUBTYPE(Type,PropList), subtype(PropList,Type)). + + +%%------------------------------------------------------------------------------ +%% Types +%%------------------------------------------------------------------------------ + +-type type_kind() :: 'basic' | 'wrapper' | 'constructed' | 'container' | atom(). +-type instance_test() :: fun((proper_gen:imm_instance()) -> boolean()) + | {'typed', + fun((proper_types:type(), + proper_gen:imm_instance()) -> boolean())}. +-type index() :: pos_integer(). +%% @alias +-type value() :: term(). +%% @private_type +%% @alias +-type extint() :: integer() | 'inf'. +%% @private_type +%% @alias +-type extnum() :: number() | 'inf'. +-type constraint_fun() :: fun((proper_gen:instance()) -> boolean()). + +-opaque type() :: {'$type', [type_prop()]}. +%% A type of the PropEr type system +%% @type raw_type(). You can consider this as an equivalent of {@type type()}. +-type raw_type() :: type() | [raw_type()] | loose_tuple(raw_type()) | term(). +-type type_prop_name() :: 'kind' | 'generator' | 'reverse_gen' | 'parts_type' + | 'combine' | 'alt_gens' | 'shrink_to_parts' + | 'size_transform' | 'is_instance' | 'shrinkers' + | 'noshrink' | 'internal_type' | 'internal_types' + | 'get_length' | 'split' | 'join' | 'get_indices' + | 'remove' | 'retrieve' | 'update' | 'constraints' + | 'parameters' | 'env' | 'subenv'. + +-type type_prop_value() :: term(). +-type type_prop() :: + {'kind', type_kind()} + | {'generator', proper_gen:generator()} + | {'reverse_gen', proper_gen:reverse_gen()} + | {'parts_type', type()} + | {'combine', proper_gen:combine_fun()} + | {'alt_gens', proper_gen:alt_gens()} + | {'shrink_to_parts', boolean()} + | {'size_transform', fun((size()) -> size())} + | {'is_instance', instance_test()} + | {'shrinkers', [proper_shrink:shrinker()]} + | {'noshrink', boolean()} + | {'internal_type', raw_type()} + | {'internal_types', tuple() | maybe_improper_list(type(),type() | [])} + %% The items returned by 'remove' must be of this type. + | {'get_length', fun((proper_gen:imm_instance()) -> length())} + %% If this is a container type, this should return the number of elements + %% it contains. + | {'split', fun((proper_gen:imm_instance()) -> [proper_gen:imm_instance()]) + | fun((length(),proper_gen:imm_instance()) -> + {proper_gen:imm_instance(),proper_gen:imm_instance()})} + %% If present, the appropriate form depends on whether get_length is + %% defined: if get_length is undefined, this must be in the one-argument + %% form (e.g. a tree should be split into its subtrees), else it must be + %% in the two-argument form (e.g. a list should be split in two at the + %% index provided). + | {'join', fun((proper_gen:imm_instance(),proper_gen:imm_instance()) -> + proper_gen:imm_instance())} + | {'get_indices', fun((proper_types:type(), + proper_gen:imm_instance()) -> [index()])} + %% If this is a container type, this should return a list of indices we + %% can use to remove or insert elements from the given instance. + | {'remove', fun((index(),proper_gen:imm_instance()) -> + proper_gen:imm_instance())} + | {'retrieve', fun((index(), proper_gen:imm_instance() | tuple() + | maybe_improper_list(type(),type() | [])) -> + value() | type())} + | {'update', fun((index(),value(),proper_gen:imm_instance()) -> + proper_gen:imm_instance())} + | {'constraints', [{constraint_fun(), boolean()}]} + %% A list of constraints on instances of this type: each constraint is a + %% tuple of a fun that must return 'true' for each valid instance and a + %% boolean field that specifies whether the condition is strict. + | {'parameters', [{atom(),value()}]} + | {'env', term()} + | {'subenv', term()}. + + +%%------------------------------------------------------------------------------ +%% Type manipulation functions +%%------------------------------------------------------------------------------ + +%% TODO: We shouldn't need the fully qualified type name in the range of these +%% functions. + +%% @private +%% TODO: just cook/1 ? +-spec cook_outer(raw_type()) -> proper_types:type(). +cook_outer(Type = {'$type',_Props}) -> + Type; +cook_outer(RawType) -> + if + is_tuple(RawType) -> tuple(tuple_to_list(RawType)); + %% CAUTION: this must handle improper lists + is_list(RawType) -> fixed_list(RawType); + %% default case (covers integers, floats, atoms, binaries, ...): + true -> exactly(RawType) + end. + +%% @private +-spec is_type(term()) -> boolean(). +is_type({'$type',_Props}) -> + true; +is_type(_) -> + false. + +%% @private +-spec equal_types(proper_types:type(), proper_types:type()) -> boolean(). +equal_types(SameType, SameType) -> + true; +equal_types(_, _) -> + false. + +%% @private +-spec is_raw_type(term()) -> boolean(). +is_raw_type({'$type',_TypeProps}) -> + true; +is_raw_type(X) -> + if + is_tuple(X) -> is_raw_type_list(tuple_to_list(X)); + is_list(X) -> is_raw_type_list(X); + true -> false + end. + +-spec is_raw_type_list(maybe_improper_list()) -> boolean(). +%% CAUTION: this must handle improper lists +is_raw_type_list(List) -> + proper_arith:safe_any(fun is_raw_type/1, List). + +%% @private +-spec to_binary(proper_types:type()) -> binary(). +to_binary(Type) -> + term_to_binary(Type). + +%% @private +%% TODO: restore: -spec from_binary(binary()) -> proper_types:type(). +from_binary(Binary) -> + binary_to_term(Binary). + +-spec type_from_list([type_prop()]) -> proper_types:type(). +type_from_list(KeyValueList) -> + {'$type',KeyValueList}. + +-spec add_prop(type_prop_name(), type_prop_value(), proper_types:type()) -> + proper_types:type(). +add_prop(PropName, Value, {'$type',Props}) -> + {'$type',lists:keystore(PropName, 1, Props, {PropName, Value})}. + +-spec add_props([type_prop()], proper_types:type()) -> proper_types:type(). +add_props(PropList, {'$type',OldProps}) -> + {'$type', lists:foldl(fun({N,_}=NV,Acc) -> + lists:keystore(N, 1, Acc, NV) + end, OldProps, PropList)}. + +-spec append_to_prop(type_prop_name(), type_prop_value(), + proper_types:type()) -> proper_types:type(). +append_to_prop(PropName, Value, {'$type',Props}) -> + Val = case lists:keyfind(PropName, 1, Props) of + {PropName, V} -> + V; + _ -> + [] + end, + {'$type', lists:keystore(PropName, 1, Props, + {PropName, lists:reverse([Value|Val])})}. + +-spec append_list_to_prop(type_prop_name(), [type_prop_value()], + proper_types:type()) -> proper_types:type(). +append_list_to_prop(PropName, List, {'$type',Props}) -> + {PropName, Val} = lists:keyfind(PropName, 1, Props), + {'$type', lists:keystore(PropName, 1, Props, {PropName, Val++List})}. + +%% @private +-spec get_prop(type_prop_name(), proper_types:type()) -> type_prop_value(). +get_prop(PropName, {'$type',Props}) -> + {_PropName, Val} = lists:keyfind(PropName, 1, Props), + Val. + +%% @private +-spec find_prop(type_prop_name(), proper_types:type()) -> + {'ok',type_prop_value()} | 'error'. +find_prop(PropName, {'$type',Props}) -> + case lists:keyfind(PropName, 1, Props) of + {PropName, Value} -> + {ok, Value}; + _ -> + error + end. + +%% @private +-spec new_type([type_prop()], type_kind()) -> proper_types:type(). +new_type(PropList, Kind) -> + Type = type_from_list(PropList), + add_prop(kind, Kind, Type). + +%% @private +-spec subtype([type_prop()], proper_types:type()) -> proper_types:type(). +%% TODO: should the 'is_instance' function etc. be reset for subtypes? +subtype(PropList, Type) -> + add_props(PropList, Type). + +%% @private +-spec is_inst(proper_gen:instance(), raw_type()) -> + boolean() | {'error',{'typeserver',term()}}. +is_inst(Instance, RawType) -> + is_inst(Instance, RawType, 10). + +%% @private +-spec is_inst(proper_gen:instance(), raw_type(), size()) -> + boolean() | {'error',{'typeserver',term()}}. +is_inst(Instance, RawType, Size) -> + proper:global_state_init_size(Size), + Result = safe_is_instance(Instance, RawType), + proper:global_state_erase(), + Result. + +%% @private +-spec safe_is_instance(proper_gen:imm_instance(), raw_type()) -> + boolean() | {'error',{'typeserver',term()}}. +safe_is_instance(ImmInstance, RawType) -> + try is_instance(ImmInstance, RawType) catch + throw:{'$typeserver',SubReason} -> {error, {typeserver,SubReason}} + end. + +%% @private +-spec is_instance(proper_gen:imm_instance(), raw_type()) -> boolean(). +%% TODO: If the second argument is not a type, let it pass (don't even check for +%% term equality?) - if it's a raw type, don't cook it, instead recurse +%% into it. +is_instance(ImmInstance, RawType) -> + CleanInstance = proper_gen:clean_instance(ImmInstance), + Type = cook_outer(RawType), + (case get_prop(kind, Type) of + wrapper -> wrapper_test(ImmInstance, Type); + constructed -> constructed_test(ImmInstance, Type); + _ -> false + end + orelse + case find_prop(is_instance, Type) of + {ok,{typed, IsInstance}} -> IsInstance(Type, ImmInstance); + {ok,IsInstance} -> IsInstance(ImmInstance); + error -> false + end) + andalso weakly(satisfies_all(CleanInstance, Type)). + +-spec wrapper_test(proper_gen:imm_instance(), proper_types:type()) -> boolean(). +wrapper_test(ImmInstance, Type) -> + %% TODO: check if it's actually a raw type that's returned? + lists:any(fun(T) -> is_instance(ImmInstance, T) end, unwrap(Type)). + +%% @private +%% TODO: restore:-spec unwrap(proper_types:type()) -> [proper_types:type(),...]. +%% TODO: check if it's actually a raw type that's returned? +unwrap(Type) -> + RawInnerTypes = proper_gen:alt_gens(Type) ++ [proper_gen:normal_gen(Type)], + [cook_outer(T) || T <- RawInnerTypes]. + +-spec constructed_test(proper_gen:imm_instance(), proper_types:type()) -> + boolean(). +constructed_test({'$used',ImmParts,ImmInstance}, Type) -> + PartsType = get_prop(parts_type, Type), + Combine = get_prop(combine, Type), + is_instance(ImmParts, PartsType) andalso + begin + %% TODO: check if it's actually a raw type that's returned? + %% TODO: move construction code to proper_gen + %% TODO: non-type => should we check for strict term equality? + RawInnerType = Combine(proper_gen:clean_instance(ImmParts)), + is_instance(ImmInstance, RawInnerType) + end; +constructed_test({'$to_part',ImmInstance}, Type) -> + PartsType = get_prop(parts_type, Type), + get_prop(shrink_to_parts, Type) =:= true andalso + %% TODO: we reject non-container types + get_prop(kind, PartsType) =:= container andalso + case {find_prop(internal_type,PartsType), + find_prop(internal_types,PartsType)} of + {{ok,EachPartType},error} -> + %% The parts are in a list or a vector. + is_instance(ImmInstance, EachPartType); + {error,{ok,PartTypesList}} -> + %% The parts are in a fixed list. + %% TODO: It should always be a proper list. + lists:any(fun(T) -> is_instance(ImmInstance,T) end, PartTypesList) + end; +constructed_test(_CleanInstance, _Type) -> + %% TODO: can we do anything better? + false. + +%% @private +-spec weakly({boolean(),boolean()}) -> boolean(). +weakly({B1,_B2}) -> B1. + +%% @private +-spec strongly({boolean(),boolean()}) -> boolean(). +strongly({_B1,B2}) -> B2. + +-spec satisfies(proper_gen:instance(), {constraint_fun(),boolean()}) + -> {boolean(),boolean()}. +satisfies(Instance, {Test,false}) -> + {true,Test(Instance)}; +satisfies(Instance, {Test,true}) -> + Result = Test(Instance), + {Result,Result}. + +%% @private +-spec satisfies_all(proper_gen:instance(), proper_types:type()) -> + {boolean(),boolean()}. +satisfies_all(Instance, Type) -> + case find_prop(constraints, Type) of + {ok, Constraints} -> + L = [satisfies(Instance, C) || C <- Constraints], + {L1,L2} = lists:unzip(L), + {lists:all(fun(B) -> B end, L1), lists:all(fun(B) -> B end, L2)}; + error -> + {true,true} + end. + + +%%------------------------------------------------------------------------------ +%% Type definition functions +%%------------------------------------------------------------------------------ + +%% @private +-spec lazy(proper_gen:nosize_generator()) -> proper_types:type(). +lazy(Gen) -> + ?WRAPPER([ + {generator, Gen} + ]). + +%% @private +-spec sized(proper_gen:sized_generator()) -> proper_types:type(). +sized(Gen) -> + ?WRAPPER([ + {generator, Gen} + ]). + +%% @private +-spec bind(raw_type(), proper_gen:combine_fun(), boolean()) -> + proper_types:type(). +bind(RawPartsType, Combine, ShrinkToParts) -> + PartsType = cook_outer(RawPartsType), + ?CONSTRUCTED([ + {parts_type, PartsType}, + {combine, Combine}, + {shrink_to_parts, ShrinkToParts} + ]). + +%% @private +-spec shrinkwith(proper_gen:nosize_generator(), proper_gen:alt_gens()) -> + proper_types:type(). +shrinkwith(Gen, DelaydAltGens) -> + ?WRAPPER([ + {generator, Gen}, + {alt_gens, DelaydAltGens} + ]). + +%% @private +-spec add_constraint(raw_type(), constraint_fun(), boolean()) -> + proper_types:type(). +add_constraint(RawType, Condition, IsStrict) -> + Type = cook_outer(RawType), + append_to_prop(constraints, {Condition,IsStrict}, Type). + +%% @private +-spec native_type(mod_name(), string()) -> proper_types:type(). +native_type(Mod, TypeStr) -> + ?WRAPPER([ + {generator, fun() -> proper_gen:native_type_gen(Mod,TypeStr) end} + ]). + + +%%------------------------------------------------------------------------------ +%% Basic types +%%------------------------------------------------------------------------------ + +%% @doc All integers between `Low' and `High', bounds included. +%% `Low' and `High' must be Erlang expressions that evaluate to integers, with +%% `Low =< High'. Additionally, `Low' and `High' may have the value `inf', in +%% which case they represent minus infinity and plus infinity respectively. +%% Instances shrink towards 0 if `Low =< 0 =< High', or towards the bound with +%% the smallest absolute value otherwise. +-spec integer(extint(), extint()) -> proper_types:type(). +integer(Low, High) -> + ?BASIC([ + {env, {Low, High}}, + {generator, {typed, fun integer_gen/2}}, + {is_instance, {typed, fun integer_is_instance/2}}, + {shrinkers, [fun number_shrinker/3]} + ]). + +integer_gen(Type, Size) -> + {Low, High} = get_prop(env, Type), + proper_gen:integer_gen(Size, Low, High). + +integer_is_instance(Type, X) -> + {Low, High} = get_prop(env, Type), + is_integer(X) andalso le(Low, X) andalso le(X, High). + +number_shrinker(X, Type, S) -> + {Low, High} = get_prop(env, Type), + proper_shrink:number_shrinker(X, Low, High, S). + +%% @doc All floats between `Low' and `High', bounds included. +%% `Low' and `High' must be Erlang expressions that evaluate to floats, with +%% `Low =< High'. Additionally, `Low' and `High' may have the value `inf', in +%% which case they represent minus infinity and plus infinity respectively. +%% Instances shrink towards 0.0 if `Low =< 0.0 =< High', or towards the bound +%% with the smallest absolute value otherwise. +-spec float(extnum(), extnum()) -> proper_types:type(). +float(Low, High) -> + ?BASIC([ + {env, {Low, High}}, + {generator, {typed, fun float_gen/2}}, + {is_instance, {typed, fun float_is_instance/2}}, + {shrinkers, [fun number_shrinker/3]} + ]). + +float_gen(Type, Size) -> + {Low, High} = get_prop(env, Type), + proper_gen:float_gen(Size, Low, High). + +float_is_instance(Type, X) -> + {Low, High} = get_prop(env, Type), + is_float(X) andalso le(Low, X) andalso le(X, High). + +%% @private +-spec le(extnum(), extnum()) -> boolean(). +le(inf, _B) -> true; +le(_A, inf) -> true; +le(A, B) -> A =< B. + +%% @doc All atoms. All atoms used internally by PropEr start with a '`$'', so +%% such atoms will never be produced as instances of this type. You should also +%% refrain from using such atoms in your code, to avoid a potential clash. +%% Instances shrink towards the empty atom, ''. +-spec atom() -> proper_types:type(). +atom() -> + ?WRAPPER([ + {generator, fun proper_gen:atom_gen/1}, + {reverse_gen, fun proper_gen:atom_rev/1}, + {size_transform, fun(Size) -> erlang:min(Size,255) end}, + {is_instance, fun atom_is_instance/1} + ]). + +atom_is_instance(X) -> + is_atom(X) + %% We return false for atoms starting with '$', since these are + %% atoms used internally and never produced by the atom generator. + andalso (X =:= '' orelse hd(atom_to_list(X)) =/= $$). + +%% @doc All binaries. Instances shrink towards the empty binary, `<<>>'. +-spec binary() -> proper_types:type(). +binary() -> + ?WRAPPER([ + {generator, fun proper_gen:binary_gen/1}, + {reverse_gen, fun proper_gen:binary_rev/1}, + {is_instance, fun erlang:is_binary/1} + ]). + +%% @doc All binaries with a byte size of `Len'. +%% `Len' must be an Erlang expression that evaluates to a non-negative integer. +%% Instances shrink towards binaries of zeroes. +-spec binary(length()) -> proper_types:type(). +binary(Len) -> + ?WRAPPER([ + {env, Len}, + {generator, {typed, fun binary_len_gen/1}}, + {reverse_gen, fun proper_gen:binary_rev/1}, + {is_instance, {typed, fun binary_len_is_instance/2}} + ]). + +binary_len_gen(Type) -> + Len = get_prop(env, Type), + proper_gen:binary_len_gen(Len). + +binary_len_is_instance(Type, X) -> + Len = get_prop(env, Type), + is_binary(X) andalso byte_size(X) =:= Len. + +%% @doc All bitstrings. Instances shrink towards the empty bitstring, `<<>>'. +-spec bitstring() -> proper_types:type(). +bitstring() -> + ?WRAPPER([ + {generator, fun proper_gen:bitstring_gen/1}, + {reverse_gen, fun proper_gen:bitstring_rev/1}, + {is_instance, fun erlang:is_bitstring/1} + ]). + +%% @doc All bitstrings with a bit size of `Len'. +%% `Len' must be an Erlang expression that evaluates to a non-negative integer. +%% Instances shrink towards bitstrings of zeroes +-spec bitstring(length()) -> proper_types:type(). +bitstring(Len) -> + ?WRAPPER([ + {env, Len}, + {generator, {typed, fun bitstring_len_gen/1}}, + {reverse_gen, fun proper_gen:bitstring_rev/1}, + {is_instance, {typed, fun bitstring_len_is_instance/2}} + ]). + +bitstring_len_gen(Type) -> + Len = get_prop(env, Type), + proper_gen:bitstring_len_gen(Len). + +bitstring_len_is_instance(Type, X) -> + Len = get_prop(env, Type), + is_bitstring(X) andalso bit_size(X) =:= Len. + +%% @doc All lists containing elements of type `ElemType'. +%% Instances shrink towards the empty list, `[]'. +-spec list(ElemType::raw_type()) -> proper_types:type(). +% TODO: subtyping would be useful here (list, vector, fixed_list) +list(RawElemType) -> + ElemType = cook_outer(RawElemType), + ?CONTAINER([ + {generator, {typed, fun list_gen/2}}, + {is_instance, {typed, fun list_is_instance/2}}, + {internal_type, ElemType}, + {get_length, fun erlang:length/1}, + {split, fun lists:split/2}, + {join, fun lists:append/2}, + {get_indices, fun list_get_indices/2}, + {remove, fun proper_arith:list_remove/2}, + {retrieve, fun lists:nth/2}, + {update, fun proper_arith:list_update/3} + ]). + +list_gen(Type, Size) -> + ElemType = get_prop(internal_type, Type), + proper_gen:list_gen(Size, ElemType). + +list_is_instance(Type, X) -> + ElemType = get_prop(internal_type, Type), + list_test(X, ElemType). + +%% @doc A type that generates exactly the list `List'. Instances shrink towards +%% shorter sublists of the original list. +-spec shrink_list([term()]) -> proper_types:type(). +shrink_list(List) -> + ?CONTAINER([ + {env, List}, + {generator, {typed, fun shrink_list_gen/1}}, + {is_instance, {typed, fun shrink_list_is_instance/2}}, + {get_length, fun erlang:length/1}, + {split, fun lists:split/2}, + {join, fun lists:append/2}, + {get_indices, fun list_get_indices/2}, + {remove, fun proper_arith:list_remove/2} + ]). + +shrink_list_gen(Type) -> + get_prop(env, Type). + +shrink_list_is_instance(Type, X) -> + List = get_prop(env, Type), + is_sublist(X, List). + +-spec is_sublist([term()], [term()]) -> boolean(). +is_sublist([], _) -> true; +is_sublist(_, []) -> false; +is_sublist([H|T1], [H|T2]) -> is_sublist(T1, T2); +is_sublist(Slice, [_|T2]) -> is_sublist(Slice, T2). + +-spec list_test(proper_gen:imm_instance(), proper_types:type()) -> boolean(). +list_test(X, ElemType) -> + is_list(X) andalso lists:all(fun(E) -> is_instance(E, ElemType) end, X). + +%% @private +-spec list_get_indices(proper_gen:generator(), list()) -> [position()]. +list_get_indices(_, List) -> + lists:seq(1, length(List)). + +%% @private +%% This assumes that: +%% - instances of size S are always valid instances of size >S +%% - any recursive calls inside Gen are lazy +-spec distlist(size(), proper_gen:sized_generator(), boolean()) -> + proper_types:type(). +distlist(Size, Gen, NonEmpty) -> + ParentType = case NonEmpty of + true -> non_empty(list(Gen(Size))); + false -> list(Gen(Size)) + end, + ?SUBTYPE(ParentType, [ + {subenv, {Size, Gen, NonEmpty}}, + {generator, {typed, fun distlist_gen/1}} + ]). + +distlist_gen(Type) -> + {Size, Gen, NonEmpty} = get_prop(subenv, Type), + proper_gen:distlist_gen(Size, Gen, NonEmpty). + +%% @doc All lists of length `Len' containing elements of type `ElemType'. +%% `Len' must be an Erlang expression that evaluates to a non-negative integer. +-spec vector(length(), ElemType::raw_type()) -> proper_types:type(). +vector(Len, RawElemType) -> + ElemType = cook_outer(RawElemType), + ?CONTAINER([ + {env, Len}, + {generator, {typed, fun vector_gen/1}}, + {is_instance, {typed, fun vector_is_instance/2}}, + {internal_type, ElemType}, + {get_indices, fun vector_get_indices/2}, + {retrieve, fun lists:nth/2}, + {update, fun proper_arith:list_update/3} + ]). + +vector_gen(Type) -> + Len = get_prop(env, Type), + ElemType = get_prop(internal_type, Type), + proper_gen:vector_gen(Len, ElemType). + +vector_is_instance(Type, X) -> + Len = get_prop(env, Type), + ElemType = get_prop(internal_type, Type), + is_list(X) + andalso length(X) =:= Len + andalso lists:all(fun(E) -> is_instance(E, ElemType) end, X). + +vector_get_indices(Type, _X) -> + lists:seq(1, get_prop(env, Type)). + +%% @doc The union of all types in `ListOfTypes'. `ListOfTypes' can't be empty. +%% The random instance generator is equally likely to choose any one of the +%% types in `ListOfTypes'. The shrinking subsystem will always try to shrink an +%% instance of a type union to an instance of the first type in `ListOfTypes', +%% thus you should write the simplest case first. +-spec union(ListOfTypes::[raw_type(),...]) -> proper_types:type(). +union(RawChoices) -> + Choices = [cook_outer(C) || C <- RawChoices], + ?BASIC([ + {env, Choices}, + {generator, {typed, fun union_gen/1}}, + {is_instance, {typed, fun union_is_instance/2}}, + {shrinkers, [fun union_shrinker_1/3, fun union_shrinker_2/3]} + ]). + +union_gen(Type) -> + Choices = get_prop(env,Type), + proper_gen:union_gen(Choices). + +union_is_instance(Type, X) -> + Choices = get_prop(env, Type), + lists:any(fun(C) -> is_instance(X, C) end, Choices). + +union_shrinker_1(X, Type, S) -> + Choices = get_prop(env, Type), + proper_shrink:union_first_choice_shrinker(X, Choices, S). + +union_shrinker_2(X, Type, S) -> + Choices = get_prop(env, Type), + proper_shrink:union_recursive_shrinker(X, Choices, S). + +%% @doc A specialization of {@link union/1}, where each type in `ListOfTypes' is +%% assigned a frequency. Frequencies must be Erlang expressions that evaluate to +%% positive integers. Types with larger frequencies are more likely to be chosen +%% by the random instance generator. The shrinking subsystem will ignore the +%% frequencies and try to shrink towards the first type in the list. +-spec weighted_union(ListOfTypes::[{frequency(),raw_type()},...]) -> + proper_types:type(). +weighted_union(RawFreqChoices) -> + CookFreqType = fun({Freq,RawType}) -> {Freq,cook_outer(RawType)} end, + FreqChoices = lists:map(CookFreqType, RawFreqChoices), + Choices = [T || {_F,T} <- FreqChoices], + ?SUBTYPE(union(Choices), [ + {subenv, FreqChoices}, + {generator, {typed, fun weighted_union_gen/1}} + ]). + +weighted_union_gen(Gen) -> + FreqChoices = get_prop(subenv, Gen), + proper_gen:weighted_union_gen(FreqChoices). + +%% @private +-spec safe_union([raw_type(),...]) -> proper_types:type(). +safe_union(RawChoices) -> + Choices = [cook_outer(C) || C <- RawChoices], + subtype( + [{subenv, Choices}, + {generator, {typed, fun safe_union_gen/1}}], + union(Choices)). + +safe_union_gen(Type) -> + Choices = get_prop(subenv, Type), + proper_gen:safe_union_gen(Choices). + +%% @private +-spec safe_weighted_union([{frequency(),raw_type()},...]) -> + proper_types:type(). +safe_weighted_union(RawFreqChoices) -> + CookFreqType = fun({Freq,RawType}) -> + {Freq,cook_outer(RawType)} end, + FreqChoices = lists:map(CookFreqType, RawFreqChoices), + Choices = [T || {_F,T} <- FreqChoices], + subtype([{subenv, FreqChoices}, + {generator, {typed, fun safe_weighted_union_gen/1}}], + union(Choices)). + +safe_weighted_union_gen(Type) -> + FreqChoices = get_prop(subenv, Type), + proper_gen:safe_weighted_union_gen(FreqChoices). + +%% @doc All tuples whose i-th element is an instance of the type at index i of +%% `ListOfTypes'. Also written simply as a tuple of types. +-spec tuple(ListOfTypes::[raw_type()]) -> proper_types:type(). +tuple(RawFields) -> + Fields = [cook_outer(F) || F <- RawFields], + ?CONTAINER([ + {env, Fields}, + {generator, {typed, fun tuple_gen/1}}, + {is_instance, {typed, fun tuple_is_instance/2}}, + {internal_types, list_to_tuple(Fields)}, + {get_indices, fun tuple_get_indices/2}, + {retrieve, fun erlang:element/2}, + {update, fun tuple_update/3} + ]). + +tuple_gen(Type) -> + Fields = get_prop(env, Type), + proper_gen:tuple_gen(Fields). + +tuple_is_instance(Type, X) -> + Fields = get_prop(env, Type), + is_tuple(X) andalso fixed_list_test(tuple_to_list(X), Fields). + +tuple_get_indices(Type, _X) -> + lists:seq(1, length(get_prop(env, Type))). + +-spec tuple_update(index(), value(), tuple()) -> tuple(). +tuple_update(Index, NewElem, Tuple) -> + setelement(Index, Tuple, NewElem). + +%% @doc Tuples whose elements are all of type `ElemType'. +%% Instances shrink towards the 0-size tuple, `{}'. +-spec loose_tuple(ElemType::raw_type()) -> proper_types:type(). +loose_tuple(RawElemType) -> + ElemType = cook_outer(RawElemType), + ?WRAPPER([ + {env, ElemType}, + {generator, {typed, fun loose_tuple_gen/2}}, + {reverse_gen, {typed, fun loose_tuple_rev/2}}, + {is_instance, {typed, fun loose_tuple_is_instance/2}} + ]). + +loose_tuple_gen(Type, Size) -> + ElemType = get_prop(env, Type), + proper_gen:loose_tuple_gen(Size, ElemType). + +loose_tuple_rev(Type, X) -> + ElemType = get_prop(env, Type), + proper_gen:loose_tuple_rev(X, ElemType). + +loose_tuple_is_instance(Type, X) -> + ElemType = get_prop(env, Type), + is_tuple(X) andalso list_test(tuple_to_list(X), ElemType). + +%% @doc Singleton type consisting only of `E'. `E' must be an evaluated term. +%% Also written simply as `E'. +-spec exactly(term()) -> proper_types:type(). +exactly(E) -> + ?BASIC([ + {env, E}, + {generator, {typed, fun exactly_gen/1}}, + {is_instance, {typed, fun exactly_is_instance/2}} + ]). + +exactly_gen(Type) -> + E = get_prop(env, Type), + proper_gen:exactly_gen(E). + +exactly_is_instance(Type, X) -> + E = get_prop(env, Type), + X =:= E. + +%% @doc All lists whose i-th element is an instance of the type at index i of +%% `ListOfTypes'. Also written simply as a list of types. +-spec fixed_list(ListOfTypes::maybe_improper_list(raw_type(),raw_type()|[])) -> + proper_types:type(). +fixed_list(MaybeImproperRawFields) -> + %% CAUTION: must handle improper lists + {Fields, Internal, Len, Retrieve, Update} = + case proper_arith:cut_improper_tail(MaybeImproperRawFields) of + % TODO: have cut_improper_tail return the length and use it in test? + {ProperRawHead, ImproperRawTail} -> + HeadLen = length(ProperRawHead), + CookedHead = [cook_outer(F) || F <- ProperRawHead], + CookedTail = cook_outer(ImproperRawTail), + {{CookedHead,CookedTail}, + CookedHead ++ CookedTail, + HeadLen + 1, + fun(I,L) -> improper_list_retrieve(I, L, HeadLen) end, + fun(I,V,L) -> improper_list_update(I, V, L, HeadLen) end}; + ProperRawFields -> + LocalFields = [cook_outer(F) || F <- ProperRawFields], + {LocalFields, + LocalFields, + length(ProperRawFields), + fun lists:nth/2, + fun proper_arith:list_update/3} + end, + ?CONTAINER([ + {env, {Fields, Len}}, + {generator, {typed, fun fixed_list_gen/1}}, + {is_instance, {typed, fun fixed_list_is_instance/2}}, + {internal_types, Internal}, + {get_indices, fun fixed_list_get_indices/2}, + {retrieve, Retrieve}, + {update, Update} + ]). + +fixed_list_gen(Type) -> + {Fields, _} = get_prop(env, Type), + proper_gen:fixed_list_gen(Fields). + +fixed_list_is_instance(Type, X) -> + {Fields, _} = get_prop(env, Type), + fixed_list_test(X, Fields). + +fixed_list_get_indices(Type, _X) -> + {_, Len} = get_prop(env, Type), + lists:seq(1, Len). + +-spec fixed_list_test(proper_gen:imm_instance(), + [proper_types:type()] | {[proper_types:type()], + proper_types:type()}) -> + boolean(). +fixed_list_test(X, {ProperHead,ImproperTail}) -> + is_list(X) andalso + begin + ProperHeadLen = length(ProperHead), + proper_arith:head_length(X) >= ProperHeadLen andalso + begin + {XHead,XTail} = lists:split(ProperHeadLen, X), + fixed_list_test(XHead, ProperHead) + andalso is_instance(XTail, ImproperTail) + end + end; +fixed_list_test(X, ProperFields) -> + is_list(X) + andalso length(X) =:= length(ProperFields) + andalso lists:all(fun({E,T}) -> is_instance(E, T) end, + lists:zip(X, ProperFields)). + +%% TODO: Move these 2 functions to proper_arith? +-spec improper_list_retrieve(index(), nonempty_improper_list(value(),value()), + pos_integer()) -> value(). +improper_list_retrieve(Index, List, HeadLen) -> + case Index =< HeadLen of + true -> lists:nth(Index, List); + false -> lists:nthtail(HeadLen, List) + end. + +-spec improper_list_update(index(), value(), + nonempty_improper_list(value(),value()), + pos_integer()) -> + nonempty_improper_list(value(),value()). +improper_list_update(Index, Value, List, HeadLen) -> + case Index =< HeadLen of + %% TODO: This happens to work, but is not implied by list_update's spec. + true -> proper_arith:list_update(Index, Value, List); + false -> lists:sublist(List, HeadLen) ++ Value + end. + +%% @doc All pure functions that map instances of `ArgTypes' to instances of +%% `RetType'. The syntax `function(Arity, RetType)' is also acceptable. +-spec function(ArgTypes::[raw_type()] | arity(), RetType::raw_type()) -> + proper_types:type(). +function(Arity, RawRetType) when is_integer(Arity), Arity >= 0, Arity =< 255 -> + RetType = cook_outer(RawRetType), + ?BASIC([ + {env, {Arity, RetType}}, + {generator, {typed, fun function_gen/1}}, + {is_instance, {typed, fun function_is_instance/2}} + ]); +function(RawArgTypes, RawRetType) -> + function(length(RawArgTypes), RawRetType). + +function_gen(Type) -> + {Arity, RetType} = get_prop(env, Type), + proper_gen:function_gen(Arity, RetType). + +function_is_instance(Type, X) -> + {Arity, RetType} = get_prop(env, Type), + is_function(X, Arity) + %% TODO: what if it's not a function we produced? + andalso equal_types(RetType, proper_gen:get_ret_type(X)). + +%% @doc All Erlang terms (that PropEr can produce). For reasons of efficiency, +%% functions are never produced as instances of this type.<br /> +%% CAUTION: Instances of this type are expensive to produce, shrink and instance- +%% check, both in terms of processing time and consumed memory. Only use this +%% type if you are certain that you need it. +-spec any() -> proper_types:type(). +any() -> + AllTypes = [integer(),float(),atom(),bitstring(),?LAZY(loose_tuple(any())), + ?LAZY(list(any()))], + ?SUBTYPE(union(AllTypes), [ + {generator, fun proper_gen:any_gen/1} + ]). + + +%%------------------------------------------------------------------------------ +%% Type aliases +%%------------------------------------------------------------------------------ + +%% @equiv integer(inf, inf) +-spec integer() -> proper_types:type(). +integer() -> integer(inf, inf). + +%% @equiv integer(0, inf) +-spec non_neg_integer() -> proper_types:type(). +non_neg_integer() -> integer(0, inf). + +%% @equiv integer(1, inf) +-spec pos_integer() -> proper_types:type(). +pos_integer() -> integer(1, inf). + +%% @equiv integer(inf, -1) +-spec neg_integer() -> proper_types:type(). +neg_integer() -> integer(inf, -1). + +%% @equiv integer(Low, High) +-spec range(extint(), extint()) -> proper_types:type(). +range(Low, High) -> integer(Low, High). + +%% @equiv float(inf, inf) +-spec float() -> proper_types:type(). +float() -> float(inf, inf). + +%% @equiv float(0.0, inf) +-spec non_neg_float() -> proper_types:type(). +non_neg_float() -> float(0.0, inf). + +%% @equiv union([integer(), float()]) +-spec number() -> proper_types:type(). +number() -> union([integer(), float()]). + +%% @doc The atoms `true' and `false'. Instances shrink towards `false'. +-spec boolean() -> proper_types:type(). +boolean() -> union(['false', 'true']). + +%% @equiv integer(0, 255) +-spec byte() -> proper_types:type(). +byte() -> integer(0, 255). + +%% @equiv integer(0, 16#10ffff) +-spec char() -> proper_types:type(). +char() -> integer(0, 16#10ffff). + +%% @equiv list(any()) +-spec list() -> proper_types:type(). +list() -> list(any()). + +%% @equiv loose_tuple(any()) +-spec tuple() -> proper_types:type(). +tuple() -> loose_tuple(any()). + +%% @equiv list(char()) +-spec string() -> proper_types:type(). +string() -> list(char()). + +%% @equiv weighted_union(FreqChoices) +-spec wunion([{frequency(),raw_type()},...]) -> proper_types:type(). +wunion(FreqChoices) -> weighted_union(FreqChoices). + +%% @equiv any() +-spec term() -> proper_types:type(). +term() -> any(). + +%% @equiv union([non_neg_integer() | infinity]) +-spec timeout() -> proper_types:type(). +timeout() -> union([non_neg_integer(), 'infinity']). + +%% @equiv integer(0, 255) +-spec arity() -> proper_types:type(). +arity() -> integer(0, 255). + + +%%------------------------------------------------------------------------------ +%% QuickCheck compatibility types +%%------------------------------------------------------------------------------ + +%% @doc Small integers (bound by the current value of the `size' parameter). +%% Instances shrink towards `0'. +-spec int() -> proper_types:type(). +int() -> ?SIZED(Size, integer(-Size,Size)). + +%% @doc Small non-negative integers (bound by the current value of the `size' +%% parameter). Instances shrink towards `0'. +-spec nat() -> proper_types:type(). +nat() -> ?SIZED(Size, integer(0,Size)). + +%% @equiv integer() +-spec largeint() -> proper_types:type(). +largeint() -> integer(). + +%% @equiv float() +-spec real() -> proper_types:type(). +real() -> float(). + +%% @equiv boolean() +-spec bool() -> proper_types:type(). +bool() -> boolean(). + +%% @equiv integer(Low, High) +-spec choose(extint(), extint()) -> proper_types:type(). +choose(Low, High) -> integer(Low, High). + +%% @equiv union(Choices) +-spec elements([raw_type(),...]) -> proper_types:type(). +elements(Choices) -> union(Choices). + +%% @equiv union(Choices) +-spec oneof([raw_type(),...]) -> proper_types:type(). +oneof(Choices) -> union(Choices). + +%% @equiv weighted_union(Choices) +-spec frequency([{frequency(),raw_type()},...]) -> proper_types:type(). +frequency(FreqChoices) -> weighted_union(FreqChoices). + +%% @equiv exactly(E) +-spec return(term()) -> proper_types:type(). +return(E) -> exactly(E). + +%% @doc Adds a default value, `Default', to `Type'. +%% The default serves as a primary shrinking target for instances, while it +%% is also chosen by the random instance generation subsystem half the time. +-spec default(raw_type(), raw_type()) -> proper_types:type(). +default(Default, Type) -> + union([Default, Type]). + +%% @doc All sorted lists containing elements of type `ElemType'. +%% Instances shrink towards the empty list, `[]'. +-spec orderedlist(ElemType::raw_type()) -> proper_types:type(). +orderedlist(RawElemType) -> + ?LET(L, list(RawElemType), lists:sort(L)). + +%% @equiv function(0, RetType) +-spec function0(raw_type()) -> proper_types:type(). +function0(RetType) -> + function(0, RetType). + +%% @equiv function(1, RetType) +-spec function1(raw_type()) -> proper_types:type(). +function1(RetType) -> + function(1, RetType). + +%% @equiv function(2, RetType) +-spec function2(raw_type()) -> proper_types:type(). +function2(RetType) -> + function(2, RetType). + +%% @equiv function(3, RetType) +-spec function3(raw_type()) -> proper_types:type(). +function3(RetType) -> + function(3, RetType). + +%% @equiv function(4, RetType) +-spec function4(raw_type()) -> proper_types:type(). +function4(RetType) -> + function(4, RetType). + +%% @doc A specialization of {@link default/2}, where `Default' and `Type' are +%% assigned weights to be considered by the random instance generator. The +%% shrinking subsystem will ignore the weights and try to shrink using the +%% default value. +-spec weighted_default({frequency(),raw_type()}, {frequency(),raw_type()}) -> + proper_types:type(). +weighted_default(Default, Type) -> + weighted_union([Default, Type]). + + +%%------------------------------------------------------------------------------ +%% Additional type specification functions +%%------------------------------------------------------------------------------ + +%% @doc Overrides the `size' parameter used when generating instances of +%% `Type' with `NewSize'. Has no effect on size-less types, such as unions. +%% Also, this will not affect the generation of any internal types contained in +%% `Type', such as the elements of a list - those will still be generated +%% using the test-wide value of `size'. One use of this function is to modify +%% types to produce instances that grow faster or slower, like so: +%% ```?SIZED(Size, resize(Size * 2, list(integer()))''' +%% The above specifies a list type that grows twice as fast as normal lists. +-spec resize(size(), Type::raw_type()) -> proper_types:type(). +resize(NewSize, RawType) -> + Type = cook_outer(RawType), + case find_prop(size_transform, Type) of + {ok,Transform} -> + add_prop(size_transform, fun(_S) -> Transform(NewSize) end, Type); + error -> + add_prop(size_transform, fun(_S) -> NewSize end, Type) + end. + +%% @doc This is a predefined constraint that can be applied to random-length +%% list and binary types to ensure that the produced values are never empty. +%% +%% e.g. {@link list/0}, {@link string/0}, {@link binary/0}) +-spec non_empty(ListType::raw_type()) -> proper_types:type(). +non_empty(RawListType) -> + ?SUCHTHAT(L, RawListType, L =/= [] andalso L =/= <<>>). + +%% @doc Creates a new type which is equivalent to `Type', but whose instances +%% are never shrunk by the shrinking subsystem. +-spec noshrink(Type::raw_type()) -> proper_types:type(). +noshrink(RawType) -> + add_prop(noshrink, true, cook_outer(RawType)). + +%% @doc Associates the atom key `Parameter' with the value `Value' while +%% generating instances of `Type'. +-spec with_parameter(atom(), value(), Type::raw_type()) -> proper_types:type(). +with_parameter(Parameter, Value, RawType) -> + with_parameters([{Parameter,Value}], RawType). + +%% @doc Similar to {@link with_parameter/3}, but accepts a list of +%% `{Parameter, Value}' pairs. +-spec with_parameters([{atom(),value()}], Type::raw_type()) -> + proper_types:type(). +with_parameters(PVlist, RawType) -> + Type = cook_outer(RawType), + case find_prop(parameters, Type) of + {ok,Params} when is_list(Params) -> + append_list_to_prop(parameters, PVlist, Type); + error -> + add_prop(parameters, PVlist, Type) + end. + +%% @doc Returns the value associated with `Parameter', or `Default' in case +%% `Parameter' is not associated with any value. +-spec parameter(atom(), value()) -> value(). +parameter(Parameter, Default) -> + Parameters = + case erlang:get('$parameters') of + undefined -> []; + List -> List + end, + proplists:get_value(Parameter, Parameters, Default). + +%% @equiv parameter(Parameter, undefined) +-spec parameter(atom()) -> value(). +parameter(Parameter) -> + parameter(Parameter, undefined). diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/proper/proper_typeserver.erl b/lib/dialyzer/test/opaque_SUITE_data/src/proper/proper_typeserver.erl new file mode 100644 index 0000000000..b6cab5e24b --- /dev/null +++ b/lib/dialyzer/test/opaque_SUITE_data/src/proper/proper_typeserver.erl @@ -0,0 +1,2401 @@ +%%% Copyright 2010-2015 Manolis Papadakis <[email protected]>, +%%% Eirini Arvaniti <[email protected]> +%%% and Kostis Sagonas <[email protected]> +%%% +%%% This file is part of PropEr. +%%% +%%% PropEr is free software: you can redistribute it and/or modify +%%% it under the terms of the GNU General Public License as published by +%%% the Free Software Foundation, either version 3 of the License, or +%%% (at your option) any later version. +%%% +%%% PropEr is distributed in the hope that it will be useful, +%%% but WITHOUT ANY WARRANTY; without even the implied warranty of +%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +%%% GNU General Public License for more details. +%%% +%%% You should have received a copy of the GNU General Public License +%%% along with PropEr. If not, see <http://www.gnu.org/licenses/>. + +%%% @copyright 2010-2015 Manolis Papadakis, Eirini Arvaniti and Kostis Sagonas +%%% @version {@version} +%%% @author Manolis Papadakis + +%%% @doc Erlang type system - PropEr type system integration module. +%%% +%%% PropEr can parse types expressed in Erlang's type language and convert them +%%% to its own type format. Such expressions can be used instead of regular type +%%% constructors in the second argument of `?FORALL's. No extra notation is +%%% required; PropEr will detect which calls correspond to native types by +%%% applying a parse transform during compilation. This parse transform is +%%% automatically applied to any module that includes the `proper.hrl' header +%%% file. You can disable this feature by compiling your modules with +%%% `-DPROPER_NO_TRANS'. Note that this will currently also disable the +%%% automatic exporting of properties. +%%% +%%% The use of native types in properties is subject to the following usage +%%% rules: +%%% <ul> +%%% <li>Native types cannot be used outside of `?FORALL's.</li> +%%% <li>Inside `?FORALL's, native types can be combined with other native +%%% types, and even with PropEr types, inside tuples and lists (the constructs +%%% `[...]', `{...}' and `++' are all allowed).</li> +%%% <li>All other constructs of Erlang's built-in type system (e.g. `|' for +%%% union, `_' as an alias of `any()', `<<_:_>>' binary type syntax and +%%% `fun((...) -> ...)' function type syntax) are not allowed in `?FORALL's, +%%% because they are rejected by the Erlang parser.</li> +%%% <li>Anything other than a tuple constructor, list constructor, `++' +%%% application, local or remote call will automatically be considered a +%%% PropEr type constructor and not be processed further by the parse +%%% transform.</li> +%%% <li>Parametric native types are fully supported; of course, they can only +%%% appear instantiated in a `?FORALL'. The arguments of parametric native +%%% types are always interpreted as native types.</li> +%%% <li>Parametric PropEr types, on the other hand, can take any kind of +%%% argument. You can even mix native and PropEr types in the arguments of a +%%% PropEr type. For example, assuming that the following declarations are +%%% present: +%%% ``` my_proper_type() -> ?LET(...). +%%% -type my_native_type() :: ... .''' +%%% Then the following expressions are all legal: +%%% ``` vector(2, my_native_type()) +%%% function(0, my_native_type()) +%%% union([my_proper_type(), my_native_type()])''' </li> +%%% <li>Some type constructors can take native types as arguments (but only +%%% inside `?FORALL's): +%%% <ul> +%%% <li>`?SUCHTHAT', `?SUCHTHATMAYBE', `non_empty', `noshrink': these work +%%% with native types too</li> +%%% <li>`?LAZY', `?SHRINK', `resize', `?SIZED': these don't work with native +%%% types</li> +%%% <li>`?LET', `?LETSHRINK': only the top-level base type can be a native +%%% type</li> +%%% </ul></li> +%%% <li>Native type declarations in the `?FORALL's of a module can reference any +%%% custom type declared in a `-type' or `-opaque' attribute of the same +%%% module, as long as no module identifier is used.</li> +%%% <li>Typed records cannot be referenced inside `?FORALL's using the +%%% `#rec_name{}' syntax. To use a typed record in a `?FORALL', enclose the +%%% record in a custom type like so: +%%% ``` -type rec_name() :: #rec_name{}. ''' +%%% and use the custom type instead.</li> +%%% <li>`?FORALL's may contain references to self-recursive or mutually +%%% recursive native types, so long as each type in the hierarchy has a clear +%%% base case. +%%% Currently, PropEr requires that the toplevel of any recursive type +%%% declaration is either a (maybe empty) list or a union containing at least +%%% one choice that doesn't reference the type directly (it may, however, +%%% reference any of the types that are mutually recursive with it). This +%%% means, for example, that some valid recursive type declarations, such as +%%% this one: +%%% ``` ?FORALL(..., a(), ...) ''' +%%% where: +%%% ``` -type a() :: {'a','none' | a()}. ''' +%%% are not accepted by PropEr. However, such types can be rewritten in a way +%%% that allows PropEr to parse them: +%%% ``` ?FORALL(..., a(), ...) ''' +%%% where: +%%% ``` -type a() :: {'a','none'} | {'a',a()}. ''' +%%% This also means that recursive record declarations are not allowed: +%%% ``` ?FORALL(..., rec(), ...) ''' +%%% where: +%%% ``` -type rec() :: #rec{}. +%%% -record(rec, {a = 0 :: integer(), b = 'nil' :: 'nil' | #rec{}}). ''' +%%% A little rewritting can usually remedy this problem as well: +%%% ``` ?FORALL(..., rec(), ...) ''' +%%% where: +%%% ``` -type rec() :: #rec{b :: 'nil'} | #rec{b :: rec()}. +%%% -record(rec, {a = 0 :: integer(), b = 'nil' :: 'nil' | #rec{}}). ''' +%%% </li> +%%% <li>Remote types may be referenced in a `?FORALL', so long as they are +%%% exported from the remote module. Currently, PropEr requires that any +%%% remote modules whose types are directly referenced from within properties +%%% are present in the code path at compile time, either compiled with +%%% `debug_info' enabled or in source form. If PropEr cannot find a remote +%%% module at all, finds only a compiled object file with no debug +%%% information or fails to compile the source file, all calls to that module +%%% will automatically be considered calls to PropEr type constructors.</li> +%%% <li>For native types to be translated correctly, both the module that +%%% contains the `?FORALL' declaration as well as any module that contains +%%% the declaration of a type referenced (directly or indirectly) from inside +%%% a `?FORALL' must be present in the code path at runtime, either compiled +%%% with `debug_info' enabled or in source form.</li> +%%% <li>Local types with the same name as an auto-imported BIF are not accepted +%%% by PropEr, unless the BIF in question has been declared in a +%%% `no_auto_import' option.</li> +%%% <li>When an expression can be interpreted both as a PropEr type and as a +%%% native type, the former takes precedence. This means that a function +%%% `foo()' will shadow a type `foo()' if they are both present in the module. +%%% The same rule applies to remote functions and types as well.</li> +%%% <li>The above may cause some confusion when list syntax is used: +%%% <ul> +%%% <li>The expression `[integer()]' can be interpreted both ways, so the +%%% PropEr way applies. Therefore, instances of this type will always be +%%% lists of length 1, not arbitrary integer lists, as would be expected +%%% when interpreting the expression as a native type.</li> +%%% <li>Assuming that a custom type foo/1 has been declared, the expression +%%% `foo([integer()])' can only be interpreted as a native type declaration, +%%% which means that the generic type of integer lists will be passed to +%%% `foo/1'.</li> +%%% </ul></li> +%%% <li>Currently, PropEr does not detect the following mistakes: +%%% <ul> +%%% <li>inline record-field specializations that reference non-existent +%%% fields</li> +%%% <li>type parameters that are not present in the RHS of a `-type' +%%% declaration</li> +%%% <li>using `_' as a type variable in the LHS of a `-type' declaration</li> +%%% <li>using the same variable in more than one position in the LHS of a +%%% `-type' declaration</li> +%%% </ul> +%%% </li> +%%% </ul> +%%% +%%% You can use <a href="#index">these</a> functions to try out the type +%%% translation subsystem. +%%% +%%% CAUTION: These functions should never be used inside properties. They are +%%% meant for demonstration purposes only. + +-module(proper_typeserver). +-behaviour(gen_server). +-export([demo_translate_type/2, demo_is_instance/3]). + +-export([start/0, restart/0, stop/0, create_spec_test/3, get_exp_specced/1, + is_instance/3, translate_type/1]). +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, + code_change/3]). +-export([get_exp_info/1, match/2]). + +-export_type([imm_type/0, mod_exp_types/0, mod_exp_funs/0]). + +-include("proper_internal.hrl"). + + +%%------------------------------------------------------------------------------ +%% Macros +%%------------------------------------------------------------------------------ + +-define(SRC_FILE_EXT, ".erl"). + +%% CAUTION: all these must be sorted +-define(STD_TYPES_0, + [any,arity,atom,binary,bitstring,bool,boolean,byte,char,float,integer, + list,neg_integer,non_neg_integer,number,pos_integer,string,term, + timeout]). +-define(HARD_ADTS, + %% gb_trees:iterator and gb_sets:iterator are NOT hardcoded + [{{array,0},array}, {{array,1},proper_array}, + {{dict,0},dict}, {{dict,2},proper_dict}, + {{gb_set,0},gb_sets}, {{gb_set,1},proper_gb_sets}, + {{gb_tree,0},gb_trees}, {{gb_tree,2},proper_gb_trees}, + {{orddict,2},proper_orddict}, + {{ordset,1},proper_ordsets}, + {{queue,0},queue}, {{queue,1},proper_queue}, + {{set,0},sets}, {{set,1},proper_sets}]). +-define(HARD_ADT_MODS, + [{array, [{{array,0}, + {{type,0,record,[{atom,0,array}]},[]}}]}, + {dict, [{{dict,0}, + {{type,0,record,[{atom,0,dict}]},[]}}]}, + {gb_sets, [{{gb_set,0}, + {{type,0,tuple,[{type,0,non_neg_integer,[]}, + {type,0,gb_set_node,[]}]},[]}}]}, + {gb_trees, [{{gb_tree,0}, + {{type,0,tuple,[{type,0,non_neg_integer,[]}, + {type,0,gb_tree_node,[]}]},[]}}]}, + %% Our parametric ADTs are already declared as normal types, we just + %% need to change them to opaques. + {proper_array, [{{array,1},already_declared}]}, + {proper_dict, [{{dict,2},already_declared}]}, + {proper_gb_sets, [{{gb_set,1},already_declared}, + {{iterator,1},already_declared}]}, + {proper_gb_trees, [{{gb_tree,2},already_declared}, + {{iterator,2},already_declared}]}, + {proper_orddict, [{{orddict,2},already_declared}]}, + {proper_ordsets, [{{ordset,1},already_declared}]}, + {proper_queue, [{{queue,1},already_declared}]}, + {proper_sets, [{{set,1},already_declared}]}, + {queue, [{{queue,0}, + {{type,0,tuple,[{type,0,list,[]},{type,0,list,[]}]},[]}}]}, + {sets, [{{set,0}, + {{type,0,record,[{atom,0,set}]},[]}}]}]). + + +%%------------------------------------------------------------------------------ +%% Types +%%------------------------------------------------------------------------------ + +-type type_name() :: atom(). +-type var_name() :: atom(). %% TODO: also integers? +-type field_name() :: atom(). + +-type type_kind() :: 'type' | 'record'. +-type type_ref() :: {type_kind(),type_name(),arity()}. +-ifdef(NO_MODULES_IN_OPAQUES). +-type substs_dict() :: dict(). %% dict(field_name(),ret_type()) +-else. +-type substs_dict() :: dict:dict(field_name(),ret_type()). +-endif. +-type full_type_ref() :: {mod_name(),type_kind(),type_name(), + [ret_type()] | substs_dict()}. +-type symb_info() :: 'not_symb' | {'orig_abs',abs_type()}. +-type type_repr() :: {'abs_type',abs_type(),[var_name()],symb_info()} + | {'cached',fin_type(),abs_type(),symb_info()} + | {'abs_record',[{field_name(),abs_type()}]}. +-type gen_fun() :: fun((size()) -> fin_type()). +-type rec_fun() :: fun(([gen_fun()],size()) -> fin_type()). +-type rec_arg() :: {boolean() | {'list',boolean(),rec_fun()},full_type_ref()}. +-type rec_args() :: [rec_arg()]. +-type ret_type() :: {'simple',fin_type()} | {'rec',rec_fun(),rec_args()}. +-type rec_fun_info() :: {pos_integer(),pos_integer(),[arity(),...], + [rec_fun(),...]}. + +-type imm_type_ref() :: {type_name(),arity()}. +-type hard_adt_repr() :: {abs_type(),[var_name()]} | 'already_declared'. +-type fun_ref() :: {fun_name(),arity()}. +-type fun_repr() :: fun_clause_repr(). +-type fun_clause_repr() :: {[abs_type()],abs_type()}. +-type proc_fun_ref() :: {fun_name(),[abs_type()],abs_type()}. +-type full_imm_type_ref() :: {mod_name(),type_name(),arity()}. +-type imm_stack() :: [full_imm_type_ref()]. +-type pat_field() :: 0 | 1 | atom(). +-type pattern() :: loose_tuple(pat_field()). +-type next_step() :: 'none' | 'take_head' | {'match_with',pattern()}. + +-ifdef(NO_MODULES_IN_OPAQUES). +%% @private_type +-type mod_exp_types() :: set(). %% set(imm_type_ref()) +-type mod_types() :: dict(). %% dict(type_ref(),type_repr()) +%% @private_type +-type mod_exp_funs() :: set(). %% set(fun_ref()) +-type mod_specs() :: dict(). %% dict(fun_ref(),fun_repr()) +-else. +%% @private_type +-type mod_exp_types() :: sets:set(imm_type_ref()). +-type mod_types() :: dict:dict(type_ref(),type_repr()). +%% @private_type +-type mod_exp_funs() :: sets:set(fun_ref()). +-type mod_specs() :: dict:dict(fun_ref(),fun_repr()). +-endif. + +-ifdef(NO_MODULES_IN_OPAQUES). +-record(state, + {cached = dict:new() :: dict(), %% dict(imm_type(),fin_type()) + exp_types = dict:new() :: dict(), %% dict(mod_name(),mod_exp_types()) + types = dict:new() :: dict(), %% dict(mod_name(),mod_types()) + exp_specs = dict:new() :: dict()}). %% dict(mod_name(),mod_specs()) +-else. +-record(state, + {cached = dict:new() :: dict:dict(), %% dict(imm_type(),fin_type()) + exp_types = dict:new() :: dict:dict(), %% dict(mod_name(),mod_exp_types()) + types = dict:new() :: dict:dict(), %% dict(mod_name(),mod_types()) + exp_specs = dict:new() :: dict:dict()}). %% dict(mod_name(),mod_specs()) +%% {cached = dict:new() :: dict:dict(imm_type(),fin_type()), +%% exp_types = dict:new() :: dict:dict(mod_name(),mod_exp_types()), +%% types = dict:new() :: dict:dict(mod_name(),mod_types()), +%% exp_specs = dict:new() :: dict:dict(mod_name(),mod_specs())}). +-endif. +-type state() :: #state{}. + +-record(mod_info, + {mod_exp_types = sets:new() :: mod_exp_types(), + mod_types = dict:new() :: mod_types(), + mod_opaques = sets:new() :: mod_exp_types(), + mod_exp_funs = sets:new() :: mod_exp_funs(), + mod_specs = dict:new() :: mod_specs()}). +-type mod_info() :: #mod_info{}. + +-type stack() :: [full_type_ref() | 'tuple' | 'list' | 'union' | 'fun']. +-ifdef(NO_MODULES_IN_OPAQUES). +-type var_dict() :: dict(). %% dict(var_name(),ret_type()) +-else. +-type var_dict() :: dict:dict(var_name(),ret_type()). +-endif. +%% @private_type +-type imm_type() :: {mod_name(),string()}. +%% @alias +-type fin_type() :: proper_types:type(). +-type tagged_result(T) :: {'ok',T} | 'error'. +-type tagged_result2(T,S) :: {'ok',T,S} | 'error'. +%% @alias +-type rich_result(T) :: {'ok',T} | {'error',term()}. +-type rich_result2(T,S) :: {'ok',T,S} | {'error',term()}. +-type false_positive_mfas() :: proper:false_positive_mfas(). + +-type server_call() :: {'create_spec_test',mfa(),timeout(),false_positive_mfas()} + | {'get_exp_specced',mod_name()} + | {'get_type_repr',mod_name(),type_ref(),boolean()} + | {'translate_type',imm_type()}. +-type server_response() :: rich_result(proper:test()) + | rich_result([mfa()]) + | rich_result(type_repr()) + | rich_result(fin_type()). + + +%%------------------------------------------------------------------------------ +%% Server interface functions +%%------------------------------------------------------------------------------ + +%% @private +-spec start() -> 'ok'. +start() -> + {ok,TypeserverPid} = gen_server:start_link(?MODULE, dummy, []), + put('$typeserver_pid', TypeserverPid), + ok. + +%% @private +-spec restart() -> 'ok'. +restart() -> + TypeserverPid = get('$typeserver_pid'), + case (TypeserverPid =:= undefined orelse not is_process_alive(TypeserverPid)) of + true -> start(); + false -> ok + end. + +%% @private +-spec stop() -> 'ok'. +stop() -> + TypeserverPid = get('$typeserver_pid'), + erase('$typeserver_pid'), + gen_server:cast(TypeserverPid, stop). + +%% @private +-spec create_spec_test(mfa(), timeout(), false_positive_mfas()) -> rich_result(proper:test()). +create_spec_test(MFA, SpecTimeout, FalsePositiveMFAs) -> + TypeserverPid = get('$typeserver_pid'), + gen_server:call(TypeserverPid, {create_spec_test,MFA,SpecTimeout,FalsePositiveMFAs}). + +%% @private +-spec get_exp_specced(mod_name()) -> rich_result([mfa()]). +get_exp_specced(Mod) -> + TypeserverPid = get('$typeserver_pid'), + gen_server:call(TypeserverPid, {get_exp_specced,Mod}). + +-spec get_type_repr(mod_name(), type_ref(), boolean()) -> + rich_result(type_repr()). +get_type_repr(Mod, TypeRef, IsRemote) -> + TypeserverPid = get('$typeserver_pid'), + gen_server:call(TypeserverPid, {get_type_repr,Mod,TypeRef,IsRemote}). + +%% @private +-spec translate_type(imm_type()) -> rich_result(fin_type()). +translate_type(ImmType) -> + TypeserverPid = get('$typeserver_pid'), + gen_server:call(TypeserverPid, {translate_type,ImmType}). + +%% @doc Translates the native type expression `TypeExpr' (which should be +%% provided inside a string) into a PropEr type, which can then be passed to any +%% of the demo functions defined in the {@link proper_gen} module. PropEr acts +%% as if it found this type expression inside the code of module `Mod'. +-spec demo_translate_type(mod_name(), string()) -> rich_result(fin_type()). +demo_translate_type(Mod, TypeExpr) -> + start(), + Result = translate_type({Mod,TypeExpr}), + stop(), + Result. + +%% @doc Checks if `Term' is a valid instance of native type `TypeExpr' (which +%% should be provided inside a string). PropEr acts as if it found this type +%% expression inside the code of module `Mod'. +-spec demo_is_instance(term(), mod_name(), string()) -> + boolean() | {'error',term()}. +demo_is_instance(Term, Mod, TypeExpr) -> + case parse_type(TypeExpr) of + {ok,TypeForm} -> + start(), + Result = + %% Force the typeserver to load the module. + case translate_type({Mod,"integer()"}) of + {ok,_FinType} -> + try is_instance(Term, Mod, TypeForm) + catch + throw:{'$typeserver',Reason} -> {error, Reason} + end; + {error,_Reason} = Error -> + Error + end, + stop(), + Result; + {error,_Reason} = Error -> + Error + end. + + +%%------------------------------------------------------------------------------ +%% Implementation of gen_server interface +%%------------------------------------------------------------------------------ + +%% @private +-spec init(_) -> {'ok',state()}. +init(_) -> + {ok, #state{}}. + +%% @private +-spec handle_call(server_call(), _, state()) -> + {'reply',server_response(),state()}. +handle_call({create_spec_test,MFA,SpecTimeout,FalsePositiveMFAs}, _From, State) -> + case create_spec_test(MFA, SpecTimeout, FalsePositiveMFAs, State) of + {ok,Test,NewState} -> + {reply, {ok,Test}, NewState}; + {error,_Reason} = Error -> + {reply, Error, State} + end; +handle_call({get_exp_specced,Mod}, _From, State) -> + case get_exp_specced(Mod, State) of + {ok,MFAs,NewState} -> + {reply, {ok,MFAs}, NewState}; + {error,_Reason} = Error -> + {reply, Error, State} + end; +handle_call({get_type_repr,Mod,TypeRef,IsRemote}, _From, State) -> + case get_type_repr(Mod, TypeRef, IsRemote, State) of + {ok,TypeRepr,NewState} -> + {reply, {ok,TypeRepr}, NewState}; + {error,_Reason} = Error -> + {reply, Error, State} + end; +handle_call({translate_type,ImmType}, _From, State) -> + case translate_type(ImmType, State) of + {ok,FinType,NewState} -> + {reply, {ok,FinType}, NewState}; + {error,_Reason} = Error -> + {reply, Error, State} + end. + +%% @private +-spec handle_cast('stop', state()) -> {'stop','normal',state()}. +handle_cast(stop, State) -> + {stop, normal, State}. + +%% @private +-spec handle_info(term(), state()) -> {'stop',{'received_info',term()},state()}. +handle_info(Info, State) -> + {stop, {received_info,Info}, State}. + +%% @private +-spec terminate(term(), state()) -> 'ok'. +terminate(_Reason, _State) -> + ok. + +%% @private +-spec code_change(term(), state(), _) -> {'ok',state()}. +code_change(_OldVsn, State, _) -> + {ok, State}. + + +%%------------------------------------------------------------------------------ +%% Top-level interface +%%------------------------------------------------------------------------------ + +-spec create_spec_test(mfa(), timeout(), false_positive_mfas(), state()) -> + rich_result2(proper:test(),state()). +create_spec_test(MFA, SpecTimeout, FalsePositiveMFAs, State) -> + case get_exp_spec(MFA, State) of + {ok,FunRepr,NewState} -> + make_spec_test(MFA, FunRepr, SpecTimeout, FalsePositiveMFAs, NewState); + {error,_Reason} = Error -> + Error + end. + +-spec get_exp_spec(mfa(), state()) -> rich_result2(fun_repr(),state()). +get_exp_spec({Mod,Fun,Arity} = MFA, State) -> + case add_module(Mod, State) of + {ok,#state{exp_specs = ExpSpecs} = NewState} -> + ModExpSpecs = dict:fetch(Mod, ExpSpecs), + case dict:find({Fun,Arity}, ModExpSpecs) of + {ok,FunRepr} -> + {ok, FunRepr, NewState}; + error -> + {error, {function_not_exported_or_specced,MFA}} + end; + {error,_Reason} = Error -> + Error + end. + +-spec make_spec_test(mfa(), fun_repr(), timeout(), false_positive_mfas(), state()) -> + rich_result2(proper:test(),state()). +make_spec_test({Mod,_Fun,_Arity}=MFA, {Domain,_Range}=FunRepr, SpecTimeout, FalsePositiveMFAs, State) -> + case convert(Mod, {type,0,'$fixed_list',Domain}, State) of + {ok,FinType,NewState} -> + Test = ?FORALL(Args, FinType, apply_spec_test(MFA, FunRepr, SpecTimeout, FalsePositiveMFAs, Args)), + {ok, Test, NewState}; + {error,_Reason} = Error -> + Error + end. + +-spec apply_spec_test(mfa(), fun_repr(), timeout(), false_positive_mfas(), term()) -> proper:test(). +apply_spec_test({Mod,Fun,_Arity}=MFA, {_Domain,Range}, SpecTimeout, FalsePositiveMFAs, Args) -> + ?TIMEOUT(SpecTimeout, + begin + %% NOTE: only call apply/3 inside try/catch (do not trust ?MODULE:is_instance/3) + Result = + try apply(Mod,Fun,Args) of + X -> {ok, X} + catch + X:Y -> {X, Y} + end, + case Result of + {ok, Z} -> + case ?MODULE:is_instance(Z,Mod,Range) of + true -> + true; + false when is_function(FalsePositiveMFAs) -> + FalsePositiveMFAs(MFA, Args, {fail, Z}); + false -> + false + end; + Exception when is_function(FalsePositiveMFAs) -> + case FalsePositiveMFAs(MFA, Args, Exception) of + true -> + true; + false -> + error(Exception, erlang:get_stacktrace()) + end; + Exception -> + error(Exception, erlang:get_stacktrace()) + end + end). + +-spec get_exp_specced(mod_name(), state()) -> rich_result2([mfa()],state()). +get_exp_specced(Mod, State) -> + case add_module(Mod, State) of + {ok,#state{exp_specs = ExpSpecs} = NewState} -> + ModExpSpecs = dict:fetch(Mod, ExpSpecs), + ExpSpecced = [{Mod,F,A} || {F,A} <- dict:fetch_keys(ModExpSpecs)], + {ok, ExpSpecced, NewState}; + {error,_Reason} = Error -> + Error + end. + +-spec get_type_repr(mod_name(), type_ref(), boolean(), state()) -> + rich_result2(type_repr(),state()). +get_type_repr(Mod, {type,Name,Arity} = TypeRef, true, State) -> + case prepare_for_remote(Mod, Name, Arity, State) of + {ok,NewState} -> + get_type_repr(Mod, TypeRef, false, NewState); + {error,_Reason} = Error -> + Error + end; +get_type_repr(Mod, TypeRef, false, #state{types = Types} = State) -> + ModTypes = dict:fetch(Mod, Types), + case dict:find(TypeRef, ModTypes) of + {ok,TypeRepr} -> + {ok, TypeRepr, State}; + error -> + {error, {missing_type,Mod,TypeRef}} + end. + +-spec prepare_for_remote(mod_name(), type_name(), arity(), state()) -> + rich_result(state()). +prepare_for_remote(RemMod, Name, Arity, State) -> + case add_module(RemMod, State) of + {ok,#state{exp_types = ExpTypes} = NewState} -> + RemModExpTypes = dict:fetch(RemMod, ExpTypes), + case sets:is_element({Name,Arity}, RemModExpTypes) of + true -> {ok, NewState}; + false -> {error, {type_not_exported,{RemMod,Name,Arity}}} + end; + {error,_Reason} = Error -> + Error + end. + +-spec translate_type(imm_type(), state()) -> rich_result2(fin_type(),state()). +translate_type({Mod,Str} = ImmType, #state{cached = Cached} = State) -> + case dict:find(ImmType, Cached) of + {ok,Type} -> + {ok, Type, State}; + error -> + case parse_type(Str) of + {ok,TypeForm} -> + case add_module(Mod, State) of + {ok,NewState} -> + case convert(Mod, TypeForm, NewState) of + {ok,FinType, + #state{cached = Cached} = FinalState} -> + NewCached = dict:store(ImmType, FinType, + Cached), + {ok, FinType, + FinalState#state{cached = NewCached}}; + {error,_Reason} = Error -> + Error + end; + {error,_Reason} = Error -> + Error + end; + {error,Reason} -> + {error, {parse_error,Str,Reason}} + end + end. + +-spec parse_type(string()) -> rich_result(abs_type()). +parse_type(Str) -> + TypeStr = "-type mytype() :: " ++ Str ++ ".", + case erl_scan:string(TypeStr) of + {ok,Tokens,_EndLocation} -> + case erl_parse:parse_form(Tokens) of + {ok,{attribute,_Line,type,{mytype,TypeExpr,[]}}} -> + {ok, TypeExpr}; + {error,_ErrorInfo} = Error -> + Error + end; + {error,ErrorInfo,_EndLocation} -> + {error, ErrorInfo} + end. + +-spec add_module(mod_name(), state()) -> rich_result(state()). +add_module(Mod, #state{exp_types = ExpTypes} = State) -> + case dict:is_key(Mod, ExpTypes) of + true -> + {ok, State}; + false -> + case get_code_and_exports(Mod) of + {ok,AbsCode,ModExpFuns} -> + RawModInfo = get_mod_info(Mod, AbsCode, ModExpFuns), + ModInfo = process_adts(Mod, RawModInfo), + {ok, store_mod_info(Mod,ModInfo,State)}; + {error,Reason} -> + {error, {cant_load_code,Mod,Reason}} + end + end. + +%% @private +-spec get_exp_info(mod_name()) -> rich_result2(mod_exp_types(),mod_exp_funs()). +get_exp_info(Mod) -> + case get_code_and_exports(Mod) of + {ok,AbsCode,ModExpFuns} -> + RawModInfo = get_mod_info(Mod, AbsCode, ModExpFuns), + {ok, RawModInfo#mod_info.mod_exp_types, ModExpFuns}; + {error,_Reason} = Error -> + Error + end. + +-spec get_code_and_exports(mod_name()) -> + rich_result2([abs_form()],mod_exp_funs()). +get_code_and_exports(Mod) -> + case code:get_object_code(Mod) of + {Mod, ObjBin, _ObjFileName} -> + case get_chunks(ObjBin) of + {ok,_AbsCode,_ModExpFuns} = Result -> + Result; + {error,Reason} -> + get_code_and_exports_from_source(Mod, Reason) + end; + error -> + get_code_and_exports_from_source(Mod, cant_find_object_file) + end. + +-spec get_code_and_exports_from_source(mod_name(), term()) -> + rich_result2([abs_form()],mod_exp_funs()). +get_code_and_exports_from_source(Mod, ObjError) -> + SrcFileName = atom_to_list(Mod) ++ ?SRC_FILE_EXT, + case code:where_is_file(SrcFileName) of + FullSrcFileName when is_list(FullSrcFileName) -> + Opts = [binary,debug_info,return_errors,{d,'PROPER_REMOVE_PROPS'}], + case compile:file(FullSrcFileName, Opts) of + {ok,Mod,Binary} -> + get_chunks(Binary); + {error,Errors,_Warnings} -> + {error, {ObjError,{cant_compile_source_file,Errors}}} + end; + non_existing -> + {error, {ObjError,cant_find_source_file}} + end. + +-spec get_chunks(string() | binary()) -> + rich_result2([abs_form()],mod_exp_funs()). +get_chunks(ObjFile) -> + case beam_lib:chunks(ObjFile, [abstract_code,exports]) of + {ok,{_Mod,[{abstract_code,AbsCodeChunk},{exports,ExpFunsList}]}} -> + case AbsCodeChunk of + {raw_abstract_v1,AbsCode} -> + %% HACK: Add a declaration for iolist() to every module + {ok, add_iolist(AbsCode), sets:from_list(ExpFunsList)}; + no_abstract_code -> + {error, no_abstract_code}; + _ -> + {error, unsupported_abstract_code_format} + end; + {error,beam_lib,Reason} -> + {error, Reason} + end. + +-spec add_iolist([abs_form()]) -> [abs_form()]. +add_iolist(Forms) -> + IOListDef = + {type,0,maybe_improper_list, + [{type,0,union,[{type,0,byte,[]},{type,0,binary,[]}, + {type,0,iolist,[]}]}, + {type,0,binary,[]}]}, + IOListDecl = {attribute,0,type,{iolist,IOListDef,[]}}, + [IOListDecl | Forms]. + +-spec get_mod_info(mod_name(), [abs_form()], mod_exp_funs()) -> mod_info(). +get_mod_info(Mod, AbsCode, ModExpFuns) -> + StartModInfo = #mod_info{mod_exp_funs = ModExpFuns}, + ImmModInfo = lists:foldl(fun add_mod_info/2, StartModInfo, AbsCode), + #mod_info{mod_specs = AllModSpecs} = ImmModInfo, + IsExported = fun(FunRef,_FunRepr) -> sets:is_element(FunRef,ModExpFuns) end, + ModExpSpecs = dict:filter(IsExported, AllModSpecs), + ModInfo = ImmModInfo#mod_info{mod_specs = ModExpSpecs}, + case orddict:find(Mod, ?HARD_ADT_MODS) of + {ok,ModADTs} -> + #mod_info{mod_exp_types = ModExpTypes, mod_types = ModTypes, + mod_opaques = ModOpaques} = ModInfo, + ModADTsSet = + sets:from_list([ImmTypeRef + || {ImmTypeRef,_HardADTRepr} <- ModADTs]), + NewModExpTypes = sets:union(ModExpTypes, ModADTsSet), + NewModTypes = lists:foldl(fun store_hard_adt/2, ModTypes, ModADTs), + NewModOpaques = sets:union(ModOpaques, ModADTsSet), + ModInfo#mod_info{mod_exp_types = NewModExpTypes, + mod_types = NewModTypes, + mod_opaques = NewModOpaques}; + error -> + ModInfo + end. + +-spec store_hard_adt({imm_type_ref(),hard_adt_repr()}, mod_types()) -> + mod_types(). +store_hard_adt({_ImmTypeRef,already_declared}, ModTypes) -> + ModTypes; +store_hard_adt({{Name,Arity},{TypeForm,VarNames}}, ModTypes) -> + TypeRef = {type,Name,Arity}, + TypeRepr = {abs_type,TypeForm,VarNames,not_symb}, + dict:store(TypeRef, TypeRepr, ModTypes). + +-spec add_mod_info(abs_form(), mod_info()) -> mod_info(). +add_mod_info({attribute,_Line,export_type,TypesList}, + #mod_info{mod_exp_types = ModExpTypes} = ModInfo) -> + NewModExpTypes = sets:union(sets:from_list(TypesList), ModExpTypes), + ModInfo#mod_info{mod_exp_types = NewModExpTypes}; +add_mod_info({attribute,_Line,type,{{record,RecName},Fields,[]}}, + #mod_info{mod_types = ModTypes} = ModInfo) -> + FieldInfo = [process_rec_field(F) || F <- Fields], + NewModTypes = dict:store({record,RecName,0}, {abs_record,FieldInfo}, + ModTypes), + ModInfo#mod_info{mod_types = NewModTypes}; +add_mod_info({attribute,_Line,record,{RecName,Fields}}, + #mod_info{mod_types = ModTypes} = ModInfo) -> + case dict:is_key(RecName, ModTypes) of + true -> + ModInfo; + false -> + TypedRecord = {attribute,0,type,{{record,RecName},Fields,[]}}, + add_mod_info(TypedRecord, ModInfo) + end; +add_mod_info({attribute,_Line,Kind,{Name,TypeForm,VarForms}}, + #mod_info{mod_types = ModTypes, + mod_opaques = ModOpaques} = ModInfo) + when Kind =:= type; Kind =:= opaque -> + Arity = length(VarForms), + VarNames = [V || {var,_,V} <- VarForms], + %% TODO: No check whether variables are different, or non-'_'. + NewModTypes = dict:store({type,Name,Arity}, + {abs_type,TypeForm,VarNames,not_symb}, ModTypes), + NewModOpaques = + case Kind of + type -> ModOpaques; + opaque -> sets:add_element({Name,Arity}, ModOpaques) + end, + ModInfo#mod_info{mod_types = NewModTypes, mod_opaques = NewModOpaques}; +add_mod_info({attribute,_Line,spec,{RawFunRef,[RawFirstClause | _Rest]}}, + #mod_info{mod_specs = ModSpecs} = ModInfo) -> + FunRef = case RawFunRef of + {_Mod,Name,Arity} -> {Name,Arity}; + {_Name,_Arity} = F -> F + end, + %% TODO: We just take the first function clause. + FirstClause = process_fun_clause(RawFirstClause), + NewModSpecs = dict:store(FunRef, FirstClause, ModSpecs), + ModInfo#mod_info{mod_specs = NewModSpecs}; +add_mod_info(_Form, ModInfo) -> + ModInfo. + +-spec process_rec_field(abs_rec_field()) -> {field_name(),abs_type()}. +process_rec_field({record_field,_,{atom,_,FieldName}}) -> + {FieldName, {type,0,any,[]}}; +process_rec_field({record_field,_,{atom,_,FieldName},_Initialization}) -> + {FieldName, {type,0,any,[]}}; +process_rec_field({typed_record_field,RecField,FieldType}) -> + {FieldName,_} = process_rec_field(RecField), + {FieldName, FieldType}. + +-spec process_fun_clause(abs_type()) -> fun_clause_repr(). +process_fun_clause({type,_,'fun',[{type,_,product,Domain},Range]}) -> + {Domain, Range}; +process_fun_clause({type,_,bounded_fun,[MainClause,Constraints]}) -> + {RawDomain,RawRange} = process_fun_clause(MainClause), + VarSubsts = [{V,T} || {type,_,constraint, + [{atom,_,is_subtype},[{var,_,V},T]]} <- Constraints, + V =/= '_'], + VarSubstsDict = dict:from_list(VarSubsts), + Domain = [update_vars(A, VarSubstsDict, false) || A <- RawDomain], + Range = update_vars(RawRange, VarSubstsDict, false), + {Domain, Range}. + +-spec store_mod_info(mod_name(), mod_info(), state()) -> state(). +store_mod_info(Mod, #mod_info{mod_exp_types = ModExpTypes, mod_types = ModTypes, + mod_specs = ImmModExpSpecs}, + #state{exp_types = ExpTypes, types = Types, + exp_specs = ExpSpecs} = State) -> + NewExpTypes = dict:store(Mod, ModExpTypes, ExpTypes), + NewTypes = dict:store(Mod, ModTypes, Types), + ModExpSpecs = dict:map(fun unbound_to_any/2, ImmModExpSpecs), + NewExpSpecs = dict:store(Mod, ModExpSpecs, ExpSpecs), + State#state{exp_types = NewExpTypes, types = NewTypes, + exp_specs = NewExpSpecs}. + +-spec unbound_to_any(fun_ref(), fun_repr()) -> fun_repr(). +unbound_to_any(_FunRef, {Domain,Range}) -> + EmptySubstsDict = dict:new(), + NewDomain = [update_vars(A,EmptySubstsDict,true) || A <- Domain], + NewRange = update_vars(Range, EmptySubstsDict, true), + {NewDomain, NewRange}. + + +%%------------------------------------------------------------------------------ +%% ADT translation functions +%%------------------------------------------------------------------------------ + +-spec process_adts(mod_name(), mod_info()) -> mod_info(). +process_adts(Mod, + #mod_info{mod_exp_types = ModExpTypes, mod_opaques = ModOpaques, + mod_specs = ModExpSpecs} = ModInfo) -> + %% TODO: No warning on unexported opaques. + case sets:to_list(sets:intersection(ModExpTypes,ModOpaques)) of + [] -> + ModInfo; + ModADTs -> + %% TODO: No warning on unexported API functions. + ModExpSpecsList = [{Name,Domain,Range} + || {{Name,_Arity},{Domain,Range}} + <- dict:to_list(ModExpSpecs)], + AddADT = fun(ADT,Acc) -> add_adt(Mod,ADT,Acc,ModExpSpecsList) end, + lists:foldl(AddADT, ModInfo, ModADTs) + end. + +-spec add_adt(mod_name(), imm_type_ref(), mod_info(), [proc_fun_ref()]) -> + mod_info(). +add_adt(Mod, {Name,Arity}, #mod_info{mod_types = ModTypes} = ModInfo, + ModExpFunSpecs) -> + ADTRef = {type,Name,Arity}, + {abs_type,InternalRepr,VarNames,not_symb} = dict:fetch(ADTRef, ModTypes), + FullADTRef = {Mod,Name,Arity}, + %% TODO: No warning on unsuitable range. + SymbCalls1 = [get_symb_call(FullADTRef,Spec) || Spec <- ModExpFunSpecs], + %% TODO: No warning on bad use of variables. + SymbCalls2 = [fix_vars(FullADTRef,Call,RangeVars,VarNames) + || {ok,Call,RangeVars} <- SymbCalls1], + case [Call || {ok,Call} <- SymbCalls2] of + [] -> + %% TODO: No warning on no acceptable spec. + ModInfo; + SymbCalls3 -> + NewADTRepr = {abs_type,{type,0,union,SymbCalls3},VarNames, + {orig_abs,InternalRepr}}, + NewModTypes = dict:store(ADTRef, NewADTRepr, ModTypes), + ModInfo#mod_info{mod_types = NewModTypes} + end. + +-spec get_symb_call(full_imm_type_ref(), proc_fun_ref()) -> + tagged_result2(abs_type(),[var_name()]). +get_symb_call({Mod,_TypeName,_Arity} = FullADTRef, {FunName,Domain,Range}) -> + BaseCall = {type,0,tuple,[{atom,0,'$call'},{atom,0,Mod},{atom,0,FunName}, + {type,0,'$fixed_list',Domain}]}, + unwrap_range(FullADTRef, BaseCall, Range, false). + +-spec unwrap_range(full_imm_type_ref(), abs_type() | next_step(), abs_type(), + boolean()) -> + tagged_result2(abs_type() | next_step(),[var_name()]). +unwrap_range(FullADTRef, Call, {paren_type,_,[Type]}, TestRun) -> + unwrap_range(FullADTRef, Call, Type, TestRun); +unwrap_range(FullADTRef, Call, {ann_type,_,[_Var,Type]}, TestRun) -> + unwrap_range(FullADTRef, Call, Type, TestRun); +unwrap_range(FullADTRef, Call, {type,_,list,[ElemType]}, TestRun) -> + unwrap_list(FullADTRef, Call, ElemType, TestRun); +unwrap_range(FullADTRef, Call, {type,_,maybe_improper_list,[Cont,_Term]}, + TestRun) -> + unwrap_list(FullADTRef, Call, Cont, TestRun); +unwrap_range(FullADTRef, Call, {type,_,nonempty_list,[ElemType]}, TestRun) -> + unwrap_list(FullADTRef, Call, ElemType, TestRun); +unwrap_range(FullADTRef, Call, {type,_,nonempty_improper_list,[Cont,_Term]}, + TestRun) -> + unwrap_list(FullADTRef, Call, Cont, TestRun); +unwrap_range(FullADTRef, Call, + {type,_,nonempty_maybe_improper_list,[Cont,_Term]}, TestRun) -> + unwrap_list(FullADTRef, Call, Cont, TestRun); +unwrap_range(_FullADTRef, _Call, {type,_,tuple,any}, _TestRun) -> + error; +unwrap_range(FullADTRef, Call, {type,_,tuple,FieldForms}, TestRun) -> + Translates = fun(T) -> unwrap_range(FullADTRef,none,T,true) =/= error end, + case proper_arith:find_first(Translates, FieldForms) of + none -> + error; + {TargetPos,TargetElem} -> + Pattern = get_pattern(TargetPos, FieldForms), + case TestRun of + true -> + NewCall = + case Call of + none -> {match_with,Pattern}; + _ -> Call + end, + {ok, NewCall, []}; + false -> + AbsPattern = term_to_singleton_type(Pattern), + NewCall = + {type,0,tuple, + [{atom,0,'$call'},{atom,0,?MODULE},{atom,0,match}, + {type,0,'$fixed_list',[AbsPattern,Call]}]}, + unwrap_range(FullADTRef, NewCall, TargetElem, TestRun) + end + end; +unwrap_range(FullADTRef, Call, {type,_,union,Choices}, TestRun) -> + TestedChoices = [unwrap_range(FullADTRef,none,C,true) || C <- Choices], + NotError = fun(error) -> false; (_) -> true end, + case proper_arith:find_first(NotError, TestedChoices) of + none -> + error; + {_ChoicePos,{ok,none,_RangeVars}} -> + error; + {ChoicePos,{ok,NextStep,_RangeVars}} -> + {A, [ChoiceElem|B]} = lists:split(ChoicePos-1, Choices), + OtherChoices = A ++ B, + DistinctChoice = + case NextStep of + take_head -> + fun cant_have_head/1; + {match_with,Pattern} -> + fun(C) -> cant_match(Pattern, C) end + end, + case {lists:all(DistinctChoice,OtherChoices), TestRun} of + {true,true} -> + {ok, NextStep, []}; + {true,false} -> + unwrap_range(FullADTRef, Call, ChoiceElem, TestRun); + {false,_} -> + error + end + end; +unwrap_range({_Mod,SameName,Arity}, Call, {type,_,SameName,ArgForms}, + _TestRun) -> + RangeVars = [V || {var,_,V} <- ArgForms, V =/= '_'], + case length(ArgForms) =:= Arity andalso length(RangeVars) =:= Arity of + true -> {ok, Call, RangeVars}; + false -> error + end; +unwrap_range({SameMod,SameName,_Arity} = FullADTRef, Call, + {remote_type,_,[{atom,_,SameMod},{atom,_,SameName},ArgForms]}, + TestRun) -> + unwrap_range(FullADTRef, Call, {type,0,SameName,ArgForms}, TestRun); +unwrap_range(_FullADTRef, _Call, _Range, _TestRun) -> + error. + +-spec unwrap_list(full_imm_type_ref(), abs_type() | next_step(), abs_type(), + boolean()) -> + tagged_result2(abs_type() | next_step(),[var_name()]). +unwrap_list(FullADTRef, Call, HeadType, TestRun) -> + NewCall = + case TestRun of + true -> + case Call of + none -> take_head; + _ -> Call + end; + false -> + {type,0,tuple,[{atom,0,'$call'},{atom,0,erlang},{atom,0,hd}, + {type,0,'$fixed_list',[Call]}]} + end, + unwrap_range(FullADTRef, NewCall, HeadType, TestRun). + +-spec fix_vars(full_imm_type_ref(), abs_type(), [var_name()], [var_name()]) -> + tagged_result(abs_type()). +fix_vars(FullADTRef, Call, RangeVars, VarNames) -> + NotAnyVar = fun(V) -> V =/= '_' end, + case no_duplicates(VarNames) andalso lists:all(NotAnyVar,VarNames) of + true -> + RawUsedVars = + collect_vars(FullADTRef, Call, [[V] || V <- RangeVars]), + UsedVars = [lists:usort(L) || L <- RawUsedVars], + case correct_var_use(UsedVars) of + true -> + PairAll = fun(L,Y) -> [{X,{var,0,Y}} || X <- L] end, + VarSubsts = + lists:flatten(lists:zipwith(PairAll,UsedVars,VarNames)), + VarSubstsDict = dict:from_list(VarSubsts), + {ok, update_vars(Call,VarSubstsDict,true)}; + false -> + error + end; + false -> + error + end. + +-spec no_duplicates(list()) -> boolean(). +no_duplicates(L) -> + length(lists:usort(L)) =:= length(L). + +-spec correct_var_use([[var_name() | 0]]) -> boolean(). +correct_var_use(UsedVars) -> + NoNonVarArgs = fun([0|_]) -> false; (_) -> true end, + lists:all(NoNonVarArgs, UsedVars) + andalso no_duplicates(lists:flatten(UsedVars)). + +-spec collect_vars(full_imm_type_ref(), abs_type(), [[var_name() | 0]]) -> + [[var_name() | 0]]. +collect_vars(FullADTRef, {paren_type,_,[Type]}, UsedVars) -> + collect_vars(FullADTRef, Type, UsedVars); +collect_vars(FullADTRef, {ann_type,_,[_Var,Type]}, UsedVars) -> + collect_vars(FullADTRef, Type, UsedVars); +collect_vars(_FullADTRef, {type,_,tuple,any}, UsedVars) -> + UsedVars; +collect_vars({_Mod,SameName,Arity} = FullADTRef, {type,_,SameName,ArgForms}, + UsedVars) -> + case length(ArgForms) =:= Arity of + true -> + VarArgs = [V || {var,_,V} <- ArgForms, V =/= '_'], + case length(VarArgs) =:= Arity of + true -> + AddToList = fun(X,L) -> [X | L] end, + lists:zipwith(AddToList, VarArgs, UsedVars); + false -> + [[0|L] || L <- UsedVars] + end; + false -> + multi_collect_vars(FullADTRef, ArgForms, UsedVars) + end; +collect_vars(FullADTRef, {type,_,_Name,ArgForms}, UsedVars) -> + multi_collect_vars(FullADTRef, ArgForms, UsedVars); +collect_vars({SameMod,SameName,_Arity} = FullADTRef, + {remote_type,_,[{atom,_,SameMod},{atom,_,SameName},ArgForms]}, + UsedVars) -> + collect_vars(FullADTRef, {type,0,SameName,ArgForms}, UsedVars); +collect_vars(FullADTRef, {remote_type,_,[_RemModForm,_NameForm,ArgForms]}, + UsedVars) -> + multi_collect_vars(FullADTRef, ArgForms, UsedVars); +collect_vars(_FullADTRef, _Call, UsedVars) -> + UsedVars. + +-spec multi_collect_vars(full_imm_type_ref(), [abs_type()], + [[var_name() | 0]]) -> [[var_name() | 0]]. +multi_collect_vars({_Mod,_Name,Arity} = FullADTRef, Forms, UsedVars) -> + NoUsedVars = lists:duplicate(Arity, []), + MoreUsedVars = [collect_vars(FullADTRef,T,NoUsedVars) || T <- Forms], + CombineVars = fun(L1,L2) -> lists:zipwith(fun erlang:'++'/2, L1, L2) end, + lists:foldl(CombineVars, UsedVars, MoreUsedVars). + +-ifdef(NO_MODULES_IN_OPAQUES). +-type var_substs_dict() :: dict(). +-else. +-type var_substs_dict() :: dict:dict(var_name(),abs_type()). +-endif. +-spec update_vars(abs_type(), var_substs_dict(), boolean()) -> abs_type(). +update_vars({paren_type,Line,[Type]}, VarSubstsDict, UnboundToAny) -> + {paren_type, Line, [update_vars(Type,VarSubstsDict,UnboundToAny)]}; +update_vars({ann_type,Line,[Var,Type]}, VarSubstsDict, UnboundToAny) -> + {ann_type, Line, [Var,update_vars(Type,VarSubstsDict,UnboundToAny)]}; +update_vars({var,Line,VarName} = Call, VarSubstsDict, UnboundToAny) -> + case dict:find(VarName, VarSubstsDict) of + {ok,SubstType} -> + SubstType; + error when UnboundToAny =:= false -> + Call; + error when UnboundToAny =:= true -> + {type,Line,any,[]} + end; +update_vars({remote_type,Line,[RemModForm,NameForm,ArgForms]}, VarSubstsDict, + UnboundToAny) -> + NewArgForms = [update_vars(A,VarSubstsDict,UnboundToAny) || A <- ArgForms], + {remote_type, Line, [RemModForm,NameForm,NewArgForms]}; +update_vars({type,_,tuple,any} = Call, _VarSubstsDict, _UnboundToAny) -> + Call; +update_vars({type,Line,Name,ArgForms}, VarSubstsDict, UnboundToAny) -> + {type, Line, Name, [update_vars(A,VarSubstsDict,UnboundToAny) + || A <- ArgForms]}; +update_vars(Call, _VarSubstsDict, _UnboundToAny) -> + Call. + + +%%------------------------------------------------------------------------------ +%% Match-related functions +%%------------------------------------------------------------------------------ + +-spec get_pattern(position(), [abs_type()]) -> pattern(). +get_pattern(TargetPos, FieldForms) -> + {0,RevPattern} = lists:foldl(fun add_field/2, {TargetPos,[]}, FieldForms), + list_to_tuple(lists:reverse(RevPattern)). + +-spec add_field(abs_type(), {non_neg_integer(),[pat_field()]}) -> + {non_neg_integer(),[pat_field(),...]}. +add_field(_Type, {1,Acc}) -> + {0, [1|Acc]}; +add_field({atom,_,Tag}, {Left,Acc}) -> + {erlang:max(0,Left-1), [Tag|Acc]}; +add_field(_Type, {Left,Acc}) -> + {erlang:max(0,Left-1), [0|Acc]}. + +%% @private +-spec match(pattern(), tuple()) -> term(). +match(Pattern, Term) when tuple_size(Pattern) =:= tuple_size(Term) -> + match(tuple_to_list(Pattern), tuple_to_list(Term), none, false); +match(_Pattern, _Term) -> + throw(no_match). + +-spec match([pat_field()], [term()], 'none' | {'ok',T}, boolean()) -> T. +match([], [], {ok,Target}, _TypeMode) -> + Target; +match([0|PatRest], [_|ToMatchRest], Acc, TypeMode) -> + match(PatRest, ToMatchRest, Acc, TypeMode); +match([1|PatRest], [Target|ToMatchRest], none, TypeMode) -> + match(PatRest, ToMatchRest, {ok,Target}, TypeMode); +match([Tag|PatRest], [X|ToMatchRest], Acc, TypeMode) when is_atom(Tag) -> + MatchesTag = + case TypeMode of + true -> can_be_tag(Tag, X); + false -> Tag =:= X + end, + case MatchesTag of + true -> match(PatRest, ToMatchRest, Acc, TypeMode); + false -> throw(no_match) + end. + +%% CAUTION: these must be sorted +-define(NON_ATOM_TYPES, + [arity,binary,bitstring,byte,char,float,'fun',function,integer,iodata, + iolist,list,maybe_improper_list,mfa,neg_integer,nil,no_return, + non_neg_integer,none,nonempty_improper_list,nonempty_list, + nonempty_maybe_improper_list,nonempty_string,number,pid,port, + pos_integer,range,record,reference,string,tuple]). +-define(NON_TUPLE_TYPES, + [arity,atom,binary,bitstring,bool,boolean,byte,char,float,'fun', + function,identifier,integer,iodata,iolist,list,maybe_improper_list, + neg_integer,nil,no_return,node,non_neg_integer,none, + nonempty_improper_list,nonempty_list,nonempty_maybe_improper_list, + nonempty_string,number,pid,port,pos_integer,range,reference,string, + timeout]). +-define(NO_HEAD_TYPES, + [arity,atom,binary,bitstring,bool,boolean,byte,char,float,'fun', + function,identifier,integer,mfa,module,neg_integer,nil,no_return,node, + non_neg_integer,none,number,pid,port,pos_integer,range,record, + reference,timeout,tuple]). + +-spec can_be_tag(atom(), abs_type()) -> boolean(). +can_be_tag(Tag, {ann_type,_,[_Var,Type]}) -> + can_be_tag(Tag, Type); +can_be_tag(Tag, {paren_type,_,[Type]}) -> + can_be_tag(Tag, Type); +can_be_tag(Tag, {atom,_,Atom}) -> + Tag =:= Atom; +can_be_tag(_Tag, {integer,_,_Int}) -> + false; +can_be_tag(_Tag, {op,_,_Op,_Arg}) -> + false; +can_be_tag(_Tag, {op,_,_Op,_Arg1,_Arg2}) -> + false; +can_be_tag(Tag, {type,_,BName,[]}) when BName =:= bool; BName =:= boolean -> + is_boolean(Tag); +can_be_tag(Tag, {type,_,timeout,[]}) -> + Tag =:= infinity; +can_be_tag(Tag, {type,_,union,Choices}) -> + lists:any(fun(C) -> can_be_tag(Tag,C) end, Choices); +can_be_tag(_Tag, {type,_,Name,_Args}) -> + not ordsets:is_element(Name, ?NON_ATOM_TYPES); +can_be_tag(_Tag, _Type) -> + true. + +-spec cant_match(pattern(), abs_type()) -> boolean(). +cant_match(Pattern, {ann_type,_,[_Var,Type]}) -> + cant_match(Pattern, Type); +cant_match(Pattern, {paren_type,_,[Type]}) -> + cant_match(Pattern, Type); +cant_match(_Pattern, {atom,_,_Atom}) -> + true; +cant_match(_Pattern, {integer,_,_Int}) -> + true; +cant_match(_Pattern, {op,_,_Op,_Arg}) -> + true; +cant_match(_Pattern, {op,_,_Op,_Arg1,_Arg2}) -> + true; +cant_match(Pattern, {type,_,mfa,[]}) -> + cant_match(Pattern, {type,0,tuple,[{type,0,atom,[]},{type,0,atom,[]}, + {type,0,arity,[]}]}); +cant_match(Pattern, {type,_,union,Choices}) -> + lists:all(fun(C) -> cant_match(Pattern,C) end, Choices); +cant_match(_Pattern, {type,_,tuple,any}) -> + false; +cant_match(Pattern, {type,_,tuple,Fields}) -> + tuple_size(Pattern) =/= length(Fields) orelse + try match(tuple_to_list(Pattern), Fields, none, true) of + _ -> false + catch + throw:no_match -> true + end; +cant_match(_Pattern, {type,_,Name,_Args}) -> + ordsets:is_element(Name, ?NON_TUPLE_TYPES); +cant_match(_Pattern, _Type) -> + false. + +-spec cant_have_head(abs_type()) -> boolean(). +cant_have_head({ann_type,_,[_Var,Type]}) -> + cant_have_head(Type); +cant_have_head({paren_type,_,[Type]}) -> + cant_have_head(Type); +cant_have_head({atom,_,_Atom}) -> + true; +cant_have_head({integer,_,_Int}) -> + true; +cant_have_head({op,_,_Op,_Arg}) -> + true; +cant_have_head({op,_,_Op,_Arg1,_Arg2}) -> + true; +cant_have_head({type,_,union,Choices}) -> + lists:all(fun cant_have_head/1, Choices); +cant_have_head({type,_,Name,_Args}) -> + ordsets:is_element(Name, ?NO_HEAD_TYPES); +cant_have_head(_Type) -> + false. + +%% Only covers atoms, integers and tuples, i.e. those that can be specified +%% through singleton types. +-spec term_to_singleton_type(atom() | integer() + | loose_tuple(atom() | integer())) -> abs_type(). +term_to_singleton_type(Atom) when is_atom(Atom) -> + {atom,0,Atom}; +term_to_singleton_type(Int) when is_integer(Int), Int >= 0 -> + {integer,0,Int}; +term_to_singleton_type(Int) when is_integer(Int), Int < 0 -> + {op,0,'-',{integer,0,-Int}}; +term_to_singleton_type(Tuple) when is_tuple(Tuple) -> + Fields = tuple_to_list(Tuple), + {type,0,tuple,[term_to_singleton_type(F) || F <- Fields]}. + + +%%------------------------------------------------------------------------------ +%% Instance testing functions +%%------------------------------------------------------------------------------ + +%% CAUTION: this must be sorted +-define(EQUIV_TYPES, + [{arity, {type,0,range,[{integer,0,0},{integer,0,255}]}}, + {bool, {type,0,boolean,[]}}, + {byte, {type,0,range,[{integer,0,0},{integer,0,255}]}}, + {char, {type,0,range,[{integer,0,0},{integer,0,16#10ffff}]}}, + {function, {type,0,'fun',[]}}, + {identifier, {type,0,union,[{type,0,pid,[]},{type,0,port,[]}, + {type,0,reference,[]}]}}, + {iodata, {type,0,union,[{type,0,binary,[]},{type,0,iolist,[]}]}}, + {iolist, {type,0,maybe_improper_list, + [{type,0,union,[{type,0,byte,[]},{type,0,binary,[]}, + {type,0,iolist,[]}]}, + {type,0,binary,[]}]}}, + {list, {type,0,list,[{type,0,any,[]}]}}, + {maybe_improper_list, {type,0,maybe_improper_list,[{type,0,any,[]}, + {type,0,any,[]}]}}, + {mfa, {type,0,tuple,[{type,0,atom,[]},{type,0,atom,[]}, + {type,0,arity,[]}]}}, + {node, {type,0,atom,[]}}, + {nonempty_list, {type,0,nonempty_list,[{type,0,any,[]}]}}, + {nonempty_maybe_improper_list, {type,0,nonempty_maybe_improper_list, + [{type,0,any,[]},{type,0,any,[]}]}}, + {nonempty_string, {type,0,nonempty_list,[{type,0,char,[]}]}}, + {string, {type,0,list,[{type,0,char,[]}]}}, + {term, {type,0,any,[]}}, + {timeout, {type,0,union,[{atom,0,infinity}, + {type,0,non_neg_integer,[]}]}}]). + +%% @private +%% TODO: Most of these functions accept an extended form of abs_type(), namely +%% the addition of a custom wrapper: {'from_mod',mod_name(),...} +-spec is_instance(term(), mod_name(), abs_type()) -> boolean(). +is_instance(X, Mod, TypeForm) -> + is_instance(X, Mod, TypeForm, []). + +-spec is_instance(term(), mod_name(), abs_type(), imm_stack()) -> boolean(). +is_instance(X, _Mod, {from_mod,OrigMod,Type}, Stack) -> + is_instance(X, OrigMod, Type, Stack); +is_instance(_X, _Mod, {var,_,'_'}, _Stack) -> + true; +is_instance(_X, _Mod, {var,_,Name}, _Stack) -> + %% All unconstrained spec vars have been replaced by 'any()' and we always + %% replace the variables on the RHS of types before recursing into them. + %% Provided that '-type' declarations contain no unbound variables, we + %% don't expect to find any non-'_' variables while recursing. + throw({'$typeserver',{unbound_var_in_type_declaration,Name}}); +is_instance(X, Mod, {ann_type,_,[_Var,Type]}, Stack) -> + is_instance(X, Mod, Type, Stack); +is_instance(X, Mod, {paren_type,_,[Type]}, Stack) -> + is_instance(X, Mod, Type, Stack); +is_instance(X, Mod, {remote_type,_,[{atom,_,RemMod},{atom,_,Name},ArgForms]}, + Stack) -> + is_custom_instance(X, Mod, RemMod, Name, ArgForms, true, Stack); +is_instance(SameAtom, _Mod, {atom,_,SameAtom}, _Stack) -> + true; +is_instance(SameInt, _Mod, {integer,_,SameInt}, _Stack) -> + true; +is_instance(X, _Mod, {op,_,_Op,_Arg} = Expr, _Stack) -> + is_int_const(X, Expr); +is_instance(X, _Mod, {op,_,_Op,_Arg1,_Arg2} = Expr, _Stack) -> + is_int_const(X, Expr); +is_instance(_X, _Mod, {type,_,any,[]}, _Stack) -> + true; +is_instance(X, _Mod, {type,_,atom,[]}, _Stack) -> + is_atom(X); +is_instance(X, _Mod, {type,_,binary,[]}, _Stack) -> + is_binary(X); +is_instance(X, _Mod, {type,_,binary,[BaseExpr,UnitExpr]}, _Stack) -> + %% <<_:X,_:_*Y>> means "bitstrings of X + k*Y bits, k >= 0" + case eval_int(BaseExpr) of + {ok,Base} when Base >= 0 -> + case eval_int(UnitExpr) of + {ok,Unit} when Unit >= 0 -> + case is_bitstring(X) of + true -> + BitSizeX = bit_size(X), + case Unit =:= 0 of + true -> + BitSizeX =:= Base; + false -> + BitSizeX >= Base + andalso + (BitSizeX - Base) rem Unit =:= 0 + end; + false -> false + end; + _ -> + abs_expr_error(invalid_unit, UnitExpr) + end; + _ -> + abs_expr_error(invalid_base, BaseExpr) + end; +is_instance(X, _Mod, {type,_,bitstring,[]}, _Stack) -> + is_bitstring(X); +is_instance(X, _Mod, {type,_,boolean,[]}, _Stack) -> + is_boolean(X); +is_instance(X, _Mod, {type,_,float,[]}, _Stack) -> + is_float(X); +is_instance(X, _Mod, {type,_,'fun',[]}, _Stack) -> + is_function(X); +%% TODO: how to check range type? random inputs? special case for 0-arity? +is_instance(X, _Mod, {type,_,'fun',[{type,_,any,[]},_Range]}, _Stack) -> + is_function(X); +is_instance(X, _Mod, {type,_,'fun',[{type,_,product,Domain},_Range]}, _Stack) -> + is_function(X, length(Domain)); +is_instance(X, _Mod, {type,_,integer,[]}, _Stack) -> + is_integer(X); +is_instance(X, Mod, {type,_,list,[Type]}, _Stack) -> + list_test(X, Mod, Type, dummy, true, true, false); +is_instance(X, Mod, {type,_,maybe_improper_list,[Cont,Term]}, _Stack) -> + list_test(X, Mod, Cont, Term, true, true, true); +is_instance(X, _Mod, {type,_,module,[]}, _Stack) -> + is_atom(X) orelse + is_tuple(X) andalso X =/= {} andalso is_atom(element(1,X)); +is_instance([], _Mod, {type,_,nil,[]}, _Stack) -> + true; +is_instance(X, _Mod, {type,_,neg_integer,[]}, _Stack) -> + is_integer(X) andalso X < 0; +is_instance(X, _Mod, {type,_,non_neg_integer,[]}, _Stack) -> + is_integer(X) andalso X >= 0; +is_instance(X, Mod, {type,_,nonempty_list,[Type]}, _Stack) -> + list_test(X, Mod, Type, dummy, false, true, false); +is_instance(X, Mod, {type,_,nonempty_improper_list,[Cont,Term]}, _Stack) -> + list_test(X, Mod, Cont, Term, false, false, true); +is_instance(X, Mod, {type,_,nonempty_maybe_improper_list,[Cont,Term]}, + _Stack) -> + list_test(X, Mod, Cont, Term, false, true, true); +is_instance(X, _Mod, {type,_,number,[]}, _Stack) -> + is_number(X); +is_instance(X, _Mod, {type,_,pid,[]}, _Stack) -> + is_pid(X); +is_instance(X, _Mod, {type,_,port,[]}, _Stack) -> + is_port(X); +is_instance(X, _Mod, {type,_,pos_integer,[]}, _Stack) -> + is_integer(X) andalso X > 0; +is_instance(_X, _Mod, {type,_,product,_Elements}, _Stack) -> + throw({'$typeserver',{internal,product_in_is_instance}}); +is_instance(X, _Mod, {type,_,range,[LowExpr,HighExpr]}, _Stack) -> + case {eval_int(LowExpr),eval_int(HighExpr)} of + {{ok,Low},{ok,High}} when Low =< High -> + X >= Low andalso X =< High; + _ -> + abs_expr_error(invalid_range, LowExpr, HighExpr) + end; +is_instance(X, Mod, {type,_,record,[{atom,_,Name} = NameForm | RawSubsts]}, + Stack) -> + Substs = [{N,T} || {type,_,field_type,[{atom,_,N},T]} <- RawSubsts], + SubstsDict = dict:from_list(Substs), + case get_type_repr(Mod, {record,Name,0}, false) of + {ok,{abs_record,OrigFields}} -> + Fields = [case dict:find(FieldName, SubstsDict) of + {ok,NewFieldType} -> NewFieldType; + error -> OrigFieldType + end + || {FieldName,OrigFieldType} <- OrigFields], + is_instance(X, Mod, {type,0,tuple,[NameForm|Fields]}, Stack); + {error,Reason} -> + throw({'$typeserver',Reason}) + end; +is_instance(X, _Mod, {type,_,reference,[]}, _Stack) -> + is_reference(X); +is_instance(X, _Mod, {type,_,tuple,any}, _Stack) -> + is_tuple(X); +is_instance(X, Mod, {type,_,tuple,Fields}, _Stack) -> + is_tuple(X) andalso tuple_test(tuple_to_list(X), Mod, Fields); +is_instance(X, Mod, {type,_,union,Choices}, Stack) -> + IsInstance = fun(Choice) -> is_instance(X,Mod,Choice,Stack) end, + lists:any(IsInstance, Choices); +is_instance(X, Mod, {type,_,Name,[]}, Stack) -> + case orddict:find(Name, ?EQUIV_TYPES) of + {ok,EquivType} -> + is_instance(X, Mod, EquivType, Stack); + error -> + is_maybe_hard_adt(X, Mod, Name, [], Stack) + end; +is_instance(X, Mod, {type,_,Name,ArgForms}, Stack) -> + is_maybe_hard_adt(X, Mod, Name, ArgForms, Stack); +is_instance(_X, _Mod, _Type, _Stack) -> + false. + +-spec is_int_const(term(), abs_expr()) -> boolean(). +is_int_const(X, Expr) -> + case eval_int(Expr) of + {ok,Int} -> + X =:= Int; + error -> + abs_expr_error(invalid_int_const, Expr) + end. + +%% TODO: We implicitly add the '| []' at the termination of maybe_improper_list. +%% TODO: We ignore a '[]' termination in improper_list. +-spec list_test(term(), mod_name(), abs_type(), 'dummy' | abs_type(), boolean(), + boolean(), boolean()) -> boolean(). +list_test(X, Mod, Content, Termination, CanEmpty, CanProper, CanImproper) -> + is_list(X) andalso + list_rec(X, Mod, Content, Termination, CanEmpty, CanProper, CanImproper). + +-spec list_rec(term(), mod_name(), abs_type(), 'dummy' | abs_type(), boolean(), + boolean(), boolean()) -> boolean(). +list_rec([], _Mod, _Content, _Termination, CanEmpty, CanProper, _CanImproper) -> + CanEmpty andalso CanProper; +list_rec([X | Rest], Mod, Content, Termination, _CanEmpty, CanProper, + CanImproper) -> + is_instance(X, Mod, Content, []) andalso + list_rec(Rest, Mod, Content, Termination, true, CanProper, CanImproper); +list_rec(X, Mod, _Content, Termination, _CanEmpty, _CanProper, CanImproper) -> + CanImproper andalso is_instance(X, Mod, Termination, []). + +-spec tuple_test([term()], mod_name(), [abs_type()]) -> boolean(). +tuple_test([], _Mod, []) -> + true; +tuple_test([X | XTail], Mod, [T | TTail]) -> + is_instance(X, Mod, T, []) andalso tuple_test(XTail, Mod, TTail); +tuple_test(_, _Mod, _) -> + false. + +-spec is_maybe_hard_adt(term(), mod_name(), type_name(), [abs_type()], + imm_stack()) -> boolean(). +is_maybe_hard_adt(X, Mod, Name, ArgForms, Stack) -> + case orddict:find({Name,length(ArgForms)}, ?HARD_ADTS) of + {ok,ADTMod} -> + is_custom_instance(X, Mod, ADTMod, Name, ArgForms, true, Stack); + error -> + is_custom_instance(X, Mod, Mod, Name, ArgForms, false, Stack) + end. + +-spec is_custom_instance(term(), mod_name(), mod_name(), type_name(), + [abs_type()], boolean(), imm_stack()) -> boolean(). +is_custom_instance(X, Mod, RemMod, Name, RawArgForms, IsRemote, Stack) -> + ArgForms = case Mod =/= RemMod of + true -> [{from_mod,Mod,A} || A <- RawArgForms]; + false -> RawArgForms + end, + Arity = length(ArgForms), + FullTypeRef = {RemMod,Name,Arity}, + case lists:member(FullTypeRef, Stack) of + true -> + throw({'$typeserver',{self_reference,FullTypeRef}}); + false -> + TypeRef = {type,Name,Arity}, + AbsType = get_abs_type(RemMod, TypeRef, ArgForms, IsRemote), + is_instance(X, RemMod, AbsType, [FullTypeRef|Stack]) + end. + +-spec get_abs_type(mod_name(), type_ref(), [abs_type()], boolean()) -> + abs_type(). +get_abs_type(RemMod, TypeRef, ArgForms, IsRemote) -> + case get_type_repr(RemMod, TypeRef, IsRemote) of + {ok,TypeRepr} -> + {FinalAbsType,SymbInfo,VarNames} = + case TypeRepr of + {cached,_FinType,FAT,SI} -> {FAT,SI,[]}; + {abs_type,FAT,VN,SI} -> {FAT,SI,VN} + end, + AbsType = + case SymbInfo of + not_symb -> FinalAbsType; + {orig_abs,OrigAbsType} -> OrigAbsType + end, + VarSubstsDict = dict:from_list(lists:zip(VarNames,ArgForms)), + update_vars(AbsType, VarSubstsDict, false); + {error,Reason} -> + throw({'$typeserver',Reason}) + end. + +-spec abs_expr_error(atom(), abs_expr()) -> no_return(). +abs_expr_error(ImmReason, Expr) -> + {error,Reason} = expr_error(ImmReason, Expr), + throw({'$typeserver',Reason}). + +-spec abs_expr_error(atom(), abs_expr(), abs_expr()) -> no_return(). +abs_expr_error(ImmReason, Expr1, Expr2) -> + {error,Reason} = expr_error(ImmReason, Expr1, Expr2), + throw({'$typeserver',Reason}). + + +%%------------------------------------------------------------------------------ +%% Type translation functions +%%------------------------------------------------------------------------------ + +-spec convert(mod_name(), abs_type(), state()) -> + rich_result2(fin_type(),state()). +convert(Mod, TypeForm, State) -> + case convert(Mod, TypeForm, State, [], dict:new()) of + {ok,{simple,Type},NewState} -> + {ok, Type, NewState}; + {ok,{rec,_RecFun,_RecArgs},_NewState} -> + {error, {internal,rec_returned_to_toplevel}}; + {error,_Reason} = Error -> + Error + end. + +-spec convert(mod_name(), abs_type(), state(), stack(), var_dict()) -> + rich_result2(ret_type(),state()). +convert(Mod, {paren_type,_,[Type]}, State, Stack, VarDict) -> + convert(Mod, Type, State, Stack, VarDict); +convert(Mod, {ann_type,_,[_Var,Type]}, State, Stack, VarDict) -> + convert(Mod, Type, State, Stack, VarDict); +convert(_Mod, {var,_,'_'}, State, _Stack, _VarDict) -> + {ok, {simple,proper_types:any()}, State}; +convert(_Mod, {var,_,VarName}, State, _Stack, VarDict) -> + case dict:find(VarName, VarDict) of + %% TODO: do we need to check if we are at toplevel of a recursive? + {ok,RetType} -> {ok, RetType, State}; + error -> {error, {unbound_var,VarName}} + end; +convert(Mod, {remote_type,_,[{atom,_,RemMod},{atom,_,Name},ArgForms]}, State, + Stack, VarDict) -> + case prepare_for_remote(RemMod, Name, length(ArgForms), State) of + {ok,NewState} -> + convert_custom(Mod,RemMod,Name,ArgForms,NewState,Stack,VarDict); + {error,_Reason} = Error -> + Error + end; +convert(_Mod, {atom,_,Atom}, State, _Stack, _VarDict) -> + {ok, {simple,proper_types:exactly(Atom)}, State}; +convert(_Mod, {integer,_,_Int} = IntExpr, State, _Stack, _VarDict) -> + convert_integer(IntExpr, State); +convert(_Mod, {op,_,_Op,_Arg} = OpExpr, State, _Stack, _VarDict) -> + convert_integer(OpExpr, State); +convert(_Mod, {op,_,_Op,_Arg1,_Arg2} = OpExpr, State, _Stack, _VarDict) -> + convert_integer(OpExpr, State); +convert(_Mod, {type,_,binary,[BaseExpr,UnitExpr]}, State, _Stack, _VarDict) -> + %% <<_:X,_:_*Y>> means "bitstrings of X + k*Y bits, k >= 0" + case eval_int(BaseExpr) of + {ok,0} -> + case eval_int(UnitExpr) of + {ok,0} -> {ok, {simple,proper_types:exactly(<<>>)}, State}; + {ok,1} -> {ok, {simple,proper_types:bitstring()}, State}; + {ok,8} -> {ok, {simple,proper_types:binary()}, State}; + {ok,N} when N > 0 -> + Gen = ?LET(L, proper_types:list(proper_types:bitstring(N)), + concat_bitstrings(L)), + {ok, {simple,Gen}, State}; + _ -> expr_error(invalid_unit, UnitExpr) + end; + {ok,Base} when Base > 0 -> + Head = proper_types:bitstring(Base), + case eval_int(UnitExpr) of + {ok,0} -> {ok, {simple,Head}, State}; + {ok,1} -> + Tail = proper_types:bitstring(), + {ok, {simple,concat_binary_gens(Head, Tail)}, State}; + {ok,8} -> + Tail = proper_types:binary(), + {ok, {simple,concat_binary_gens(Head, Tail)}, State}; + {ok,N} when N > 0 -> + Tail = + ?LET(L, proper_types:list(proper_types:bitstring(N)), + concat_bitstrings(L)), + {ok, {simple,concat_binary_gens(Head, Tail)}, State}; + _ -> expr_error(invalid_unit, UnitExpr) + end; + _ -> + expr_error(invalid_base, BaseExpr) + end; +convert(_Mod, {type,_,range,[LowExpr,HighExpr]}, State, _Stack, _VarDict) -> + case {eval_int(LowExpr),eval_int(HighExpr)} of + {{ok,Low},{ok,High}} when Low =< High -> + {ok, {simple,proper_types:integer(Low,High)}, State}; + _ -> + expr_error(invalid_range, LowExpr, HighExpr) + end; +convert(_Mod, {type,_,nil,[]}, State, _Stack, _VarDict) -> + {ok, {simple,proper_types:exactly([])}, State}; +convert(Mod, {type,_,list,[ElemForm]}, State, Stack, VarDict) -> + convert_list(Mod, false, ElemForm, State, Stack, VarDict); +convert(Mod, {type,_,nonempty_list,[ElemForm]}, State, Stack, VarDict) -> + convert_list(Mod, true, ElemForm, State, Stack, VarDict); +convert(_Mod, {type,_,nonempty_list,[]}, State, _Stack, _VarDict) -> + {ok, {simple,proper_types:non_empty(proper_types:list())}, State}; +convert(_Mod, {type,_,nonempty_string,[]}, State, _Stack, _VarDict) -> + {ok, {simple,proper_types:non_empty(proper_types:string())}, State}; +convert(_Mod, {type,_,tuple,any}, State, _Stack, _VarDict) -> + {ok, {simple,proper_types:tuple()}, State}; +convert(Mod, {type,_,tuple,ElemForms}, State, Stack, VarDict) -> + convert_tuple(Mod, ElemForms, false, State, Stack, VarDict); +convert(Mod, {type,_,'$fixed_list',ElemForms}, State, Stack, VarDict) -> + convert_tuple(Mod, ElemForms, true, State, Stack, VarDict); +convert(Mod, {type,_,record,[{atom,_,Name}|FieldForms]}, State, Stack, + VarDict) -> + convert_record(Mod, Name, FieldForms, State, Stack, VarDict); +convert(Mod, {type,_,union,ChoiceForms}, State, Stack, VarDict) -> + convert_union(Mod, ChoiceForms, State, Stack, VarDict); +convert(Mod, {type,_,'fun',[{type,_,product,Domain},Range]}, State, Stack, + VarDict) -> + convert_fun(Mod, length(Domain), Range, State, Stack, VarDict); +%% TODO: These types should be replaced with accurate types. +%% TODO: Add support for nonempty_improper_list/2. +convert(Mod, {type,_,maybe_improper_list,[]}, State, Stack, VarDict) -> + convert(Mod, {type,0,list,[]}, State, Stack, VarDict); +convert(Mod, {type,_,maybe_improper_list,[Cont,_Ter]}, State, Stack, VarDict) -> + convert(Mod, {type,0,list,[Cont]}, State, Stack, VarDict); +convert(Mod, {type,_,nonempty_maybe_improper_list,[]}, State, Stack, VarDict) -> + convert(Mod, {type,0,nonempty_list,[]}, State, Stack, VarDict); +convert(Mod, {type,_,nonempty_maybe_improper_list,[Cont,_Term]}, State, Stack, + VarDict) -> + convert(Mod, {type,0,nonempty_list,[Cont]}, State, Stack, VarDict); +convert(Mod, {type,_,iodata,[]}, State, Stack, VarDict) -> + RealType = {type,0,union,[{type,0,binary,[]},{type,0,iolist,[]}]}, + convert(Mod, RealType, State, Stack, VarDict); +convert(Mod, {type,_,Name,[]}, State, Stack, VarDict) -> + case ordsets:is_element(Name, ?STD_TYPES_0) of + true -> + {ok, {simple,proper_types:Name()}, State}; + false -> + convert_maybe_hard_adt(Mod, Name, [], State, Stack, VarDict) + end; +convert(Mod, {type,_,Name,ArgForms}, State, Stack, VarDict) -> + convert_maybe_hard_adt(Mod, Name, ArgForms, State, Stack, VarDict); +convert(_Mod, TypeForm, _State, _Stack, _VarDict) -> + {error, {unsupported_type,TypeForm}}. + +-spec concat_bitstrings([bitstring()]) -> bitstring(). +concat_bitstrings(BitStrings) -> + concat_bitstrings_tr(BitStrings, <<>>). + +-spec concat_bitstrings_tr([bitstring()], bitstring()) -> bitstring(). +concat_bitstrings_tr([], Acc) -> + Acc; +concat_bitstrings_tr([BitString | Rest], Acc) -> + concat_bitstrings_tr(Rest, <<Acc/bits,BitString/bits>>). + +-spec concat_binary_gens(fin_type(), fin_type()) -> fin_type(). +concat_binary_gens(HeadType, TailType) -> + ?LET({H,T}, {HeadType,TailType}, <<H/bits,T/bits>>). + +-spec convert_fun(mod_name(), arity(), abs_type(), state(), stack(), + var_dict()) -> rich_result2(ret_type(),state()). +convert_fun(Mod, Arity, Range, State, Stack, VarDict) -> + case convert(Mod, Range, State, ['fun' | Stack], VarDict) of + {ok,{simple,RangeType},NewState} -> + {ok, {simple,proper_types:function(Arity,RangeType)}, NewState}; + {ok,{rec,RecFun,RecArgs},NewState} -> + case at_toplevel(RecArgs, Stack) of + true -> base_case_error(Stack); + false -> convert_rec_fun(Arity, RecFun, RecArgs, NewState) + end; + {error,_Reason} = Error -> + Error + end. + +-spec convert_rec_fun(arity(), rec_fun(), rec_args(), state()) -> + {'ok',ret_type(),state()}. +convert_rec_fun(Arity, RecFun, RecArgs, State) -> + %% We bind the generated value by size. + NewRecFun = + fun(GenFuns,Size) -> + proper_types:function(Arity, RecFun(GenFuns,Size)) + end, + NewRecArgs = clean_rec_args(RecArgs), + {ok, {rec,NewRecFun,NewRecArgs}, State}. + +-spec convert_list(mod_name(), boolean(), abs_type(), state(), stack(), + var_dict()) -> rich_result2(ret_type(),state()). +convert_list(Mod, NonEmpty, ElemForm, State, Stack, VarDict) -> + case convert(Mod, ElemForm, State, [list | Stack], VarDict) of + {ok,{simple,ElemType},NewState} -> + InnerType = proper_types:list(ElemType), + FinType = case NonEmpty of + true -> proper_types:non_empty(InnerType); + false -> InnerType + end, + {ok, {simple,FinType}, NewState}; + {ok,{rec,RecFun,RecArgs},NewState} -> + case {at_toplevel(RecArgs,Stack), NonEmpty} of + {true,true} -> + base_case_error(Stack); + {true,false} -> + NewRecFun = + fun(GenFuns,Size) -> + ElemGen = fun(S) -> ?LAZY(RecFun(GenFuns,S)) end, + proper_types:distlist(Size, ElemGen, false) + end, + NewRecArgs = clean_rec_args(RecArgs), + {ok, {rec,NewRecFun,NewRecArgs}, NewState}; + {false,_} -> + {NewRecFun,NewRecArgs} = + convert_rec_list(RecFun, RecArgs, NonEmpty), + {ok, {rec,NewRecFun,NewRecArgs}, NewState} + end; + {error,_Reason} = Error -> + Error + end. + +-spec convert_rec_list(rec_fun(), rec_args(), boolean()) -> + {rec_fun(),rec_args()}. +convert_rec_list(RecFun, [{true,FullTypeRef}] = RecArgs, NonEmpty) -> + {NewRecFun,_NormalRecArgs} = + convert_normal_rec_list(RecFun, RecArgs, NonEmpty), + AltRecFun = + fun([InstListGen],Size) -> + InstTypesList = + proper_types:get_prop(internal_types, InstListGen(Size)), + proper_types:fixed_list([RecFun([fun(_Size) -> I end],0) + || I <- InstTypesList]) + end, + NewRecArgs = [{{list,NonEmpty,AltRecFun},FullTypeRef}], + {NewRecFun, NewRecArgs}; +convert_rec_list(RecFun, RecArgs, NonEmpty) -> + convert_normal_rec_list(RecFun, RecArgs, NonEmpty). + +-spec convert_normal_rec_list(rec_fun(), rec_args(), boolean()) -> + {rec_fun(),rec_args()}. +convert_normal_rec_list(RecFun, RecArgs, NonEmpty) -> + NewRecFun = fun(GenFuns,Size) -> + ElemGen = fun(S) -> RecFun(GenFuns, S) end, + proper_types:distlist(Size, ElemGen, NonEmpty) + end, + NewRecArgs = clean_rec_args(RecArgs), + {NewRecFun, NewRecArgs}. + +-spec convert_tuple(mod_name(), [abs_type()], boolean(), state(), stack(), + var_dict()) -> rich_result2(ret_type(),state()). +convert_tuple(Mod, ElemForms, ToList, State, Stack, VarDict) -> + case process_list(Mod, ElemForms, State, [tuple | Stack], VarDict) of + {ok,RetTypes,NewState} -> + case combine_ret_types(RetTypes, {tuple,ToList}) of + {simple,_FinType} = RetType -> + {ok, RetType, NewState}; + {rec,_RecFun,RecArgs} = RetType -> + case at_toplevel(RecArgs, Stack) of + true -> base_case_error(Stack); + false -> {ok, RetType, NewState} + end + end; + {error,_Reason} = Error -> + Error + end. + +-spec convert_union(mod_name(), [abs_type()], state(), stack(), var_dict()) -> + rich_result2(ret_type(),state()). +convert_union(Mod, ChoiceForms, State, Stack, VarDict) -> + case process_list(Mod, ChoiceForms, State, [union | Stack], VarDict) of + {ok,RawChoices,NewState} -> + ProcessChoice = fun(T,A) -> process_choice(T,A,Stack) end, + {RevSelfRecs,RevNonSelfRecs,RevNonRecs} = + lists:foldl(ProcessChoice, {[],[],[]}, RawChoices), + case {lists:reverse(RevSelfRecs),lists:reverse(RevNonSelfRecs), + lists:reverse(RevNonRecs)} of + {_SelfRecs,[],[]} -> + base_case_error(Stack); + {[],NonSelfRecs,NonRecs} -> + {ok, combine_ret_types(NonRecs ++ NonSelfRecs, union), + NewState}; + {SelfRecs,NonSelfRecs,NonRecs} -> + {BCaseRecFun,BCaseRecArgs} = + case combine_ret_types(NonRecs ++ NonSelfRecs, union) of + {simple,BCaseType} -> + {fun([],_Size) -> BCaseType end,[]}; + {rec,BCRecFun,BCRecArgs} -> + {BCRecFun,BCRecArgs} + end, + NumBCaseGens = length(BCaseRecArgs), + [ParentRef | _Upper] = Stack, + FallbackRecFun = fun([SelfGen],_Size) -> SelfGen(0) end, + FallbackRecArgs = [{false,ParentRef}], + FallbackRetType = {rec,FallbackRecFun,FallbackRecArgs}, + {rec,RCaseRecFun,RCaseRecArgs} = + combine_ret_types([FallbackRetType] ++ SelfRecs + ++ NonSelfRecs, wunion), + NewRecFun = + fun(AllGens,Size) -> + {BCaseGens,RCaseGens} = + lists:split(NumBCaseGens, AllGens), + case Size of + 0 -> BCaseRecFun(BCaseGens,0); + _ -> RCaseRecFun(RCaseGens,Size) + end + end, + NewRecArgs = BCaseRecArgs ++ RCaseRecArgs, + {ok, {rec,NewRecFun,NewRecArgs}, NewState} + end; + {error,_Reason} = Error -> + Error + end. + +-spec process_choice(ret_type(), {[ret_type()],[ret_type()],[ret_type()]}, + stack()) -> {[ret_type()],[ret_type()],[ret_type()]}. +process_choice({simple,_} = RetType, {SelfRecs,NonSelfRecs,NonRecs}, _Stack) -> + {SelfRecs, NonSelfRecs, [RetType | NonRecs]}; +process_choice({rec,RecFun,RecArgs}, {SelfRecs,NonSelfRecs,NonRecs}, Stack) -> + case at_toplevel(RecArgs, Stack) of + true -> + case partition_by_toplevel(RecArgs, Stack, true) of + {[],[],_,_} -> + NewRecArgs = clean_rec_args(RecArgs), + {[{rec,RecFun,NewRecArgs} | SelfRecs], NonSelfRecs, + NonRecs}; + {SelfRecArgs,SelfPos,OtherRecArgs,_OtherPos} -> + NumInstances = length(SelfRecArgs), + IsListInst = fun({true,_FTRef}) -> false + ; ({{list,_NE,_AltRecFun},_FTRef}) -> true + end, + NewRecFun = + case proper_arith:filter(IsListInst,SelfRecArgs) of + {[],[]} -> + no_list_inst_rec_fun(RecFun,NumInstances, + SelfPos); + {[{{list,NonEmpty,AltRecFun},_}],[ListInstPos]} -> + list_inst_rec_fun(AltRecFun,NumInstances, + SelfPos,NonEmpty,ListInstPos) + end, + [{_B,SelfRef} | _] = SelfRecArgs, + NewRecArgs = + [{false,SelfRef} | clean_rec_args(OtherRecArgs)], + {[{rec,NewRecFun,NewRecArgs} | SelfRecs], NonSelfRecs, + NonRecs} + end; + false -> + NewRecArgs = clean_rec_args(RecArgs), + {SelfRecs, [{rec,RecFun,NewRecArgs} | NonSelfRecs], NonRecs} + end. + +-spec no_list_inst_rec_fun(rec_fun(), pos_integer(), [position()]) -> rec_fun(). +no_list_inst_rec_fun(RecFun, NumInstances, SelfPos) -> + fun([SelfGen|OtherGens], Size) -> + ?LETSHRINK( + Instances, + %% Size distribution will be a little off if both normal and + %% instance-accepting generators are present. + lists:duplicate(NumInstances, SelfGen(Size div NumInstances)), + begin + InstGens = [fun(_Size) -> proper_types:exactly(I) end + || I <- Instances], + AllGens = proper_arith:insert(InstGens, SelfPos, OtherGens), + RecFun(AllGens, Size) + end) + end. + +-spec list_inst_rec_fun(rec_fun(), pos_integer(), [position()], boolean(), + position()) -> rec_fun(). +list_inst_rec_fun(AltRecFun, NumInstances, SelfPos, NonEmpty, ListInstPos) -> + fun([SelfGen|OtherGens], Size) -> + ?LETSHRINK( + AllInsts, + lists:duplicate(NumInstances - 1, SelfGen(Size div NumInstances)) + ++ proper_types:distlist(Size div NumInstances, SelfGen, NonEmpty), + begin + {Instances,InstList} = lists:split(NumInstances - 1, AllInsts), + InstGens = [fun(_Size) -> proper_types:exactly(I) end + || I <- Instances], + InstTypesList = [proper_types:exactly(I) || I <- InstList], + InstListGen = + fun(_Size) -> proper_types:fixed_list(InstTypesList) end, + AllInstGens = proper_arith:list_insert(ListInstPos, InstListGen, + InstGens), + AllGens = proper_arith:insert(AllInstGens, SelfPos, OtherGens), + AltRecFun(AllGens, Size) + end) + end. + +-spec convert_maybe_hard_adt(mod_name(), type_name(), [abs_type()], state(), + stack(), var_dict()) -> + rich_result2(ret_type(),state()). +convert_maybe_hard_adt(Mod, Name, ArgForms, State, Stack, VarDict) -> + Arity = length(ArgForms), + case orddict:find({Name,Arity}, ?HARD_ADTS) of + {ok,Mod} -> + convert_custom(Mod, Mod, Name, ArgForms, State, Stack, VarDict); + {ok,ADTMod} -> + ADT = {remote_type,0,[{atom,0,ADTMod},{atom,0,Name},ArgForms]}, + convert(Mod, ADT, State, Stack, VarDict); + error -> + convert_custom(Mod, Mod, Name, ArgForms, State, Stack, VarDict) + end. + +-spec convert_custom(mod_name(), mod_name(), type_name(), [abs_type()], state(), + stack(), var_dict()) -> rich_result2(ret_type(),state()). +convert_custom(Mod, RemMod, Name, ArgForms, State, Stack, VarDict) -> + case process_list(Mod, ArgForms, State, Stack, VarDict) of + {ok,Args,NewState} -> + Arity = length(Args), + TypeRef = {type,Name,Arity}, + FullTypeRef = {RemMod,type,Name,Args}, + convert_type(TypeRef, FullTypeRef, NewState, Stack); + {error,_Reason} = Error -> + Error + end. + +-spec convert_record(mod_name(), type_name(), [abs_type()], state(), stack(), + var_dict()) -> rich_result2(ret_type(),state()). +convert_record(Mod, Name, RawSubsts, State, Stack, VarDict) -> + Substs = [{N,T} || {type,_,field_type,[{atom,_,N},T]} <- RawSubsts], + {SubstFields,SubstTypeForms} = lists:unzip(Substs), + case process_list(Mod, SubstTypeForms, State, Stack, VarDict) of + {ok,SubstTypes,NewState} -> + SubstsDict = dict:from_list(lists:zip(SubstFields, SubstTypes)), + TypeRef = {record,Name,0}, + FullTypeRef = {Mod,record,Name,SubstsDict}, + convert_type(TypeRef, FullTypeRef, NewState, Stack); + {error,_Reason} = Error -> + Error + end. + +-spec convert_type(type_ref(), full_type_ref(), state(), stack()) -> + rich_result2(ret_type(),state()). +convert_type(TypeRef, {Mod,_Kind,_Name,_Spec} = FullTypeRef, State, Stack) -> + case stack_position(FullTypeRef, Stack) of + none -> + case get_type_repr(Mod, TypeRef, false, State) of + {ok,TypeRepr,NewState} -> + convert_new_type(TypeRef, FullTypeRef, TypeRepr, NewState, + Stack); + {error,_Reason} = Error -> + Error + end; + 1 -> + base_case_error(Stack); + _Pos -> + {ok, {rec,fun([Gen],Size) -> Gen(Size) end,[{true,FullTypeRef}]}, + State} + end. + +-spec convert_new_type(type_ref(), full_type_ref(), type_repr(), state(), + stack()) -> rich_result2(ret_type(),state()). +convert_new_type(_TypeRef, {_Mod,type,_Name,[]}, + {cached,FinType,_TypeForm,_SymbInfo}, State, _Stack) -> + {ok, {simple,FinType}, State}; +convert_new_type(TypeRef, {Mod,type,_Name,Args} = FullTypeRef, + {abs_type,TypeForm,Vars,SymbInfo}, State, Stack) -> + VarDict = dict:from_list(lists:zip(Vars, Args)), + case convert(Mod, TypeForm, State, [FullTypeRef | Stack], VarDict) of + {ok, {simple,ImmFinType}, NewState} -> + FinType = case SymbInfo of + not_symb -> + ImmFinType; + {orig_abs,_OrigAbsType} -> + proper_symb:internal_well_defined(ImmFinType) + end, + FinalState = case Vars of + [] -> cache_type(Mod, TypeRef, FinType, TypeForm, + SymbInfo, NewState); + _ -> NewState + end, + {ok, {simple,FinType}, FinalState}; + {ok, {rec,RecFun,RecArgs}, NewState} -> + convert_maybe_rec(FullTypeRef, SymbInfo, RecFun, RecArgs, NewState, + Stack); + {error,_Reason} = Error -> + Error + end; +convert_new_type(_TypeRef, {Mod,record,Name,SubstsDict} = FullTypeRef, + {abs_record,OrigFields}, State, Stack) -> + Fields = [case dict:find(FieldName, SubstsDict) of + {ok,NewFieldType} -> NewFieldType; + error -> OrigFieldType + end + || {FieldName,OrigFieldType} <- OrigFields], + case convert_tuple(Mod, [{atom,0,Name} | Fields], false, State, + [FullTypeRef | Stack], dict:new()) of + {ok, {simple,_FinType}, _NewState} = Result -> + Result; + {ok, {rec,RecFun,RecArgs}, NewState} -> + convert_maybe_rec(FullTypeRef, not_symb, RecFun, RecArgs, NewState, + Stack); + {error,_Reason} = Error -> + Error + end. + +-spec cache_type(mod_name(), type_ref(), fin_type(), abs_type(), symb_info(), + state()) -> state(). +cache_type(Mod, TypeRef, FinType, TypeForm, SymbInfo, + #state{types = Types} = State) -> + TypeRepr = {cached,FinType,TypeForm,SymbInfo}, + ModTypes = dict:fetch(Mod, Types), + NewModTypes = dict:store(TypeRef, TypeRepr, ModTypes), + NewTypes = dict:store(Mod, NewModTypes, Types), + State#state{types = NewTypes}. + +-spec convert_maybe_rec(full_type_ref(), symb_info(), rec_fun(), rec_args(), + state(), stack()) -> rich_result2(ret_type(),state()). +convert_maybe_rec(FullTypeRef, SymbInfo, RecFun, RecArgs, State, Stack) -> + case at_toplevel(RecArgs, Stack) of + true -> base_case_error(Stack); + false -> safe_convert_maybe_rec(FullTypeRef, SymbInfo, RecFun, RecArgs, + State) + end. + +-spec safe_convert_maybe_rec(full_type_ref(),symb_info(),rec_fun(),rec_args(), + state()) -> rich_result2(ret_type(),state()). +safe_convert_maybe_rec(FullTypeRef, SymbInfo, RecFun, RecArgs, State) -> + case partition_rec_args(FullTypeRef, RecArgs, false) of + {[],[],_,_} -> + {ok, {rec,RecFun,RecArgs}, State}; + {MyRecArgs,MyPos,OtherRecArgs,_OtherPos} -> + case lists:all(fun({B,_T}) -> B =:= false end, MyRecArgs) of + true -> convert_rec_type(SymbInfo, RecFun, MyPos, OtherRecArgs, + State); + false -> {error, {internal,true_rec_arg_reached_type}} + end + end. + +-spec convert_rec_type(symb_info(), rec_fun(), [position()], rec_args(), + state()) -> {ok, ret_type(), state()}. +convert_rec_type(SymbInfo, RecFun, MyPos, [], State) -> + NumRecArgs = length(MyPos), + M = fun(GenFun) -> + fun(Size) -> + GenFuns = lists:duplicate(NumRecArgs, GenFun), + RecFun(GenFuns, erlang:max(0,Size - 1)) + end + end, + SizedGen = y(M), + ImmFinType = ?SIZED(Size,SizedGen(Size + 1)), + FinType = case SymbInfo of + not_symb -> + ImmFinType; + {orig_abs,_OrigAbsType} -> + proper_symb:internal_well_defined(ImmFinType) + end, + {ok, {simple,FinType}, State}; +convert_rec_type(_SymbInfo, RecFun, MyPos, OtherRecArgs, State) -> + NumRecArgs = length(MyPos), + NewRecFun = + fun(OtherGens,TopSize) -> + M = fun(GenFun) -> + fun(Size) -> + GenFuns = lists:duplicate(NumRecArgs, GenFun), + AllGens = + proper_arith:insert(GenFuns, MyPos, OtherGens), + RecFun(AllGens, erlang:max(0,Size - 1)) + end + end, + (y(M))(TopSize) + end, + NewRecArgs = clean_rec_args(OtherRecArgs), + {ok, {rec,NewRecFun,NewRecArgs}, State}. + +%% Y Combinator: Read more at http://bc.tech.coop/blog/070611.html. +-spec y(fun((fun((T) -> S)) -> fun((T) -> S))) -> fun((T) -> S). +y(M) -> + G = fun(F) -> + M(fun(A) -> (F(F))(A) end) + end, + G(G). + +-spec process_list(mod_name(), [abs_type() | ret_type()], state(), stack(), + var_dict()) -> rich_result2([ret_type()],state()). +process_list(Mod, RawTypes, State, Stack, VarDict) -> + Process = fun({simple,_FinType} = Type, {ok,Types,State1}) -> + {ok, [Type|Types], State1}; + ({rec,_RecFun,_RecArgs} = Type, {ok,Types,State1}) -> + {ok, [Type|Types], State1}; + (TypeForm, {ok,Types,State1}) -> + case convert(Mod, TypeForm, State1, Stack, VarDict) of + {ok,Type,State2} -> {ok,[Type|Types],State2}; + {error,_} = Err -> Err + end; + (_RawType, {error,_} = Err) -> + Err + end, + case lists:foldl(Process, {ok,[],State}, RawTypes) of + {ok,RevTypes,NewState} -> + {ok, lists:reverse(RevTypes), NewState}; + {error,_Reason} = Error -> + Error + end. + +-spec convert_integer(abs_expr(), state()) -> rich_result2(ret_type(),state()). +convert_integer(Expr, State) -> + case eval_int(Expr) of + {ok,Int} -> {ok, {simple,proper_types:exactly(Int)}, State}; + error -> expr_error(invalid_int_const, Expr) + end. + +-spec eval_int(abs_expr()) -> tagged_result(integer()). +eval_int(Expr) -> + NoBindings = erl_eval:new_bindings(), + try erl_eval:expr(Expr, NoBindings) of + {value,Value,_NewBindings} when is_integer(Value) -> + {ok, Value}; + _ -> + error + catch + error:_ -> + error + end. + +-spec expr_error(atom(), abs_expr()) -> {'error',term()}. +expr_error(Reason, Expr) -> + {error, {Reason,lists:flatten(erl_pp:expr(Expr))}}. + +-spec expr_error(atom(), abs_expr(), abs_expr()) -> {'error',term()}. +expr_error(Reason, Expr1, Expr2) -> + Str1 = lists:flatten(erl_pp:expr(Expr1)), + Str2 = lists:flatten(erl_pp:expr(Expr2)), + {error, {Reason,Str1,Str2}}. + +-spec base_case_error(stack()) -> {'error',term()}. +%% TODO: This might confuse, since it doesn't record the arguments to parametric +%% types or the type subsitutions of a record. +base_case_error([{Mod,type,Name,Args} | _Upper]) -> + Arity = length(Args), + {error, {no_base_case,{Mod,type,Name,Arity}}}; +base_case_error([{Mod,record,Name,_SubstsDict} | _Upper]) -> + {error, {no_base_case,{Mod,record,Name}}}. + + +%%------------------------------------------------------------------------------ +%% Helper datatypes handling functions +%%------------------------------------------------------------------------------ + +-spec stack_position(full_type_ref(), stack()) -> 'none' | pos_integer(). +stack_position(FullTypeRef, Stack) -> + SameType = fun(A) -> same_full_type_ref(A,FullTypeRef) end, + case proper_arith:find_first(SameType, Stack) of + {Pos,_} -> Pos; + none -> none + end. + +-spec partition_by_toplevel(rec_args(), stack(), boolean()) -> + {rec_args(),[position()],rec_args(),[position()]}. +partition_by_toplevel(RecArgs, [], _OnlyInstanceAccepting) -> + {[],[],RecArgs,lists:seq(1,length(RecArgs))}; +partition_by_toplevel(RecArgs, [_Parent | _Upper], _OnlyInstanceAccepting) + when is_atom(_Parent) -> + {[],[],RecArgs,lists:seq(1,length(RecArgs))}; +partition_by_toplevel(RecArgs, [Parent | _Upper], OnlyInstanceAccepting) -> + partition_rec_args(Parent, RecArgs, OnlyInstanceAccepting). + +-spec at_toplevel(rec_args(), stack()) -> boolean(). +at_toplevel(RecArgs, Stack) -> + case partition_by_toplevel(RecArgs, Stack, false) of + {[],[],_,_} -> false; + _ -> true + end. + +-spec partition_rec_args(full_type_ref(), rec_args(), boolean()) -> + {rec_args(),[position()],rec_args(),[position()]}. +partition_rec_args(FullTypeRef, RecArgs, OnlyInstanceAccepting) -> + SameType = + case OnlyInstanceAccepting of + true -> fun({false,_T}) -> false + ; ({_B,T}) -> same_full_type_ref(T,FullTypeRef) end; + false -> fun({_B,T}) -> same_full_type_ref(T,FullTypeRef) end + end, + proper_arith:partition(SameType, RecArgs). + +%% Tuples can be of 0 arity, unions of 1 and wunions at least of 2. +-spec combine_ret_types([ret_type()], {'tuple',boolean()} | 'union' + | 'wunion') -> ret_type(). +combine_ret_types(RetTypes, EnclosingType) -> + case lists:all(fun is_simple_ret_type/1, RetTypes) of + true -> + %% This should never happen for wunion. + Combine = case EnclosingType of + {tuple,false} -> fun proper_types:tuple/1; + {tuple,true} -> fun proper_types:fixed_list/1; + union -> fun proper_types:union/1 + end, + FinTypes = [T || {simple,T} <- RetTypes], + {simple, Combine(FinTypes)}; + false -> + NumTypes = length(RetTypes), + {RevRecFuns,RevRecArgsList,NumRecs} = + lists:foldl(fun add_ret_type/2, {[],[],0}, RetTypes), + RecFuns = lists:reverse(RevRecFuns), + RecArgsList = lists:reverse(RevRecArgsList), + RecArgLens = [length(RecArgs) || RecArgs <- RecArgsList], + RecFunInfo = {NumTypes,NumRecs,RecArgLens,RecFuns}, + FlatRecArgs = lists:flatten(RecArgsList), + {NewRecFun,NewRecArgs} = + case EnclosingType of + {tuple,ToList} -> + {tuple_rec_fun(RecFunInfo,ToList), + soft_clean_rec_args(FlatRecArgs,RecFunInfo,ToList)}; + union -> + {union_rec_fun(RecFunInfo),clean_rec_args(FlatRecArgs)}; + wunion -> + {wunion_rec_fun(RecFunInfo), + clean_rec_args(FlatRecArgs)} + end, + {rec, NewRecFun, NewRecArgs} + end. + +-spec tuple_rec_fun(rec_fun_info(), boolean()) -> rec_fun(). +tuple_rec_fun({_NumTypes,NumRecs,RecArgLens,RecFuns}, ToList) -> + Combine = case ToList of + true -> fun proper_types:fixed_list/1; + false -> fun proper_types:tuple/1 + end, + fun(AllGFs,TopSize) -> + Size = TopSize div NumRecs, + GFsList = proper_arith:unflatten(AllGFs, RecArgLens), + ArgsList = [[GenFuns,Size] || GenFuns <- GFsList], + ZipFun = fun erlang:apply/2, + Combine(lists:zipwith(ZipFun, RecFuns, ArgsList)) + end. + +-spec union_rec_fun(rec_fun_info()) -> rec_fun(). +union_rec_fun({_NumTypes,_NumRecs,RecArgLens,RecFuns}) -> + fun(AllGFs,Size) -> + GFsList = proper_arith:unflatten(AllGFs, RecArgLens), + ArgsList = [[GenFuns,Size] || GenFuns <- GFsList], + ZipFun = fun(F,A) -> ?LAZY(apply(F,A)) end, + proper_types:union(lists:zipwith(ZipFun, RecFuns, ArgsList)) + end. + +-spec wunion_rec_fun(rec_fun_info()) -> rec_fun(). +wunion_rec_fun({NumTypes,_NumRecs,RecArgLens,RecFuns}) -> + fun(AllGFs,Size) -> + GFsList = proper_arith:unflatten(AllGFs, RecArgLens), + ArgsList = [[GenFuns,Size] || GenFuns <- GFsList], + ZipFun = fun(W,F,A) -> {W,?LAZY(apply(F,A))} end, + RecWeight = erlang:max(1, Size div (NumTypes - 1)), + Weights = [1 | lists:duplicate(NumTypes - 1, RecWeight)], + WeightedChoices = lists:zipwith3(ZipFun, Weights, RecFuns, ArgsList), + proper_types:wunion(WeightedChoices) + end. + +-spec add_ret_type(ret_type(), {[rec_fun()],[rec_args()],non_neg_integer()}) -> + {[rec_fun()],[rec_args()],non_neg_integer()}. +add_ret_type({simple,FinType}, {RecFuns,RecArgsList,NumRecs}) -> + {[fun([],_) -> FinType end | RecFuns], [[] | RecArgsList], NumRecs}; +add_ret_type({rec,RecFun,RecArgs}, {RecFuns,RecArgsList,NumRecs}) -> + {[RecFun | RecFuns], [RecArgs | RecArgsList], NumRecs + 1}. + +-spec is_simple_ret_type(ret_type()) -> boolean(). +is_simple_ret_type({simple,_FinType}) -> + true; +is_simple_ret_type({rec,_RecFun,_RecArgs}) -> + false. + +-spec clean_rec_args(rec_args()) -> rec_args(). +clean_rec_args(RecArgs) -> + [{false,F} || {_B,F} <- RecArgs]. + +-spec soft_clean_rec_args(rec_args(), rec_fun_info(), boolean()) -> rec_args(). +soft_clean_rec_args(RecArgs, RecFunInfo, ToList) -> + soft_clean_rec_args_tr(RecArgs, [], RecFunInfo, ToList, false, 1). + +-spec soft_clean_rec_args_tr(rec_args(), rec_args(), rec_fun_info(), boolean(), + boolean(), position()) -> rec_args(). +soft_clean_rec_args_tr([], Acc, _RecFunInfo, _ToList, _FoundListInst, _Pos) -> + lists:reverse(Acc); +soft_clean_rec_args_tr([{{list,_NonEmpty,_AltRecFun},FTRef} | Rest], Acc, + RecFunInfo, ToList, true, Pos) -> + NewArg = {false,FTRef}, + soft_clean_rec_args_tr(Rest, [NewArg|Acc], RecFunInfo, ToList, true, Pos+1); +soft_clean_rec_args_tr([{{list,NonEmpty,AltRecFun},FTRef} | Rest], Acc, + RecFunInfo, ToList, false, Pos) -> + {NumTypes,NumRecs,RecArgLens,RecFuns} = RecFunInfo, + AltRecFunPos = get_group(Pos, RecArgLens), + AltRecFuns = proper_arith:list_update(AltRecFunPos, AltRecFun, RecFuns), + AltRecFunInfo = {NumTypes,NumRecs,RecArgLens,AltRecFuns}, + NewArg = {{list,NonEmpty,tuple_rec_fun(AltRecFunInfo,ToList)},FTRef}, + soft_clean_rec_args_tr(Rest, [NewArg|Acc], RecFunInfo, ToList, true, Pos+1); +soft_clean_rec_args_tr([Arg | Rest], Acc, RecFunInfo, ToList, FoundListInst, + Pos) -> + soft_clean_rec_args_tr(Rest, [Arg | Acc], RecFunInfo, ToList, FoundListInst, + Pos+1). + +-spec get_group(pos_integer(), [non_neg_integer()]) -> pos_integer(). +get_group(Pos, AllMembers) -> + get_group_tr(Pos, AllMembers, 1). + +-spec get_group_tr(pos_integer(), [non_neg_integer()], pos_integer()) -> + pos_integer(). +get_group_tr(Pos, [Members | Rest], GroupNum) -> + case Pos =< Members of + true -> GroupNum; + false -> get_group_tr(Pos - Members, Rest, GroupNum + 1) + end. + +-spec same_full_type_ref(full_type_ref(), term()) -> boolean(). +same_full_type_ref({SameMod,type,SameName,Args1}, + {SameMod,type,SameName,Args2}) -> + length(Args1) =:= length(Args2) + andalso lists:all(fun({A,B}) -> same_ret_type(A,B) end, + lists:zip(Args1, Args2)); +same_full_type_ref({SameMod,record,SameName,SubstsDict1}, + {SameMod,record,SameName,SubstsDict2}) -> + same_substs_dict(SubstsDict1, SubstsDict2); +same_full_type_ref(_, _) -> + false. + +-spec same_ret_type(ret_type(), ret_type()) -> boolean(). +same_ret_type({simple,FinType1}, {simple,FinType2}) -> + same_fin_type(FinType1, FinType2); +same_ret_type({rec,RecFun1,RecArgs1}, {rec,RecFun2,RecArgs2}) -> + NumRecArgs = length(RecArgs1), + length(RecArgs2) =:= NumRecArgs + andalso lists:all(fun({A1,A2}) -> same_rec_arg(A1,A2,NumRecArgs) end, + lists:zip(RecArgs1,RecArgs2)) + andalso same_rec_fun(RecFun1, RecFun2, NumRecArgs); +same_ret_type(_, _) -> + false. + +%% TODO: Is this too strict? +-spec same_rec_arg(rec_arg(), rec_arg(), arity()) -> boolean(). +same_rec_arg({{list,SameBool,AltRecFun1},FTRef1}, + {{list,SameBool,AltRecFun2},FTRef2}, NumRecArgs) -> + same_rec_fun(AltRecFun1, AltRecFun2, NumRecArgs) + andalso same_full_type_ref(FTRef1, FTRef2); +same_rec_arg({true,FTRef1}, {true,FTRef2}, _NumRecArgs) -> + same_full_type_ref(FTRef1, FTRef2); +same_rec_arg({false,FTRef1}, {false,FTRef2}, _NumRecArgs) -> + same_full_type_ref(FTRef1, FTRef2); +same_rec_arg(_, _, _NumRecArgs) -> + false. + +-spec same_substs_dict(substs_dict(), substs_dict()) -> boolean(). +same_substs_dict(SubstsDict1, SubstsDict2) -> + SameKVPair = fun({{_K,V1},{_K,V2}}) -> same_ret_type(V1,V2); + (_) -> false + end, + SubstsKVList1 = lists:sort(dict:to_list(SubstsDict1)), + SubstsKVList2 = lists:sort(dict:to_list(SubstsDict2)), + length(SubstsKVList1) =:= length(SubstsKVList2) + andalso lists:all(SameKVPair, lists:zip(SubstsKVList1,SubstsKVList2)). + +-spec same_fin_type(fin_type(), fin_type()) -> boolean(). +same_fin_type(Type1, Type2) -> + proper_types:equal_types(Type1, Type2). + +-spec same_rec_fun(rec_fun(), rec_fun(), arity()) -> boolean(). +same_rec_fun(RecFun1, RecFun2, NumRecArgs) -> + %% It's ok that we return a type, even if there's a 'true' for use of + %% an instance. + GenFun = fun(_Size) -> proper_types:exactly('$dummy') end, + GenFuns = lists:duplicate(NumRecArgs,GenFun), + same_fin_type(RecFun1(GenFuns,0), RecFun2(GenFuns,0)). diff --git a/lib/dialyzer/test/plt_SUITE.erl b/lib/dialyzer/test/plt_SUITE.erl index ecbac14e5d..6ebe23b54b 100644 --- a/lib/dialyzer/test/plt_SUITE.erl +++ b/lib/dialyzer/test/plt_SUITE.erl @@ -7,12 +7,14 @@ -include("dialyzer_test_constants.hrl"). -export([suite/0, all/0, build_plt/1, beam_tests/1, update_plt/1, - run_plt_check/1, run_succ_typings/1]). + local_fun_same_as_callback/1, + remove_plt/1, run_plt_check/1, run_succ_typings/1]). suite() -> [{timetrap, ?plt_timeout}]. -all() -> [build_plt, beam_tests, update_plt, run_plt_check, run_succ_typings]. +all() -> [build_plt, beam_tests, update_plt, run_plt_check, + remove_plt, run_succ_typings, local_fun_same_as_callback]. build_plt(Config) -> OutDir = ?config(priv_dir, Config), @@ -158,6 +160,95 @@ update_plt(Config) -> {init_plt, Plt}] ++ Opts), ok. +%%% If a behaviour module contains an non-exported function with the same name +%%% as one of the behaviour's callbacks, the callback info was inadvertently +%%% deleted from the PLT as the dialyzer_plt:delete_list/2 function was cleaning +%%% up the callback table. This bug was reported by Brujo Benavides. + +local_fun_same_as_callback(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + Prog1 = + <<"-module(bad_behaviour). + -callback bad() -> bad. + -export([publicly_bad/0]). + + %% @doc This function is here just to avoid the 'unused' warning for bad/0 + publicly_bad() -> bad(). + + %% @doc This function overlaps with the callback with the same name, and + %% that was an issue for dialyzer since it's a private function. + bad() -> bad.">>, + {ok, Beam} = compile(Config, Prog1, bad_behaviour, []), + + ErlangBeam = case code:where_is_file("erlang.beam") of + non_existing -> + filename:join([code:root_dir(), + "erts", "preloaded", "ebin", + "erlang.beam"]); + EBeam -> + EBeam + end, + Plt = filename:join(PrivDir, "plt_bad_behaviour.plt"), + Opts = [{check_plt, true}, {from, byte_code}], + [] = dialyzer:run([{analysis_type, plt_build}, + {files, [Beam, ErlangBeam]}, + {output_plt, Plt}] ++ Opts), + + Prog2 = + <<"-module(bad_child). + -behaviour(bad_behaviour). + + -export([bad/0]). + + %% @doc This function incorreclty implements bad_behaviour. + bad() -> not_bad.">>, + {ok, TestBeam} = compile(Config, Prog2, bad_child, []), + + [{warn_behaviour, _, + {callback_type_mismatch, + [bad_behaviour,bad,0,"'not_bad'","'bad'"]}}] = + dialyzer:run([{analysis_type, succ_typings}, + {files, [TestBeam]}, + {init_plt, Plt}] ++ Opts), + ok. + +%%% [James Fish:] +%%% Dialyzer always asserts that files and directories passed in its +%%% options exist. Therefore it is not possible to remove a beam/module +%%% from a PLT when the beam file no longer exists. Dialyzer should not to +%%% check files exist on disk when removing from the PLT. +remove_plt(Config) -> + PrivDir = ?config(priv_dir, Config), + Prog1 = <<"-module(m1). + -export([t/0]). + t() -> + m2:a(a).">>, + {ok, Beam1} = compile(Config, Prog1, m1, []), + + Prog2 = <<"-module(m2). + -export([a/1]). + a(A) when is_integer(A) -> A.">>, + {ok, Beam2} = compile(Config, Prog2, m2, []), + + Plt = filename:join(PrivDir, "remove.plt"), + Opts = [{check_plt, true}, {from, byte_code}], + + [{warn_return_no_exit, _, {no_return,[only_normal,t,0]}}, + {warn_failing_call, _, {call, [m2,a,"('a')",_,_,_,_,_]}}] = + dialyzer:run([{analysis_type, plt_build}, + {files, [Beam1, Beam2]}, + {get_warnings, true}, + {output_plt, Plt}] ++ Opts), + + [] = dialyzer:run([{init_plt, Plt}, + {files, [Beam2]}, + {analysis_type, plt_remove}]), + + [] = dialyzer:run([{analysis_type, succ_typings}, + {files, [Beam1]}, + {init_plt, Plt}] ++ Opts), + ok. + compile(Config, Prog, Module, CompileOpts) -> Source = lists:concat([Module, ".erl"]), PrivDir = ?config(priv_dir,Config), diff --git a/lib/dialyzer/test/small_SUITE_data/results/abs b/lib/dialyzer/test/small_SUITE_data/results/abs new file mode 100644 index 0000000000..f229a6d036 --- /dev/null +++ b/lib/dialyzer/test/small_SUITE_data/results/abs @@ -0,0 +1,9 @@ + +abs.erl:12: Function i1/0 has no local return +abs.erl:16: The pattern 'true' can never match the type 'false' +abs.erl:23: Function i2/0 has no local return +abs.erl:27: The pattern 'true' can never match the type 'false' +abs.erl:34: Function i3/0 has no local return +abs.erl:37: The pattern 'true' can never match the type 'false' +abs.erl:45: Function i4/0 has no local return +abs.erl:49: The pattern 'true' can never match the type 'false' diff --git a/lib/dialyzer/test/small_SUITE_data/results/comparisons b/lib/dialyzer/test/small_SUITE_data/results/comparisons index 642585d25e..5083d2695a 100644 --- a/lib/dialyzer/test/small_SUITE_data/results/comparisons +++ b/lib/dialyzer/test/small_SUITE_data/results/comparisons @@ -1,50 +1,43 @@ comparisons.erl:100: The pattern 'true' can never match the type 'false' -comparisons.erl:101: The pattern 'true' can never match the type 'false' +comparisons.erl:101: The pattern 'false' can never match the type 'true' comparisons.erl:102: The pattern 'false' can never match the type 'true' -comparisons.erl:103: The pattern 'false' can never match the type 'true' +comparisons.erl:103: The pattern 'true' can never match the type 'false' comparisons.erl:104: The pattern 'true' can never match the type 'false' -comparisons.erl:105: The pattern 'true' can never match the type 'false' -comparisons.erl:107: The pattern 'true' can never match the type 'false' -comparisons.erl:108: The pattern 'true' can never match the type 'false' -comparisons.erl:109: The pattern 'false' can never match the type 'true' -comparisons.erl:110: The pattern 'false' can never match the type 'true' -comparisons.erl:111: The pattern 'true' can never match the type 'false' -comparisons.erl:112: The pattern 'true' can never match the type 'false' -comparisons.erl:113: The pattern 'false' can never match the type 'true' -comparisons.erl:114: The pattern 'false' can never match the type 'true' -comparisons.erl:115: The pattern 'true' can never match the type 'false' -comparisons.erl:116: The pattern 'true' can never match the type 'false' -comparisons.erl:117: The pattern 'false' can never match the type 'true' comparisons.erl:118: The pattern 'false' can never match the type 'true' +comparisons.erl:119: The pattern 'false' can never match the type 'true' +comparisons.erl:120: The pattern 'true' can never match the type 'false' +comparisons.erl:121: The pattern 'true' can never match the type 'false' +comparisons.erl:122: The pattern 'false' can never match the type 'true' comparisons.erl:123: The pattern 'false' can never match the type 'true' -comparisons.erl:124: The pattern 'false' can never match the type 'true' +comparisons.erl:124: The pattern 'true' can never match the type 'false' comparisons.erl:125: The pattern 'true' can never match the type 'false' -comparisons.erl:126: The pattern 'true' can never match the type 'false' +comparisons.erl:126: The pattern 'false' can never match the type 'true' comparisons.erl:127: The pattern 'false' can never match the type 'true' -comparisons.erl:128: The pattern 'false' can never match the type 'true' +comparisons.erl:128: The pattern 'true' can never match the type 'false' comparisons.erl:129: The pattern 'true' can never match the type 'false' -comparisons.erl:130: The pattern 'true' can never match the type 'false' +comparisons.erl:130: The pattern 'false' can never match the type 'true' +comparisons.erl:131: The pattern 'false' can never match the type 'true' comparisons.erl:132: The pattern 'true' can never match the type 'false' comparisons.erl:133: The pattern 'true' can never match the type 'false' comparisons.erl:134: The pattern 'false' can never match the type 'true' comparisons.erl:135: The pattern 'false' can never match the type 'true' comparisons.erl:136: The pattern 'true' can never match the type 'false' comparisons.erl:137: The pattern 'true' can never match the type 'false' -comparisons.erl:138: The pattern 'false' can never match the type 'true' -comparisons.erl:139: The pattern 'false' can never match the type 'true' +comparisons.erl:139: The pattern 'true' can never match the type 'false' comparisons.erl:140: The pattern 'true' can never match the type 'false' -comparisons.erl:141: The pattern 'true' can never match the type 'false' +comparisons.erl:141: The pattern 'false' can never match the type 'true' comparisons.erl:142: The pattern 'false' can never match the type 'true' -comparisons.erl:143: The pattern 'false' can never match the type 'true' +comparisons.erl:143: The pattern 'true' can never match the type 'false' comparisons.erl:144: The pattern 'true' can never match the type 'false' -comparisons.erl:145: The pattern 'true' can never match the type 'false' +comparisons.erl:145: The pattern 'false' can never match the type 'true' comparisons.erl:146: The pattern 'false' can never match the type 'true' -comparisons.erl:147: The pattern 'false' can never match the type 'true' -comparisons.erl:152: The pattern 'false' can never match the type 'true' -comparisons.erl:153: The pattern 'false' can never match the type 'true' -comparisons.erl:154: The pattern 'true' can never match the type 'false' -comparisons.erl:155: The pattern 'true' can never match the type 'false' +comparisons.erl:147: The pattern 'true' can never match the type 'false' +comparisons.erl:148: The pattern 'true' can never match the type 'false' +comparisons.erl:149: The pattern 'false' can never match the type 'true' +comparisons.erl:150: The pattern 'false' can never match the type 'true' +comparisons.erl:155: The pattern 'false' can never match the type 'true' +comparisons.erl:156: The pattern 'false' can never match the type 'true' comparisons.erl:157: The pattern 'true' can never match the type 'false' comparisons.erl:158: The pattern 'true' can never match the type 'false' comparisons.erl:159: The pattern 'false' can never match the type 'true' @@ -59,36 +52,62 @@ comparisons.erl:167: The pattern 'false' can never match the type 'true' comparisons.erl:168: The pattern 'false' can never match the type 'true' comparisons.erl:169: The pattern 'true' can never match the type 'false' comparisons.erl:170: The pattern 'true' can never match the type 'false' -comparisons.erl:171: The pattern 'false' can never match the type 'true' -comparisons.erl:172: The pattern 'false' can never match the type 'true' +comparisons.erl:172: The pattern 'true' can never match the type 'false' comparisons.erl:173: The pattern 'true' can never match the type 'false' -comparisons.erl:174: The pattern 'true' can never match the type 'false' +comparisons.erl:174: The pattern 'false' can never match the type 'true' comparisons.erl:175: The pattern 'false' can never match the type 'true' -comparisons.erl:176: The pattern 'false' can never match the type 'true' +comparisons.erl:176: The pattern 'true' can never match the type 'false' +comparisons.erl:177: The pattern 'true' can never match the type 'false' +comparisons.erl:178: The pattern 'false' can never match the type 'true' +comparisons.erl:179: The pattern 'false' can never match the type 'true' +comparisons.erl:180: The pattern 'true' can never match the type 'false' +comparisons.erl:181: The pattern 'true' can never match the type 'false' +comparisons.erl:182: The pattern 'false' can never match the type 'true' +comparisons.erl:183: The pattern 'false' can never match the type 'true' +comparisons.erl:184: The pattern 'true' can never match the type 'false' +comparisons.erl:185: The pattern 'true' can never match the type 'false' comparisons.erl:186: The pattern 'false' can never match the type 'true' comparisons.erl:187: The pattern 'false' can never match the type 'true' -comparisons.erl:188: The pattern 'true' can never match the type 'false' -comparisons.erl:189: The pattern 'true' can never match the type 'false' -comparisons.erl:190: The pattern 'false' can never match the type 'true' -comparisons.erl:191: The pattern 'false' can never match the type 'true' -comparisons.erl:192: The pattern 'true' can never match the type 'false' -comparisons.erl:193: The pattern 'true' can never match the type 'false' -comparisons.erl:203: The pattern 'false' can never match the type 'true' -comparisons.erl:204: The pattern 'false' can never match the type 'true' +comparisons.erl:192: The pattern 'false' can never match the type 'true' +comparisons.erl:193: The pattern 'false' can never match the type 'true' +comparisons.erl:194: The pattern 'true' can never match the type 'false' +comparisons.erl:195: The pattern 'true' can never match the type 'false' +comparisons.erl:196: The pattern 'false' can never match the type 'true' +comparisons.erl:197: The pattern 'false' can never match the type 'true' +comparisons.erl:198: The pattern 'true' can never match the type 'false' +comparisons.erl:199: The pattern 'true' can never match the type 'false' +comparisons.erl:200: The pattern 'false' can never match the type 'true' +comparisons.erl:201: The pattern 'false' can never match the type 'true' +comparisons.erl:202: The pattern 'true' can never match the type 'false' +comparisons.erl:203: The pattern 'true' can never match the type 'false' comparisons.erl:205: The pattern 'true' can never match the type 'false' comparisons.erl:206: The pattern 'true' can never match the type 'false' -comparisons.erl:208: The pattern 'true' can never match the type 'false' +comparisons.erl:207: The pattern 'false' can never match the type 'true' +comparisons.erl:208: The pattern 'false' can never match the type 'true' comparisons.erl:209: The pattern 'true' can never match the type 'false' -comparisons.erl:210: The pattern 'false' can never match the type 'true' +comparisons.erl:210: The pattern 'true' can never match the type 'false' comparisons.erl:211: The pattern 'false' can never match the type 'true' +comparisons.erl:212: The pattern 'false' can never match the type 'true' +comparisons.erl:213: The pattern 'true' can never match the type 'false' +comparisons.erl:214: The pattern 'true' can never match the type 'false' +comparisons.erl:215: The pattern 'false' can never match the type 'true' +comparisons.erl:216: The pattern 'false' can never match the type 'true' +comparisons.erl:217: The pattern 'true' can never match the type 'false' +comparisons.erl:218: The pattern 'true' can never match the type 'false' +comparisons.erl:219: The pattern 'false' can never match the type 'true' +comparisons.erl:220: The pattern 'false' can never match the type 'true' comparisons.erl:221: The pattern 'true' can never match the type 'false' comparisons.erl:222: The pattern 'true' can never match the type 'false' comparisons.erl:223: The pattern 'false' can never match the type 'true' comparisons.erl:224: The pattern 'false' can never match the type 'true' -comparisons.erl:225: The pattern 'true' can never match the type 'false' -comparisons.erl:226: The pattern 'true' can never match the type 'false' -comparisons.erl:227: The pattern 'false' can never match the type 'true' -comparisons.erl:228: The pattern 'false' can never match the type 'true' +comparisons.erl:229: The pattern 'true' can never match the type 'false' +comparisons.erl:230: The pattern 'true' can never match the type 'false' +comparisons.erl:231: The pattern 'false' can never match the type 'true' +comparisons.erl:232: The pattern 'false' can never match the type 'true' +comparisons.erl:233: The pattern 'false' can never match the type 'true' +comparisons.erl:234: The pattern 'false' can never match the type 'true' +comparisons.erl:235: The pattern 'true' can never match the type 'false' +comparisons.erl:236: The pattern 'true' can never match the type 'false' comparisons.erl:242: The pattern 'false' can never match the type 'true' comparisons.erl:243: The pattern 'false' can never match the type 'true' comparisons.erl:244: The pattern 'true' can never match the type 'false' @@ -97,57 +116,86 @@ comparisons.erl:246: The pattern 'false' can never match the type 'true' comparisons.erl:247: The pattern 'false' can never match the type 'true' comparisons.erl:248: The pattern 'true' can never match the type 'false' comparisons.erl:249: The pattern 'true' can never match the type 'false' -comparisons.erl:251: The pattern 'true' can never match the type 'false' -comparisons.erl:252: The pattern 'true' can never match the type 'false' -comparisons.erl:253: The pattern 'false' can never match the type 'true' -comparisons.erl:254: The pattern 'false' can never match the type 'true' -comparisons.erl:263: The pattern 'false' can never match the type 'true' -comparisons.erl:264: The pattern 'false' can never match the type 'true' +comparisons.erl:259: The pattern 'false' can never match the type 'true' +comparisons.erl:260: The pattern 'false' can never match the type 'true' +comparisons.erl:261: The pattern 'true' can never match the type 'false' +comparisons.erl:262: The pattern 'true' can never match the type 'false' +comparisons.erl:264: The pattern 'true' can never match the type 'false' comparisons.erl:265: The pattern 'true' can never match the type 'false' -comparisons.erl:266: The pattern 'true' can never match the type 'false' -comparisons.erl:268: The pattern 'true' can never match the type 'false' -comparisons.erl:269: The pattern 'true' can never match the type 'false' -comparisons.erl:270: The pattern 'false' can never match the type 'true' -comparisons.erl:271: The pattern 'false' can never match the type 'true' -comparisons.erl:272: The pattern 'true' can never match the type 'false' -comparisons.erl:273: The pattern 'true' can never match the type 'false' -comparisons.erl:274: The pattern 'false' can never match the type 'true' -comparisons.erl:275: The pattern 'false' can never match the type 'true' -comparisons.erl:293: The pattern 'false' can never match the type 'true' -comparisons.erl:294: The pattern 'false' can never match the type 'true' -comparisons.erl:295: The pattern 'true' can never match the type 'false' -comparisons.erl:296: The pattern 'true' can never match the type 'false' -comparisons.erl:311: The pattern 'true' can never match the type 'false' -comparisons.erl:312: The pattern 'true' can never match the type 'false' -comparisons.erl:313: The pattern 'false' can never match the type 'true' -comparisons.erl:314: The pattern 'false' can never match the type 'true' -comparisons.erl:44: The pattern 'false' can never match the type 'true' -comparisons.erl:45: The pattern 'false' can never match the type 'true' -comparisons.erl:46: The pattern 'true' can never match the type 'false' -comparisons.erl:47: The pattern 'true' can never match the type 'false' -comparisons.erl:48: The pattern 'false' can never match the type 'true' -comparisons.erl:49: The pattern 'false' can never match the type 'true' -comparisons.erl:50: The pattern 'true' can never match the type 'false' -comparisons.erl:51: The pattern 'true' can never match the type 'false' +comparisons.erl:266: The pattern 'false' can never match the type 'true' +comparisons.erl:267: The pattern 'false' can never match the type 'true' +comparisons.erl:277: The pattern 'true' can never match the type 'false' +comparisons.erl:278: The pattern 'true' can never match the type 'false' +comparisons.erl:279: The pattern 'false' can never match the type 'true' +comparisons.erl:280: The pattern 'false' can never match the type 'true' +comparisons.erl:281: The pattern 'true' can never match the type 'false' +comparisons.erl:282: The pattern 'true' can never match the type 'false' +comparisons.erl:283: The pattern 'false' can never match the type 'true' +comparisons.erl:284: The pattern 'false' can never match the type 'true' +comparisons.erl:298: The pattern 'false' can never match the type 'true' +comparisons.erl:299: The pattern 'false' can never match the type 'true' +comparisons.erl:300: The pattern 'true' can never match the type 'false' +comparisons.erl:301: The pattern 'true' can never match the type 'false' +comparisons.erl:302: The pattern 'false' can never match the type 'true' +comparisons.erl:303: The pattern 'false' can never match the type 'true' +comparisons.erl:304: The pattern 'true' can never match the type 'false' +comparisons.erl:305: The pattern 'true' can never match the type 'false' +comparisons.erl:307: The pattern 'true' can never match the type 'false' +comparisons.erl:308: The pattern 'true' can never match the type 'false' +comparisons.erl:309: The pattern 'false' can never match the type 'true' +comparisons.erl:310: The pattern 'false' can never match the type 'true' +comparisons.erl:319: The pattern 'false' can never match the type 'true' +comparisons.erl:320: The pattern 'false' can never match the type 'true' +comparisons.erl:321: The pattern 'true' can never match the type 'false' +comparisons.erl:322: The pattern 'true' can never match the type 'false' +comparisons.erl:324: The pattern 'true' can never match the type 'false' +comparisons.erl:325: The pattern 'true' can never match the type 'false' +comparisons.erl:326: The pattern 'false' can never match the type 'true' +comparisons.erl:327: The pattern 'false' can never match the type 'true' +comparisons.erl:328: The pattern 'true' can never match the type 'false' +comparisons.erl:329: The pattern 'true' can never match the type 'false' +comparisons.erl:330: The pattern 'false' can never match the type 'true' +comparisons.erl:331: The pattern 'false' can never match the type 'true' +comparisons.erl:349: The pattern 'false' can never match the type 'true' +comparisons.erl:350: The pattern 'false' can never match the type 'true' +comparisons.erl:351: The pattern 'true' can never match the type 'false' +comparisons.erl:352: The pattern 'true' can never match the type 'false' +comparisons.erl:367: The pattern 'true' can never match the type 'false' +comparisons.erl:368: The pattern 'true' can never match the type 'false' +comparisons.erl:369: The pattern 'false' can never match the type 'true' +comparisons.erl:370: The pattern 'false' can never match the type 'true' comparisons.erl:52: The pattern 'false' can never match the type 'true' comparisons.erl:53: The pattern 'false' can never match the type 'true' comparisons.erl:54: The pattern 'true' can never match the type 'false' comparisons.erl:55: The pattern 'true' can never match the type 'false' +comparisons.erl:56: The pattern 'false' can never match the type 'true' +comparisons.erl:57: The pattern 'false' can never match the type 'true' +comparisons.erl:58: The pattern 'true' can never match the type 'false' +comparisons.erl:59: The pattern 'true' can never match the type 'false' +comparisons.erl:60: The pattern 'false' can never match the type 'true' +comparisons.erl:61: The pattern 'false' can never match the type 'true' +comparisons.erl:62: The pattern 'true' can never match the type 'false' +comparisons.erl:63: The pattern 'true' can never match the type 'false' +comparisons.erl:64: The pattern 'false' can never match the type 'true' +comparisons.erl:65: The pattern 'false' can never match the type 'true' +comparisons.erl:66: The pattern 'true' can never match the type 'false' +comparisons.erl:67: The pattern 'true' can never match the type 'false' +comparisons.erl:68: The pattern 'false' can never match the type 'true' comparisons.erl:69: The pattern 'false' can never match the type 'true' -comparisons.erl:70: The pattern 'false' can never match the type 'true' +comparisons.erl:70: The pattern 'true' can never match the type 'false' comparisons.erl:71: The pattern 'true' can never match the type 'false' -comparisons.erl:72: The pattern 'true' can never match the type 'false' -comparisons.erl:73: The pattern 'false' can never match the type 'true' -comparisons.erl:74: The pattern 'false' can never match the type 'true' -comparisons.erl:75: The pattern 'true' can never match the type 'false' -comparisons.erl:76: The pattern 'true' can never match the type 'false' -comparisons.erl:77: The pattern 'false' can never match the type 'true' -comparisons.erl:78: The pattern 'false' can never match the type 'true' -comparisons.erl:79: The pattern 'true' can never match the type 'false' -comparisons.erl:80: The pattern 'true' can never match the type 'false' +comparisons.erl:85: The pattern 'false' can never match the type 'true' +comparisons.erl:86: The pattern 'false' can never match the type 'true' +comparisons.erl:87: The pattern 'true' can never match the type 'false' +comparisons.erl:88: The pattern 'true' can never match the type 'false' +comparisons.erl:89: The pattern 'false' can never match the type 'true' +comparisons.erl:90: The pattern 'false' can never match the type 'true' +comparisons.erl:91: The pattern 'true' can never match the type 'false' +comparisons.erl:92: The pattern 'true' can never match the type 'false' +comparisons.erl:93: The pattern 'false' can never match the type 'true' comparisons.erl:94: The pattern 'false' can never match the type 'true' -comparisons.erl:95: The pattern 'false' can never match the type 'true' +comparisons.erl:95: The pattern 'true' can never match the type 'false' comparisons.erl:96: The pattern 'true' can never match the type 'false' -comparisons.erl:97: The pattern 'true' can never match the type 'false' +comparisons.erl:97: The pattern 'false' can never match the type 'true' comparisons.erl:98: The pattern 'false' can never match the type 'true' -comparisons.erl:99: The pattern 'false' can never match the type 'true' +comparisons.erl:99: The pattern 'true' can never match the type 'false' diff --git a/lib/dialyzer/test/small_SUITE_data/results/fun_arity b/lib/dialyzer/test/small_SUITE_data/results/fun_arity new file mode 100644 index 0000000000..cc9db65152 --- /dev/null +++ b/lib/dialyzer/test/small_SUITE_data/results/fun_arity @@ -0,0 +1,37 @@ + +fun_arity.erl:100: Fun application will fail since _cor1 :: fun(() -> any()) is not a function of arity 1 +fun_arity.erl:100: Function 'Mfa_0_ko'/1 has no local return +fun_arity.erl:104: Fun application will fail since _cor1 :: fun((_) -> any()) is not a function of arity 0 +fun_arity.erl:104: Function 'Mfa_1_ko'/1 has no local return +fun_arity.erl:111: Fun application will fail since _cor1 :: fun(() -> any()) is not a function of arity 1 +fun_arity.erl:111: Function mFa_0_ko/1 has no local return +fun_arity.erl:115: Fun application will fail since _cor1 :: fun((_) -> any()) is not a function of arity 0 +fun_arity.erl:115: Function mFa_1_ko/1 has no local return +fun_arity.erl:122: Fun application will fail since _cor2 :: fun(() -> any()) is not a function of arity 1 +fun_arity.erl:122: Function 'MFa_0_ko'/2 has no local return +fun_arity.erl:126: Fun application will fail since _cor2 :: fun((_) -> any()) is not a function of arity 0 +fun_arity.erl:126: Function 'MFa_1_ko'/2 has no local return +fun_arity.erl:35: Fun application will fail since _cor0 :: fun(() -> 'ok') is not a function of arity 1 +fun_arity.erl:35: Function f_0_ko/0 has no local return +fun_arity.erl:39: Fun application will fail since _cor0 :: fun((_) -> 'ok') is not a function of arity 0 +fun_arity.erl:39: Function f_1_ko/0 has no local return +fun_arity.erl:48: Fun application will fail since _cor0 :: fun(() -> 'ok') is not a function of arity 1 +fun_arity.erl:48: Function fa_0_ko/0 has no local return +fun_arity.erl:53: Fun application will fail since _cor0 :: fun((_) -> 'ok') is not a function of arity 0 +fun_arity.erl:53: Function fa_1_ko/0 has no local return +fun_arity.erl:63: Fun application will fail since _cor0 :: fun(() -> any()) is not a function of arity 1 +fun_arity.erl:63: Function mfa_0_ko/0 has no local return +fun_arity.erl:68: Fun application will fail since _cor0 :: fun((_) -> any()) is not a function of arity 0 +fun_arity.erl:68: Function mfa_1_ko/0 has no local return +fun_arity.erl:76: Fun application will fail since _cor0 :: fun(() -> any()) is not a function of arity 1 +fun_arity.erl:76: Function mfa_ne_0_ko/0 has no local return +fun_arity.erl:78: Function mf_ne/0 will never be called +fun_arity.erl:81: Fun application will fail since _cor0 :: fun((_) -> any()) is not a function of arity 0 +fun_arity.erl:81: Function mfa_ne_1_ko/0 has no local return +fun_arity.erl:83: Function mf_ne/1 will never be called +fun_arity.erl:89: Fun application will fail since _cor0 :: fun(() -> any()) is not a function of arity 1 +fun_arity.erl:89: Function mfa_nd_0_ko/0 has no local return +fun_arity.erl:90: Call to missing or unexported function fun_arity:mf_nd/0 +fun_arity.erl:93: Fun application will fail since _cor0 :: fun((_) -> any()) is not a function of arity 0 +fun_arity.erl:93: Function mfa_nd_1_ko/0 has no local return +fun_arity.erl:94: Call to missing or unexported function fun_arity:mf_nd/1 diff --git a/lib/dialyzer/test/small_SUITE_data/results/maps1 b/lib/dialyzer/test/small_SUITE_data/results/maps1 new file mode 100644 index 0000000000..5a78d66a92 --- /dev/null +++ b/lib/dialyzer/test/small_SUITE_data/results/maps1 @@ -0,0 +1,4 @@ + +maps1.erl:43: Function t3/0 has no local return +maps1.erl:44: The call maps1:foo(~{'greger'=>3, ~{'arne'=>'anka'}~=>45}~,1) will never return since it differs in the 2nd argument from the success typing arguments: (#{},'b') +maps1.erl:52: The call Mod:'function'(~{'literal'=>'map'}~,'another_arg') requires that Mod is of type atom() | tuple() not #{} diff --git a/lib/dialyzer/test/small_SUITE_data/results/non_existing b/lib/dialyzer/test/small_SUITE_data/results/non_existing index 58da2bfc8b..b0da5998c7 100644 --- a/lib/dialyzer/test/small_SUITE_data/results/non_existing +++ b/lib/dialyzer/test/small_SUITE_data/results/non_existing @@ -1,2 +1,3 @@ +non_existing.erl:12: Call to missing or unexported function lists:non_existing_fun/1 non_existing.erl:9: Call to missing or unexported function lists:non_existing_call/1 diff --git a/lib/dialyzer/test/small_SUITE_data/src/abs.erl b/lib/dialyzer/test/small_SUITE_data/src/abs.erl new file mode 100644 index 0000000000..251e24cdfc --- /dev/null +++ b/lib/dialyzer/test/small_SUITE_data/src/abs.erl @@ -0,0 +1,71 @@ +-module(abs). + +%% OTP-12948. erlang:abs/1 bug fix. + +-export([t/0]). + +t() -> + Fs = [fun i1/0, fun i2/0, fun i3/0, fun i4/0, fun f1/0], + _ = [catch F() || F <- Fs], + ok. + +i1() -> + A = int(), + I1 = i1(A), + true = I1 < 2, + true = I1 < 1. % can never match + +-spec i1(neg_integer()) -> non_neg_integer(). + +i1(A) when is_integer(A), A < 0 -> + abs(A). + +i2() -> + A = int(), + I2 = i2(A), + true = I2 < 1, + true = I2 < 0. % can never match + +-spec i2(non_neg_integer()) -> non_neg_integer(). + +i2(A) when is_integer(A), A >= 0 -> + abs(A). + +i3() -> + A = int(), + I3 = i3(A), + true = I3 < -1, + true = I3 < 0. % can never match + +-spec i3(integer()) -> non_neg_integer(). + +i3(A) when is_integer(A) -> + abs(A). + +i4() -> + A = int(), + I4 = i4(A), + true = I4 =:= 0 orelse I4 =:= 1, + true = I4 < 0 orelse I4 > 1. % can never match + +-spec i4(integer()) -> number(). + +i4(A) when A =:= -1; A =:= 0; A =:= 1 -> + abs(A). + +f1() -> + F1 = f1(float()), + math:sqrt(F1). + +f1(A) -> + abs(A). + +-spec int() -> integer(). + +int() -> + foo:bar(). + +-spec float() -> float(). + +float() -> + math:sqrt(1.0). diff --git a/lib/dialyzer/test/small_SUITE_data/src/comparisons.erl b/lib/dialyzer/test/small_SUITE_data/src/comparisons.erl index 70e3cb6af4..64927c6c91 100644 --- a/lib/dialyzer/test/small_SUITE_data/src/comparisons.erl +++ b/lib/dialyzer/test/small_SUITE_data/src/comparisons.erl @@ -19,12 +19,20 @@ tuple(X) when is_tuple(X) -> X. list() -> list(?r). list(X) when is_list(X) -> X. +map() -> map(?r). +map(X) when is_map(X) -> #{}. + +bitstring() -> bitstring(?r). +bitstring(X) when is_bitstring(X) -> <<0:63>>. + i() -> integer(). f() -> mfloat(). n() -> case ?r of 1 -> i(); 2 -> f() end. a() -> atom(). t() -> tuple(). l() -> list(). +m() -> map(). +b() -> bitstring(). na() -> case ?r of 1 -> n(); 2 -> a() end. at() -> case ?r of 1 -> t(); 2 -> a() end. tl() -> case ?r of 1 -> t(); 2 -> l() end. @@ -53,6 +61,14 @@ test_i_ll_l() -> case i() < l() of true -> always; false -> never end. test_i_le_l() -> case i() =< l() of true -> always; false -> never end. test_i_gg_l() -> case i() > l() of true -> never; false -> always end. test_i_ge_l() -> case i() >= l() of true -> never; false -> always end. +test_i_ll_m() -> case i() < m() of true -> always; false -> never end. +test_i_le_m() -> case i() =< m() of true -> always; false -> never end. +test_i_gg_m() -> case i() > m() of true -> never; false -> always end. +test_i_ge_m() -> case i() >= m() of true -> never; false -> always end. +test_i_ll_b() -> case i() < b() of true -> always; false -> never end. +test_i_le_b() -> case i() =< b() of true -> always; false -> never end. +test_i_gg_b() -> case i() > b() of true -> never; false -> always end. +test_i_ge_b() -> case i() >= b() of true -> never; false -> always end. test_f_ll_i() -> case f() < i() of true -> maybe; false -> maybe_too end. test_f_le_i() -> case f() =< i() of true -> maybe; false -> maybe_too end. @@ -78,6 +94,14 @@ test_f_ll_l() -> case f() < l() of true -> always; false -> never end. test_f_le_l() -> case f() =< l() of true -> always; false -> never end. test_f_gg_l() -> case f() > l() of true -> never; false -> always end. test_f_ge_l() -> case f() >= l() of true -> never; false -> always end. +test_f_ll_m() -> case f() < m() of true -> always; false -> never end. +test_f_le_m() -> case f() =< m() of true -> always; false -> never end. +test_f_gg_m() -> case f() > m() of true -> never; false -> always end. +test_f_ge_m() -> case f() >= m() of true -> never; false -> always end. +test_f_ll_b() -> case f() < b() of true -> always; false -> never end. +test_f_le_b() -> case f() =< b() of true -> always; false -> never end. +test_f_gg_b() -> case f() > b() of true -> never; false -> always end. +test_f_ge_b() -> case f() >= b() of true -> never; false -> always end. test_n_ll_i() -> case n() < i() of true -> maybe; false -> maybe_too end. test_n_le_i() -> case n() =< i() of true -> maybe; false -> maybe_too end. @@ -103,6 +127,14 @@ test_n_ll_l() -> case n() < l() of true -> always; false -> never end. test_n_le_l() -> case n() =< l() of true -> always; false -> never end. test_n_gg_l() -> case n() > l() of true -> never; false -> always end. test_n_ge_l() -> case n() >= l() of true -> never; false -> always end. +test_n_ll_m() -> case n() < m() of true -> always; false -> never end. +test_n_le_m() -> case n() =< m() of true -> always; false -> never end. +test_n_gg_m() -> case n() > m() of true -> never; false -> always end. +test_n_ge_m() -> case n() >= m() of true -> never; false -> always end. +test_n_ll_b() -> case n() < b() of true -> always; false -> never end. +test_n_le_b() -> case n() =< b() of true -> always; false -> never end. +test_n_gg_b() -> case n() > b() of true -> never; false -> always end. +test_n_ge_b() -> case n() >= b() of true -> never; false -> always end. test_a_ll_i() -> case a() < i() of true -> never; false -> always end. test_a_le_i() -> case a() =< i() of true -> never; false -> always end. @@ -128,6 +160,14 @@ test_a_ll_l() -> case a() < l() of true -> always; false -> never end. test_a_le_l() -> case a() =< l() of true -> always; false -> never end. test_a_gg_l() -> case a() > l() of true -> never; false -> always end. test_a_ge_l() -> case a() >= l() of true -> never; false -> always end. +test_a_ll_m() -> case a() < m() of true -> always; false -> never end. +test_a_le_m() -> case a() =< m() of true -> always; false -> never end. +test_a_gg_m() -> case a() > m() of true -> never; false -> always end. +test_a_ge_m() -> case a() >= m() of true -> never; false -> always end. +test_a_ll_b() -> case a() < b() of true -> always; false -> never end. +test_a_le_b() -> case a() =< b() of true -> always; false -> never end. +test_a_gg_b() -> case a() > b() of true -> never; false -> always end. +test_a_ge_b() -> case a() >= b() of true -> never; false -> always end. test_t_ll_i() -> case t() < i() of true -> never; false -> always end. test_t_le_i() -> case t() =< i() of true -> never; false -> always end. @@ -153,6 +193,14 @@ test_t_ll_l() -> case t() < l() of true -> always; false -> never end. test_t_le_l() -> case t() =< l() of true -> always; false -> never end. test_t_gg_l() -> case t() > l() of true -> never; false -> always end. test_t_ge_l() -> case t() >= l() of true -> never; false -> always end. +test_t_ll_m() -> case t() < m() of true -> always; false -> never end. +test_t_le_m() -> case t() =< m() of true -> always; false -> never end. +test_t_gg_m() -> case t() > m() of true -> never; false -> always end. +test_t_ge_m() -> case t() >= m() of true -> never; false -> always end. +test_t_ll_b() -> case t() < b() of true -> always; false -> never end. +test_t_le_b() -> case t() =< b() of true -> always; false -> never end. +test_t_gg_b() -> case t() > b() of true -> never; false -> always end. +test_t_ge_b() -> case t() >= b() of true -> never; false -> always end. test_l_ll_i() -> case l() < i() of true -> never; false -> always end. test_l_le_i() -> case l() =< i() of true -> never; false -> always end. @@ -178,6 +226,14 @@ test_l_ll_l() -> case l() < l() of true -> maybe; false -> maybe_too end. test_l_le_l() -> case l() =< l() of true -> maybe; false -> maybe_too end. test_l_gg_l() -> case l() > l() of true -> maybe; false -> maybe_too end. test_l_ge_l() -> case l() >= l() of true -> maybe; false -> maybe_too end. +test_l_ll_m() -> case l() < m() of true -> never; false -> always end. +test_l_le_m() -> case l() =< m() of true -> never; false -> always end. +test_l_gg_m() -> case l() > m() of true -> always; false -> never end. +test_l_ge_m() -> case l() >= m() of true -> always; false -> never end. +test_l_ll_b() -> case l() < b() of true -> always; false -> never end. +test_l_le_b() -> case l() =< b() of true -> always; false -> never end. +test_l_gg_b() -> case l() > b() of true -> never; false -> always end. +test_l_ge_b() -> case l() >= b() of true -> never; false -> always end. test_n_ll_na() -> case n() < na() of true -> maybe; false -> maybe_too end. test_n_le_na() -> case n() =< na() of true -> maybe; false -> maybe_too end. diff --git a/lib/dialyzer/test/small_SUITE_data/src/fun_arity.erl b/lib/dialyzer/test/small_SUITE_data/src/fun_arity.erl new file mode 100644 index 0000000000..850d2fd331 --- /dev/null +++ b/lib/dialyzer/test/small_SUITE_data/src/fun_arity.erl @@ -0,0 +1,127 @@ +%%-------------------------------------------------------------------------- +%% Module which contains calls to funs of different arity. +%%-------------------------------------------------------------------------- +-module(fun_arity). + +-export([f_0_ok/0, f_0_ko/0]). +-export([f_1_ok/0, f_1_ko/0]). + +-export([fa_0_ok/0, fa_0_ko/0]). +-export([fa_1_ok/0, fa_1_ko/0]). + +-export([mfa_0_ok/0, mfa_0_ko/0, mf/0]). +-export([mfa_1_ok/0, mfa_1_ko/0, mf/1]). + +-export([mfa_ne_0_ok/0, mfa_ne_0_ko/0]). +-export([mfa_ne_1_ok/0, mfa_ne_1_ko/0]). + +-export([mfa_nd_0_ok/0, mfa_nd_0_ko/0]). +-export([mfa_nd_1_ok/0, mfa_nd_1_ko/0]). + +-export(['Mfa_0_ok'/1, 'Mfa_0_ko'/1]). +-export(['Mfa_1_ok'/1, 'Mfa_1_ko'/1]). + +-export(['mFa_0_ok'/1, 'mFa_0_ko'/1]). +-export(['mFa_1_ok'/1, 'mFa_1_ko'/1]). + +-export(['MFa_0_ok'/2, 'MFa_0_ko'/2]). +-export(['MFa_1_ok'/2, 'MFa_1_ko'/2]). + +%%-------------------------------------------------------------------------- + +%% Funs like "fun(...) -> ... end". + +f_0_ok() -> (fun_f_0())(). +f_0_ko() -> (fun_f_0())(1). +fun_f_0() -> fun() -> ok end. + +f_1_ok() -> (fun_f_1())(1). +f_1_ko() -> (fun_f_1())(). +fun_f_1() -> fun(_) -> ok end . + +%%-------------------------------------------------------------------------- + +%% Funs like "fun F/A" when F is literal atom and A is literal +%% non-negative integer. + +fa_0_ok() -> (fun_fa_0())(). +fa_0_ko() -> (fun_fa_0())(1). +fun_fa_0() -> fun f/0. +f() -> ok. + +fa_1_ok() -> (fun_fa_1())(1). +fa_1_ko() -> (fun_fa_1())(). +fun_fa_1() -> fun f/1. +f(_) -> ok. + +%%-------------------------------------------------------------------------- + +%% Funs like "fun M:F/A" when M and F are literal atoms, A is literal +%% non-negative integer and function is (defined and) exported. + +mfa_0_ok() -> (fun_mfa_0())(). +mfa_0_ko() -> (fun_mfa_0())(1). +fun_mfa_0() -> fun ?MODULE:mf/0. +mf() -> ok. + +mfa_1_ok() -> (fun_mfa_1())(1). +mfa_1_ko() -> (fun_mfa_1())(). +fun_mfa_1() -> fun ?MODULE:mf/1. +mf(_) -> ok. + +%% Funs like "fun M:F/A" when M and F are literal atoms, A is literal +%% non-negative integer and function is defined but not exported. + +mfa_ne_0_ok() -> (fun_mfa_ne_0())(). +mfa_ne_0_ko() -> (fun_mfa_ne_0())(1). +fun_mfa_ne_0() -> fun ?MODULE:mf_ne/0. +mf_ne() -> ok. + +mfa_ne_1_ok() -> (fun_mfa_ne_1())(1). +mfa_ne_1_ko() -> (fun_mfa_ne_1())(). +fun_mfa_ne_1() -> fun ?MODULE:mf_ne/1. +mf_ne(_) -> ok. + +%% Funs like "fun M:F/A" when M and F are literal atoms, A is literal +%% non-negative integer and function is not defined. + +mfa_nd_0_ok() -> (fun_mfa_nd_0())(). +mfa_nd_0_ko() -> (fun_mfa_nd_0())(1). +fun_mfa_nd_0() -> fun ?MODULE:mf_nd/0. + +mfa_nd_1_ok() -> (fun_mfa_nd_1())(1). +mfa_nd_1_ko() -> (fun_mfa_nd_1())(). +fun_mfa_nd_1() -> fun ?MODULE:mf_nd/1. + +%% Funs like "fun M:F/A" when M is variable, F is literal atoms and A +%% is literal non-negative integer. + +'Mfa_0_ok'(M) -> ('fun_Mfa_0'(M))(). +'Mfa_0_ko'(M) -> ('fun_Mfa_0'(M))(1). +'fun_Mfa_0'(M) -> fun M:f/0. + +'Mfa_1_ok'(M) -> ('fun_Mfa_1'(M))(1). +'Mfa_1_ko'(M) -> ('fun_Mfa_1'(M))(). +'fun_Mfa_1'(M) -> fun M:f/1. + +%% Funs like "fun M:F/A" when M is literal atom, F is variable and A +%% is literal non-negative integer. + +'mFa_0_ok'(F) -> ('fun_mFa_0'(F))(). +'mFa_0_ko'(F) -> ('fun_mFa_0'(F))(1). +'fun_mFa_0'(F) -> fun ?MODULE:F/0. + +'mFa_1_ok'(F) -> ('fun_mFa_1'(F))(1). +'mFa_1_ko'(F) -> ('fun_mFa_1'(F))(). +'fun_mFa_1'(F) -> fun ?MODULE:F/1. + +%% Funs like "fun M:F/A" when M and F are variables and A is literal +%% non-negative integer. + +'MFa_0_ok'(M, F) -> ('fun_MFa_0'(M, F))(). +'MFa_0_ko'(M, F) -> ('fun_MFa_0'(M, F))(1). +'fun_MFa_0'(M, F) -> fun M:F/0. + +'MFa_1_ok'(M, F) -> ('fun_MFa_1'(M, F))(1). +'MFa_1_ko'(M, F) -> ('fun_MFa_1'(M, F))(). +'fun_MFa_1'(M, F) -> fun M:F/1. diff --git a/lib/dialyzer/test/small_SUITE_data/src/keydel.erl b/lib/dialyzer/test/small_SUITE_data/src/keydel.erl new file mode 100644 index 0000000000..18a5c0670c --- /dev/null +++ b/lib/dialyzer/test/small_SUITE_data/src/keydel.erl @@ -0,0 +1,29 @@ +-module(keydel). + +-export([store/3]). + +-record(att, {f}). + +-type attachment() :: list(). + +-opaque att() :: #att{} | attachment(). + +-spec store(atom(), any(), att()) -> att(). +store(Field, undefined, Att) when is_list(Att) -> + lists:keydelete(Field, 1, Att); +store(Field, Value, Att) when is_list(Att) -> + lists:keystore(Field, 1, Att, {Field, Value}); +store(Field, Value, Att) -> + store(Field, Value, upgrade(Att)). + + +-spec upgrade(#att{}) -> attachment(). +upgrade(#att{} = Att) -> + Map = lists:zip( + record_info(fields, att), + lists:seq(2, record_info(size, att)) + ), + %% Don't store undefined elements since that is default + [{F, element(I, Att)} || {F, I} <- Map, element(I, Att) /= undefined]; +upgrade(Att) -> + Att. diff --git a/lib/dialyzer/test/small_SUITE_data/src/maps1.erl b/lib/dialyzer/test/small_SUITE_data/src/maps1.erl index 06ced5b69e..bb2f66a498 100644 --- a/lib/dialyzer/test/small_SUITE_data/src/maps1.erl +++ b/lib/dialyzer/test/small_SUITE_data/src/maps1.erl @@ -39,3 +39,15 @@ t2() -> ok. update(#{ id := Id, val := Val } = M, X) when is_integer(Id) -> M#{ val := [Val,X] }. + +t3() -> + foo(#{greger => 3, #{arne=>anka} => 45}, 1). + +foo(#{} = M, b) -> %% Error + M#{alfa => 42, beta := 1337}. + +t4() -> + case #{} of + #{} -> ok; + Mod -> Mod:function(#{literal => map}, another_arg) %% Error + end. diff --git a/lib/dialyzer/vsn.mk b/lib/dialyzer/vsn.mk index 48e0830109..44982ab46d 100644 --- a/lib/dialyzer/vsn.mk +++ b/lib/dialyzer/vsn.mk @@ -1 +1 @@ -DIALYZER_VSN = 2.8 +DIALYZER_VSN = 2.9 diff --git a/lib/diameter/doc/src/diameter.xml b/lib/diameter/doc/src/diameter.xml index 1e1206aa2d..5cb29c80e3 100644 --- a/lib/diameter/doc/src/diameter.xml +++ b/lib/diameter/doc/src/diameter.xml @@ -467,7 +467,7 @@ Matches only those peers whose Origin-Host has the specified value, or all peers if the atom <c>any</c>.</p> </item> -<tag><c>{realm, any|&dict_DiameterIdentity;</c></tag> +<tag><c>{realm, any|&dict_DiameterIdentity;}</c></tag> <item> <p> Matches only those peers whose Origin-Realm has the @@ -500,18 +500,22 @@ Matches only those peers matched by each filter in the specified list.</p> <item> <p> Matches only those peers matched by at least one filter in the -specified list.</p> +specified list. +The resulting list will be in match order, peers matching the +first filter of the list sorting before those matched by the second, +and so on.</p> +</item> +<tag><c>{first, [&peer_filter;]}</c></tag> +<item> <p> -The resulting peer list will be in match order, peers matching the -first filter of the list sorting before those matched by the second, -and so on. -For example, the following filter causes peers matching both the host -and realm filters to be presented before those matching only the realm -filter.</p> +Like <c>any</c>, but stops at the first filter for which there are +matches, which can be much more efficient when there are many peers. +For example, the following filter causes only peers best matching +both the host and realm filters to be presented.</p> <pre> -{any, [{all, [host, realm]}, realm]} +{first, [{all, [host, realm]}, realm]} </pre> </item> @@ -795,14 +799,6 @@ Messages larger than the specified number of bytes are discarded.</p> Defaults to <c>16777215</c>, the maximum value of the 24-bit Message Length field in a Diameter Header.</p> -<warning> -<p> -This option should be set to as low a value as is sufficient for the -Diameter applications and peers in question, since decoding incoming -messages from a malicious peer can otherwise generate significant -load.</p> -</warning> - </item> <tag><c>{restrict_connections, false @@ -921,6 +917,49 @@ Options <c>monitor</c> and <c>link</c> are ignored.</p> Defaults to the empty list.</p> </item> +<marker id="strict_mbit"/> +<tag><c>{strict_mbit, boolean()}</c></tag> +<item> +<p> +Whether or not to regard an AVP setting the M-bit as erroneous when +the command grammar in question does not explicitly allow the AVP. +If <c>true</c> then such AVPs are regarded as 5001 errors, +DIAMETER_AVP_UNSUPPORTED. +If <c>false</c> then the M-bit is ignored and policing +it becomes the receiver's responsibility.</p> + +<p> +Defaults to <c>true</c>.</p> + +<warning> +<p> +RFC 6733 is unclear about the semantics of the M-bit. +One the one hand, the CCF specification in section 3.2 documents AVP +in a command grammar as meaning <b>any</b> arbitrary AVP; on the +other hand, 1.3.4 states that AVPs setting the M-bit cannot be added +to an existing command: the modified command must instead be +placed in a new Diameter application.</p> +<p> +The reason for the latter is presumably interoperability: +allowing arbitrary AVPs setting the M-bit in a command makes its +interpretation implementation-dependent, since there's no +guarantee that all implementations will understand the same set of +arbitrary AVPs in the context of a given command. +However, interpreting <c>AVP</c> in a command grammar as <b>any</b> +AVP, regardless of M-bit, renders 1.3.4 meaningless, since the receiver +can simply ignore any AVP it thinks isn't relevant, regardless of the +sender's intent.</p> +<p> +Beware of confusing mandatory in the sense of the M-bit with mandatory +in the sense of the command grammar. +The former is a semantic requirement: that the receiver understand the +semantics of the AVP in the context in question. +The latter is a syntactic requirement: whether or not the AVP must +occur in the message in question.</p> +</warning> + +</item> + <marker id="string_decode"/> <tag><c>{string_decode, boolean()}</c></tag> <item> @@ -1232,9 +1271,7 @@ is not the length of the message in question, as received over the transport interface documented in &man_transport;.</p> <p> -If <c>exit</c> then a warning report is emitted and the parent of the -transport process in question exits, which causes the transport -process itself to exit as described in &man_transport;. +If <c>exit</c> then the transport process in question exits. If <c>handle</c> then the message is processed as usual, a resulting &app_handle_request; or &app_handle_answer; callback (if one takes place) indicating the <c>5015</c> error (DIAMETER_INVALID_MESSAGE_LENGTH). diff --git a/lib/diameter/doc/src/notes.xml b/lib/diameter/doc/src/notes.xml index 299d4093da..5052515d6a 100644 --- a/lib/diameter/doc/src/notes.xml +++ b/lib/diameter/doc/src/notes.xml @@ -43,6 +43,149 @@ first.</p> <!-- ===================================================================== --> +<section><title>diameter 1.11.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Make peer handling more efficient.</p> + <p> + Inefficient lookup and manipulation of peer lists could + result in poor performance when many outgoing requests + were sent simultaneously, or when many peers connected + simultaneously. Filtering peer lists on realm/host is now + also more efficient in many cases.</p> + <p> + Own Id: OTP-13164</p> + </item> + <item> + <p> + Fix handling of shared peer connections in watchdog state + SUSPECT.</p> + <p> + A peer connection shared from a remote node was regarded + as being up for the lifetime of the connection, ignoring + watchdog transitions into state SUSPECT.</p> + <p> + Own Id: OTP-13342</p> + </item> + </list> + </section> + +</section> + +<section><title>diameter 1.11.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix request table leaks</p> + <p> + The End-to-End and Hop-by-Hop identifiers of outgoing + Diameter requests are stored in a table in order for the + caller to be located when the corresponding answer + message is received. Entries were orphaned if the handler + was terminated by an exit signal as a consequence of + actions taken by callback functions, or if callbacks + modified identifiers in retransmission cases.</p> + <p> + Own Id: OTP-13137</p> + </item> + </list> + </section> + +</section> + +<section><title>diameter 1.11</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix relay encode of nested, Grouped AVPs.</p> + <p> + A fault in OTP-12475 caused encode to fail if the first + AVP in a Grouped AVP was itself Grouped.</p> + <p> + Own Id: OTP-12879 Aux Id: OTP-12475 </p> + </item> + <item> + <p> + Match acceptable peer addresses case insensitively.</p> + <p> + Regular expressions passed in an 'accept' tuple to + diameter_tcp or diameter_sctp inappropriately matched + case.</p> + <p> + Own Id: OTP-12902</p> + </item> + <item> + <p> + Fix diameter_watchdog function clause.</p> + <p> + OTP-12912 introduced an error with accepting transports + setting <c>{restrict_connections, false}</c>, causing + processes to fail when peer connections were terminated.</p> + <p> + Own Id: OTP-12969</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Don't report 5005 (DIAMETER_AVP_MISSING) errors + unnecessarily.</p> + <p> + An AVP whose decode failed was reported as missing, + despite having been reported with another error as a + consequence of the failure.</p> + <p> + Own Id: OTP-12871</p> + </item> + <item> + <p> + Improve decode performance.</p> + <p> + The time required to decode a message increased + quadratically with the number of AVPs in the worst case, + leading to extremely long execution times.</p> + <p> + Own Id: OTP-12891</p> + </item> + <item> + <p> + Improve watchdog and statistics performance.</p> + <p> + Inefficient use of timers contributed to poor performance + at high load, as did ordering of the table statistics are + written to.</p> + <p> + Own Id: OTP-12912</p> + </item> + <item> + <p> + Add service_opt() strict_mbit.</p> + <p> + There are differing opinions on whether or not reception + of an arbitrary AVP setting the M-bit is an error. The + default interpretation is strict: if a command grammar + doesn't explicitly allow an AVP setting the M-bit then + reception of such an AVP is regarded as an error. Setting + <c>{strict_mbit, false}</c> disables this check.</p> + <p> + Own Id: OTP-12947</p> + </item> + </list> + </section> + +</section> + <section><title>diameter 1.10</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -134,7 +277,7 @@ first.</p> <item> <p> Change license text from Erlang Public License to Apache - Public License v2</p> + Public License v2.</p> <p> Own Id: OTP-12845</p> </item> diff --git a/lib/diameter/include/diameter_gen.hrl b/lib/diameter/include/diameter_gen.hrl index a43ab4edb2..611ad796a9 100644 --- a/lib/diameter/include/diameter_gen.hrl +++ b/lib/diameter/include/diameter_gen.hrl @@ -31,7 +31,10 @@ %% Key to a value in the process dictionary that determines whether or %% not an unrecognized AVP setting the M-bit should be regarded as an -%% error or not. See is_strict/0. +%% error or not. See is_strict/0. This is only used to relax M-bit +%% interpretation inside Grouped AVPs not setting the M-bit. The +%% service_opt() strict_mbit can be used to disable the check +%% globally. -define(STRICT_KEY, strict). %% Key that says whether or not we should do a best-effort decode @@ -186,9 +189,10 @@ decode_avps(Name, Recs) -> = lists:foldl(fun(T,A) -> decode(Name, T, A) end, {[], {newrec(Name), []}}, Recs), - {Rec, Avps, Failed ++ missing(Rec, Name)}. -%% Append 5005 errors so that a 5014 for the same AVP will take -%% precedence in a Result-Code/Failed-AVP setting. + {Rec, Avps, Failed ++ missing(Rec, Name, Failed)}. +%% Append 5005 errors so that errors are reported in the order +%% encountered. Failed-AVP should typically contain the first +%% encountered error accordg to the RFC. newrec(Name) -> '#new-'(name2rec(Name)). @@ -201,20 +205,36 @@ newrec(Name) -> %% Failed-AVP AVP SHOULD be included in the message. The Failed-AVP %% AVP MUST contain an example of the missing AVP complete with the %% Vendor-Id if applicable. The value field of the missing AVP -%% should be of correct minimum length and contain zeroes. - -missing(Rec, Name) -> - [{5005, empty_avp(F)} || F <- '#info-'(element(1, Rec), fields), - A <- [avp_arity(Name, F)], - false <- [have_arity(A, '#get-'(F, Rec))]]. +%% should be of correct minimum length and contain zeros. + +missing(Rec, Name, Failed) -> + Avps = lists:foldl(fun({_, #diameter_avp{code = C, vendor_id = V}}, A) -> + sets:add_element({C,V}, A) + end, + sets:new(), + Failed), + [{5005, A} || F <- '#info-'(element(1, Rec), fields), + not has_arity(avp_arity(Name, F), '#get-'(F, Rec)), + #diameter_avp{code = C, vendor_id = V} + = A <- [empty_avp(F)], + not sets:is_element({C,V}, Avps)]. %% Maximum arities have already been checked in building the record. -have_arity({Min, _}, L) -> - Min =< length(L); -have_arity(N, V) -> +has_arity({Min, _}, L) -> + has_prefix(Min, L); +has_arity(N, V) -> N /= 1 orelse V /= undefined. +%% Compare a non-negative integer and the length of a list without +%% computing the length. +has_prefix(0, _) -> + true; +has_prefix(_, []) -> + false; +has_prefix(N, L) -> + has_prefix(N-1, tl(L)). + %% empty_avp/1 empty_avp(Name) -> @@ -431,7 +451,8 @@ relax(_, _) -> false. is_strict() -> - false /= getr(?STRICT_KEY). + diameter_codec:getopt(strict_mbit) + andalso false /= getr(?STRICT_KEY). %% relax/1 %% @@ -608,14 +629,17 @@ pack(undefined, 1, FieldName, Avp, Acc) -> %% AVP MUST be included and contain a copy of the first instance of %% the offending AVP that exceeded the maximum number of occurrences %% + pack(_, 1, _, Avp, {Rec, Failed}) -> {Rec, [{5009, Avp} | Failed]}; -pack(L, {_, Max}, _, Avp, {Rec, Failed}) - when length(L) == Max -> - {Rec, [{5009, Avp} | Failed]}; - -pack(L, _, FieldName, Avp, Acc) -> - p(FieldName, fun(V) -> [V|L] end, Avp, Acc). +pack(L, {_, Max}, FieldName, Avp, Acc) -> + case '*' /= Max andalso has_prefix(Max, L) of + true -> + {Rec, Failed} = Acc, + {Rec, [{5009, Avp} | Failed]}; + false -> + p(FieldName, fun(V) -> [V|L] end, Avp, Acc) + end. %% p/4 diff --git a/lib/diameter/src/base/diameter.erl b/lib/diameter/src/base/diameter.erl index e82c2c168c..de88f6befd 100644 --- a/lib/diameter/src/base/diameter.erl +++ b/lib/diameter/src/base/diameter.erl @@ -312,6 +312,7 @@ call(SvcName, App, Message) -> | {sequence, sequence() | evaluable()} | {share_peers, remotes()} | {string_decode, boolean()} + | {strict_mbit, boolean()} | {incoming_maxlen, message_length()} | {use_shared_peers, remotes()} | {spawn_opt, list()}. diff --git a/lib/diameter/src/base/diameter_codec.erl b/lib/diameter/src/base/diameter_codec.erl index 34276a1674..1ea5357924 100644 --- a/lib/diameter/src/base/diameter_codec.erl +++ b/lib/diameter/src/base/diameter_codec.erl @@ -77,9 +77,10 @@ setopts(Opts) when is_list(Opts) -> lists:foreach(fun setopt/1, Opts). -%% Decode stringish types to string()? The default true is for -%% backwards compatibility. -setopt({string_decode = K, false = B}) -> +%% The default string_decode true is for backwards compatibility. +setopt({K, false = B}) + when K == string_decode; + K == strict_mbit -> setopt(K, B); %% Regard anything but the generated RFC 3588 dictionary as modern. @@ -97,7 +98,8 @@ setopt(Key, Value) -> getopt(Key) -> case get({diameter, Key}) of - undefined when Key == string_decode -> + undefined when Key == string_decode; + Key == strict_mbit -> true; undefined when Key == rfc -> 6733; @@ -657,16 +659,23 @@ split_data(Bin, Len) -> %% The normal case here is data as an #diameter_avp{} list or an %% iolist, which are the cases that generated codec modules use. The -%% other case is as a convenience in the relay case in which the +%% other cases are a convenience in the relay case in which the %% dictionary doesn't know about specific AVP's. -%% Grouped AVP whose components need packing ... -pack_avp([#diameter_avp{} = A | Avps]) -> - pack_avp(A#diameter_avp{data = Avps}); -pack_avp(#diameter_avp{data = [#diameter_avp{} | _] = Avps} = A) -> - pack_avp(A#diameter_avp{data = encode_avps(Avps)}); +%% Decoded Grouped AVP with decoded components: ignore components +%% since they're already encoded in the Grouped AVP. +pack_avp([#diameter_avp{} = Grouped | _Components]) -> + pack_avp(Grouped); -%% ... data as a type/value tuple ... +%% Grouped AVP whose components need packing. It's intentional that +%% this isn't equivalent to [Grouped | Components]: here the +%% components need to be encoded before wrapping with the Grouped AVP, +%% and the list is flat, nesting being accomplished in the data +%% fields. +pack_avp(#diameter_avp{data = [#diameter_avp{} | _] = Components} = Grouped) -> + pack_avp(Grouped#diameter_avp{data = encode_avps(Components)}); + +%% Data as a type/value tuple ... pack_avp(#diameter_avp{data = {Type, Value}} = A) when is_atom(Type) -> pack_avp(A#diameter_avp{data = diameter_types:Type(encode, Value)}); diff --git a/lib/diameter/src/base/diameter_config.erl b/lib/diameter/src/base/diameter_config.erl index 5ae4ff1f46..702f11593a 100644 --- a/lib/diameter/src/base/diameter_config.erl +++ b/lib/diameter/src/base/diameter_config.erl @@ -38,8 +38,7 @@ -module(diameter_config). -behaviour(gen_server). --compile({no_auto_import, [monitor/2, now/0]}). --import(diameter_lib, [now/0]). +-compile({no_auto_import, [monitor/2]}). -export([start_service/2, stop_service/1, @@ -70,7 +69,7 @@ -include("diameter_internal.hrl"). %% Server state. --record(state, {id = now()}). +-record(state, {id = diameter_lib:now()}). %% Registered name of the server. -define(SERVER, ?MODULE). @@ -648,6 +647,7 @@ make_config(SvcName, Opts) -> {?NOMASK, sequence}, {nodes, restrict_connections}, {16#FFFFFF, incoming_maxlen}, + {true, strict_mbit}, {true, string_decode}, {[], spawn_opt}]), @@ -686,12 +686,14 @@ opt(K, false = B) K == use_shared_peers; K == monitor; K == restrict_connections; + K == strict_mbit; K == string_decode -> B; opt(K, true = B) when K == share_peers; K == use_shared_peers; + K == strict_mbit; K == string_decode -> B; diff --git a/lib/diameter/src/base/diameter_lib.erl b/lib/diameter/src/base/diameter_lib.erl index b5b37dcf62..43b0ca24ab 100644 --- a/lib/diameter/src/base/diameter_lib.erl +++ b/lib/diameter/src/base/diameter_lib.erl @@ -103,32 +103,18 @@ fmt(T) -> %% # now/0 %% --------------------------------------------------------------------------- --type timestamp() :: {non_neg_integer(), 0..999999, 0..999999}. --type now() :: integer() %% monotonic time - | timestamp(). - -spec now() - -> now(). - -%% Use monotonic time if it exists, fall back to erlang:now() -%% otherwise. + -> integer(). now() -> - try - erlang:monotonic_time() - catch - error: undef -> erlang:now() - end. + erlang:monotonic_time(). %% --------------------------------------------------------------------------- %% # timestamp/1 %% --------------------------------------------------------------------------- --spec timestamp(NowT :: now()) - -> timestamp(). - -timestamp({_,_,_} = T) -> %% erlang:now() - T; +-spec timestamp(integer()) + -> erlang:timestamp(). timestamp(MonoT) -> %% monotonic time MicroSecs = monotonic_to_microseconds(MonoT + erlang:time_offset()), @@ -142,30 +128,27 @@ monotonic_to_microseconds(MonoT) -> %% # now_diff/1 %% --------------------------------------------------------------------------- --spec now_diff(NowT :: now()) +-spec now_diff(T0 :: integer()) -> {Hours, Mins, Secs, MicroSecs} when Hours :: non_neg_integer(), Mins :: 0..59, Secs :: 0..59, MicroSecs :: 0..999999. -%% Return timer:now_diff(now(), NowT) as an {H, M, S, MicroS} tuple -%% instead of as integer microseconds. +%% Return time difference as an {H, M, S, MicroS} tuple instead of as +%% integer microseconds. -now_diff(Time) -> - time(micro_diff(Time)). +now_diff(T0) -> + time(micro_diff(T0)). %% --------------------------------------------------------------------------- %% # micro_diff/1 %% --------------------------------------------------------------------------- --spec micro_diff(NowT :: now()) +-spec micro_diff(T0 :: integer()) -> MicroSecs when MicroSecs :: non_neg_integer(). -micro_diff({_,_,_} = T0) -> - timer:now_diff(erlang:now(), T0); - micro_diff(T0) -> %% monotonic time monotonic_to_microseconds(erlang:monotonic_time() - T0). @@ -173,16 +156,12 @@ micro_diff(T0) -> %% monotonic time %% # micro_diff/2 %% --------------------------------------------------------------------------- --spec micro_diff(T1 :: now(), T0 :: now()) +-spec micro_diff(T1 :: integer(), T0 :: integer()) -> MicroSecs when MicroSecs :: non_neg_integer(). -micro_diff(T1, T0) - when is_integer(T1), is_integer(T0) -> %% monotonic time - monotonic_to_microseconds(T1 - T0); - -micro_diff(T1, T0) -> %% at least one erlang:now() - timer:now_diff(timestamp(T1), timestamp(T0)). +micro_diff(T1, T0) -> %% monotonic time + monotonic_to_microseconds(T1 - T0). %% --------------------------------------------------------------------------- %% # time/1 @@ -190,19 +169,13 @@ micro_diff(T1, T0) -> %% at least one erlang:now() %% Return an elapsed time as an {H, M, S, MicroS} tuple. %% --------------------------------------------------------------------------- --spec time(NowT | Diff) +-spec time(Diff :: non_neg_integer()) -> {Hours, Mins, Secs, MicroSecs} - when NowT :: timestamp(), - Diff :: non_neg_integer(), - Hours :: non_neg_integer(), + when Hours :: non_neg_integer(), Mins :: 0..59, Secs :: 0..59, MicroSecs :: 0..999999. -time({_,_,_} = NowT) -> %% time of day - %% 24 hours = 24*60*60*1000000 = 86400000000 microsec - time(timer:now_diff(NowT, {0,0,0}) rem 86400000000); - time(Micro) -> %% elapsed time Seconds = Micro div 1000000, H = Seconds div 3600, @@ -215,7 +188,7 @@ time(Micro) -> %% elapsed time %% --------------------------------------------------------------------------- -spec seed() - -> {timestamp(), {integer(), integer(), integer()}}. + -> {erlang:timestamp(), {integer(), integer(), integer()}}. %% Return an argument for random:seed/1. @@ -225,9 +198,6 @@ seed() -> %% seed/1 -seed({_,_,_} = T) -> - T; - seed(T) -> %% monotonic time {erlang:phash2(node()), T, erlang:unique_integer()}. diff --git a/lib/diameter/src/base/diameter_peer.erl b/lib/diameter/src/base/diameter_peer.erl index acec91c43f..2759f17e64 100644 --- a/lib/diameter/src/base/diameter_peer.erl +++ b/lib/diameter/src/base/diameter_peer.erl @@ -21,9 +21,6 @@ -module(diameter_peer). -behaviour(gen_server). --compile({no_auto_import, [now/0]}). --import(diameter_lib, [now/0]). - %% Interface towards transport modules ... -export([recv/2, up/1, @@ -60,7 +57,7 @@ -define(SERVER, ?MODULE). %% Server state. --record(state, {id = now()}). +-record(state, {id = diameter_lib:now()}). %% Default transport_module/config. -define(DEFAULT_TMOD, diameter_tcp). diff --git a/lib/diameter/src/base/diameter_peer_fsm.erl b/lib/diameter/src/base/diameter_peer_fsm.erl index f5e04d3eae..2b23183d18 100644 --- a/lib/diameter/src/base/diameter_peer_fsm.erl +++ b/lib/diameter/src/base/diameter_peer_fsm.erl @@ -315,7 +315,7 @@ handle_info(T, #state{} = State) -> ?LOG(stop, Reason), {stop, {shutdown, Reason}, State}; stop -> - ?LOG(stop, T), + ?LOG(stop, truncate(T)), {stop, {shutdown, T}, State} catch exit: {diameter_codec, encode, T} = Reason -> @@ -348,6 +348,11 @@ code_change(_, State, _) -> %% --------------------------------------------------------------------------- %% --------------------------------------------------------------------------- +truncate({'DOWN' = T, _, process, Pid, _}) -> + {T, Pid}; +truncate(T) -> + T. + putr(Key, Val) -> put({?MODULE, Key}, Val). diff --git a/lib/diameter/src/base/diameter_reg.erl b/lib/diameter/src/base/diameter_reg.erl index ce29baae45..7f198080ba 100644 --- a/lib/diameter/src/base/diameter_reg.erl +++ b/lib/diameter/src/base/diameter_reg.erl @@ -25,8 +25,7 @@ -module(diameter_reg). -behaviour(gen_server). --compile({no_auto_import, [monitor/2, now/0]}). --import(diameter_lib, [now/0]). +-compile({no_auto_import, [monitor/2]}). -export([add/1, add_new/1, @@ -68,7 +67,7 @@ %% Table entry containing the Term -> Pid mapping. -define(MAPPING(Term, Pid), {Term, Pid}). --record(state, {id = now(), +-record(state, {id = diameter_lib:now(), q = []}). %% [{From, Pat}] %% =========================================================================== diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl index 5cb7fa5abe..87ef2e522d 100644 --- a/lib/diameter/src/base/diameter_service.erl +++ b/lib/diameter/src/base/diameter_service.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2015. All Rights Reserved. +%% Copyright Ericsson AB 2010-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -25,9 +25,6 @@ -module(diameter_service). -behaviour(gen_server). --compile({no_auto_import, [now/0]}). --import(diameter_lib, [now/0]). - %% towards diameter_service_sup -export([start_link/1]). @@ -86,16 +83,8 @@ -define(DEFAULT_TC, 30000). %% RFC 3588 ch 2.1 -define(RESTART_TC, 1000). %% if restart was this recent -%% Used to be able to swap this with anything else dict-like but now -%% rely on the fact that a service's #state{} record does not change -%% in storing in it ?STATE table and not always going through the -%% service process. In particular, rely on the fact that operations on -%% a ?Dict don't change the handle to it. --define(Dict, diameter_dict). - -%% Maintains state in a table. In contrast to previously, a service's -%% stat is not constant and is accessed outside of the service -%% process. +%% Maintain state in a table since a service's state is accessed +%% outside of the service process. -define(STATE_TABLE, ?MODULE). %% The default sequence mask. @@ -115,23 +104,23 @@ %% to determine whether or not we need to call the process for a %% pick_peer callback in the statefull case. -record(state, - {id = now(), + {id = diameter_lib:now(), service_name :: diameter:service_name(), %% key in ?STATE_TABLE service :: #diameter_service{}, watchdogT = ets_new(watchdogs) %% #watchdog{} at start :: ets:tid(), - peerT = ets_new(peers) %% #peer{pid = TPid} at okay/reopen - :: ets:tid(), - shared_peers = ?Dict:new() %% Alias -> [{TPid, Caps}, ...] - :: ets:tid(), - local_peers = ?Dict:new() %% Alias -> [{TPid, Caps}, ...] - :: ets:tid(), + peerT, %% undefined in new code, but remain for upgrade + shared_peers, %% reasons. Replaced by local/remote. + local_peers, %% + local :: {ets:tid(), ets:tid(), ets:tid()}, + remote :: {ets:tid(), ets:tid(), ets:tid()}, monitor = false :: false | pid(), %% process to die with options :: [{sequence, diameter:sequence()} %% sequence mask | {share_peers, diameter:remotes()} %% broadcast to | {use_shared_peers, diameter:remotes()} %% use from | {restrict_connections, diameter:restriction()} + | {strict_mbit, boolean()} | {string_decode, boolean()} | {incoming_maxlen, diameter:message_length()}]}). %% shared_peers reflects the peers broadcast from remote nodes. @@ -144,18 +133,20 @@ ref :: match(reference()), %% key into diameter_config options :: match([diameter:transport_opt()]),%% from start_transport state = ?WD_INITIAL :: match(wd_state()), - started = now(), %% at process start + started = diameter_lib:now(),%% at process start peer = false :: match(boolean() | pid())}). %% true at accepted, pid() at okay/reopen -%% Record representing an Peer State Machine processes implemented by +%% Record representing a Peer State Machine processes implemented by %% diameter_peer_fsm. -record(peer, - {pid :: pid(), - apps :: [{0..16#FFFFFFFF, diameter:app_alias()}], %% {Id, Alias} - caps :: #diameter_caps{}, - started = now(), %% at process start - watchdog :: pid()}). %% key into watchdogT + {pid :: pid(), + apps :: match([{0..16#FFFFFFFF, diameter:app_alias()}] %% {Id, Alias} + | [diameter:app_alias()]), %% remote + caps :: match(#diameter_caps{}), + started = diameter_lib:now(), %% at process start or sharing + watchdog :: match(pid() %% key into watchdogT + | undefined)}). %% undefined if remote %% --------------------------------------------------------------------------- %% # start/1 @@ -183,7 +174,7 @@ stop(SvcName) -> end. stop(ok, Pid) -> - MRef = erlang:monitor(process, Pid), + MRef = monitor(process, Pid), receive {'DOWN', MRef, process, _, _} -> ok end; stop(No, _) -> No. @@ -210,7 +201,7 @@ stop_transport(SvcName, [_|_] = Refs) -> info(SvcName, Item) -> case lookup_state(SvcName) of - [#state{} = S] -> + [S] -> service_info(Item, S); [] -> undefined @@ -219,7 +210,12 @@ info(SvcName, Item) -> %% lookup_state/1 lookup_state(SvcName) -> - ets:lookup(?STATE_TABLE, SvcName). + case ets:lookup(?STATE_TABLE, SvcName) of + [#state{}] = L -> + L; + _ -> + [] + end. %% --------------------------------------------------------------------------- %% # subscribe/1 @@ -492,6 +488,9 @@ transition({service, Pid}, S) -> transition({peer, TPid, Aliases, Caps}, S) -> remote_peer_up(TPid, Aliases, Caps, S), ok; +transition({peer, TPid}, S) -> + remote_peer_down(TPid, S), + ok; %% Remote peer process has died. transition({'DOWN', _, process, TPid, _}, S) -> @@ -511,7 +510,7 @@ transition(Req, S) -> %% # terminate/2 %% --------------------------------------------------------------------------- -terminate(Reason, #state{service_name = Name, peerT = PeerT} = S) -> +terminate(Reason, #state{service_name = Name, local = {PeerT, _, _}} = S) -> send_event(Name, stop), ets:delete(?STATE_TABLE, Name), @@ -533,23 +532,80 @@ terminate(Reason, #state{service_name = Name, peerT = PeerT} = S) -> %% # code_change/3 %% --------------------------------------------------------------------------- -code_change(FromVsn, - #state{service_name = SvcName, - service = #diameter_service{applications = Apps}} - = S, - Extra) -> - lists:foreach(fun(A) -> - code_change(FromVsn, SvcName, Extra, A) - end, - Apps), +code_change(_FromVsn, #state{} = S, _Extra) -> + {ok, S}; + +%% Don't support downgrade since we won't in appup. +code_change({down = T, _}, _, _Extra) -> + {error, T}; + +%% Upgrade local/shared peers dicts populated in old code. Don't +code_change(_FromVsn, S0, _Extra) -> + {state, Id, SvcName, Svc, WT, PeerT, SDict, LDict, Monitor, Opts} + = S0, + + init_peers(LT = setelement(1, {PT, _, _} = init_peers(), PeerT), + fun({_,A}) -> A end), + init_peers(init_peers(RT = init_peers(), SDict), + fun(A) -> A end), + + S = #state{id = Id, + service_name = SvcName, + service = Svc, + watchdogT = WT, + peerT = PT, %% empty + shared_peers = SDict, + local_peers = LDict, + local = LT, + remote = RT, + monitor = Monitor, + options = Opts}, + + %% Replacing the table entry and deleting the old shared tables + %% can make outgoing requests return {error, no_connection} until + %% everyone is running new code. Don't delete the tables to avoid + %% crashing request processes. + ets:delete_all_objects(SDict), + ets:delete_all_objects(LDict), + ets:insert(?STATE_TABLE, S), {ok, S}. -code_change(FromVsn, SvcName, Extra, #diameter_app{alias = Alias} = A) -> - {ok, S} = cb(A, code_change, [FromVsn, - mod_state(Alias), - Extra, - SvcName]), - mod_state(Alias, S). +%% init_peers/2 + +%% Populate app and identity bags from a new-style #peer{} sets. +init_peers({PeerT, _, _} = T, F) + when is_function(F) -> + ets:foldl(fun(#peer{pid = P, apps = As, caps = C}, N) -> + insert_peer(P, lists:map(F, As), C, T), + N+1 + end, + 0, + PeerT); + +%% Populate #peer{} table given a shared peers dict. +init_peers({PeerT, _, _}, SDict) -> + dict:fold(fun(P, As, N) -> + ets:update_element(PeerT, P, {#peer.apps, As}), + N+1 + end, + 0, + diameter_dict:fold(fun(A, Ps, D) -> + init_peers(A, Ps, PeerT, D) + end, + dict:new(), + SDict)). + +%% init_peers/4 + +init_peers(App, TCs, PeerT, Dict) -> + lists:foldl(fun({P,C}, D) -> + ets:insert(PeerT, #peer{pid = P, + apps = [], + caps = C}), + dict:append(P, App, D) + end, + Dict, + TCs). %% =========================================================================== %% =========================================================================== @@ -557,9 +613,6 @@ code_change(FromVsn, SvcName, Extra, #diameter_app{alias = Alias} = A) -> unexpected(F, A, #state{service_name = Name}) -> ?UNEXPECTED(F, A ++ [Name]). -cb(#diameter_app{module = [_|_] = M}, F, A) -> - eval(M, F, A). - eval([M|X], F, A) -> apply(M, F, A ++ X). @@ -579,10 +632,6 @@ choose(false, _, X) -> X. ets_new(Tbl) -> ets:new(Tbl, [{keypos, 2}]). -insert(Tbl, Rec) -> - ets:insert(Tbl, Rec), - Rec. - %% Using the process dictionary for the callback state was initially %% just a way to make what was horrendous trace (big state record and %% much else everywhere) somewhat more readable. There's not as much @@ -683,6 +732,8 @@ cfg_acc({SvcName, #diameter_service{applications = Apps} = Rec, Opts}, lists:foreach(fun init_mod/1, Apps), S = #state{service_name = SvcName, service = Rec#diameter_service{pid = self()}, + local = init_peers(), + remote = init_peers(), monitor = mref(get_value(monitor, Opts)), options = service_options(Opts)}, {S, Acc}; @@ -692,6 +743,13 @@ cfg_acc({_Ref, Type, _Opts} = T, {S, Acc}) Type == listen -> {S, [T | Acc]}. +init_peers() -> + {ets_new(caps), %% #peer{} + ets:new(apps, [bag]), %% {Alias, TPid} + ets:new(idents, [bag])}. %% {{host, OH} | {realm, OR} | {OR, OH}, + %% Alias, + %% TPid} + service_options(Opts) -> [{sequence, proplists:get_value(sequence, Opts, ?NOMASK)}, {share_peers, get_value(share_peers, Opts)}, @@ -701,13 +759,14 @@ service_options(Opts) -> ?RESTRICT)}, {spawn_opt, proplists:get_value(spawn_opt, Opts, [])}, {string_decode, proplists:get_value(string_decode, Opts, true)}, - {incoming_maxlen, proplists:get_value(incoming_maxlen, Opts, 16#FFFFFF)}]. + {incoming_maxlen, proplists:get_value(incoming_maxlen, Opts, 16#FFFFFF)}, + {strict_mbit, proplists:get_value(strict_mbit, Opts, true)}]. %% The order of options is significant since we match against the list. mref(false = No) -> No; mref(P) -> - erlang:monitor(process, P). + monitor(process, P). init_shared(#state{options = [_, _, {_,T} | _], service_name = Svc}) -> @@ -806,7 +865,7 @@ start(Ref, Type, Opts, State) -> %% start/5 start(Ref, Type, Opts, N, #state{watchdogT = WatchdogT, - peerT = PeerT, + local = {PeerT, _, _}, options = SvcOpts, service_name = SvcName, service = Svc0}) @@ -837,7 +896,7 @@ binary_caps(#diameter_service{capabilities = Caps} = Svc, false) -> wd(Type, Ref, T, WatchdogT, Rec) -> Pid = start_watchdog(Type, Ref, T), - insert(WatchdogT, Rec#watchdog{pid = Pid}), + ets:insert(WatchdogT, Rec#watchdog{pid = Pid}), Pid. %% Note that the service record passed into the watchdog is the merged @@ -894,8 +953,8 @@ accepted(Pid, _TPid, #state{watchdogT = WatchdogT} = S) -> #watchdog{ref = Ref, type = accept = T, peer = false, options = Opts} = Wd = fetch(WatchdogT, Pid), - insert(WatchdogT, Wd#watchdog{peer = true}),%% mark replacement as started - start(Ref, T, Opts, S). %% start new watchdog + ets:insert(WatchdogT, Wd#watchdog{peer = true}),%% mark replacement started + start(Ref, T, Opts, S). %% start new watchdog fetch(Tid, Key) -> [T] = ets:lookup(Tid, Key), @@ -921,13 +980,14 @@ watchdog(TPid, [], ?WD_SUSPECT, ?WD_OKAY, Wd, State) -> #watchdog{peer = TPid} = Wd, %% assert connection_up(Wd, State); -%% Watchdog has an unresponsive connection. +%% Watchdog has an unresponsive connection. Note that the peer table +%% entry isn't removed until DOWN. watchdog(TPid, [], ?WD_OKAY, ?WD_SUSPECT = To, Wd, State) -> #watchdog{peer = TPid} = Wd, %% assert watchdog_down(Wd, To, State); %% Watchdog has lost its connection. -watchdog(TPid, [], _, ?WD_DOWN = To, Wd, #state{peerT = PeerT} = S) -> +watchdog(TPid, [], _, ?WD_DOWN = To, Wd, #state{local = {PeerT, _, _}} = S) -> close(Wd), watchdog_down(Wd, To, S), ets:delete(PeerT, TPid); @@ -936,7 +996,7 @@ watchdog(_, [], _, _, _, _) -> ok. watchdog_down(Wd, To, #state{watchdogT = WatchdogT} = S) -> - insert(WatchdogT, Wd#watchdog{state = To}), + ets:insert(WatchdogT, Wd#watchdog{state = To}), connection_down(Wd, To, S). %% --------------------------------------------------------------------------- @@ -948,14 +1008,14 @@ watchdog_down(Wd, To, #state{watchdogT = WatchdogT} = S) -> connection_up({TPid, {Caps, SupportedApps, Pkt}}, #watchdog{pid = Pid} = Wd, - #state{peerT = PeerT} + #state{local = {PeerT, _, _}} = S) -> - Pr = #peer{pid = TPid, - apps = SupportedApps, - caps = Caps, - watchdog = Pid}, - insert(PeerT, Pr), - connection_up([Pkt], Wd#watchdog{peer = TPid}, Pr, S). + Rec = #peer{pid = TPid, + apps = SupportedApps, + caps = Caps, + watchdog = Pid}, + ets:insert(PeerT, Rec), + connection_up([Pkt], Wd#watchdog{peer = TPid}, Rec, S). %% --------------------------------------------------------------------------- %% # reopen/3 @@ -965,22 +1025,23 @@ reopen({TPid, {Caps, SupportedApps, _Pkt}}, #watchdog{pid = Pid} = Wd, #state{watchdogT = WatchdogT, - peerT = PeerT}) -> - insert(PeerT, #peer{pid = TPid, - apps = SupportedApps, - caps = Caps, - watchdog = Pid}), - insert(WatchdogT, Wd#watchdog{state = ?WD_REOPEN, - peer = TPid}). + local = {PeerT, _, _}}) -> + ets:insert(PeerT, #peer{pid = TPid, + apps = SupportedApps, + caps = Caps, + watchdog = Pid}), + ets:insert(WatchdogT, Wd#watchdog{state = ?WD_REOPEN, + peer = TPid}). %% --------------------------------------------------------------------------- %% # connection_up/2 %% --------------------------------------------------------------------------- -%% Watchdog has recovered as suspect connection. Note that there has +%% Watchdog has recovered a suspect connection. Note that there has %% been no new capabilties exchange in this case. -connection_up(#watchdog{peer = TPid} = Wd, #state{peerT = PeerT} = S) -> +connection_up(#watchdog{peer = TPid} = Wd, #state{local = {PeerT, _, _}} + = S) -> connection_up([], Wd, fetch(PeerT, TPid), S). %% connection_up/4 @@ -991,23 +1052,23 @@ connection_up(Extra, #peer{apps = SApps, caps = Caps} = Pr, #state{watchdogT = WatchdogT, - local_peers = LDict, + local = LT, service_name = SvcName, service = #diameter_service{applications = Apps}} = S) -> - insert(WatchdogT, Wd#watchdog{state = ?WD_OKAY}), + ets:insert(WatchdogT, Wd#watchdog{state = ?WD_OKAY}), diameter_traffic:peer_up(TPid), - insert_local_peer(SApps, {{TPid, Caps}, {SvcName, Apps}}, LDict), + local_peer_up(SApps, {TPid, Caps}, {SvcName, Apps}, LT), report_status(up, Wd, Pr, S, Extra). -insert_local_peer(SApps, T, LDict) -> - lists:foldl(fun(A,D) -> ilp(A, T, D) end, LDict, SApps). +local_peer_up(SApps, {TPid, Caps} = TC, SA, LT) -> + insert_peer(TPid, [A || {_,A} <- SApps], Caps, LT), + lists:foreach(fun(A) -> peer_up(A, TC, SA) end, SApps). -ilp({Id, Alias}, {TC, SA}, LDict) -> - init_conn(Id, Alias, TC, SA), - ?Dict:append(Alias, TC, LDict). +peer_up({Id, Alias}, TC, SA) -> + peer_up(Id, Alias, TC, SA). -init_conn(Id, Alias, {TPid, _} = TC, {SvcName, Apps}) -> +peer_up(Id, Alias, {TPid, _} = TC, {SvcName, Apps}) -> #diameter_app{id = Id} %% assert = App = find_app(Alias, Apps), @@ -1105,17 +1166,17 @@ connection_down(#watchdog{state = ?WD_OKAY, = Pr, #state{service_name = SvcName, service = #diameter_service{applications = Apps}, - local_peers = LDict} + local = LT} = S) -> report_status(down, Wd, Pr, S, []), - remove_local_peer(SApps, {{TPid, Caps}, {SvcName, Apps}}, LDict), + local_peer_down(SApps, {TPid, Caps}, {SvcName, Apps}, LT), diameter_traffic:peer_down(TPid); connection_down(#watchdog{state = ?WD_OKAY, peer = TPid} = Wd, To, - #state{peerT = PeerT} + #state{local = {PeerT, _, _}} = S) when is_atom(To) -> connection_down(Wd, #peer{} = fetch(PeerT, TPid), S); @@ -1123,15 +1184,14 @@ connection_down(#watchdog{state = ?WD_OKAY, connection_down(#watchdog{}, _, _) -> ok. -remove_local_peer(SApps, T, LDict) -> - lists:foldl(fun(A,D) -> rlp(A, T, D) end, LDict, SApps). +local_peer_down(SApps, {TPid, _Caps} = TC, SA, LT) -> + delete_peer(TPid, LT), + lists:foreach(fun(A) -> peer_down(A, TC, SA) end, SApps). -rlp({Id, Alias}, {TC, SA}, LDict) -> - L = ?Dict:fetch(Alias, LDict), - down_conn(Id, Alias, TC, SA), - ?Dict:store(Alias, lists:delete(TC, L), LDict). +peer_down({Id, Alias}, TC, SA) -> + peer_down(Id, Alias, TC, SA). -down_conn(Id, Alias, TC, {SvcName, Apps}) -> +peer_down(Id, Alias, TC, {SvcName, Apps}) -> #diameter_app{id = Id} %% assert = App = find_app(Alias, Apps), @@ -1156,7 +1216,7 @@ wd_down(#watchdog{peer = B}, _) ok; %% ... or maybe it has. -wd_down(#watchdog{peer = TPid} = Wd, #state{peerT = PeerT} = S) -> +wd_down(#watchdog{peer = TPid} = Wd, #state{local = {PeerT, _, _}} = S) -> connection_down(Wd, ?WD_DOWN, S), ets:delete(PeerT, TPid). @@ -1364,19 +1424,37 @@ share_peer(up, Caps, Apps, TPid, #state{options = [_, {_,T} | _], service_name = Svc}) -> notify(T, Svc, {peer, TPid, [A || {_,A} <- Apps], Caps}); -share_peer(_, _, _, _, _) -> - ok. +share_peer(down, _Caps, _Apps, TPid, #state{options = [_, {_,T} | _], + service_name = Svc}) -> + notify(T, Svc, {peer, TPid}). %% --------------------------------------------------------------------------- %% # share_peers/2 %% --------------------------------------------------------------------------- -share_peers(Pid, #state{options = [_, {_,T} | _], local_peers = PDict}) -> - is_remote(Pid, T) - andalso ?Dict:fold(fun(A,Ps,ok) -> sp(Pid, A, Ps), ok end, ok, PDict). - -sp(Pid, Alias, Peers) -> - lists:foreach(fun({P,C}) -> Pid ! {peer, P, [Alias], C} end, Peers). +share_peers(Pid, #state{options = [_, {_,SP} | _], + local = {PeerT, AppT, _}}) -> + is_remote(Pid, SP) + andalso ets:foldl(fun(T, N) -> N + sp(Pid, AppT, T) end, + 0, + PeerT). + +%% An entry in the peer table doesn't mean the watchdog state is OKAY, +%% an entry in the app table does. + +sp(Pid, AppT, #peer{pid = TPid, + apps = [{_, Alias} | _] = Apps, + caps = Caps}) -> + Spec = [{{'$1', TPid}, + [{'==', '$1', {const, Alias}}], + ['$_']}], + case ets:select(AppT, Spec, 1) of + '$end_of_table' -> + 0; + _ -> + Pid ! {peer, TPid, [A || {_,A} <- Apps], Caps}, + 1 + end. is_remote(Pid, T) -> Node = node(Pid), @@ -1386,32 +1464,49 @@ is_remote(Pid, T) -> %% # remote_peer_up/4 %% --------------------------------------------------------------------------- -remote_peer_up(Pid, Aliases, Caps, #state{options = [_, _, {_,T} | _]} = S) -> - is_remote(Pid, T) - andalso rpu(Pid, Aliases, Caps, S). +remote_peer_up(TPid, Aliases, Caps, #state{options = [_, _, {_,T} | _]} = S) -> + is_remote(TPid, T) andalso rpu(TPid, Aliases, Caps, S). -rpu(Pid, Aliases, Caps, #state{service = Svc, shared_peers = PDict}) -> +rpu(TPid, Aliases, Caps, #state{service = Svc, remote = RT}) -> #diameter_service{applications = Apps} = Svc, Key = #diameter_app.alias, F = fun(A) -> lists:keymember(A, Key, Apps) end, - rpu(Pid, lists:filter(F, Aliases), Caps, PDict); + rpu(TPid, lists:filter(F, Aliases), Caps, RT); rpu(_, [] = No, _, _) -> No; -rpu(Pid, Aliases, Caps, PDict) -> - erlang:monitor(process, Pid), - T = {Pid, Caps}, - lists:foreach(fun(A) -> ?Dict:append(A, T, PDict) end, Aliases). +rpu(TPid, Aliases, Caps, {PeerT, _, _} = RT) -> + monitor(process, TPid), + ets:insert(PeerT, #peer{pid = TPid, + apps = Aliases, + caps = Caps}), + insert_peer(TPid, Aliases, Caps, RT). + +%% insert_peer/4 + +insert_peer(TPid, Aliases, Caps, {_PeerT, AppT, IdentT}) -> + #diameter_caps{origin_host = {_, OH}, + origin_realm = {_, OR}} + = Caps, + ets:insert(AppT, [{A, TPid} || A <- Aliases]), + H = iolist_to_binary(OH), + R = iolist_to_binary(OR), + ets:insert(IdentT, [{T, A, TPid} || T <- [{host, H}, {realm, R}, {R, H}], + A <- Aliases]). %% --------------------------------------------------------------------------- %% # remote_peer_down/2 %% --------------------------------------------------------------------------- -remote_peer_down(Pid, #state{shared_peers = PDict}) -> - lists:foreach(fun(A) -> rpd(Pid, A, PDict) end, ?Dict:fetch_keys(PDict)). +remote_peer_down(TPid, #state{remote = {PeerT, _, _} = RT}) -> + ets:delete(PeerT, TPid), + delete_peer(TPid, RT). -rpd(Pid, Alias, PDict) -> - ?Dict:update(Alias, fun(Ps) -> lists:keydelete(Pid, 1, Ps) end, PDict). +%% delete_peer/2 + +delete_peer(TPid, {_PeerT, AppT, IdentT}) -> + ets:select_delete(AppT, [{{'_', TPid}, [], [true]}]), + ets:select_delete(IdentT, [{{'_', '_', TPid}, [], [true]}]). %% --------------------------------------------------------------------------- %% pick_peer/4 @@ -1421,12 +1516,12 @@ pick_peer(#diameter_app{alias = Alias} = App, RealmAndHost, Filter, - #state{local_peers = L, - shared_peers = S, + #state{local = LT, + remote = RT, service_name = SvcName, service = #diameter_service{pid = Pid}}) -> - pick_peer(peers(Alias, RealmAndHost, Filter, L), - peers(Alias, RealmAndHost, Filter, S), + pick_peer(peers(Alias, RealmAndHost, Filter, LT), + peers(Alias, RealmAndHost, Filter, RT), Pid, SvcName, App). @@ -1491,54 +1586,196 @@ pick_peer(Local, %% peers/4 -peers(Alias, RH, Filter, Peers) -> - case ?Dict:find(Alias, Peers) of - {ok, L} -> - filter(L, RH, Filter); - error -> +peers(Alias, RH, Filter, T) -> + filter(Alias, RH, Filter, T, true). + +%% filter/5 +%% +%% Try to limit the peers list by starting with a host/realm lookup. + +filter(Alias, RH, {neg, F}, T, B) -> + filter(Alias, RH, F, T, not B); + +filter(_, _, none, _, false) -> + []; + +filter(Alias, _, none, T, true) -> + all_peers(Alias, T); + +filter(Alias, [DR,DH] = RH, K, T, B) + when K == realm, DR == undefined; + K == host, DH == undefined -> + filter(Alias, RH, none, T, B); + +filter(Alias, [DR,_] = RH, realm = K, T, B) -> + filter(Alias, RH, {K, DR}, T, B); + +filter(Alias, [_,DH] = RH, host = K, T, B) -> + filter(Alias, RH, {K, DH}, T, B); + +filter(Alias, _, {K, D}, {PeerT, _AppT, IdentT}, true) + when K == host; + K == realm -> + try iolist_to_binary(D) of + B -> + caps(PeerT, ets:select(IdentT, [{{{K, B}, '$1', '$2'}, + [{'==', '$1', {const, Alias}}], + ['$2']}])) + catch + error:_ -> [] - end. + end; -%% filter/3 +filter(Alias, RH, {all, Filters}, T, B) + when is_list(Filters) -> + fltr_all(Alias, RH, Filters, T, B); + +filter(Alias, RH, {first, Filters}, T, B) + when is_list(Filters) -> + fltr_first(Alias, RH, Filters, T, B); + +filter(Alias, RH, Filter, T, B) -> + {Ts, Fs} = filter(all_peers(Alias, T), RH, Filter), + choose(B, Ts, Fs). + +%% fltr_all/5 + +fltr_all(Alias, RH, [{K, any} | Filters], T, B) + when K == host; + K == realm -> + fltr_all(Alias, RH, Filters, T, B); + +fltr_all(Alias, RH, [{host, _} = H, {realm, _} = R | Filters], T, B) -> + fltr_all(Alias, RH, [R, H | Filters], T, B); + +fltr_all(Alias, RH, [{realm, _} = R, {host, any} | Filters], T, B) -> + fltr_all(Alias, RH, [R | Filters], T, B); + +fltr_all(Alias, RH, [{realm, OR}, {host, OH} | Filters], T, true) -> + {PeerT, _AppT, IdentT} = T, + try {iolist_to_binary(OR), iolist_to_binary(OH)} of + BT -> + Peers = caps(PeerT, + ets:select(IdentT, [{{BT, '$1', '$2'}, + [{'==', '$1', {const, Alias}}], + ['$2']}])), + {Ts, _} = filter(Peers, RH, {all, Filters}), + Ts + catch + error:_ -> + [] + end; + +fltr_all(Alias, [undefined,_] = RH, [realm | Filters], T, B) -> + fltr_all(Alias, RH, Filters, T, B); + +fltr_all(Alias, [DR,_] = RH, [realm | Filters], T, B) -> + fltr_all(Alias, RH, [{realm, DR} | Filters], T, B); + +fltr_all(Alias, [_,undefined] = RH, [host | Filters], T, B) -> + fltr_all(Alias, RH, Filters, T, B); + +fltr_all(Alias, [_,DH] = RH, [host | Filters], T, B) -> + fltr_all(Alias, RH, [{host, DH} | Filters], T, B); + +fltr_all(Alias, RH, [{K, _} = KT, KA | Filters], T, B) + when K == host, KA == realm; + K == realm, KA == host -> + fltr_all(Alias, RH, [KA, KT | Filters], T, B); + +fltr_all(Alias, RH, [F | Filters], T, B) -> + {Ts, Fs} = filter(filter(Alias, RH, F, T, B), RH, {all, Filters}), + choose(B, Ts, Fs); + +fltr_all(Alias, RH, [], T, B) -> + filter(Alias, RH, none, T, B). + +%% fltr_first/5 %% -%% Return peers in match order. +%% Like any, but stop at the first filter with any matches. -filter(Peers, RH, Filter) -> - {Ts, _} = fltr(Peers, RH, Filter), - Ts. +fltr_first(Alias, RH, [F | Filters], T, B) -> + case filter(Alias, RH, F, T, B) of + [] -> + fltr_first(Alias, RH, Filters, T, B); + [_|_] = Ts -> + Ts + end; -%% fltr/4 +fltr_first(Alias, RH, [], T, B) -> + filter(Alias, RH, none, T, not B). -fltr(Peers, _, none) -> +%% all_peers/2 + +all_peers(Alias, {PeerT, AppT, _}) -> + ets:select(PeerT, [{#peer{pid = P, caps = '$1', _ = '_'}, + [], + [{{P, '$1'}}]} + || {_,P} <- ets:lookup(AppT, Alias)]). + +%% caps/2 + +caps(PeerT, Pids) -> + ets:select(PeerT, [{#peer{pid = P, caps = '$1', _ = '_'}, + [], + [{{P, '$1'}}]} + || P <- Pids]). + +%% filter/3 +%% +%% Return peers in match order. + +filter(Peers, _, none) -> {Peers, []}; -fltr(Peers, RH, {neg, F}) -> - {Ts, Fs} = fltr(Peers, RH, F), +filter(Peers, RH, {neg, F}) -> + {Ts, Fs} = filter(Peers, RH, F), {Fs, Ts}; -fltr(Peers, RH, {all, L}) +filter(Peers, RH, {all, L}) when is_list(L) -> lists:foldl(fun(F,A) -> fltr_all(F, A, RH) end, {Peers, []}, L); -fltr(Peers, RH, {any, L}) +filter(Peers, RH, {any, L}) when is_list(L) -> lists:foldl(fun(F,A) -> fltr_any(F, A, RH) end, {[], Peers}, L); -fltr(Peers, RH, F) -> +filter(Peers, RH, {first, L}) + when is_list(L) -> + fltr_first(Peers, RH, L); + +filter(Peers, RH, F) -> lists:partition(fun({_,C}) -> caps_filter(C, RH, F) end, Peers). +%% fltr_all/3 + fltr_all(F, {Ts0, Fs0}, RH) -> - {Ts1, Fs1} = fltr(Ts0, RH, F), + {Ts1, Fs1} = filter(Ts0, RH, F), {Ts1, Fs0 ++ Fs1}. +%% fltr_any/3 + fltr_any(F, {Ts0, Fs0}, RH) -> - {Ts1, Fs1} = fltr(Fs0, RH, F), + {Ts1, Fs1} = filter(Fs0, RH, F), {Ts0 ++ Ts1, Fs1}. +%% fltr_first/3 + +fltr_first(Peers, _, []) -> + {[], Peers}; + +fltr_first(Peers, RH, [F | Filters]) -> + case filter(Peers, RH, F) of + {[], _} -> + fltr_first(Peers, RH, Filters); + {_, _} = T -> + T + end. + %% caps_filter/3 caps_filter(#diameter_caps{origin_host = {_,OH}}, [_,DH], host) -> @@ -1582,8 +1819,8 @@ eq(Any, Id, PeerId) -> transports(#state{watchdogT = WatchdogT}) -> ets:select(WatchdogT, [{#watchdog{peer = '$1', _ = '_'}, - [{'is_pid', '$1'}], - ['$1']}]). + [{'is_pid', '$1'}], + ['$1']}]). %% --------------------------------------------------------------------------- %% # service_info/2 @@ -1636,7 +1873,7 @@ tagged_info(Item, S) undefined end; -tagged_info(TPid, #state{watchdogT = WatchdogT, peerT = PeerT}) +tagged_info(TPid, #state{watchdogT = WatchdogT, local = {PeerT, _, _}}) when is_pid(TPid) -> try [#peer{watchdog = Pid}] = ets:lookup(PeerT, TPid), @@ -1786,7 +2023,7 @@ keys(connect = T, Opts) -> keys(_, _) -> [{listen, accept}]. -peer_dict(#state{watchdogT = WatchdogT, peerT = PeerT}, Dict0) -> +peer_dict(#state{watchdogT = WatchdogT, local = {PeerT, _, _}}, Dict0) -> try ets:tab2list(WatchdogT) of L -> lists:foldl(fun(T,A) -> peer_acc(PeerT, A, T) end, Dict0, L) catch diff --git a/lib/diameter/src/base/diameter_stats.erl b/lib/diameter/src/base/diameter_stats.erl index 83e562e7fe..8c10464e98 100644 --- a/lib/diameter/src/base/diameter_stats.erl +++ b/lib/diameter/src/base/diameter_stats.erl @@ -25,9 +25,6 @@ -module(diameter_stats). -behaviour(gen_server). --compile({no_auto_import, [now/0]}). --import(diameter_lib, [now/0]). - -export([reg/2, reg/1, incr/3, incr/1, read/1, @@ -61,7 +58,7 @@ -define(SERVER, ?MODULE). %% Server state. --record(state, {id = now()}). +-record(state, {id = diameter_lib:now()}). -type counter() :: any(). -type ref() :: any(). @@ -143,9 +140,14 @@ read(Refs, B) -> L. to_refdict(L) -> - lists:foldl(fun({{C,R}, N}, D) -> orddict:append(R, {C,N}, D) end, - orddict:new(), - L). + lists:foldl(fun append/2, orddict:new(), L). + +%% Order both references and counters in the returned list. +append({{Ctr, Ref}, N}, Dict) -> + orddict:update(Ref, + fun(D) -> orddict:store(Ctr, N, D) end, + [{Ctr, N}], + Dict). %% --------------------------------------------------------------------------- %% # sum(Refs) @@ -221,7 +223,7 @@ uptime() -> %% ---------------------------------------------------------- init([]) -> - ets:new(?TABLE, [named_table, ordered_set, public]), + ets:new(?TABLE, [named_table, set, public, {write_concurrency, true}]), {ok, #state{}}. %% ---------------------------------------------------------- diff --git a/lib/diameter/src/base/diameter_sync.erl b/lib/diameter/src/base/diameter_sync.erl index 3309224399..7fb6888e21 100644 --- a/lib/diameter/src/base/diameter_sync.erl +++ b/lib/diameter/src/base/diameter_sync.erl @@ -28,9 +28,6 @@ -module(diameter_sync). -behaviour(gen_server). --compile({no_auto_import, [now/0]}). --import(diameter_lib, [now/0]). - -export([call/4, call/5, cast/4, cast/5, carp/1, carp/2]). @@ -73,7 +70,7 @@ %% Server state. -record(state, - {time = now(), + {time = diameter_lib:now(), pending = 0 :: non_neg_integer(), %% outstanding requests monitor = new() :: ets:tid(), %% MonitorRef -> {Name, From} queue = new() :: ets:tid()}). %% Name -> queue of {Pid, Ref} diff --git a/lib/diameter/src/base/diameter_traffic.erl b/lib/diameter/src/base/diameter_traffic.erl index 692a01e651..c169d3fc2c 100644 --- a/lib/diameter/src/base/diameter_traffic.erl +++ b/lib/diameter/src/base/diameter_traffic.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2013-2015. All Rights Reserved. +%% Copyright Ericsson AB 2013-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -41,7 +41,6 @@ -export([make_recvdata/1, peer_up/1, peer_down/1, - failover/1, pending/1]). %% towards ?MODULE @@ -80,6 +79,7 @@ apps :: [#diameter_app{}], sequence :: diameter:sequence(), codec :: [{string_decode, boolean()} + | {strict_mbit, boolean()} | {incoming_maxlen, diameter:message_length()}]}). %% Note that incoming_maxlen is currently handled in diameter_peer_fsm, %% so that any message exceeding the maximum is discarded. Retain the @@ -106,7 +106,8 @@ make_recvdata([SvcName, PeerT, Apps, SvcOpts | _]) -> sequence = Mask, codec = [T || {K,_} = T <- SvcOpts, lists:member(K, [string_decode, - incoming_maxlen])]}. + incoming_maxlen, + strict_mbit])]}. %% --------------------------------------------------------------------------- %% peer_up/1 @@ -167,7 +168,7 @@ incr_error(Dir, Id, TPid, _) -> incr_error(Dir, Id, TPid) -> incr(TPid, {Id, Dir, error}). - + %% --------------------------------------------------------------------------- %% incr_rc/4 %% --------------------------------------------------------------------------- @@ -1483,16 +1484,12 @@ send_R(Pkt0, caps = Caps, packet = Pkt0}, - try - incr(send, Pkt, TPid, AppDict), - TRef = send_request(TPid, Pkt, Req, SvcName, Timeout), - Pid ! Ref, %% tell caller a send has been attempted - handle_answer(SvcName, - App, - recv_A(Timeout, SvcName, App, Opts, {TRef, Req})) - after - erase_requests(Pkt) - end. + incr(send, Pkt, TPid, AppDict), + TRef = send_request(TPid, Pkt, Req, SvcName, Timeout), + Pid ! Ref, %% tell caller a send has been attempted + handle_answer(SvcName, + App, + recv_A(Timeout, SvcName, App, Opts, {TRef, Req})). %% recv_A/5 @@ -1568,6 +1565,8 @@ answer(Pkt, Req) -> a(Pkt, SvcName, ModX, AE, Req). +-spec a(_, _, _) -> no_return(). %% silence dialyzer + a(#diameter_packet{errors = Es} = Pkt, SvcName, @@ -1692,9 +1691,18 @@ encode(_, _, #diameter_packet{} = Pkt) -> send_request(TPid, #diameter_packet{bin = Bin} = Pkt, Req, _SvcName, Timeout) when node() == node(TPid) -> - %% Store the outgoing request before sending to avoid a race with - %% reply reception. - TRef = store_request(TPid, Bin, Req, Timeout), + Seqs = diameter_codec:sequence_numbers(Bin), + TRef = erlang:start_timer(Timeout, self(), TPid), + Entry = {Seqs, Req, TRef}, + + %% Ensure that request table is cleaned even if we receive an exit + %% signal. An alternative would be to simply trap exits, but + %% callbacks are applied in this process, and these could possibly + %% be expecting the prevailing behaviour. + Self = self(), + spawn(fun() -> diameter_lib:wait([Self]), erase_request(Entry) end), + + store_request(Entry, TPid), send(TPid, Pkt), TRef; @@ -1709,31 +1717,21 @@ send_request(TPid, #diameter_packet{} = Pkt, Req, SvcName, Timeout) -> %% send/1 send({TPid, Pkt, #request{handler = Pid} = Req0, SvcName, Timeout, TRef}) -> - Seqs = diameter_codec:sequence_numbers(Pkt), Req = Req0#request{handler = self()}, - Ref = send_request(TPid, Pkt, Req, SvcName, Timeout), - - try - recv(TPid, Pid, TRef, Ref) - after - %% Remove only the entry for this specific send since a resend - %% from the originating node can pick another transport on - %% this one. - ets:delete_object(?REQUEST_TABLE, {Seqs, Req, Ref}) - end. + recv(TPid, Pid, TRef, send_request(TPid, Pkt, Req, SvcName, Timeout)). %% recv/4 %% %% Relay an answer from a remote node. -recv(TPid, Pid, TRef, Ref) -> +recv(TPid, Pid, TRef, LocalTRef) -> receive {answer, _, _, _, _} = A -> Pid ! A; - {failover = T, Ref} -> + {failover = T, LocalTRef} -> Pid ! {T, TRef}; T -> - exit({timeout, Ref, TPid} = T) + exit({timeout, LocalTRef, TPid} = T) end. %% send/2 @@ -1810,17 +1808,21 @@ resend_request(Pkt0, TRef = send_request(TPid, Pkt, Req, SvcName, Tmo), {TRef, Req}. -%% store_request/4 +%% store_request/2 -store_request(TPid, Bin, Req, Timeout) -> - Seqs = diameter_codec:sequence_numbers(Bin), - TRef = erlang:start_timer(Timeout, self(), TPid), - ets:insert(?REQUEST_TABLE, {Seqs, Req, TRef}), +store_request(T, TPid) -> + ets:insert(?REQUEST_TABLE, T), ets:member(?REQUEST_TABLE, TPid) - orelse (self() ! {failover, TRef}), %% failover/1 may have missed - TRef. + orelse begin + {_Seqs, _Req, TRef} = T, + self() ! {failover, TRef} %% failover/1 may have missed + end. %% lookup_request/2 +%% +%% Note the match on both the key and transport pid. The latter is +%% necessary since the same Hop-by-Hop and End-to-End identifiers are +%% reused in the case of retransmission. lookup_request(Msg, TPid) -> Seqs = diameter_codec:sequence_numbers(Msg), @@ -1834,10 +1836,10 @@ lookup_request(Msg, TPid) -> false end. -%% erase_requests/1 +%% erase_request/1 -erase_requests(Pkt) -> - ets:delete(?REQUEST_TABLE, diameter_codec:sequence_numbers(Pkt)). +erase_request(T) -> + ets:delete_object(?REQUEST_TABLE, T). %% match_requests/1 @@ -1860,10 +1862,10 @@ failover(TPid) when is_pid(TPid) -> lists:foreach(fun failover/1, match_requests(TPid)); %% Note that a request process can store its request after failover -%% notifications are sent here: store_request/4 sends the notification +%% notifications are sent here: store_request/2 sends the notification %% in that case. -%% Failover as a consequence of request_peer_down/1: inform the +%% Failover as a consequence of peer_down/1: inform the %% request process. failover({_, Req, TRef}) -> #request{handler = Pid, diff --git a/lib/diameter/src/base/diameter_watchdog.erl b/lib/diameter/src/base/diameter_watchdog.erl index c6d0a0b6ed..ea8b2fdb0e 100644 --- a/lib/diameter/src/base/diameter_watchdog.erl +++ b/lib/diameter/src/base/diameter_watchdog.erl @@ -66,7 +66,9 @@ %% end PCB parent = self() :: pid(), %% service process transport :: pid() | undefined, %% peer_fsm process - tref :: reference(), %% reference for current watchdog timer + tref :: reference() %% reference for current watchdog timer + | integer() %% monotonic time + | undefined, dictionary :: module(), %% common dictionary receive_data :: term(), %% term passed into diameter_service with incoming message @@ -94,7 +96,7 @@ start({_,_} = Type, T) -> Ack = make_ref(), {ok, Pid} = diameter_watchdog_sup:start_child({Ack, Type, self(), T}), try - {erlang:monitor(process, Pid), Pid} + {monitor(process, Pid), Pid} after send(Pid, Ack) end. @@ -121,7 +123,7 @@ i({Ack, T, Pid, {RecvData, #diameter_service{applications = Apps, capabilities = Caps} = Svc}}) -> - erlang:monitor(process, Pid), + monitor(process, Pid), wait(Ack, Pid), {_, Seed} = diameter_lib:seed(), random:seed(Seed), @@ -246,11 +248,16 @@ handle_info(T, #watchdog{} = State) -> event(T, State, S), %% before 'watchdog' {noreply, S}; stop -> - ?LOG(stop, T), + ?LOG(stop, truncate(T)), event(T, State, State#watchdog{status = down}), {stop, {shutdown, T}, State} end. +truncate({'DOWN' = T, _, process, Pid, _}) -> + {T, Pid}; +truncate(T) -> + T. + close({'DOWN', _, process, TPid, {shutdown, Reason}}, #watchdog{transport = TPid, parent = Pid}) -> @@ -447,11 +454,12 @@ transition({recv, TPid, Name, Pkt}, #watchdog{transport = TPid} = S) -> %% Current watchdog has timed out. transition({timeout, TRef, tw}, #watchdog{tref = TRef} = S) -> - set_watchdog(timeout(S)); + set_watchdog(0, timeout(S)); -%% Timer was canceled after message was already sent. -transition({timeout, _, tw}, #watchdog{}) -> - ok; +%% Message has arrived since the timer was started: subtract time +%% already elapsed from new timer. +transition({timeout, _, tw}, #watchdog{tref = T0} = S) -> + set_watchdog(diameter_lib:micro_diff(T0) div 1000, S); %% State query. transition({state, Pid}, #watchdog{status = S}) -> @@ -527,18 +535,27 @@ role() -> %% set_watchdog/1 -set_watchdog(#watchdog{tw = TwInit, - tref = TRef} - = S) -> - cancel(TRef), - S#watchdog{tref = erlang:start_timer(tw(TwInit), self(), tw)}; -set_watchdog(stop = No) -> - No. +%% Timer not yet set. +set_watchdog(#watchdog{tref = undefined} = S) -> + set_watchdog(0, S); -cancel(undefined) -> - ok; -cancel(TRef) -> - erlang:cancel_timer(TRef). +%% Timer already set: start at new one only at expiry. +set_watchdog(#watchdog{} = S) -> + S#watchdog{tref = diameter_lib:now()}. + +%% set_watchdog/2 + +set_watchdog(_, stop = No) -> + No; + +set_watchdog(Ms, #watchdog{tw = TwInit} = S) -> + S#watchdog{tref = erlang:start_timer(tw(TwInit, Ms), self(), tw)}. + +%% A callback could return anything, so ensure the result isn't +%% negative. Don't prevent abuse, even though the smallest valid +%% timeout is 4000. +tw(TwInit, Ms) -> + max(tw(TwInit) - Ms, 0). tw(T) when is_integer(T), T >= 6000 -> diff --git a/lib/diameter/src/diameter.appup.src b/lib/diameter/src/diameter.appup.src index 86d231179c..a3e21db012 100644 --- a/lib/diameter/src/diameter.appup.src +++ b/lib/diameter/src/diameter.appup.src @@ -42,7 +42,15 @@ {"1.8", [{restart_application, diameter}]}, %% 17.4 {"1.9", [{restart_application, diameter}]}, %% 17.5 {"1.9.1", [{restart_application, diameter}]}, %% 17.5.3 - {"1.9.2", [{restart_application, diameter}]} %% 17.5.5 + {"1.9.2", [{restart_application, diameter}]}, %% 17.5.5 + {"1.9.2.1", [{restart_application, diameter}]}, %% 17.5.6.3 + {"1.9.2.2", [{restart_application, diameter}]}, %% 17.5.6.7 + {"1.9.2.3", [{restart_application, diameter}]}, %% 17.5.6.8 + {"1.10", [{restart_application, diameter}]}, %% 18.0 + {"1.11", [{load_module, diameter_traffic}, %% 18.1 + {update, diameter_service, {advanced, []}}]}, + {"1.11.1", [{load_module, diameter_traffic}, %% 18.2 + {update, diameter_service, {advanced, []}}]} ], [ {"0.9", [{restart_application, diameter}]}, @@ -66,6 +74,12 @@ {"1.8", [{restart_application, diameter}]}, {"1.9", [{restart_application, diameter}]}, {"1.9.1", [{restart_application, diameter}]}, - {"1.9.2", [{restart_application, diameter}]} + {"1.9.2", [{restart_application, diameter}]}, + {"1.9.2.1", [{restart_application, diameter}]}, + {"1.9.2.2", [{restart_application, diameter}]}, + {"1.9.2.3", [{restart_application, diameter}]}, + {"1.10", [{restart_application, diameter}]}, + {"1.11", [{restart_application, diameter}]}, + {"1.11.1", [{restart_application, diameter}]} ] }. diff --git a/lib/diameter/src/info/diameter_info.erl b/lib/diameter/src/info/diameter_info.erl index 2e08662a9e..59a3b94ee4 100644 --- a/lib/diameter/src/info/diameter_info.erl +++ b/lib/diameter/src/info/diameter_info.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2014. All Rights Reserved. +%% Copyright Ericsson AB 2010-2015. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -52,8 +52,6 @@ p/1, p/3]). --compile({no_auto_import,[max/2]}). - -export([collect/2]). -define(LONG_TIMEOUT, 30000). @@ -684,9 +682,6 @@ pt(T) -> recsplit(SFun, Rec) -> fun(Fs,Vs) -> SFun(element(1, Rec), Fs, Vs) end. -max(A, B) -> - if A > B -> A; true -> B end. - keyfetch(Key, List) -> {Key,V} = lists:keyfind(Key, 1, List), V. diff --git a/lib/diameter/src/transport/diameter_sctp.erl b/lib/diameter/src/transport/diameter_sctp.erl index 3e08b78ea1..678dc9b5d6 100644 --- a/lib/diameter/src/transport/diameter_sctp.erl +++ b/lib/diameter/src/transport/diameter_sctp.erl @@ -21,9 +21,6 @@ -module(diameter_sctp). -behaviour(gen_server). --compile({no_auto_import, [now/0]}). --import(diameter_lib, [now/0]). - %% interface -export([start/3]). diff --git a/lib/diameter/test/diameter_examples_SUITE.erl b/lib/diameter/test/diameter_examples_SUITE.erl index 2c10daec50..e4ed2b227d 100644 --- a/lib/diameter/test/diameter_examples_SUITE.erl +++ b/lib/diameter/test/diameter_examples_SUITE.erl @@ -299,7 +299,7 @@ slave(_) -> T0 = diameter_lib:now(), {ok, Node} = ct_slave:start(?MODULE, ?TIMEOUTS), T1 = diameter_lib:now(), - T2 = rpc:call(Node, erlang, now, []), + T2 = rpc:call(Node, diameter_lib, now, []), {ok, Node} = ct_slave:stop(?MODULE), now_diff([T0, T1, T2, diameter_lib:now()]). diff --git a/lib/diameter/test/diameter_gen_sctp_SUITE.erl b/lib/diameter/test/diameter_gen_sctp_SUITE.erl index c739643dbe..cbd7fc8ec5 100644 --- a/lib/diameter/test/diameter_gen_sctp_SUITE.erl +++ b/lib/diameter/test/diameter_gen_sctp_SUITE.erl @@ -300,10 +300,10 @@ connect2(Pid, PortNr, Bin) -> %% T2 = time after listening process received our message %% T3 = time after reply is received - T1 = diameter_util:timestamp(), + T1 = diameter_lib:now(), ok = send(Sock, Id, Bin), T2 = unmark(recv(Sock, Id)), - T3 = diameter_util:timestamp(), + T3 = diameter_lib:now(), {diameter_lib:micro_diff(T2, T1), %% Outbound diameter_lib:micro_diff(T3, T2)}. %% Inbound @@ -330,13 +330,13 @@ send(Sock, Id, Bin) -> %% mark/1 mark(Bin) -> - Info = term_to_binary(diameter_util:timestamp()), + Info = term_to_binary(diameter_lib:now()), <<Info/binary, Bin/binary>>. %% unmark/1 unmark(Bin) -> - {_,_,_} = binary_to_term(Bin). + binary_to_term(Bin). %% =========================================================================== diff --git a/lib/diameter/test/diameter_relay_SUITE.erl b/lib/diameter/test/diameter_relay_SUITE.erl index fd83c2cd7f..f766f54a80 100644 --- a/lib/diameter/test/diameter_relay_SUITE.erl +++ b/lib/diameter/test/diameter_relay_SUITE.erl @@ -334,13 +334,39 @@ realm(Host) -> call(Server) -> Realm = realm(Server), + %% Include some arbitrary AVPs to exercise encode/decode, that + %% are received back in the STA. + Avps = [#diameter_avp{code = 111, + data = [#diameter_avp{code = 222, + data = <<222:24>>}, + #diameter_avp{code = 333, + data = <<333:16>>}]}, + #diameter_avp{code = 444, + data = <<444:24>>}, + #diameter_avp{code = 555, + data = [#diameter_avp{code = 666, + data = [#diameter_avp + {code = 777, + data = <<7>>}]}, + #diameter_avp{code = 888, + data = <<8>>}, + #diameter_avp{code = 999, + data = <<9>>}]}], + Req = ['STR', {'Destination-Realm', Realm}, {'Destination-Host', [Server]}, {'Termination-Cause', ?LOGOUT}, - {'Auth-Application-Id', ?APP_ID}], + {'Auth-Application-Id', ?APP_ID}, + {'AVP', Avps}], + #diameter_base_STA{'Result-Code' = ?SUCCESS, 'Origin-Host' = Server, - 'Origin-Realm' = Realm} + 'Origin-Realm' = Realm, + %% Unknown AVPs can't be decoded as Grouped since + %% types aren't known. + 'AVP' = [#diameter_avp{code = 111}, + #diameter_avp{code = 444}, + #diameter_avp{code = 555}]} = call(Req, [{filter, realm}]). call(Req, Opts) -> @@ -434,9 +460,18 @@ request(_Pkt, #diameter_caps{origin_host = {OH, _}}) request(#diameter_packet{msg = #diameter_base_STR{'Session-Id' = SId, 'Origin-Host' = Host, 'Origin-Realm' = Realm, - 'Route-Record' = Route}}, + 'Route-Record' = Route, + 'AVP' = Avps}}, #diameter_caps{origin_host = {OH, _}, origin_realm = {OR, _}}) -> + + %% Payloads of unknown AVPs aren't decoded, so we don't know that + %% some types here are Grouped. + [#diameter_avp{code = 111, vendor_id = undefined}, + #diameter_avp{code = 444, vendor_id = undefined, data = <<444:24>>}, + #diameter_avp{code = 555, vendor_id = undefined}] + = Avps, + %% The request should have the Origin-Host/Realm of the original %% sender. R = realm(?CLIENT), @@ -447,4 +482,5 @@ request(#diameter_packet{msg = #diameter_base_STR{'Session-Id' = SId, {reply, #diameter_base_STA{'Result-Code' = ?SUCCESS, 'Session-Id' = SId, 'Origin-Host' = OH, - 'Origin-Realm' = OR}}. + 'Origin-Realm' = OR, + 'AVP' = Avps}}. diff --git a/lib/diameter/test/diameter_stats_SUITE.erl b/lib/diameter/test/diameter_stats_SUITE.erl index 39cb6ae30d..4716082394 100644 --- a/lib/diameter/test/diameter_stats_SUITE.erl +++ b/lib/diameter/test/diameter_stats_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2013. All Rights Reserved. +%% Copyright Ericsson AB 2010-2015. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -96,7 +96,7 @@ read(_) -> 7 = ?stat:incr(C1, Ref, 7), Self = self(), [{Ref, [{C1,7}]}, {Self, [{C1,2}, {C2,1}]}] - = lists:sort(?stat:read([self(), Ref, make_ref()])), + = ?stat:read([self(), Ref, make_ref()]), [] = ?stat:read([]), [] = ?stat:read([make_ref()]), ?stat:flush([self(), Ref, make_ref()]). @@ -116,7 +116,7 @@ sum(_) -> [{Self, [{C1,1}, {C2,2}]}] = ?stat:sum([self()]), [{Ref, [{C1,7}]}, {Self, [{C1,1}, {C2,2}]}] - = lists:sort(?stat:flush([self(), Ref])). + = ?stat:flush([self(), Ref]). flush(_) -> Ref = make_ref(), diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl index 7e316c03f1..967a0bf591 100644 --- a/lib/diameter/test/diameter_traffic_SUITE.erl +++ b/lib/diameter/test/diameter_traffic_SUITE.erl @@ -725,7 +725,8 @@ send_any_2(Config) -> Req = ['STR', {'Termination-Cause', ?LOGOUT}, {'Destination-Host', [?HOST(SN, "unknown.org")]}], ?answer_message(?UNABLE_TO_DELIVER) - = call(Config, Req, [{filter, {any, [host, realm]}}]). + = call(Config, Req, [{filter, {first, [{all, [host, realm]}, + realm]}}]). %% Send with a conjunctive filter. send_all_1(Config) -> diff --git a/lib/diameter/test/diameter_transport_SUITE.erl b/lib/diameter/test/diameter_transport_SUITE.erl index 701fe070d0..53d2d6660e 100644 --- a/lib/diameter/test/diameter_transport_SUITE.erl +++ b/lib/diameter/test/diameter_transport_SUITE.erl @@ -54,7 +54,7 @@ %% Receive a message. -define(RECV(Pat, Ret), receive Pat -> Ret end). --define(RECV(Pat), ?RECV(Pat, diameter_util:timestamp())). +-define(RECV(Pat), ?RECV(Pat, diameter_lib:now())). %% Sockets are opened on the loopback address. -define(ADDR, {127,0,0,1}). @@ -417,8 +417,7 @@ gen_accept(tcp, LSock) -> gen_send(sctp, Sock, Bin) -> {OS, _IS, Id} = getr(assoc), - {_, _, Us} = diameter_util:timestamp(), - gen_sctp:send(Sock, Id, Us rem OS, Bin); + gen_sctp:send(Sock, Id, erlang:unique_integer([positive]) rem OS, Bin); gen_send(tcp, Sock, Bin) -> gen_tcp:send(Sock, Bin). diff --git a/lib/diameter/test/diameter_util.erl b/lib/diameter/test/diameter_util.erl index c727d10ddf..52b747e99c 100644 --- a/lib/diameter/test/diameter_util.erl +++ b/lib/diameter/test/diameter_util.erl @@ -31,7 +31,6 @@ fold/3, foldl/3, scramble/1, - timestamp/0, seed/0, unique_string/0, have_sctp/0]). @@ -189,12 +188,6 @@ s(Acc, L) -> s([T|Acc], H ++ Rest). %% --------------------------------------------------------------------------- -%% timestamp/0 - -timestamp() -> - diameter_lib:timestamp(diameter_lib:now()). - -%% --------------------------------------------------------------------------- %% seed/0 seed() -> @@ -205,14 +198,7 @@ seed() -> %% unique_string/0 unique_string() -> - try erlang:unique_integer() of - N -> - integer_to_list(N) - catch - error: undef -> %% OTP < 18 - {M,S,U} = timestamp(), - tl(lists:append(["-" ++ integer_to_list(N) || N <- [M,S,U]])) - end. + integer_to_list(erlang:unique_integer()). %% --------------------------------------------------------------------------- %% have_sctp/0 diff --git a/lib/diameter/test/diameter_watchdog_SUITE.erl b/lib/diameter/test/diameter_watchdog_SUITE.erl index 016801383b..6d22ddcc18 100644 --- a/lib/diameter/test/diameter_watchdog_SUITE.erl +++ b/lib/diameter/test/diameter_watchdog_SUITE.erl @@ -49,7 +49,8 @@ accept/1, connect/3, send/2, - setopts/2]). + setopts/2, + close/1]). -include("diameter.hrl"). -include("diameter_ct.hrl"). @@ -421,7 +422,6 @@ suspect(TRef, false, SvcName, N) -> %% abuse/1 abuse(F) -> - [] = run([[abuse, F, T] || T <- [listen, connect]]). abuse(F, [_,_,_|_] = Args) -> @@ -546,6 +546,9 @@ setopts(Sock, Opts) -> send(Sock, Bin) -> send(getr(config), Sock, Bin). +close(Sock) -> + gen_tcp:close(Sock). + %% send/3 %% First outgoing message from a new transport process is CER/CEA. diff --git a/lib/diameter/vsn.mk b/lib/diameter/vsn.mk index 1e3135680d..836def8447 100644 --- a/lib/diameter/vsn.mk +++ b/lib/diameter/vsn.mk @@ -17,5 +17,5 @@ # %CopyrightEnd% APPLICATION = diameter -DIAMETER_VSN = 1.10 +DIAMETER_VSN = 1.11.2 APP_VSN = $(APPLICATION)-$(DIAMETER_VSN)$(PRE_VSN) diff --git a/lib/edoc/doc/overview.edoc b/lib/edoc/doc/overview.edoc index 3639bb43a5..d2bba9d744 100644 --- a/lib/edoc/doc/overview.edoc +++ b/lib/edoc/doc/overview.edoc @@ -755,7 +755,7 @@ following escape sequences may be used: <dl> === Function specifications === -<note>Although the syntax described in the following can still be used +Note that although the syntax described in the following can still be used for specifying functions we recommend that Erlang specifications as described in <seealso marker="doc/reference_manual:typespec"> Types and Function Specification</seealso> should be added to the source @@ -764,7 +764,6 @@ marker="dialyzer:dialyzer">Dialyzer</seealso>'s can be utilized in the process of keeping the documentation consistent and up-to-date. Erlang specifications will be used unless there is also a function specification (a `@spec' tag followed by a type) with the same name. -</note> The following grammar describes the form of the specifications following a `@spec' tag. A '`?'' suffix implies that the element is optional. @@ -973,12 +972,12 @@ contain any annotations at all. === Type definitions === -<note>Although the syntax described in the following can still be used +Note that although the syntax described in the following can still be used for specifying types we recommend that Erlang types as described in <seealso marker="doc/reference_manual:typespec"> Types and Function Specification</seealso> should be added to the source code instead. Erlang types will be used unless there is a type alias with the same -name.</note> +name. The following grammar (see above for auxiliary definitions) describes the form of the definitions that may follow a `@type' tag: diff --git a/lib/edoc/doc/src/notes.xml b/lib/edoc/doc/src/notes.xml index 5260a1d465..3f9d26796a 100644 --- a/lib/edoc/doc/src/notes.xml +++ b/lib/edoc/doc/src/notes.xml @@ -32,6 +32,33 @@ <p>This document describes the changes made to the EDoc application.</p> +<section><title>Edoc 0.7.18</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> Assign correct names to list arguments. </p> + <p> + Own Id: OTP-13234 Aux Id: ERL-63 </p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Unless the <c>sort_functions</c> option is <c>true</c>, + <c>edoc_layout</c> does not sort functions.</p> + <p> + Own Id: OTP-13302</p> + </item> + </list> + </section> + +</section> + <section><title>Edoc 0.7.17</title> <section><title>Improvements and New Features</title> diff --git a/lib/edoc/src/edoc.erl b/lib/edoc/src/edoc.erl index 90f1fc3071..d2494b69fe 100644 --- a/lib/edoc/src/edoc.erl +++ b/lib/edoc/src/edoc.erl @@ -555,7 +555,6 @@ read_source(Name) -> %% <dd>Specifies a list of pre-defined Erlang preprocessor (`epp') %% macro definitions, used if the `preprocess' option is turned on. %% The default value is the empty list.</dd> -%% </dl> %% <dt>{@type {report_missing_types, boolean()@}} %% </dt> %% <dd>If the value is `true', warnings are issued for missing types. @@ -563,6 +562,7 @@ read_source(Name) -> %% `no_report_missing_types' is an alias for %% `{report_missing_types, false}'. %% </dd> +%% </dl> %% %% @see get_doc/2 %% @see //syntax_tools/erl_syntax diff --git a/lib/edoc/src/edoc_layout.erl b/lib/edoc/src/edoc_layout.erl index b67ec31ae3..f723cd8373 100644 --- a/lib/edoc/src/edoc_layout.erl +++ b/lib/edoc/src/edoc_layout.erl @@ -180,7 +180,9 @@ layout_module(#xmlElement{name = module, content = Es}=E, Opts) -> FullDesc = get_content(fullDescription, Desc), Functions = [{function_name(E), E} || E <- get_content(functions, Es)], Types = [{type_name(E), E} || E <- get_content(typedecls, Es)], - SortedFs = lists:sort(Functions), + SortedFs = if Opts#opts.sort_functions -> lists:sort(Functions); + true -> Functions + end, Body = (navigation("top") ++ [?NL, hr, ?NL, ?NL, {h1, Title}, ?NL] ++ doc_index(FullDesc, Functions, Types) @@ -204,9 +206,7 @@ layout_module(#xmlElement{name = module, content = Es}=E, Opts) -> end ++ types(lists:sort(Types), Opts) ++ function_index(SortedFs, Opts#opts.index_columns) - ++ if Opts#opts.sort_functions -> functions(SortedFs, Opts); - true -> functions(Functions, Opts) - end + ++ functions(SortedFs, Opts) ++ [hr, ?NL] ++ navigation("bottom") ++ timestamp()), diff --git a/lib/edoc/src/edoc_specs.erl b/lib/edoc/src/edoc_specs.erl index bb98e8b04f..f2e5891c2e 100644 --- a/lib/edoc/src/edoc_specs.erl +++ b/lib/edoc/src/edoc_specs.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2015. All Rights Reserved. +%% Copyright Ericsson AB 1996-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -270,12 +270,8 @@ parms([], []) -> parms([A | As], [D | Ds]) -> [param(A, D) | parms(As, Ds)]. -param(#t_list{type = Type}, Default) -> - param(Type, Default); param(#t_paren{type = Type}, Default) -> param(Type, Default); -param(#t_nonempty_list{type = Type}, Default) -> - param(Type, Default); param(#t_record{name = #t_atom{val = Name}}, _Default) -> list_to_atom(capitalize(atom_to_list(Name))); param(T, Default) -> diff --git a/lib/edoc/vsn.mk b/lib/edoc/vsn.mk index 49a73331c6..83514ac94f 100644 --- a/lib/edoc/vsn.mk +++ b/lib/edoc/vsn.mk @@ -1 +1 @@ -EDOC_VSN = 0.7.17 +EDOC_VSN = 0.7.18 diff --git a/lib/eldap/doc/src/eldap.xml b/lib/eldap/doc/src/eldap.xml index 8f4479a730..43873e44e2 100644 --- a/lib/eldap/doc/src/eldap.xml +++ b/lib/eldap/doc/src/eldap.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2012</year><year>2013</year> + <year>2012</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -29,7 +29,7 @@ <rev>B</rev> </header> <module>eldap</module> - <modulesummary>Eldap Functions</modulesummary> + <modulesummary>LDAP Client</modulesummary> <description> <p>This module provides a client api to the Lightweight Directory Access Protocol (LDAP). </p> @@ -40,20 +40,67 @@ </list> <p>The above publications can be found at <url href="http://www.ietf.org">IETF</url>. </p> - <p><em>Types</em></p> - <pre> -handle() Connection handle -attribute() {Type = string(), Values=[string()]} -modify_op() See mod_add/2, mod_delete/2, mod_replace/2 -scope() See baseObject/0, singleLevel/0, wholeSubtree/0 -dereference() See neverDerefAliases/0, derefInSearching/0, derefFindingBaseObj/0, derefAlways/0 -filter() See present/1, substrings/2, - equalityMatch/2, greaterOrEqual/2, lessOrEqual/2, - approxMatch/2, extensibleMatch/2, - 'and'/1, 'or'/1, 'not'/1. - </pre> - <p></p> </description> + + <section> + <title>DATA TYPES</title> + <p>Type definitions that are used more than once in this module: + </p> + <taglist> + <tag><c>handle()</c></tag> + <item><p>Connection handle</p></item> + + <tag><c>attribute() =</c></tag> + <item><p><c>{Type = string(), Values=[string()]}</c></p></item> + + <tag><c>modify_op()</c></tag> + <item><p>See + <seealso marker="#mod_add/2">mod_add/2</seealso>, + <seealso marker="#mod_delete/2">mod_delete/2</seealso>, + <seealso marker="#mod_replace/2">mod_replace/2</seealso> + </p></item> + + <tag><c>scope()</c></tag> + <item><p>See + <seealso marker="#baseObject/0">baseObject/0</seealso>, + <seealso marker="#singleLevel/0">singleLevel/0</seealso>, + <seealso marker="#wholeSubtree/0">wholeSubtree/0</seealso> + </p></item> + + <tag><c>dereference()</c></tag> + <item><p>See + <seealso marker="#neverDerefAliases/0">neverDerefAliases/0</seealso>, + <seealso marker="#derefInSearching/0">derefInSearching/0</seealso>, + <seealso marker="#derefFindingBaseObj/0">derefFindingBaseObj/0</seealso>, + <seealso marker="#derefAlways/0">derefAlways/0</seealso> + </p></item> + + <tag><c>filter()</c></tag> + <item><p>See + <seealso marker="#present/1">present/1</seealso>, + <seealso marker="#substrings/2">substrings/2</seealso>, + <seealso marker="#equalityMatch/2">equalityMatch/2</seealso>, + <seealso marker="#greaterOrEqual/2">greaterOrEqual/2</seealso>, + <seealso marker="#lessOrEqual/2">lessOrEqual/2</seealso>, + <seealso marker="#approxMatch/2">approxMatch/2</seealso>, + <seealso marker="#extensibleMatch/2">extensibleMatch/2</seealso>, + <seealso marker="#'and'/1">'and'/1</seealso>, + <seealso marker="#'or'/1">'or'/1</seealso>, + <seealso marker="#'not'/1">'not'/1</seealso> + </p></item> + + <tag><c>return_value() = </c></tag> + <item><p><c>ok | {ok, {referral,referrals()}} | {error,Error}</c> + </p></item> + + <tag><c>referrals() =</c></tag> + <item><p><c>[Address = string()]</c> The contents of <c>Address</c> is server dependent. + </p></item> + + </taglist> + </section> + + <funcs> <func> <name>open([Host]) -> {ok, Handle} | {error, Reason}</name> @@ -88,18 +135,19 @@ filter() See present/1, substrings/2, <v>Handle = handle()</v> </type> <desc> - <p>Shutdown the connection.</p> + <p>Shutdown the connection after sending an unbindRequest to the server. If the connection is tls the connection + will be closed with <c>ssl:close/1</c>, otherwise with <c>gen_tcp:close/1</c>.</p> </desc> </func> <func> - <name>start_tls(Handle, Options) -> ok | {error,Error}</name> + <name>start_tls(Handle, Options) -> return_value()</name> <fsummary>Upgrade a connection to TLS.</fsummary> <desc> <p>Same as start_tls(Handle, Options, infinity)</p> </desc> </func> <func> - <name>start_tls(Handle, Options, Timeout) -> ok | {error,Error}</name> + <name>start_tls(Handle, Options, Timeout) -> return_value()</name> <fsummary>Upgrade a connection to TLS.</fsummary> <type> <v>Handle = handle()</v> @@ -128,7 +176,7 @@ filter() See present/1, substrings/2, </desc> </func> <func> - <name>simple_bind(Handle, Dn, Password) -> ok | {error, Reason}</name> + <name>simple_bind(Handle, Dn, Password) -> return_value()</name> <fsummary>Authenticate the connection.</fsummary> <type> <v>Handle = handle()</v> @@ -140,7 +188,7 @@ filter() See present/1, substrings/2, </desc> </func> <func> - <name>add(Handle, Dn, [Attribute]) -> ok | {error, Reason}</name> + <name>add(Handle, Dn, [Attribute]) -> return_value()</name> <fsummary>Add an entry.</fsummary> <type> <v>Handle = handle()</v> @@ -161,7 +209,7 @@ filter() See present/1, substrings/2, </desc> </func> <func> - <name>delete(Handle, Dn) -> ok | {error, Reason}</name> + <name>delete(Handle, Dn) -> return_value()</name> <fsummary>Delete an entry.</fsummary> <type> <v>Dn = string()</v> @@ -203,7 +251,7 @@ filter() See present/1, substrings/2, </func> <func> - <name>modify(Handle, Dn, [ModifyOp]) -> ok | {error, Reason}</name> + <name>modify(Handle, Dn, [ModifyOp]) -> return_value()</name> <fsummary>Modify an entry.</fsummary> <type> <v>Dn = string()</v> @@ -219,7 +267,7 @@ filter() See present/1, substrings/2, </desc> </func> <func> - <name>modify_password(Handle, Dn, NewPasswd) -> ok | {ok, GenPasswd} | {error, Reason}</name> + <name>modify_password(Handle, Dn, NewPasswd) -> return_value() | {ok, GenPasswd}</name> <fsummary>Modify the password of a user.</fsummary> <type> <v>Dn = string()</v> @@ -230,7 +278,7 @@ filter() See present/1, substrings/2, </desc> </func> <func> - <name>modify_password(Handle, Dn, NewPasswd, OldPasswd) -> ok | {ok, GenPasswd} | {error, Reason}</name> + <name>modify_password(Handle, Dn, NewPasswd, OldPasswd) -> return_value() | {ok, GenPasswd}</name> <fsummary>Modify the password of a user.</fsummary> <type> <v>Dn = string()</v> @@ -259,7 +307,7 @@ filter() See present/1, substrings/2, </desc> </func> <func> - <name>modify_dn(Handle, Dn, NewRDN, DeleteOldRDN, NewSupDN) -> ok | {error, Reason}</name> + <name>modify_dn(Handle, Dn, NewRDN, DeleteOldRDN, NewSupDN) -> return_value()</name> <fsummary>Modify the DN of an entry.</fsummary> <type> <v>Dn = string()</v> @@ -279,7 +327,7 @@ filter() See present/1, substrings/2, </desc> </func> <func> - <name>search(Handle, SearchOptions) -> {ok, #eldap_search_result{}} | {error, Reason}</name> + <name>search(Handle, SearchOptions) -> {ok, #eldap_search_result{}} | {ok, {referral,referrals()}} | {error, Reason}</name> <fsummary>Search the Directory</fsummary> <type> <v>SearchOptions = #eldap_search{} | [SearchOption]</v> diff --git a/lib/eldap/doc/src/notes.xml b/lib/eldap/doc/src/notes.xml index b40977cfd9..04b75f9e31 100644 --- a/lib/eldap/doc/src/notes.xml +++ b/lib/eldap/doc/src/notes.xml @@ -31,6 +31,37 @@ </header> <p>This document describes the changes made to the Eldap application.</p> +<section><title>Eldap 1.2.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + ELDAP did not send an <c>'unBind'</c> request before + closing the connection.</p> + <p> + Own Id: OTP-13327</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Handles the <c>referral</c> result code from LDAP + servers. Adds the return value <c>{ok, + {referral,UrlList}}</c> to some functions. See the Eldap + reference manual for details.</p> + <p> + Own Id: OTP-12272</p> + </item> + </list> + </section> + +</section> + <section><title>Eldap 1.2</title> <section><title>Improvements and New Features</title> diff --git a/lib/eldap/src/eldap.erl b/lib/eldap/src/eldap.erl index ae47c815c9..0c03021bd0 100644 --- a/lib/eldap/src/eldap.erl +++ b/lib/eldap/src/eldap.erl @@ -10,16 +10,23 @@ %%% See MIT-LICENSE at the top dir for licensing information. %%% -------------------------------------------------------------------- -vc('$Id$ '). --export([open/1,open/2,simple_bind/3,controlling_process/2, - start_tls/2, start_tls/3, - modify_password/3, modify_password/4, +-export([open/1, open/2, + simple_bind/3, simple_bind/4, + controlling_process/2, + start_tls/2, start_tls/3, start_tls/4, + modify_password/3, modify_password/4, modify_password/5, getopts/2, baseObject/0,singleLevel/0,wholeSubtree/0,close/1, equalityMatch/2,greaterOrEqual/2,lessOrEqual/2, extensibleMatch/2, - approxMatch/2,search/2,substrings/2,present/1, - 'and'/1,'or'/1,'not'/1,modify/3, mod_add/2, mod_delete/2, - mod_replace/2, add/3, delete/2, modify_dn/5,parse_dn/1, + search/2, search/3, + approxMatch/2,substrings/2,present/1, + 'and'/1,'or'/1,'not'/1,mod_add/2, mod_delete/2, + mod_replace/2, + modify/3, modify/4, + add/3, add/4, + delete/2, delete/3, + modify_dn/5,parse_dn/1, parse_ldap_url/1]). -export([neverDerefAliases/0, derefInSearching/0, @@ -91,7 +98,10 @@ start_tls(Handle, TlsOptions) -> start_tls(Handle, TlsOptions, infinity). start_tls(Handle, TlsOptions, Timeout) -> - send(Handle, {start_tls,TlsOptions,Timeout}), + start_tls(Handle, TlsOptions, Timeout, asn1_NOVALUE). + +start_tls(Handle, TlsOptions, Timeout, Controls) -> + send(Handle, {start_tls,TlsOptions,Timeout,Controls}), recv(Handle). %%% -------------------------------------------------------------------- @@ -108,7 +118,11 @@ modify_password(Handle, Dn, NewPasswd) -> modify_password(Handle, Dn, NewPasswd, OldPasswd) when is_pid(Handle), is_list(Dn), is_list(NewPasswd), is_list(OldPasswd) -> - send(Handle, {passwd_modify,optional(Dn),optional(NewPasswd),optional(OldPasswd)}), + modify_password(Handle, Dn, NewPasswd, OldPasswd, asn1_NOVALUE). + +modify_password(Handle, Dn, NewPasswd, OldPasswd, Controls) + when is_pid(Handle), is_list(Dn), is_list(NewPasswd), is_list(OldPasswd) -> + send(Handle, {passwd_modify,optional(Dn),optional(NewPasswd),optional(OldPasswd),Controls}), recv(Handle). %%% -------------------------------------------------------------------- @@ -147,7 +161,10 @@ controlling_process(Handle, Pid) when is_pid(Handle), is_pid(Pid) -> %%% Returns: ok | {error, Error} %%% -------------------------------------------------------------------- simple_bind(Handle, Dn, Passwd) when is_pid(Handle) -> - send(Handle, {simple_bind, Dn, Passwd}), + simple_bind(Handle, Dn, Passwd, asn1_NOVALUE). + +simple_bind(Handle, Dn, Passwd, Controls) when is_pid(Handle) -> + send(Handle, {simple_bind, Dn, Passwd, Controls}), recv(Handle). %%% -------------------------------------------------------------------- @@ -164,7 +181,10 @@ simple_bind(Handle, Dn, Passwd) when is_pid(Handle) -> %%% ) %%% -------------------------------------------------------------------- add(Handle, Entry, Attributes) when is_pid(Handle),is_list(Entry),is_list(Attributes) -> - send(Handle, {add, Entry, add_attrs(Attributes)}), + add(Handle, Entry, Attributes, asn1_NOVALUE). + +add(Handle, Entry, Attributes, Controls) when is_pid(Handle),is_list(Entry),is_list(Attributes) -> + send(Handle, {add, Entry, add_attrs(Attributes), Controls}), recv(Handle). %%% Do sanity check ! @@ -188,7 +208,10 @@ add_attrs(Attrs) -> %%% ) %%% -------------------------------------------------------------------- delete(Handle, Entry) when is_pid(Handle), is_list(Entry) -> - send(Handle, {delete, Entry}), + delete(Handle, Entry, asn1_NOVALUE). + +delete(Handle, Entry, Controls) when is_pid(Handle), is_list(Entry) -> + send(Handle, {delete, Entry, Controls}), recv(Handle). %%% -------------------------------------------------------------------- @@ -203,7 +226,10 @@ delete(Handle, Entry) when is_pid(Handle), is_list(Entry) -> %%% ) %%% -------------------------------------------------------------------- modify(Handle, Object, Mods) when is_pid(Handle), is_list(Object), is_list(Mods) -> - send(Handle, {modify, Object, Mods}), + modify(Handle, Object, Mods, asn1_NOVALUE). + +modify(Handle, Object, Mods, Controls) when is_pid(Handle), is_list(Object), is_list(Mods) -> + send(Handle, {modify, Object, Mods, Controls}), recv(Handle). %%% @@ -236,8 +262,12 @@ m(Operation, Type, Values) -> %%% -------------------------------------------------------------------- modify_dn(Handle, Entry, NewRDN, DelOldRDN, NewSup) when is_pid(Handle),is_list(Entry),is_list(NewRDN),is_atom(DelOldRDN),is_list(NewSup) -> + modify_dn(Handle, Entry, NewRDN, DelOldRDN, NewSup, asn1_NOVALUE). + +modify_dn(Handle, Entry, NewRDN, DelOldRDN, NewSup, Controls) + when is_pid(Handle),is_list(Entry),is_list(NewRDN),is_atom(DelOldRDN),is_list(NewSup) -> send(Handle, {modify_dn, Entry, NewRDN, - bool_p(DelOldRDN), optional(NewSup)}), + bool_p(DelOldRDN), optional(NewSup), Controls}), recv(Handle). %%% Sanity checks ! @@ -272,16 +302,19 @@ optional(Value) -> Value. %%% []}} %%% %%% -------------------------------------------------------------------- -search(Handle, A) when is_pid(Handle), is_record(A, eldap_search) -> - call_search(Handle, A); -search(Handle, L) when is_pid(Handle), is_list(L) -> +search(Handle, X) when is_pid(Handle), is_record(X,eldap_search) ; is_list(X) -> + search(Handle, X, asn1_NOVALUE). + +search(Handle, A, Controls) when is_pid(Handle), is_record(A, eldap_search) -> + call_search(Handle, A, Controls); +search(Handle, L, Controls) when is_pid(Handle), is_list(L) -> case catch parse_search_args(L) of {error, Emsg} -> {error, Emsg}; - A when is_record(A, eldap_search) -> call_search(Handle, A) + A when is_record(A, eldap_search) -> call_search(Handle, A, Controls) end. -call_search(Handle, A) -> - send(Handle, {search, A}), +call_search(Handle, A, Controls) -> + send(Handle, {search, A, Controls}), recv(Handle). parse_search_args(Args) -> @@ -484,33 +517,33 @@ do_connect(Host, Data, Opts) when Data#eldap.ldaps == true -> loop(Cpid, Data) -> receive - {From, {search, A}} -> - {Res,NewData} = do_search(Data, A), + {From, {search, A, Controls}} -> + {Res,NewData} = do_search(Data, A, Controls), send(From,Res), ?MODULE:loop(Cpid, NewData); - {From, {modify, Obj, Mod}} -> - {Res,NewData} = do_modify(Data, Obj, Mod), + {From, {modify, Obj, Mod, Controls}} -> + {Res,NewData} = do_modify(Data, Obj, Mod, Controls), send(From,Res), ?MODULE:loop(Cpid, NewData); - {From, {modify_dn, Obj, NewRDN, DelOldRDN, NewSup}} -> - {Res,NewData} = do_modify_dn(Data, Obj, NewRDN, DelOldRDN, NewSup), + {From, {modify_dn, Obj, NewRDN, DelOldRDN, NewSup, Controls}} -> + {Res,NewData} = do_modify_dn(Data, Obj, NewRDN, DelOldRDN, NewSup, Controls), send(From,Res), ?MODULE:loop(Cpid, NewData); - {From, {add, Entry, Attrs}} -> - {Res,NewData} = do_add(Data, Entry, Attrs), + {From, {add, Entry, Attrs, Controls}} -> + {Res,NewData} = do_add(Data, Entry, Attrs, Controls), send(From,Res), ?MODULE:loop(Cpid, NewData); - {From, {delete, Entry}} -> - {Res,NewData} = do_delete(Data, Entry), + {From, {delete, Entry, Controls}} -> + {Res,NewData} = do_delete(Data, Entry, Controls), send(From,Res), ?MODULE:loop(Cpid, NewData); - {From, {simple_bind, Dn, Passwd}} -> - {Res,NewData} = do_simple_bind(Data, Dn, Passwd), + {From, {simple_bind, Dn, Passwd, Controls}} -> + {Res,NewData} = do_simple_bind(Data, Dn, Passwd, Controls), send(From,Res), ?MODULE:loop(Cpid, NewData); @@ -520,17 +553,18 @@ loop(Cpid, Data) -> ?PRINT("New Cpid is: ~p~n",[NewCpid]), ?MODULE:loop(NewCpid, Data); - {From, {start_tls,TlsOptions,Timeout}} -> - {Res,NewData} = do_start_tls(Data, TlsOptions, Timeout), + {From, {start_tls,TlsOptions,Timeout,Controls}} -> + {Res,NewData} = do_start_tls(Data, TlsOptions, Timeout, Controls), send(From,Res), ?MODULE:loop(Cpid, NewData); - {From, {passwd_modify,Dn,NewPasswd,OldPasswd}} -> - {Res,NewData} = do_passwd_modify(Data, Dn, NewPasswd, OldPasswd), + {From, {passwd_modify,Dn,NewPasswd,OldPasswd,Controls}} -> + {Res,NewData} = do_passwd_modify(Data, Dn, NewPasswd, OldPasswd, Controls), send(From, Res), ?MODULE:loop(Cpid, NewData); {_From, close} -> + {no_reply,_NewData} = do_unbind(Data), unlink(Cpid), exit(closed); @@ -578,11 +612,10 @@ loop(Cpid, Data) -> %%% -------------------------------------------------------------------- %%% startTLS Request %%% -------------------------------------------------------------------- - -do_start_tls(Data=#eldap{using_tls=true}, _, _) -> +do_start_tls(Data=#eldap{using_tls=true}, _, _, _) -> {{error,tls_already_started}, Data}; -do_start_tls(Data=#eldap{fd=FD} , TlsOptions, Timeout) -> - case catch exec_start_tls(Data) of +do_start_tls(Data=#eldap{fd=FD} , TlsOptions, Timeout, Controls) -> + case catch exec_start_tls(Data, Controls) of {ok,NewData} -> case ssl:connect(FD,TlsOptions,Timeout) of {ok, SslSocket} -> @@ -593,15 +626,16 @@ do_start_tls(Data=#eldap{fd=FD} , TlsOptions, Timeout) -> {error,Error} -> {{error,Error}, Data} end; - {error,Error} -> {{error,Error},Data}; - Else -> {{error,Else},Data} + {{ok,Val},NewData} -> {{ok,Val},NewData}; + {error,Error} -> {{error,Error},Data}; + Else -> {{error,Else},Data} end. -define(START_TLS_OID, "1.3.6.1.4.1.1466.20037"). -exec_start_tls(Data) -> +exec_start_tls(Data, Controls) -> Req = #'ExtendedRequest'{requestName = ?START_TLS_OID}, - Reply = request(Data#eldap.fd, Data, Data#eldap.id, {extendedReq, Req}), + Reply = request(Data#eldap.fd, Data, Data#eldap.id, {extendedReq, Req, Controls}), exec_extended_req_reply(Data, Reply). exec_extended_req_reply(Data, {ok,Msg}) when @@ -611,6 +645,8 @@ exec_extended_req_reply(Data, {ok,Msg}) when case Result#'ExtendedResponse'.resultCode of success -> {ok,Data}; + referral -> + {{ok, {referral,Result#'ExtendedResponse'.referral}}, Data}; Error -> {error, {response,Error}} end; @@ -626,30 +662,32 @@ exec_extended_req_reply(_, Error) -> %%% Authenticate ourselves to the directory using %%% simple authentication. -do_simple_bind(Data, anon, anon) -> %% For testing - do_the_simple_bind(Data, "", ""); -do_simple_bind(Data, Dn, _Passwd) when Dn=="",Data#eldap.anon_auth==false -> +do_simple_bind(Data, anon, anon, Controls) -> %% For testing + do_the_simple_bind(Data, "", "", Controls); +do_simple_bind(Data, Dn, _Passwd,_) when Dn=="",Data#eldap.anon_auth==false -> {{error,anonymous_auth},Data}; -do_simple_bind(Data, _Dn, Passwd) when Passwd=="",Data#eldap.anon_auth==false -> +do_simple_bind(Data, _Dn, Passwd,_) when Passwd=="",Data#eldap.anon_auth==false -> {{error,anonymous_auth},Data}; -do_simple_bind(Data, Dn, Passwd) -> - do_the_simple_bind(Data, Dn, Passwd). +do_simple_bind(Data, Dn, Passwd, Controls) -> + do_the_simple_bind(Data, Dn, Passwd, Controls). -do_the_simple_bind(Data, Dn, Passwd) -> +do_the_simple_bind(Data, Dn, Passwd, Controls) -> case catch exec_simple_bind(Data#eldap{binddn = Dn, passwd = Passwd, - id = bump_id(Data)}) of - {ok,NewData} -> {ok,NewData}; - {error,Emsg} -> {{error,Emsg},Data}; - Else -> {{error,Else},Data} + id = bump_id(Data)}, + Controls) of + {ok,NewData} -> {ok,NewData}; + {{ok,Val},NewData} -> {{ok,Val},NewData}; + {error,Emsg} -> {{error,Emsg},Data}; + Else -> {{error,Else},Data} end. -exec_simple_bind(Data) -> +exec_simple_bind(Data, Controls) -> Req = #'BindRequest'{version = Data#eldap.version, name = Data#eldap.binddn, authentication = {simple, Data#eldap.passwd}}, log2(Data, "bind request = ~p~n", [Req]), - Reply = request(Data#eldap.fd, Data, Data#eldap.id, {bindRequest, Req}), + Reply = request(Data#eldap.fd, Data, Data#eldap.id, {bindRequest, Req, Controls}), log2(Data, "bind reply = ~p~n", [Reply]), exec_simple_bind_reply(Data, Reply). @@ -659,6 +697,7 @@ exec_simple_bind_reply(Data, {ok,Msg}) when {bindResponse, Result} -> case Result#'BindResponse'.resultCode of success -> {ok,Data}; + referral -> {{ok, {referral,Result#'BindResponse'.referral}}, Data}; Error -> {error, Error} end; Other -> {error, Other} @@ -671,10 +710,11 @@ exec_simple_bind_reply(_, Error) -> %%% searchRequest %%% -------------------------------------------------------------------- -do_search(Data, A) -> - case catch do_search_0(Data, A) of +do_search(Data, A, Controls) -> + case catch do_search_0(Data, A, Controls) of {error,Emsg} -> {ldap_closed_p(Data, Emsg),Data}; {'EXIT',Error} -> {ldap_closed_p(Data, Error),Data}; + {{ok,Val},NewData} -> {{ok,Val},NewData}; {ok,Res,Ref,NewData} -> {{ok,polish(Res, Ref)},NewData}; {{error,Reason},NewData} -> {{error,Reason},NewData}; Else -> {ldap_closed_p(Data, Else),Data} @@ -700,7 +740,7 @@ polish_result([H|T]) when is_record(H, 'SearchResultEntry') -> polish_result([]) -> []. -do_search_0(Data, A) -> +do_search_0(Data, A, Controls) -> Req = #'SearchRequest'{baseObject = A#eldap_search.base, scope = v_scope(A#eldap_search.scope), derefAliases = v_deref(A#eldap_search.deref), @@ -711,15 +751,15 @@ do_search_0(Data, A) -> attributes = v_attributes(A#eldap_search.attributes) }, Id = bump_id(Data), - collect_search_responses(Data#eldap{id=Id}, Req, Id). + collect_search_responses(Data#eldap{id=Id}, Req, Id, Controls). %%% The returned answers cames in one packet per entry %%% mixed with possible referals -collect_search_responses(Data, Req, ID) -> +collect_search_responses(Data, Req, ID, Controls) -> S = Data#eldap.fd, log2(Data, "search request = ~p~n", [Req]), - send_request(S, Data, ID, {searchRequest, Req}), + send_request(S, Data, ID, {searchRequest, Req, Controls}), Resp = recv_response(S, Data), log2(Data, "search reply = ~p~n", [Resp]), collect_search_responses(Data, S, ID, Resp, [], []). @@ -732,6 +772,8 @@ collect_search_responses(Data, S, ID, {ok,Msg}, Acc, Ref) success -> log2(Data, "search reply = searchResDone ~n", []), {ok,Acc,Ref,Data}; + referral -> + {{ok, {referral,R#'LDAPResult'.referral}}, Data}; Reason -> {{error,Reason},Data} end; @@ -756,21 +798,22 @@ collect_search_responses(_, _, _, Else, _, _) -> %%% addRequest %%% -------------------------------------------------------------------- -do_add(Data, Entry, Attrs) -> - case catch do_add_0(Data, Entry, Attrs) of +do_add(Data, Entry, Attrs, Controls) -> + case catch do_add_0(Data, Entry, Attrs, Controls) of {error,Emsg} -> {ldap_closed_p(Data, Emsg),Data}; {'EXIT',Error} -> {ldap_closed_p(Data, Error),Data}; {ok,NewData} -> {ok,NewData}; + {{ok,Val},NewData} -> {{ok,Val},NewData}; Else -> {ldap_closed_p(Data, Else),Data} end. -do_add_0(Data, Entry, Attrs) -> +do_add_0(Data, Entry, Attrs, Controls) -> Req = #'AddRequest'{entry = Entry, attributes = Attrs}, S = Data#eldap.fd, Id = bump_id(Data), log2(Data, "add request = ~p~n", [Req]), - Resp = request(S, Data, Id, {addRequest, Req}), + Resp = request(S, Data, Id, {addRequest, Req, Controls}), log2(Data, "add reply = ~p~n", [Resp]), check_reply(Data#eldap{id = Id}, Resp, addResponse). @@ -779,19 +822,20 @@ do_add_0(Data, Entry, Attrs) -> %%% deleteRequest %%% -------------------------------------------------------------------- -do_delete(Data, Entry) -> - case catch do_delete_0(Data, Entry) of +do_delete(Data, Entry, Controls) -> + case catch do_delete_0(Data, Entry, Controls) of {error,Emsg} -> {ldap_closed_p(Data, Emsg),Data}; {'EXIT',Error} -> {ldap_closed_p(Data, Error),Data}; {ok,NewData} -> {ok,NewData}; + {{ok,Val},NewData} -> {{ok,Val},NewData}; Else -> {ldap_closed_p(Data, Else),Data} end. -do_delete_0(Data, Entry) -> +do_delete_0(Data, Entry, Controls) -> S = Data#eldap.fd, Id = bump_id(Data), log2(Data, "del request = ~p~n", [Entry]), - Resp = request(S, Data, Id, {delRequest, Entry}), + Resp = request(S, Data, Id, {delRequest, Entry, Controls}), log2(Data, "del reply = ~p~n", [Resp]), check_reply(Data#eldap{id = Id}, Resp, delResponse). @@ -800,22 +844,23 @@ do_delete_0(Data, Entry) -> %%% modifyRequest %%% -------------------------------------------------------------------- -do_modify(Data, Obj, Mod) -> - case catch do_modify_0(Data, Obj, Mod) of +do_modify(Data, Obj, Mod, Controls) -> + case catch do_modify_0(Data, Obj, Mod, Controls) of {error,Emsg} -> {ldap_closed_p(Data, Emsg),Data}; {'EXIT',Error} -> {ldap_closed_p(Data, Error),Data}; {ok,NewData} -> {ok,NewData}; + {{ok,Val},NewData} -> {{ok,Val},NewData}; Else -> {ldap_closed_p(Data, Else),Data} end. -do_modify_0(Data, Obj, Mod) -> +do_modify_0(Data, Obj, Mod, Controls) -> v_modifications(Mod), Req = #'ModifyRequest'{object = Obj, changes = Mod}, S = Data#eldap.fd, Id = bump_id(Data), log2(Data, "modify request = ~p~n", [Req]), - Resp = request(S, Data, Id, {modifyRequest, Req}), + Resp = request(S, Data, Id, {modifyRequest, Req, Controls}), log2(Data, "modify reply = ~p~n", [Resp]), check_reply(Data#eldap{id = Id}, Resp, modifyResponse). @@ -825,16 +870,17 @@ do_modify_0(Data, Obj, Mod) -> -define(PASSWD_MODIFY_OID, "1.3.6.1.4.1.4203.1.11.1"). -do_passwd_modify(Data, Dn, NewPasswd, OldPasswd) -> - case catch do_passwd_modify_0(Data, Dn, NewPasswd, OldPasswd) of +do_passwd_modify(Data, Dn, NewPasswd, OldPasswd, Controls) -> + case catch do_passwd_modify_0(Data, Dn, NewPasswd, OldPasswd, Controls) of {error,Emsg} -> {ldap_closed_p(Data, Emsg),Data}; {'EXIT',Error} -> {ldap_closed_p(Data, Error),Data}; {ok,NewData} -> {ok,NewData}; + {{ok,Val},NewData} -> {{ok,Val},NewData}; {ok,Passwd,NewData} -> {{ok, Passwd},NewData}; Else -> {ldap_closed_p(Data, Else),Data} end. -do_passwd_modify_0(Data, Dn, NewPasswd, OldPasswd) -> +do_passwd_modify_0(Data, Dn, NewPasswd, OldPasswd, Controls) -> Req = #'PasswdModifyRequestValue'{userIdentity = Dn, oldPasswd = OldPasswd, newPasswd = NewPasswd}, @@ -844,7 +890,7 @@ do_passwd_modify_0(Data, Dn, NewPasswd, OldPasswd) -> requestValue = Bytes}, Id = bump_id(Data), log2(Data, "extended request = ~p~n", [ExtReq]), - Reply = request(Data#eldap.fd, Data, Id, {extendedReq, ExtReq}), + Reply = request(Data#eldap.fd, Data, Id, {extendedReq, ExtReq, Controls}), log2(Data, "modify password reply = ~p~n", [Reply]), exec_passwd_modify_reply(Data#eldap{id = Id}, Reply). @@ -865,6 +911,8 @@ exec_passwd_modify_reply(Data, {ok,Msg}) when throw(Error) end end; + referral -> + {{ok, {referral,Result#'ExtendedResponse'.referral}}, Data}; Error -> {error, {response,Error}} end; @@ -877,15 +925,16 @@ exec_passwd_modify_reply(_, Error) -> %%% modifyDNRequest %%% -------------------------------------------------------------------- -do_modify_dn(Data, Entry, NewRDN, DelOldRDN, NewSup) -> - case catch do_modify_dn_0(Data, Entry, NewRDN, DelOldRDN, NewSup) of +do_modify_dn(Data, Entry, NewRDN, DelOldRDN, NewSup, Controls) -> + case catch do_modify_dn_0(Data, Entry, NewRDN, DelOldRDN, NewSup, Controls) of {error,Emsg} -> {ldap_closed_p(Data, Emsg),Data}; {'EXIT',Error} -> {ldap_closed_p(Data, Error),Data}; {ok,NewData} -> {ok,NewData}; + {{ok,Val},NewData} -> {{ok,Val},NewData}; Else -> {ldap_closed_p(Data, Else),Data} end. -do_modify_dn_0(Data, Entry, NewRDN, DelOldRDN, NewSup) -> +do_modify_dn_0(Data, Entry, NewRDN, DelOldRDN, NewSup, Controls) -> Req = #'ModifyDNRequest'{entry = Entry, newrdn = NewRDN, deleteoldrdn = DelOldRDN, @@ -893,22 +942,51 @@ do_modify_dn_0(Data, Entry, NewRDN, DelOldRDN, NewSup) -> S = Data#eldap.fd, Id = bump_id(Data), log2(Data, "modify DN request = ~p~n", [Req]), - Resp = request(S, Data, Id, {modDNRequest, Req}), + Resp = request(S, Data, Id, {modDNRequest, Req, Controls}), log2(Data, "modify DN reply = ~p~n", [Resp]), check_reply(Data#eldap{id = Id}, Resp, modDNResponse). +%%%-------------------------------------------------------------------- +%%% unbindRequest +%%%-------------------------------------------------------------------- +do_unbind(Data) -> + Req = "", + log2(Data, "unbind request = ~p (has no reply)~n", [Req]), + send_request(Data#eldap.fd, Data, Data#eldap.id, {unbindRequest, Req}), + case Data#eldap.using_tls of + true -> ssl:close(Data#eldap.fd); + false -> gen_tcp:close(Data#eldap.fd) + end, + {no_reply, Data#eldap{binddn = (#eldap{})#eldap.binddn, + passwd = (#eldap{})#eldap.passwd, + fd = (#eldap{})#eldap.fd, + using_tls = false + }}. + + %%% -------------------------------------------------------------------- %%% Send an LDAP request and receive the answer %%% -------------------------------------------------------------------- - request(S, Data, ID, Request) -> send_request(S, Data, ID, Request), recv_response(S, Data). -send_request(S, Data, ID, Request) -> - Message = #'LDAPMessage'{messageID = ID, - protocolOp = Request}, - {ok,Bytes} = 'ELDAPv3':encode('LDAPMessage', Message), +send_request(S, Data, Id, {T,P}) -> + send_the_LDAPMessage(S, Data, #'LDAPMessage'{messageID = Id, + protocolOp = {T,P}}); +send_request(S, Data, Id, {T,P,asn1_NOVALUE}) -> + send_the_LDAPMessage(S, Data, #'LDAPMessage'{messageID = Id, + protocolOp = {T,P}}); +send_request(S, Data, Id, {T,P,Controls0}) -> + Controls = [#'Control'{controlType=F1, + criticality=F2, + controlValue=F3} || {control,F1,F2,F3} <- Controls0], + send_the_LDAPMessage(S, Data, #'LDAPMessage'{messageID = Id, + protocolOp = {T,P}, + controls = Controls}). + +send_the_LDAPMessage(S, Data, LDAPMessage) -> + {ok,Bytes} = 'ELDAPv3':encode('LDAPMessage', LDAPMessage), case do_send(S, Data, Bytes) of {error,Reason} -> throw({gen_tcp_error,Reason}); Else -> Else @@ -942,6 +1020,7 @@ check_reply(Data, {ok,Msg}, Op) when {Op, Result} -> case Result#'LDAPResult'.resultCode of success -> {ok,Data}; + referral -> {{ok, {referral,Result#'LDAPResult'.referral}}, Data}; Error -> {error, Error} end; Other -> {error, Other} diff --git a/lib/eldap/test/eldap_basic_SUITE.erl b/lib/eldap/test/eldap_basic_SUITE.erl index 638a609346..8414ca6e46 100644 --- a/lib/eldap/test/eldap_basic_SUITE.erl +++ b/lib/eldap/test/eldap_basic_SUITE.erl @@ -30,6 +30,11 @@ -define(TIMEOUT, 120000). % 2 min + +%% Control to delete a referral object: +-define(manageDsaIT, {control,"2.16.840.1.113730.3.4.2",false,asn1_NOVALUE}). + + all() -> [app, appup, @@ -59,6 +64,7 @@ groups() -> {api_bound, [], [add_when_bound, add_already_exists, more_add, + add_referral, search_filter_equalityMatch, search_filter_substring_any, search_filter_initial, @@ -67,8 +73,11 @@ groups() -> search_filter_or, search_filter_and_not, search_two_hits, + search_referral, modify, + modify_referral, delete, + delete_referral, modify_dn_delete_old, modify_dn_keep_old]}, {v4_connections, [], connection_tests()}, @@ -92,11 +101,16 @@ connection_tests() -> init_per_suite(Config) -> SSL_available = init_ssl_certs_et_al(Config), - LDAP_server = find_first_server(false, [{config,eldap_server}, {config,ldap_server}, {"localhost",9876}]), + LDAP_server = find_first_server(false, [{config,eldap_server}, + {config,ldap_server}, + {"localhost",9876}, + {"aramis.otp.ericsson.se",9876}]), LDAPS_server = case SSL_available of true -> - find_first_server(true, [{config,ldaps_server}, {"localhost",9877}]); + find_first_server(true, [{config,ldaps_server}, + {"localhost",9877}, + {"aramis.otp.ericsson.se",9877}]); false -> undefined end, @@ -454,6 +468,16 @@ more_add(Config) -> [{"objectclass", ["organizationalUnit"]}, {"ou", ["Team"]}]). +%%%---------------------------------------------------------------- +add_referral(Config) -> + H = ?config(handle, Config), + BasePath = ?config(eldap_path, Config), + {ok,{referral,["ldap://nowhere.example.com"++_]}} = + eldap:add(H, "cn=Foo Bar,dc=notHere," ++ BasePath, + [{"objectclass", ["person"]}, + {"cn", ["Foo Bar"]}, + {"sn", ["Bar"]}, + {"telephoneNumber", ["555-1232", "555-5432"]}]). %%%---------------------------------------------------------------- search_filter_equalityMatch(Config) -> @@ -569,6 +593,16 @@ search_two_hits(Config) -> [ok=eldap:delete(H,DN) || DN <- ExpectedDNs]. %%%---------------------------------------------------------------- +search_referral(Config) -> + H = ?config(handle, Config), + BasePath = ?config(eldap_path, Config), + DN = "cn=Santa Claus,dc=notHere," ++ BasePath, + {ok,{referral,["ldap://nowhere.example.com"++_]}} = + eldap:search(H, #eldap_search{base = DN, + filter = eldap:present("description"), + scope=eldap:singleLevel()}). + +%%%---------------------------------------------------------------- modify(Config) -> H = ?config(handle, Config), BasePath = ?config(eldap_path, Config), @@ -602,6 +636,19 @@ modify(Config) -> restore_original_object(H, DN, OriginalAttrs). %%%---------------------------------------------------------------- +modify_referral(Config) -> + H = ?config(handle, Config), + BasePath = ?config(eldap_path, Config), + %% The object to modify + DN = "cn=Foo Bar,dc=notHere," ++ BasePath, + + %% Do a change + Mod = [eldap:mod_replace("telephoneNumber", ["555-12345"]), + eldap:mod_add("description", ["Nice guy"])], + {ok,{referral,["ldap://nowhere.example.com"++_]}} = + eldap:modify(H, DN, Mod). + +%%%---------------------------------------------------------------- delete(Config) -> H = ?config(handle, Config), BasePath = ?config(eldap_path, Config), @@ -620,6 +667,14 @@ delete(Config) -> restore_original_object(H, DN, OriginalAttrs). %%%---------------------------------------------------------------- +delete_referral(Config) -> + H = ?config(handle, Config), + BasePath = ?config(eldap_path, Config), + %% The element to play with: + DN = "cn=Jonas Jonsson,dc=notHere," ++ BasePath, + {ok,{referral,["ldap://nowhere.example.com"++_]}} = eldap:delete(H, DN). + +%%%---------------------------------------------------------------- modify_dn_delete_old(Config) -> H = ?config(handle, Config), BasePath = ?config(eldap_path, Config), @@ -817,25 +872,44 @@ delete_old_contents(H, Path) -> {filter, eldap:present("objectclass")}, {scope, eldap:wholeSubtree()}]) of - {ok, #eldap_search_result{entries=Entries}} -> + {ok, _R=#eldap_search_result{entries=Entries}} -> + case eldap:delete(H, "dc=notHere,"++Path, [?manageDsaIT]) of + ok -> ok; + {error,noSuchObject} -> ok; + Other -> ct:fail("eldap:delete notHere ret ~p",[Other]) + end, [ok = eldap:delete(H,DN) || #eldap_entry{object_name=DN} <- Entries]; _Res -> ignore end. + +-define(ok(X), ok(?MODULE,?LINE,X)). + add_new_contents(H, Path, MyHost) -> - ok(eldap:add(H,"dc=ericsson,dc=se", + ?ok(eldap:add(H,"dc=ericsson,dc=se", [{"objectclass", ["dcObject", "organization"]}, {"dc", ["ericsson"]}, {"o", ["Testing"]}])), - ok(eldap:add(H,Path, + ?ok(eldap:add(H,Path, [{"objectclass", ["dcObject", "organization"]}, {"dc", [MyHost]}, - {"o", ["Test machine"]}])). - - -ok({error,entryAlreadyExists}) -> ok; -ok(X) -> ok=X. + {"o", ["Test machine"]}])), + ?ok(eldap:add(H, "dc=notHere,"++Path, + [{"objectclass", ["referral", + "dcObject" + ]}, + {"ref", ["ldap://nowhere.example.com/notHere,"++Path]}, + {"dc", ["notHere"]} + ])). + + + +ok(_, _, {error,entryAlreadyExists}) -> ok; +ok(_, _, ok) -> ok; +ok(MODULE, LINE, X) -> + ct:pal("~p:~p add_new_contents: ret from eldap:add = ~p",[MODULE,LINE,X]), + X. diff --git a/lib/eldap/vsn.mk b/lib/eldap/vsn.mk index 105a2bcdbb..99c474d588 100644 --- a/lib/eldap/vsn.mk +++ b/lib/eldap/vsn.mk @@ -1 +1 @@ -ELDAP_VSN = 1.2 +ELDAP_VSN = 1.2.1 diff --git a/lib/erl_docgen/doc/src/erl_docgen_app.xml b/lib/erl_docgen/doc/src/erl_docgen_app.xml index c2c65a0592..58c2a24f4b 100644 --- a/lib/erl_docgen/doc/src/erl_docgen_app.xml +++ b/lib/erl_docgen/doc/src/erl_docgen_app.xml @@ -32,7 +32,7 @@ <description> <p> - The application consists of the following parts + The application consists of the following parts:</p> <taglist> <tag>XSL</tag> <item> @@ -59,7 +59,6 @@ </p> </item> </taglist> - </p> </description> </appref> diff --git a/lib/erl_docgen/doc/src/notes.xml b/lib/erl_docgen/doc/src/notes.xml index ba1ad2f5e8..f70b3c8404 100644 --- a/lib/erl_docgen/doc/src/notes.xml +++ b/lib/erl_docgen/doc/src/notes.xml @@ -31,7 +31,39 @@ </header> <p>This document describes the changes made to the <em>erl_docgen</em> application.</p> - <section><title>Erl_Docgen 0.4</title> + <section><title>Erl_Docgen 0.4.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Correctly generate anno tags for maps keys</p> + <p> + Own Id: OTP-12955</p> + </item> + </list> + </section> + +</section> + +<section><title>Erl_Docgen 0.4.1</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> Updated the xmllint target to just check the xml + files with real documentation content.<br/> Corrected + some errors and added some missing target in the DTD's. + </p> + <p> + Own Id: OTP-13026</p> + </item> + </list> + </section> + +</section> + +<section><title>Erl_Docgen 0.4</title> <section><title>Improvements and New Features</title> <list> diff --git a/lib/erl_docgen/priv/dtd/cites.dtd b/lib/erl_docgen/priv/dtd/cites.dtd index 73931af009..4558947db0 100644 --- a/lib/erl_docgen/priv/dtd/cites.dtd +++ b/lib/erl_docgen/priv/dtd/cites.dtd @@ -30,7 +30,7 @@ <!ELEMENT cite (id, shortdef, def, resp?) > <!ELEMENT id (#PCDATA) > <!ELEMENT shortdef (#PCDATA) > -<!ELEMENT def (#PCDATA|c|em)* > +<!ELEMENT def (#PCDATA|c|i|em)* > <!ELEMENT resp (#PCDATA) > <!ELEMENT c (#PCDATA) > <!ELEMENT em (#PCDATA|c)* > diff --git a/lib/erl_docgen/priv/dtd/common.dtd b/lib/erl_docgen/priv/dtd/common.dtd index ded16d308f..961bcd3fc2 100644 --- a/lib/erl_docgen/priv/dtd/common.dtd +++ b/lib/erl_docgen/priv/dtd/common.dtd @@ -24,21 +24,23 @@ <!ENTITY % block "p|pre|code|list|taglist|codeinclude| erleval" > -<!ENTITY % inline "#PCDATA|c|em|term|cite|br|path|seealso| - url|marker" > +<!ENTITY % inline "#PCDATA|c|i|em|term|cite|br|path|seealso| + url|marker|anno" > <!-- XXX --> <!ELEMENT p (%inline;)* > -<!ELEMENT pre (#PCDATA|seealso|url|input)* > -<!ELEMENT input (#PCDATA|seealso|url)* > -<!ELEMENT code (#PCDATA) > +<!ELEMENT pre (#PCDATA|seealso|url|input|anno)* > +<!ELEMENT input (#PCDATA|seealso|url|anno)* > +<!ELEMENT code (#PCDATA|anno)* > <!ATTLIST code type (erl|c|none) "none" > <!ELEMENT quote (p)* > <!ELEMENT warning (%block;|quote|br|marker)* > <!ELEMENT note (%block;|quote|br|marker)* > <!ELEMENT dont (%block;|quote|br|marker)* > <!ELEMENT do (%block;|quote|br|marker)* > -<!ELEMENT c (#PCDATA) > -<!ELEMENT em (#PCDATA|c)* > +<!ELEMENT c (#PCDATA|anno)* > +<!ELEMENT i (#PCDATA|c|anno)* > +<!ELEMENT em (#PCDATA|c|anno)* > +<!ELEMENT anno (#PCDATA) > <!-- XXX --> <!ELEMENT term (termdef?) > @@ -64,13 +66,13 @@ <!ELEMENT list (item+) > <!ATTLIST list type (ordered|bulleted) "bulleted" > -<!ELEMENT taglist (tag,item)+ > -<!ELEMENT tag (#PCDATA|c|em|seealso|url|marker)* > -<!ELEMENT item (%inline;|%block;)* > +<!ELEMENT taglist (tag,item+)+ > +<!ELEMENT tag (#PCDATA|c|i|em|br|seealso|url|marker|anno)* > +<!ELEMENT item (%inline;|%block;|warning|note|dont|do)* > <!-- References --> -<!ELEMENT seealso (#PCDATA|c|em)* > +<!ELEMENT seealso (#PCDATA|c|i|em|anno)* > <!ATTLIST seealso marker CDATA #REQUIRED > <!ELEMENT url (#PCDATA) > <!ATTLIST url href CDATA #REQUIRED > diff --git a/lib/erl_docgen/priv/dtd/common.header.dtd b/lib/erl_docgen/priv/dtd/common.header.dtd index 71a8662572..eb27dc8f97 100644 --- a/lib/erl_docgen/priv/dtd/common.header.dtd +++ b/lib/erl_docgen/priv/dtd/common.header.dtd @@ -18,8 +18,8 @@ $Id$ --> <!ELEMENT header (copyright?,legalnotice?,title,shorttitle?, - prepared,responsible?,docno,approved?, - checked?,date,rev,file?) > + prepared?,responsible?,docno?,approved?, + checked?,date?,rev?,file?) > <!-- The titlestyle attribute is only defined to make all the book.xml files diff --git a/lib/erl_docgen/priv/dtd/common.refs.dtd b/lib/erl_docgen/priv/dtd/common.refs.dtd index f57e46a624..4f87007a09 100644 --- a/lib/erl_docgen/priv/dtd/common.refs.dtd +++ b/lib/erl_docgen/priv/dtd/common.refs.dtd @@ -27,21 +27,23 @@ <!ELEMENT description (%block;|quote|br|marker|warning|note|dont|do)* > <!ELEMENT funcs (func)+ > -<!ELEMENT func (name+,type_desc*,fsummary,type?,desc?) > +<!ELEMENT func (name+,fsummary,(type|type_desc)*,desc?) > <!-- ELEMENT name is defined in each ref dtd --> -<!ELEMENT fsummary (#PCDATA|c|em)* > +<!ELEMENT fsummary (#PCDATA|c|i|em|anno)* > <!ELEMENT type (v,d?)* > <!ATTLIST type variable CDATA #IMPLIED + name CDATA #IMPLIED name_i CDATA #IMPLIED> -<!ELEMENT v (#PCDATA) > -<!ELEMENT d (#PCDATA|c|em)* > -<!ELEMENT desc (%block;|quote|br|marker|warning|note|dont|do|anno)* > +<!ELEMENT v (#PCDATA|seealso)* > +<!ELEMENT d (#PCDATA|seealso|c|i|em)* > +<!ELEMENT desc (%block;|quote|br|marker|warning|note|dont|do)* > <!ELEMENT authors (aname,email)+ > <!ELEMENT aname (#PCDATA) > <!ELEMENT email (#PCDATA) > <!ELEMENT section (marker*,title,(%block;|quote|br|marker| - warning|note|dont|do)*) > + warning|note|dont|do|section)*) > <!ELEMENT datatypes (datatype)+ > <!ELEMENT datatype (name+,desc?) > -<!ELEMENT type_desc (#PCDATA) > -<!ATTLIST type_desc variable CDATA #REQUIRED> +<!ELEMENT type_desc (#PCDATA|anno|c|seealso)* > +<!ATTLIST type_desc variable CDATA #IMPLIED + name CDATA #IMPLIED> diff --git a/lib/erl_docgen/priv/dtd/erlref.dtd b/lib/erl_docgen/priv/dtd/erlref.dtd index d62e2a5fcb..835407520a 100644 --- a/lib/erl_docgen/priv/dtd/erlref.dtd +++ b/lib/erl_docgen/priv/dtd/erlref.dtd @@ -32,4 +32,5 @@ <!ELEMENT name (#PCDATA) > <!ATTLIST name name CDATA #IMPLIED arity CDATA #IMPLIED - clause_i CDATA #IMPLIED> + clause_i CDATA #IMPLIED + n_vars CDATA #IMPLIED> diff --git a/lib/erl_docgen/priv/dtd/terms.dtd b/lib/erl_docgen/priv/dtd/terms.dtd index fd160b5c02..c2965eb61c 100644 --- a/lib/erl_docgen/priv/dtd/terms.dtd +++ b/lib/erl_docgen/priv/dtd/terms.dtd @@ -30,7 +30,7 @@ <!ELEMENT term (id, shortdef, def, resp?) > <!ELEMENT id (#PCDATA) > <!ELEMENT shortdef (#PCDATA) > -<!ELEMENT def (#PCDATA|c|em)* > +<!ELEMENT def (#PCDATA|c|i|em)* > <!ELEMENT resp (#PCDATA) > <!ELEMENT c (#PCDATA) > <!ELEMENT em (#PCDATA|c)* > diff --git a/lib/erl_docgen/priv/xsl/db_html.xsl b/lib/erl_docgen/priv/xsl/db_html.xsl index f5ddd364d3..c2325fbee9 100644 --- a/lib/erl_docgen/priv/xsl/db_html.xsl +++ b/lib/erl_docgen/priv/xsl/db_html.xsl @@ -990,12 +990,15 @@ </p> </xsl:template> - <!-- Inline elements --> <xsl:template match="b"> <strong><xsl:apply-templates/></strong> </xsl:template> + <xsl:template match="i"> + <i><xsl:apply-templates/></i> + </xsl:template> + <xsl:template match="br"> <br/> </xsl:template> diff --git a/lib/erl_docgen/priv/xsl/db_man.xsl b/lib/erl_docgen/priv/xsl/db_man.xsl index 120bf9880d..5201465e42 100644 --- a/lib/erl_docgen/priv/xsl/db_man.xsl +++ b/lib/erl_docgen/priv/xsl/db_man.xsl @@ -595,6 +595,12 @@ <xsl:text>\fR\& </xsl:text> </xsl:template> + <xsl:template match="i"> + <xsl:text>\fI</xsl:text> + <xsl:apply-templates/> + <xsl:text>\fR\& </xsl:text> + </xsl:template> + <xsl:template match="br"> <xsl:choose> <xsl:when test="ancestor::head"> diff --git a/lib/erl_docgen/priv/xsl/db_pdf.xsl b/lib/erl_docgen/priv/xsl/db_pdf.xsl index 53e202d52c..37a2d55274 100644 --- a/lib/erl_docgen/priv/xsl/db_pdf.xsl +++ b/lib/erl_docgen/priv/xsl/db_pdf.xsl @@ -1186,6 +1186,12 @@ </fo:inline> </xsl:template> + <xsl:template match="i"> + <fo:inline font-weight="italic"> + <xsl:apply-templates/> + </fo:inline> + </xsl:template> + <xsl:template match="br"> <fo:block/> </xsl:template> diff --git a/lib/erl_docgen/src/docgen_edoc_xml_cb.erl b/lib/erl_docgen/src/docgen_edoc_xml_cb.erl index 03fc161c5a..0ac7985a48 100644 --- a/lib/erl_docgen/src/docgen_edoc_xml_cb.erl +++ b/lib/erl_docgen/src/docgen_edoc_xml_cb.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2012. All Rights Reserved. +%% Copyright Ericsson AB 2001-2015. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -352,8 +352,8 @@ otp_xmlify_e(#xmlElement{name=code} = E) -> % 4) end; otp_xmlify_e(#xmlElement{name=Tag} = E) % 5a when Tag==h1; Tag==h2; Tag==h3; Tag==h4; Tag==h5 -> - Content = text_and_a_name_only(E#xmlElement.content), - [E#xmlElement{name=b, content=Content}]; + {Name, Text} = text_and_a_name_only(E#xmlElement.content), + [Name, E#xmlElement{name=b, content=Text}]; otp_xmlify_e(#xmlElement{name=Tag} = E) % 5b-c) when Tag==center; Tag==font -> @@ -1190,17 +1190,13 @@ get_text(#xmlElement{content=[#xmlText{value=Text}]}) -> get_text(#xmlElement{content=[E]}) -> get_text(E). -%% text_and_name_only(Es) -> Ts -text_and_a_name_only([#xmlElement{ - name = a, - attributes = [#xmlAttribute{name=name}]} = Name|Es]) -> - [Name|text_and_a_name_only(Es)]; -text_and_a_name_only([#xmlElement{content = Content}|Es]) -> - text_and_a_name_only(Content) ++ text_and_a_name_only(Es); -text_and_a_name_only([#xmlText{} = E |Es]) -> - [E | text_and_a_name_only(Es)]; -text_and_a_name_only([]) -> - []. +%% text_and_name_only(Es) -> {N, Ts} +text_and_a_name_only(Es) -> + [Name|_] = [Name || + #xmlElement{ + name = a, + attributes = [#xmlAttribute{name=name}]}=Name <- Es], + {Name#xmlElement{content = []}, text_only(Es)}. %% text_only(Es) -> Ts %% Takes a list of xmlElement and xmlText and return a lists of xmlText. diff --git a/lib/erl_docgen/src/docgen_otp_specs.erl b/lib/erl_docgen/src/docgen_otp_specs.erl index 37baa7c2f9..e154323f07 100644 --- a/lib/erl_docgen/src/docgen_otp_specs.erl +++ b/lib/erl_docgen/src/docgen_otp_specs.erl @@ -729,5 +729,9 @@ annos_type([E=#xmlElement{name = typevar}]) -> annos_elem(E); annos_type([#xmlElement{name = paren, content = Es}]) -> annos(get_elem(type, Es)); +annos_type([#xmlElement{name = map, content = Es}]) -> + lists:flatmap(fun(E) -> annos_type([E]) end, Es); +annos_type([#xmlElement{name = map_field, content = Es}]) -> + lists:flatmap(fun annos_elem/1, get_elem(type,Es)); annos_type(_) -> []. diff --git a/lib/erl_docgen/vsn.mk b/lib/erl_docgen/vsn.mk index 2abd3d2b7e..3188b926ff 100644 --- a/lib/erl_docgen/vsn.mk +++ b/lib/erl_docgen/vsn.mk @@ -1 +1 @@ -ERL_DOCGEN_VSN = 0.4 +ERL_DOCGEN_VSN = 0.4.2 diff --git a/lib/erl_interface/configure.in b/lib/erl_interface/configure.in index 3ac9212085..7a3b5ce378 100644 --- a/lib/erl_interface/configure.in +++ b/lib/erl_interface/configure.in @@ -251,7 +251,7 @@ case "$threads_disabled" in ;; win32_threads) EI_THREADS="true" - THR_DEFS="$THR_DEFS -D_WIN32_WINNT=0x0500 -DWINVER=0x0500" + THR_DEFS="$THR_DEFS -D_WIN32_WINNT=0x0600 -DWINVER=0x0600" ;; pthread) EI_THREADS="true" diff --git a/lib/erl_interface/doc/src/ei.xml b/lib/erl_interface/doc/src/ei.xml index 6044ac8ef7..8ef433d10f 100644 --- a/lib/erl_interface/doc/src/ei.xml +++ b/lib/erl_interface/doc/src/ei.xml @@ -264,9 +264,9 @@ typedef enum { <fsummary>Encode an atom</fsummary> <desc> <p>Encodes an atom in the binary format with character encoding - <c><seealso marker="#erlang_char_encoding">to_enc</seealso></c> (latin1 or utf8). + <seealso marker="#erlang_char_encoding"><c>to_enc</c></seealso> (latin1 or utf8). The <c>p</c> parameter is the name of the atom with character encoding - <c><seealso marker="#erlang_char_encoding">from_enc</seealso></c> (ascii, latin1 or utf8). + <seealso marker="#erlang_char_encoding"><c>from_enc</c></seealso> (ascii, latin1 or utf8). The name must either be zero-terminated or a function variant with a <c>len</c> parameter must be used. If <c>to_enc</c> is set to the bitwise-or'd combination <c>(ERLANG_LATIN1|ERLANG_UTF8)</c>, utf8 encoding is only used if the atom string @@ -569,8 +569,8 @@ ei_x_encode_string(&x, "Banana"); <p>This function decodes an atom from the binary format. The null terminated name of the atom is placed in buffer at <c>p</c> of length <c>plen</c> bytes.</p> - <p>The wanted string encoding is specified by <c><seealso marker="#erlang_char_encoding"> - want</seealso></c>. The original encoding used in the + <p>The wanted string encoding is specified by <seealso marker="#erlang_char_encoding"> + <c>want</c></seealso>. The original encoding used in the binary format (latin1 or utf8) can be obtained from <c>*was</c>. The actual encoding of the resulting string (7-bit ascii, latin1 or utf8) can be obtained from <c>*result</c>. Both <c>was</c> and <c>result</c> can be <c>NULL</c>. diff --git a/lib/erl_interface/doc/src/erl_call.xml b/lib/erl_interface/doc/src/erl_call.xml index aed1ba0ac9..e982bf89e1 100644 --- a/lib/erl_interface/doc/src/erl_call.xml +++ b/lib/erl_interface/doc/src/erl_call.xml @@ -178,7 +178,7 @@ erl_call -s -a 'erlang halt' -n madonna <code type="none"><![CDATA[ erl_call -s -a 'lists map [{math,sqrt},[1,4,9,16,25]]' -n madonna ]]></code> - <p>Evaluates a couple of expressions. <b>The input ends with EOF (Control-D)</b>.</p> + <p>Evaluates a couple of expressions. <em>The input ends with EOF (Control-D)</em>.</p> <code type="none"><![CDATA[ erl_call -s -e -n madonna statistics(runtime), @@ -189,7 +189,7 @@ Y=2, ^D {ok,{3,0}} ]]></code> - <p>Compiles a module and runs it. <b>Again, the input ends with EOF (Control-D)</b>. (In the example shown, the output has been formatted afterwards).</p> + <p>Compiles a module and runs it. <em>Again, the input ends with EOF (Control-D)</em>. (In the example shown, the output has been formatted afterwards).</p> <code type="none"><![CDATA[ erl_call -s -m -a lolita -n madonna -module(lolita). diff --git a/lib/erl_interface/doc/src/erl_eterm.xml b/lib/erl_interface/doc/src/erl_eterm.xml index 9a53a137c2..713a90a390 100644 --- a/lib/erl_interface/doc/src/erl_eterm.xml +++ b/lib/erl_interface/doc/src/erl_eterm.xml @@ -78,10 +78,12 @@ </p> <taglist> <tag><c><![CDATA[char *ERL_ATOM_PTR(t)]]></c></tag> + <item/> <tag><c><![CDATA[char *ERL_ATOM_PTR_UTF8(t)]]></c></tag> <item>A string representing atom <c><![CDATA[t]]></c>. </item> <tag><c><![CDATA[int ERL_ATOM_SIZE(t)]]></c></tag> + <item/> <tag><c><![CDATA[int ERL_ATOM_SIZE_UTF8(t)]]></c></tag> <item>The length (in bytes) of atom t.</item> <tag><c><![CDATA[void *ERL_BIN_PTR(t)]]></c></tag> @@ -95,6 +97,7 @@ <tag><c><![CDATA[double ERL_FLOAT_VALUE(t)]]></c></tag> <item>The floating point value of <c><![CDATA[t]]></c>.</item> <tag><c><![CDATA[ETERM *ERL_PID_NODE(t)]]></c></tag> + <item/> <tag><c><![CDATA[ETERM *ERL_PID_NODE_UTF8(t)]]></c></tag> <item>The Node in pid <c><![CDATA[t]]></c>.</item> <tag><c><![CDATA[int ERL_PID_NUMBER(t)]]></c></tag> @@ -108,6 +111,7 @@ <tag><c><![CDATA[int ERL_PORT_CREATION(t)]]></c></tag> <item>The creation number in port <c><![CDATA[t]]></c>.</item> <tag><c><![CDATA[ETERM *ERL_PORT_NODE(t)]]></c></tag> + <item/> <tag><c><![CDATA[ETERM *ERL_PORT_NODE_UTF8(t)]]></c></tag> <item>The node in port <c><![CDATA[t]]></c>.</item> <tag><c><![CDATA[int ERL_REF_NUMBER(t)]]></c></tag> diff --git a/lib/erl_interface/doc/src/notes.xml b/lib/erl_interface/doc/src/notes.xml index 00427ea2ee..37266d9354 100644 --- a/lib/erl_interface/doc/src/notes.xml +++ b/lib/erl_interface/doc/src/notes.xml @@ -31,6 +31,52 @@ </header> <p>This document describes the changes made to the Erl_interface application.</p> +<section><title>Erl_Interface 3.8.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix Erl_Interface build error on Debian/Hurd and + Debian/kFreeBSD. (Thanks to Sergei Golovan)</p> + <p> + Own Id: OTP-13328</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + EPMD supports both IPv4 and IPv6</p> + <p> + Also affects oldest supported windows version.</p> + <p> + Own Id: OTP-13364</p> + </item> + </list> + </section> + +</section> + +<section><title>Erl_Interface 3.8.1</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Fix the conditional selection of gethostbyname_r and + gethostbyaddr_r.</p> + <p> + Own Id: OTP-13188</p> + </item> + </list> + </section> + +</section> + <section><title>Erl_Interface 3.8</title> <section><title>Improvements and New Features</title> diff --git a/lib/erl_interface/src/connect/ei_resolve.c b/lib/erl_interface/src/connect/ei_resolve.c index 3f1be2b17d..414cb8be3e 100644 --- a/lib/erl_interface/src/connect/ei_resolve.c +++ b/lib/erl_interface/src/connect/ei_resolve.c @@ -616,7 +616,7 @@ struct hostent *ei_gethostbyaddr_r(const char *addr, #ifndef HAVE_GETHOSTBYNAME_R return my_gethostbyaddr_r(addr,length,type,hostp,buffer,buflen,h_errnop); #else -#if (defined(__GLIBC__) || (__FreeBSD_version >= 602000) || defined(__DragonFly__)) +#if (defined(__GLIBC__) || defined(__linux__) || (__FreeBSD_version >= 602000) || defined(__DragonFly__)) struct hostent *result; gethostbyaddr_r(addr, length, type, hostp, buffer, buflen, &result, @@ -643,7 +643,7 @@ struct hostent *ei_gethostbyname_r(const char *name, #ifndef HAVE_GETHOSTBYNAME_R return my_gethostbyname_r(name,hostp,buffer,buflen,h_errnop); #else -#if (defined(__GLIBC__) || (__FreeBSD_version >= 602000) || defined(__DragonFly__) || defined(__ANDROID__)) +#if (defined(__GLIBC__) || defined(__linux__) || (__FreeBSD_version >= 602000) || defined(__DragonFly__) || defined(__ANDROID__)) struct hostent *result; gethostbyname_r(name, hostp, buffer, buflen, &result, h_errnop); diff --git a/lib/erl_interface/vsn.mk b/lib/erl_interface/vsn.mk index 94cfd30cec..56dbdbac9f 100644 --- a/lib/erl_interface/vsn.mk +++ b/lib/erl_interface/vsn.mk @@ -1,2 +1,2 @@ -EI_VSN = 3.8 +EI_VSN = 3.8.2 ERL_INTERFACE_VSN = $(EI_VSN) diff --git a/lib/eunit/doc/overview.edoc b/lib/eunit/doc/overview.edoc index df716cdeea..12ea02f442 100644 --- a/lib/eunit/doc/overview.edoc +++ b/lib/eunit/doc/overview.edoc @@ -885,7 +885,7 @@ the timeout is exceeded, the unfinished tests will be forced to terminate. Note that if a timeout is set around a fixture, it includes the time for setup and cleanup, and if the timeout is triggered, the entire fixture is abruptly terminated (without running the -cleanup).</dd> +cleanup). The default timeout for an individual test is 5 seconds.</dd> <dt>`{inorder, Tests}'</dt> <dd>Runs the specified tests in strict order. Also see `{inparallel, Tests}'. By default, tests are neither marked as `inorder' or @@ -907,7 +907,6 @@ the test set is finished, regardless of the outcome (success, failures, timeouts, etc.). To make the descriptions simpler, we first list some definitions: -<center> <table border="0" cellspacing="4"> <tr> <td>`Setup'</td><td>`() -> (R::any())'</td> @@ -928,7 +927,6 @@ To make the descriptions simpler, we first list some definitions: <td>`Where'</td><td>`local | spawn | {spawn, Node::atom()}'</td> </tr> </table> -</center> (these are explained in more detail further below.) The following representations specify fixture handling for test sets: diff --git a/lib/eunit/doc/src/notes.xml b/lib/eunit/doc/src/notes.xml index d4ffb30967..398729217b 100644 --- a/lib/eunit/doc/src/notes.xml +++ b/lib/eunit/doc/src/notes.xml @@ -33,6 +33,50 @@ </header> <p>This document describes the changes made to the EUnit application.</p> +<section><title>Eunit 2.2.13</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> Suppress Dialyzer warnings. </p> + <p> + Own Id: OTP-12862</p> + </item> + </list> + </section> + +</section> + +<section><title>Eunit 2.2.12</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Small documentation fixes</p> + <p> + Own Id: OTP-13017</p> + </item> + </list> + </section> + +</section> + +<section><title>Eunit 2.2.11</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Improve success message when 2 tests have passed</p> + <p> + Own Id: OTP-12952</p> + </item> + </list> + </section> + +</section> + <section><title>Eunit 2.2.10</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/eunit/include/eunit.hrl b/lib/eunit/include/eunit.hrl index 88e9d6c19b..8f678b0290 100644 --- a/lib/eunit/include/eunit.hrl +++ b/lib/eunit/include/eunit.hrl @@ -135,7 +135,6 @@ -define(_assertThrow(Term, Expr), ?_assertException(throw, Term, Expr)). -define(_assertNotException(Class, Term, Expr), ?_test(?assertNotException(Class, Term, Expr))). --define(_assertReceive(Guard, Expr), ?_test(?assertReceive(Guard, Expr))). %% Macros for running operating system commands. (Note that these %% require EUnit to be present at runtime, or at least eunit_lib.) diff --git a/lib/eunit/src/eunit_data.erl b/lib/eunit/src/eunit_data.erl index 8b53a3681d..cc002cb449 100644 --- a/lib/eunit/src/eunit_data.erl +++ b/lib/eunit/src/eunit_data.erl @@ -761,6 +761,7 @@ lazy_test_() -> lazy_gen(7), ?_assertMatch(7, get(count))]}. +-dialyzer({no_improper_lists, lazy_gen/1}). lazy_gen(N) -> {generator, fun () -> diff --git a/lib/eunit/src/eunit_lib.erl b/lib/eunit/src/eunit_lib.erl index d8f98cffa5..4dbe023257 100644 --- a/lib/eunit/src/eunit_lib.erl +++ b/lib/eunit/src/eunit_lib.erl @@ -192,6 +192,7 @@ error_msg(Title, Fmt, Args) -> io_lib:fwrite("*** ~ts ***\n~ts\n\n", [Title, Msg]). -ifdef(TEST). +-dialyzer({no_match, format_exception_test_/0}). format_exception_test_() -> [?_assertMatch( "\nymmud:rorre"++_, @@ -273,6 +274,7 @@ dlist_next([], Xs) -> -ifdef(TEST). +-dialyzer({no_match, dlist_test_/0}). dlist_test_() -> {"deep list traversal", [{"non-list term -> singleton list", @@ -338,6 +340,7 @@ is_nonempty_string([]) -> false; is_nonempty_string(Cs) -> is_string(Cs). -ifdef(TEST). +-dialyzer({no_match, is_string_test_/0}). is_string_test_() -> {"is_string", [{"no non-lists", ?_assert(not is_string($A))}, @@ -399,6 +402,7 @@ uniq([X | Xs]) -> [X | uniq(Xs)]; uniq([]) -> []. -ifdef(TEST). +-dialyzer({[no_match, no_fail_call, no_improper_lists], uniq_test_/0}). uniq_test_() -> {"uniq", [?_assertError(function_clause, uniq(ok)), @@ -459,6 +463,7 @@ normalize([]) -> -ifdef(TEST). +-dialyzer({no_match, cmd_test_/0}). cmd_test_() -> ([?_test({0, "hello\n"} = ?_cmd_("echo hello"))] ++ case os:type() of @@ -576,6 +581,7 @@ trie_match([], _T) -> -ifdef(TEST). +-dialyzer({no_match, trie_test_/0}). trie_test_() -> [{"basic representation", [?_assert(trie_new() =:= gb_trees:empty()), diff --git a/lib/eunit/src/eunit_listener.erl b/lib/eunit/src/eunit_listener.erl index ecaac424a2..c34eacb1d6 100644 --- a/lib/eunit/src/eunit_listener.erl +++ b/lib/eunit/src/eunit_listener.erl @@ -27,14 +27,11 @@ -export([start/1, start/2]). --export([behaviour_info/1]). - - -behaviour_info(callbacks) -> - [{init,1},{handle_begin,3},{handle_end,3},{handle_cancel,3}, - {terminate,2}]; -behaviour_info(_Other) -> - undefined. +-callback init(_) -> _. +-callback handle_begin(_, _, _) -> _. +-callback handle_end(_, _, _) -> _. +-callback handle_cancel(_, _, _) -> _. +-callback terminate(_, _) -> _. -record(state, {callback, % callback module @@ -50,18 +47,22 @@ start(Callback) -> start(Callback, Options) -> St = #state{callback = Callback}, - spawn_opt(fun () -> init(St, Options) end, + spawn_opt(init_fun(St, Options), proplists:get_all_values(spawn, Options)). -init(St0, Options) -> - St1 = call(init, [Options], St0), - St2 = expect([], undefined, St1), - Data = [{pass, St2#state.pass}, - {fail, St2#state.fail}, - {skip, St2#state.skip}, - {cancel, St2#state.cancel}], - call(terminate, [{ok, Data}, St2#state.state], St2), - exit(normal). +-spec init_fun(_, _) -> fun(() -> no_return()). + +init_fun(St0, Options) -> + fun () -> + St1 = call(init, [Options], St0), + St2 = expect([], undefined, St1), + Data = [{pass, St2#state.pass}, + {fail, St2#state.fail}, + {skip, St2#state.skip}, + {cancel, St2#state.cancel}], + call(terminate, [{ok, Data}, St2#state.state], St2), + exit(normal) + end. expect(Id, ParentId, St) -> case wait_for(Id, 'begin', ParentId) of diff --git a/lib/eunit/src/eunit_proc.erl b/lib/eunit/src/eunit_proc.erl index 98ae31d54b..8bdf94c877 100644 --- a/lib/eunit/src/eunit_proc.erl +++ b/lib/eunit/src/eunit_proc.erl @@ -268,6 +268,8 @@ insulator_wait(Child, Parent, Buf, St) -> kill_task(Child, St) end. +-spec kill_task(_, _) -> no_return(). + kill_task(Child, St) -> exit(Child, kill), terminate_insulator(St). diff --git a/lib/eunit/src/eunit_serial.erl b/lib/eunit/src/eunit_serial.erl index 1a0179a5df..da76064a53 100644 --- a/lib/eunit/src/eunit_serial.erl +++ b/lib/eunit/src/eunit_serial.erl @@ -61,14 +61,16 @@ messages = dict:new() :: dict:dict()}). start(Pids) -> - spawn(fun () -> serializer(Pids) end). - -serializer(Pids) -> - St = #state{listeners = sets:from_list(Pids), - cancelled = eunit_lib:trie_new(), - messages = dict:new()}, - expect([], undefined, 0, St), - exit(normal). + spawn(serializer_fun(Pids)). + +serializer_fun(Pids) -> + fun () -> + St = #state{listeners = sets:from_list(Pids), + cancelled = eunit_lib:trie_new(), + messages = dict:new()}, + expect([], undefined, 0, St), + exit(normal) + end. %% collect beginning and end of an expected item; return {Done, NewSt} %% where Done is true if there are no more items of this group diff --git a/lib/eunit/src/eunit_test.erl b/lib/eunit/src/eunit_test.erl index 9cf40a738d..62d30b1930 100644 --- a/lib/eunit/src/eunit_test.erl +++ b/lib/eunit/src/eunit_test.erl @@ -40,6 +40,7 @@ get_stacktrace() -> get_stacktrace(Ts) -> eunit_lib:uniq(prune_trace(erlang:get_stacktrace(), Ts)). +-dialyzer({no_match, prune_trace/2}). prune_trace([{eunit_data, _, _} | Rest], Tail) -> prune_trace(Rest, Tail); prune_trace([{eunit_data, _, _, _} | Rest], Tail) -> @@ -75,6 +76,7 @@ run_testfun(F) -> -ifdef(TEST). +-dialyzer({[no_match, no_fail_call, no_return], macro_test_/0}). macro_test_() -> {"macro definitions", [{?LINE, fun () -> @@ -301,6 +303,7 @@ wrapper_test_() -> ]}. %% this must be exported (done automatically by the autoexport transform) +-dialyzer({no_missing_calls, wrapper_test_exported_/0}). wrapper_test_exported_() -> {ok, ?MODULE:nonexisting_function()}. -endif. diff --git a/lib/eunit/src/eunit_tests.erl b/lib/eunit/src/eunit_tests.erl index 47ea0aaf46..5dee1cb49e 100644 --- a/lib/eunit/src/eunit_tests.erl +++ b/lib/eunit/src/eunit_tests.erl @@ -23,6 +23,8 @@ -include("eunit.hrl"). +-dialyzer(no_match). + -ifdef(TEST). id(X) -> X. % for suppressing compiler warnings -endif. diff --git a/lib/eunit/src/eunit_tty.erl b/lib/eunit/src/eunit_tty.erl index 699d2adaca..f604ca5ba3 100644 --- a/lib/eunit/src/eunit_tty.erl +++ b/lib/eunit/src/eunit_tty.erl @@ -67,6 +67,8 @@ terminate({ok, Data}, St) -> end, if Pass =:= 1 -> fwrite(" Test passed.\n"); + Pass =:= 2 -> + fwrite(" 2 tests passed.\n"); true -> fwrite(" All ~w tests passed.\n", [Pass]) end diff --git a/lib/eunit/vsn.mk b/lib/eunit/vsn.mk index 8b489bdc04..dcb7fad699 100644 --- a/lib/eunit/vsn.mk +++ b/lib/eunit/vsn.mk @@ -1 +1 @@ -EUNIT_VSN = 2.2.10 +EUNIT_VSN = 2.2.13 diff --git a/lib/hipe/arm/hipe_arm_assemble.erl b/lib/hipe/arm/hipe_arm_assemble.erl index 7859e2d4a8..5f98c6593e 100644 --- a/lib/hipe/arm/hipe_arm_assemble.erl +++ b/lib/hipe/arm/hipe_arm_assemble.erl @@ -48,7 +48,7 @@ assemble(CompiledCode, Closures, Exports, Options) -> DataRelocs = hipe_pack_constants:mk_data_relocs(RefsFromConsts, LabelMap), SSE = hipe_pack_constants:slim_sorted_exportmap(ExportMap,Closures,Exports), SlimRefs = hipe_pack_constants:slim_refs(AccRefs), - Bin = term_to_binary([{?VERSION_STRING(),?HIPE_SYSTEM_CRC}, + Bin = term_to_binary([{?VERSION_STRING(),?HIPE_ERTS_CHECKSUM}, ConstAlign, ConstSize, SC, DataRelocs, % nee LM, LabelMap diff --git a/lib/hipe/cerl/cerl_prettypr.erl b/lib/hipe/cerl/cerl_prettypr.erl index 7e8b7f60bd..1a6e6999fe 100644 --- a/lib/hipe/cerl/cerl_prettypr.erl +++ b/lib/hipe/cerl/cerl_prettypr.erl @@ -64,8 +64,8 @@ seq_arg/1, seq_body/1, string_lit/1, try_arg/1, try_body/1, try_vars/1, try_evars/1, try_handler/1, tuple_es/1, type/1, values_es/1, var_name/1, - c_map/1, map_arg/1, map_es/1, is_c_map_empty/1, - c_map_pair/2, map_pair_key/1, map_pair_val/1, map_pair_op/1 + map_arg/1, map_es/1, is_c_map_empty/1, + map_pair_key/1, map_pair_val/1, map_pair_op/1 ]). -define(PAPER, 76). @@ -499,12 +499,8 @@ lay_literal(Node, Ctxt) -> lay_cons(Node, Ctxt); V when is_tuple(V) -> lay_tuple(Node, Ctxt); - M when is_map(M), map_size(M) =:= 0 -> - text("~{}~"); M when is_map(M) -> - lay_map(c_map([c_map_pair(abstract(K),abstract(V)) - || {K,V} <- maps:to_list(M)]), - Ctxt) + lay_map(Node, Ctxt) end. lay_var(Node, Ctxt) -> @@ -627,12 +623,10 @@ lay_map_pair(Node, Ctxt) -> K = map_pair_key(Node), V = map_pair_val(Node), OpTxt = case concrete(map_pair_op(Node)) of - assoc -> "::<"; - exact -> "~<" + assoc -> "=>"; + exact -> ":=" end, - beside(floating(text(OpTxt)), - beside(lay(K,Ctxt),beside(floating(text(",")), beside(lay(V,Ctxt), - floating(text(">")))))). + beside(lay(K,Ctxt),beside(floating(text(OpTxt)),lay(V,Ctxt))). lay_let(Node, Ctxt) -> V = lay_value_list(let_vars(Node), Ctxt), diff --git a/lib/hipe/cerl/cerl_to_icode.erl b/lib/hipe/cerl/cerl_to_icode.erl index 97b95f2e7c..ab131c2d01 100644 --- a/lib/hipe/cerl/cerl_to_icode.erl +++ b/lib/hipe/cerl/cerl_to_icode.erl @@ -794,9 +794,9 @@ bitstr_gen_op([V], #ctxt{fail=FL, class=guard}, SizeInfo, ConstInfo, Type, Flags, Base, Offset) -> SL = new_label(), case SizeInfo of - {all,_NewUnit, NewAlign, S1} -> + {all, NewUnit, NewAlign, S1} -> Type = binary, - Name = {bs_put_binary_all, Flags}, + Name = {bs_put_binary_all, NewUnit, Flags}, Primop = {hipe_bs_primop, Name}, {add_code([icode_guardop([Offset], Primop, [V, Base, Offset], SL, FL), @@ -819,9 +819,9 @@ bitstr_gen_op([V], #ctxt{fail=FL, class=guard}, SizeInfo, ConstInfo, bitstr_gen_op([V], _Ctxt, SizeInfo, ConstInfo, Type, Flags, Base, Offset) -> case SizeInfo of - {all, _NewUnit, NewAlign, S} -> + {all, NewUnit, NewAlign, S} -> Type = binary, - Name = {bs_put_binary_all, Flags}, + Name = {bs_put_binary_all, NewUnit, Flags}, Primop = {hipe_bs_primop, Name}, {add_code([icode_call_primop([Offset], Primop, [V, Base, Offset])], S), diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl index 41a6c731c9..9f23b6a9b3 100644 --- a/lib/hipe/cerl/erl_bif_types.erl +++ b/lib/hipe/cerl/erl_bif_types.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2014. All Rights Reserved. +%% Copyright Ericsson AB 2003-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -93,7 +93,7 @@ t_list/0, t_list/1, t_list_elements/2, - t_list_termination/1, + t_list_termination/2, t_mfa/0, t_module/0, t_nil/0, @@ -514,14 +514,15 @@ type(erlang, 'bsl', 2, Xs, Opaques) -> type(erlang, 'bnot', 1, Xs, Opaques) -> strict(erlang, 'bnot', 1, Xs, fun ([X1]) -> - case arith('bnot', X1, Opaques) of + case arith_bnot(X1, Opaques) of error -> t_integer(); {ok, T} -> T end end, Opaques); %% Guard bif, needs to be here. type(erlang, abs, 1, Xs, Opaques) -> - strict(erlang, abs, 1, Xs, fun ([X]) -> X end, Opaques); + strict(erlang, abs, 1, Xs, + fun ([X1]) -> arith_abs(X1, Opaques) end, Opaques); %% This returns (-X)-1, so it often gives a negative result. %% strict(erlang, 'bnot', 1, Xs, fun (_) -> t_integer() end, Opaques); type(erlang, append, 2, Xs, _Opaques) -> type(erlang, '++', 2, Xs); % alias @@ -767,6 +768,18 @@ type(erlang, length, 1, Xs, Opaques) -> %% Guard bif, needs to be here. type(erlang, map_size, 1, Xs, Opaques) -> strict(erlang, map_size, 1, Xs, fun (_) -> t_non_neg_integer() end, Opaques); +type(erlang, make_fun, 3, Xs, Opaques) -> + strict(erlang, make_fun, 3, Xs, + fun ([_, _, Arity]) -> + case t_number_vals(Arity, Opaques) of + [N] -> + case is_integer(N) andalso 0 =< N andalso N =< 255 of + true -> t_fun(N, t_any()); + false -> t_none() + end; + _Other -> t_fun() + end + end, Opaques); type(erlang, make_tuple, 2, Xs, Opaques) -> strict(erlang, make_tuple, 2, Xs, fun ([Int, _]) -> @@ -1336,8 +1349,8 @@ type(lists, foldr, 3, Xs, _Opaques) -> type(lists, foldl, 3, Xs); % same type(lists, keydelete, 3, Xs, Opaques) -> strict(lists, keydelete, 3, Xs, fun ([_, _, L]) -> - Term = t_list_termination(L), - t_sup(Term, erl_types:lift_list_to_pos_empty(L)) + Term = t_list_termination(L, Opaques), + t_sup(Term, erl_types:lift_list_to_pos_empty(L, Opaques)) end, Opaques); type(lists, keyfind, 3, Xs, Opaques) -> strict(lists, keyfind, 3, Xs, @@ -1927,7 +1940,7 @@ negwidth(X, N) -> false -> negwidth(X, N+1) end. -arith('bnot', X1, Opaques) -> +arith_bnot(X1, Opaques) -> case t_is_integer(X1, Opaques) of false -> error; true -> @@ -1937,6 +1950,28 @@ arith('bnot', X1, Opaques) -> infinity_add(infinity_inv(Min1), -1))} end. +arith_abs(X1, Opaques) -> + case t_is_integer(X1, Opaques) of + false -> + case t_is_float(X1, Opaques) of + true -> t_float(); + false -> t_number() + end; + true -> + Min1 = number_min(X1, Opaques), + Max1 = number_max(X1, Opaques), + {NewMin, NewMax} = + case infinity_geq(Min1, 0) of + true -> {Min1, Max1}; + false -> + case infinity_geq(Max1, 0) of + true -> {0, infinity_inv(Min1)}; + false -> {infinity_inv(Max1), infinity_inv(Min1)} + end + end, + t_from_range(NewMin, NewMax) + end. + arith_mult(Min1, Max1, Min2, Max2) -> Tmp_list = [infinity_mult(Min1, Min2), infinity_mult(Min1, Max2), infinity_mult(Max1, Min2), infinity_mult(Max1, Max2)], @@ -2165,7 +2200,7 @@ type_ranks(Type, I, Min, Max, [TypeClass|Rest], Opaques) -> type_order() -> [t_number(), t_atom(), t_reference(), t_fun(), t_port(), t_pid(), t_tuple(), - t_list(), t_binary()]. + t_map(), t_list(), t_bitstr()]. key_comparisons_fail(X0, KeyPos, TupleList, Opaques) -> X = case t_is_number(t_inf(X0, t_number(), Opaques), Opaques) of @@ -2265,7 +2300,7 @@ arg_types(erlang, bit_size, 1) -> [t_bitstr()]; %% Guard bif, needs to be here. arg_types(erlang, byte_size, 1) -> - [t_binary()]; + [t_bitstr()]; arg_types(erlang, disconnect_node, 1) -> [t_node()]; arg_types(erlang, halt, 0) -> @@ -2338,6 +2373,8 @@ arg_types(erlang, length, 1) -> %% Guard bif, needs to be here. arg_types(erlang, map_size, 1) -> [t_map()]; +arg_types(erlang, make_fun, 3) -> + [t_atom(), t_atom(), t_arity()]; arg_types(erlang, make_tuple, 2) -> [t_non_neg_fixnum(), t_any()]; % the value 0 is OK as first argument arg_types(erlang, make_tuple, 3) -> diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl index 25cf1a7ae1..7a2abc226f 100644 --- a/lib/hipe/cerl/erl_types.erl +++ b/lib/hipe/cerl/erl_types.erl @@ -82,7 +82,7 @@ t_form_to_string/1, t_from_form/4, t_from_form/5, - t_from_form_without_remote/2, + t_from_form_without_remote/3, t_check_record_fields/4, t_check_record_fields/5, t_from_range/2, @@ -150,7 +150,7 @@ t_list/0, t_list/1, t_list_elements/1, t_list_elements/2, - t_list_termination/1, + t_list_termination/1, t_list_termination/2, t_map/0, t_map/1, t_matchstate/0, @@ -209,7 +209,7 @@ record_field_diffs_to_string/2, subst_all_vars_to_any/1, subst_all_remote/2, - lift_list_to_pos_empty/1, + lift_list_to_pos_empty/1, lift_list_to_pos_empty/2, is_opaque_type/2, is_erl_type/1, atom_to_string/1 @@ -1510,6 +1510,11 @@ t_list_elements(Type, Opaques) -> list_elements(?list(Contents, _, _)) -> Contents; list_elements(?nil) -> ?none. +-spec t_list_termination(erl_type(), opaques()) -> erl_type(). + +t_list_termination(Type, Opaques) -> + do_opaque(Type, Opaques, fun t_list_termination/1). + -spec t_list_termination(erl_type()) -> erl_type(). t_list_termination(?nil) -> ?nil; @@ -1585,6 +1590,11 @@ is_maybe_improper_list(_) -> false. %% %% false = t_is_subtype(t_nil(), Termination), %% ?list(Content, Termination, ?any). +-spec lift_list_to_pos_empty(erl_type(), opaques()) -> erl_type(). + +lift_list_to_pos_empty(Type, Opaques) -> + do_opaque(Type, Opaques, fun lift_list_to_pos_empty/1). + -spec lift_list_to_pos_empty(erl_type()) -> erl_type(). lift_list_to_pos_empty(?nil) -> ?nil; @@ -2701,8 +2711,94 @@ is_compat_args([A1|Args1], [A2|Args2]) -> is_compat_args([], []) -> true; is_compat_args(_, _) -> false. -is_compat_arg(A, A) -> true; -is_compat_arg(A1, A2) -> t_is_any(A1) orelse t_is_any(A2). +is_compat_arg(A1, A2) -> + is_specialization(A1, A2) orelse is_specialization(A2, A1). + +-spec is_specialization(erl_type(), erl_type()) -> boolean(). + +%% Returns true if the first argument is a specialization of the +%% second argument in the sense that every type is a specialization of +%% any(). For example, {_,_} is a specialization of any(), but not of +%% tuple(). Does not handle variables, but any() and unions (sort of). + +is_specialization(T, T) -> true; +is_specialization(_, ?any) -> true; +is_specialization(?any, _) -> false; +is_specialization(?function(Domain1, Range1), ?function(Domain2, Range2)) -> + (is_specialization(Domain1, Domain2) andalso + is_specialization(Range1, Range2)); +is_specialization(?list(Contents1, Termination1, Size1), + ?list(Contents2, Termination2, Size2)) -> + (Size1 =:= Size2 andalso + is_specialization(Contents1, Contents2) andalso + is_specialization(Termination1, Termination2)); +is_specialization(?product(Types1), ?product(Types2)) -> + specialization_list(Types1, Types2); +is_specialization(?tuple(?any, ?any, ?any), ?tuple(_, _, _)) -> false; +is_specialization(?tuple(_, _, _), ?tuple(?any, ?any, ?any)) -> false; +is_specialization(?tuple(Elements1, Arity, _), + ?tuple(Elements2, Arity, _)) when Arity =/= ?any -> + specialization_list(Elements1, Elements2); +is_specialization(?tuple_set([{Arity, List}]), + ?tuple(Elements2, Arity, _)) when Arity =/= ?any -> + specialization_list(sup_tuple_elements(List), Elements2); +is_specialization(?tuple(Elements1, Arity, _), + ?tuple_set([{Arity, List}])) when Arity =/= ?any -> + specialization_list(Elements1, sup_tuple_elements(List)); +is_specialization(?tuple_set(List1), ?tuple_set(List2)) -> + try + specialization_list_list([sup_tuple_elements(T) || {_Arity, T} <- List1], + [sup_tuple_elements(T) || {_Arity, T} <- List2]) + catch _:_ -> false + end; +is_specialization(?union(List1)=T1, ?union(List2)=T2) -> + case specialization_union2(T1, T2) of + {yes, Type1, Type2} -> is_specialization(Type1, Type2); + no -> specialization_list(List1, List2) + end; +is_specialization(?union(List), T2) -> + case unify_union(List) of + {yes, Type} -> is_specialization(Type, T2); + no -> false + end; +is_specialization(T1, ?union(List)) -> + case unify_union(List) of + {yes, Type} -> is_specialization(T1, Type); + no -> false + end; +is_specialization(?opaque(_) = T1, T2) -> + is_specialization(t_opaque_structure(T1), T2); +is_specialization(T1, ?opaque(_) = T2) -> + is_specialization(T1, t_opaque_structure(T2)); +is_specialization(?var(_), _) -> exit(error); +is_specialization(_, ?var(_)) -> exit(error); +is_specialization(?none, _) -> false; +is_specialization(_, ?none) -> false; +is_specialization(?unit, _) -> false; +is_specialization(_, ?unit) -> false; +is_specialization(#c{}, #c{}) -> false. + +specialization_list_list(LL1, LL2) -> + length(LL1) =:= length(LL2) andalso specialization_list_list1(LL1, LL2). + +specialization_list_list1([], []) -> true; +specialization_list_list1([L1|LL1], [L2|LL2]) -> + specialization_list(L1, L2) andalso specialization_list_list1(LL1, LL2). + +specialization_list(L1, L2) -> + length(L1) =:= length(L2) andalso specialization_list1(L1, L2). + +specialization_list1([], []) -> true; +specialization_list1([T1|L1], [T2|L2]) -> + is_specialization(T1, T2) andalso specialization_list1(L1, L2). + +specialization_union2(?union(List1)=T1, ?union(List2)=T2) -> + case {unify_union(List1), unify_union(List2)} of + {{yes, Type1}, {yes, Type2}} -> {yes, Type1, Type2}; + {{yes, Type1}, no} -> {yes, Type1, T2}; + {no, {yes, Type2}} -> {yes, T1, Type2}; + {no, no} -> no + end. -spec t_inf_lists([erl_type()], [erl_type()]) -> [erl_type()]. @@ -3961,27 +4057,32 @@ mod_name(Mod, Name) -> -type type_names() :: [type_key() | record_key()]. +-type mta() :: {module(), atom(), arity()}. +-type mra() :: {module(), atom(), arity()}. +-type site() :: {'type', mta()} | {'spec', mfa()} | {'record', mra()}. + -spec t_from_form(parse_form(), sets:set(mfa()), - module(), mod_records()) -> erl_type(). + site(), mod_records()) -> erl_type(). -t_from_form(Form, ExpTypes, Module, RecDict) -> - t_from_form(Form, ExpTypes, Module, RecDict, dict:new()). +t_from_form(Form, ExpTypes, Site, RecDict) -> + t_from_form(Form, ExpTypes, Site, RecDict, dict:new()). -spec t_from_form(parse_form(), sets:set(mfa()), - module(), mod_records(), var_table()) -> erl_type(). + site(), mod_records(), var_table()) -> erl_type(). -t_from_form(Form, ExpTypes, Module, RecDict, VarDict) -> - {T, _} = t_from_form1(Form, [], ExpTypes, Module, RecDict, VarDict), +t_from_form(Form, ExpTypes, Site, RecDict, VarDict) -> + {T, _} = t_from_form1(Form, ExpTypes, Site, RecDict, VarDict), T. %% Replace external types with with none(). --spec t_from_form_without_remote(parse_form(), type_table()) -> erl_type(). +-spec t_from_form_without_remote(parse_form(), site(), type_table()) -> + erl_type(). -t_from_form_without_remote(Form, TypeTable) -> - Module = mod, +t_from_form_without_remote(Form, Site, TypeTable) -> + Module = site_module(Site), RecDict = dict:from_list([{Module, TypeTable}]), ExpTypes = replace_by_none, - {T, _} = t_from_form1(Form, [], ExpTypes, Module, RecDict, dict:new()), + {T, _} = t_from_form1(Form, ExpTypes, Site, RecDict, dict:new()), T. %% REC_TYPE_LIMIT is used for limiting the depth of recursive types. @@ -3995,23 +4096,32 @@ t_from_form_without_remote(Form, TypeTable) -> -type expand_depth() :: integer(). -t_from_form1(Form, TypeNames, ET, M, MR, V) -> - t_from_form1(Form, TypeNames, ET, M, MR, V, ?EXPAND_DEPTH). +-spec t_from_form1(parse_form(), sets:set(mfa()) | 'replace_by_none', + site(), mod_records(), var_table()) -> + {erl_type(), expand_limit()}. + +t_from_form1(Form, ET, Site, MR, V) -> + TypeNames = initial_typenames(Site), + t_from_form1(Form, TypeNames, ET, Site, MR, V, ?EXPAND_DEPTH). -t_from_form1(Form, TypeNames, ET, M, MR, V, D) -> +initial_typenames({type, _MTA}=Site) -> [Site]; +initial_typenames({spec, _MFA}) -> []; +initial_typenames({record, _MRA}) -> []. + +t_from_form1(Form, TypeNames, ET, Site, MR, V, D) -> L = ?EXPAND_LIMIT, - {T, L1} = t_from_form(Form, TypeNames, ET, M, MR, V, D, L), + {T, L1} = t_from_form(Form, TypeNames, ET, Site, MR, V, D, L), if L1 =< 0, D > 1 -> D1 = D div 2, - t_from_form1(Form, TypeNames, ET, M, MR, V, D1); + t_from_form1(Form, TypeNames, ET, Site, MR, V, D1); true -> {T, L1} end. -spec t_from_form(parse_form(), type_names(), sets:set(mfa()) | 'replace_by_none', - module(), mod_records(), var_table(), + site(), mod_records(), var_table(), expand_depth(), expand_limit()) -> {erl_type(), expand_limit()}. @@ -4021,193 +4131,194 @@ t_from_form1(Form, TypeNames, ET, M, MR, V, D) -> %% self() ! {self(), ext_types, {RemMod, Name, ArgsLen}} %% is called, unless 'replace_by_none' is given. %% -%% It is assumed that M can be found in MR. +%% It is assumed that site_module(S) can be found in MR. -t_from_form(_, _TypeNames, _ET, _M, _MR, _V, D, L) when D =< 0 ; L =< 0 -> +t_from_form(_, _TypeNames, _ET, _S, _MR, _V, D, L) when D =< 0 ; L =< 0 -> {t_any(), L}; -t_from_form({var, _L, '_'}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({var, _L, '_'}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_any(), L}; -t_from_form({var, _L, Name}, _TypeNames, _ET, _M, _MR, V, _D, L) -> +t_from_form({var, _L, Name}, _TypeNames, _ET, _S, _MR, V, _D, L) -> case dict:find(Name, V) of error -> {t_var(Name), L}; {ok, Val} -> {Val, L} end; -t_from_form({ann_type, _L, [_Var, Type]}, TypeNames, ET, M, MR, V, D, L) -> - t_from_form(Type, TypeNames, ET, M, MR, V, D, L); -t_from_form({paren_type, _L, [Type]}, TypeNames, ET, M, MR, V, D, L) -> - t_from_form(Type, TypeNames, ET, M, MR, V, D, L); +t_from_form({ann_type, _L, [_Var, Type]}, TypeNames, ET, S, MR, V, D, L) -> + t_from_form(Type, TypeNames, ET, S, MR, V, D, L); +t_from_form({paren_type, _L, [Type]}, TypeNames, ET, S, MR, V, D, L) -> + t_from_form(Type, TypeNames, ET, S, MR, V, D, L); t_from_form({remote_type, _L, [{atom, _, Module}, {atom, _, Type}, Args]}, - TypeNames, ET, M, MR, V, D, L) -> - remote_from_form(Module, Type, Args, TypeNames, ET, M, MR, V, D, L); -t_from_form({atom, _L, Atom}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> + TypeNames, ET, S, MR, V, D, L) -> + remote_from_form(Module, Type, Args, TypeNames, ET, S, MR, V, D, L); +t_from_form({atom, _L, Atom}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_atom(Atom), L}; -t_from_form({integer, _L, Int}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({integer, _L, Int}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_integer(Int), L}; -t_from_form({op, _L, _Op, _Arg} = Op, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({op, _L, _Op, _Arg} = Op, _TypeNames, _ET, _S, _MR, _V, _D, L) -> case erl_eval:partial_eval(Op) of {integer, _, Val} -> {t_integer(Val), L}; _ -> throw({error, io_lib:format("Unable to evaluate type ~w\n", [Op])}) end; t_from_form({op, _L, _Op, _Arg1, _Arg2} = Op, _TypeNames, - _ET, _M, _MR, _V, _D, L) -> + _ET, _S, _MR, _V, _D, L) -> case erl_eval:partial_eval(Op) of {integer, _, Val} -> {t_integer(Val), L}; _ -> throw({error, io_lib:format("Unable to evaluate type ~w\n", [Op])}) end; -t_from_form({type, _L, any, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, any, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_any(), L}; -t_from_form({type, _L, arity, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, arity, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_arity(), L}; -t_from_form({type, _L, atom, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, atom, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_atom(), L}; -t_from_form({type, _L, binary, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, binary, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_binary(), L}; t_from_form({type, _L, binary, [Base, Unit]} = Type, - _TypeNames, _ET, _M, _MR, _V, _D, L) -> + _TypeNames, _ET, _S, _MR, _V, _D, L) -> case {erl_eval:partial_eval(Base), erl_eval:partial_eval(Unit)} of {{integer, _, B}, {integer, _, U}} when B >= 0, U >= 0 -> {t_bitstr(U, B), L}; _ -> throw({error, io_lib:format("Unable to evaluate type ~w\n", [Type])}) end; -t_from_form({type, _L, bitstring, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, bitstring, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_bitstr(), L}; -t_from_form({type, _L, bool, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, bool, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_boolean(), L}; % XXX: Temporarily -t_from_form({type, _L, boolean, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, boolean, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_boolean(), L}; -t_from_form({type, _L, byte, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, byte, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_byte(), L}; -t_from_form({type, _L, char, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, char, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_char(), L}; -t_from_form({type, _L, float, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, float, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_float(), L}; -t_from_form({type, _L, function, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, function, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_fun(), L}; -t_from_form({type, _L, 'fun', []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, 'fun', []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_fun(), L}; t_from_form({type, _L, 'fun', [{type, _, any}, Range]}, TypeNames, - ET, M, MR, V, D, L) -> - {T, L1} = t_from_form(Range, TypeNames, ET, M, MR, V, D - 1, L - 1), + ET, S, MR, V, D, L) -> + {T, L1} = t_from_form(Range, TypeNames, ET, S, MR, V, D - 1, L - 1), {t_fun(T), L1}; t_from_form({type, _L, 'fun', [{type, _, product, Domain}, Range]}, - TypeNames, ET, M, MR, V, D, L) -> - {Dom1, L1} = list_from_form(Domain, TypeNames, ET, M, MR, V, D, L), - {Ran1, L2} = t_from_form(Range, TypeNames, ET, M, MR, V, D - 1, L1), + TypeNames, ET, S, MR, V, D, L) -> + {Dom1, L1} = list_from_form(Domain, TypeNames, ET, S, MR, V, D, L), + {Ran1, L2} = t_from_form(Range, TypeNames, ET, S, MR, V, D - 1, L1), {t_fun(Dom1, Ran1), L2}; -t_from_form({type, _L, identifier, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, identifier, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_identifier(), L}; -t_from_form({type, _L, integer, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, integer, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_integer(), L}; -t_from_form({type, _L, iodata, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, iodata, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_iodata(), L}; -t_from_form({type, _L, iolist, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, iolist, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_iolist(), L}; -t_from_form({type, _L, list, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, list, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_list(), L}; -t_from_form({type, _L, list, [Type]}, TypeNames, ET, M, MR, V, D, L) -> - {T, L1} = t_from_form(Type, TypeNames, ET, M, MR, V, D - 1, L - 1), +t_from_form({type, _L, list, [Type]}, TypeNames, ET, S, MR, V, D, L) -> + {T, L1} = t_from_form(Type, TypeNames, ET, S, MR, V, D - 1, L - 1), {t_list(T), L1}; -t_from_form({type, _L, map, _}, TypeNames, ET, M, MR, V, D, L) -> - builtin_type(map, t_map([]), TypeNames, ET, M, MR, V, D, L); -t_from_form({type, _L, mfa, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, map, _}, TypeNames, ET, S, MR, V, D, L) -> + builtin_type(map, t_map([]), TypeNames, ET, S, MR, V, D, L); +t_from_form({type, _L, mfa, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_mfa(), L}; -t_from_form({type, _L, module, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, module, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_module(), L}; -t_from_form({type, _L, nil, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, nil, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_nil(), L}; -t_from_form({type, _L, neg_integer, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, neg_integer, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_neg_integer(), L}; -t_from_form({type, _L, non_neg_integer, []}, _TypeNames, _ET, _M, _MR, +t_from_form({type, _L, non_neg_integer, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_non_neg_integer(), L}; -t_from_form({type, _L, no_return, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, no_return, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_unit(), L}; -t_from_form({type, _L, node, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, node, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_node(), L}; -t_from_form({type, _L, none, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, none, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_none(), L}; -t_from_form({type, _L, nonempty_list, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, nonempty_list, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_nonempty_list(), L}; -t_from_form({type, _L, nonempty_list, [Type]}, TypeNames, ET, M, MR, V, D, L) -> - {T, L1} = t_from_form(Type, TypeNames, ET, M, MR, V, D, L - 1), +t_from_form({type, _L, nonempty_list, [Type]}, TypeNames, ET, S, MR, V, D, L) -> + {T, L1} = t_from_form(Type, TypeNames, ET, S, MR, V, D, L - 1), {t_nonempty_list(T), L1}; t_from_form({type, _L, nonempty_improper_list, [Cont, Term]}, TypeNames, - ET, M, MR, V, D, L) -> - {T1, L1} = t_from_form(Cont, TypeNames, ET, M, MR, V, D, L - 1), - {T2, L2} = t_from_form(Term, TypeNames, ET, M, MR, V, D, L1), + ET, S, MR, V, D, L) -> + {T1, L1} = t_from_form(Cont, TypeNames, ET, S, MR, V, D, L - 1), + {T2, L2} = t_from_form(Term, TypeNames, ET, S, MR, V, D, L1), {t_cons(T1, T2), L2}; t_from_form({type, _L, nonempty_maybe_improper_list, []}, _TypeNames, - _ET, _M, _MR, _V, _D, L) -> + _ET, _S, _MR, _V, _D, L) -> {t_cons(?any, ?any), L}; t_from_form({type, _L, nonempty_maybe_improper_list, [Cont, Term]}, - TypeNames, ET, M, MR, V, D, L) -> - {T1, L1} = t_from_form(Cont, TypeNames, ET, M, MR, V, D, L - 1), - {T2, L2} = t_from_form(Term, TypeNames, ET, M, MR, V, D, L1), + TypeNames, ET, S, MR, V, D, L) -> + {T1, L1} = t_from_form(Cont, TypeNames, ET, S, MR, V, D, L - 1), + {T2, L2} = t_from_form(Term, TypeNames, ET, S, MR, V, D, L1), {t_cons(T1, T2), L2}; -t_from_form({type, _L, nonempty_string, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, nonempty_string, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_nonempty_string(), L}; -t_from_form({type, _L, number, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, number, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_number(), L}; -t_from_form({type, _L, pid, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, pid, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_pid(), L}; -t_from_form({type, _L, port, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, port, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_port(), L}; -t_from_form({type, _L, pos_integer, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, pos_integer, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_pos_integer(), L}; t_from_form({type, _L, maybe_improper_list, []}, _TypeNames, - _ET, _M, _MR, _V, _D, L) -> + _ET, _S, _MR, _V, _D, L) -> {t_maybe_improper_list(), L}; t_from_form({type, _L, maybe_improper_list, [Content, Termination]}, - TypeNames, ET, M, MR, V, D, L) -> - {T1, L1} = t_from_form(Content, TypeNames, ET, M, MR, V, D, L - 1), - {T2, L2} = t_from_form(Termination, TypeNames, ET, M, MR, V, D, L1), + TypeNames, ET, S, MR, V, D, L) -> + {T1, L1} = t_from_form(Content, TypeNames, ET, S, MR, V, D, L - 1), + {T2, L2} = t_from_form(Termination, TypeNames, ET, S, MR, V, D, L1), {t_maybe_improper_list(T1, T2), L2}; -t_from_form({type, _L, product, Elements}, TypeNames, ET, M, MR, V, D, L) -> - {Lst, L1} = list_from_form(Elements, TypeNames, ET, M, MR, V, D - 1, L), +t_from_form({type, _L, product, Elements}, TypeNames, ET, S, MR, V, D, L) -> + {Lst, L1} = list_from_form(Elements, TypeNames, ET, S, MR, V, D - 1, L), {t_product(Lst), L1}; t_from_form({type, _L, range, [From, To]} = Type, - _TypeNames, _ET, _M, _MR, _V, _D, L) -> + _TypeNames, _ET, _S, _MR, _V, _D, L) -> case {erl_eval:partial_eval(From), erl_eval:partial_eval(To)} of {{integer, _, FromVal}, {integer, _, ToVal}} -> {t_from_range(FromVal, ToVal), L}; _ -> throw({error, io_lib:format("Unable to evaluate type ~w\n", [Type])}) end; -t_from_form({type, _L, record, [Name|Fields]}, TypeNames, ET, M, MR, V, D, L) -> - record_from_form(Name, Fields, TypeNames, ET, M, MR, V, D, L); -t_from_form({type, _L, reference, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, record, [Name|Fields]}, TypeNames, ET, S, MR, V, D, L) -> + record_from_form(Name, Fields, TypeNames, ET, S, MR, V, D, L); +t_from_form({type, _L, reference, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_reference(), L}; -t_from_form({type, _L, string, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, string, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_string(), L}; -t_from_form({type, _L, term, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, term, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_any(), L}; -t_from_form({type, _L, timeout, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, timeout, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_timeout(), L}; -t_from_form({type, _L, tuple, any}, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +t_from_form({type, _L, tuple, any}, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {t_tuple(), L}; -t_from_form({type, _L, tuple, Args}, TypeNames, ET, M, MR, V, D, L) -> - {Lst, L1} = list_from_form(Args, TypeNames, ET, M, MR, V, D - 1, L), +t_from_form({type, _L, tuple, Args}, TypeNames, ET, S, MR, V, D, L) -> + {Lst, L1} = list_from_form(Args, TypeNames, ET, S, MR, V, D - 1, L), {t_tuple(Lst), L1}; -t_from_form({type, _L, union, Args}, TypeNames, ET, M, MR, V, D, L) -> - {Lst, L1} = list_from_form(Args, TypeNames, ET, M, MR, V, D, L), +t_from_form({type, _L, union, Args}, TypeNames, ET, S, MR, V, D, L) -> + {Lst, L1} = list_from_form(Args, TypeNames, ET, S, MR, V, D, L), {t_sup(Lst), L1}; -t_from_form({user_type, _L, Name, Args}, TypeNames, ET, M, MR, V, D, L) -> - type_from_form(Name, Args, TypeNames, ET, M, MR, V, D, L); -t_from_form({type, _L, Name, Args}, TypeNames, ET, M, MR, V, D, L) -> +t_from_form({user_type, _L, Name, Args}, TypeNames, ET, S, MR, V, D, L) -> + type_from_form(Name, Args, TypeNames, ET, S, MR, V, D, L); +t_from_form({type, _L, Name, Args}, TypeNames, ET, S, MR, V, D, L) -> %% Compatibility: modules compiled before Erlang/OTP 18.0. - type_from_form(Name, Args, TypeNames, ET, M, MR, V, D, L); + type_from_form(Name, Args, TypeNames, ET, S, MR, V, D, L); t_from_form({opaque, _L, Name, {Mod, Args, Rep}}, _TypeNames, - _ET, _M, _MR, _V, _D, L) -> + _ET, _S, _MR, _V, _D, L) -> %% XXX. To be removed. {t_opaque(Mod, Name, Args, Rep), L}. -builtin_type(Name, Type, TypeNames, ET, M, MR, V, D, L) -> +builtin_type(Name, Type, TypeNames, ET, Site, MR, V, D, L) -> + M = site_module(Site), case dict:find(M, MR) of {ok, R} -> case lookup_type(Name, 0, R) of {_, {{_M, _FL, _F, _A}, _T}} -> - type_from_form(Name, [], TypeNames, ET, M, MR, V, D, L); + type_from_form(Name, [], TypeNames, ET, Site, MR, V, D, L); error -> {Type, L} end; @@ -4215,92 +4326,107 @@ builtin_type(Name, Type, TypeNames, ET, M, MR, V, D, L) -> {Type, L} end. -type_from_form(Name, Args, TypeNames, ET, M, MR, V, D, L) -> +type_from_form(Name, Args, TypeNames, ET, Site0, MR, V, D, L) -> ArgsLen = length(Args), - {ArgTypes, L1} = list_from_form(Args, TypeNames, ET, M, MR, V, D, L), - {ok, R} = dict:find(M, MR), + Module = site_module(Site0), + {ok, R} = dict:find(Module, MR), + TypeName = {type, {Module, Name, ArgsLen}}, case lookup_type(Name, ArgsLen, R) of {type, {{Module, _FileName, Form, ArgNames}, _Type}} -> - TypeName = {type, Module, Name, ArgsLen}, case can_unfold_more(TypeName, TypeNames) of true -> + NewTypeNames = [TypeName|TypeNames], + {ArgTypes, L1} = + list_from_form(Args, TypeNames, ET, Site0, MR, V, D, L), List = lists:zip(ArgNames, ArgTypes), TmpV = dict:from_list(List), - t_from_form(Form, [TypeName|TypeNames], ET, M, MR, TmpV, D, L1); + Site = TypeName, + t_from_form(Form, NewTypeNames, ET, Site, MR, TmpV, D, L1); false -> - {t_any(), L1} + {t_any(), L} end; {opaque, {{Module, _FileName, Form, ArgNames}, Type}} -> - TypeName = {opaque, Module, Name, ArgsLen}, - {Rep, L2} = - case can_unfold_more(TypeName, TypeNames) of - true -> - List = lists:zip(ArgNames, ArgTypes), - TmpV = dict:from_list(List), - t_from_form(Form, [TypeName|TypeNames], ET, M, MR, TmpV, D, L1); - false -> {t_any(), L1} - end, - Rep1 = choose_opaque_type(Rep, Type), - Rep2 = case t_is_none(Rep1) of - true -> Rep1; - false -> - Args2 = [subst_all_vars_to_any(ArgType) || - ArgType <- ArgTypes], - t_opaque(Module, Name, Args2, Rep1) - end, - {Rep2, L2}; + case can_unfold_more(TypeName, TypeNames) of + true -> + NewTypeNames = [TypeName|TypeNames], + {ArgTypes, L1} = + list_from_form(Args, NewTypeNames, ET, Site0, MR, V, D, L), + List = lists:zip(ArgNames, ArgTypes), + TmpV = dict:from_list(List), + Site = TypeName, + {Rep, L2} = + t_from_form(Form, NewTypeNames, ET, Site, MR, TmpV, D, L1), + Rep1 = choose_opaque_type(Rep, Type), + Rep2 = case cannot_have_opaque(Rep1, TypeName, TypeNames) of + true -> Rep1; + false -> + ArgTypes2 = subst_all_vars_to_any_list(ArgTypes), + t_opaque(Module, Name, ArgTypes2, Rep1) + end, + {Rep2, L2}; + false -> {t_any(), L} + end; error -> Msg = io_lib:format("Unable to find type ~w/~w\n", [Name, ArgsLen]), throw({error, Msg}) end. -remote_from_form(RemMod, Name, Args, TypeNames, ET, M, MR, V, D, L) -> - {ArgTypes, L1} = list_from_form(Args, TypeNames, ET, M, MR, V, D, L), +remote_from_form(RemMod, Name, Args, TypeNames, ET, S, MR, V, D, L) -> if ET =:= replace_by_none -> - {t_none(), L1}; + {t_none(), L}; true -> ArgsLen = length(Args), + MFA = {RemMod, Name, ArgsLen}, case dict:find(RemMod, MR) of error -> - self() ! {self(), ext_types, {RemMod, Name, ArgsLen}}, - {t_any(), L1}; + self() ! {self(), ext_types, MFA}, + {t_any(), L}; {ok, RemDict} -> - MFA = {RemMod, Name, ArgsLen}, + RemType = {type, MFA}, case sets:is_element(MFA, ET) of true -> case lookup_type(Name, ArgsLen, RemDict) of {type, {{_Mod, _FileLine, Form, ArgNames}, _Type}} -> - RemType = {type, RemMod, Name, ArgsLen}, case can_unfold_more(RemType, TypeNames) of true -> + NewTypeNames = [RemType|TypeNames], + {ArgTypes, L1} = list_from_form(Args, TypeNames, + ET, S, MR, V, D, L), List = lists:zip(ArgNames, ArgTypes), TmpVarDict = dict:from_list(List), - NewTypeNames = [RemType|TypeNames], + Site = RemType, t_from_form(Form, NewTypeNames, ET, - RemMod, MR, TmpVarDict, D, L1); + Site, MR, TmpVarDict, D, L1); false -> - {t_any(), L1} + {t_any(), L} end; {opaque, {{Mod, _FileLine, Form, ArgNames}, Type}} -> - RemType = {opaque, RemMod, Name, ArgsLen}, - List = lists:zip(ArgNames, ArgTypes), - TmpVarDict = dict:from_list(List), - {NewRep, L2} = - case can_unfold_more(RemType, TypeNames) of - true -> - NewTypeNames = [RemType|TypeNames], - t_from_form(Form, NewTypeNames, ET, RemMod, MR, - TmpVarDict, D, L1); - false -> - {t_any(), L1} - end, - NewRep1 = choose_opaque_type(NewRep, Type), - NewRep2 = case t_is_none(NewRep1) of - true -> NewRep1; - false -> t_opaque(Mod, Name, ArgTypes, NewRep1) - end, - {NewRep2, L2}; + case can_unfold_more(RemType, TypeNames) of + true -> + NewTypeNames = [RemType|TypeNames], + {ArgTypes, L1} = list_from_form(Args, NewTypeNames, + ET, S, MR, V, D, L), + List = lists:zip(ArgNames, ArgTypes), + TmpVarDict = dict:from_list(List), + Site = RemType, + {NewRep, L2} = + t_from_form(Form, NewTypeNames, ET, Site, MR, + TmpVarDict, D, L1), + NewRep1 = choose_opaque_type(NewRep, Type), + NewRep2 = + case + cannot_have_opaque(NewRep1, RemType, TypeNames) + of + true -> NewRep1; + false -> + ArgTypes2 = subst_all_vars_to_any_list(ArgTypes), + t_opaque(Mod, Name, ArgTypes2, NewRep1) + end, + {NewRep2, L2}; + false -> + {t_any(), L} + end; error -> Msg = io_lib:format("Unable to find remote type ~w:~w()\n", [RemMod, Name]), @@ -4308,11 +4434,14 @@ remote_from_form(RemMod, Name, Args, TypeNames, ET, M, MR, V, D, L) -> end; false -> self() ! {self(), ext_types, {RemMod, Name, ArgsLen}}, - {t_any(), L1} + {t_any(), L} end end end. +subst_all_vars_to_any_list(Types) -> + [subst_all_vars_to_any(Type) || Type <- Types]. + %% Opaque types (both local and remote) are problematic when it comes %% to the limits (TypeNames, D, and L). The reason is that if any() is %% substituted for a more specialized subtype of an opaque type, the @@ -4332,22 +4461,24 @@ choose_opaque_type(Type, DeclType) -> false -> DeclType end. -record_from_form({atom, _, Name}, ModFields, TypeNames, ET, M, MR, V, D, L) -> +record_from_form({atom, _, Name}, ModFields, TypeNames, ET, S, MR, V, D, L) -> case can_unfold_more({record, Name}, TypeNames) of true -> + M = site_module(S), {ok, R} = dict:find(M, MR), case lookup_record(Name, R) of {ok, DeclFields} -> NewTypeNames = [{record, Name}|TypeNames], + S1 = {record, {M, Name, length(DeclFields)}}, {GetModRec, L1} = get_mod_record(ModFields, DeclFields, - NewTypeNames, ET, M, MR, V, D, L), + NewTypeNames, ET, S1, MR, V, D, L), case GetModRec of {error, FieldName} -> throw({error, io_lib:format("Illegal declaration of #~w{~w}\n", [Name, FieldName])}); {ok, NewFields} -> {NewFields1, L2} = - fields_from_form(NewFields, NewTypeNames, ET, M, MR, + fields_from_form(NewFields, NewTypeNames, ET, S1, MR, dict:new(), D, L1), Rec = t_tuple( [t_atom(Name)|[Type @@ -4361,12 +4492,12 @@ record_from_form({atom, _, Name}, ModFields, TypeNames, ET, M, MR, V, D, L) -> {t_any(), L} end. -get_mod_record([], DeclFields, _TypeNames, _ET, _M, _MR, _V, _D, L) -> +get_mod_record([], DeclFields, _TypeNames, _ET, _S, _MR, _V, _D, L) -> {{ok, DeclFields}, L}; -get_mod_record(ModFields, DeclFields, TypeNames, ET, M, MR, V, D, L) -> +get_mod_record(ModFields, DeclFields, TypeNames, ET, S, MR, V, D, L) -> DeclFieldsDict = lists:keysort(1, DeclFields), {ModFieldsDict, L1} = - build_field_dict(ModFields, TypeNames, ET, M, MR, V, D, L), + build_field_dict(ModFields, TypeNames, ET, S, MR, V, D, L), case get_mod_record_types(DeclFieldsDict, ModFieldsDict, []) of {error, _FieldName} = Error -> {Error, L1}; {ok, FinalKeyDict} -> @@ -4375,17 +4506,17 @@ get_mod_record(ModFields, DeclFields, TypeNames, ET, M, MR, V, D, L) -> {{ok, Fields}, L1} end. -build_field_dict(FieldTypes, TypeNames, ET, M, MR, V, D, L) -> - build_field_dict(FieldTypes, TypeNames, ET, M, MR, V, D, L, []). +build_field_dict(FieldTypes, TypeNames, ET, S, MR, V, D, L) -> + build_field_dict(FieldTypes, TypeNames, ET, S, MR, V, D, L, []). build_field_dict([{type, _, field_type, [{atom, _, Name}, Type]}|Left], - TypeNames, ET, M, MR, V, D, L, Acc) -> - {T, L1} = t_from_form(Type, TypeNames, ET, M, MR, V, D, L - 1), + TypeNames, ET, S, MR, V, D, L, Acc) -> + {T, L1} = t_from_form(Type, TypeNames, ET, S, MR, V, D, L - 1), NewAcc = [{Name, Type, T}|Acc], {Dict, L2} = - build_field_dict(Left, TypeNames, ET, M, MR, V, D, L1, NewAcc), + build_field_dict(Left, TypeNames, ET, S, MR, V, D, L1, NewAcc), {Dict, L2}; -build_field_dict([], _TypeNames, _ET, _M, _MR, _V, _D, L, Acc) -> +build_field_dict([], _TypeNames, _ET, _S, _MR, _V, _D, L, Acc) -> {lists:keysort(1, Acc), L}. get_mod_record_types([{FieldName, _Abstr, _DeclType}|Left1], @@ -4404,88 +4535,94 @@ get_mod_record_types(_, [{FieldName2, _FormType, _ModType}|_], _Acc) -> %% It is important to create a limited version of the record type %% since nested record types can otherwise easily result in huge %% terms. -fields_from_form([], _TypeNames, _ET, _M, _MR, _V, _D, L) -> +fields_from_form([], _TypeNames, _ET, _S, _MR, _V, _D, L) -> {[], L}; -fields_from_form([{Name, Abstr, _Type}|Tail], TypeNames, ET, M, MR, +fields_from_form([{Name, Abstr, _Type}|Tail], TypeNames, ET, S, MR, V, D, L) -> - {T, L1} = t_from_form(Abstr, TypeNames, ET, M, MR, V, D, L), - {F, L2} = fields_from_form(Tail, TypeNames, ET, M, MR, V, D, L1), + {T, L1} = t_from_form(Abstr, TypeNames, ET, S, MR, V, D, L), + {F, L2} = fields_from_form(Tail, TypeNames, ET, S, MR, V, D, L1), {[{Name, T}|F], L2}. -list_from_form([], _TypeNames, _ET, _M, _MR, _V, _D, L) -> +list_from_form([], _TypeNames, _ET, _S, _MR, _V, _D, L) -> {[], L}; -list_from_form([H|Tail], TypeNames, ET, M, MR, V, D, L) -> - {H1, L1} = t_from_form(H, TypeNames, ET, M, MR, V, D, L - 1), - {T1, L2} = list_from_form(Tail, TypeNames, ET, M, MR, V, D, L1), +list_from_form([H|Tail], TypeNames, ET, S, MR, V, D, L) -> + {H1, L1} = t_from_form(H, TypeNames, ET, S, MR, V, D, L - 1), + {T1, L2} = list_from_form(Tail, TypeNames, ET, S, MR, V, D, L1), {[H1|T1], L2}. --spec t_check_record_fields(parse_form(), sets:set(mfa()), module(), +-spec t_check_record_fields(parse_form(), sets:set(mfa()), site(), mod_records()) -> ok. -t_check_record_fields(Form, ExpTypes, Module, RecDict) -> - t_check_record_fields(Form, ExpTypes, Module, RecDict, dict:new()). +t_check_record_fields(Form, ExpTypes, Site, RecDict) -> + t_check_record_fields(Form, ExpTypes, Site, RecDict, dict:new()). --spec t_check_record_fields(parse_form(), sets:set(mfa()), module(), +-spec t_check_record_fields(parse_form(), sets:set(mfa()), site(), mod_records(), var_table()) -> ok. %% If there is something wrong with parse_form() %% throw({error, io_lib:chars()} is called. -t_check_record_fields({var, _L, _}, _ET, _M, _MR, _V) -> ok; -t_check_record_fields({ann_type, _L, [_Var, Type]}, ET, M, MR, V) -> - t_check_record_fields(Type, ET, M, MR, V); -t_check_record_fields({paren_type, _L, [Type]}, ET, M, MR, V) -> - t_check_record_fields(Type, ET, M, MR, V); +t_check_record_fields({var, _L, _}, _ET, _S, _MR, _V) -> ok; +t_check_record_fields({ann_type, _L, [_Var, Type]}, ET, S, MR, V) -> + t_check_record_fields(Type, ET, S, MR, V); +t_check_record_fields({paren_type, _L, [Type]}, ET, S, MR, V) -> + t_check_record_fields(Type, ET, S, MR, V); t_check_record_fields({remote_type, _L, [{atom, _, _}, {atom, _, _}, Args]}, - ET, M, MR, V) -> - list_check_record_fields(Args, ET, M, MR, V); -t_check_record_fields({atom, _L, _}, _ET, _M, _MR, _V) -> ok; -t_check_record_fields({integer, _L, _}, _ET, _M, _MR, _V) -> ok; -t_check_record_fields({op, _L, _Op, _Arg}, _ET, _M, _MR, _V) -> ok; -t_check_record_fields({op, _L, _Op, _Arg1, _Arg2}, _ET, _M, _MR, _V) -> ok; -t_check_record_fields({type, _L, tuple, any}, _ET, _M, _MR, _V) -> ok; -t_check_record_fields({type, _L, map, any}, _ET, _M, _MR, _V) -> ok; -t_check_record_fields({type, _L, binary, [_Base, _Unit]}, _ET, _M, _MR, _V) -> + ET, S, MR, V) -> + list_check_record_fields(Args, ET, S, MR, V); +t_check_record_fields({atom, _L, _}, _ET, _S, _MR, _V) -> ok; +t_check_record_fields({integer, _L, _}, _ET, _S, _MR, _V) -> ok; +t_check_record_fields({op, _L, _Op, _Arg}, _ET, _S, _MR, _V) -> ok; +t_check_record_fields({op, _L, _Op, _Arg1, _Arg2}, _ET, _S, _MR, _V) -> ok; +t_check_record_fields({type, _L, tuple, any}, _ET, _S, _MR, _V) -> ok; +t_check_record_fields({type, _L, map, any}, _ET, _S, _MR, _V) -> ok; +t_check_record_fields({type, _L, binary, [_Base, _Unit]}, _ET, _S, _MR, _V) -> ok; t_check_record_fields({type, _L, 'fun', [{type, _, any}, Range]}, - ET, M, MR, V) -> - t_check_record_fields(Range, ET, M, MR, V); -t_check_record_fields({type, _L, range, [_From, _To]}, _ET, _M, _MR, _V) -> + ET, S, MR, V) -> + t_check_record_fields(Range, ET, S, MR, V); +t_check_record_fields({type, _L, range, [_From, _To]}, _ET, _S, _MR, _V) -> ok; -t_check_record_fields({type, _L, record, [Name|Fields]}, ET, M, MR, V) -> - check_record(Name, Fields, ET, M, MR, V); -t_check_record_fields({type, _L, _, Args}, ET, M, MR, V) -> - list_check_record_fields(Args, ET, M, MR, V); -t_check_record_fields({user_type, _L, _Name, Args}, ET, M, MR, V) -> - list_check_record_fields(Args, ET, M, MR, V). - -check_record({atom, _, Name}, ModFields, ET, M, MR, V) -> +t_check_record_fields({type, _L, record, [Name|Fields]}, ET, S, MR, V) -> + check_record(Name, Fields, ET, S, MR, V); +t_check_record_fields({type, _L, _, Args}, ET, S, MR, V) -> + list_check_record_fields(Args, ET, S, MR, V); +t_check_record_fields({user_type, _L, _Name, Args}, ET, S, MR, V) -> + list_check_record_fields(Args, ET, S, MR, V). + +check_record({atom, _, Name}, ModFields, ET, Site, MR, V) -> + M = site_module(Site), {ok, R} = dict:find(M, MR), {ok, DeclFields} = lookup_record(Name, R), - case check_fields(ModFields, DeclFields, ET, M, MR, V) of + case check_fields(Name, ModFields, DeclFields, ET, Site, MR, V) of {error, FieldName} -> throw({error, io_lib:format("Illegal declaration of #~w{~w}\n", [Name, FieldName])}); ok -> ok end. -check_fields([{type, _, field_type, [{atom, _, Name}, Abstr]}|Left], - DeclFields, ET, M, MR, V) -> - Type = t_from_form(Abstr, ET, M, MR, V), +check_fields(RecName, [{type, _, field_type, [{atom, _, Name}, Abstr]}|Left], + DeclFields, ET, Site0, MR, V) -> + M = site_module(Site0), + Site = {record, {M, RecName, length(DeclFields)}}, + Type = t_from_form(Abstr, ET, Site, MR, V), {Name, _, DeclType} = lists:keyfind(Name, 1, DeclFields), TypeNoVars = subst_all_vars_to_any(Type), case t_is_subtype(TypeNoVars, DeclType) of false -> {error, Name}; - true -> check_fields(Left, DeclFields, ET, M, MR, V) + true -> check_fields(RecName, Left, DeclFields, ET, Site0, MR, V) end; -check_fields([], _Decl, _ET, _M, _MR, _V) -> +check_fields(_RecName, [], _Decl, _ET, _Site, _MR, _V) -> ok. -list_check_record_fields([], _ET, _M, _MR, _V) -> +list_check_record_fields([], _ET, _S, _MR, _V) -> ok; -list_check_record_fields([H|Tail], ET, M, MR, V) -> - ok = t_check_record_fields(H, ET, M, MR, V), - list_check_record_fields(Tail, ET, M, MR, V). +list_check_record_fields([H|Tail], ET, S, MR, V) -> + ok = t_check_record_fields(H, ET, S, MR, V), + list_check_record_fields(Tail, ET, S, MR, V). + +site_module({_, {Module, _, _}}) -> + Module. -spec t_var_names([erl_type()]) -> [atom()]. @@ -4580,8 +4717,9 @@ t_form_to_string({type, _L, Name, []} = T) -> M = mod, D0 = dict:new(), MR = dict:from_list([{M, D0}]), + S = {type, {M,Name,0}}, {T1, _} = - t_from_form(T, [], sets:new(), M, MR, D0, _Deep=1000, _ALot=100000), + t_from_form(T, [], sets:new(), S, MR, D0, _Deep=1000, _ALot=100000), t_to_string(T1) catch throw:{error, _} -> atom_to_string(Name) ++ "()" end; @@ -4673,6 +4811,12 @@ lookup_type(Name, Arity, RecDict) -> type_is_defined(TypeOrOpaque, Name, Arity, RecDict) -> dict:is_key({TypeOrOpaque, Name, Arity}, RecDict). +cannot_have_opaque(Type, TypeName, TypeNames) -> + t_is_none(Type) orelse is_recursive(TypeName, TypeNames). + +is_recursive(TypeName, TypeNames) -> + lists:member(TypeName, TypeNames). + can_unfold_more(TypeName, TypeNames) -> Fun = fun(E, Acc) -> case E of TypeName -> Acc + 1; _ -> Acc end end, lists:foldl(Fun, 0, TypeNames) < ?REC_TYPE_LIMIT. diff --git a/lib/hipe/doc/src/hipe_app.xml b/lib/hipe/doc/src/hipe_app.xml index 98fec900af..bf4bdbb3b3 100644 --- a/lib/hipe/doc/src/hipe_app.xml +++ b/lib/hipe/doc/src/hipe_app.xml @@ -37,15 +37,14 @@ <description> <p> The normal way to native-compile an Erlang module using HiPE is to include the atom native - in the Erlang compiler options, as in: - <code> - 1> <input>c(my_module, [native]).</input></code> - Options to the HiPE compiler are then passed as follows: - <code> - 1> <input>c(my_module, [native,{hipe,Options}]).</input></code> - For on-line help in the Erlang shell, call <c>hipe:help()</c>. - Details on HiPE compiler options are given by <c>hipe:help_options()</c>. - </p> + in the Erlang compiler options, as in:</p> + <pre> + 1> <input>c(my_module, [native]).</input></pre> + <p>Options to the HiPE compiler are then passed as follows:</p> + <pre> + 1> <input>c(my_module, [native,{hipe,Options}]).</input></pre> + <p>For on-line help in the Erlang shell, call <c>hipe:help()</c>. + Details on HiPE compiler options are given by <c>hipe:help_options()</c>.</p> </description> <section> <title>SEE ALSO</title> diff --git a/lib/hipe/doc/src/notes.xml b/lib/hipe/doc/src/notes.xml index 33a18ff7ef..761b4d9f90 100644 --- a/lib/hipe/doc/src/notes.xml +++ b/lib/hipe/doc/src/notes.xml @@ -31,6 +31,159 @@ </header> <p>This document describes the changes made to HiPE.</p> +<section><title>Hipe 3.15</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix pretty printing of Core Maps</p> + <p> + Literal maps could cause Dialyzer to crash when pretty + printing the results.</p> + <p> + Own Id: OTP-13238</p> + </item> + <item> + <p> + Dialyzer warnings removed.</p> + <p> + Own Id: OTP-13379</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Fix HiPE ErLLVM code generation for pattern matching with + UTF binaries.</p> + <p> + Own Id: OTP-13269</p> + </item> + <item> + <p> + Fix various binary construction inconsistencies for hipe + compiled code. <list> <item>Passing bad field sizes to + binary constructions would throw <c>badarith</c> rather + than <c>badarg</c>. Worse, in guards, when the unit size + of the field was 1, the exception would leak rather than + failing the function clause match.</item> <item>Passing + bignums as field sizes to binary constructions would + always fail (and always with <c>badarg</c>).</item> + <item>A bug in bs_init_bits that cased binary + constructions to fail with system_limit if they were at + least 1/8th of the actual limit.</item> <item>Compiler + crashes when matches against an integer literal whose + size fits an unsigned word, but not a signed word or + matches against an integer literal that whose size is + larger than the largest allowed bignum.</item> <item>Very + large binary constructions that should fail with + system_limit could instead fail with <c>badarg</c> or + even succeed with a faulty result.</item> <item>Add + missing check for unit size match when inserting a + binary. For example, a faulty expression like + <c><<<<1:7>>/binary>></c> would + succeed.</item> </list></p> + <p> + Own Id: OTP-13272</p> + </item> + </list> + </section> + +</section> + +<section><title>Hipe 3.14</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix hipe bug causing segfaults when native code + constructs binaries starting with a zero-length integer + field.</p> + <p> + Own Id: OTP-13048</p> + </item> + <item> + <p> + Reintroduce the <c>erlang:make_fun/3</c> BIF in + erl_bif_types.</p> + <p> + Own Id: OTP-13068</p> + </item> + <item> + <p> + In certain cases of matching with very big binaries, the + HiPE compiler generated code that would fail the match, + even in cases that the matching was successful. The + problem was more quite noticeable on 32-bit platforms.</p> + <p> + Own Id: OTP-13092</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + mikpe/hipe_x86_signal-musl-support</p> + <p> + Own Id: OTP-13159</p> + </item> + </list> + </section> + +</section> + +<section><title>Hipe 3.13</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> Fix bugs concerning <c>erlang:abs/1</c>. </p> + <p> + Own Id: OTP-12948</p> + </item> + <item> + <p> Fix a bug concerning <c>lists:keydelete/3</c> with + union and opaque types. </p> + <p> + Own Id: OTP-12949</p> + </item> + <item> + <p> + A beam file compiled by hipe for an incompatible runtime + system was sometimes not rejected by the loader, which + could lead to vm crash. This fix will also allow the same + hipe compiler to be used by both normal and debug-built + vm.</p> + <p> + Own Id: OTP-12962</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + New function <c>hipe:erts_checksum/0</c> which returns a + value identifying the target runtime system for the + compiler. Used by dialyzer for its beam cache directory.</p> + <p> + Own Id: OTP-12963 Aux Id: OTP-12962, OTP-12964 </p> + </item> + </list> + </section> + +</section> + <section><title>Hipe 3.12</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -275,22 +428,28 @@ <p> EEP43: New data type - Maps</p> <p> - With Maps you may for instance: <taglist> <item><c>M0 = - #{ a => 1, b => 2}, % create - associations</c></item> <item><c>M1 = M0#{ a := 10 }, % - update values</c></item> <item><c>M2 = M1#{ "hi" => - "hello"}, % add new associations</c></item> <item><c>#{ - "hi" := V1, a := V2, b := V3} = M2. % match keys with - values</c></item> </taglist></p> + With Maps you may for instance:</p> + <taglist> + <tag/> <item><c>M0 = #{ a => 1, b => 2}, % create + associations</c></item> + <tag/><item><c>M1 = M0#{ a := 10 }, % update values</c></item> + <tag/><item><c>M2 = M1#{ "hi" => + "hello"}, % add new associations</c></item> + <tag/><item><c>#{ "hi" := V1, a := V2, b := V3} = M2. + % match keys with values</c></item> + </taglist> <p> For information on how to use Maps please see Map Expressions in the <seealso marker="doc/reference_manual:expressions#map_expressions"> Reference Manual</seealso>.</p> <p> The current implementation is without the following - features: <taglist> <item>No variable keys</item> - <item>No single value access</item> <item>No map - comprehensions</item> </taglist></p> + features:</p> + <taglist> + <tag/><item>No variable keys</item> + <tag/><item>No single value access</item> + <tag/><item>No map comprehensions</item> + </taglist> <p> Note that Maps is <em>experimental</em> during OTP 17.0.</p> <p> @@ -558,19 +717,17 @@ <section><title>Fixed Bugs and Malfunctions</title> <list> <item> - <p> <list> <item><p>No warnings for underspecs with remote types</p></item> <item><p> Fix crash in Typer</p></item> <item><p>Fix Dialyzer's warning for its own code</p></item> <item><p>Fix Dialyzer's warnings in HiPE</p></item> <item><p>Add file/line info in a particular Dialyzer crash</p></item> <item><p>Update - inets test results</p></item> </list></p> + inets test results</p></item> </list> <p> Own Id: OTP-9758</p> </item> <item> - <p> <list> <item><p>Correct callback spec in application module</p></item> <item><p>Refine warning about callback specs with extra ranges</p></item> <item><p>Cleanup @@ -581,7 +738,7 @@ analysis</p></item> <item><p>Fix crash in Dialyzer</p></item> <item><p>Variable substitution was not generalizing any unknown variables.</p></item> - </list></p> + </list> <p> Own Id: OTP-9776</p> </item> diff --git a/lib/hipe/icode/hipe_beam_to_icode.erl b/lib/hipe/icode/hipe_beam_to_icode.erl index 0c7bdb788a..37c6ba9c60 100644 --- a/lib/hipe/icode/hipe_beam_to_icode.erl +++ b/lib/hipe/icode/hipe_beam_to_icode.erl @@ -881,6 +881,15 @@ trans_fun([{bs_init_bits,{f,Lbl},Size,_Words,_LiveRegs,{field_flags,Flags0},X}| trans_fun([{bs_add, {f,Lbl}, [Old,New,Unit], Res}|Instructions], Env) -> Dst = mk_var(Res), Temp = mk_var(new), + {FailLblName, FailCode} = + if Lbl =:= 0 -> + FailLbl = mk_label(new), + {hipe_icode:label_name(FailLbl), + [FailLbl, + hipe_icode:mk_fail([hipe_icode:mk_const(badarg)], error)]}; + true -> + {map_label(Lbl), []} + end, MultIs = case {New,Unit} of {{integer, NewInt}, _} -> @@ -890,40 +899,26 @@ trans_fun([{bs_add, {f,Lbl}, [Old,New,Unit], Res}|Instructions], Env) -> [hipe_icode:mk_move(Temp, NewVar)]; _ -> NewVar = mk_var(New), - if Lbl =:= 0 -> - [hipe_icode:mk_primop([Temp], '*', - [NewVar, hipe_icode:mk_const(Unit)])]; - true -> - Succ = mk_label(new), - [hipe_icode:mk_primop([Temp], '*', - [NewVar, hipe_icode:mk_const(Unit)], - hipe_icode:label_name(Succ), map_label(Lbl)), - Succ] - end + Succ = mk_label(new), + [hipe_icode:mk_primop([Temp], '*', + [NewVar, hipe_icode:mk_const(Unit)], + hipe_icode:label_name(Succ), FailLblName), + Succ] end, Succ2 = mk_label(new), - {FailLblName, FailCode} = - if Lbl =:= 0 -> - FailLbl = mk_label(new), - {hipe_icode:label_name(FailLbl), - [FailLbl, - hipe_icode:mk_fail([hipe_icode:mk_const(badarg)], error)]}; - true -> - {map_label(Lbl), []} - end, IsPos = [hipe_icode:mk_if('>=', [Temp, hipe_icode:mk_const(0)], hipe_icode:label_name(Succ2), FailLblName)] ++ - FailCode ++ [Succ2], - AddI = + FailCode ++ [Succ2], + AddRhs = case Old of - {integer,OldInt} -> - hipe_icode:mk_primop([Dst], '+', [Temp, hipe_icode:mk_const(OldInt)]); - _ -> - OldVar = mk_var(Old), - hipe_icode:mk_primop([Dst], '+', [Temp, OldVar]) + {integer,OldInt} -> hipe_icode:mk_const(OldInt); + _ -> mk_var(Old) end, - MultIs ++ IsPos ++ [AddI|trans_fun(Instructions, Env)]; + Succ3 = mk_label(new), + AddI = hipe_icode:mk_primop([Dst], '+', [Temp, AddRhs], + hipe_icode:label_name(Succ3), FailLblName), + MultIs ++ IsPos ++ [AddI,Succ3|trans_fun(Instructions, Env)]; %%-------------------------------------------------------------------- %% Bit syntax instructions added in R12B-5 (Fall 2008) %%-------------------------------------------------------------------- @@ -1306,7 +1301,7 @@ trans_bin([{bs_put_binary,{f,Lbl},Size,Unit,{field_flags,Flags},Source}| {Name, Args, Env2} = case Size of {atom,all} -> %% put all bits - {{bs_put_binary_all, Flags}, [Src,Base,Offset], Env}; + {{bs_put_binary_all, Unit, Flags}, [Src,Base,Offset], Env}; {integer,NoBits} when is_integer(NoBits), NoBits >= 0 -> %% Create a N*Unit bits subbinary {{bs_put_binary, NoBits*Unit, Flags}, [Src,Base,Offset], Env}; diff --git a/lib/hipe/icode/hipe_icode_primops.erl b/lib/hipe/icode/hipe_icode_primops.erl index ffb51b2ea4..a0deb31c42 100644 --- a/lib/hipe/icode/hipe_icode_primops.erl +++ b/lib/hipe/icode/hipe_icode_primops.erl @@ -116,7 +116,7 @@ is_safe({hipe_bs_primop, {bs_init, _, _}}) -> false; is_safe({hipe_bs_primop, {bs_init_bits, _}}) -> false; is_safe({hipe_bs_primop, {bs_init_bits, _, _}}) -> false; is_safe({hipe_bs_primop, {bs_put_binary, _, _}}) -> false; -is_safe({hipe_bs_primop, {bs_put_binary_all, _}}) -> false; +is_safe({hipe_bs_primop, {bs_put_binary_all, _, _}}) -> false; is_safe({hipe_bs_primop, {bs_put_float, _, _, _}}) -> false; is_safe({hipe_bs_primop, {bs_put_integer, _, _, _}}) -> false; is_safe({hipe_bs_primop, {bs_put_string, _, _}}) -> false; @@ -219,7 +219,7 @@ fails({hipe_bs_primop, {bs_init, _, _}}) -> true; fails({hipe_bs_primop, {bs_init_bits, _}}) -> true; fails({hipe_bs_primop, {bs_init_bits, _, _}}) -> true; fails({hipe_bs_primop, {bs_put_binary, _, _}}) -> true; -fails({hipe_bs_primop, {bs_put_binary_all, _}}) -> true; +fails({hipe_bs_primop, {bs_put_binary_all, _, _}}) -> true; fails({hipe_bs_primop, {bs_put_float, _, _, _}}) -> true; fails({hipe_bs_primop, {bs_put_integer, _, _, _}}) -> true; fails({hipe_bs_primop, {bs_put_string, _, _}}) -> true; @@ -265,8 +265,8 @@ pp(Dev, Op) -> io:format(Dev, "gc_test<~w>", [N]); {hipe_bs_primop, BsOp} -> case BsOp of - {bs_put_binary_all, Flags} -> - io:format(Dev, "bs_put_binary_all<~w>", [Flags]); + {bs_put_binary_all, Unit, Flags} -> + io:format(Dev, "bs_put_binary_all<~w, ~w>", [Unit,Flags]); {bs_put_binary, Size} -> io:format(Dev, "bs_put_binary<~w>", [Size]); {bs_put_binary, Flags, Size} -> @@ -504,14 +504,16 @@ type(Primop, Args) -> NewBinType = match_bin(erl_types:t_bitstr(0, Size), BinType), NewMatchState = erl_types:t_matchstate_update_present(NewBinType, MatchState), - if Signed =:= 0 -> - erl_types:t_product([erl_types:t_from_range(0, 1 bsl Size - 1), - NewMatchState]); - Signed =:= 4 -> - erl_types:t_product([erl_types:t_from_range(- (1 bsl (Size-1)), - (1 bsl (Size-1)) - 1), - NewMatchState]) - end; + Range = + case Signed of + 0 -> + UpperBound = inf_add(safe_bsl_1(Size), -1), + erl_types:t_from_range(0, UpperBound); + 4 -> + Bound = safe_bsl_1(Size - 1), + erl_types:t_from_range(inf_inv(Bound), inf_add(Bound, -1)) + end, + erl_types:t_product([Range, NewMatchState]); [_Arg] -> NewBinType = match_bin(erl_types:t_bitstr(Size, 0), BinType), NewMatchState = @@ -628,8 +630,9 @@ type(Primop, Args) -> [_SrcType, _BitsType, _Base, Type] -> erl_types:t_bitstr_concat(Type, erl_types:t_bitstr(Size, 0)) end; - {hipe_bs_primop, {bs_put_binary_all, _Flags}} -> - [SrcType, _Base, Type] = Args, + {hipe_bs_primop, {bs_put_binary_all, Unit, _Flags}} -> + [SrcType0, _Base, Type] = Args, + SrcType = erl_types:t_inf(erl_types:t_bitstr(Unit, 0), SrcType0), erl_types:t_bitstr_concat(SrcType,Type); {hipe_bs_primop, {bs_put_string, _, Size}} -> [_Base, Type] = Args, @@ -965,3 +968,20 @@ check_fun_args(_, _) -> match_bin(Pattern, Match) -> erl_types:t_bitstr_match(Pattern, Match). + +-spec safe_bsl_1(non_neg_integer()) -> non_neg_integer() | 'pos_inf'. + +safe_bsl_1(Shift) when Shift =< 128 -> 1 bsl Shift; +safe_bsl_1(_Shift) -> pos_inf. + +%% +%% The following two functions are stripped-down versions of more +%% general functions that exist in hipe_icode_range.erl +%% + +inf_inv(pos_inf) -> neg_inf; +inf_inv(Number) when is_integer(Number) -> -Number. + +inf_add(pos_inf, _Number) -> pos_inf; +inf_add(Number1, Number2) when is_integer(Number1), is_integer(Number2) -> + Number1 + Number2. diff --git a/lib/hipe/icode/hipe_icode_range.erl b/lib/hipe/icode/hipe_icode_range.erl index ba5fa1bfd7..9a20527a83 100644 --- a/lib/hipe/icode/hipe_icode_range.erl +++ b/lib/hipe/icode/hipe_icode_range.erl @@ -1202,11 +1202,11 @@ basic_type(#unsafe_update_element{}) -> not_analysed. analyse_bs_get_integer(Size, Flags, true) -> Signed = Flags band 4, if Signed =:= 0 -> - Max = 1 bsl Size - 1, + Max = inf_add(inf_bsl(1, Size), -1), Min = 0; true -> - Max = 1 bsl (Size-1) - 1, - Min = -(1 bsl (Size-1)) + Max = inf_add(inf_bsl(1, Size-1), -1), + Min = inf_inv(inf_bsl(1, Size-1)) end, {Min, Max}; analyse_bs_get_integer(Size, Flags, false) when is_integer(Size), diff --git a/lib/hipe/llvm/hipe_llvm_merge.erl b/lib/hipe/llvm/hipe_llvm_merge.erl index 3ababfc21a..6e891ac3b0 100644 --- a/lib/hipe/llvm/hipe_llvm_merge.erl +++ b/lib/hipe/llvm/hipe_llvm_merge.erl @@ -27,7 +27,7 @@ finalize(CompiledCode, Closures, Exports) -> DataRelocs = hipe_pack_constants:mk_data_relocs(RefsFromConsts, LabelMap), SSE = hipe_pack_constants:slim_sorted_exportmap(ExportMap, Closures, Exports), SlimRefs = hipe_pack_constants:slim_refs(AccRefs), - term_to_binary([{?VERSION_STRING(),?HIPE_SYSTEM_CRC}, + term_to_binary([{?VERSION_STRING(),?HIPE_ERTS_CHECKSUM}, ConstAlign, ConstSize, SC, % ConstMap DataRelocs, % LabelMap diff --git a/lib/hipe/main/hipe.app.src b/lib/hipe/main/hipe.app.src index 008393e63c..aa86b6dc5b 100644 --- a/lib/hipe/main/hipe.app.src +++ b/lib/hipe/main/hipe.app.src @@ -225,4 +225,4 @@ {applications, [kernel,stdlib]}, {env, []}, {runtime_dependencies, ["syntax_tools-1.6.14","stdlib-2.5","kernel-3.0", - "erts-7.0","compiler-5.0"]}]}. + "erts-7.1","compiler-5.0"]}]}. diff --git a/lib/hipe/main/hipe.erl b/lib/hipe/main/hipe.erl index ce4f49ffa7..1a4bbf179f 100644 --- a/lib/hipe/main/hipe.erl +++ b/lib/hipe/main/hipe.erl @@ -208,7 +208,8 @@ help_options/0, help_option/1, help_debug_options/0, - version/0]). + version/0, + erts_checksum/0]). -ifndef(DEBUG). -define(DEBUG,true). @@ -216,6 +217,7 @@ -include("hipe.hrl"). -include("../../compiler/src/beam_disasm.hrl"). +-include("../rtl/hipe_literals.hrl"). %%------------------------------------------------------------------- %% Basic type declaration for exported functions of the 'hipe' module @@ -1032,6 +1034,12 @@ post(Res, Icode, Options) -> version() -> ?VERSION_STRING(). +%% @doc Returns checksum identifying the target runtime system. +-spec erts_checksum() -> integer(). + +erts_checksum() -> + ?HIPE_ERTS_CHECKSUM. + %% -------------------------------------------------------------------- %% D O C U M E N T A T I O N - H E L P %% -------------------------------------------------------------------- @@ -1062,6 +1070,8 @@ help() -> " Prints a description of debug options.\n" ++ " version() ->\n" ++ " Returns the HiPE version as a string'.\n" ++ + " erts_checksum() ->\n" ++ + " Returns a checksum identifying the target runtime system.\n" ++ "\n" ++ " For HiPE developers only:\n" ++ " Use `help_hiper()' for information about HiPE's low-level interface\n", diff --git a/lib/hipe/ppc/hipe_ppc_assemble.erl b/lib/hipe/ppc/hipe_ppc_assemble.erl index 4d419978ef..00f28d60e4 100644 --- a/lib/hipe/ppc/hipe_ppc_assemble.erl +++ b/lib/hipe/ppc/hipe_ppc_assemble.erl @@ -50,7 +50,7 @@ assemble(CompiledCode, Closures, Exports, Options) -> DataRelocs = hipe_pack_constants:mk_data_relocs(RefsFromConsts, LabelMap), SSE = hipe_pack_constants:slim_sorted_exportmap(ExportMap,Closures,Exports), SlimRefs = hipe_pack_constants:slim_refs(AccRefs), - Bin = term_to_binary([{?VERSION_STRING(),?HIPE_SYSTEM_CRC}, + Bin = term_to_binary([{?VERSION_STRING(),?HIPE_ERTS_CHECKSUM}, ConstAlign, ConstSize, SC, DataRelocs, % nee LM, LabelMap diff --git a/lib/hipe/rtl/Makefile b/lib/hipe/rtl/Makefile index d2517b13fc..1bf52fe312 100644 --- a/lib/hipe/rtl/Makefile +++ b/lib/hipe/rtl/Makefile @@ -75,7 +75,7 @@ TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) include ../native.mk -ERL_COMPILE_FLAGS += +inline +warn_unused_import +warn_exported_vars +ERL_COMPILE_FLAGS += -Werror +inline +warn_unused_import +warn_exported_vars # ---------------------------------------------------- # Targets diff --git a/lib/hipe/rtl/hipe_rtl_arith.inc b/lib/hipe/rtl/hipe_rtl_arith.inc index 1f455f47ed..1dff56b074 100644 --- a/lib/hipe/rtl/hipe_rtl_arith.inc +++ b/lib/hipe/rtl/hipe_rtl_arith.inc @@ -30,13 +30,13 @@ %% Returns a tuple %% {Res, Sign, Zero, Overflow, Carry} %% Res will be a number in the range -%% MAX_SIGNED_INT >= Res >= MIN_SIGNED_INT +%% MAX_UNSIGNED_INT >= Res >= 0 %% The other four values are flags that are either true or false %% eval_alu(Op, Arg1, Arg2) - when Arg1 =< ?MAX_SIGNED_INT, + when Arg1 =< ?MAX_UNSIGNED_INT, Arg1 >= ?MIN_SIGNED_INT, - Arg2 =< ?MAX_SIGNED_INT, + Arg2 =< ?MAX_UNSIGNED_INT, Arg2 >= ?MIN_SIGNED_INT -> Sign1 = sign_bit(Arg1), @@ -111,7 +111,7 @@ eval_alu(Op, Arg1, Arg2) Res = N = Z = V = C = 0, ?EXIT({"unknown alu op", Op}) end, - {two_comp_to_erl(Res), N, Z, V, C}; + {Res, N, Z, V, C}; eval_alu(Op, Arg1, Arg2) -> ?EXIT({argument_overflow,Op,Arg1,Arg2}). @@ -162,16 +162,9 @@ eval_cond(Cond, Arg1, Arg2) -> sign_bit(Val) -> ((Val bsr ?SIGN_BIT) band 1) =:= 1. -two_comp_to_erl(V) -> - if V > ?MAX_SIGNED_INT -> - - ((?MAX_UNSIGNED_INT + 1) - V); - true -> V - end. - shiftmask(Arg) -> Setbits = ?BITS - Arg, (1 bsl Setbits) - 1. zero(Val) -> Val =:= 0. - diff --git a/lib/hipe/rtl/hipe_rtl_arith_32.erl b/lib/hipe/rtl/hipe_rtl_arith_32.erl index 572556be1c..d790a8b981 100644 --- a/lib/hipe/rtl/hipe_rtl_arith_32.erl +++ b/lib/hipe/rtl/hipe_rtl_arith_32.erl @@ -24,7 +24,8 @@ %% Filename : hipe_rtl_arith_32.erl %% Module : hipe_rtl_arith_32 %% Purpose : To implement 32-bit RTL-arithmetic -%% Notes : The arithmetic works on 32-bit signed integers. +%% Notes : The arithmetic works on 32-bit signed and unsigned +%% integers. %% The implementation is taken from the implementation %% of arithmetic on SPARC. %% XXX: This code is seldom used, and hence also diff --git a/lib/hipe/rtl/hipe_rtl_binary.erl b/lib/hipe/rtl/hipe_rtl_binary.erl index b549073050..9cbab08ee2 100644 --- a/lib/hipe/rtl/hipe_rtl_binary.erl +++ b/lib/hipe/rtl/hipe_rtl_binary.erl @@ -1,3 +1,4 @@ +%% -*- erlang-indent-level: 2 -*- %%% %%% %CopyrightBegin% %%% @@ -28,11 +29,20 @@ -export([gen_rtl/7]). +-export([floorlog2/1, get_word_integer/4, make_size/3, make_size/4]). + +%%-------------------------------------------------------------------- + +-define(BYTE_SHIFT, 3). %% Turn bits into bytes or vice versa +-define(BYTE_SIZE, 8). + +%%-------------------------------------------------------------------- + gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SysLimName, ConstTab) -> case type_of_operation(BsOP) of match -> {hipe_rtl_binary_match:gen_rtl( - BsOP, Dst, Args, TrueLblName, FalseLblName),ConstTab}; + BsOP, Dst, Args, TrueLblName, FalseLblName),ConstTab}; construct -> hipe_rtl_binary_construct:gen_rtl( BsOP, Dst, Args, TrueLblName, FalseLblName, SysLimName, ConstTab) @@ -62,7 +72,7 @@ type_of_operation({bs_init,_,_}) -> construct; type_of_operation({bs_init_bits,_}) -> construct; type_of_operation({bs_init_bits,_,_}) -> construct; type_of_operation({bs_put_binary,_,_}) -> construct; -type_of_operation({bs_put_binary_all,_}) -> construct; +type_of_operation({bs_put_binary_all,_,_}) -> construct; type_of_operation({bs_put_float,_,_,_}) -> construct; type_of_operation({bs_put_integer,_,_,_}) -> construct; type_of_operation({bs_put_string,_,_}) -> construct; @@ -79,3 +89,133 @@ type_of_operation(bs_final) -> construct; type_of_operation({bs_append,_,_,_,_}) -> construct; type_of_operation({bs_private_append,_,_}) -> construct; type_of_operation(bs_init_writable) -> construct. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% Small utility functions: +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +create_lbls(X) when X > 0 -> + [hipe_rtl:mk_new_label()|create_lbls(X-1)]; +create_lbls(0) -> + []. + +%%------------------------------------------------------------------------------ +%% Utilities used by both hipe_rtl_binary_construct and hipe_rtl_binary_match +%%------------------------------------------------------------------------------ + +get_word_integer(Var, Register, SystemLimitLblName, FalseLblName) -> + [EndLbl] = create_lbls(1), + EndName = hipe_rtl:label_name(EndLbl), + get_word_integer(Var, Register,SystemLimitLblName, FalseLblName, EndName, EndName, + [EndLbl]). + +get_word_integer(Var, Register, SystemLimitLblName, FalseLblName, TrueLblName, + BigLblName, Tail) -> + [FixnumLbl, NotFixnumLbl, BignumLbl, SuccessLbl] = create_lbls(4), + [hipe_tagscheme:test_fixnum(Var, hipe_rtl:label_name(FixnumLbl), + hipe_rtl:label_name(NotFixnumLbl), 0.99), + FixnumLbl, + hipe_tagscheme:fixnum_ge(Var, hipe_rtl:mk_imm(hipe_tagscheme:mk_fixnum(0)), + hipe_rtl:label_name(SuccessLbl), FalseLblName, + 0.99), + SuccessLbl, + hipe_tagscheme:untag_fixnum(Register, Var), + hipe_rtl:mk_goto(TrueLblName), + NotFixnumLbl, + hipe_tagscheme:test_pos_bignum_arity(Var, 1, hipe_rtl:label_name(BignumLbl), + FalseLblName, SystemLimitLblName, 0.99), + BignumLbl, + hipe_tagscheme:unsafe_get_one_word_pos_bignum(Register, Var), + hipe_rtl:mk_goto(BigLblName) | Tail]. + +make_size(UnitImm, BitsVar, FailLblName) -> + make_size(UnitImm, BitsVar, FailLblName, FailLblName). + +make_size(1, BitsVar, OverflowLblName, FalseLblName) -> + DstReg = hipe_rtl:mk_new_reg_gcsafe(), + {get_word_integer(BitsVar, DstReg, OverflowLblName, FalseLblName), DstReg}; +make_size(?BYTE_SIZE, BitsVar, OverflowLblName, FalseLblName) -> + DstReg = hipe_rtl:mk_new_reg_gcsafe(), + [FixnumLbl, BignumLbl] = create_lbls(2), + WordBits = hipe_rtl_arch:word_size() * ?BYTE_SIZE, + FixnumLblName = hipe_rtl:label_name(FixnumLbl), + Tail = [BignumLbl, + hipe_rtl:mk_branch(DstReg, 'ltu', + hipe_rtl:mk_imm(1 bsl (WordBits - ?BYTE_SHIFT)), + FixnumLblName, OverflowLblName, 0.99), + FixnumLbl, + hipe_rtl:mk_alu(DstReg, DstReg, sll, hipe_rtl:mk_imm(?BYTE_SHIFT))], + Code = get_word_integer(BitsVar, DstReg, OverflowLblName, FalseLblName, + FixnumLblName, hipe_rtl:label_name(BignumLbl), Tail), + {Code, DstReg}; +make_size(UnitImm, BitsVar, OverflowLblName, FalseLblName) -> + DstReg = hipe_rtl:mk_new_reg_gcsafe(), + UnitList = number2list(UnitImm), + Code = multiply_code(UnitList, BitsVar, DstReg, OverflowLblName, FalseLblName), + {Code, DstReg}. + +multiply_code(List=[Head|_Tail], Variable, Result, OverflowLblName, + FalseLblName) -> + Test = set_high(Head), + Tmp1 = hipe_rtl:mk_new_reg(), + SuccessLbl = hipe_rtl:mk_new_label(), + Register = hipe_rtl:mk_new_reg(), + Code = [hipe_rtl:mk_move(Result, hipe_rtl:mk_imm(0))| + get_word_integer(Variable, Register, OverflowLblName, FalseLblName)] + ++ + [hipe_rtl:mk_alub(Tmp1, Register, 'and', hipe_rtl:mk_imm(Test), + eq, hipe_rtl:label_name(SuccessLbl), + OverflowLblName, 0.99), + SuccessLbl], + multiply_code(List, Register, Result, OverflowLblName, Tmp1, Code). + +multiply_code([ShiftSize|Rest], Register, Result, OverflowLblName, Tmp1, + OldCode) -> + SuccessLbl = hipe_rtl:mk_new_label(), + Code = + OldCode ++ + [hipe_rtl:mk_alu(Tmp1, Register, sll, hipe_rtl:mk_imm(ShiftSize)), + hipe_rtl:mk_alub(Result, Tmp1, 'add', Result, not_overflow, + hipe_rtl:label_name(SuccessLbl), OverflowLblName, 0.99), + SuccessLbl], + multiply_code(Rest, Register, Result, OverflowLblName, Tmp1, Code); +multiply_code([], _Register, _Result, _OverflowLblName, _Tmp1, Code) -> + Code. + +set_high(X) -> + WordBits = hipe_rtl_arch:word_size() * ?BYTE_SIZE, + set_high(min(X, WordBits), WordBits, 0). + +set_high(0, _, Y) -> + Y; +set_high(X, WordBits, Y) -> + set_high(X-1, WordBits, Y+(1 bsl (WordBits-X))). + + +number2list(X) when is_integer(X), X >= 0 -> + number2list(X, []). + +number2list(1, Acc) -> + lists:reverse([0|Acc]); +number2list(0, Acc) -> + lists:reverse(Acc); +number2list(X, Acc) -> + F = floorlog2(X), + number2list(X-(1 bsl F), [F|Acc]). + +floorlog2(X) -> + %% Double-precision floats do not have enough precision to make floorlog2 + %% exact for integers larger than 2^47. + Approx = round(math:log(X)/math:log(2)-0.5), + floorlog2_refine(X, Approx). + +floorlog2_refine(X, Approx) -> + if (1 bsl Approx) > X -> + floorlog2_refine(X, Approx - 1); + (1 bsl (Approx+1)) > X -> + Approx; + true -> + floorlog2_refine(X, Approx + 1) + end. diff --git a/lib/hipe/rtl/hipe_rtl_binary_construct.erl b/lib/hipe/rtl/hipe_rtl_binary_construct.erl index 40bd22aa8e..4403aa552f 100644 --- a/lib/hipe/rtl/hipe_rtl_binary_construct.erl +++ b/lib/hipe/rtl/hipe_rtl_binary_construct.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2009. All Rights Reserved. +%% Copyright Ericsson AB 2007-2015. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,6 +34,10 @@ get_field_from_term/3, set_field_from_pointer/3, get_field_from_pointer/3]). + +-import(hipe_rtl_binary, [floorlog2/1, + get_word_integer/4, + make_size/4]). %%------------------------------------------------------------------------- -include("../main/hipe.hrl"). @@ -94,10 +98,11 @@ gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab var_init_bits(Size, Dst0, Base, Offset, TrueLblName, SystemLimitLblName, FalseLblName); - {bs_put_binary_all, _Flags} -> + {bs_put_binary_all, Unit, _Flags} -> [Src, Base, Offset] = Args, [NewOffset] = get_real(Dst), - put_binary_all(NewOffset, Src, Base, Offset, TrueLblName, FalseLblName); + put_binary_all(NewOffset, Src, Base, Offset, Unit, + TrueLblName, FalseLblName); {bs_put_binary, Size, _Flags} -> case is_illegal_const(Size) of @@ -110,7 +115,9 @@ gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab put_static_binary(NewOffset, Src, Size, Base, Offset, TrueLblName, FalseLblName); [Src, Bits, Base, Offset] -> - {SizeCode, SizeReg} = make_size(Size, Bits, FalseLblName), + {SizeCode, SizeReg} = make_size(Size, Bits, + SystemLimitLblName, + FalseLblName), InCode = put_dynamic_binary(NewOffset, Src, SizeReg, Base, Offset, TrueLblName, FalseLblName), SizeCode ++ InCode @@ -132,7 +139,9 @@ gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab put_float(NewOffset, Src, Base, Offset, Size, CCode, Aligned, LittleEndian, ConstInfo, TrueLblName); [Src, Bits, Base, Offset] -> - {SizeCode, SizeReg} = make_size(Size, Bits, FalseLblName), + {SizeCode, SizeReg} = make_size(Size, Bits, + SystemLimitLblName, + FalseLblName), InCode = float_c_code(NewOffset, Src, Base, Offset, SizeReg, Flags, TrueLblName, FalseLblName), SizeCode ++ InCode @@ -161,6 +170,7 @@ gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab CCode, Aligned, LittleEndian, TrueLblName); [Src, Bits, Base, Offset] -> {SizeCode, SizeReg} = make_size(Size, Bits, + SystemLimitLblName, FalseLblName), CCode = int_c_code(NewOffset, Src, Base, Offset, SizeReg, Flags, @@ -209,6 +219,7 @@ gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab TrueLblName); [Src, Bits, Base, Offset] -> {SizeCode, SizeReg} = make_size(Size, Bits, + SystemLimitLblName, FalseLblName), CCode = int_c_code(NewOffset, Src, Base, Offset, SizeReg, Flags, @@ -293,7 +304,7 @@ gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab [SizeReg] = create_regs(1), [Base] = create_unsafe_regs(1), [hipe_rtl:mk_gctest(?PROC_BIN_WORDSIZE + ?SUB_BIN_WORDSIZE), - check_and_untag_fixnum(Size, SizeReg, FalseLblName), + get_word_integer(Size, SizeReg, SystemLimitLblName, FalseLblName), allocate_writable(DstVar, Base, SizeReg, Zero, Zero), hipe_rtl:mk_goto(TrueLblName)]; @@ -305,7 +316,7 @@ gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab SubBinSize = {sub_binary, binsize}, [get_field_from_term({sub_binary, orig}, Bin, ProcBin), get_field_from_term(SubBinSize, Bin, SubSize), - check_and_untag_fixnum(Size, SizeReg, FalseLblName), + get_word_integer(Size, SizeReg, SystemLimitLblName, FalseLblName), realloc_binary(SizeReg, ProcBin, Base), calculate_sizes(Bin, SizeReg, Offset, EndSubSize, EndSubBitSize), set_field_from_term(SubBinSize, Bin, EndSubSize), @@ -313,20 +324,21 @@ gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab hipe_rtl:mk_move(DstVar, Bin), hipe_rtl:mk_goto(TrueLblName)]; - {bs_append, _U, _F, _B, _Bla} -> + {bs_append, _U, _F, Unit, _Bla} -> [Size, Bin] = Args, [DstVar, Base, Offset] = Dst, [ProcBin] = create_vars(1), [Flags, SizeReg, IsWritable, EndSubSize, EndSubBitSize] = create_regs(5), - [ContLbl,ContLbl2,ContLbl3,WritableLbl,NotWritableLbl] = Lbls = - create_lbls(5), - [ContLblName, ContLbl2Name, ContLbl3Name, Writable, NotWritable] = + [ContLbl,ContLbl2,ContLbl3,ContLbl4,WritableLbl,NotWritableLbl] = + Lbls = create_lbls(6), + [ContLblName, ContLbl2Name, ContLbl3Name, ContLbl4Name, + Writable, NotWritable] = [hipe_rtl:label_name(Lbl) || Lbl <- Lbls], Zero = hipe_rtl:mk_imm(0), SubIsWritable = {sub_binary, is_writable}, [hipe_rtl:mk_gctest(?SUB_BIN_WORDSIZE + ?PROC_BIN_WORDSIZE), - check_and_untag_fixnum(Size, SizeReg, FalseLblName), + get_word_integer(Size, SizeReg, SystemLimitLblName, FalseLblName), hipe_tagscheme:test_bitstr(Bin, ContLblName, FalseLblName, 0.99), ContLbl, hipe_tagscheme:test_subbinary(Bin,ContLbl2Name, NotWritable), @@ -339,17 +351,19 @@ gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab get_field_from_term({proc_bin, flags}, ProcBin, Flags), hipe_rtl:mk_alub(Flags, Flags, 'and', hipe_rtl:mk_imm(?PB_IS_WRITABLE), - eq, NotWritable, Writable, 0.01), + eq, NotWritable, ContLbl4Name, 0.01), + ContLbl4, + calculate_sizes(Bin, SizeReg, Offset, EndSubSize, EndSubBitSize), + is_divisible(Offset, Unit, Writable, FalseLblName), WritableLbl, set_field_from_term(SubIsWritable, Bin, Zero), realloc_binary(SizeReg, ProcBin, Base), - calculate_sizes(Bin, SizeReg, Offset, EndSubSize, EndSubBitSize), hipe_tagscheme:mk_sub_binary(DstVar, EndSubSize, Zero, EndSubBitSize, Zero, hipe_rtl:mk_imm(1), ProcBin), hipe_rtl:mk_goto(TrueLblName), NotWritableLbl, - not_writable_code(Bin, SizeReg, DstVar, Base, Offset, + not_writable_code(Bin, SizeReg, DstVar, Base, Offset, Unit, TrueLblName, FalseLblName)] end, {Code, ConstTab} @@ -361,7 +375,7 @@ gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -not_writable_code(Bin, SizeReg, Dst, Base, Offset, +not_writable_code(Bin, SizeReg, Dst, Base, Offset, Unit, TrueLblName, FalseLblName) -> [SrcBase] = create_unsafe_regs(1), [SrcOffset, SrcSize, TotSize, TotBytes, UsedBytes] = create_regs(5), @@ -372,13 +386,13 @@ not_writable_code(Bin, SizeReg, Dst, Base, Offset, hipe_rtl:mk_alu(TotBytes, TotSize, add, ?LOW_BITS), hipe_rtl:mk_alu(TotBytes, TotBytes, srl, ?BYTE_SHIFT), hipe_rtl:mk_alu(UsedBytes, TotBytes, sll, hipe_rtl:mk_imm(1)), - hipe_rtl:mk_branch(UsedBytes, ge, hipe_rtl:mk_imm(256), + hipe_rtl:mk_branch(UsedBytes, geu, hipe_rtl:mk_imm(256), AllLblName, IncLblName), IncLbl, hipe_rtl:mk_move(UsedBytes, hipe_rtl:mk_imm(256)), AllLbl, allocate_writable(Dst, Base, UsedBytes, TotBytes, TotSize), - put_binary_all(Offset, Bin, Base, hipe_rtl:mk_imm(0), + put_binary_all(Offset, Bin, Base, hipe_rtl:mk_imm(0), Unit, TrueLblName, FalseLblName)]. allocate_writable(Dst, Base, UsedBytes, TotBytes, TotSize) -> @@ -397,16 +411,6 @@ allocate_writable(Dst, Base, UsedBytes, TotBytes, TotSize) -> hipe_tagscheme:mk_sub_binary(Dst, EndSubSize, Zero, EndSubBitSize, Zero, hipe_rtl:mk_imm(1), ProcBin)]. -check_and_untag_fixnum(Size, SizeReg, FalseLblName) -> - [ContLbl,NextLbl] = Lbls = create_lbls(2), - [ContLblName,NextLblName] = get_label_names(Lbls), - [hipe_tagscheme:test_fixnum(Size, ContLblName, FalseLblName, 0.99), - ContLbl, - hipe_tagscheme:untag_fixnum(SizeReg,Size), - hipe_rtl:mk_branch(SizeReg, ge, hipe_rtl:mk_imm(0), NextLblName, - FalseLblName), - NextLbl]. - realloc_binary(SizeReg, ProcBin, Base) -> [NoReallocLbl, ReallocLbl, NextLbl, ContLbl] = Lbls = create_lbls(4), [NoReallocLblName, ReallocLblName, NextLblName, ContLblName] = @@ -428,7 +432,7 @@ realloc_binary(SizeReg, ProcBin, Base) -> set_field_from_term(ProcBinFlagsTag, ProcBin, Flags), get_field_from_term(ProcBinValTag, ProcBin, BinPointer), get_field_from_pointer(BinOrigSizeTag, BinPointer, OrigSize), - hipe_rtl:mk_branch(OrigSize, 'lt', ResultingSize, + hipe_rtl:mk_branch(OrigSize, 'ltu', ResultingSize, ReallocLblName, NoReallocLblName), NoReallocLbl, get_field_from_term(ProcBinBytesTag, ProcBin, Base), @@ -669,14 +673,14 @@ var_init2(Size, Dst, Base, Offset, TrueLblName, SystemLimitLblName, FalseLblName WordSize = hipe_rtl_arch:word_size(), [ContLbl,HeapLbl,REFCLbl,NextLbl] = create_lbls(4), [USize,Tmp] = create_unsafe_regs(2), - [get_32_bit_value(Size, USize, SystemLimitLblName, FalseLblName), - hipe_rtl:mk_branch(USize, le, hipe_rtl:mk_imm(?MAX_BINSIZE), - hipe_rtl:label_name(ContLbl), - SystemLimitLblName), + [get_word_integer(Size, USize, SystemLimitLblName, FalseLblName), + hipe_rtl:mk_branch(USize, leu, hipe_rtl:mk_imm(?MAX_BINSIZE), + hipe_rtl:label_name(ContLbl), + SystemLimitLblName), ContLbl, hipe_rtl:mk_move(Offset, hipe_rtl:mk_imm(0)), - hipe_rtl:mk_branch(USize, le, hipe_rtl:mk_imm(?MAX_HEAP_BIN_SIZE), - hipe_rtl:label_name(HeapLbl), + hipe_rtl:mk_branch(USize, leu, hipe_rtl:mk_imm(?MAX_HEAP_BIN_SIZE), + hipe_rtl:label_name(HeapLbl), hipe_rtl:label_name(REFCLbl)), HeapLbl, hipe_rtl:mk_alu(Tmp, USize, add, hipe_rtl:mk_imm(3*WordSize-1)), @@ -694,8 +698,8 @@ var_init2(Size, Dst, Base, Offset, TrueLblName, SystemLimitLblName, FalseLblName hipe_rtl:mk_goto(TrueLblName)]. var_init_bits(Size, Dst, Base, Offset, TrueLblName, SystemLimitLblName, FalseLblName) -> - [HeapLbl,REFCLbl,NextLbl,NoSubLbl,SubLbl,ContLbl, - NoCreateSubBin, CreateSubBin, JoinLbl, JoinLbl2] = create_lbls(10), + [HeapLbl,REFCLbl,NextLbl,NoSubLbl,SubLbl, + NoCreateSubBin, CreateSubBin, JoinLbl, JoinLbl2] = create_lbls(9), [USize,ByteSize,TotByteSize,OffsetBits] = create_regs(4), [TmpDst] = create_unsafe_regs(1), Log2WordSize = hipe_rtl_arch:log2_word_size(), @@ -705,7 +709,7 @@ var_init_bits(Size, Dst, Base, Offset, TrueLblName, SystemLimitLblName, FalseLbl ?PROC_BIN_WORDSIZE) + ?SUB_BIN_WORDSIZE, Zero = hipe_rtl:mk_imm(0), [hipe_rtl:mk_gctest(MaximumWords), - get_32_bit_value(Size, USize, SystemLimitLblName, FalseLblName), + get_word_integer(Size, USize, SystemLimitLblName, FalseLblName), hipe_rtl:mk_alu(ByteSize, USize, srl, ?BYTE_SHIFT), hipe_rtl:mk_alub(OffsetBits, USize, 'and', ?LOW_BITS, eq, hipe_rtl:label_name(NoSubLbl), @@ -716,11 +720,7 @@ var_init_bits(Size, Dst, Base, Offset, TrueLblName, SystemLimitLblName, FalseLbl SubLbl, hipe_rtl:mk_alu(TotByteSize, ByteSize, 'add', hipe_rtl:mk_imm(1)), JoinLbl, - hipe_rtl:mk_branch(USize, le, hipe_rtl:mk_imm(?MAX_BINSIZE), - hipe_rtl:label_name(ContLbl), - SystemLimitLblName), - ContLbl, - hipe_rtl:mk_branch(TotByteSize, 'le', hipe_rtl:mk_imm(?MAX_HEAP_BIN_SIZE), + hipe_rtl:mk_branch(TotByteSize, 'leu', hipe_rtl:mk_imm(?MAX_HEAP_BIN_SIZE), hipe_rtl:label_name(HeapLbl), hipe_rtl:label_name(REFCLbl)), HeapLbl, @@ -743,13 +743,16 @@ var_init_bits(Size, Dst, Base, Offset, TrueLblName, SystemLimitLblName, FalseLbl hipe_rtl:mk_move(Dst, TmpDst), hipe_rtl:mk_goto(TrueLblName)]. -put_binary_all(NewOffset, Src, Base, Offset, TLName, FLName) -> +put_binary_all(NewOffset, Src, Base, Offset, Unit, TLName, FLName) -> [SrcBase,SrcOffset,NumBits] = create_regs(3), + [ContLbl] = create_lbls(1), CCode = binary_c_code(NewOffset, Src, Base, Offset, NumBits, TLName), AlignedCode = copy_aligned_bytes(SrcBase, SrcOffset, NumBits, Base, Offset, NewOffset, TLName), - get_base_offset_size(Src, SrcBase, SrcOffset, NumBits,FLName) ++ - test_alignment(SrcOffset, NumBits, Offset, AlignedCode, CCode). + [get_base_offset_size(Src, SrcBase, SrcOffset, NumBits,FLName), + is_divisible(NumBits, Unit, hipe_rtl:label_name(ContLbl), FLName), + ContLbl + |test_alignment(SrcOffset, NumBits, Offset, AlignedCode, CCode)]. test_alignment(SrcOffset, NumBits, Offset, AlignedCode, CCode) -> [Tmp] = create_regs(1), @@ -976,7 +979,7 @@ copy_string(StringBase, StringSize, BinBase, BinOffset, NewOffset, TrueLblName) small_check(SizeVar, CopySize, FalseLblName) -> SuccessLbl = hipe_rtl:mk_new_label(), - [hipe_rtl:mk_branch(SizeVar, le, CopySize, + [hipe_rtl:mk_branch(SizeVar, leu, CopySize, hipe_rtl:label_name(SuccessLbl), FalseLblName), SuccessLbl]. @@ -1192,7 +1195,10 @@ copy_little_word(Base, Offset, NewOffset, Word) -> hipe_rtl:mk_store(Base, TmpOffset, Word, byte), hipe_rtl:mk_alu(NewOffset, Offset, 'add', hipe_rtl:mk_imm(32))]. -copy_offset_int_big(Base, Offset, NewOffset, Size, Tmp1) when is_integer(Size) -> +copy_offset_int_big(_Base, Offset, NewOffset, 0, _Tmp1) -> + [hipe_rtl:mk_move(NewOffset, Offset)]; +copy_offset_int_big(Base, Offset, NewOffset, Size, Tmp1) + when is_integer(Size), Size > 0 -> Tmp2 = hipe_rtl:mk_new_reg(), Tmp3 = hipe_rtl:mk_new_reg(), Tmp4 = hipe_rtl:mk_new_reg(), @@ -1203,7 +1209,7 @@ copy_offset_int_big(Base, Offset, NewOffset, Size, Tmp1) when is_integer(Size) - Tmp9 = hipe_rtl:mk_new_reg(), OldByte = hipe_rtl:mk_new_reg(), TmpOffset = hipe_rtl:mk_new_reg(), - BranchLbl = hipe_rtl:mk_new_label(), + BranchLbl = hipe_rtl:mk_new_label(), BodyLbl = hipe_rtl:mk_new_label(), EndLbl = hipe_rtl:mk_new_label(), NextLbl = hipe_rtl:mk_new_label(), @@ -1276,89 +1282,18 @@ copy_float_big(Base, Offset, NewOffset, Src, FalseLblName, TrueLblName, var) -> hipe_tagscheme:test_flonum(Src, hipe_rtl:label_name(SuccessLbl), FalseLblName, 0.99) ++ [SuccessLbl|copy_float_big(Base, Offset, NewOffset, Src, FalseLblName, TrueLblName, pass)]. -make_size(1, BitsVar, FalseLblName) -> - [DstReg] = create_regs(1), - {first_part(BitsVar, DstReg, FalseLblName), DstReg}; -make_size(?BYTE_SIZE, BitsVar, FalseLblName) -> - [DstReg] = create_regs(1), - Code = - first_part(BitsVar, DstReg, FalseLblName) ++ - [hipe_rtl:mk_alu(DstReg, DstReg, 'sll', ?BYTE_SHIFT)], - {Code, DstReg}; -make_size(UnitImm, BitsVar, FalseLblName) -> - [DstReg] = create_regs(1), - UnitList = number2list(UnitImm), - Code = multiply_code(UnitList, BitsVar, DstReg, FalseLblName), - {Code, DstReg}. - -multiply_code(List=[Head|_Tail], Variable, Result, FalseLblName) -> - Test = set_high(Head), - Tmp1 = hipe_rtl:mk_new_reg(), - SuccessLbl = hipe_rtl:mk_new_label(), - Register = hipe_rtl:mk_new_reg(), - Code = [hipe_rtl:mk_move(Result, hipe_rtl:mk_imm(0))| - first_part(Variable, Register, FalseLblName)] - ++ - [hipe_rtl:mk_alub(Tmp1, Register, 'and', hipe_rtl:mk_imm(Test), - 'eq', hipe_rtl:label_name(SuccessLbl), - FalseLblName, 0.99), - SuccessLbl], - multiply_code(List, Register, Result, FalseLblName, Tmp1, Code). - -multiply_code([ShiftSize|Rest], Register, Result, FalseLblName, Tmp1, OldCode) -> - SuccessLbl = hipe_rtl:mk_new_label(), - Code = OldCode ++ [hipe_rtl:mk_alu(Tmp1, Register, 'sll', - hipe_rtl:mk_imm(ShiftSize)), - hipe_rtl:mk_alub(Result, Tmp1, 'add', Result, not_overflow, hipe_rtl:label_name(SuccessLbl), FalseLblName, 0.99), - SuccessLbl], - multiply_code(Rest, Register, Result, FalseLblName, Tmp1, Code); -multiply_code([], _Register, _Result, _FalseLblName, _Tmp1, Code) -> - Code. - -number2list(X) when is_integer(X), X >= 0 -> - number2list(X, []). - -number2list(1, Acc) -> - lists:reverse([0|Acc]); -number2list(0, Acc) -> - lists:reverse(Acc); -number2list(X, Acc) -> - F = floorlog2(X), - number2list(X-(1 bsl F), [F|Acc]). - -floorlog2(X) -> - round(math:log(X)/math:log(2)-0.5). - -set_high(X) -> - set_high(X, 0). - -set_high(0, Y) -> - Y; -set_high(X, Y) -> - set_high(X-1, Y+(1 bsl (27-X))). - -get_32_bit_value(Size, USize, SystemLimitLblName, NegLblName) -> - Lbls = [FixLbl, BigLbl, OkLbl, PosBigLbl] = create_lbls(4), - [FixLblName, BigLblName, OkLblName, PosBigLblName] = [hipe_rtl:label_name(Lbl) || Lbl <- Lbls], - [hipe_tagscheme:test_fixnum(Size, FixLblName, BigLblName, 0.99), - FixLbl, - hipe_tagscheme:untag_fixnum(USize, Size), - hipe_rtl:mk_branch(USize, ge, hipe_rtl:mk_imm(0), OkLblName, NegLblName), - BigLbl, - hipe_tagscheme:test_pos_bignum(Size, PosBigLblName, NegLblName, 0.99), - PosBigLbl, - hipe_tagscheme:get_one_word_pos_bignum(USize, Size, SystemLimitLblName), - OkLbl]. - - -first_part(Var, Register, FalseLblName) -> - [SuccessLbl1, SuccessLbl2] = create_lbls(2), - [hipe_tagscheme:test_fixnum(Var, hipe_rtl:label_name(SuccessLbl1), - FalseLblName, 0.99), - SuccessLbl1, - hipe_tagscheme:fixnum_ge(Var, hipe_rtl:mk_imm(hipe_tagscheme:mk_fixnum(0)), - hipe_rtl:label_name(SuccessLbl2), FalseLblName, 0.99), - SuccessLbl2, - hipe_tagscheme:untag_fixnum(Register, Var)]. - - +is_divisible(_Dividend, 1, SuccLbl, _FailLbl) -> + [hipe_rtl:mk_goto(SuccLbl)]; +is_divisible(Dividend, Divisor, SuccLbl, FailLbl) -> + Log2 = floorlog2(Divisor), + case Divisor =:= 1 bsl Log2 of + true -> %% Divisor is a power of 2 + %% Test that the Log2-1 lowest bits are clear + Mask = hipe_rtl:mk_imm(Divisor - 1), + [Tmp] = create_regs(1), + [hipe_rtl:mk_alub(Tmp, Dividend, 'and', Mask, eq, SuccLbl, FailLbl, 0.99)]; + false -> + %% We need division, fall back to a primop + [hipe_rtl:mk_call([], is_divisible, [Dividend, hipe_rtl:mk_imm(Divisor)], + SuccLbl, FailLbl, not_remote)] + end. diff --git a/lib/hipe/rtl/hipe_rtl_binary_match.erl b/lib/hipe/rtl/hipe_rtl_binary_match.erl index 364aab1b6f..be4c35dae0 100644 --- a/lib/hipe/rtl/hipe_rtl_binary_match.erl +++ b/lib/hipe/rtl/hipe_rtl_binary_match.erl @@ -2,7 +2,7 @@ %%% %%% %CopyrightBegin% %%% -%%% Copyright Ericsson AB 2007-2013. All Rights Reserved. +%%% Copyright Ericsson AB 2007-2015. All Rights Reserved. %%% %%% Licensed under the Apache License, Version 2.0 (the "License"); %%% you may not use this file except in compliance with the License. @@ -31,11 +31,12 @@ -import(hipe_tagscheme, [set_field_from_term/3, get_field_from_term/3]). +-import(hipe_rtl_binary, [make_size/3]). + -include("hipe_literals.hrl"). %%-------------------------------------------------------------------- --define(MAX_BINSIZE, trunc(?MAX_HEAP_BIN_SIZE / hipe_rtl_arch:word_size()) + 2). -define(BYTE_SHIFT, 3). %% Turn bits into bytes or vice versa -define(LOW_BITS, 7). %% Three lowest bits set -define(BYTE_SIZE, 8). @@ -181,17 +182,20 @@ gen_rtl({bs_get_binary, Size, Flags}, [Dst, NewMs], Args, [hipe_rtl:mk_goto(FalseLblName)]; false -> Unsafe = unsafe(Flags), - case Args of - [Ms] -> - SizeReg = hipe_rtl:mk_new_reg(), - SizeCode = [hipe_rtl:mk_move(SizeReg, hipe_rtl:mk_imm(Size))]; - [Ms, BitsVar] -> - {SizeCode, SizeReg} = make_size(Size, BitsVar, FalseLblName) - end, - InCode = get_binary(Dst, Ms, SizeReg, Unsafe, + {OldMs, SizeReg, SizeCode} = + case Args of + [Ms] -> + SzReg = hipe_rtl:mk_new_reg(), + SzCode = [hipe_rtl:mk_move(SzReg, hipe_rtl:mk_imm(Size))], + {Ms, SzReg, SzCode}; + [Ms, BitsVar] -> + {SzCode, SzReg} = make_size(Size, BitsVar, FalseLblName), + {Ms, SzReg, SzCode} + end, + InCode = get_binary(Dst, OldMs, SizeReg, Unsafe, TrueLblName, FalseLblName), [hipe_rtl:mk_gctest(?SUB_BIN_WORDSIZE)] ++ - update_ms(NewMs, Ms) ++ SizeCode ++ InCode + update_ms(NewMs, OldMs) ++ SizeCode ++ InCode end; %% ----- bs_get_utf8 ----- gen_rtl(bs_get_utf8, [Dst, NewMs], [Ms], TrueLblName, FalseLblName) -> @@ -230,14 +234,26 @@ gen_rtl({bs_skip_bits_all, Unit, _Flags}, Dst, [Ms], skip_bits_all(Unit, Ms, TrueLblName, FalseLblName); %% ----- bs_skip_bits ----- gen_rtl({bs_skip_bits, Bits}, Dst, [Ms|Args], TrueLblName, FalseLblName) -> + MaxValue = (1 bsl (hipe_rtl_arch:word_size() * ?BYTE_SIZE)), opt_update_ms(Dst, Ms) ++ - case Args of - [] -> - skip_bits2(Ms, hipe_rtl:mk_imm(Bits), TrueLblName, FalseLblName); - [Arg] -> - {SizeCode, SizeReg} = make_size(Bits, Arg, FalseLblName), - InCode = skip_bits2(Ms, SizeReg, TrueLblName, FalseLblName), - SizeCode ++ InCode + case Bits < MaxValue of + true -> + case Args of + [] -> + skip_bits2(Ms, hipe_rtl:mk_imm(Bits), TrueLblName, FalseLblName); + [Arg] -> + {SizeCode, SizeReg} = make_size(Bits, Arg, FalseLblName), + InCode = skip_bits2(Ms, SizeReg, TrueLblName, FalseLblName), + SizeCode ++ InCode + end; + false -> % handle overflow case + case Args of + [] -> + [hipe_rtl:mk_goto(FalseLblName)]; + [Arg] -> + [hipe_rtl:mk_branch(Arg, 'eq', hipe_tagscheme:mk_fixnum(0), + TrueLblName, FalseLblName, 0.5)] + end end; %% ----- bs_restore ----- gen_rtl({bs_restore, Slot}, [NewMs], [Ms], TrueLblName, _FalseLblName) -> @@ -318,32 +334,50 @@ float_get_c_code(Dst1, Ms, Size, Flags, TrueLblName, FalseLblName) -> get_c_code(Func, Dst1, Ms, Size, Flags, TrueLblName, FalseLblName) -> SizeReg = hipe_rtl:mk_new_reg_gcsafe(), FlagsReg = hipe_rtl:mk_new_reg_gcsafe(), + RetReg = hipe_rtl:mk_new_reg_gcsafe(), MatchBuf = hipe_rtl:mk_new_reg(), RetLabel = hipe_rtl:mk_new_label(), + OkLabel = hipe_rtl:mk_new_label(), NonVal = hipe_rtl:mk_imm(hipe_tagscheme:mk_non_value()), [hipe_rtl:mk_move(SizeReg, Size), hipe_rtl:mk_move(FlagsReg, hipe_rtl:mk_imm(Flags)), hipe_tagscheme:extract_matchbuffer(MatchBuf, Ms), - hipe_rtl_arch:call_bif([Dst1], Func, [SizeReg, FlagsReg, MatchBuf], + hipe_rtl_arch:call_bif([RetReg], Func, [SizeReg, FlagsReg, MatchBuf], hipe_rtl:label_name(RetLabel), FalseLblName), RetLabel, - hipe_rtl:mk_branch(Dst1, eq, NonVal, FalseLblName, TrueLblName, 0.01)]. + hipe_rtl:mk_branch(RetReg, eq, NonVal, FalseLblName, + hipe_rtl:label_name(OkLabel), 0.01), + OkLabel, + hipe_rtl:mk_move(Dst1, RetReg), + hipe_rtl:mk_goto(TrueLblName)]. utf8_get_c_code(Dst, Ms, TrueLblName, FalseLblName) -> + RetReg = hipe_rtl:mk_new_reg_gcsafe(), + OkLabel = hipe_rtl:mk_new_label(), MatchBuf = hipe_rtl:mk_new_reg(), NonVal = hipe_rtl:mk_imm(hipe_tagscheme:mk_non_value()), [hipe_tagscheme:extract_matchbuffer(MatchBuf, Ms), - hipe_rtl_arch:call_bif([Dst], bs_get_utf8, [MatchBuf], [], []), - hipe_rtl:mk_branch(Dst, eq, NonVal, FalseLblName, TrueLblName, 0.01)]. + hipe_rtl_arch:call_bif([RetReg], bs_get_utf8, [MatchBuf], [], []), + hipe_rtl:mk_branch(RetReg, eq, NonVal, FalseLblName, + hipe_rtl:label_name(OkLabel), 0.01), + OkLabel, + hipe_rtl:mk_move(Dst, RetReg), + hipe_rtl:mk_goto(TrueLblName)]. utf16_get_c_code(Flags, Dst, Ms, TrueLblName, FalseLblName) -> + RetReg = hipe_rtl:mk_new_reg_gcsafe(), + OkLabel = hipe_rtl:mk_new_label(), MatchBuf = hipe_rtl:mk_new_reg(), NonVal = hipe_rtl:mk_imm(hipe_tagscheme:mk_non_value()), FlagsReg = hipe_rtl:mk_new_reg_gcsafe(), [hipe_tagscheme:extract_matchbuffer(MatchBuf, Ms), hipe_rtl:mk_move(FlagsReg, hipe_rtl:mk_imm(Flags)), - hipe_rtl_arch:call_bif([Dst], bs_get_utf16, [MatchBuf, FlagsReg], [], []), - hipe_rtl:mk_branch(Dst, eq, NonVal, FalseLblName, TrueLblName, 0.01)]. + hipe_rtl_arch:call_bif([RetReg], bs_get_utf16, [MatchBuf, FlagsReg], [], []), + hipe_rtl:mk_branch(RetReg, eq, NonVal, FalseLblName, + hipe_rtl:label_name(OkLabel), 0.01), + OkLabel, + hipe_rtl:mk_move(Dst, RetReg), + hipe_rtl:mk_goto(TrueLblName)]. validate_unicode_retract_c_code(Src, Ms, TrueLblName, FalseLblName) -> MatchBuf = hipe_rtl:mk_new_reg(), @@ -802,10 +836,10 @@ create_lbls(0) -> create_lbls(X) when X > 0 -> [hipe_rtl:mk_new_label()|create_lbls(X-1)]. -make_dyn_prep(SizeReg, CCode) -> +make_dyn_prep(SizeReg, CCode) -> [CLbl, SuccessLbl] = create_lbls(2), - Init = [hipe_rtl:mk_branch(SizeReg, le, hipe_rtl:mk_imm(?MAX_SMALL_BITS), - hipe_rtl:label_name(SuccessLbl), + Init = [hipe_rtl:mk_branch(SizeReg, leu, hipe_rtl:mk_imm(?MAX_SMALL_BITS), + hipe_rtl:label_name(SuccessLbl), hipe_rtl:label_name(CLbl)), SuccessLbl], End = [CLbl|CCode], @@ -850,8 +884,8 @@ get_unaligned_int_to_reg(Reg, Size, Base, Offset, LowBits, Shiftr, Type) -> hipe_rtl:mk_imm((WordSize-MinLoad)*?BYTE_SIZE))]; {_, WordSize} -> UnsignedBig = {unsigned, big}, - [hipe_rtl:mk_branch(TotBits, le, hipe_rtl:mk_imm(MinLoad*?BYTE_SIZE), - hipe_rtl:label_name(LessLbl), + [hipe_rtl:mk_branch(TotBits, leu, hipe_rtl:mk_imm(MinLoad*?BYTE_SIZE), + hipe_rtl:label_name(LessLbl), hipe_rtl:label_name(MoreLbl)), LessLbl, load_bytes(LoadDst, Base, ByteOffset, Type, MinLoad), @@ -911,7 +945,7 @@ get_big_unknown_int(Dst1, Base, Offset, NewOffset, hipe_rtl:mk_alu(ByteOffset, Offset, srl, hipe_rtl:mk_imm(?BYTE_SHIFT)), load_bytes(LoadDst, Base, ByteOffset, Type, 1), BackLbl, - hipe_rtl:mk_branch(ByteOffset, le, Limit, hipe_rtl:label_name(LoopLbl), + hipe_rtl:mk_branch(ByteOffset, leu, Limit, hipe_rtl:label_name(LoopLbl), hipe_rtl:label_name(EndLbl)), LoopLbl, load_bytes(Tmp, Base, ByteOffset, {unsigned, big}, 1), @@ -940,8 +974,8 @@ get_little_unknown_int(Dst1, Base, Offset, NewOffset, hipe_rtl:mk_alu(Limit, Tmp, srl, hipe_rtl:mk_imm(?BYTE_SHIFT)), hipe_rtl:mk_move(ShiftReg, hipe_rtl:mk_imm(0)), BackLbl, - hipe_rtl:mk_branch(ByteOffset, lt, Limit, - hipe_rtl:label_name(LoopLbl), + hipe_rtl:mk_branch(ByteOffset, ltu, Limit, + hipe_rtl:label_name(LoopLbl), hipe_rtl:label_name(DoneLbl)), LoopLbl, load_bytes(Tmp, Base, ByteOffset, {unsigned, big}, 1), @@ -1057,7 +1091,7 @@ load_bytes(Dst, Base, Offset, {Signedness, Endianness}, X) when X > 1 -> hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)), hipe_rtl:mk_alu(Dst, Dst, sll, hipe_rtl:mk_imm(8)), hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1), - hipe_rtl:mk_branch(Offset, lt, Limit, hipe_rtl:label_name(LoopLbl), + hipe_rtl:mk_branch(Offset, ltu, Limit, hipe_rtl:label_name(LoopLbl), hipe_rtl:label_name(EndLbl)), EndLbl]; little -> @@ -1069,7 +1103,7 @@ load_bytes(Dst, Base, Offset, {Signedness, Endianness}, X) when X > 1 -> hipe_rtl:mk_load(Tmp1, Base, TmpOffset, byte, Signedness), hipe_rtl:mk_alu(Dst, Dst, sll, hipe_rtl:mk_imm(8)), hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1), - hipe_rtl:mk_branch(Offset, lt, TmpOffset, hipe_rtl:label_name(LoopLbl), + hipe_rtl:mk_branch(Offset, ltu, TmpOffset, hipe_rtl:label_name(LoopLbl), hipe_rtl:label_name(EndLbl)), EndLbl, hipe_rtl:mk_move(Offset, Limit)] @@ -1085,78 +1119,5 @@ create_gcsafe_regs(X) when X > 0 -> create_gcsafe_regs(0) -> []. -first_part(Var, Register, FalseLblName) -> - [SuccessLbl1, SuccessLbl2] = create_lbls(2), - [hipe_tagscheme:test_fixnum(Var, hipe_rtl:label_name(SuccessLbl1), - FalseLblName, 0.99), - SuccessLbl1, - hipe_tagscheme:fixnum_ge(Var, hipe_rtl:mk_imm(hipe_tagscheme:mk_fixnum(0)), - hipe_rtl:label_name(SuccessLbl2), FalseLblName, 0.99), - SuccessLbl2, - hipe_tagscheme:untag_fixnum(Register, Var)]. - -make_size(1, BitsVar, FalseLblName) -> - [DstReg] = create_regs(1), - {first_part(BitsVar, DstReg, FalseLblName), DstReg}; -make_size(?BYTE_SIZE, BitsVar, FalseLblName) -> - [DstReg] = create_regs(1), - Code = - first_part(BitsVar, DstReg, FalseLblName) ++ - [hipe_rtl:mk_alu(DstReg, DstReg, sll, hipe_rtl:mk_imm(?BYTE_SHIFT))], - {Code, DstReg}; -make_size(UnitImm, BitsVar, FalseLblName) -> - [DstReg] = create_regs(1), - UnitList = number2list(UnitImm), - Code = multiply_code(UnitList, BitsVar, DstReg, FalseLblName), - {Code, DstReg}. - -multiply_code(List=[Head|_Tail], Variable, Result, FalseLblName) -> - Test = set_high(Head), - Tmp1 = hipe_rtl:mk_new_reg(), - SuccessLbl = hipe_rtl:mk_new_label(), - Register = hipe_rtl:mk_new_reg(), - Code = [hipe_rtl:mk_move(Result, hipe_rtl:mk_imm(0))| - first_part(Variable, Register, FalseLblName)] - ++ - [hipe_rtl:mk_alub(Tmp1, Register, 'and', hipe_rtl:mk_imm(Test), - eq, hipe_rtl:label_name(SuccessLbl), - FalseLblName, 0.99), - SuccessLbl], - multiply_code(List, Register, Result, FalseLblName, Tmp1, Code). - -multiply_code([ShiftSize|Rest], Register, Result, FalseLblName, Tmp1, OldCode) -> - SuccessLbl = hipe_rtl:mk_new_label(), - Code = - OldCode ++ - [hipe_rtl:mk_alu(Tmp1, Register, sll, hipe_rtl:mk_imm(ShiftSize)), - hipe_rtl:mk_alub(Result, Tmp1, 'add', Result, not_overflow, - hipe_rtl:label_name(SuccessLbl), FalseLblName, 0.99), - SuccessLbl], - multiply_code(Rest, Register, Result, FalseLblName, Tmp1, Code); -multiply_code([], _Register, _Result, _FalseLblName, _Tmp1, Code) -> - Code. - -number2list(X) when is_integer(X), X >= 0 -> - number2list(X, []). - -number2list(1, Acc) -> - lists:reverse([0|Acc]); -number2list(0, Acc) -> - lists:reverse(Acc); -number2list(X, Acc) -> - F = floorlog2(X), - number2list(X-(1 bsl F), [F|Acc]). - -floorlog2(X) -> - round(math:log(X)/math:log(2)-0.5). - -set_high(X) -> - set_high(X, 0). - -set_high(0, Y) -> - Y; -set_high(X, Y) -> - set_high(X-1, Y+(1 bsl (27-X))). - is_illegal_const(Const) -> Const >= 1 bsl (hipe_rtl_arch:word_size() * ?BYTE_SIZE) orelse Const < 0. diff --git a/lib/hipe/rtl/hipe_tagscheme.erl b/lib/hipe/rtl/hipe_tagscheme.erl index 1bb4c3cc5f..8825a3ade3 100644 --- a/lib/hipe/rtl/hipe_tagscheme.erl +++ b/lib/hipe/rtl/hipe_tagscheme.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2013. All Rights Reserved. +%% Copyright Ericsson AB 2001-2015. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -41,7 +41,8 @@ test_any_pid/4, test_any_port/4, test_ref/4, test_fun/4, test_fun2/5, test_matchstate/4, test_binary/4, test_bitstr/4, test_list/4, test_map/4, - test_integer/4, test_number/4, test_tuple_N/5]). + test_integer/4, test_number/4, test_tuple_N/5, + test_pos_bignum_arity/6]). -export([realtag_fixnum/2, tag_fixnum/2, realuntag_fixnum/2, untag_fixnum/2]). -export([test_two_fixnums/3, test_fixnums/4, unsafe_fixnum_add/3, unsafe_fixnum_sub/3, @@ -53,9 +54,10 @@ -export([unsafe_closure_element/3]). -export([mk_fun_header/0, tag_fun/2]). -export([unsafe_untag_float/2, unsafe_tag_float/2]). --export([mk_sub_binary/6,mk_sub_binary/7]). +-export([mk_sub_binary/6, mk_sub_binary/7]). -export([unsafe_mk_big/3, unsafe_load_float/3]). --export([bignum_sizeneed/1,bignum_sizeneed_code/2, get_one_word_pos_bignum/3]). +-export([bignum_sizeneed/1, bignum_sizeneed_code/2, get_one_word_pos_bignum/3, + unsafe_get_one_word_pos_bignum/2]). -export([test_subbinary/3, test_heap_binary/3]). -export([create_heap_binary/3, create_refc_binary/3, create_refc_binary/4]). -export([create_matchstate/6, convert_matchstate/1, compare_matchstate/4]). @@ -349,6 +351,24 @@ test_pos_bignum(X, TrueLab, FalseLab, Pred) -> mask_and_compare(Tmp, BigMask, ?TAG_HEADER_POS_BIG, TrueLab, FalseLab, Pred)]. +test_pos_bignum_arity(X, Arity, TrueLab, NotPosBignumLab, FalseLab, Pred) -> + Tmp = hipe_rtl:mk_new_reg_gcsafe(), + BoxedLab = hipe_rtl:mk_new_label(), + HeaderImm = hipe_rtl:mk_imm(mk_header(Arity, ?TAG_HEADER_POS_BIG)), + [test_is_boxed(X, hipe_rtl:label_name(BoxedLab), NotPosBignumLab, Pred), + BoxedLab, + get_header(Tmp, X)] ++ + case NotPosBignumLab =:= FalseLab of + true -> []; + false -> + BignumLab = hipe_rtl:mk_new_label(), + BigMask = ?TAG_HEADER_MASK, + [mask_and_compare(Tmp, BigMask, ?TAG_HEADER_POS_BIG, + hipe_rtl:label_name(BignumLab), NotPosBignumLab, Pred), + BignumLab] + end ++ + [hipe_rtl:mk_branch(Tmp, 'eq', HeaderImm, TrueLab, FalseLab, Pred)]. + test_matchstate(X, TrueLab, FalseLab, Pred) -> Tmp = hipe_rtl:mk_new_reg_gcsafe(), HalfTrueLab = hipe_rtl:mk_new_label(), @@ -963,13 +983,16 @@ get_one_word_pos_bignum(USize, Size, Fail) -> Header = hipe_rtl:mk_new_reg(), HalfLbl = hipe_rtl:mk_new_label(), HalfLblName = hipe_rtl:label_name(HalfLbl), - WordSize = hipe_rtl_arch:word_size(), PosHead = hipe_rtl:mk_imm(mk_header(1, ?TAG_HEADER_POS_BIG)), [get_header(Header, Size), hipe_rtl:mk_branch(Header, eq, PosHead, HalfLblName, Fail), - HalfLbl, - hipe_rtl:mk_load(USize, Size, hipe_rtl:mk_imm(1*WordSize - -?TAG_PRIMARY_BOXED))]. + HalfLbl | + unsafe_get_one_word_pos_bignum(USize, Size)]. + +unsafe_get_one_word_pos_bignum(USize, Size) -> + WordSize = hipe_rtl_arch:word_size(), + Imm = hipe_rtl:mk_imm(1*WordSize-?TAG_PRIMARY_BOXED), + [hipe_rtl:mk_load(USize, Size, Imm)]. -spec bignum_sizeneed(non_neg_integer()) -> non_neg_integer(). diff --git a/lib/hipe/sparc/hipe_sparc_assemble.erl b/lib/hipe/sparc/hipe_sparc_assemble.erl index 5424a6c965..0e27c78416 100644 --- a/lib/hipe/sparc/hipe_sparc_assemble.erl +++ b/lib/hipe/sparc/hipe_sparc_assemble.erl @@ -49,7 +49,7 @@ assemble(CompiledCode, Closures, Exports, Options) -> DataRelocs = hipe_pack_constants:mk_data_relocs(RefsFromConsts, LabelMap), SSE = hipe_pack_constants:slim_sorted_exportmap(ExportMap,Closures,Exports), SlimRefs = hipe_pack_constants:slim_refs(AccRefs), - Bin = term_to_binary([{?VERSION_STRING(),?HIPE_SYSTEM_CRC}, + Bin = term_to_binary([{?VERSION_STRING(),?HIPE_ERTS_CHECKSUM}, ConstAlign, ConstSize, SC, DataRelocs, % nee LM, LabelMap diff --git a/lib/hipe/test/Makefile b/lib/hipe/test/Makefile index 009f503abb..d781e4f9be 100644 --- a/lib/hipe/test/Makefile +++ b/lib/hipe/test/Makefile @@ -10,8 +10,10 @@ MODULES= \ # .erl files for these modules are automatically generated GEN_MODULES= \ + basic_SUITE \ bs_SUITE \ - maps_SUITE + maps_SUITE \ + sanity_SUITE ERL_FILES= $(MODULES:%=%.erl) diff --git a/lib/hipe/test/basic_SUITE_data/basic_arith.erl b/lib/hipe/test/basic_SUITE_data/basic_arith.erl new file mode 100644 index 0000000000..28e99be053 --- /dev/null +++ b/lib/hipe/test/basic_SUITE_data/basic_arith.erl @@ -0,0 +1,72 @@ +%%% -*- erlang-indent-level: 2 -*- +%%%--------------------------------------------------------------------- +%%% Author: Kostis Sagonas +%%% +%%% Contains tests cases for compilation of arithmetic. +%%%--------------------------------------------------------------------- +-module(basic_arith). + +-export([test/0]). + +test() -> + ok = test_rem(), + ok = test_bit_ops(), + ok = test_uplus(), + ok = test_bsl_errors(), + ok. + +%%---------------------------------------------------------------------- +%% Tests the remainder operator. + +test_rem() -> + 2 = ret_rem(42, 20), + -2 = ret_rem(-42, 20), + -2 = ret_rem(-42, -20), + {'EXIT', {badarith, _}} = ret_rem(3.14, 2), + {'EXIT', {badarith, _}} = ret_rem(42, 3.14), + ok. + +ret_rem(X, Y) -> + catch X rem Y. + +%%---------------------------------------------------------------------- +%% + +test_bit_ops() -> + 2 = bbb(11, 2, 16#3ff), + ok. + +bbb(X, Y, Z) -> + ((1 bsl X) bor Y) band Z. + +%%---------------------------------------------------------------------- +%% Tests unary plus: it used to be the identity function but not anymore + +test_uplus() -> + badarith = try uplus(gazonk) catch error:Err -> Err end, + 42 = uplus(42), + ok. + +uplus(X) -> +(X). + +%%---------------------------------------------------------------------- +%% The first part of this test triggered a bug in the emulator as one +%% of the arguments to bsl is not an integer. +%% +%% The second part triggered a compilation crash since an arithmetic +%% expression resulting in a 'system_limit' exception was statically +%% evaluated and an arithmetic result was expected. + +test_bsl_errors() -> + {'EXIT', {'badarith', _}} = (catch (t1(0, pad, 0))), + badarith = try t2(0, pad, 0) catch error:Err1 -> Err1 end, + system_limit = try (id(1) bsl 100000000) catch error:Err2 -> Err2 end, + ok. + +t1(_, X, _) -> + (1 bsl X) + 1. + +t2(_, X, _) -> + (X bsl 1) + 1. + +id(I) -> I. diff --git a/lib/hipe/test/basic_SUITE_data/basic_beam_instrs.erl b/lib/hipe/test/basic_SUITE_data/basic_beam_instrs.erl new file mode 100644 index 0000000000..6fafea3b09 --- /dev/null +++ b/lib/hipe/test/basic_SUITE_data/basic_beam_instrs.erl @@ -0,0 +1,102 @@ +%%% -*- erlang-indent-level: 2 -*- +%%%------------------------------------------------------------------- +%%% Author: Kostis Sagonas +%%% +%%% Tests for correct translation of various BEAM instructions. +%%%------------------------------------------------------------------- +-module(basic_beam_instrs). + +-export([test/0]). + +test() -> + ok = test_make_fun(), + ok = test_switch_val(), + ok = test_put_literal(), + ok = test_set_tuple_element(), + ok = test_unguarded_unsafe_element(), + ok. + +%%-------------------------------------------------------------------- +%% Tests whether the translation of make_fun works. + +test_make_fun() -> + {F, G} = double_the_fun(), + ok = F(), + {ok, 42} = G(42), + FV1 = {ok, free_var1}, + FV2 = {also, {free, var2}}, + {FV1, {ok, [bv]}, FV2} = contains_fun(FV1, ignored, FV2), + ok. + +double_the_fun() -> + {fun () -> ok end, fun (V) -> {ok, V} end}. + +contains_fun(X, _IGNORED_ARG, Y) -> + calls_fun(fun(Term) -> {X, Term, Y} end). + +calls_fun(F) -> + F({ok, [bv]}). + +%%-------------------------------------------------------------------- +%% Tests whether the translation of switch_val works. + +test_switch_val() -> + 'A' = sv(a), + 'B' = sv(b), + 'C' = sv(c), + foo = sv(d), + ok. + +sv(a) -> 'A'; +sv(b) -> 'B'; +sv(c) -> 'C'; +sv(_) -> foo. + +%%-------------------------------------------------------------------- +%% Tests correct handling of literals (statically constant terms) + +-define(QUADRUPLE, {a,b,c,42}). +-define(DEEP_LIST, [42,[42,[42]]]). + +test_put_literal() -> + ?QUADRUPLE = mk_literal_quadruple(), + ?DEEP_LIST = mk_literal_deep_list(), + ok. + +mk_literal_quadruple() -> + ?QUADRUPLE. + +mk_literal_deep_list() -> + ?DEEP_LIST. + +%%-------------------------------------------------------------------- +%% Tests whether the translation of set_tuple_element works. + +-record(rec, {f1, f2, f3, f4, f5}). + +test_set_tuple_element() -> + F2 = [a,b,c], F4 = {a,b}, + State0 = init_rec(F2, F4), + State1 = simple_set(State0, 42), + #rec{f1 = foo, f2 = F2, f3 = 42, f4 = F4, f5 = 42.0} = odd_set(State1, 21), + ok. + +init_rec(F2, F4) -> + #rec{f1 = bar, f2 = F2, f3 = 10, f4 = F4, f5 = 3.14}. + +simple_set(State, Val) -> %% f3 = Val is the one used in set_element; + State#rec{f3 = Val, f5 = Val*2}. %% this checks the case of variable + +odd_set(State, Val) -> %% f3 = foo is the one used in set_element; + State#rec{f1 = foo, f5 = Val*2.0}. %% this checks the case of constant + +%%-------------------------------------------------------------------- +%% Tests the handling of unguarded unsafe_element operations that BEAM +%% can sometimes construct on records (when it has enough context). + +test_unguarded_unsafe_element() -> + {badrecord, rec} = try unguarded_unsafe_element(42) catch error:E -> E end, + ok. + +unguarded_unsafe_element(X) -> + X#rec{f1 = X#rec.f3}. diff --git a/lib/hipe/test/basic_SUITE_data/basic_bifs.erl b/lib/hipe/test/basic_SUITE_data/basic_bifs.erl new file mode 100644 index 0000000000..e7ee2f3678 --- /dev/null +++ b/lib/hipe/test/basic_SUITE_data/basic_bifs.erl @@ -0,0 +1,257 @@ +%%% -*- erlang-indent-level: 2 -*- +%%%------------------------------------------------------------------- +%%% Author: Kostis Sagonas +%%% +%%% Contains tests for handling of BIFs in guards and body calls. +%%%------------------------------------------------------------------- +-module(basic_bifs). + +-export([test/0]). + +-define(BIG, 1398479237498374913984792374983749). + +test() -> + ok = test_abs(), + ok = test_binary_part(), + ok = test_element(), + ok = test_float(), + ok = test_float_to_list(), + ok = test_integer_to_list(), + ok = test_list_to_float(), + ok = test_list_to_integer(), + ok = test_round(), + ok = test_trunc(), + ok. + +%%-------------------------------------------------------------------- + +test_abs() -> + t_abs(5.5, 0.0, -100.0, 5, 0, -100, ?BIG). + +t_abs(F1, F2, F3, I1, I2, I3, BigNum) -> + %% Floats. + 5.5 = abs(F1), + 0.0 = abs(F2), + 100.0 = abs(F3), + %% Integers. + 5 = abs(I1), + 0 = abs(I2), + 100 = abs(I3), + %% Bignums. + BigNum = abs(BigNum), + BigNum = abs(-BigNum), + ok. + +%%-------------------------------------------------------------------- +%% Checks that 2-ary and 3-ary BIFs can be compiled to native code. + +test_binary_part() -> + Bin = <<1,2,3,4,5,6,7,8,9,10>>, + BinPart = bp3(Bin), + <<7,8>> = bp2(BinPart), + ok. + +bp2(Bin) -> + binary_part(Bin, {1, 2}). + +bp3(Bin) -> + binary_part(Bin, byte_size(Bin), -5). + +%%-------------------------------------------------------------------- + +test_element() -> + true = elem({a, b}), + false = elem({a, c}), + other = elem(gazonk), + ok. + +elem(T) when element(1, T) == a -> element(2, T) == b; +elem(_) -> other. + +%%-------------------------------------------------------------------- + +test_float() -> + t_float(0, 42, -100, 2.5, 0.0, -100.42, ?BIG, -?BIG). + +t_float(I1, I2, I3, F1, F2, F3, B1, B2) -> + 0.0 = float(I1), + 2.5 = float(F1), + 0.0 = float(F2), + -100.42 = float(F3), + 42.0 = float(I2), + -100.0 = float(I3), + %% Bignums. + 1398479237498374913984792374983749.0 = float(B1), + -1398479237498374913984792374983749.0 = float(B2), + %% Extremly big bignums. + Big = list_to_integer(duplicate(2000, $1)), + {'EXIT', _} = (catch float(Big)), + %% Invalid types and lists. + {'EXIT', _} = (catch my_list_to_integer(atom)), + {'EXIT', _} = (catch my_list_to_integer(123)), + {'EXIT', _} = (catch my_list_to_integer([$1, [$2]])), + {'EXIT', _} = (catch my_list_to_integer("1.2")), + {'EXIT', _} = (catch my_list_to_integer("a")), + {'EXIT', _} = (catch my_list_to_integer("")), + ok. + +my_list_to_integer(X) -> + list_to_integer(X). + +%%-------------------------------------------------------------------- + +test_float_to_list() -> + test_ftl("0.0e+0", 0.0), + test_ftl("2.5e+1", 25.0), + test_ftl("2.5e+0", 2.5), + test_ftl("2.5e-1", 0.25), + test_ftl("-3.5e+17", -350.0e15), + ok. + +test_ftl(Expect, Float) -> + %% No \n on the next line -- we want the line number from t_float_to_list. + Expect = remove_zeros(lists:reverse(float_to_list(Float)), []). + +%% Removes any non-significant zeros in a floating point number. +%% Example: 2.500000e+01 -> 2.5e+1 + +remove_zeros([$+, $e|Rest], [$0, X|Result]) -> + remove_zeros([$+, $e|Rest], [X|Result]); +remove_zeros([$-, $e|Rest], [$0, X|Result]) -> + remove_zeros([$-, $e|Rest], [X|Result]); +remove_zeros([$0, $.|Rest], [$e|Result]) -> + remove_zeros(Rest, [$., $0, $e|Result]); +remove_zeros([$0|Rest], [$e|Result]) -> + remove_zeros(Rest, [$e|Result]); +remove_zeros([Char|Rest], Result) -> + remove_zeros(Rest, [Char|Result]); +remove_zeros([], Result) -> + Result. + +%%-------------------------------------------------------------------- + +test_integer_to_list() -> + t_integer_to_list(0, 42, 32768, 268435455, 123456932798748738738). + +t_integer_to_list(I1, I2, I3, I4, BIG) -> + "0" = integer_to_list(I1), + "42" = integer_to_list(I2), + "-42" = integer_to_list(-I2), + "-42" = integer_to_list(-I2), + "32768" = integer_to_list(I3), + "268435455" = integer_to_list(I4), + "-268435455" = integer_to_list(-I4), + "123456932798748738738" = integer_to_list(BIG), + BigList = duplicate(2000, $1), + Big = list_to_integer(BigList), + BigList = integer_to_list(Big), + ok. + +%%-------------------------------------------------------------------- + +test_list_to_float() -> + ok = t_list_to_float_safe(), + ok = t_list_to_float_risky(). + +t_list_to_float_safe() -> + 0.0 = my_list_to_float("0.0"), + 0.0 = my_list_to_float("-0.0"), + 0.5 = my_list_to_float("0.5"), + -0.5 = my_list_to_float("-0.5"), + 100.0 = my_list_to_float("1.0e2"), + 127.5 = my_list_to_float("127.5"), + -199.5 = my_list_to_float("-199.5"), + {'EXIT', _} = (catch my_list_to_float("0")), + {'EXIT', _} = (catch my_list_to_float("0..0")), + {'EXIT', _} = (catch my_list_to_float("0e12")), + {'EXIT', _} = (catch my_list_to_float("--0.0")), + ok. + +my_list_to_float(X) -> + list_to_float(X). + +%% This might crash the emulator. (Used to crash Erlang 4.4.1 on Unix.) + +t_list_to_float_risky() -> + Many_Ones = duplicate(25000, $1), + ok = case list_to_float("2." ++ Many_Ones) of + F when is_float(F), 0.0 < F, F =< 3.14 -> ok + end, + {'EXIT', _} = (catch list_to_float("2" ++ Many_Ones)), + ok. + +%%-------------------------------------------------------------------- + +test_list_to_integer() -> + ok = t_list_to_integer_small("0", "00", "-0", "1", "-1", "42", "-12", + "32768", "268435455", "-268435455"), + ok = t_list_to_integer_bignum("123456932798748738738666"), + ok. + +t_list_to_integer_small(S1, S2, S3, S4, S5, S6, S7, S8, S9, S10) -> + 0 = list_to_integer(S1), + 0 = list_to_integer(S2), + 0 = list_to_integer(S3), + 1 = list_to_integer(S4), + -1 = list_to_integer(S5), + 42 = list_to_integer(S6), + -12 = list_to_integer(S7), + 32768 = list_to_integer(S8), + 268435455 = list_to_integer(S9), + -268435455 = list_to_integer(S10), + ok. + +t_list_to_integer_bignum(S) -> + 123456932798748738738666 = list_to_integer(S), + case list_to_integer(duplicate(2000, $1)) of + I when is_integer(I), I > 123456932798748738738666 -> ok + end. + +%%-------------------------------------------------------------------- + +test_round() -> + ok = t_round_small(0.0, 0.4, 0.5, -0.4, -0.5, 255.3, 255.6, -1033.3, -1033.6), + ok = t_round_big(4294967296.1, 4294967296.9), + ok. + +t_round_small(F1, F2, F3, F4, F5, F6, F7, F8, F9) -> + 0 = round(F1), + 0 = round(F2), + 1 = round(F3), + 0 = round(F4), + -1 = round(F5), + 255 = round(F6), + 256 = round(F7), + -1033 = round(F8), + -1034 = round(F9), + ok. + +t_round_big(B1, B2) -> + 4294967296 = round(B1), + 4294967297 = round(B2), + -4294967296 = round(-B1), + -4294967297 = round(-B2), + ok. + +%%-------------------------------------------------------------------- + +test_trunc() -> + t_trunc(0.0, 5.3333, -10.978987, 4294967305.7). + +t_trunc(F1, F2, F3, B) -> + 0 = trunc(F1), + 5 = trunc(F2), + -10 = trunc(F3), + %% Bignums. + 4294967305 = trunc(B), + -4294967305 = trunc(-B), + ok. + +%%-------------------------------------------------------------------- +%% Auxiliary functions below + +duplicate(N, X) when is_integer(N), N >= 0 -> + duplicate(N, X, []). + +duplicate(0, _, L) -> L; +duplicate(N, X, L) -> duplicate(N-1, X, [X|L]). diff --git a/lib/hipe/test/basic_SUITE_data/basic_bignums.erl b/lib/hipe/test/basic_SUITE_data/basic_bignums.erl new file mode 100644 index 0000000000..e3b523b3f5 --- /dev/null +++ b/lib/hipe/test/basic_SUITE_data/basic_bignums.erl @@ -0,0 +1,143 @@ +%%% -*- erlang-indent-level: 2 -*- +%%%------------------------------------------------------------------- +%%% Author: Kostis Sagonas +%%% +%%% Contains code examples that test bignum arithmetic and matching. +%%%------------------------------------------------------------------- +-module(basic_bignums). + +-export([test/0, test_bsl/0]). + +test() -> + ok = test_ops(), + ok = test_big_fac(), + ok = test_int_overfl_32(), + ok = test_int_overfl_64(), + ok = test_int_overfl_32_guard(), + ok = test_int_overfl_64_guard(), + ok. + +%%-------------------------------------------------------------------- +%% Define some constants for the tests of arithmetic operators + +-define(X, 68719476736). +-define(Y, 98765432101234). +-define(Z, 4722366482869645213696). +-define(W, 339254531512339254531512). + +-define(B1, 4398046511104). +-define(B5, 1645504557321206042154969182557350504982735865633579863348609024). +-define(B17, 86182066610968551542636378241108028056376767329454880514019834315878107616003372189510312530372009184902888961739623919010110377987011442493486117202360415845666384627768436296772219009176743399772868636439042064384). + +%%-------------------------------------------------------------------- + +test_ops() -> + ok = test_mult(), + ok = test_div(), + ok = test_round(), + ok = test_trunc(), + ok = test_bsl(), + ok. + +test_mult() -> + ?Z = mult(?X, ?X), + ok. + +mult(X, Y) -> X * Y. + +test_div() -> + 4 = div_f(339254531512, ?X), + 0 = div_f(?Y, ?Y+1), + 64 = div_f(?B1, ?X), + ?X = div_f(?Z, ?X), + 1073741824 = div_f(?Z, ?B1), + ok. + +div_f(X, Y) -> X div Y. + +test_round() -> + 0 = round_f(?Z, ?W), + 1 = round_f(?Y, ?Y), + 71 = round_f(?W, ?Z), + 1437 = round_f(?Y, ?X), + 47813960 = round_f(?Z, ?Y), + 4936803183406 = round_f(?W, ?X), + ok. + +trunc_f(X, Y) -> round(X/Y). + +test_trunc() -> + 0 = trunc_f(?Z, ?W), + 1 = trunc_f(?Y, ?Y), + 72 = trunc_f(?W, ?Z), + 1437 = trunc_f(?Y, ?X), + 47813961 = trunc_f(?Z, ?Y), + 4936803183407 = trunc_f(?W, ?X), + ok. + +round_f(X, Y) -> trunc(X/Y). + +test_bsl() -> + ?B1 = bsl_f(1, 42), + ?B5 = n(5, fun erlang:'bsl'/2, 1, 42), % use the operator + ?B17 = n(17, fun bsl_f/2, 1, 42), % use the local function + ok. + +bsl_f(X, Y) -> X bsl Y. + +%% applies a binary function N times +n(1, F, X, Y) -> F(X, Y); +n(N, F, X, Y) when N > 1 -> n(N-1, F, F(X, Y), Y). + +%%-------------------------------------------------------------------- + +-define(FAC42, 1405006117752879898543142606244511569936384000000000). + +test_big_fac() -> + ?FAC42 = fac(42), + ok. + +fac(0) -> 1; +fac(N) -> N * fac(N-1). + +%%-------------------------------------------------------------------- +%% Tests for correct handling of integer overflow + +test_int_overfl_32() -> + 16#7FFFFFF = add(16#7FFFFFF, 0), + 16#8000000 = add(16#8000000, 0), + 16#8000001 = add(16#8000000, 1), + case add(16#7FFFFFF, 1) of + 16#8000000 -> ok; + -16#7FFFFFF -> error + end. + +test_int_overfl_64() -> + 16#7FFFFFFFFFFFFFF = add(16#7FFFFFFFFFFFFFF, 0), + 16#800000000000000 = add(16#800000000000000, 0), + 16#800000000000001 = add(16#800000000000000, 1), + case add(16#7FFFFFFFFFFFFFF, 1) of + 16#800000000000000 -> ok; + -16#7FFFFFFFFFFFFFF -> error + end. + +add(X, Y) -> X + Y. + +%%-------------------------------------------------------------------- +%% Tests for correct handling of integer overflow in guards + +test_int_overfl_32_guard() -> + ok = overfl_in_guard(16#7ffffff, 0), + ok = overfl_in_guard(16#7ffffff, 16#7ffffff), + ok. + +test_int_overfl_64_guard() -> + ok = overfl_in_guard(16#7ffffffffffffff, 0), + ok = overfl_in_guard(16#7ffffffffffffff, 16#7ffffffffffffff), + ok. + +overfl_in_guard(X, Y) -> + case ok of + V when X+Y > 12 -> V; + _ -> bad + end. diff --git a/lib/hipe/test/basic_SUITE_data/basic_boolean.erl b/lib/hipe/test/basic_SUITE_data/basic_boolean.erl new file mode 100644 index 0000000000..e4a91ef5af --- /dev/null +++ b/lib/hipe/test/basic_SUITE_data/basic_boolean.erl @@ -0,0 +1,47 @@ +%%% -*- erlang-indent-level: 2 -*- +%%%------------------------------------------------------------------- +%%% Author: Kostis Sagonas +%%% +%%% Tests for correct translation of booleans and their primitives. +%%%------------------------------------------------------------------- +-module(basic_boolean). + +-export([test/0]). + +test() -> + ok = test_boolean_ops(false, true), + ok = test_orelse_redundant(), + ok. + +%%-------------------------------------------------------------------- + +test_boolean_ops(F, T) -> + true = T and T, + false = T and F, + false = F and T, + false = F and F, + true = T or T, + true = T or F, + true = F or T, + false = F or F, + true = T andalso T, + false = T andalso F, + false = F andalso T, + false = F andalso F, + true = T orelse T, + true = T orelse F, + true = F orelse T, + false = F orelse F, + ok. + +%%-------------------------------------------------------------------- +%% Redundant test in BEAM code will generate type warning. + +test_orelse_redundant() -> + true = test_orelse(true, true, true), + ok. + +test_orelse(A, B, C) -> + A andalso B orelse C. + +%%-------------------------------------------------------------------- diff --git a/lib/hipe/test/basic_SUITE_data/basic_bugs_beam.erl b/lib/hipe/test/basic_SUITE_data/basic_bugs_beam.erl new file mode 100644 index 0000000000..964b0f423a --- /dev/null +++ b/lib/hipe/test/basic_SUITE_data/basic_bugs_beam.erl @@ -0,0 +1,138 @@ +%%% -*- erlang-indent-level: 2 -*- +%%%------------------------------------------------------------------- +%%% Author: Kostis Sagonas +%%% +%%% Contains code examples that exhibited bugs in the BEAM compiler. +%%%------------------------------------------------------------------- +-module(basic_bugs_beam). + +-export([test/0]). + +%% the following is needed for the test_weird_message +-export([loop/1]). +%% the following are needed for the test_catch_bug +-behaviour(gen_server). +-export([start_link/1]). +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, + terminate/2, code_change/3]). + +test() -> + ok = test_fp_basic_blocks(), + ok = test_weird_message(), + ok = test_catch_bug(), + ok. + +%%-------------------------------------------------------------------- +%% Test which shows that BEAM's splitting of basic blocks should take +%% into account that arithmetic operations implemented as BIFs can +%% also cause exceptions and thus calls to BIFs should end basic blocks. +%% +%% Investigated and fixed in the beginning of April 2004. +%%-------------------------------------------------------------------- + +test_fp_basic_blocks() -> + ok = t1(), + ok = t2(). + +t1() -> + X = (catch bad_arith1(2.0, 1.7)), + case X of + {'EXIT', {badarith, _}} -> + ok; + _ -> + error + end. + +bad_arith1(X, Y) when is_float(X) -> + X1 = X * 1.7e+308, + X2 = X1 + 1.0, + Y1 = Y * 2, + {X2, Y1}. + +%% Similarly, it is not kosher to have anything that can fail inside +%% the fp block since it will throw the exception before the fp +%% exception and we will get the same problems. + +t2() -> + case catch bad_arith2(2.0, []) of + {'EXIT', {badarith, _}} -> + ok; + _ -> + error + end. + +bad_arith2(X, Y) when is_float(X) -> + X1 = X * 1.7e+308, + Y1 = element(1, Y), + {X1 + 1.0, Y1}. + +%%-------------------------------------------------------------------- +%% Sending 'test' to this process should return 'ok'. But: +%% +%% 1> MOD:test(). +%% Weird: received true +%% timeout +%% +%% Surprisingly, the message has been bound to the value of 'ena' +%% in the record! The problem was visible in the .S file. +%%-------------------------------------------------------------------- + +-record(state, {ena = true}). + +test_weird_message() -> + P = spawn_link(?MODULE, loop, [#state{}]), + P ! {msg, self()}, + receive + What -> What + after 42 -> timeout + end. + +loop(S) -> + receive + _ when S#state.ena == false -> + io:format("Weird: ena is false\n"); + % loop(S); + {msg, Pid} -> + Pid ! ok; + % loop(S); + Other -> + io:format("Weird: received ~p\n", [Other]) + % loop(S) + end. + +%%-------------------------------------------------------------------- +%% This was posted on the Erlang mailing list as a question: +%% +%% Given the module below and the function call +%% "catch_bug:start_link(foo)." +%% from the Erlang shell, why does Erlang crash with "Catch not found"? +%% +%% The BEAM compiler was generating wrong code for this case; +%% this was fixed in R9C-0. Native code generation was OK. +%%-------------------------------------------------------------------- + +test_catch_bug() -> + ignore = start_link(foo), + ok. + +start_link(Param) -> + gen_server:start_link(?MODULE, Param, []). + +init(Param) -> + process_flag(trap_exit, true), + (catch begin + dummy(Param), + (catch exit(bar)) + end + ), + ignore. + +dummy(_) -> ok. + +%% gen_server callbacks below +handle_call(_Call, _From, State) -> {noreply, State}. +handle_cast(_Msg, State) -> {noreply, State}. +handle_info(_Msg, State) -> {noreply, State}. +terminate(_Reason, _State) -> ok. +code_change(_OldVsn, State, _Extra) -> {ok, State}. + diff --git a/lib/hipe/test/basic_SUITE_data/basic_bugs_hipe.erl b/lib/hipe/test/basic_SUITE_data/basic_bugs_hipe.erl new file mode 100644 index 0000000000..caa0e71d0b --- /dev/null +++ b/lib/hipe/test/basic_SUITE_data/basic_bugs_hipe.erl @@ -0,0 +1,463 @@ +%%% -*- erlang-indent-level: 2 -*- +%%%---------------------------------------------------------------------- +%%% Author: Kostis Sagonas +%%% +%%% Contains code examples that exhibited bugs in the HiPE compiler. +%%%---------------------------------------------------------------------- +-module(basic_bugs_hipe). + +-export([test/0]). + +test() -> + ok = test_ets_bifs(), + ok = test_szar_bug(), + ok = test_bit_shift(), + ok = test_match_big_list(), + ok = test_unsafe_bsl(), + ok = test_unsafe_bsr(), + ok = test_R12B5_seg_fault(), + ok = test_switch_neg_int(), + ok = test_icode_range_anal(), + ok. + +%%----------------------------------------------------------------------- +%% From: Bjorn Gustavsson +%% +%% This code, if HiPE compiled, crashed like this (on SPARC) +%% +%% (gdb) where +%% #0 fullsweep_heap (p=0x2c60dc, new_sz=610, objv=0xffbee8b4, nobj=3) +%% at beam/ggc.c:1060 +%% #1 0x7ff24 in erts_garbage_collect (p=0x2c60dc, need=2, objv=0x1128fc, ...) +%% at beam/ggc.c:1648 +%% #2 0xab6fc in hipe_mode_switch (p=0x2c60dc, cmd=704512, reg=0x1128fc) +%% at hipe/hipe_mode_switch.c:180 +%% #3 0x8e27c in process_main () at beam/beam_emu.c:3314 +%% #4 0x31338 in erl_start (argc=9, argv=0xffbeed5c) at beam/erl_init.c:936 +%% #5 0x2d9f4 in main (argc=9, argv=0xffbeed5c) at sys/unix/erl_main.c:28 +%% +%% A guess at what could be the problem: From R8, many ets BIFs trap +%% to other ets BIFs with a *different* arity (i.e. they have more or +%% less arguments). I have probably forgotten to mention that subtle +%% change. +%%----------------------------------------------------------------------- + +test_ets_bifs() -> + Seed = {1032, 15890, 22716}, + put(random_seed, Seed), + do_random_test(). + +do_random_test() -> + OrdSet = ets:new(xxx, [ordered_set]), + Set = ets:new(xxx, []), + do_n_times(fun() -> + Key = create_random_string(25), + Value = create_random_tuple(25), + ets:insert(OrdSet, {Key, Value}), + ets:insert(Set, {Key, Value}) + end, 5000), + %% io:format("~nData inserted~n"), + do_n_times(fun() -> + I = random:uniform(25), + Key = create_random_string(I) ++ '_', + L1 = ets_match_object(OrdSet, {Key, '_'}), + L2 = lists:sort(ets_match_object(Set, {Key, '_'})), + case L1 == L2 of + false -> + %% io:format("~p != ~p~n", [L1, L2]), + exit({not_eq, L1, L2}); + true -> + ok + end + end, 2000), + %% io:format("~nData matched~n"), + ets:match_delete(OrdSet, '_'), + ets:match_delete(Set, '_'), + ok. + +create_random_string(0) -> + []; +create_random_string(OfLength) -> + C = case random:uniform(2) of + 1 -> (random:uniform($Z - $A + 1) - 1) + $A; + _ -> (random:uniform($z - $a + 1) - 1) + $a + end, + [C | create_random_string(OfLength - 1)]. + +create_random_tuple(OfLength) -> + list_to_tuple([list_to_atom([X]) || X <- create_random_string(OfLength)]). + +ets_match_object(Tab,Expr) -> + case random:uniform(2) of + 1 -> ets:match_object(Tab,Expr); + _ -> match_object_chunked(Tab,Expr) + end. + +match_object_chunked(Tab,Expr) -> + match_object_chunked_collect(ets:match_object(Tab, Expr, + random:uniform(1999) + 1)). + +match_object_chunked_collect('$end_of_table') -> + []; +match_object_chunked_collect({Results, Continuation}) -> + Results ++ match_object_chunked_collect(ets:match_object(Continuation)). + +do_n_times(_, 0) -> + ok; +do_n_times(Fun, N) -> + Fun(), + case N rem 1000 of + 0 -> ok; %% WAS: io:format("."); + _ -> ok + end, + do_n_times(Fun, N - 1). + +%%----------------------------------------------------------------------- +%% From: Jozsef Berces (PR/ECZ) +%% Date: Feb 19, 2004 +%% +%% Program which was added to the testsuite as a result of another bug +%% report involving tuples as funs. Thanks God, these are no longer +%% supported, but the following is a good test for testing calling +%% native code funs from BEAM code (lists:map, lists:filter, ...). +%%----------------------------------------------------------------------- + +test_szar_bug() -> + ["A","B","C"] = smartconcat([], "H'A, H'B, H'C"), + ok. + +smartconcat(B, L) -> + LL = tokenize(L, $,), + NewlineDel = fun (X) -> killcontrol(X) end, + StripFun = fun (X) -> string:strip(X) end, + LL2 = lists:map(NewlineDel, lists:map(StripFun, LL)), + EmptyDel = fun(X) -> + case string:len(X) of + 0 -> false; + _ -> true + end + end, + LL3 = lists:filter(EmptyDel, LL2), + HexFormat = fun(X, Acc) -> + case string:str(X, "H'") of + 1 -> + case checkhex(string:substr(X, 3)) of + {ok, Y} -> + {Y, Acc}; + _ -> + {X, Acc + 1} + end; + _ -> + {X, Acc + 1} + end + end, + {LL4,_Ret} = lists:mapfoldl(HexFormat, 0, LL3), + lists:append(B, lists:sublist(LL4, lists:max([0, 25 - length(B)]))). + +checkhex(L) -> + checkhex(L, ""). + +checkhex([H | T], N) when H >= $0, H =< $9 -> + checkhex(T, [H | N]); +checkhex([H | T], N) when H >= $A, H =< $F -> + checkhex(T, [H | N]); +checkhex([H | T], N) when H =< 32 -> + checkhex(T, N); +checkhex([_ | _], _) -> + {error, ""}; +checkhex([], N) -> + {ok, lists:reverse(N)}. + +killcontrol([C | S]) when C < 32 -> + killcontrol(S); +killcontrol([C | S]) -> + [C | killcontrol(S)]; +killcontrol([]) -> + []. + +tokenize(L, C) -> + tokenize(L, C, [], []). + +tokenize([C | T], C, A, B) -> + case A of + [] -> + tokenize(T, C, [], B); + _ -> + tokenize(T, C, [], [lists:reverse(A) | B]) + end; +tokenize([H | T], C, A, B) -> + tokenize(T, C, [H | A], B); +tokenize(_, _, [], B) -> + lists:reverse(B); +tokenize(_, _, A, B) -> + lists:reverse([lists:reverse(A) | B]). + +%%----------------------------------------------------------------------- +%% From: Niclas Pehrsson +%% Date: Apr 20, 2006 +%% +%% We found something weird with the bit shifting in HiPE. It seems +%% that bsr in some cases shifts the bits in the wrong way... +%% +%% Fixed about 10 mins afterwards; was a bug in constant propagation. +%%----------------------------------------------------------------------- + +test_bit_shift() -> + 1 = plain_shift(), % 1 + 6 = length_list_plus(), % 6 + 0 = shift_length_list(), % 0 + 1 = shift_length_list_plus(), % 1 + 1 = shift_length_list_plus2(), % 1 + 24 = shift_length_list_plus_bsl(), % 24 + 1 = shift_fun(), % 1 + %% {1, 6, 0, 1, 1, 24, 1} = {A, B, C, D, E, F, G}, + ok. + +plain_shift() -> + 6 bsr 2. + +length_list() -> + length([0,0]). + +length_list_plus() -> + length([0,0]) + 4. + +shift_length_list() -> + length([0,0]) bsr 2. + +shift_length_list_plus() -> + (length([0,0]) + 4) bsr 2. + +shift_length_list_plus_bsl() -> + (length([0,0]) + 4) bsl 2. + +shift_length_list_plus2() -> + N = length([0,0]) + 4, + N bsr 2. + +shift_fun() -> + (length_list() + 4) bsr 2. + +%%----------------------------------------------------------------------- +%% From: Igor Goryachev +%% Date: June 15, 2006 +%% +%% I have experienced a different behaviour and possibly a weird result +%% while playing with matching a big list on x86 and x86_64 machines. +%%----------------------------------------------------------------------- + +-define(BIG_LIST, + ["uid", "nickname", "n_family", "n_given", "email_pref", + "tel_home_number", "tel_cellular_number", "adr_home_country", + "adr_home_locality", "adr_home_region", "url", "gender", "bday", + "constitution", "height", "weight", "hair", "routine", "smoke", + "maritalstatus", "children", "independence", "school_number", + "school_locality", "school_title", "school_period", "org_orgname", + "title", "adr_work_locality", "photo_type", "photo_binval"]). + +test_match_big_list() -> + case create_tuple_with_big_const_list() of + {selected, ?BIG_LIST, _} -> ok; + _ -> weird + end. + +create_tuple_with_big_const_list() -> + {selected, ?BIG_LIST, [{"test"}]}. + +%%----------------------------------------------------------------------- +%% In October 2006 the HiPE compiler acquired more type-driven +%% optimisations of arithmetic operations. One of these, the +%% transformation of bsl to a pure fixnum bsl fixnum -> fixnum version +%% (unsafe_bsl), was incorrectly performed even when the result +%% wouldn't be a fixnum. The error occurred for all backends, but the +%% only place known to break was hipe_arm:imm_to_am1/2. Some +%% immediates got broken on ARM, causing segmentation faults in +%% compiler_tests when HiPE recompiled itself. +%%----------------------------------------------------------------------- + +test_unsafe_bsl() -> + ok = bsl_check(bsl_test_cases()). + +bsl_test_cases() -> + [{16#FF, {16#FF, 0}}, + {16#F000000F, {16#FF, 2}}]. + +bsl_check([]) -> ok; +bsl_check([{X, Y}|Rest]) -> + case imm_to_am1(X) of + Y -> bsl_check(Rest); + _ -> 'hipe_broke_bsl' + end. + +imm_to_am1(Imm) -> + imm_to_am1(Imm band 16#FFFFFFFF, 16). +imm_to_am1(Imm, RotCnt) -> + if Imm >= 0, Imm =< 255 -> {Imm, RotCnt band 15}; + true -> + NewRotCnt = RotCnt - 1, + if NewRotCnt =:= 0 -> []; % full circle, no joy + true -> + NewImm = (Imm bsr 2) bor ((Imm band 3) bsl 30), + imm_to_am1(NewImm, NewRotCnt) + end + end. + +%%----------------------------------------------------------------------- +%% Another transformation, namely that of bsr to a pure fixnum bsr +%% fixnum -> fixnum version (unsafe_bsr), failed to check for shifts +%% larger than the number of bits in fixnums. Such shifts should +%% return zero, but instead they became plain machine-level shift +%% instructions. Machines often only consider the low-order bits of +%% the shift count, so machine-level shifts larger than the word size +%% do not match the Erlang semantics. +%%----------------------------------------------------------------------- + +test_unsafe_bsr() -> + ok = bsr_check(bsr_test_cases()). + +bsr_test_cases() -> + [{16#FF, 4, 16#0F}, + {16#FF, 64, 0}]. + +bsr_check([]) -> ok; +bsr_check([{X, Y, Z}|Rest]) -> + case do_bsr(X, Y) of + Z -> bsr_check(Rest); + _ -> 'hipe_broke_bsr' + end. + +do_bsr(X, Y) -> + (X band 16#FFFF) bsr (Y band 16#FFFF). + +%%----------------------------------------------------------------------- +%% From: Sergey S, mid January 2009. +%% +%% While I was playing with +native option, I run into a bug in HiPE +%% which leads to segmentation fault using +native and Erlang R12B-5. +%% +%% Eshell V5.6.5 +%% 1> crash:test(). +%% # Some message to be printed here each loop iteration +%% Segmentation fault +%% +%% Diagnosed and fixed by Mikael Pettersson (22 Jan 2009): +%% +%% I've analysed the recently posted HiPE bug report on erlang-bugs +%% <http://www.erlang.org/pipermail/erlang-bugs/2009-January/001162.html>. +%% The segfault is caused by memory corruption, which in turn is caused +%% by RTL removing an update of the HP (heap pointer) register due to +%% what looks like broken liveness information. +%%----------------------------------------------------------------------- + +test_R12B5_seg_fault() -> + _ = spawn(fun() -> init() end), + ok. + +init() -> + repeat(5, fun() -> void end), + receive after infinity -> ok end. + +repeat(0, _) -> + ok; +repeat(N, Fun) -> + %% io:format("# Some message to be printed here each loop iteration\n"), + Fun(), + repeat(N - 1, Fun). + +%%----------------------------------------------------------------------- +%% From: Jon Meredith +%% Date: July 9, 2009 +%% +%% Binary search key tables are sorted by the loader based on the +%% runtime representations of the keys as unsigned words. However, +%% the code generated for the binary search used signed comparisons. +%% That worked for atoms and non-negative fixnums, but not for +%% negative fixnums. Fixed by Mikael Pettersson July 10, 2009. +%%----------------------------------------------------------------------- + +test_switch_neg_int() -> + ok = f(-80, 8). + +f(10, -1) -> ok; +f(X, Y) -> + Y = g(X), + f(X + 10, Y - 1). + +g(X) -> % g(0) should be 0 but became -1 + case X of + 0 -> 0; + -10 -> 1; + -20 -> 2; + -30 -> 3; + -40 -> 4; + -50 -> 5; + -60 -> 6; + -70 -> 7; + -80 -> 8; + _ -> -1 + end. + +%%----------------------------------------------------------------------- +%% From: Paul Guyot +%% Date: Jan 31, 2011 +%% +%% There is a bug in HiPE compilation with the comparison of floats +%% with integers. This bug happens in functions f/1 and g/2 below. +%% BEAM will evaluate f_eq(42) and f_eq(42.0) to true, while HiPE +%% will evaluate them to false. +%% +%% The culprit was the Icode range analysis which was buggy. (On the +%% other hand, HiPE properly evaluated these calls to true if passed +%% the option 'no_icode_range'.) Fixed by Kostis Sagonas. +%% -------------------------------------------------------------------- + +test_icode_range_anal() -> + true = f_eq(42), + true = f_eq(42.0), + false = f_ne(42), + false = f_ne(42.0), + false = f_eq_ex(42), + false = f_eq_ex(42.0), + true = f_ne_ex(42), + true = f_ne_ex(42.0), + false = f_gt(42), + false = f_gt(42.0), + true = f_le(42), + true = f_le(42.0), + zero_test = g(0, test), + zero_test = g(0.0, test), + non_zero_test = g(42, test), + other = g(42, other), + ok. + +f_eq(X) -> + Y = X / 2, + Y == 21. + +f_ne(X) -> + Y = X / 2, + Y /= 21. + +f_eq_ex(X) -> + Y = X / 2, + Y =:= 21. + +f_ne_ex(X) -> + Y = X / 2, + Y =/= 21. + +f_gt(X) -> + Y = X / 2, + Y > 21. + +f_le(X) -> + Y = X / 2, + Y =< 21. + +g(X, Z) -> + Y = X / 2, + case Z of + test when Y == 0 -> zero_test; + test -> non_zero_test; + other -> other + end. diff --git a/lib/hipe/test/basic_SUITE_data/basic_comparisons.erl b/lib/hipe/test/basic_SUITE_data/basic_comparisons.erl new file mode 100644 index 0000000000..8dab2cab1f --- /dev/null +++ b/lib/hipe/test/basic_SUITE_data/basic_comparisons.erl @@ -0,0 +1,157 @@ +%%% -*- erlang-indent-level: 2 -*- +%%%------------------------------------------------------------------- +%%% Author: Kostis Sagonas +%%% +%%% Contains tests for correct execution of comparison operators. +%%%------------------------------------------------------------------- +-module(basic_comparisons). + +-export([test/0]). + +test() -> + Ns = [0, 0.0, 42, 42.0, gazonk], + T1F4 = [true, false, false, false, false], + T2F3 = [true, true, false, false, false], + F1T4 = [false, true, true, true, true], + F2T3 = [false, false, true, true, true], + %% tests for calls + T1F4 = [eq_exact_call(0, N) || N <- Ns], + F1T4 = [ne_exact_call(0, N) || N <- Ns], + T2F3 = [eq_call(0, N) || N <- Ns], + F2T3 = [ne_call(0, N) || N <- Ns], + %% tests for guards + T1F4 = [eq_exact_guard(0, N) || N <- Ns], + F1T4 = [ne_exact_guard(0, N) || N <- Ns], + T2F3 = [eq_guard(0, N) || N <- Ns], + F2T3 = [ne_guard(0, N) || N <- Ns], + %% some more tests + ok = test_against_zero(), + ok = test_against_other_terms(), + ok = test_sofs_func(), + ok. + +test_against_zero() -> + Xs = [0, 1, 0.0], + [true, false, false] = [is_zero_int(X) || X <- Xs], + [true, false, true] = [is_zero_num(X) || X <- Xs], + [false, true, true] = [is_nonzero_int(X) || X <- Xs], + [false, true, false] = [is_nonzero_num(X) || X <- Xs], + ok. + +test_against_other_terms() -> + TTT = {true, true, true}, + FFF = {false, false, false}, + TTT = {is_foo_exact(foo), is_foo_term1(foo), is_foo_term2(foo)}, + FFF = {is_foo_exact(bar), is_foo_term1(bar), is_foo_term2(bar)}, + FFF = {is_nonfoo_exact(foo), is_nonfoo_term1(foo), is_nonfoo_term2(foo)}, + TTT = {is_nonfoo_exact(bar), is_nonfoo_term1(bar), is_nonfoo_term2(bar)}, + Tup = {a, {42}, [c]}, + TTT = {is_tuple_skel(Tup), is_tuple_exact(Tup), is_tuple_term(Tup)}, + BNi = <<42>>, + TTT = {is_bin_exact(BNi), is_bin_term1(BNi), is_bin_term2(BNi)}, + BNf = <<42/float>>, + FFF = {is_bin_exact(BNf), is_bin_term1(BNf), is_bin_term2(BNf)}, + ok. + +test_sofs_func() -> + L = [0, 0.0], + ok = sofs_func(L, L, L). + +%%-------------------------------------------------------------------- +%% Test for comparison operators used in body calls + +eq_exact_call(X, Y) -> X =:= Y. + +ne_exact_call(X, Y) -> X =/= Y. + +eq_call(X, Y) -> X == Y. + +ne_call(X, Y) -> X /= Y. + +%%-------------------------------------------------------------------- +%% Tests for comparison operators used as guards + +eq_exact_guard(X, Y) when X =:= Y -> true; +eq_exact_guard(_, _) -> false. + +ne_exact_guard(X, Y) when X =/= Y -> true; +ne_exact_guard(_, _) -> false. + +eq_guard(X, Y) when X == Y -> true; +eq_guard(_, _) -> false. + +ne_guard(X, Y) when X /= Y -> true; +ne_guard(_, _) -> false. + +%%-------------------------------------------------------------------- + +is_zero_int(N) when N =:= 0 -> true; +is_zero_int(_) -> false. + +is_nonzero_int(N) when N =/= 0 -> true; +is_nonzero_int(_) -> false. + +is_zero_num(N) when N == 0 -> true; +is_zero_num(_) -> false. + +is_nonzero_num(N) when N /= 0 -> true; +is_nonzero_num(_) -> false. + +%%-------------------------------------------------------------------- +%% There should not really be any difference in the generated code +%% for the following three functions. + +is_foo_exact(A) when A =:= foo -> true; +is_foo_exact(_) -> false. + +is_foo_term1(A) when A == foo -> true; +is_foo_term1(_) -> false. + +is_foo_term2(A) when foo == A -> true; +is_foo_term2(_) -> false. + +%%-------------------------------------------------------------------- +%% Same for these cases + +is_nonfoo_exact(A) when A =/= foo -> true; +is_nonfoo_exact(_) -> false. + +is_nonfoo_term1(A) when A /= foo -> true; +is_nonfoo_term1(_) -> false. + +is_nonfoo_term2(A) when foo /= A -> true; +is_nonfoo_term2(_) -> false. + +%%-------------------------------------------------------------------- + +is_tuple_skel({A,{B},[C]}) when is_atom(A), is_integer(B), is_atom(C) -> true; +is_tuple_skel(T) when is_tuple(T) -> false. + +is_tuple_exact(T) when T =:= {a,{42},[c]} -> true; +is_tuple_exact(T) when is_tuple(T) -> false. + +is_tuple_term(T) when T == {a,{42.0},[c]} -> true; +is_tuple_term(T) when is_tuple(T) -> false. + +%%-------------------------------------------------------------------- +%% But for binaries the treatment has to be different, due to the need +%% for construction of the binary in the guard. + +is_bin_exact(B) when B =:= <<42>> -> true; +is_bin_exact(_) -> false. + +is_bin_term1(B) when B == <<42>> -> true; +is_bin_term1(_) -> false. + +is_bin_term2(B) when <<42>> == B -> true; +is_bin_term2(_) -> false. + +%%-------------------------------------------------------------------- +%% a test from sofs.erl which failed at some point + +sofs_func([X | Ts], X0, L) when X /= X0 -> + sofs_func(Ts, X, L); +sofs_func([X | _Ts], X0, _L) when X == X0 -> + ok; +sofs_func([], _X0, L) -> + L. diff --git a/lib/hipe/test/basic_SUITE_data/basic_exceptions.erl b/lib/hipe/test/basic_SUITE_data/basic_exceptions.erl new file mode 100644 index 0000000000..229a0516dc --- /dev/null +++ b/lib/hipe/test/basic_SUITE_data/basic_exceptions.erl @@ -0,0 +1,465 @@ +%%% -*- erlang-indent-level: 2 -*- +%%%------------------------------------------------------------------- +%%% Author: Kostis Sagonas +%%% +%%% Contains tests that raise exceptions and catch them. +%%%------------------------------------------------------------------- +-module(basic_exceptions). + +-export([test/0, test_catches/0]). + +%% functions used as arguments to spawn/3 +-export([bad_guy/2]). + +test() -> + ok = test_catch_exit(42), + ok = test_catch_throw(42), + ok = test_catch_element(), + ok = test_catch_crash(), + ok = test_catch_empty(), + ok = test_catch_merge(), + ok = test_catches_merged(), + ok = test_pending_errors(), + ok = test_bad_fun_call(), + ok = test_guard_bif(), + ok. + +%%-------------------------------------------------------------------- +%% Written in 2001 by Erik Johansson. + +test_catches() -> + ExitBar = {'EXIT', bar}, + L1 = [ExitBar, ok, ExitBar, {ok, ExitBar}], + L1 = [t1(), t2(), t3(), t4()], + badarith = (catch element(1, element(2, t5(a, b)))), + L2 = [42, ExitBar, ExitBar, {no_exception, ok}], + L2 = [t5(21, 21), t6(), t7(), t8()], + ok. + +t1() -> + catch foo(). + +t2() -> + V = (catch ok()), + s(), + V. + +t3() -> + V = (catch foo()), + V. + +t4() -> + V1 = ok(), + V2 = (catch foo()), + {V1, V2}. + +t5(A, B) -> + catch A + B. + +t6() -> + catch {no_exception, ok(), foo()}. + +t7() -> + catch {no_exception, foo(), ok()}. + +t8() -> + catch {no_exception, ok()}. + +foo() -> + s(), + exit(bar). + +ok() -> s(), ok. + +s() -> nada. + +%%-------------------------------------------------------------------- + +test_catch_exit(N) -> + {'EXIT', N} = (catch exit(N)), + {'EXIT', 42} = (catch exit(42)), + 42 = try exit(N) catch exit:R1 -> R1 end, + 42 = try exit(42) catch exit:R2 -> R2 end, + ok. + +%%-------------------------------------------------------------------- + +test_catch_throw(N) -> + N = (catch throw(N)), + 42 = (catch throw(42)), + 42 = try throw(N) catch throw:R1 -> R1 end, + 42 = try throw(42) catch throw:R2 -> R2 end, + ok. + +%%-------------------------------------------------------------------- + +test_catch_element() -> + 'EXIT' = test_catch_element([]), + 'EXIT' = test_catch_element(42), + ok. + +test_catch_element(N) -> + element(1, catch element(N, {1,2,3,4,5,6,7,8,9,10,11})). + +%%-------------------------------------------------------------------- + +-define(try_match(E), + catch ?MODULE:non_existing(), + {'EXIT', {{badmatch, nomatch}, _}} = (catch E = no_match())). + +test_catch_crash() -> + ?try_match(a), + ?try_match(42), + ?try_match({a, b, c}), + ?try_match([]), + ?try_match(1.0), + ok. + +no_match() -> nomatch. + +%% small_test() -> +%% catch ?MODULE:non_existing(), +%% io:format("Before\n",[]), +%% hipe_bifs:show_nstack(self()), +%% io:format("After\n",[]), +%% garbage_collect(). + +%%-------------------------------------------------------------------- +%% Tests whether the HiPE compiler optimizes catches in a way that +%% does not result in an infinite loop. +%%-------------------------------------------------------------------- + +test_catch_empty() -> + badmatch(). + +badmatch() -> + Big = ret_big(), + Float = ret_float(), + catch a = Big, + catch b = Float, + ok = case Big of Big -> ok end, + ok = case Float of Float -> ok end, + ok. + +ret_big() -> + 329847987298478924982978248748729829487298292982972978239874. + +ret_float() -> + 3.1415927. + +%%-------------------------------------------------------------------- +%% Test that shows how BEAM can merge catch-end blocks that belong to +%% different catch-start instructions. Written by Richard Carlsson. +%%-------------------------------------------------------------------- + +test_catch_merge() -> + merge(get(whatever)). + +merge(foo=X) -> + catch f(X), + catch g(X); +merge(X) -> + catch f(X), + catch g(X). + +f(_) -> ok. + +g(_) -> ok. + +%%-------------------------------------------------------------------- +%% Written by Tobias Lindahl. + +test_catches_merged() -> + {'EXIT', _} = merged_catches(foo), + {'EXIT', {badarith, _}} = merged_catches(bar), + {'EXIT', _} = merged_catches(baz), + ok. + +merged_catches(X) -> + case X of + foo -> catch fail1(0); + bar -> catch {catch(1 = X), fail2(0)}; + baz -> catch fail3(0) + end. + +fail1(X) -> 1/X. + +fail2(X) -> 1/X. + +fail3(X) -> 1/X. + +%%-------------------------------------------------------------------- +%% Taken from exception_SUITE.erl +%%-------------------------------------------------------------------- + +test_pending_errors() -> + error_logger:tty(false), % disable printouts of error reports + pending_errors(). + +%% Test various exceptions, in the presence of a previous error +%% suppressed in a guard. +pending_errors() -> + pending(e_badmatch, {badmatch, b}), + pending(x, function_clause), + pending(e_case, {case_clause, xxx}), + pending(e_if, if_clause), + %% pending(e_badarith, badarith), + %% pending(e_undef, undef), + pending(e_timeoutval, timeout_value), + %% pending(e_badarg, badarg), + %% pending(e_badarg_spawn, badarg), + ok. + +bad_guy(pe_badarith, Other) when Other+1 =:= 0 -> % badarith (suppressed) + ok; +bad_guy(pe_badarg, Other) when length(Other) > 0 -> % badarg (suppressed) + ok; +bad_guy(_, e_case) -> + case xxx() of + ok -> ok + end; % case_clause +bad_guy(_, e_if) -> + B = b(), + if + a == B -> ok + end; % if_clause +%% bad_guy(_, e_badarith) -> +%% 1+b; % badarith +bad_guy(_, e_undef) -> + non_existing_module:foo(); % undef +bad_guy(_, e_timeoutval) -> + receive + after gazonk -> ok % timeout_value + end; +bad_guy(_, e_badarg) -> + node(xxx); % badarg +bad_guy(_, e_badarg_spawn) -> + spawn({}, {}, {}); % badarg +bad_guy(_, e_badmatch) -> + a = b(). % badmatch + +xxx() -> xxx. + +b() -> b. + +pending(Arg, Expected) -> + pending(pe_badarith, Arg, Expected), + pending(pe_badarg, Arg, Expected). + +pending(First, Second, Expected) -> + pending_catched(First, Second, Expected), + pending_exit_message([First, Second], Expected). + +pending_catched(First, Second, Expected) -> + %% ok = io:format("Catching bad_guy(~p, ~p)\n", [First, Second]), + case catch bad_guy(First, Second) of + {'EXIT', Reason} -> + pending(Reason, bad_guy, [First, Second], Expected); + Other -> + exit({not_exit, Other}) + end. + +pending_exit_message(Args, Expected) -> + %% ok = io:format("Trapping exits from spawn_link(~p, ~p, ~p)\n", + %% [?MODULE, bad_guy, Args]), + process_flag(trap_exit, true), + Pid = spawn_link(?MODULE, bad_guy, Args), + receive + {'EXIT', Pid, Reason} -> + pending(Reason, bad_guy, Args, Expected); + Other -> + exit({unexpected_message, Other}) + after 10000 -> + exit(timeout) + end, + process_flag(trap_exit, false). + +%% pending({badarg, [{erlang,Bif,BifArgs},{?MODULE,Func,Arity}|_]}, +%% Func, Args, _Code) +%% when atom(Bif), list(BifArgs), length(Args) =:= Arity -> +%% ok; +pending({badarg,Trace}, _, _, _) when is_list(Trace) -> + ok; +%% pending({undef,[{non_existing_module,foo,[]}|_]}, _, _, _) -> +%% ok; +pending({undef,Trace}, _, _, _) when is_list(Trace) -> + ok; +%% pending({function_clause,[{?MODULE,Func,Args}|_]}, Func, Args, _Code) -> +%% ok; +pending({function_clause,Trace}, _, _, _) when is_list(Trace) -> + ok; +%% pending({Code,[{?MODULE,Func,Arity}|_]}, Func, Args, Code) +%% when length(Args) =:= Arity -> +%% ok; +pending({Code,Trace}, _, _, Code) when is_list(Trace) -> + ok; +pending(Reason, _Function, _Args, _Code) -> + exit({bad_exit_reason, Reason}). + +%%-------------------------------------------------------------------- +%% Taken from fun_SUITE.erl +%% +%% Checks correct exception throwing when calling a bad fun. +%%-------------------------------------------------------------------- + +test_bad_fun_call() -> + ok = bad_call_fc(42), + ok = bad_call_fc(xx), + ok = bad_call_fc({}), + ok = bad_call_fc({1}), + ok = bad_call_fc({1,2,3}), + ok = bad_call_fc({1,2,3}), + ok = bad_call_fc({1,2,3,4}), + ok = bad_call_fc({1,2,3,4,5,6}), + ok = bad_call_fc({1,2,3,4,5}), + ok = bad_call_fc({1,2}), + ok. + +bad_call_fc(Fun) -> + Args = [some, stupid, args], + Res = (catch Fun(Fun(Args))), + case Res of + {'EXIT', {{badfun, Fun} ,_Where}} -> + ok; %% = io:format("~p(~p) -> ~p\n", [Fun, Args, Res]); + Other -> + io:format("~p(~p) -> ~p\n", [Fun, Args, Res]), + exit({bad_result, Other}) + end. + +%%-------------------------------------------------------------------- +%% Taken from guard_SUITE.erl +%% +%% Tests correct handling of exceptions by calling guard BIFs with +%% nasty (but legal arguments). +%%-------------------------------------------------------------------- + +test_guard_bif() -> + Big = -237849247829874297658726487367328971246284736473821617265433, + Float = 387924.874, + + %% Succeding use of guard bifs. + + try_gbif('abs/1', Big, -Big), + try_gbif('float/1', Big, float(Big)), + try_gbif('trunc/1', Float, 387924.0), + try_gbif('round/1', Float, 387925.0), + try_gbif('length/1', [], 0), + + try_gbif('length/1', [a], 1), + try_gbif('length/1', [a, b], 2), + try_gbif('length/1', lists:seq(0, 31), 32), + + try_gbif('hd/1', [a], a), + try_gbif('hd/1', [a, b], a), + + try_gbif('tl/1', [a], []), + try_gbif('tl/1', [a, b], [b]), + try_gbif('tl/1', [a, b, c], [b, c]), + + try_gbif('size/1', {}, 0), + try_gbif('size/1', {a}, 1), + try_gbif('size/1', {a, b}, 2), + try_gbif('size/1', {a, b, c}, 3), + try_gbif('size/1', list_to_binary([]), 0), + try_gbif('size/1', list_to_binary([1]), 1), + try_gbif('size/1', list_to_binary([1, 2]), 2), + try_gbif('size/1', list_to_binary([1, 2, 3]), 3), + + try_gbif('element/2', {x}, {1, x}), + try_gbif('element/2', {x, y}, {1, x}), + try_gbif('element/2', {x, y}, {2, y}), + + try_gbif('self/0', 0, self()), + try_gbif('node/0', 0, node()), + try_gbif('node/1', self(), node()), + + %% Failing use of guard bifs. + + try_fail_gbif('abs/1', Big, 1), + try_fail_gbif('abs/1', [], 1), + + try_fail_gbif('float/1', Big, 42), + try_fail_gbif('float/1', [], 42), + + try_fail_gbif('trunc/1', Float, 0.0), + try_fail_gbif('trunc/1', [], 0.0), + + try_fail_gbif('round/1', Float, 1.0), + try_fail_gbif('round/1', [], a), + + try_fail_gbif('length/1', [], 1), + try_fail_gbif('length/1', [a], 0), + try_fail_gbif('length/1', a, 0), + try_fail_gbif('length/1', {a}, 0), + + try_fail_gbif('hd/1', [], 0), + try_fail_gbif('hd/1', [a], x), + try_fail_gbif('hd/1', x, x), + + try_fail_gbif('tl/1', [], 0), + try_fail_gbif('tl/1', [a], x), + try_fail_gbif('tl/1', x, x), + + try_fail_gbif('size/1', {}, 1), + try_fail_gbif('size/1', [], 0), + try_fail_gbif('size/1', [a], 1), + try_fail_gbif('size/1', fun() -> 1 end, 0), + try_fail_gbif('size/1', fun() -> 1 end, 1), + + try_fail_gbif('element/2', {}, {1, x}), + try_fail_gbif('element/2', {x}, {1, y}), + try_fail_gbif('element/2', [], {1, z}), + + try_fail_gbif('self/0', 0, list_to_pid("<0.0.0>")), + try_fail_gbif('node/0', 0, xxxx), + try_fail_gbif('node/1', self(), xxx), + try_fail_gbif('node/1', yyy, xxx), + ok. + +try_gbif(Id, X, Y) -> + case guard_bif(Id, X, Y) of + {Id, X, Y} -> + %% io:format("guard_bif(~p, ~p, ~p) -- ok\n", [Id, X, Y]); + ok; + Other -> + ok = io:format("guard_bif(~p, ~p, ~p) -- bad result: ~p\n", + [Id, X, Y, Other]), + exit({bad_result,try_gbif}) + end. + +try_fail_gbif(Id, X, Y) -> + case catch guard_bif(Id, X, Y) of + %% {'EXIT', {function_clause,[{?MODULE,guard_bif,[Id,X,Y]}|_]}} -> + {'EXIT', {function_clause,_}} -> % in HiPE, a trace is not generated + %% io:format("guard_bif(~p, ~p, ~p) -- ok\n", [Id,X,Y]); + ok; + Other -> + ok = io:format("guard_bif(~p, ~p, ~p) -- bad result: ~p\n", + [Id, X, Y, Other]), + exit({bad_result,try_fail_gbif}) + end. + +guard_bif('abs/1', X, Y) when abs(X) == Y -> + {'abs/1', X, Y}; +guard_bif('float/1', X, Y) when float(X) == Y -> + {'float/1', X, Y}; +guard_bif('trunc/1', X, Y) when trunc(X) == Y -> + {'trunc/1', X, Y}; +guard_bif('round/1', X, Y) when round(X) == Y -> + {'round/1', X, Y}; +guard_bif('length/1', X, Y) when length(X) == Y -> + {'length/1', X, Y}; +guard_bif('hd/1', X, Y) when hd(X) == Y -> + {'hd/1', X, Y}; +guard_bif('tl/1', X, Y) when tl(X) == Y -> + {'tl/1', X, Y}; +guard_bif('size/1', X, Y) when size(X) == Y -> + {'size/1', X, Y}; +guard_bif('element/2', X, {Pos, Expected}) when element(Pos, X) == Expected -> + {'element/2', X, {Pos, Expected}}; +guard_bif('self/0', X, Y) when self() == Y -> + {'self/0', X, Y}; +guard_bif('node/0', X, Y) when node() == Y -> + {'node/0', X, Y}; +guard_bif('node/1', X, Y) when node(X) == Y -> + {'node/1', X, Y}. diff --git a/lib/hipe/test/basic_SUITE_data/basic_floats.erl b/lib/hipe/test/basic_SUITE_data/basic_floats.erl new file mode 100644 index 0000000000..eec175075a --- /dev/null +++ b/lib/hipe/test/basic_SUITE_data/basic_floats.erl @@ -0,0 +1,180 @@ +%%% -*- erlang-indent-level: 2 -*- +%%%------------------------------------------------------------------- +%%% Author: Kostis Sagonas +%%% +%%% Contains tests that manipulate floating point numbers. +%%%------------------------------------------------------------------- +-module(basic_floats). + +-export([test/0]). +-export([test_fmt_double_fpe_leak/0]). % suppress the unused warning + +test() -> + ok = test_arith_ops(), + ok = test_fp_ebb(), + ok = test_fp_phi(), + ok = test_big_bad_float(), + ok = test_catch_bad_fp_arith(), + ok = test_catch_fp_conv(), + ok = test_fp_with_fp_exceptions(), + %% ok = test_fmt_double_fpe_leak(), % this requires printing + ok. + +%%-------------------------------------------------------------------- + +test_arith_ops() -> + E = 2.5617, + 5.703200000000001 = add(E), + 0.5798000000000001 = sub(E), + 8.047580550000001 = mult(E), + -6.023e23 = negate(6.023e23), + ok. + +add(X) -> + 3.1415 + X. + +sub(X) -> + 3.1415 - X. + +mult(X) -> + 3.1415 * X. + +%% tests the translation of the fnegate BEAM instruction. +negate(X) -> + - (X + 0.0). + +%%-------------------------------------------------------------------- +%% Test the construction of overlapping extended basic blocks where +%% BEAM has constructed one and hipe_icode_fp constructs the other. +%%-------------------------------------------------------------------- + +test_fp_ebb() -> + 1.0 = foo(2 * math:pi()), + 1.0 = bar(2 * math:pi()), + ok. + +foo(X) -> + X / (2 * math:pi()). + +bar(X) -> + F = float_two(), + case F < 3.0 of + true -> (X * F) / ((2 * F) * math:pi()); + false -> weird + end. + +float_two() -> + 2.0. + +%%-------------------------------------------------------------------- + +test_fp_phi() -> + 10 = fp_phi(10, 100), + undefined = fp_phi(1.1e302, 0.000000001), + ok. + +fp_phi(A, B) -> + case catch A / B of + {'EXIT', _Reason} -> undefined; + _ -> round(100 * (A / B)) + end. + +%%-------------------------------------------------------------------- + +-define(BS, "93904329458954829589425849258998492384932849328493284932849328493284932389248329432932483294832949245827588578423578435783475834758375837580745807304258924584295924588459834958349589348589345934859384958349583945893458934859438593485995348594385943859438593458934589345938594385934859483958348934589435894859485943859438594594385938459438595034950439504395043950495043593485943758.0"). + +test_big_bad_float() -> + ok = try f2l(?BS) catch error:badarg -> ok end, + ok = case catch f2l(?BS) of {'EXIT', {badarg, _}} -> ok end, + ok. + +f2l(F) -> + float_to_list(list_to_float(F)). + +%%-------------------------------------------------------------------- +%% Tests catching of floating point bad arithmetic. + +test_catch_bad_fp_arith() -> + 5.7 = f(2.56), + {'EXIT', {badarith, _}} = bad_arith(9.9), + ok. + +f(F) when is_float(F) -> F + 3.14. + +bad_arith(F) when is_float(F) -> + catch F * 1.70000e+308. + +%%-------------------------------------------------------------------- +%% Tests proper catching of exceptions due to illegal convertion of +%% bignums to floating point numbers. + +test_catch_fp_conv() -> + F = 1.7e308, %% F is a number very close to a maximum float. + ok = big_arith(F), + ok = big_const_float(F), + ok. + +big_arith(F) -> + I = trunc(F), + {'EXIT', {badarith, _}} = big_int_arith(I), + ok. + +big_int_arith(I) when is_integer(I) -> + catch(3.0 + 2*I). + +big_const_float(F) -> + I = trunc(F), + badarith = try (1/(2*I)) catch error:Err -> Err end, + _ = 2/I, + {'EXIT', _} = (catch 4/(2*I)), + ok. + +%%-------------------------------------------------------------------- +%% Forces floating point exceptions and tests that subsequent, legal, +%% operations are calculated correctly. + +test_fp_with_fp_exceptions() -> + 0.0 = math:log(1.0), + badarith = try math:log(float_minus_one()) catch error:E1 -> E1 end, + 0.0 = math:log(1.0), + badarith = try math:log(float_zero()) catch error:E2 -> E2 end, + 0.0 = math:log(1.0), + %% An old-fashioned exception here just so as to test this case also + {'EXIT', _} = (catch fp_mult(3.23e133, 3.57e257)), + 0.0 = math:log(1.0), + badarith = try fp_div(5.0, 0.0) catch error:E3 -> E3 end, + 0.0 = math:log(1.0), + ok. + +fp_mult(X, Y) -> X * Y. + +fp_div(X, Y) -> X / Y. + +%% The following two function definitions appear here just to shut +%% off 'expression will fail with a badarg' warnings from the compiler + +float_zero() -> 0.0. + +float_minus_one() -> -1.0. + +%%-------------------------------------------------------------------- +%% Test that erl_printf_format.c:fmt_double() does not leak pending FP +%% exceptions to subsequent code. This used to break x87 FP code on +%% 32-bit x86. Based on a problem report from Richard Carlsson. + +test_fmt_double_fpe_leak() -> + test_fmt_double_fpe_leak(float_zero(), int_two()), + ok. + +%% We need the specific sequence of erlang:display/1 on a float that +%% triggers faulting ops in fmt_double() followed by a simple FP BIF. +%% We also need to repeat this at least three times. +test_fmt_double_fpe_leak(X, Y) -> + erlang:display(X), _ = math:log10(Y), + erlang:display(X), _ = math:log10(Y), + erlang:display(X), _ = math:log10(Y), + erlang:display(X), _ = math:log10(Y), + erlang:display(X), + math:log10(Y). + +int_two() -> 2. diff --git a/lib/hipe/test/basic_SUITE_data/basic_fun.erl b/lib/hipe/test/basic_SUITE_data/basic_fun.erl new file mode 100644 index 0000000000..18ba7fdb3f --- /dev/null +++ b/lib/hipe/test/basic_SUITE_data/basic_fun.erl @@ -0,0 +1,124 @@ +%%% -*- erlang-indent-level: 2 -*- +%%%------------------------------------------------------------------- +%%% Author: Kostis Sagonas +%%% +%%% Tests for correct handling of funs. +%%%------------------------------------------------------------------- +-module(basic_fun). + +-export([test/0]). + +-export([dummy_foo/4, add1/1, test_fun03/0]). + +test() -> + ok = test_calls(), + ok = test_is_function(), + ok = test_is_function2(), + ok. + +%%-------------------------------------------------------------------- +%% Tests function and fun calls. + +test_calls() -> + ok = test_apply_call(?MODULE, dummy_foo), + ok = test_fun_call(fun dummy_foo/4), + ok = test_fun_call(fun ?MODULE:dummy_foo/4), + ok. + +test_apply_call(M, F) -> + M:F(bar, 42, foo, 17). + +test_fun_call(Fun) -> + Fun(bar, 42, foo, 17). + +dummy_foo(_, _, foo, _) -> ok. + +%%-------------------------------------------------------------------- +%% Tests handling of funs out of exported functions and 2-tuple funs. + +test_fun03() -> + MFPair = add1_as_2tuple(), + 4712 = do_call(add1_as_export(), 4711), + {badfun, MFPair} = try do_call(MFPair, 88) catch error:Err -> Err end, + true = do_guard(add1_as_export()), + false = do_guard(MFPair), % 2-tuples do not satisfy is_function/1 + ok. + +do_call(F, X) -> F(X). + +do_guard(F) when is_function(F) -> true; +do_guard(_) -> false. + +add1_as_export() -> fun ?MODULE:add1/1. + +add1_as_2tuple() -> {?MODULE, add1}. + +add1(X) -> X+1. + +%%-------------------------------------------------------------------- +%% Tests the is_function guard and BIF. + +test_is_function() -> + Fun = fun (X, foo) -> dummy_foo(X, mnesia_lib, foo, [X]) end, + ok = test_when_guard(Fun), + ok = test_if_guard(Fun), + ok. + +test_when_guard(X) when is_function(X) -> ok. + +test_if_guard(X) -> + if is_function(X) -> ok; + true -> weird + end. + +%%-------------------------------------------------------------------- +%% Tests the is_function2 guard and BIF. + +test_is_function2() -> + ok = test_guard(), + ok = test_guard2(), + ok = test_call(), + ok. + +test_guard() -> + zero_fun = test_f2(fun () -> ok end), + unary_fun = test_f2(fun(X) -> X end), + binary_fun = test_f2(fun (X, Y) -> {X, Y} end), + no_fun = test_f2(gazonk), + ok. + +test_f2(Fun) when is_function(Fun, 0) -> + zero_fun; +test_f2(Fun) when is_function(Fun, 1) -> + unary_fun; +test_f2(Fun) when is_function(Fun, 2) -> + binary_fun; +test_f2(_) -> + no_fun. + +test_guard2() -> + zero_fun = test_f2_n(fun () -> ok end, 0), + unary_fun = test_f2_n(fun (X) -> X end, 1), + binary_fun = test_f2_n(fun (X, Y) -> {X, Y} end, 2), + no_fun = test_f2_n(gazonk, 0), + ok. + +test_f2_n(F, N) when is_function(F, N) -> + case N of + 0 -> zero_fun; + 1 -> unary_fun; + 2 -> binary_fun + end; +test_f2_n(_, _) -> + no_fun. + +test_call() -> + true = test_fn2(fun (X, Y) -> {X,Y} end, 2), + false = test_fn2(fun (X, Y) -> {X,Y} end, 3), + false = test_fn2(gazonk, 2), + {'EXIT', {badarg, _TR1}} = (catch test_fn2(gazonk, gazonk)), + {'EXIT', {badarg, _TR2}} = (catch test_fn2(fun (X, Y) -> {X, Y} end, gazonk)), + ok. + +test_fn2(F, N) -> + is_function(F, N). diff --git a/lib/hipe/test/basic_SUITE_data/basic_guards.erl b/lib/hipe/test/basic_SUITE_data/basic_guards.erl new file mode 100644 index 0000000000..81eeed7c3b --- /dev/null +++ b/lib/hipe/test/basic_SUITE_data/basic_guards.erl @@ -0,0 +1,164 @@ +%%% -*- erlang-indent-level: 2 -*- +%%%------------------------------------------------------------------- +%%% Author: Kostis Sagonas +%%% +%%% Contains tests for correct handling of guards and guard BIFs. +%%%------------------------------------------------------------------- +-module(basic_guards). + +-export([test/0]). +%% Prevent the inlining of the following functions +-export([bad_arith/0, bad_tuple/0, is_strange_guard/0]). + +test() -> + ok = guard0(4.2), + ok = guard1([foo]), + ok = test_guard2(), + ok = test_guard3(), + ok = test_guard4(), + ok = test_is_boolean(), + ok = test_bad_guards(), + ok. + +%%-------------------------------------------------------------------- + +guard0(X) when X /= 0, is_float(X) -> + ok. + +guard1(X) when is_atom(X) orelse is_float(X) -> + error1; +guard1(X) when is_reference(hd(X)) -> + error2; +guard1(X) when is_integer(hd(X)) -> + error3; +guard1(X) when hd(X) == foo -> + ok. + +%%-------------------------------------------------------------------- + +test_guard2() -> + ok1 = guard2(true), + not_boolean = guard2(42), + ok2 = guard2(false), + ok. + +guard2(X) when X -> % gets transformed to: is_boolean(X), X =:= true + ok1; +guard2(X) when X =:= false -> + ok2; +guard2(_) -> + not_boolean. + +%%-------------------------------------------------------------------- + +-define(is_foo(X), (is_atom(X) or (is_tuple(X) and (element(1, X) =:= 'foo')))). + +test_guard3() -> + no = f('foo'), + yes = f({'foo', 42}), + no = f(42), + ok. + +f(X) when ?is_foo(X) -> yes; +f(_) -> no. + +%%-------------------------------------------------------------------- + +-define(EXT_REF, <<131,114,0,3,100,0,19,114,101,102,95,116,101,115,116,95,98,117,103,64,103,111,114,98,97,103,2,0,0,0,125,0,0,0,0,0,0,0,0>>). + +test_guard4() -> + yes = is_ref(make_ref()), + no = is_ref(gazonk), + yes = is_ref(an_external_ref(?EXT_REF)), + ok. + +is_ref(Ref) when is_reference(Ref) -> yes; +is_ref(_Ref) -> no. + +an_external_ref(Bin) -> + binary_to_term(Bin). + +%%-------------------------------------------------------------------- + +test_is_boolean() -> + ok = is_boolean_in_if(), + ok = is_boolean_in_guard(). + +is_boolean_in_if() -> + ok1 = tif(true), + ok2 = tif(false), + not_bool = tif(other), + ok. + +is_boolean_in_guard() -> + ok = tg(true), + ok = tg(false), + not_bool = tg(other), + ok. + +tif(V) -> + Yes = yes(), %% just to prevent the optimizer removing this + if + %% the following line generates an is_boolean instruction + V, Yes == yes -> + %% while the following one does not (?!) + %% Yes == yes, V -> + ok1; + not(not(not(V))) -> + ok2; + V -> + ok3; + true -> + not_bool + end. + +tg(V) when is_boolean(V) -> + ok; +tg(_) -> + not_bool. + +yes() -> yes. + +%%-------------------------------------------------------------------- +%% original test by Bjorn G + +test_bad_guards() -> + ok = bad_arith(), + ok = bad_tuple(), + ok = is_strange_guard(), + ok. + +bad_arith() -> + 13 = bad_arith1(1, 12), + 42 = bad_arith1(1, infinity), + 42 = bad_arith1(infinity, 1), + 42 = bad_arith2(infinity, 1), + 42 = bad_arith3(inf), + 42 = bad_arith4(infinity, 1), + ok. + +bad_arith1(T1, T2) when (T1 + T2) < 17 -> T1 + T2; +bad_arith1(_, _) -> 42. + +bad_arith2(T1, T2) when (T1 * T2) < 17 -> T1 * T2; +bad_arith2(_, _) -> 42. + +bad_arith3(T) when (bnot T) < 17 -> T; +bad_arith3(_) -> 42. + +bad_arith4(T1, T2) when (T1 bsr T2) < 10 -> T1 bsr T2; +bad_arith4(_, _) -> 42. + +bad_tuple() -> + error = bad_tuple1(a), + error = bad_tuple1({a, b}), + x = bad_tuple1({x, b}), + y = bad_tuple1({a, b, y}), + ok. + +bad_tuple1(T) when element(1, T) =:= x -> x; +bad_tuple1(T) when element(3, T) =:= y -> y; +bad_tuple1(_) -> error. + +is_strange_guard() when is_tuple({1, bar, length([1, 2, 3, 4]), self()}) -> ok; +is_strange_guard() -> error. diff --git a/lib/hipe/test/basic_SUITE_data/basic_inline_function.erl b/lib/hipe/test/basic_SUITE_data/basic_inline_function.erl new file mode 100644 index 0000000000..4c08064670 --- /dev/null +++ b/lib/hipe/test/basic_SUITE_data/basic_inline_function.erl @@ -0,0 +1,73 @@ +%%% -*- erlang-indent-level: 2 -*- +%%%------------------------------------------------------------------- +%%% Author: Kostis Sagonas +%%% +%%% Contains tests that depend on the compiler inliner being turned on. +%%%------------------------------------------------------------------- +-module(basic_inline_function). + +-export([test/0]). + +-compile({inline, [{to_objects, 3}]}). + +test() -> + ok = test_inline_match(), + ok. + +%%-------------------------------------------------------------------- + +test_inline_match() -> + bad_object = test1(a, {binary, foo, set}, c), + bad_object = test2(a, {binary, foo, set}, c), + bad_object = test3(a, {binary, foo, set}, c), + ok. + +%% Inlined +test1(KeysObjs, C, Ts) -> + case catch to_objects(KeysObjs, C, Ts) of + {'EXIT', _} -> + bad_object; + ok -> + ok + end. + +%% "Inlined" by hand +test2(KeysObjs, C, _Ts) -> + case catch (case C of + {binary, _, set} -> + <<_ObjSz0:32, _T/binary>> = KeysObjs; + _ -> ok + end) of + {'EXIT', _} -> + bad_object; + ok -> + ok + end. + +%% Not inlined +test3(KeysObjs, C, Ts) -> + case catch fto_objects(KeysObjs, C, Ts) of + {'EXIT', _} -> + bad_object; + ok -> + ok + end. + +%% Inlined. +to_objects(Bin, {binary, _, set}, _Ts) -> + <<_ObjSz0:32, _T/binary>> = Bin, + ok; +to_objects(<<_ObjSz0:32, _T/binary>> ,_, _) -> + ok; +to_objects(_Bin, _, _Ts) -> + ok. + +%% Not Inlined. +fto_objects(Bin, {binary, _, set}, _Ts) -> + <<_ObjSz0:32, _T/binary>> = Bin, + ok; +fto_objects(<<_ObjSz0:32, _T/binary>> ,_,_) -> + ok; +fto_objects(_Bin, _, _Ts) -> + ok. + diff --git a/lib/hipe/test/basic_SUITE_data/basic_inline_module.erl b/lib/hipe/test/basic_SUITE_data/basic_inline_module.erl new file mode 100644 index 0000000000..306c6a39ce --- /dev/null +++ b/lib/hipe/test/basic_SUITE_data/basic_inline_module.erl @@ -0,0 +1,31 @@ +%%% -*- erlang-indent-level: 2 -*- +%%%------------------------------------------------------------------- +%%% Author: Kostis Sagonas +%%% +%%% Contains tests that depend on the compiler inliner being turned on. +%%%------------------------------------------------------------------- +-module(basic_inline_module). + +-export([test/0]). + +-compile([inline]). %% necessary for these tests + +test() -> + ok = test_case_end_atom(), + ok. + +%%-------------------------------------------------------------------- +%% Tests whether the translation of a case_end instruction works even +%% when an exception (no matching case pattern) is to be raised. + +test_case_end_atom() -> + {'EXIT',{{case_clause,some_atom},_Trace}} = (catch test_case_stm_inlining()), + ok. + +test_case_stm_inlining() -> + case some_atom() of + another_atom -> strange_result + end. + +some_atom() -> + some_atom. diff --git a/lib/hipe/test/basic_SUITE_data/basic_issues_beam.erl b/lib/hipe/test/basic_SUITE_data/basic_issues_beam.erl new file mode 100644 index 0000000000..73367c5c45 --- /dev/null +++ b/lib/hipe/test/basic_SUITE_data/basic_issues_beam.erl @@ -0,0 +1,326 @@ +%%% -*- erlang-indent-level: 2 -*- +%%%------------------------------------------------------------------- +%%% Author: Kostis Sagonas +%%% +%%% Contains code examples, mostly taken from the mailing list, that +%%% crashed the BEAM compiler or gave an internal error at some point. +%%%------------------------------------------------------------------- +-module(basic_issues_beam). + +-export([test/0]). + +test() -> + ok = test_crash_R10_hinde(), + ok = test_error_R10_mander(), + ok = test_error_R11_bjorklund(), + ok = test_error_R11_rath(), + ok = test_error_R12_empty_bin_rec(), + ok = test_bug_R12_cornish(), + ok = test_crash_R12_morris(), + ok = test_error_R13_almeida(), + ok = test_error_R13B01_fisher(), + ok = test_error_R13B01_sawatari(), + ok = test_error_R13B01_whongo(), + ok = test_error_R16B03_norell(), + ok = test_error_try_wings(), + ok. + +%%-------------------------------------------------------------------- +%% Fisher R10 compiler crash +%%-------------------------------------------------------------------- + +-record(r, {a, b, c}). + +test_crash_R10_hinde() -> + rec_R10_hinde(#r{}). + +rec_R10_hinde(As) -> + case As of + A when A#r.b == ""; A#r.b == undefined -> ok; + _ -> error + end. + +%%-------------------------------------------------------------------- +%% From: Peter-Henry Mander +%% Date: 27 Jan, 2005 +%% +%% I managed to isolate a non-critical BEAM compilation error +%% (internal error in v3_codegen) when compiling the following code: +%%-------------------------------------------------------------------- + +test_error_R10_mander() -> + try just_compile_me_R10() catch _:_ -> ok end. + +just_compile_me_R10() -> + URI_Before = + {absoluteURI, + {scheme, fun() -> nil end}, + {hier_part, + {net_path, + {srvr, + {userinfo, nil}, + fun() -> nil end}, + nil}, + {port, nil}}}, + {absoluteURI, + {scheme, _}, + {hier_part, + {net_path, + {srvr, + {userinfo, nil}, + _HostportBefore}, + nil}, + {port, nil}}} = URI_Before, + %% ... some funky code ommitted, not relevant ... + {absoluteURI, + {scheme, _}, + {hier_part, + {net_path, + {srvr, + {userinfo, nil}, + HostportAfter}, + nil}, + {port, nil}}} = URI_Before, + %% NOTE: I intended to write URI_After instead of URI_Before + %% but the accident revealed that when you add the line below, + %% it causes internal error in v3_codegen on compilation + {hostport, {hostname, "HostName"}, {port, nil}} = HostportAfter, + ok. + +%%-------------------------------------------------------------------- +%% From: Martin Bjorklund +%% Date: Aug 16, 2006 +%% +%% I found this compiler bug in R10B-10 and R11B-0. +%% +%% Function -just_compile_me/0-fun-2-/1 refers to undefined label 18 +%% ./bjorklund_R11compiler_bug.erl:none: internal error in beam_clean; +%% crash reason: {{case_clause,{'EXIT',{undefined_label,18}}}, +%% [{compile,'-select_passes/2-anonymous-2-',2}, +%% {compile,'-internal_comp/4-anonymous-1-',2}, +%% {compile,fold_comp,3}, +%% {compile,internal_comp,4}, +%% {compile,internal,3}]} +%%-------------------------------------------------------------------- + +test_error_R11_bjorklund() -> + just_compile_me_R11_bjorklund(). + +just_compile_me_R11_bjorklund() -> + G = fun() -> ok end, + try + G() %% fun() -> ok end + after + fun({A, B}) -> A + B end + end. + +%%-------------------------------------------------------------------- +%% From: Tim Rath +%% Date: Sep 13, 2006 +%% Subject: Compiler bug not quite fixed +%% +%% +%% I saw a compiler bug posted to the list by Martin Bjorklund that +%% appeared to be exactly the problem I'm seeing, and then noticed +%% that this was fixed in R11B-1. Unfortunately, though R11B-1 appears +%% to fix the code submitted by Martin, it does not fix my case. +%% +%% Function -just_compile_me/0-fun-2-/1 refers to undefined label 13 +%% ./rath_R11compiler_bug.erl:none: internal error in beam_clean; +%% crash reason: {{case_clause,{'EXIT',{undefined_label,13}}}, +%% [{compile,'-select_passes/2-anonymous-2-',2}, +%% {compile,'-internal_comp/4-anonymous-1-',2}, +%% {compile,fold_comp,3}, +%% {compile,internal_comp,4}, +%% {compile,internal,3}]} +%%-------------------------------------------------------------------- + +test_error_R11_rath() -> + just_compile_me_R11_rath(). + +just_compile_me_R11_rath() -> + A = {6}, + try + io:fwrite("") + after + fun () -> + fun () -> {_} = A end + end + end. + +%%---------------------------------------------------------------------- +%% Program that crashed the R12B-0 compiler: internal error in v3_codegen +%%---------------------------------------------------------------------- + +-record(rec, {a = <<>> :: binary(), b = 42 :: integer()}). + +test_error_R12_empty_bin_rec() -> + 42 = test_empty_bin_rec(#rec{}), + ok. + +test_empty_bin_rec(R) -> + #rec{a = <<>>} = R, + R#rec.b. + +%%---------------------------------------------------------------------- +%% From: Simon Cornish +%% Date: Jan 13, 2008 +%% +%% The attached Erlang code demonstrates an R12B-0 bug with funs. +%% Compile and evaluate the two die/1 calls for two different failure modes. +%% It seems to me that the live register check for call_fun is off by one. +%%---------------------------------------------------------------------- + +-record(b, {c}). + +test_bug_R12_cornish() -> + {a2, a} = die(a), + {a2, {b, c}} = die({b, c}), + ok. + +die(A) -> + F = fun() -> {ok, A} end, + if A#b.c =:= [] -> one; + true -> + case F() of + {ok, A2} -> {a2, A2}; + _ -> three + end + end. + +%%---------------------------------------------------------------------- +%% From: Hunter Morris +%% Date: Nov 20, 2008 +%% +%% The following code (tested with R12B-4 or R12B-5, vanilla compiler +%% options) produces a compiler crash. It's nonsensical, and I realise +%% that andalso can be quite evil, but it's a crash nonetheless. +%%---------------------------------------------------------------------- + +test_crash_R12_morris() -> + foo(42). + +foo(Bar) when (is_integer(Bar) andalso Bar =:= 0) ; Bar =:= 42 -> + ok. + +%%-------------------------------------------------------------------- +%% From: Paulo Sergio Almeida +%% Date: May 20, 2009 +%% +%% The following code when compiled under R13B gives a compiler error. +%% Function loop/1 refers to undefined label 6 +%% ./almeida_R13compiler_bug.erl:none: internal error in beam_peep; +%% crash reason: {{case_clause,{'EXIT',{undefined_label,6}}}, +%% [{compile,'-select_passes/2-anonymous-2-',2}, +%% {compile,'-internal_comp/4-anonymous-1-',2}, +%%-------------------------------------------------------------------- + +test_error_R13_almeida() -> + self() ! {backup, 42, false}, + loop([]). + +loop(Tids) -> + receive + {backup, Tid, Dumping} -> + case Dumping of + false -> ok; + _ -> receive {logged, Tab, Tid} -> put({log, Tab}, Tid) end + end, + collect(Tid, Tids, []) + end. + +collect(_, _, _) -> ok. + +%%-------------------------------------------------------------------- +%% Fisher R13B01 compiler error +%%-------------------------------------------------------------------- + +test_error_R13B01_fisher() -> + perform_select({foo, "42"}). + +perform_select({Type, Keyval}) -> + try + if is_atom(Type) andalso length(Keyval) > 0 -> ok; + true -> ok + end + catch + _:_ -> fail + end. + +%%-------------------------------------------------------------------- +%% From: Mikage Sawatari +%% Date: Jun 12, 2009 +%% +%% I have the following compilation problem on Erlang R13B01. +%% Compiler reports "Internal consistency check failed". +%%-------------------------------------------------------------------- + +test_error_R13B01_sawatari() -> + test_sawatari([1, null, 3], <<1, 2, 3>>). + +test_sawatari([], _Bin) -> ok; +test_sawatari([H|T], Bin) -> + _ = case H of + null -> <<Bin/binary>>; + _ -> ok + end, + test_sawatari(T, Bin). + +%%-------------------------------------------------------------------- + +test_error_R13B01_whongo() -> + S = "gazonk", + S = orgno_alphanum(S), + ok. + +orgno_alphanum(Cs) -> + [C || C <- Cs, ((C >= $0) andalso (C =< $9)) + orelse ((C >= $a) andalso (C =< $z)) + orelse ((C >= $A) andalso (C =< $Z))]. + +%%-------------------------------------------------------------------- +%% I'm getting an Internal Consistency Check error when attempting to +%% build Wings3D on Mac OS X 10.4.2 (Erlang OTP R10B-6): +%% +%% erlc -pa /ebin +warn_unused_vars -I/include -I ../e3d -W +debug_info +%% '-Dwings_version="0.98.31"' -pa ../ebin -o../ebin wings_color.erl +%% wings_color: function internal_rgb_to_hsv/3+97: +%% Internal consistency check failed - please report this bug. +%% Instruction: {test,is_eq_exact,{f,80},[{x,0},{atom,error}]} +%% Error: {unsafe_instruction,{float_error_state,cleared}}: +%% +%% The problem is the interaction of the 'try' construct with the +%% handling of FP exceptions. +%%-------------------------------------------------------------------- + +test_error_try_wings() -> + %% a call with a possible FP exception + {199.99999999999997, 0.045454545454545456, 44} = rgb_to_hsv(42, 43, 44), + ok. + +rgb_to_hsv(R, G, B) -> + Max = lists:max([R, G, B]), + Min = lists:min([R, G, B]), + V = Max, + {Hue, Sat} = try + {if Min == B -> (G-Min)/(R+G-2.0*Min); + Min == R -> (1.0+(B-Min)/(B+G-2.0*Min)); + Min == G -> (2.0+(R-Min)/(B+R-2.0*Min)) + end * 120, (Max-Min)/Max} + catch + error:badarith -> {undefined, 0.0} + end, + {Hue, Sat, V}. + +%%-------------------------------------------------------------------- +%% From: Ulf Norell +%% Date: Feb 28, 2014 +%% +%% This caused an internal error in v3_codegen +%%-------------------------------------------------------------------- + +test_error_R16B03_norell() -> + test_error_R16B03_norell(#r{}, gazonk). + +test_error_R16B03_norell(Rec, Tag) -> + is_record(Rec, Tag, 3) orelse ok. diff --git a/lib/hipe/test/basic_SUITE_data/basic_issues_hipe.erl b/lib/hipe/test/basic_SUITE_data/basic_issues_hipe.erl new file mode 100644 index 0000000000..e71045bfe2 --- /dev/null +++ b/lib/hipe/test/basic_SUITE_data/basic_issues_hipe.erl @@ -0,0 +1,153 @@ +%%% -*- erlang-indent-level: 2 -*- +%%%------------------------------------------------------------------- +%%% Author: Kostis Sagonas +%%% +%%% Contains code examples that exhibited crashes in the HiPE compiler. +%%%------------------------------------------------------------------- +-module(basic_issues_hipe). + +-export([test/0]). + +%% functions that need to be exported so that they are retained. +-export([auth/4]). + +test() -> + ok = test_dominance_trees(), + ok = test_merged_const(), + ok = test_var_pair(), + ok = test_bif_fails(), + ok = test_find_catches(), + ok = test_heap_allocate_trim(), + ok. + +%%-------------------------------------------------------------------- +%% This is taken from a file sent to us by Martin Bjorklund @ Nortel +%% on 14th November 2004. The problem was in the SSA unconvert pass. +%% +%% No tests here; we simply check that the HiPE compiler does not go +%% into an infinite loop when compiling strange functions like this. +%%-------------------------------------------------------------------- + +auth(_, A, B, C) -> + auth(A, B, C, []). + +%%-------------------------------------------------------------------- +%% Exposed a crash in the generation of dominance trees used in SSA. +%%-------------------------------------------------------------------- + +-record(state, {f}). + +test_dominance_trees() -> + {ok, true} = doit(true, #state{f = true}), + ok. + +doit(Foo, S) -> + Fee = case Foo of + Bar when Bar == S#state.f; Bar == [] -> true; + _ -> false + end, + {ok, Fee}. + +%%-------------------------------------------------------------------- +%% Checks that the merging of constants in the constant table uses the +%% appropriate comparison function for this. +%%-------------------------------------------------------------------- + +test_merged_const() -> + Const1 = {'', 1.0000}, + Const2 = {'', 1}, + match(Const1, Const2). + +match(A, A) -> + error; +match(_A, _B) -> + ok. + +%%-------------------------------------------------------------------- +%% Checks that the HiPE compiler does not get confused by constant +%% data structures similar to the internal compiler data structures. +%%-------------------------------------------------------------------- + +test_var_pair() -> + ok = var_pair([gazonk]). + +var_pair([_|_]) -> + var_pair({var, some_atom}); +var_pair(_) -> + ok. + +%%-------------------------------------------------------------------- +%% This module was causing the HiPE compiler to crash in January 2007. +%% The culprit was an "optimization" of the BEAM compiler: postponing +%% the save of x variables when BIFs cannot fail. This was fixed on +%% February 1st, by making the HiPE compiler use the same functions +%% as the BEAM compiler for deciding whether a BIF fails. +%%-------------------------------------------------------------------- + +test_bif_fails() -> + [42] = bif_fails_in_catch([42]), + true = bif_fails_in_try([42]), + ok. + +bif_fails_in_catch(X) -> + case catch get(gazonk) of + _ -> X + end. + +bif_fails_in_try(X) -> + try + true = X =/= [] + catch + _ -> nil(X) + end. + +nil(_) -> []. + +%%-------------------------------------------------------------------- +%% Test that resulted in a native code compiler crash in the code of +%% hipe_icode_exceptions:find_catches/1 when compiling find_catches/2. +%%-------------------------------------------------------------------- + +test_find_catches() -> + 42 = find_catches(a, false), + ok. + +find_catches(X, Y) -> + case X of + a when Y =:= true -> + catch id(X), + X; + b when Y =:= true -> + catch id(X), + X; + a -> + catch id(X), + 42; + b -> + catch id(X), + 42 + end. + +id(X) -> X. + +%%-------------------------------------------------------------------- +%% Date: Dec 28, 2007 +%% +%% This is a test adapted from the file sent to the Erlang mailing +%% list by Eranga Udesh. The file did not compile because of problems +%% with the heap_allocate instruction and stack trimming. +%%-------------------------------------------------------------------- + +test_heap_allocate_trim() -> + {abandon, 42} = get_next_retry(a, 42), + ok. + +get_next_retry(Error, Count) -> + case catch pair(retry_scheme, {Error, Count}) of + _ -> + case pair(Error, Count) of + _ -> {abandon, Count} + end + end. + +pair(A, B) -> {A, B}. diff --git a/lib/hipe/test/basic_SUITE_data/basic_lists.erl b/lib/hipe/test/basic_SUITE_data/basic_lists.erl new file mode 100644 index 0000000000..264a7f86f6 --- /dev/null +++ b/lib/hipe/test/basic_SUITE_data/basic_lists.erl @@ -0,0 +1,61 @@ +%%% -*- erlang-indent-level: 2 -*- +%%%------------------------------------------------------------------- +%%% Author: Kostis Sagonas +%%% +%%% Contains tests that manipulate and pattern match against lists +%%% (perhaps by calling functions from the 'lists' module). +%%%------------------------------------------------------------------- +-module(basic_lists). + +-export([test/0]). + +test() -> + ok = test_length(), + ok = test_lists_key(), + ok = test_lists_and_strings(), + ok. + +%%-------------------------------------------------------------------- + +test_length() -> + Len = 42, + Lst = mklist(Len, []), + Len = iterate(100, Lst), + ok. + +mklist(0, L) -> L; +mklist(X, L) -> mklist(X-1, [X|L]). + +iterate(0, L) -> len(L, 0); +iterate(X, L) -> len(L, 0), iterate(X-1, L). + +len([_|X], L) -> len(X, L+1); +len([], L) -> L. + +%%-------------------------------------------------------------------- + +test_lists_key() -> + First = {x, 42.0}, + Second = {y, -77}, + Third = {z, [a, b, c], {5.0}}, + List = [First, Second, Third], + {value, First} = key_search_find(42, 2, List), + ok. + +key_search_find(Key, Pos, List) -> + case lists:keyfind(Key, Pos, List) of + false -> + false = lists:keysearch(Key, Pos, List); + Tuple when is_tuple(Tuple) -> + {value, Tuple} = lists:keysearch(Key, Pos, List) + end. + +%%-------------------------------------------------------------------- + +test_lists_and_strings() -> + LL = ["H'A", " H'B", " H'C"], + LL2 = lists:map(fun string:strip/1, LL), + HexFormat = fun(X, Acc) -> {string:substr(X, 3), Acc} end, + {LL3,_Ret} = lists:mapfoldl(HexFormat, 0, LL2), + ["A", "B", "C"] = lists:sublist(LL3, 42), + ok. diff --git a/lib/hipe/test/basic_SUITE_data/basic_module_info.erl b/lib/hipe/test/basic_SUITE_data/basic_module_info.erl new file mode 100644 index 0000000000..cab48b10ba --- /dev/null +++ b/lib/hipe/test/basic_SUITE_data/basic_module_info.erl @@ -0,0 +1,32 @@ +%%% -*- erlang-indent-level: 2 -*- +%%%------------------------------------------------------------------- +%%% Author: Kostis Sagonas +%%% Date: Oct 25, 2003 +%%% +%%% Tests whether calling module_info from the same module works. +%%% This seems trivial, but the problem is that the module_info/[0,1] +%%% functions that the BEAM file contains used to be dummy functions +%%% containing crap. So, these functions could not be used for +%%% compilation to native code and the functions that the BEAM loader +%%% generates should have been used instead. This was a HiPE bug +%%% reported by Dan Wallin. +%%%------------------------------------------------------------------- +-module(basic_module_info). + +-export([test/0]). + +test() -> + L = test_local_mi0_call(), + E = test_remote_mi1_call(), + {3, 3} = {L, E}, + ok. + +test_local_mi0_call() -> + ModInfo = module_info(), + %% io:format("ok, ModInfo=~w\n", [ModInfo]), + {exports, FunList} = lists:keyfind(exports, 1, ModInfo), + length(FunList). + +test_remote_mi1_call() -> + FunList = ?MODULE:module_info(exports), + length(FunList). diff --git a/lib/hipe/test/basic_SUITE_data/basic_pattern_match.erl b/lib/hipe/test/basic_SUITE_data/basic_pattern_match.erl new file mode 100644 index 0000000000..93240354a7 --- /dev/null +++ b/lib/hipe/test/basic_SUITE_data/basic_pattern_match.erl @@ -0,0 +1,46 @@ +%%% -*- erlang-indent-level: 2 -*- +%%%------------------------------------------------------------------- +%%% Author: Kostis Sagonas +%%% +%%% Contains code examples that test pattern matching against terms of +%%% various types. +%%%------------------------------------------------------------------- +-module(basic_pattern_match). + +-export([test/0]). + +test() -> + ok = test_hello_world(), + ok = test_list_plus_plus_match(), + ok. + +%%-------------------------------------------------------------------- +%% Trivial test to test pattern matching compilation with atoms, the +%% correct handling of all sorts of alphanumeric types in Erlang, and +%% conversions between them. + +test_hello_world() -> + String = gimme(string), + String = atom_to_list(gimme(atom)), + String = binary_to_list(gimme(binary)), + true = (list_to_atom(String) =:= gimme(atom)), + true = (list_to_binary(String) =:= gimme(binary)), + ok. + +gimme(string) -> + "hello world"; +gimme(atom) -> + 'hello world'; +gimme(binary) -> + <<"hello world">>. + +%%-------------------------------------------------------------------- +%% Makes sure that pattern matching expressions involving ++ work OK. +%% The third expression caused a problem in the Erlang shell of R11B-5. +%% It worked OK in both interpreted and compiled code. + +test_list_plus_plus_match() -> + ok = (fun("X" ++ _) -> ok end)("X"), + ok = (fun([$X | _]) -> ok end)("X"), + ok = (fun([$X] ++ _) -> ok end)("X"), + ok. diff --git a/lib/hipe/test/basic_SUITE_data/basic_random.erl b/lib/hipe/test/basic_SUITE_data/basic_random.erl new file mode 100644 index 0000000000..783947bd31 --- /dev/null +++ b/lib/hipe/test/basic_SUITE_data/basic_random.erl @@ -0,0 +1,238 @@ +%%% -*- erlang-indent-level: 2 -*- +%%%------------------------------------------------------------------- +%%% Author: Kostis Sagonas +%%% +%%% A test for list handling created using the 'random' module. +%%%------------------------------------------------------------------- +-module(basic_random). + +-export([test/0]). + +%% It can be used as a benchmark by playing with the following defines +-define(N, 1000). +-define(Iter, 500). + +test() -> + ok = random(?N). + +random(N) -> + random(N, ?Iter). + +random(N, Iter) -> + random:seed(1, 2, 3), + t(ranlist(N, [], N*100), Iter). + +ranlist(0, L, _N) -> L; +ranlist(N, L, N0) -> ranlist(N-1, [random:uniform(N0)+300 | L], N0). + +t(_, 0) -> ok; +t(L, Iter) -> + %% io:format("Sort starting~n"), + sort(L), + t(L, Iter-1). + +sort([X, Y | L]) when X =< Y -> + split_1(X, Y, L, [], []); +sort([X, Y | L]) -> + split_2(X, Y, L, [], []); +sort(L) -> + L. + +%% Ascending. +split_1(X, Y, [Z | L], R, Rs) when Z >= Y -> + split_1(Y, Z, L, [X | R], Rs); +split_1(X, Y, [Z | L], R, Rs) when Z >= X -> + split_1(Z, Y, L, [X | R], Rs); +split_1(X, Y, [Z | L], [], Rs) -> + split_1(X, Y, L, [Z], Rs); +split_1(X, Y, [Z | L], R, Rs) -> + split_1_1(X, Y, L, R, Rs, Z); +split_1(X, Y, [], R, Rs) -> + rmergel([[Y, X | R] | Rs], []). + +%% One out-of-order element, S. +split_1_1(X, Y, [Z | L], R, Rs, S) when Z >= Y -> + split_1_1(Y, Z, L, [X | R], Rs, S); +split_1_1(X, Y, [Z | L], R, Rs, S) when Z >= X -> + split_1_1(Z, Y, L, [X | R], Rs, S); +split_1_1(X, Y, [Z | L], R, Rs, S) when S =< Z -> + split_1(S, Z, L, [], [[Y, X | R] | Rs]); +split_1_1(X, Y, [Z | L], R, Rs, S) -> + split_1(Z, S, L, [], [[Y, X | R] | Rs]); +split_1_1(X, Y, [], R, Rs, S) -> + rmergel([[S], [Y, X | R] | Rs], []). + +%% Descending. +split_2(X, Y, [Z | L], R, Rs) when Z =< Y -> + split_2(Y, Z, L, [X | R], Rs); +split_2(X, Y, [Z | L], R, Rs) when Z =< X -> + split_2(Z, Y, L, [X | R], Rs); +split_2(X, Y, [Z | L], [], Rs) -> + split_2(X, Y, L, [Z], Rs); +split_2(X, Y, [Z | L], R, Rs) -> + split_2_1(X, Y, L, R, Rs, Z); +split_2(X, Y, [], R, Rs) -> + mergel([[Y, X | R] | Rs], []). + +split_2_1(X, Y, [Z | L], R, Rs, S) when Z =< Y -> + split_2_1(Y, Z, L, [X | R], Rs, S); +split_2_1(X, Y, [Z | L], R, Rs, S) when Z =< X -> + split_2_1(Z, Y, L, [X | R], Rs, S); +split_2_1(X, Y, [Z | L], R, Rs, S) when S > Z -> + split_2(S, Z, L, [], [[Y, X | R] | Rs]); +split_2_1(X, Y, [Z | L], R, Rs, S) -> + split_2(Z, S, L, [], [[Y, X | R] | Rs]); +split_2_1(X, Y, [], R, Rs, S) -> + mergel([[S], [Y, X | R] | Rs], []). + +mergel([[] | L], Acc) -> + mergel(L, Acc); +mergel([A, [H2 | T2], [H3 | T3] | L], Acc) -> + mergel(L, [merge3_1(A, [], H2, T2, H3, T3) | Acc]); +mergel([A, [H | T]], Acc) -> + rmergel([merge2_1(A, H, T, []) | Acc], []); +mergel([L], []) -> + L; +mergel([L], Acc) -> + rmergel([lists:reverse(L, []) | Acc], []); +mergel([], []) -> + []; +mergel([], Acc) -> + rmergel(Acc, []); +mergel([A, [] | L], Acc) -> + mergel([A | L], Acc); +mergel([A, B, [] | L], Acc) -> + mergel([A, B | L], Acc). + +rmergel([A, [H2 | T2], [H3 | T3] | L], Acc) -> + rmergel(L, [rmerge3_1(A, [], H2, T2, H3, T3) | Acc]); +rmergel([A, [H | T]], Acc) -> + mergel([rmerge2_1(A, H, T, []) | Acc], []); +rmergel([L], Acc) -> + mergel([lists:reverse(L, []) | Acc], []); +rmergel([], Acc) -> + mergel(Acc, []). + +%% Take L1 apart. +merge3_1([H1 | T1], M, H2, T2, H3, T3) when H1 =< H2 -> + merge3_12(T1, H1, H2, T2, H3, T3, M); +merge3_1([H1 | T1], M, H2, T2, H3, T3) -> + merge3_21(T1, H1, H2, T2, H3, T3, M); +merge3_1(_nil, M, H2, T2, H3, T3) when H2 =< H3 -> + merge2_1(T2, H3, T3, [H2 | M]); +merge3_1(_nil, M, H2, T2, H3, T3) -> + merge2_1(T3, H2, T2, [H3 | M]). + +%% Take L2 apart. +merge3_2(T1, H1, M, [H2 | T2], H3, T3) when H1 =< H2 -> + merge3_12(T1, H1, H2, T2, H3, T3, M); +merge3_2(T1, H1, M, [H2 | T2], H3, T3) -> + merge3_21(T1, H1, H2, T2, H3, T3, M); +merge3_2(T1, H1, M, _nil, H3, T3) when H1 =< H3 -> + merge2_1(T1, H3, T3, [H1 | M]); +merge3_2(T1, H1, M, _nil, H3, T3) -> + merge2_1(T3, H1, T1, [H3 | M]). + +%% H1 <= H2. Inlined. +merge3_12(T1, H1, H2, T2, H3, T3, M) when H3 < H1 -> + merge3_12_3(T1, H1, H2, T2, [H3 | M], T3); +merge3_12(T1, H1, H2, T2, H3, T3, M) -> + merge3_1(T1, [H1 | M], H2, T2, H3, T3). + +%% H1 <= H2, take L3 apart. +merge3_12_3(T1, H1, H2, T2, M, [H3 | T3]) when H3 < H1 -> + merge3_12_3(T1, H1, H2, T2, [H3 | M], T3); +merge3_12_3(T1, H1, H2, T2, M, [H3 | T3]) -> + merge3_1(T1, [H1 | M], H2, T2, H3, T3); +merge3_12_3(T1, H1, H2, T2, M, _nil) -> + merge2_1(T1, H2, T2, [H1 | M]). + +%% H1 > H2. Inlined. +merge3_21(T1, H1, H2, T2, H3, T3, M) when H3 < H2 -> + merge3_21_3(T1, H1, H2, T2, [H3 | M], T3); +merge3_21(T1, H1, H2, T2, H3, T3, M) -> + merge3_2(T1, H1, [H2 | M], T2, H3, T3). + +%% H1 > H2, take L3 apart. +merge3_21_3(T1, H1, H2, T2, M, [H3 | T3]) when H3 < H2 -> + merge3_21_3(T1, H1, H2, T2, [H3 | M], T3); +merge3_21_3(T1, H1, H2, T2, M, [H3 | T3]) -> + merge3_2(T1, H1, [H2 | M], T2, H3, T3); +merge3_21_3(T1, H1, H2, T2, M, _nil) -> + merge2_1(T2, H1, T1, [H2 | M]). + +%% Take L1 apart. +rmerge3_1([H1 | T1], M, H2, T2, H3, T3) when H1 > H2 -> + rmerge3_12(T1, H1, H2, T2, H3, T3, M); +rmerge3_1([H1 | T1], M, H2, T2, H3, T3) -> + rmerge3_21(T1, H1, H2, T2, H3, T3, M); +rmerge3_1(_nil, M, H2, T2, H3, T3) when H2 > H3 -> + rmerge2_1(T2, H3, T3, [H2 | M]); +rmerge3_1(_nil, M, H2, T2, H3, T3) -> + rmerge2_1(T3, H2, T2, [H3 | M]). + +%% Take L2 apart. +rmerge3_2(T1, H1, M, [H2 | T2], H3, T3) when H1 > H2 -> + rmerge3_12(T1, H1, H2, T2, H3, T3, M); +rmerge3_2(T1, H1, M, [H2 | T2], H3, T3) -> + rmerge3_21(T1, H1, H2, T2, H3, T3, M); +rmerge3_2(T1, H1, M, _nil, H3, T3) when H1 > H3 -> + rmerge2_1(T1, H3, T3, [H1 | M]); +rmerge3_2(T1, H1, M, _nil, H3, T3) -> + rmerge2_1(T3, H1, T1, [H3 | M]). + +%% H1 > H2. Inlined. +rmerge3_12(T1, H1, H2, T2, H3, T3, M) when H3 >= H1 -> + rmerge3_12_3(T1, H1, H2, T2, [H3 | M], T3); +rmerge3_12(T1, H1, H2, T2, H3, T3, M) -> + rmerge3_1(T1, [H1 | M], H2, T2, H3, T3). + +%% H1 > H2, take L3 apart. +rmerge3_12_3(T1, H1, H2, T2, M, [H3 | T3]) when H3 >= H1 -> + rmerge3_12_3(T1, H1, H2, T2, [H3 | M], T3); +rmerge3_12_3(T1, H1, H2, T2, M, [H3 | T3]) -> + rmerge3_1(T1, [H1 | M], H2, T2, H3, T3); +rmerge3_12_3(T1, H1, H2, T2, M, _nil) -> + rmerge2_1(T1, H2, T2, [H1 | M]). + +%% H1 =< H2. Inlined. +rmerge3_21(T1, H1, H2, T2, H3, T3, M) when H3 >= H2 -> + rmerge3_21_3(T1, H1, H2, T2, [H3 | M], T3); +rmerge3_21(T1, H1, H2, T2, H3, T3, M) -> + rmerge3_2(T1, H1, [H2 | M], T2, H3, T3). + +%% H1 =< H2, take L3 apart. +rmerge3_21_3(T1, H1, H2, T2, M, [H3 | T3]) when H3 >= H2 -> + rmerge3_21_3(T1, H1, H2, T2, [H3 | M], T3); +rmerge3_21_3(T1, H1, H2, T2, M, [H3 | T3]) -> + rmerge3_2(T1, H1, [H2 | M], T2, H3, T3); +rmerge3_21_3(T1, H1, H2, T2, M, _nil) -> + rmerge2_1(T2, H1, T1, [H2 | M]). + +merge2_1([H1 | T1], H2, T2, M) when H2 < H1 -> + merge2_2(T1, H1, T2, [H2 | M]); +merge2_1([H1 | T1], H2, T2, M) -> + merge2_1(T1, H2, T2, [H1 | M]); +merge2_1(_nil, H2, T2, M) -> + lists:reverse(T2, [H2 | M]). + +merge2_2(T1, H1, [H2 | T2], M) when H1 < H2 -> + merge2_1(T1, H2, T2, [H1 | M]); +merge2_2(T1, H1, [H2 | T2], M) -> + merge2_2(T1, H1, T2, [H2 | M]); +merge2_2(T1, H1, _nil, M) -> + lists:reverse(T1, [H1 | M]). + +rmerge2_1([H1 | T1], H2, T2, M) when H2 >= H1 -> + rmerge2_2(T1, H1, T2, [H2 | M]); +rmerge2_1([H1 | T1], H2, T2, M) -> + rmerge2_1(T1, H2, T2, [H1 | M]); +rmerge2_1(_nil, H2, T2, M) -> + lists:reverse(T2, [H2 | M]). + +rmerge2_2(T1, H1, [H2 | T2], M) when H1 >= H2 -> + rmerge2_1(T1, H2, T2, [H1 | M]); +rmerge2_2(T1, H1, [H2 | T2], M) -> + rmerge2_2(T1, H1, T2, [H2 | M]); +rmerge2_2(T1, H1, _nil, M) -> + lists:reverse(T1, [H1 | M]). diff --git a/lib/hipe/test/basic_SUITE_data/basic_receive.erl b/lib/hipe/test/basic_SUITE_data/basic_receive.erl new file mode 100644 index 0000000000..5f865d7b7a --- /dev/null +++ b/lib/hipe/test/basic_SUITE_data/basic_receive.erl @@ -0,0 +1,56 @@ +%%% -*- erlang-indent-level: 2 -*- +%%%------------------------------------------------------------------- +%%% Author: Kostis Sagonas +%%% +%%% Contains code examples that test correct handling of receives. +%%%------------------------------------------------------------------- +-module(basic_receive). + +-export([test/0]). + +test() -> + ok = test_wait_timeout(), + ok = test_double_timeout(), + ok = test_reschedule(), + ok. + +%%-------------------------------------------------------------------- + +test_wait_timeout() -> + receive after 42 -> ok end. + +%%-------------------------------------------------------------------- + +test_double_timeout() -> + self() ! foo, + self() ! another_foo, + receive + non_existent -> weird + after 0 -> timeout + end, + receive + foo -> ok + after 1000 -> timeout + end. + +%%-------------------------------------------------------------------- +%% Check that RESCHEDULE returns from BIFs work. + +test_reschedule() -> + erts_debug:set_internal_state(available_internal_state, true), + First = self(), + Second = spawn(fun() -> doit(First) end), + receive + Second -> ok + end, + receive + after 42 -> ok + end, + erts_debug:set_internal_state(hipe_test_reschedule_resume, Second), + ok. + +doit(First) -> + First ! self(), + erts_debug:set_internal_state(hipe_test_reschedule_suspend, 1). + +%%-------------------------------------------------------------------- diff --git a/lib/hipe/test/basic_SUITE_data/basic_records.erl b/lib/hipe/test/basic_SUITE_data/basic_records.erl new file mode 100644 index 0000000000..cbb451196c --- /dev/null +++ b/lib/hipe/test/basic_SUITE_data/basic_records.erl @@ -0,0 +1,28 @@ +%% -*- erlang-indent-level: 2 -*- +%%%------------------------------------------------------------------- +%%% Author: Kostis Sagonas +%%% +%%% Contains tests that manipulate and pattern match against records. +%%%------------------------------------------------------------------- +-module(basic_records). + +-export([test/0]). + +test() -> + ok = test_rec1(), + ok. + +%%-------------------------------------------------------------------- + +-record(r, {ra}). +-record(s, {sa, sb, sc, sd}). + +test_rec1() -> + R = #r{}, + S = #s{}, + S1 = S#s{sc=R, sd=1}, + R1 = S1#s.sc, + undefined = R1#r.ra, + ok. + +%%-------------------------------------------------------------------- diff --git a/lib/hipe/test/basic_SUITE_data/basic_strength_reduce.erl b/lib/hipe/test/basic_SUITE_data/basic_strength_reduce.erl new file mode 100644 index 0000000000..0f94320a33 --- /dev/null +++ b/lib/hipe/test/basic_SUITE_data/basic_strength_reduce.erl @@ -0,0 +1,65 @@ +%%% -*- erlang-indent-level: 2 -*- +%%%------------------------------------------------------------------- +%%% Author: Kostis Sagonas +%%% +%%% Tests the strength reduction component of the HiPE compiler. +%%%------------------------------------------------------------------- +-module(basic_strength_reduce). + +-export([test/0]). +%% These functions are exported so as to not remove them by inlining +-export([crash_0/1, crash_1/1, crash_2/1, crash_3/1, bug_div_2N/1]). + +test() -> + ok = test_strength_reduce1(), + ok. + +%%-------------------------------------------------------------------- + +test_strength_reduce1() -> + ok = crash_0(0), + ok = crash_1(42), + ok = crash_2(42), + ok = crash_3(42), + 5 = 42 bsr 3 = bug_div_2N(42), + -6 = -42 bsr 3 = bug_div_2N(-42) - 1, + ok. + +%% This is a crash report by Peter Wang (10 July 2007) triggering an +%% R11B-5 crash: strength reduction could not handle calls with no +%% destination +crash_0(A) -> + case A of + 0 -> + A div 8, + ok + end. + +%% The above was simplified to the following which showed another +%% crash, this time on RTL +crash_1(A) when is_integer(A), A >= 0 -> + A div 8, + ok. + +%% A similar crash like the first one, but in a different place in the +%% code, was triggered by the following code +crash_2(A) when is_integer(A), A >= 0 -> + A div 1, + ok. + +%% A crash similar to the first one happened in the following code +crash_3(A) -> + case A of + 42 -> + A * 0, + ok + end. + +%% Strength reduction for div/2 and rem/2 with a power of 2 +%% should be performed only for non-negative integers +bug_div_2N(X) when is_integer(X), X >= 0 -> + X div 8; +bug_div_2N(X) when is_integer(X), X < 0 -> + X div 8. + +%%-------------------------------------------------------------------- diff --git a/lib/hipe/test/basic_SUITE_data/basic_switches.erl b/lib/hipe/test/basic_SUITE_data/basic_switches.erl new file mode 100644 index 0000000000..0a7ae5b8b7 --- /dev/null +++ b/lib/hipe/test/basic_SUITE_data/basic_switches.erl @@ -0,0 +1,52 @@ +%%% -*- erlang-indent-level: 2 -*- +%%%------------------------------------------------------------------- +%%% Author: Kostis Sagonas +%%% +%%% Contains tests for pattern matching switches. +%%%------------------------------------------------------------------- +-module(basic_switches). + +-export([test/0]). + +test() -> + ok = test_switch_mix(), + ok. + +%%--------------------------------------------------------------------- + +-define(BIG1, 21323233222132323322). +-define(BIG2, 4242424242424242424242424242424242). + +test_switch_mix() -> + small1 = t(42), + small2 = t(17), + big1 = t(?BIG1), + big2 = t(?BIG2), + atom = t(foo), + pid = t(self()), + float = t(4.2), + ok. + +t(V) -> + S = self(), + case V of + 42 -> small1; + 17 -> small2; + ?BIG1 -> big1; + ?BIG2 -> big2; + 1 -> no; + 2 -> no; + 3 -> no; + 4 -> no; + 5 -> no; + 6 -> no; + 7 -> no; + 8 -> no; + foo -> atom; + 9 -> no; + 4.2 -> float; + S -> pid; + _ -> no + end. + +%%--------------------------------------------------------------------- diff --git a/lib/hipe/test/basic_SUITE_data/basic_tail_rec.erl b/lib/hipe/test/basic_SUITE_data/basic_tail_rec.erl new file mode 100644 index 0000000000..0124f13df6 --- /dev/null +++ b/lib/hipe/test/basic_SUITE_data/basic_tail_rec.erl @@ -0,0 +1,39 @@ +%%% -*- erlang-indent-level: 2 -*- +%%%------------------------------------------------------------------- +%%% Author: Kostis Sagonas +%%% +%%% Contains tests that check that tail recursion optimization occurs. +%%%------------------------------------------------------------------- +-module(basic_tail_rec). + +-export([test/0]). +-export([app0/2]). %% used in an apply/3 call + +test() -> + ok = test_app_tail(), + ok. + +%%-------------------------------------------------------------------- +%% Written by Mikael Pettersson: check that apply is tail recursive. + +%% Increased the following quantity from 20 to 30 so that the test +%% remains valid even with the naive register allocator. - Kostis +-define(SIZE_INCREASE, 30). + +test_app_tail() -> + Inc = start(400), + %% io:format("Inc ~w\n", [Inc]), + case Inc > ?SIZE_INCREASE of + true -> + {error, "apply/3 is not tail recursive in native code"}; + false -> + ok + end. + +start(N) -> + app0(N, hipe_bifs:nstack_used_size()). + +app0(0, Size0) -> + hipe_bifs:nstack_used_size() - Size0; +app0(N, Size) -> + apply(?MODULE, app0, [N-1, Size]). diff --git a/lib/hipe/test/basic_SUITE_data/basic_tuples.erl b/lib/hipe/test/basic_SUITE_data/basic_tuples.erl new file mode 100644 index 0000000000..94c187e364 --- /dev/null +++ b/lib/hipe/test/basic_SUITE_data/basic_tuples.erl @@ -0,0 +1,177 @@ +%%% -*- erlang-indent-level: 2 -*- +%%%------------------------------------------------------------------- +%%% Author: Kostis Sagonas +%%% +%%% Contains tests that manipulate and pattern match against tuples. +%%%------------------------------------------------------------------- +-module(basic_tuples). + +-export([test/0]). + +test() -> + Num = 4711, + ok = test_match({}, {1}, {1,2}, {1,2,3}, {1,2,3,4}, {1,2,3,4,5}, + {1,2,3,4,5,6}, {1,2,3,4,5,6,7}, {1,2,3,4,5,6,7,8}), + ok = test_size({}, {a}, {{a},{b}}, {a,{b},c}), + ok = test_element({}, {a}, {a,b}, Num), + ok = test_setelement({}, {1}, {1,2}, 3, [1,2]), + ok = test_tuple_to_list({}, {a}, {a,b}, {a,b,c}, {a,b,c,d}, Num), + ok = test_list_to_tuple([], [a], [a,b], [a,b,c], [a,b,c,d], Num), + ok = test_tuple_with_case(), + ok = test_tuple_in_guard({a, b}, {a, b, c}), + ok. + +%%-------------------------------------------------------------------- +%% Tests matching of tuples + +test_match(T0, T1, T2, T3, T4, T5, T6, T7, T8) -> + {} = T0, + {1} = T1, + {1, 2} = T2, + {1, 2, 3} = T3, + {1, 2, 3, 4} = T4, + {1, 2, 3, 4, 5} = T5, + {1, 2, 3, 4, 5, 6} = T6, + T6 = {1, 2, 3, 4, 5, 6}, + T7 = {1, 2, 3, 4, 5, 6, 7}, + {1, 2, 3, 4, 5, 6, 7, 8} = T8, + ok. + +%%-------------------------------------------------------------------- +%% Tests the size/1 and tuple_size/1 BIFs. + +test_size(T0, T1, T2, T3) -> + [0, 1, 2, 3] = [size(T) || T <- [T0, T1, T2, T3]], + [0, 1, 2, 3] = [tuple_size(T) || T <- [T0, T1, T2, T3]], + ok. + +%%-------------------------------------------------------------------- +%% Tests element/2. + +test_element(T0, T1, T2, N) -> + a = element(1, T1), + a = element(1, T2), + %% indirect calls to element/2 + List = lists:seq(1, N), + Tuple = list_to_tuple(List), + ok = get_elements(List, Tuple, 1), + %% some cases that throw exceptions + {'EXIT', _} = (catch my_element(0, T2)), + {'EXIT', _} = (catch my_element(3, T2)), + {'EXIT', _} = (catch my_element(1, T0)), + {'EXIT', _} = (catch my_element(1, List)), + {'EXIT', _} = (catch my_element(1, N)), + {'EXIT', _} = (catch my_element(1.5, T2)), + ok. + +my_element(Pos, Term) -> + element(Pos, Term). + +get_elements([Element|Rest], Tuple, Pos) -> + Element = element(Pos, Tuple), + get_elements(Rest, Tuple, Pos + 1); +get_elements([], _Tuple, _Pos) -> + ok. + +%%-------------------------------------------------------------------- +%% Tests set_element/3. + +test_setelement(T0, T1, Pair, Three, L) -> + {x} = setelement(1, T1, x), + {x, 2} = setelement(1, Pair, x), + {1, x} = setelement(2, Pair, x), + %% indirect calls to setelement/3 + Tuple = list_to_tuple(lists:duplicate(2048, x)), + NewTuple = set_all_elements(Tuple, 1), + NewTuple = list_to_tuple(lists:seq(1+7, 2048+7)), + %% the following cases were rewritten to use the Three + %% variable in this weird way so as to silence the compiler + {'EXIT', _} = (catch setelement(Three - Three, Pair, x)), + {'EXIT', _} = (catch setelement(Three, Pair, x)), + {'EXIT', _} = (catch setelement(Three div Three, T0, x)), + {'EXIT', _} = (catch setelement(Three div Three, L, x)), + {'EXIT', _} = (catch setelement(Three / 2, Pair, x)), + ok. + +set_all_elements(Tuple, Pos) when Pos =< tuple_size(Tuple) -> + set_all_elements(setelement(Pos, Tuple, Pos+7), Pos+1); +set_all_elements(Tuple, Pos) when Pos > tuple_size(Tuple) -> + Tuple. + +%%-------------------------------------------------------------------- +%% Tests tuple_to_list/1. + +test_tuple_to_list(T0, T1, T2, T3, T4, Size) -> + [] = tuple_to_list(T0), + [a] = tuple_to_list(T1), + [a, b] = tuple_to_list(T2), + [a, b, c] = tuple_to_list(T3), + [a, b, c, d] = tuple_to_list(T4), + [a, b, c, d] = tuple_to_list(T4), + %% test a big tuple + List = lists:seq(1, Size), + Tuple = list_to_tuple(List), + Size = tuple_size(Tuple), + List = tuple_to_list(Tuple), + %% some cases that should result in errors + {'EXIT', _} = (catch my_tuple_to_list(element(2, T3))), + {'EXIT', _} = (catch my_tuple_to_list(Size)), + ok. + +my_tuple_to_list(X) -> + tuple_to_list(X). + +%%-------------------------------------------------------------------- +%% Tests list_to_tuple/1. + +test_list_to_tuple(L0, L1, L2, L3, L4, Size) -> + {} = list_to_tuple(L0), + {a} = list_to_tuple(L1), + {a, b} = list_to_tuple(L2), + {a, b, c} = list_to_tuple(L3), + {a, b, c, d} = list_to_tuple(L4), + {a, b, c, d, e} = list_to_tuple(L4++[e]), + %% test list_to_tuple with a big list + Tuple = list_to_tuple(lists:seq(1, Size)), + Size = tuple_size(Tuple), + %% some cases that should result in errors + {'EXIT', _} = (catch my_list_to_tuple({a,b})), + {'EXIT', _} = (catch my_list_to_tuple([hd(L1)|hd(L2)])), + ok. + +my_list_to_tuple(X) -> + list_to_tuple(X). + +%%-------------------------------------------------------------------- +%% Tests that a case nested inside a tuple is ok. +%% (This was known to crash earlier versions of BEAM.) + +test_tuple_with_case() -> + {reply, true} = tuple_with_case(), + ok. + +tuple_with_case() -> + %% The following comments apply to the BEAM compiler. + void(), % Reset var count. + {reply, % Compiler will choose {x,1} for tuple. + case void() of % Call will reset var count. + {'EXIT', Reason} -> % Case will return in {x,1} (first free), + {error, Reason}; % but the tuple will be build in {x,1}, + _ -> % so case value is lost and a circular + true % data element is built. + end}. + +void() -> ok. + +%%-------------------------------------------------------------------- +%% Test to build a tuple in a guard. + +test_tuple_in_guard(T2, T3) -> + %% T2 = {a, b}; T3 = {a, b, c} + ok = if T2 == {element(1, T3), element(2, T3)} -> ok; + true -> other + end, + ok = if T3 == {element(1, T3), element(2, T3), element(3, T3)} -> ok; + true -> other + end, + ok. diff --git a/lib/hipe/test/bs_SUITE_data/bs_add.erl b/lib/hipe/test/bs_SUITE_data/bs_add.erl index af5a3b2f23..4b92e6b413 100644 --- a/lib/hipe/test/bs_SUITE_data/bs_add.erl +++ b/lib/hipe/test/bs_SUITE_data/bs_add.erl @@ -2,7 +2,7 @@ %%------------------------------------------------------------------------- %% The guard in f/3 revealed a problem in the translation of the 'bs_add' %% BEAM instruction to Icode. The fail label was not properly translated. -%% Fixed 3/2/2011. +%% Fixed 3/2/2011. Then in 2015 we found another issue: g/2. Also fixed. %%------------------------------------------------------------------------- -module(bs_add). @@ -10,9 +10,17 @@ test() -> 42 = f(<<12345:16>>, 4711, <<42>>), + true = g(<<1:13>>, 3), %% was handled OK, but + false = g(<<>>, gurka), %% this one leaked badarith ok. f(Bin, A, B) when <<A:9, B:7/binary>> == Bin -> gazonk; f(Bin, _, _) when is_binary(Bin) -> 42. + +%% Complex way of testing (bit_size(Bin) + Len) rem 8 =:= 0 +g(Bin, Len) when is_binary(<<Bin/binary-unit:1, 123:Len>>) -> + true; +g(_, _) -> + false. diff --git a/lib/hipe/test/bs_SUITE_data/bs_construct.erl b/lib/hipe/test/bs_SUITE_data/bs_construct.erl index 9cc9ac848c..b9e7d93570 100644 --- a/lib/hipe/test/bs_SUITE_data/bs_construct.erl +++ b/lib/hipe/test/bs_SUITE_data/bs_construct.erl @@ -13,6 +13,12 @@ test() -> ok = bs5(), 16#10000008 = bit_size(large_bin(1, 2, 3, 4)), ok = bad_ones(), + ok = zero_width(), + ok = not_used(), + ok = bad_append(), + ok = system_limit(), + ok = bad_floats(), + ok = huge_binaries(), ok. %%-------------------------------------------------------------------- @@ -126,3 +132,174 @@ bad_ones() -> Bin123 = <<1,2,3>>, ?FAIL(<<Bin123/float>>), ok. + +%%-------------------------------------------------------------------- +%% Taken from the emulator bs_construct_SUITE - seg faulted till 18.1 + +zero_width() -> + Z = id(0), + Small = id(42), + Big = id(1 bsl 128), % puts stuff on the heap + <<>> = <<Small:Z>>, + <<>> = <<Small:0>>, + <<>> = <<Big:Z>>, + <<>> = <<Big:0>>, + ok. + +id(X) -> X. + +%%-------------------------------------------------------------------- +%% Taken from bs_construct_SUITE. The test checks that constructed +%% binaries that are not used would still give a `badarg' exception. +%% Problem was that in native code one of them gave `badarith'. + +not_used() -> + ok = not_used1(3, <<"dum">>), + {'EXIT',{badarg,_}} = (catch not_used1(42, "dum_string")), + {'EXIT',{badarg,_}} = (catch not_used2(666, -2)), + {'EXIT',{badarg,_}} = (catch not_used2(666, "bad_size")), % this one + {'EXIT',{badarg,_}} = (catch not_used3(666)), + ok. + +not_used1(I, BinString) -> + <<I:32,BinString/binary>>, + ok. + +not_used2(I, Sz) -> + <<I:Sz>>, + ok. + +not_used3(I) -> + <<I:(-8)>>, + ok. + +%%-------------------------------------------------------------------- +%% Taken from bs_construct_SUITE. + +bad_append() -> + do_bad_append(<<127:1>>, fun append_unit_3/1), + do_bad_append(<<127:2>>, fun append_unit_3/1), + do_bad_append(<<127:17>>, fun append_unit_3/1), + + do_bad_append(<<127:3>>, fun append_unit_4/1), + do_bad_append(<<127:5>>, fun append_unit_4/1), + do_bad_append(<<127:7>>, fun append_unit_4/1), + do_bad_append(<<127:199>>, fun append_unit_4/1), + + do_bad_append(<<127:7>>, fun append_unit_8/1), + do_bad_append(<<127:9>>, fun append_unit_8/1), + + do_bad_append(<<0:8>>, fun append_unit_16/1), + do_bad_append(<<0:15>>, fun append_unit_16/1), + do_bad_append(<<0:17>>, fun append_unit_16/1), + ok. + +do_bad_append(Bin0, Appender) -> + {'EXIT',{badarg,_}} = (catch Appender(Bin0)), + + Bin1 = id(<<0:3,Bin0/bitstring>>), + <<_:3,Bin2/bitstring>> = Bin1, + {'EXIT',{badarg,_}} = (catch Appender(Bin2)), + + %% Create a writable binary. + Empty = id(<<>>), + Bin3 = <<Empty/bitstring,Bin0/bitstring>>, + {'EXIT',{badarg,_}} = (catch Appender(Bin3)), + ok. + +append_unit_3(Bin) -> + <<Bin/binary-unit:3,0:1>>. + +append_unit_4(Bin) -> + <<Bin/binary-unit:4,0:1>>. + +append_unit_8(Bin) -> + <<Bin/binary,0:1>>. + +append_unit_16(Bin) -> + <<Bin/binary-unit:16,0:1>>. + +%%-------------------------------------------------------------------- +%% Taken from bs_construct_SUITE. + +system_limit() -> + WordSize = erlang:system_info(wordsize), + BitsPerWord = WordSize * 8, + {'EXIT',{system_limit,_}} = + (catch <<0:(id(0)),42:(id(1 bsl BitsPerWord))>>), + {'EXIT',{system_limit,_}} = + (catch <<42:(id(1 bsl BitsPerWord)),0:(id(0))>>), + {'EXIT',{system_limit,_}} = + (catch <<(id(<<>>))/binary,0:(id(1 bsl 100))>>), + + %% Would fail to load. + {'EXIT',{system_limit,_}} = (catch <<0:(1 bsl 67)>>), + {'EXIT',{system_limit,_}} = (catch <<0:((1 bsl 64)+1)>>), + case WordSize of + 4 -> + system_limit_32(); + 8 -> + ok + end. + +system_limit_32() -> + {'EXIT',{badarg,_}} = (catch <<42:(-1)>>), + {'EXIT',{badarg,_}} = (catch <<42:(id(-1))>>), + {'EXIT',{badarg,_}} = (catch <<42:(id(-389739873536870912))/unit:8>>), + {'EXIT',{system_limit,_}} = (catch <<42:536870912/unit:8>>), + {'EXIT',{system_limit,_}} = (catch <<42:(id(536870912))/unit:8>>), + {'EXIT',{system_limit,_}} = (catch <<0:(id(8)),42:536870912/unit:8>>), + {'EXIT',{system_limit,_}} = (catch <<0:(id(8)),42:(id(536870912))/unit:8>>), + + %% The size would be silently truncated, resulting in a crash. + {'EXIT',{system_limit,_}} = (catch <<0:(1 bsl 35)>>), + {'EXIT',{system_limit,_}} = (catch <<0:((1 bsl 32)+1)>>), + + %% Would fail to load. + {'EXIT',{system_limit,_}} = (catch <<0:(1 bsl 43)>>), + {'EXIT',{system_limit,_}} = (catch <<0:((1 bsl 40)+1)>>), + ok. + +%%-------------------------------------------------------------------- + +bad_floats() -> + WordSize = erlang:system_info(wordsize), + BitsPerWord = WordSize * 8, + {'EXIT',{badarg,_}} = (catch <<3.14:(id(33))/float>>), + {'EXIT',{badarg,_}} = (catch <<3.14:(id(64 bor 32))/float>>), + {'EXIT',{badarg,_}} = (catch <<3.14:(id((1 bsl 28) bor 32))/float>>), + {'EXIT',{system_limit,_}} = (catch <<3.14:(id(1 bsl BitsPerWord))/float>>), + ok. + +%%-------------------------------------------------------------------- +%% A bug in the implementation of binaries compared sizes in bits with sizes in +%% bytes, causing <<0:(id((1 bsl 31)-1))>> to fail to construct with +%% 'system_limit'. +%% <<0:(id((1 bsl 32)-1))>> was succeeding because the comparison was +%% (incorrectly) signed. + +huge_binaries() -> + AlmostIllegal = id(<<0:(id((1 bsl 32)-8))>>), + case erlang:system_info(wordsize) of + 4 -> huge_binaries_32(AlmostIllegal); + 8 -> ok + end, + garbage_collect(), + id(<<0:(id((1 bsl 31)-1))>>), + id(<<0:(id((1 bsl 30)-1))>>), + garbage_collect(), + ok. + +huge_binaries_32(AlmostIllegal) -> + %% Attempt construction of too large binary using bs_init/1 (which takes the + %% number of bytes as an argument, which should be compared to the maximum + %% size in bytes). + {'EXIT',{system_limit,_}} = (catch <<0:32,AlmostIllegal/binary>>), + %% Attempt construction of too large binary using bs_init/1 with a size in + %% bytes that has the msb set (and would be negative if it was signed). + {'EXIT',{system_limit,_}} = + (catch <<0:8, AlmostIllegal/binary, AlmostIllegal/binary, + AlmostIllegal/binary, AlmostIllegal/binary, + AlmostIllegal/binary, AlmostIllegal/binary, + AlmostIllegal/binary, AlmostIllegal/binary>>), + ok. diff --git a/lib/hipe/test/bs_SUITE_data/bs_match.erl b/lib/hipe/test/bs_SUITE_data/bs_match.erl index 7bc93a316b..b241ea8d35 100644 --- a/lib/hipe/test/bs_SUITE_data/bs_match.erl +++ b/lib/hipe/test/bs_SUITE_data/bs_match.erl @@ -1,8 +1,8 @@ %%% -*- erlang-indent-level: 2 -*- %%%------------------------------------------------------------------- %%% File : bs_match.erl -%%% Author : Per Gustafsson <[email protected]> -%%% Purpose : Performs simple matching and construction of binaries +%%% Authors : Per Gustafsson <[email protected]>, Kostis Sagonas <[email protected]> +%%% Purpose : Tests matching and construction of binaries %%% TODO : Add binary and float tests %%% Created : 20 Feb 2004 %%%------------------------------------------------------------------- @@ -13,7 +13,7 @@ test() -> Funs = [fun test_aligned/0, fun test_unaligned/0, fun test_zero_tail/0, fun test_integer_matching/0, - fun test_writable_bin/0], + fun test_writable_bin/0, fun test_match_huge_bin/0], lists:foreach(fun (F) -> ok = F() end, Funs). %%------------------------------------------------------------------- @@ -175,6 +175,9 @@ test_dynamic_integer_matching(N) -> <<12:N/integer-little, 0:S>> = <<12:N/integer-little, 0:S>>, ok. +%%------------------------------------------------------------------- +%% Test writable bin -- added by Sverker Eriksson + test_writable_bin() -> test_writable_bin(<<>>, 0), ok. @@ -185,3 +188,102 @@ test_writable_bin(Bin0, N) when N < 128 -> Bin1 = <<Bin0/binary, N>>, <<_/utf8, _/binary>> = Bin1, test_writable_bin(Bin1, N+1). + +%%------------------------------------------------------------------- +%% Test matching with a huge bin -- taken from bs_match_bin_SUITE + +test_match_huge_bin() -> + Bin = <<0:(1 bsl 27),13:8>>, + skip_huge_bin_1(1 bsl 27, Bin), + 16777216 = match_huge_bin_1(1 bsl 27, Bin), + %% Test overflowing the size of a binary field. + nomatch = overflow_huge_bin_skip_32(Bin), + nomatch = overflow_huge_bin_32(Bin), + nomatch = overflow_huge_bin_skip_64(Bin), + nomatch = overflow_huge_bin_64(Bin), + %% Size in variable + ok = overflow_huge_bin(Bin, lists:seq(25, 32)++lists:seq(50, 64)), + ok = overflow_huge_bin_unit128(Bin, lists:seq(25, 32)++lists:seq(50, 64)), + ok. + +overflow_huge_bin(Bin, [Sz0|Sizes]) -> + Sz = id(1 bsl Sz0), + case Bin of + <<_:Sz/binary-unit:8,0,_/binary>> -> + {error,Sz}; + _ -> + case Bin of + <<NewBin:Sz/binary-unit:8,0,_/binary>> -> + {error,Sz,size(NewBin)}; + _ -> + overflow_huge_bin(Bin, Sizes) + end + end; +overflow_huge_bin(_, []) -> ok. + +overflow_huge_bin_unit128(Bin, [Sz0|Sizes]) -> + Sz = id(1 bsl Sz0), + case Bin of + <<_:Sz/binary-unit:128,0,_/binary>> -> + {error,Sz}; + _ -> + case Bin of + <<NewBin:Sz/binary-unit:128,0,_/binary>> -> + {error,Sz,size(NewBin)}; + _ -> + overflow_huge_bin_unit128(Bin, Sizes) + end + end; +overflow_huge_bin_unit128(_, []) -> ok. + +skip_huge_bin_1(I, Bin) -> + <<_:I/binary-unit:1,13>> = Bin, + ok. + +match_huge_bin_1(I, Bin) -> + case Bin of + <<Val:I/binary-unit:1,13>> -> size(Val); + _ -> nomatch + end. + +overflow_huge_bin_skip_32(<<_:4294967296/binary,0,_/binary>>) -> 1; % 1 bsl 32 +overflow_huge_bin_skip_32(<<_:33554432/binary-unit:128,0,_/binary>>) -> 2; % 1 bsl 25 +overflow_huge_bin_skip_32(<<_:67108864/binary-unit:64,0,_/binary>>) -> 3; % 1 bsl 26 +overflow_huge_bin_skip_32(<<_:134217728/binary-unit:32,0,_/binary>>) -> 4; % 1 bsl 27 +overflow_huge_bin_skip_32(<<_:268435456/binary-unit:16,0,_/binary>>) -> 5; % 1 bsl 28 +overflow_huge_bin_skip_32(<<_:536870912/binary-unit:8,0,_/binary>>) -> 6; % 1 bsl 29 +overflow_huge_bin_skip_32(<<_:1073741824/binary-unit:8,0,_/binary>>) -> 7; % 1 bsl 30 +overflow_huge_bin_skip_32(<<_:2147483648/binary-unit:8,0,_/binary>>) -> 8; % 1 bsl 31 +overflow_huge_bin_skip_32(_) -> nomatch. + +overflow_huge_bin_32(<<Bin:4294967296/binary,_/binary>>) -> {1,Bin}; % 1 bsl 32 +overflow_huge_bin_32(<<Bin:33554432/binary-unit:128,0,_/binary>>) -> {2,Bin}; % 1 bsl 25 +overflow_huge_bin_32(<<Bin:67108864/binary-unit:128,0,_/binary>>) -> {3,Bin}; % 1 bsl 26 +overflow_huge_bin_32(<<Bin:134217728/binary-unit:128,0,_/binary>>) -> {4,Bin}; % 1 bsl 27 +overflow_huge_bin_32(<<Bin:268435456/binary-unit:128,0,_/binary>>) -> {5,Bin}; % 1 bsl 28 +overflow_huge_bin_32(<<Bin:536870912/binary-unit:128,0,_/binary>>) -> {6,Bin}; % 1 bsl 29 +overflow_huge_bin_32(<<Bin:1073741824/binary-unit:128,0,_/binary>>) -> {7,Bin}; % 1 bsl 30 +overflow_huge_bin_32(<<Bin:2147483648/binary-unit:128,0,_/binary>>) -> {8,Bin}; % 1 bsl 31 +overflow_huge_bin_32(_) -> nomatch. + +overflow_huge_bin_skip_64(<<_:18446744073709551616/binary,0,_/binary>>) -> 1; % 1 bsl 64 +overflow_huge_bin_skip_64(<<_:144115188075855872/binary-unit:128,0,_/binary>>) -> 2; % 1 bsl 57 +overflow_huge_bin_skip_64(<<_:288230376151711744/binary-unit:64,0,_/binary>>) -> 3; % 1 bsl 58 +overflow_huge_bin_skip_64(<<_:576460752303423488/binary-unit:32,0,_/binary>>) -> 4; % 1 bsl 59 +overflow_huge_bin_skip_64(<<_:1152921504606846976/binary-unit:16,0,_/binary>>) -> 5; % 1 bsl 60 +overflow_huge_bin_skip_64(<<_:2305843009213693952/binary-unit:8,0,_/binary>>) -> 6; % 1 bsl 61 +overflow_huge_bin_skip_64(<<_:4611686018427387904/binary-unit:8,0,_/binary>>) -> 7; % 1 bsl 62 +overflow_huge_bin_skip_64(<<_:9223372036854775808/binary-unit:8,_/binary>>) -> 8; % 1 bsl 63 +overflow_huge_bin_skip_64(_) -> nomatch. + +overflow_huge_bin_64(<<Bin:18446744073709551616/binary,_/binary>>) -> {1,Bin}; % 1 bsl 64 +overflow_huge_bin_64(<<Bin:144115188075855872/binary-unit:128,0,_/binary>>) -> {2,Bin}; % 1 bsl 57 +overflow_huge_bin_64(<<Bin:288230376151711744/binary-unit:128,0,_/binary>>) -> {3,Bin}; % 1 bsl 58 +overflow_huge_bin_64(<<Bin:576460752303423488/binary-unit:128,0,_/binary>>) -> {4,Bin}; % 1 bsl 59 +overflow_huge_bin_64(<<Bin:1152921504606846976/binary-unit:128,0,_/binary>>) -> {5,Bin}; % 1 bsl 60 +overflow_huge_bin_64(<<Bin:2305843009213693952/binary-unit:128,0,_/binary>>) -> {6,Bin}; % 1 bsl 61 +overflow_huge_bin_64(<<Bin:4611686018427387904/binary-unit:128,0,_/binary>>) -> {7,Bin}; % 1 bsl 62 +overflow_huge_bin_64(<<Bin:9223372036854775808/binary-unit:128,0,_/binary>>) -> {8,Bin}; % 1 bsl 63 +overflow_huge_bin_64(_) -> nomatch. + +id(I) -> I. diff --git a/lib/hipe/test/bs_SUITE_data/bs_split.erl b/lib/hipe/test/bs_SUITE_data/bs_split.erl index 2e52308a77..617543f789 100644 --- a/lib/hipe/test/bs_SUITE_data/bs_split.erl +++ b/lib/hipe/test/bs_SUITE_data/bs_split.erl @@ -26,13 +26,13 @@ bs1(L, B, Pos, Sz1, Sz2) -> <<B1:Sz1/binary, B2:Sz2/binary>> = B, bs2(L, B, Pos, B1, B2). -bs2(L, B, Pos, B1, B2)-> +bs2(L, B, Pos, B1, B2) -> B1 = list_to_binary(lists:sublist(L, 1, Pos)), bs3(L, B, Pos, B2). bs3(L, B, Pos, B2) -> B2 = list_to_binary(lists:nthtail(Pos, L)), - byte_split(L, B, Pos-1). + byte_split(L, B, Pos - 1). %%-------------------------------------------------------------------- @@ -56,14 +56,14 @@ bit_split_binary2(_Action, _Bin, [], _Bef) -> ok. bit_split_binary3(Action, Bin, List, Bef, Aft) when Bef =< Aft -> Action(Bin, List, Bef, (Aft-Bef) div 8 * 8), - bit_split_binary3(Action, Bin, List, Bef, Aft-8); + bit_split_binary3(Action, Bin, List, Bef, Aft - 8); bit_split_binary3(_, _, _, _, _) -> ok. make_bin_from_list(_List, 0) -> mkbin([]); make_bin_from_list(List, N) -> list_to_binary([make_int(List, 8, 0), - make_bin_from_list(lists:nthtail(8, List), N-8)]). + make_bin_from_list(lists:nthtail(8, List), N - 8)]). make_int(_List, 0, Acc) -> Acc; make_int([H|T], N, Acc) -> make_int(T, N-1, Acc bsl 1 bor H). @@ -101,5 +101,5 @@ z_split(B, N) -> <<_:N/binary>> -> [B]; _ -> - z_split(B, N+1) + z_split(B, N + 1) end. diff --git a/lib/hipe/test/bs_SUITE_data/bs_utf.erl b/lib/hipe/test/bs_SUITE_data/bs_utf.erl index f50ae08964..24526f574d 100644 --- a/lib/hipe/test/bs_SUITE_data/bs_utf.erl +++ b/lib/hipe/test/bs_SUITE_data/bs_utf.erl @@ -1,18 +1,356 @@ %% -*- erlang-indent-level: 2 -*- %%------------------------------------------------------------------- -%% Purpose: test support for UTF datatypes in binaries - INCOMPLETE +%% Purpose: test support for UTF datatypes in binaries +%% +%% Most of it taken from emulator/test/bs_utf_SUITE.erl %%------------------------------------------------------------------- -module(bs_utf). -export([test/0]). +-include_lib("test_server/include/test_server.hrl"). + test() -> + ok = utf8_cm65(), + ok = utf8_roundtrip(), + ok = utf16_roundtrip(), + ok = utf32_roundtrip(), + %% The following were problematic for the LLVM backend + ok = utf8_illegal_sequences(), + ok = utf16_illegal_sequences(), + ok = utf32_illegal_sequences(), + ok. + +%%------------------------------------------------------------------- +%% A test with construction and matching + +utf8_cm65() -> <<65>> = b65utf8(), ok = m(<<65>>). +b65utf8() -> + <<65/utf8>>. + m(<<65/utf8>>) -> ok. -b65utf8() -> - <<65/utf8>>. +%%------------------------------------------------------------------- + +utf8_roundtrip() -> + ok = utf8_roundtrip(0, 16#D7FF), + ok = utf8_roundtrip(16#E000, 16#10FFFF), + ok. + +utf8_roundtrip(First, Last) when First =< Last -> + Bin = int_to_utf8(First), + Bin = id(<<First/utf8>>), + Bin = id(<<(id(<<>>))/binary,First/utf8>>), + Unaligned = id(<<3:2,First/utf8>>), + <<_:2,Bin/binary>> = Unaligned, + <<First/utf8>> = Bin, + <<First/utf8>> = make_unaligned(Bin), + utf8_roundtrip(First+1, Last); +utf8_roundtrip(_, _) -> + ok. + +%%------------------------------------------------------------------- + +utf16_roundtrip() -> + Big = fun utf16_big_roundtrip/1, + Little = fun utf16_little_roundtrip/1, + PidRefs = [spawn_monitor(fun() -> do_utf16_roundtrip(Fun) end) || + Fun <- [Big,Little]], + [receive {'DOWN', Ref, process, Pid, Reason} -> normal=Reason end || + {Pid, Ref} <- PidRefs], + ok. + +do_utf16_roundtrip(Fun) -> + do_utf16_roundtrip(0, 16#D7FF, Fun), + do_utf16_roundtrip(16#E000, 16#10FFFF, Fun). + +do_utf16_roundtrip(First, Last, Fun) when First =< Last -> + Fun(First), + do_utf16_roundtrip(First+1, Last, Fun); +do_utf16_roundtrip(_, _, _) -> ok. + +utf16_big_roundtrip(Char) -> + Bin = id(<<Char/utf16>>), + Bin = id(<<(id(<<>>))/binary,Char/utf16>>), + Unaligned = id(<<3:2,Char/utf16>>), + <<_:2,Bin/binary>> = Unaligned, + <<Char/utf16>> = Bin, + <<Char/utf16>> = make_unaligned(Bin), + ok. + +utf16_little_roundtrip(Char) -> + Bin = id(<<Char/little-utf16>>), + Bin = id(<<(id(<<>>))/binary,Char/little-utf16>>), + Unaligned = id(<<3:2,Char/little-utf16>>), + <<_:2,Bin/binary>> = Unaligned, + <<Char/little-utf16>> = Bin, + <<Char/little-utf16>> = make_unaligned(Bin), + ok. + +%%------------------------------------------------------------------- + +utf32_roundtrip() -> + Big = fun utf32_big_roundtrip/1, + Little = fun utf32_little_roundtrip/1, + PidRefs = [spawn_monitor(fun() -> do_utf32_roundtrip(Fun) end) || + Fun <- [Big,Little]], + [receive {'DOWN', Ref, process, Pid, Reason} -> normal=Reason end || + {Pid, Ref} <- PidRefs], + ok. + +do_utf32_roundtrip(Fun) -> + do_utf32_roundtrip(0, 16#D7FF, Fun), + do_utf32_roundtrip(16#E000, 16#10FFFF, Fun). + +do_utf32_roundtrip(First, Last, Fun) when First =< Last -> + Fun(First), + do_utf32_roundtrip(First+1, Last, Fun); +do_utf32_roundtrip(_, _, _) -> ok. + +utf32_big_roundtrip(Char) -> + Bin = id(<<Char/utf32>>), + Bin = id(<<(id(<<>>))/binary,Char/utf32>>), + Unaligned = id(<<3:2,Char/utf32>>), + <<_:2,Bin/binary>> = Unaligned, + <<Char/utf32>> = Bin, + <<Char/utf32>> = make_unaligned(Bin), + ok. + +utf32_little_roundtrip(Char) -> + Bin = id(<<Char/little-utf32>>), + Bin = id(<<(id(<<>>))/binary,Char/little-utf32>>), + Unaligned = id(<<3:2,Char/little-utf32>>), + <<_:2,Bin/binary>> = Unaligned, + <<Char/little-utf32>> = Bin, + <<Char/little-utf32>> = make_unaligned(Bin), + ok. + +%%------------------------------------------------------------------- + +utf8_illegal_sequences() -> + fail_range(16#10FFFF+1, 16#10FFFF+512), % Too large. + fail_range(16#D800, 16#DFFF), % Reserved for UTF-16. + + %% Illegal first character. + [fail(<<I,16#8F,16#8F,16#8F>>) || I <- lists:seq(16#80, 16#BF)], + + %% Short sequences. + short_sequences(16#80, 16#10FFFF), + + %% Overlong sequences. (Using more bytes than necessary + %% is not allowed.) + overlong(0, 127, 2), + overlong(128, 16#7FF, 3), + overlong(16#800, 16#FFFF, 4), + ok. + +fail_range(Char, End) when Char =< End -> + {'EXIT', _} = (catch <<Char/utf8>>), + Bin = int_to_utf8(Char), + fail(Bin), + fail_range(Char+1, End); +fail_range(_, _) -> ok. + +short_sequences(Char, End) -> + Step = (End - Char) div erlang:system_info(schedulers) + 1, + PidRefs = short_sequences_1(Char, Step, End), + [receive {'DOWN', Ref, process, Pid, Reason} -> normal=Reason end || + {Pid, Ref} <- PidRefs], + ok. + +short_sequences_1(Char, Step, End) when Char =< End -> + CharEnd = lists:min([Char+Step-1,End]), + [spawn_monitor(fun() -> + %% io:format("~p - ~p\n", [Char, CharEnd]), + do_short_sequences(Char, CharEnd) + end)|short_sequences_1(Char+Step, Step, End)]; +short_sequences_1(_, _, _) -> []. + +do_short_sequences(Char, End) when Char =< End -> + short_sequence(Char), + do_short_sequences(Char+1, End); +do_short_sequences(_, _) -> ok. + +short_sequence(I) -> + case int_to_utf8(I) of + <<S0:3/binary,_:8>> -> + <<S1:2/binary,R1:8>> = S0, + <<S2:1/binary,_:8>> = S1, + fail(S0), + fail(S1), + fail(S2), + fail(<<S2/binary,16#7F,R1,R1>>), + fail(<<S1/binary,16#7F,R1>>), + fail(<<S0/binary,16#7F>>); + <<S0:2/binary,_:8>> -> + <<S1:1/binary,R1:8>> = S0, + fail(S0), + fail(S1), + fail(<<S0/binary,16#7F>>), + fail(<<S1/binary,16#7F>>), + fail(<<S1/binary,16#7F,R1>>); + <<S:1/binary,_:8>> -> + fail(S), + fail(<<S/binary,16#7F>>) + end. + +overlong(Char, Last, NumBytes) when Char =< Last -> + overlong(Char, NumBytes), + overlong(Char+1, Last, NumBytes); +overlong(_, _, _) -> ok. + +overlong(Char, NumBytes) when NumBytes < 5 -> + case int_to_utf8(Char, NumBytes) of + <<Char/utf8>>=Bin -> + ?t:fail({illegal_encoding_accepted,Bin,Char}); + <<OtherChar/utf8>>=Bin -> + ?t:fail({illegal_encoding_accepted,Bin,Char,OtherChar}); + _ -> ok + end, + overlong(Char, NumBytes+1); +overlong(_, _) -> ok. + +fail(Bin) -> + fail_1(Bin), + fail_1(make_unaligned(Bin)). + +fail_1(<<Char/utf8>> = Bin) -> + ?t:fail({illegal_encoding_accepted, Bin, Char}); +fail_1(_) -> ok. + +%%------------------------------------------------------------------- + +utf16_illegal_sequences() -> + utf16_fail_range(16#10FFFF+1, 16#10FFFF+512), % Too large. + utf16_fail_range(16#D800, 16#DFFF), % Reserved for UTF-16. + lonely_hi_surrogate(16#D800, 16#DFFF), + leading_lo_surrogate(16#DC00, 16#DFFF), + ok. + +utf16_fail_range(Char, End) when Char =< End -> + {'EXIT', _} = (catch <<Char/big-utf16>>), + {'EXIT', _} = (catch <<Char/little-utf16>>), + utf16_fail_range(Char+1, End); +utf16_fail_range(_, _) -> ok. + +lonely_hi_surrogate(Char, End) when Char =< End -> + BinBig = <<Char:16/big>>, + BinLittle = <<Char:16/little>>, + case {BinBig,BinLittle} of + {<<Bad/big-utf16>>,_} -> + ?t:fail({lonely_hi_surrogate_accepted,Bad}); + {_,<<Bad/little-utf16>>} -> + ?t:fail({lonely_hi_surrogate_accepted,Bad}); + {_,_} -> + ok + end, + lonely_hi_surrogate(Char+1, End); +lonely_hi_surrogate(_, _) -> ok. + +leading_lo_surrogate(Char, End) when Char =< End -> + leading_lo_surrogate(Char, 16#D800, 16#DFFF), + leading_lo_surrogate(Char+1, End); +leading_lo_surrogate(_, _) -> ok. + +leading_lo_surrogate(HiSurr, LoSurr, End) when LoSurr =< End -> + BinBig = <<HiSurr:16/big,LoSurr:16/big>>, + BinLittle = <<HiSurr:16/little,LoSurr:16/little>>, + case {BinBig,BinLittle} of + {<<Bad/big-utf16,_/bits>>,_} -> + ?t:fail({leading_lo_surrogate_accepted,Bad}); + {_,<<Bad/little-utf16,_/bits>>} -> + ?t:fail({leading_lo_surrogate_accepted,Bad}); + {_,_} -> + ok + end, + leading_lo_surrogate(HiSurr, LoSurr+1, End); +leading_lo_surrogate(_, _, _) -> ok. + +%%------------------------------------------------------------------- + +utf32_illegal_sequences() -> + utf32_fail_range(16#10FFFF+1, 16#10FFFF+512), % Too large. + utf32_fail_range(16#D800, 16#DFFF), % Reserved for UTF-16. + utf32_fail_range(-100, -1), + ok. + +utf32_fail_range(Char, End) when Char =< End -> + {'EXIT', _} = (catch <<Char/big-utf32>>), + {'EXIT', _} = (catch <<Char/little-utf32>>), + case {<<Char:32>>,<<Char:32/little>>} of + {<<Unexpected/utf32>>,_} -> + ?t:fail(Unexpected); + {_,<<Unexpected/little-utf32>>} -> + ?t:fail(Unexpected); + {_,_} -> ok + end, + utf32_fail_range(Char+1, End); +utf32_fail_range(_, _) -> ok. + +%%------------------------------------------------------------------- +%% This function intentionally allows construction of UTF-8 sequence +%% in illegal ranges. + +int_to_utf8(I) when I =< 16#7F -> + <<I>>; +int_to_utf8(I) when I =< 16#7FF -> + B2 = I, + B1 = (I bsr 6), + <<1:1,1:1,0:1,B1:5,1:1,0:1,B2:6>>; +int_to_utf8(I) when I =< 16#FFFF -> + B3 = I, + B2 = (I bsr 6), + B1 = (I bsr 12), + <<1:1,1:1,1:1,0:1,B1:4,1:1,0:1,B2:6,1:1,0:1,B3:6>>; +int_to_utf8(I) when I =< 16#3FFFFF -> + B4 = I, + B3 = (I bsr 6), + B2 = (I bsr 12), + B1 = (I bsr 18), + <<1:1,1:1,1:1,1:1,0:1,B1:3,1:1,0:1,B2:6,1:1,0:1,B3:6,1:1,0:1,B4:6>>; +int_to_utf8(I) when I =< 16#3FFFFFF -> + B5 = I, + B4 = (I bsr 6), + B3 = (I bsr 12), + B2 = (I bsr 18), + B1 = (I bsr 24), + <<1:1,1:1,1:1,1:1,1:1,0:1,B1:2,1:1,0:1,B2:6,1:1,0:1,B3:6,1:1,0:1,B4:6, + 1:1,0:1,B5:6>>. + +%% int_to_utf8(I, NumberOfBytes) -> Binary. +%% This function can be used to construct overlong sequences. +int_to_utf8(I, 1) -> + <<I>>; +int_to_utf8(I, 2) -> + B2 = I, + B1 = (I bsr 6), + <<1:1,1:1,0:1,B1:5,1:1,0:1,B2:6>>; +int_to_utf8(I, 3) -> + B3 = I, + B2 = (I bsr 6), + B1 = (I bsr 12), + <<1:1,1:1,1:1,0:1,B1:4,1:1,0:1,B2:6,1:1,0:1,B3:6>>; +int_to_utf8(I, 4) -> + B4 = I, + B3 = (I bsr 6), + B2 = (I bsr 12), + B1 = (I bsr 18), + <<1:1,1:1,1:1,1:1,0:1,B1:3,1:1,0:1,B2:6,1:1,0:1,B3:6,1:1,0:1,B4:6>>. + +%%------------------------------------------------------------------- + +make_unaligned(Bin0) when is_binary(Bin0) -> + Bin1 = <<0:3,Bin0/binary,31:5>>, + Sz = byte_size(Bin0), + <<0:3,Bin:Sz/binary,31:5>> = id(Bin1), + Bin. + +%%------------------------------------------------------------------- +%% Just to prevent compiler optimizations + +id(X) -> X. diff --git a/lib/hipe/test/hipe_testsuite_driver.erl b/lib/hipe/test/hipe_testsuite_driver.erl index 5f05a716bc..9f5d7421b4 100644 --- a/lib/hipe/test/hipe_testsuite_driver.erl +++ b/lib/hipe/test/hipe_testsuite_driver.erl @@ -176,7 +176,8 @@ run(TestCase, Dir, _OutDir) -> HiPEOpts = try TestCase:hipe_options() catch error:undef -> [] end, {ok, TestCase} = hipe:c(TestCase, HiPEOpts), ok = TestCase:test(), - case is_llvm_opt_available() of + ToLLVM = try TestCase:to_llvm() catch error:undef -> true end, + case ToLLVM andalso hipe:llvm_support_available() of true -> {ok, TestCase} = hipe:c(TestCase, [to_llvm|HiPEOpts]), ok = TestCase:test(); @@ -186,16 +187,3 @@ run(TestCase, Dir, _OutDir) -> %% lists:foreach(fun (DF) -> ok end, % = file:delete(DF) end, %% [filename:join(OutDir, D) || D <- DataFiles]) %% end. - - -%% This function, which is supposed to check whether the right LLVM -%% infrastructure is available, should be probably written in a better -%% and more portable way and moved to the hipe application. - -is_llvm_opt_available() -> - OptStr = os:cmd("opt -version"), - SubStr = "LLVM version ", N = length(SubStr), - case string:str(OptStr, SubStr) of - 0 -> false; - S -> P = S + N, string:sub_string(OptStr, P, P + 2) >= "3.4" - end. diff --git a/lib/hipe/test/sanity_SUITE_data/sanity_comp_timeout.erl b/lib/hipe/test/sanity_SUITE_data/sanity_comp_timeout.erl new file mode 100644 index 0000000000..9f0830574f --- /dev/null +++ b/lib/hipe/test/sanity_SUITE_data/sanity_comp_timeout.erl @@ -0,0 +1,28 @@ +%%% -*- erlang-indent-level: 2 -*- +%%%---------------------------------------------------------------------- +%%% Author: Kostis Sagonas +%%% +%%% Tests that when the native code compilation times out or gets killed +%%% for some other reason, the parent process does not also get killed. +%%% +%%% Problem discovered by Bjorn G. on 1/12/2003 and fixed by Kostis. +%%%---------------------------------------------------------------------- + +-module(sanity_comp_timeout). + +-export([test/0, to_llvm/0]). + +test() -> + ok = write_dummy_mod(), + error_logger:tty(false), % disable printouts of error reports + Self = self(), % get the parent process + c:c(dummy_mod, [native, {hipe, [{timeout, 1}]}]), % This will kill the process + Self = self(), % make sure the parent process stays the same + ok. + +to_llvm() -> false. + +write_dummy_mod() -> + Prog = <<"-module(dummy_mod).\n-export([test/0]).\ntest() -> ok.\n">>, + ok = file:write_file("dummy_mod.erl", Prog). + diff --git a/lib/hipe/test/sanity_SUITE_data/sanity_no_zombies.erl b/lib/hipe/test/sanity_SUITE_data/sanity_no_zombies.erl new file mode 100644 index 0000000000..87e746042e --- /dev/null +++ b/lib/hipe/test/sanity_SUITE_data/sanity_no_zombies.erl @@ -0,0 +1,21 @@ +%%% -*- erlang-indent-level: 2 -*- +%%%---------------------------------------------------------------------- +%%% Author: Per Gustafsson +%%% +%%% Checks that HiPE's concurrent compilation does not leave any zombie +%%% processes around after compilation has finished. +%%% +%%% This was a bug reported on erlang-bugs (Oct 25, 2007). +%%%---------------------------------------------------------------------- + +-module(sanity_no_zombies). + +-export([test/0, to_llvm/0]). + +test() -> + L = length(processes()), + hipe:c(?MODULE, [concurrent_comp]), % force concurrent compilation + L = length(processes()), + ok. + +to_llvm() -> false. diff --git a/lib/hipe/vsn.mk b/lib/hipe/vsn.mk index e507ae933f..2edfd790ed 100644 --- a/lib/hipe/vsn.mk +++ b/lib/hipe/vsn.mk @@ -1 +1 @@ -HIPE_VSN = 3.12 +HIPE_VSN = 3.15 diff --git a/lib/hipe/x86/hipe_x86_assemble.erl b/lib/hipe/x86/hipe_x86_assemble.erl index 4ffa3d35ba..695ce16887 100644 --- a/lib/hipe/x86/hipe_x86_assemble.erl +++ b/lib/hipe/x86/hipe_x86_assemble.erl @@ -83,7 +83,7 @@ assemble(CompiledCode, Closures, Exports, Options) -> DataRelocs = hipe_pack_constants:mk_data_relocs(RefsFromConsts, LabelMap), SSE = hipe_pack_constants:slim_sorted_exportmap(ExportMap,Closures,Exports), SlimRefs = hipe_pack_constants:slim_refs(AccRefs), - Bin = term_to_binary([{?VERSION_STRING(),?HIPE_SYSTEM_CRC}, + Bin = term_to_binary([{?VERSION_STRING(),?HIPE_ERTS_CHECKSUM}, ConstAlign, ConstSize, SC, DataRelocs, % nee LM, LabelMap diff --git a/lib/inets/doc/src/Makefile b/lib/inets/doc/src/Makefile index a0a3472c4a..cb71fbeb9c 100644 --- a/lib/inets/doc/src/Makefile +++ b/lib/inets/doc/src/Makefile @@ -52,7 +52,6 @@ XML_REF3_FILES = \ http_uri.xml\ httpc.xml\ httpd.xml \ - httpd_conf.xml \ httpd_custom_api.xml \ httpd_socket.xml \ httpd_util.xml \ diff --git a/lib/inets/doc/src/ftp.xml b/lib/inets/doc/src/ftp.xml index f3d4a5c45d..f64bc0e18b 100644 --- a/lib/inets/doc/src/ftp.xml +++ b/lib/inets/doc/src/ftp.xml @@ -30,95 +30,94 @@ <file>ftp.xml</file> </header> <module>ftp</module> - <modulesummary>A File Transfer Protocol client</modulesummary> + <modulesummary>A File Transfer Protocol client.</modulesummary> <description> - <p>The <c>ftp</c> module implements a client for file transfer - according to a subset of the File Transfer Protocol (see <term - id="RFC"></term>959). </p> + <p>This module implements a client for file transfer + according to a subset of the File Transfer Protocol (FTP), see + <url href="http://www.ietf.org/rfc/rfc959.txt">RFC 959</url>.</p> - <p>Starting from inets version 4.4.1 the ftp - client will always try to use passive ftp mode and only resort - to active ftp mode if this fails. There is a start option - <seealso marker="#mode">mode</seealso> where this default behavior - may be changed. </p> + <p>As from <c>Inets</c> 4.4.1, the FTP + client always tries to use passive FTP mode and only resort + to active FTP mode if this fails. This default behavior can be + changed by start option <seealso marker="#mode">mode</seealso>.</p> <marker id="two_start"></marker> - <p>There are two ways to start an ftp client. One is using the - <seealso marker="#service_start">Inets service framework</seealso> - and the other is to start it directy as a standalone process - using the <seealso marker="#open">open</seealso> function. </p> + <p>An FTP client can be started in two ways. One is using the + <seealso marker="#service_start">Inets service framework</seealso>, + the other is to start it directly as a standalone process + using function <seealso marker="#open">open</seealso>.</p> - <p>For a simple example of an ftp session see - <seealso marker="ftp_client">Inets User's Guide.</seealso></p> + <p>For a simple example of an FTP session, see + <seealso marker="ftp_client">Inets User's Guide</seealso>.</p> <p>In addition to the ordinary functions for receiving and sending - files (see <c>recv/2</c>, <c>recv/3</c>, <c>send/2</c> and + files (see <c>recv/2</c>, <c>recv/3</c>, <c>send/2</c>, and <c>send/3</c>) there are functions for receiving remote files as - binaries (see <c>recv_bin/2</c>) and for sending binaries to to be + binaries (see <c>recv_bin/2</c>) and for sending binaries to be stored as remote files (see <c>send_bin/3</c>).</p> - <p>There is also a set of functions for sending and receiving - contiguous parts of a file to be stored in a remote file (for send - see <c>send_chunk_start/2</c>, <c>send_chunk/2</c> and - <c>send_chunk_end/1</c> and for receive see + <p>A set of functions is provvided for sending and receiving + contiguous parts of a file to be stored in a remote file. For send, + see <c>send_chunk_start/2</c>, <c>send_chunk/2</c>, and + <c>send_chunk_end/1</c>. For receive, see <c>recv_chunk_start/2</c> and <c>recv_chunk/</c>).</p> - <p>The particular return values of the functions below depend very + <p>The return values of the following functions depend much on the implementation of the FTP server at the remote - host. In particular the results from <c>ls</c> and <c>nlist</c> + host. In particular, the results from <c>ls</c> and <c>nlist</c> varies. Often real errors are not reported as errors by <c>ls</c>, - even if for instance a file or directory does not + even if, for example, a file or directory does not exist. <c>nlist</c> is usually more strict, but some implementations have the peculiar behaviour of responding with an - error, if the request is a listing of the contents of directory - which exists but is empty.</p> + error if the request is a listing of the contents of a directory + that exists but is empty.</p> <marker id="service_start"></marker> </description> <section> - <title>FTP CLIENT SERVICE START/STOP </title> + <title>FTP CLIENT SERVICE START/STOP</title> <p>The FTP client can be started and stopped dynamically in runtime by - calling the Inets application API + calling the <c>Inets</c> application API <c>inets:start(ftpc, ServiceConfig)</c>, or <c>inets:start(ftpc, ServiceConfig, How)</c>, and <c>inets:stop(ftpc, Pid)</c>. - See <seealso marker="inets">inets(3)</seealso> for more info. </p> - <p>Below follows a description of - the available configuration options.</p> + For details, see <seealso marker="inets">inets(3)</seealso>.</p> + + <p>The available configuration options are as follows:</p> <taglist> <tag>{host, Host}</tag> <item> <marker id="host"></marker> - <p>Host = <c>string() | ip_address()</c> </p> + <p>Host = <c>string() | ip_address()</c></p> </item> <tag>{port, Port}</tag> <item> <marker id="port"></marker> - <p>Port = <c>integer() > 0</c> </p> - <p>Default is 21.</p> + <p>Port = <c>integer() > 0</c></p> + <p>Default is <c>21</c>.</p> </item> <tag>{mode, Mode}</tag> <item> <marker id="mode"></marker> - <p>Mode = <c>active | passive</c> </p> - <p>Default is <c>passive</c>. </p> + <p>Mode = <c>active | passive</c></p> + <p>Default is <c>passive</c>.</p> </item> <tag>{verbose, Verbose}</tag> <item> <marker id="verbose"></marker> <p>Verbose = <c>boolean()</c> </p> - <p>This determines if the FTP communication should be - verbose or not. </p> - <p>Default is <c>false</c>. </p> + <p>Determines if the FTP communication is to be + verbose or not.</p> + <p>Default is <c>false</c>.</p> </item> <tag>{debug, Debug}</tag> @@ -126,93 +125,90 @@ <marker id="debug"></marker> <p>Debug = <c>trace | debug | disable</c> </p> <p>Debugging using the dbg toolkit. </p> - <p>Default is <c>disable</c>. </p> + <p>Default is <c>disable</c>.</p> </item> <tag>{ipfamily, IpFamily}</tag> <item> <marker id="ipfamily"></marker> <p>IpFamily = <c>inet | inet6 | inet6fb4</c> </p> - <p>With <c>inet6fb4</c> the client behaves as before - (it tries to use IPv6 and only if that does not work, it - uses IPv4). </p> - <p>Default is <c>inet</c> (IPv4). </p> + <p>With <c>inet6fb4</c> the client behaves as before, that is, + tries to use IPv6, and only if that does not work it + uses IPv4).</p> + <p>Default is <c>inet</c> (IPv4).</p> </item> <tag>{timeout, Timeout}</tag> <item> <marker id="timeout"></marker> - <p>Timeout = <c>non_neg_integer()</c> </p> - <p>Connection timeout. </p> - <p>Default is 60000 (milliseconds). </p> + <p>Timeout = <c>non_neg_integer()</c></p> + <p>Connection time-out.</p> + <p>Default is <c>60000</c> (milliseconds).</p> </item> <tag>{dtimeout, DTimeout}</tag> <item> <marker id="dtimeout"></marker> <p>DTimeout = <c>non_neg_integer() | infinity</c> </p> - <p>Data Connect timeout. - The time the client will wait for the server to connect to the - data socket. </p> - <p>Default is infinity. </p> + <p>Data connect time-out. + The time the client waits for the server to connect to the + data socket.</p> + <p>Default is <c>infinity</c>. </p> </item> <tag>{progress, Progress}</tag> <item> <marker id="progress"></marker> <p>Progress = <c>ignore | {CBModule, CBFunction, InitProgress}</c></p> - <p>CBModule = <c>atom()</c>, CBFunction = <c>atom()</c> </p> - <p>InitProgress = <c>term()</c> </p> - <p>Default is <c>ignore</c>. </p> + <p><c>CBModule = atom()</c>, <c>CBFunction = atom()</c></p> + <p><c>InitProgress = term()</c></p> + <p>Default is <c>ignore</c>.</p> </item> </taglist> - <p>The progress option is intended to be used by applications that - want to create some type of progress report such as a progress bar in - a GUI. The default value for the progress option is ignore - e.i. the option is not used. When the progress option is - specified the following will happen when ftp:send/[3,4] or - ftp:recv/[3,4] are called.</p> + <p>Option <c>progress</c> is intended to be used by applications that + want to create some type of progress report, such as a progress bar in + a GUI. Default for the progress option is <c>ignore</c>, + that is, the option is not used. When the progress option is + specified, the following happens when <c>ftp:send/[3,4]</c> or + <c>ftp:recv/[3,4]</c> are called:</p> <list type="bulleted"> <item> - <p>Before a file is transfered the following call will - be made to indicate the start of the file transfer and how big + <p>Before a file is transferred, the following call is + made to indicate the start of the file transfer and how large the file is. The return value of the callback function - should be a new value for the UserProgressTerm that will - bu used as input next time the callback function is + is to be a new value for the <c>UserProgressTerm</c> that will + be used as input the next time the callback function is called.</p> - <br></br> <p><c> CBModule:CBFunction(InitProgress, File, {file_size, FileSize}) </c></p> - <br></br> </item> <item> - <p>Every time a chunk of bytes is transfered the - following call will be made:</p> - <br></br> + <p>Every time a chunk of bytes is transferred the + following call is made:</p> <p><c> - CBModule:CBFunction(UserProgressTerm, File, {transfer_size, TransferSize}) </c></p> - <br></br> + CBModule:CBFunction(UserProgressTerm, File, {transfer_size, TransferSize}) + </c></p> </item> <item> - <p>At the end of the file the following call will be - made to indicate the end of the transfer.</p> - <br></br> + <p>At the end of the file the following call is + made to indicate the end of the transfer:</p> <p><c> - CBModule:CBFunction(UserProgressTerm, File, {transfer_size, 0}) </c></p> - <br></br> + CBModule:CBFunction(UserProgressTerm, File, {transfer_size, 0}) + </c></p> </item> </list> - <p>The callback function should be defined as </p> + <p>The callback function is to be defined as follows:</p> <p><c> - CBModule:CBFunction(UserProgressTerm, File, Size) -> UserProgressTerm </c></p> + CBModule:CBFunction(UserProgressTerm, File, Size) -> UserProgressTerm + </c></p> <p><c> CBModule = CBFunction = atom() @@ -227,50 +223,51 @@ </c></p> <p><c> - Size = {transfer_size, integer()} | {file_size, integer()} | {file_size, unknown} </c></p> + Size = {transfer_size, integer()} | {file_size, integer()} | {file_size, unknown} + </c></p> - <p>Alas for remote files it is not possible for ftp to determine the + <p>For remote files, <c>ftp</c> cannot determine the file size in a platform independent way. In this case the size - will be <c>unknown</c> and it is left to the application to find - out the size. </p> + becomes <c>unknown</c> and it is left to the application to + determine the size.</p> <note> <p>The callback is made by a middleman process, hence the - file transfer will not be affected by the code in the progress - callback function. If the callback should crash this will be - detected by the ftp connection process that will print an - info-report and then go one as if the progress option was set - to ignore. </p> + file transfer is not affected by the code in the progress + callback function. If the callback crashes, this is + detected by the FTP connection process, which then prints an + info-report and goes on as if the progress option was set + to <c>ignore</c>.</p> </note> <p>The file transfer type is set to the default of the FTP server - when the session is opened. This is usually ASCCI-mode. + when the session is opened. This is usually ASCCI mode. </p> - <p>The current local working directory (cf. <c>lpwd/1</c>) is set to - the value reported by <c>file:get_cwd/1</c>. the wanted + <p>The current local working directory (compare <c>lpwd/1</c>) is set + to the value reported by <c>file:get_cwd/1</c>, the wanted local directory. </p> <p>The return value <c>Pid</c> is used as a reference to the - newly created ftp client in all other functions, and they should - be called by the process that created the connection. The ftp + newly created FTP client in all other functions, and they are to + be called by the process that created the connection. The FTP client process monitors the process that created it and - will terminate if that process terminates.</p> + terminates if that process terminates.</p> </section> <section> - <title>COMMON DATA TYPES </title> - <p>Here follows type definitions that are used by more than one - function in the FTP client API. </p> - <p><c> pid() - identifier of an ftp connection.</c></p> - <p><c> string() = list of ASCII characters.</c></p> - <p><c> shortage_reason() = etnospc | epnospc</c></p> - <p><c> restriction_reason() = epath | efnamena | elogin | enotbinary - - note not all restrictions may always relevant to all functions - </c></p> - <p><c>common_reason() = econn | eclosed | term() - some kind of - explanation of what went wrong.</c></p> + <title>DATA TYPES</title> + <p>The following type definitions are used by more than one + function in the FTP client API:</p> + <p><c>pid()</c> = identifier of an FTP connection</p> + <p><c>string()</c> = list of ASCII characters</p> + <p><c>shortage_reason()</c> = <c>etnospc | epnospc</c></p> + <p><c>restriction_reason()</c> = <c>epath | efnamena | elogin | enotbinary</c> + - all restrictions are not always relevant to all functions + </p> + <p><c>common_reason()</c> = <c>econn | eclosed | term()</c> + - some explanation of what went wrong</p> <marker id="account"></marker> </section> @@ -278,15 +275,14 @@ <funcs> <func> <name>account(Pid, Account) -> ok | {error, Reason}</name> - <fsummary>Specify which account to use.</fsummary> + <fsummary>Specifies which account to use.</fsummary> <type> <v>Pid = pid()</v> <v>Account = string()</v> <v>Reason = eacct | common_reason()</v> </type> <desc> - <p>If an account is needed for an operation set the account - with this operation.</p> + <p>Sets the account for an operation, if needed.</p> <marker id="append"></marker> <marker id="append2"></marker> @@ -297,7 +293,8 @@ <func> <name>append(Pid, LocalFile) -> </name> <name>append(Pid, LocalFile, RemoteFile) -> ok | {error, Reason}</name> - <fsummary>Transfer file to remote server, and append it to Remotefile.</fsummary> + <fsummary>Transfers a file to remote server, and appends it to + <c>Remotefile</c>.</fsummary> <type> <v>Pid = pid()</v> <v>LocalFile = RemoteFile = string()</v> @@ -306,9 +303,9 @@ <desc> <p>Transfers the file <c>LocalFile</c> to the remote server. If <c>RemoteFile</c> is specified, the name of the remote file that the - file will be appended to is set to <c>RemoteFile</c>; otherwise - the name is set to <c>LocalFile</c> If the file does not exists the - file will be created.</p> + file is appended to is set to <c>RemoteFile</c>, otherwise + to <c>LocalFile</c>. If the file does not exists, + it is created.</p> <marker id="append_bin"></marker> </desc> @@ -316,17 +313,17 @@ <func> <name>append_bin(Pid, Bin, RemoteFile) -> ok | {error, Reason}</name> - <fsummary>Transfer a binary into a remote file.</fsummary> + <fsummary>Transfers a binary into a remote file.</fsummary> <type> <v>Pid = pid()</v> <v>Bin = binary()()</v> <v>RemoteFile = string()</v> - <v>Reason = restriction_reason()| shortage_reason() | common_reason()</v> + <v>Reason = restriction_reason()| shortage_reason() | common_reason()</v> </type> <desc> - <p>Transfers the binary <c>Bin</c> to the remote server and append - it to the file <c>RemoteFile</c>. If the file does not exists it - will be created.</p> + <p>Transfers the binary <c>Bin</c> to the remote server and appends + it to the file <c>RemoteFile</c>. If the file does not exist, it + is created.</p> <marker id="append_chunk"></marker> </desc> @@ -334,18 +331,18 @@ <func> <name>append_chunk(Pid, Bin) -> ok | {error, Reason}</name> - <fsummary>append a chunk to the remote file.</fsummary> + <fsummary>Appends a chunk to the remote file.</fsummary> <type> <v>Pid = pid()</v> <v>Bin = binary()</v> <v>Reason = echunk | restriction_reason() | common_reason()</v> </type> <desc> - <p>Transfer the chunk <c>Bin</c> to the remote server, which - append it into the file specified in the call to - <c>append_chunk_start/2</c>. </p> - <p>Note that for some errors, e.g. file system full, it is - necessary to to call <c>append_chunk_end</c> to get the + <p>Transfers the chunk <c>Bin</c> to the remote server, which + appends it to the file specified in the call to + <c>append_chunk_start/2</c>.</p> + <p>For some errors, for example, file system full, it is + necessary to call <c>append_chunk_end</c> to get the proper reason.</p> <marker id="append_chunk_start"></marker> @@ -354,16 +351,16 @@ <func> <name>append_chunk_start(Pid, File) -> ok | {error, Reason}</name> - <fsummary>Start transfer of file chunks for appending to File.</fsummary> + <fsummary>Starts transfer of file chunks for appending to <c>File</c>.</fsummary> <type> <v>Pid = pid()</v> <v>File = string()</v> <v>Reason = restriction_reason() | common_reason()</v> </type> <desc> - <p>Start the transfer of chunks for appending to the file - <c>File</c> at the remote server. If the file does not exists - it will be created.</p> + <p>Starts the transfer of chunks for appending to the file + <c>File</c> at the remote server. If the file does not exist, + it is created.</p> <marker id="append_chunk_end"></marker> </desc> @@ -371,7 +368,7 @@ <func> <name>append_chunk_end(Pid) -> ok | {error, Reason}</name> - <fsummary>Stop transfer of chunks for appending.</fsummary> + <fsummary>Stops transfer of chunks for appending.</fsummary> <type> <v>Pid = pid()</v> <v>Reason = echunk | restriction_reason() | shortage_reason() </v> @@ -379,7 +376,7 @@ <desc> <p>Stops transfer of chunks for appending to the remote server. The file at the remote server, specified in the call to - <c>append_chunk_start/2</c> is closed by the server.</p> + <c>append_chunk_start/2</c>, is closed by the server.</p> <marker id="cd"></marker> </desc> @@ -387,7 +384,7 @@ <func> <name>cd(Pid, Dir) -> ok | {error, Reason}</name> - <fsummary>Change remote working directory.</fsummary> + <fsummary>Changes remote working directory.</fsummary> <type> <v>Pid = pid()</v> <v>Dir = string()</v> @@ -403,13 +400,13 @@ <func> <name>close(Pid) -> ok</name> - <fsummary>End the ftp session.</fsummary> + <fsummary>Ends the FTP session.</fsummary> <type> <v>Pid = pid()</v> </type> <desc> - <p>Ends an ftp session, created using the - <seealso marker="#open">open</seealso> function. </p> + <p>Ends an FTP session, created using function + <seealso marker="#open">open</seealso>.</p> <marker id="delete"></marker> </desc> @@ -417,7 +414,7 @@ <func> <name>delete(Pid, File) -> ok | {error, Reason}</name> - <fsummary>Delete a file at the remote server..</fsummary> + <fsummary>Deletes a file at the remote server.</fsummary> <type> <v>Pid = pid()</v> <v>File = string()</v> @@ -432,7 +429,7 @@ <func> <name>formaterror(Tag) -> string()</name> - <fsummary>Return error diagnostics.</fsummary> + <fsummary>Returns error diagnostics.</fsummary> <type> <v>Tag = {error, atom()} | atom()</v> </type> @@ -446,14 +443,14 @@ <func> <name>lcd(Pid, Dir) -> ok | {error, Reason}</name> - <fsummary>Change local working directory.</fsummary> + <fsummary>Changes local working directory.</fsummary> <type> <v>Pid = pid()</v> <v>Dir = string()</v> <v>Reason = restriction_reason()</v> </type> <desc> - <p>Changes the working directory to <c>Dir</c> for the local client. </p> + <p>Changes the working directory to <c>Dir</c> for the local client.</p> <marker id="lpwd"></marker> </desc> @@ -461,7 +458,7 @@ <func> <name>lpwd(Pid) -> {ok, Dir}</name> - <fsummary>Get local current working directory.</fsummary> + <fsummary>Gets local current working directory.</fsummary> <type> <v>Pid = pid()</v> </type> @@ -485,13 +482,13 @@ <v>Reason = restriction_reason() | common_reason()</v> </type> <desc> - <p>Returns a list of files in long format. </p> - <p><c>Pathname</c> can be a directory, a group of files or - even a file. The <c>Pathname</c> string can contain wildcard(s). </p> - <p><c>ls/1</c> implies the user's current remote directory. </p> - <p>The format of <c>Listing</c> is operating system dependent - (on UNIX it is typically produced from the output of the - <c>ls -l</c> shell command).</p> + <p>Returns a list of files in long format.</p> + <p><c>Pathname</c> can be a directory, a group of files, or + a file. The <c>Pathname</c> string can contain wildcards.</p> + <p><c>ls/1</c> implies the current remote directory of the user.</p> + <p>The format of <c>Listing</c> depends on the operating system. + On UNIX, it is typically produced from the output of the + <c>ls -l</c> shell command.</p> <marker id="mkdir"></marker> </desc> @@ -499,7 +496,7 @@ <func> <name>mkdir(Pid, Dir) -> ok | {error, Reason}</name> - <fsummary>Create remote directory.</fsummary> + <fsummary>Creates a remote directory.</fsummary> <type> <v>Pid = pid()</v> <v>Dir = string()</v> @@ -525,15 +522,15 @@ <v>Reason = restriction_reason() | common_reason()</v> </type> <desc> - <p>Returns a list of files in short format. </p> - <p><c>Pathname</c> can be a directory, a group of files or - even a file. The <c>Pathname</c> string can contain wildcard(s). </p> - <p><c>nlist/1</c> implies the user's current remote directory. </p> + <p>Returns a list of files in short format.</p> + <p><c>Pathname</c> can be a directory, a group of files, or + a file. The <c>Pathname</c> string can contain wildcards.</p> + <p><c>nlist/1</c> implies the current remote directory of the user.</p> <p>The format of <c>Listing</c> is a stream of - file names, where each name is separated by <CRLF> or - <NL>. Contrary to the <c>ls</c> function, the purpose of - <c>nlist</c> is to make it possible for a program to - automatically process file name information.</p> + filenames where each filename is separated by <CRLF> or + <NL>. Contrary to function <c>ls</c>, the purpose of + <c>nlist</c> is to enable a program to + process filename information automatically.</p> <marker id="open"></marker> </desc> @@ -542,23 +539,23 @@ <func> <name>open(Host) -> {ok, Pid} | {error, Reason}</name> <name>open(Host, Opts) -> {ok, Pid} | {error, Reason}</name> - <fsummary>Start an standalone ftp client.</fsummary> + <fsummary>Starts a standalone FTP client.</fsummary> <type> <v>Host = string() | ip_address()</v> <v>Opts = options()</v> <v>options() = [option()]</v> <v>option() = start_option() | open_option()</v> <v>start_option() = {verbose, verbose()} | {debug, debug()}</v> - <v>verbose() = boolean() (defaults to false)</v> - <v>debug() = disable | debug | trace (defaults to disable)</v> + <v>verbose() = boolean() (default is false)</v> + <v>debug() = disable | debug | trace (default is disable)</v> <v>open_option() = {ipfamily, ipfamily()} | {port, port()} | {mode, mode()} | {tls, tls_options()} | {timeout, timeout()} | {dtimeout, dtimeout()} | {progress, progress()}</v> - <v>ipfamily() = inet | inet6 | inet6fb4 (defaults to inet)</v> - <v>port() = integer() > 0 (defaults to 21)</v> - <v>mode() = active | passive (defaults to passive)</v> + <v>ipfamily() = inet | inet6 | inet6fb4 (default is inet)</v> + <v>port() = integer() > 0 (default is 21)</v> + <v>mode() = active | passive (default is passive)</v> <v>tls_options() = [<seealso marker="ssl:ssl#type-ssloption">ssl:ssloption()</seealso>]</v> - <v>timeout() = integer() > 0 (defaults to 60000 milliseconds)</v> - <v>dtimeout() = integer() > 0 | infinity (defaults to infinity)</v> - <v>pogress() = ignore | {module(), function(), initial_data()} (defaults to ignore)</v> + <v>timeout() = integer() > 0 (default is 60000 milliseconds)</v> + <v>dtimeout() = integer() > 0 | infinity (default is infinity)</v> + <v>pogress() = ignore | {module(), function(), initial_data()} (default is ignore)</v> <v>module() = atom()</v> <v>function() = atom()</v> <v>initial_data() = term()</v> @@ -566,16 +563,20 @@ </type> <desc> - <p>This function is used to start a standalone ftp client process - (without the inets service framework) and - open a session with the FTP server at <c>Host</c>. </p> + <p>Starts a standalone FTP client process + (without the <c>Inets</c> service framework) and + opens a session with the FTP server at <c>Host</c>. </p> - <p>If the option <c>{tls, tls_options()}</c> is present, the ftp session will be transported over tls (ftps, see -<url href="http://www.ietf.org/rfc/rfc4217.txt">RFC 4217</url>). The list <c>tls_options()</c> may be empty. The function <seealso marker="ssl:ssl#connect/3"><c>ssl:connect/3</c></seealso> is used for securing both the control connection and the data sessions. + <p>If option <c>{tls, tls_options()}</c> is present, the FTP session + is transported over <c>tls</c> (<c>ftps</c>, see + <url href="http://www.ietf.org/rfc/rfc4217.txt">RFC 4217</url>). + The list <c>tls_options()</c> can be empty. The function + <seealso marker="ssl:ssl#connect/3"><c>ssl:connect/3</c></seealso> + is used for securing both the control connection and the data sessions. </p> - <p>A session opened in this way, is closed using the - <seealso marker="#close">close</seealso> function. </p> + <p>A session opened in this way is closed using function + <seealso marker="#close">close</seealso>.</p> <marker id="pwd"></marker> </desc> @@ -583,22 +584,10 @@ <func> <name>pwd(Pid) -> {ok, Dir} | {error, Reason}</name> - <fsummary>Get remote current working directory.</fsummary> - <type> - <v>Pid = pid()</v> - <v>Reason = restriction_reason() | common_reason() </v> - </type> - <desc> - <p>Returns the current working directory at the remote server. </p> - </desc> - </func> - - <func> - <name>pwd(Pid) -> {ok, Dir} | {error, Reason}</name> - <fsummary>Get remote current working directory.</fsummary> + <fsummary>Gets the remote current working directory.</fsummary> <type> <v>Pid = pid()</v> - <v>Reason = restriction_reason() | common_reason() </v> + <v>Reason = restriction_reason() | common_reason()</v> </type> <desc> <p>Returns the current working directory at the remote server.</p> @@ -612,7 +601,7 @@ <func> <name>recv(Pid, RemoteFile) -> </name> <name>recv(Pid, RemoteFile, LocalFile) -> ok | {error, Reason}</name> - <fsummary>Transfer file from remote server.</fsummary> + <fsummary>Transfers a file from remote server.</fsummary> <type> <v>Pid = pid()</v> <v>RemoteFile = LocalFile = string()</v> @@ -620,14 +609,14 @@ <v>file_write_error_reason() = see file:write/2</v> </type> <desc> - <p>Transfer the file <c>RemoteFile</c> from the remote server - to the the file system of the local client. If + <p>Transfers the file <c>RemoteFile</c> from the remote server + to the file system of the local client. If <c>LocalFile</c> is specified, the local file will be - <c>LocalFile</c>; otherwise it will be + <c>LocalFile</c>, otherwise <c>RemoteFile</c>.</p> - <p>If the file write fails - (e.g. enospc), then the command is aborted and <c>{error, file_write_error_reason()}</c> is returned. The file is - however <em>not</em> removed.</p> + <p>If the file write fails (for example, <c>enospc</c>), the command is + aborted and <c>{error, file_write_error_reason()}</c> is returned. + However, the file is <em>not</em> removed.</p> <marker id="recv_bin"></marker> </desc> @@ -635,7 +624,7 @@ <func> <name>recv_bin(Pid, RemoteFile) -> {ok, Bin} | {error, Reason}</name> - <fsummary>Transfer file from remote server as a binary.</fsummary> + <fsummary>Transfers a file from remote server as a binary.</fsummary> <type> <v>Pid = pid()</v> <v>Bin = binary()</v> @@ -652,14 +641,14 @@ <func> <name>recv_chunk_start(Pid, RemoteFile) -> ok | {error, Reason}</name> - <fsummary>Start chunk-reading of the remote file.</fsummary> + <fsummary>Starts chunk-reading of the remote file.</fsummary> <type> <v>Pid = pid()</v> <v>RemoteFile = string()</v> <v>Reason = restriction_reason() | common_reason()</v> </type> <desc> - <p>Start transfer of the file <c>RemoteFile</c> from the + <p>Starts transfer of the file <c>RemoteFile</c> from the remote server.</p> <marker id="recv_chunk"></marker> @@ -668,20 +657,20 @@ <func> <name>recv_chunk(Pid) -> ok | {ok, Bin} | {error, Reason}</name> - <fsummary>Receive a chunk of the remote file.</fsummary> + <fsummary>Receives a chunk of the remote file.</fsummary> <type> <v>Pid = pid()</v> <v>Bin = binary()</v> <v>Reason = restriction_reason() | common_reason()</v> </type> <desc> - <p>Receive a chunk of the remote file (<c>RemoteFile</c> of - <c>recv_chunk_start</c>). The return values has the following + <p>Receives a chunk of the remote file (<c>RemoteFile</c> of + <c>recv_chunk_start</c>). The return values have the following meaning:</p> <list type="bulleted"> - <item><c>ok</c> the transfer is complete.</item> - <item><c>{ok, Bin}</c> just another chunk of the file.</item> - <item><c>{error, Reason}</c> transfer failed.</item> + <item><c>ok</c> = the transfer is complete.</item> + <item><c>{ok, Bin}</c> = just another chunk of the file.</item> + <item><c>{error, Reason}</c> = transfer failed.</item> </list> <marker id="rename"></marker> @@ -690,7 +679,7 @@ <func> <name>rename(Pid, Old, New) -> ok | {error, Reason}</name> - <fsummary>Rename a file at the remote server..</fsummary> + <fsummary>Renames a file at the remote server.</fsummary> <type> <v>Pid = pid()</v> <v>CurrFile = NewFile = string()</v> @@ -705,7 +694,7 @@ <func> <name>rmdir(Pid, Dir) -> ok | {error, Reason}</name> - <fsummary>Remove a remote directory.</fsummary> + <fsummary>Removes a remote directory.</fsummary> <type> <v>Pid = pid()</v> <v>Dir = string()</v> @@ -723,7 +712,7 @@ <func> <name>send(Pid, LocalFile) -></name> <name>send(Pid, LocalFile, RemoteFile) -> ok | {error, Reason}</name> - <fsummary>Transfer file to remote server.</fsummary> + <fsummary>Transfers a file to the remote server.</fsummary> <type> <v>Pid = pid()</v> <v>LocalFile = RemoteFile = string()</v> @@ -732,7 +721,7 @@ <desc> <p>Transfers the file <c>LocalFile</c> to the remote server. If <c>RemoteFile</c> is specified, the name of the remote file is set - to <c>RemoteFile</c>; otherwise the name is set to <c>LocalFile</c>.</p> + to <c>RemoteFile</c>, otherwise to <c>LocalFile</c>.</p> <marker id="send_bin"></marker> </desc> @@ -740,7 +729,7 @@ <func> <name>send_bin(Pid, Bin, RemoteFile) -> ok | {error, Reason}</name> - <fsummary>Transfer a binary into a remote file.</fsummary> + <fsummary>Transfers a binary into a remote file.</fsummary> <type> <v>Pid = pid()</v> <v>Bin = binary()()</v> @@ -757,17 +746,17 @@ <func> <name>send_chunk(Pid, Bin) -> ok | {error, Reason}</name> - <fsummary>Write a chunk to the remote file.</fsummary> + <fsummary>Writes a chunk to the remote file.</fsummary> <type> <v>Pid = pid()</v> <v>Bin = binary()</v> <v>Reason = echunk | restriction_reason() | common_reason()</v> </type> <desc> - <p>Transfer the chunk <c>Bin</c> to the remote server, which + <p>Transfers the chunk <c>Bin</c> to the remote server, which writes it into the file specified in the call to - <c>send_chunk_start/2</c>. </p> - <p>Note that for some errors, e.g. file system full, it is + <c>send_chunk_start/2</c>.</p> + <p>For some errors, for example, file system full, it is necessary to to call <c>send_chunk_end</c> to get the proper reason.</p> @@ -777,14 +766,14 @@ <func> <name>send_chunk_start(Pid, File) -> ok | {error, Reason}</name> - <fsummary>Start transfer of file chunks.</fsummary> + <fsummary>Starts transfer of file chunks.</fsummary> <type> <v>Pid = pid()</v> <v>File = string()</v> <v>Reason = restriction_reason() | common_reason()</v> </type> <desc> - <p>Start transfer of chunks into the file <c>File</c> at the + <p>Starts transfer of chunks into the file <c>File</c> at the remote server.</p> <marker id="send_chunk_end"></marker> @@ -793,7 +782,7 @@ <func> <name>send_chunk_end(Pid) -> ok | {error, Reason}</name> - <fsummary>Stop transfer of chunks.</fsummary> + <fsummary>Stops transfer of chunks.</fsummary> <type> <v>Pid = pid()</v> <v>Reason = restriction_reason() | common_reason() | shortage_reason()</v> @@ -809,7 +798,7 @@ <func> <name>type(Pid, Type) -> ok | {error, Reason}</name> - <fsummary>Set transfer type to <c>ascii</c>or <c>binary</c>.</fsummary> + <fsummary>Sets transfer type to <c>ascii</c>or <c>binary</c>.</fsummary> <type> <v>Pid = pid()</v> <v>Type = ascii | binary</v> @@ -817,8 +806,8 @@ </type> <desc> <p>Sets the file transfer type to <c>ascii</c> or <c>binary</c>. When - an ftp session is opened, the default transfer type of the - server is used, most often <c>ascii</c>, which is the default + an FTP session is opened, the default transfer type of the + server is used, most often <c>ascii</c>, which is default according to <url href="http://www.ietf.org/rfc/rfc959.txt">RFC 959</url>.</p> <marker id="user3"></marker> </desc> @@ -857,21 +846,22 @@ <func> <name>quote(Pid, Command) -> [FTPLine]</name> - <fsummary>Sends an arbitrary FTP command. </fsummary> + <fsummary>Sends an arbitrary FTP command.</fsummary> <type> <v>Pid = pid()</v> <v>Command = string()</v> - <v>FTPLine = string() - Note the telnet end of line characters, from the ftp protocol definition, CRLF e.g. "\\r\\n" has been removed.</v> - </type> - <desc> - <p>Sends an arbitrary FTP command and returns verbatimly a list - of the lines sent back by the FTP server. This functions is - intended to give an application accesses to FTP commands - that are server specific or that may not be provided by - this FTP client. </p> + <v>FTPLine = string(</v> + </type> + <desc><note><p>The telnet end of line characters, from the FTP + protocol definition, CRLF, for example, "\\r\\n" has been removed.</p></note> + <p>Sends an arbitrary FTP command and returns verbatim a list + of the lines sent back by the FTP server. This function is + intended to give application accesses to FTP commands + that are server-specific or that cannot be provided by + this FTP client.</p> <note> - <p>FTP commands that require a data connection can not be - successfully issued with this function. </p> + <p>FTP commands requiring a data connection cannot be + successfully issued with this function.</p> </note> </desc> </func> @@ -885,30 +875,31 @@ <taglist> <tag><c>echunk</c></tag> <item> - <p>Synchronisation error during chunk sending. - </p> - <p>A call has been made to <c>send_chunk/2</c> or - <c>send_chunk_end/1</c>, before a call to - <c>send_chunk_start/2</c>; or a call has been made to another - transfer function during chunk sending, i.e. before a call - to <c>send_chunk_end/1</c>.</p> + <p>Synchronization error during chunk sending according to one + of the following: + </p><list type="bulleted"> + <item>A call is made to <c>send_chunk/2</c> or <c>send_chunk_end/1</c> + before a call to <c>send_chunk_start/2</c>.</item> + <item>A call has been made to another transfer function during chunk + sending, that is, before a call to <c>send_chunk_end/1</c>.</item> + </list> </item> <tag><c>eclosed</c></tag> <item> - <p>The session has been closed.</p> + <p>The session is closed.</p> </item> <tag><c>econn</c></tag> <item> - <p>Connection to remote server prematurely closed.</p> + <p>Connection to the remote server is prematurely closed.</p> </item> <tag><c>ehost</c></tag> <item> - <p>Host not found, FTP server not found, or connection rejected + <p>Host is not found, FTP server is not found, or connection is rejected by FTP server.</p> </item> <tag><c>elogin</c></tag> <item> - <p>User not logged in.</p> + <p>User is not logged in.</p> </item> <tag><c>enotbinary</c></tag> <item> @@ -925,7 +916,7 @@ </item> <tag><c>euser</c></tag> <item> - <p>User name or password not valid.</p> + <p>Invalid username or password.</p> </item> <tag><c>etnospc</c></tag> <item> @@ -938,14 +929,16 @@ </item> <tag><c>efnamena</c></tag> <item> - <p>File name not allowed [553].</p> + <p>Filename not allowed [553].</p> </item> </taglist> </section> <section> <title>SEE ALSO</title> - <p>file, filename, J. Postel and J. Reynolds: File Transfer Protocol + <p><seealso marker="kernel:file">file(3)</seealso> + <seealso marker="stdlib:filename">filename(3)</seealso> + and J. Postel and J. Reynolds: File Transfer Protocol (<url href="http://www.ietf.org/rfc/rfc959.txt">RFC 959</url>). </p> </section> diff --git a/lib/inets/doc/src/ftp_client.xml b/lib/inets/doc/src/ftp_client.xml index 2f5b8abb5f..89e66db814 100644 --- a/lib/inets/doc/src/ftp_client.xml +++ b/lib/inets/doc/src/ftp_client.xml @@ -34,38 +34,24 @@ </header> <section> - <title>Introduction</title> + <title>Getting Started</title> - <p>Ftp clients are consider to be rather temporary and are - for that reason only started and stopped during - runtime and can not be started at application startup. - Due to the design of FTP client API, letting some - functions return intermediate results, only the process - that started the ftp client will be able to access it in - order to preserve sane semantics. (This could be solved - by changing the API and using the concept of a controlling - process more in line with other OTP applications, but - that is perhaps something for the future.) - If the process that started the ftp session - dies the ftp client process will terminate.</p> + <p>FTP clients are considered to be rather temporary. Thus, + they are only started and stopped during runtime and cannot + be started at application startup. + The FTP client API is designed to allow some functions to + return intermediate results. This implies that only the process + that started the FTP client can access it with + preserved sane semantics. + If the process that started the FTP session + dies, the FTP client process terminates.</p> - <p>The client supports ipv6 as long as the underlying mechanisms - also do so. </p> + <p>The client supports IPv6 as long as the underlying mechanisms + also do so.</p> - </section> - - <section> - <title>Using the FTP Client API</title> - <p>The following is a simple example of an ftp session, where + <p>The following is a simple example of an FTP session, where the user <c>guest</c> with password <c>password</c> logs on to - the remote host <c>erlang.org</c>, and where the file - <c>appl.erl</c> is transferred from the remote to the local - host. When the session is opened, the current directory at - the remote host is <c>/home/guest</c>, and <c>/home/fred</c> - at the local host. Before transferring the file, the current - local directory is changed to <c>/home/eproj/examples</c>, and - the remote directory is set to - <c>/home/guest/appl/examples</c>.</p> + the remote host <c>erlang.org</c>:</p> <code type="erl"><![CDATA[ 1> inets:start(). ok @@ -86,6 +72,14 @@ 9> inets:stop(ftpc, Pid). ok ]]></code> + <p> The file + <c>appl.erl</c> is transferred from the remote to the local + host. When the session is opened, the current directory at + the remote host is <c>/home/guest</c>, and <c>/home/fred</c> + at the local host. Before transferring the file, the current + local directory is changed to <c>/home/eproj/examples</c>, and + the remote directory is set to + <c>/home/guest/appl/examples</c>.</p> </section> </chapter> diff --git a/lib/inets/doc/src/http_client.xml b/lib/inets/doc/src/http_client.xml index 5c42f72cec..f4d7b751ac 100644 --- a/lib/inets/doc/src/http_client.xml +++ b/lib/inets/doc/src/http_client.xml @@ -34,103 +34,91 @@ </header> <section> - <title>Introduction</title> + <title>Configuration</title> - <p>The HTTP client default profile will be started when the inets + <p>The HTTP client default profile is started when the <c>Inets</c> application is started and is then available to all processes on - that erlang node. Other profiles may also be started at + that Erlang node. Other profiles can also be started at application startup, or profiles can be started and stopped - dynamically in runtime. Each client profile will spawn a new - process to handle each request unless there is a possibility to use - a persistent connection with or without pipelining. - The client will add a <c>host</c> header and an empty + dynamically in runtime. Each client profile spawns a new + process to handle each request, unless a persistent connection + can be used with or without pipelining. + The client adds a <c>host</c> header and an empty <c>te</c> header if there are no such headers present in the request.</p> - <p>The client supports ipv6 as long as the underlying mechanisms also do + <p>The client supports IPv6 as long as the underlying mechanisms also do so.</p> - </section> - <section> - <title>Configuration</title> - <p> What to put in the erlang node application configuration file - in order to start a profile at application startup.</p> + <p>The following is to be put in the Erlang node application configuration file + to start a profile at application startup:</p> <pre> - [{inets, [{services, [{httpc, PropertyList}]}]}] - </pre> - <p>For valid properties see + [{inets, [{services, [{httpc, PropertyList}]}]}]</pre> + <p>For valid properties, see <seealso marker="httpc">httpc(3)</seealso>. </p> </section> <section> - <title>Using the HTTP Client API</title> + <title>Getting Started</title> + <p>Start <c>Inets</c>:</p> <code type="erl"> 1 > inets:start(). - ok - </code> - <p> The following calls uses the default client profile. - Use the proxy "www-proxy.mycompany.com:8000", - but not for requests to localhost. This will apply to all subsequent - requests</p> + ok</code> + <p>The following calls use the default client profile. + Use the proxy <c>"www-proxy.mycompany.com:8000"</c>, + except from requests to localhost. This applies to all the + following requests.</p> + <p>Example:</p> <code type="erl"> 2 > httpc:set_options([{proxy, {{"www-proxy.mycompany.com", 8000}, ["localhost"]}}]). - ok - </code> - <p>An ordinary synchronous request. </p> + ok</code> + <p>The following is an ordinary synchronous request:</p> <code type="erl"> 3 > {ok, {{Version, 200, ReasonPhrase}, Headers, Body}} = - httpc:request(get, {"http://www.erlang.org", []}, [], []). - </code> - <p>With all default values, as above, a get request can also be written - like this.</p> + httpc:request(get, {"http://www.erlang.org", []}, [], []).</code> + <p>With all the default values presented, a get request can also be written + as follows:</p> <code type="erl"> 4 > {ok, {{Version, 200, ReasonPhrase}, Headers, Body}} = - httpc:request("http://www.erlang.org"). - </code> - <p>An ordinary asynchronous request. The result will be sent - to the calling process in the form <c>{http, {ReqestId, Result}}</c></p> + httpc:request("http://www.erlang.org").</code> + <p>The following is an ordinary asynchronous request:</p> <code type="erl"> 5 > {ok, RequestId} = - httpc:request(get, {"http://www.erlang.org", []}, [], [{sync, false}]). - </code> - <p>In this case the calling process is the shell, so we receive the - result.</p> + httpc:request(get, {"http://www.erlang.org", []}, [], [{sync, false}]).</code> + <p>The result is sent to the calling process as + <c>{http, {ReqestId, Result}}</c>.</p> + <p>In this case, the calling process is the shell, so the following + result is received:</p> <code type="erl"> 6 > receive {http, {RequestId, Result}} -> ok after 500 -> error end. - ok - </code> - <p>Send a request with a specified connection header. </p> + ok</code> + <p>This sends a request with a specified connection header:</p> <code type="erl"> 7 > {ok, {{NewVersion, 200, NewReasonPhrase}, NewHeaders, NewBody}} = httpc:request(get, {"http://www.erlang.org", [{"connection", "close"}]}, - [], []). - </code> + [], []).</code> - <p>Start a HTTP client profile. </p> + <p>Start an HTTP client profile:</p> <code><![CDATA[ 8 > {ok, Pid} = inets:start(httpc, [{profile, foo}]). {ok, <0.45.0>} ]]></code> - <p>The new profile has no proxy settings so the connection will - be refused</p> + <p>The new profile has no proxy settings, so the connection is refused:</p> <code type="erl"> 9 > httpc:request("http://www.erlang.org", foo). - {error, econnrefused} - </code> + {error, econnrefused}</code> - <p>Stop a HTTP client profile. </p> + <p>Stop the HTTP client profile:</p> <code type="erl"> 10 > inets:stop(httpc, foo). - ok - </code> + ok</code> - <p>Alternatively:</p> + <p>Alternative way to stop the HTTP client profile:</p> <code type="erl"> 10 > inets:stop(httpc, Pid). - ok - </code> + ok</code> </section> </chapter> diff --git a/lib/inets/doc/src/http_server.xml b/lib/inets/doc/src/http_server.xml index 51ed826c7c..aeda961714 100644 --- a/lib/inets/doc/src/http_server.xml +++ b/lib/inets/doc/src/http_server.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2004</year><year>2013</year> + <year>2004</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -21,77 +21,67 @@ limitations under the License. </legalnotice> - - <title>HTTP server </title> - <prepared>Ingela Anderton Andin</prepared> - <responsible></responsible> - <docno></docno> - <approved></approved> - <checked></checked> - <date></date> - <rev></rev> + <title>HTTP server</title> <file>http_server.xml</file> - - <marker id="intro"></marker> </header> <section> - <title>Introduction</title> - + <title>Configuration</title> + <marker id="config"></marker> <p>The HTTP server, also referred to as httpd, handles HTTP requests - as described in RFC 2616 with a few exceptions such as gateway - and proxy functionality. The server supports ipv6 as long as the - underlying mechanisms also do so. </p> - - <p>The server implements numerous features such as SSL (Secure Sockets - Layer), ESI (Erlang Scripting Interface), CGI (Common Gateway - Interface), User Authentication(using Mnesia, dets or plain text - database), Common Logfile Format (with or without disk_log(3) - support), URL Aliasing, Action Mappings, and Directory Listings</p> - - <p>The configuration of the server is provided as an erlang - property list, and for backwards compatibility also a configuration + as described in + <url href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</url> + with a few exceptions, such as gateway + and proxy functionality. The server supports IPv6 as long as the + underlying mechanisms also do so.</p> + + <p>The server implements numerous features, such as:</p> + <list type="bulleted"> + <item>Secure Sockets Layer (SSL)</item> + <item>Erlang Scripting Interface (ESI)</item> + <item>Common Gateway Interface (CGI)</item> + <item>User Authentication (using <c>Mnesia</c>, + <c>Dets</c> or plain text database)</item> + <item>Common Logfile Format (with or without disk_log(3) support)</item> + <item>URL Aliasing</item> + <item>Action Mappings</item> + <item>Directory Listings</item> + </list> + + <p>The configuration of the server is provided as an Erlang + property list. For backwards compatibility, a configuration file using apache-style configuration directives is supported.</p> - <p>As of inets version 5.0 the HTTP server is an easy to - start/stop and customize web server that provides the most basic - web server functionality. Depending on your needs there - are also other erlang based web servers that may be of interest - such as Yaws, http://yaws.hyber.org, that for instance has its own - markup support to generate html, and supports certain buzzword - technologies such as SOAP.</p> + <p>As of <c>Inets</c> 5.0 the HTTP server is an easy to + start/stop and customize web server providing the most basic + web server functionality. Inets is designed for embedded systems + and if you want a full-fledged web server there are exists other + erlang open source alternatives.</p> - <p>Allmost all server functionality has been implemented using an - especially crafted server API which is described in the Erlang Web - Server API. This API can be used to advantage by all who wish + <p>Almost all server functionality has been implemented using an + especially crafted server API, which is described in the Erlang Web + Server API. This API can be used to enhance the core server functionality, for example with custom logging and authentication.</p> - <marker id="config"></marker> - </section> - - <section> - <title>Configuration</title> - - <p> What to put in the erlang node application configuration file - in order to start a http server at application startup.</p> + <p>The following is to be put in the Erlang node application configuration + file to start an HTTP server at application startup:</p> <code type="erl"> [{inets, [{services, [{httpd, [{proplist_file, "/var/tmp/server_root/conf/8888_props.conf"}]}, {httpd, [{proplist_file, - "/var/tmp/server_root/conf/8080_props.conf"}]}]}]}]. - </code> - - <p>The server is configured using an erlang property list. - For the available properties see - <seealso marker="httpd">httpd(3)</seealso> - For backwards compatibility also apache-like config files - are supported. + "/var/tmp/server_root/conf/8080_props.conf"}]}]}]}].</code> + + <p>The server is configured using an Erlang property list. + For the available properties, see + <seealso marker="httpd">httpd(3)</seealso>. + For backwards compatibility, apache-like configuration files + are also supported. </p> - <p>All possible config properties are as follows </p> + <p>The available configuration properties are as follows:</p> <code type="none"> httpd_service() -> {httpd, httpd()} httpd() -> [httpd_config()] @@ -103,40 +93,43 @@ debug_options() -> {all_functions, modules()} | {exported_functions, modules()} | {disable, modules()} - modules() -> [atom()] - </code> - <p>{proplist_file, file()} File containing an erlang property + modules() -> [atom()]</code> + <p>Here:</p> + <taglist> + <tag><c>{file, file()}</c></tag> + <item><p>If you use an old apace-like configuration file.</p></item> + <tag><c>{proplist_file, file()}</c></tag> + <item><p>File containing an Erlang property list, followed by a full stop, describing the HTTP server - configuration.</p> - <p>{file, file()} If you use an old apace-like configuration file.</p> - <p>{debug, debug()} - Can enable trace on all - functions or only exported functions on chosen modules.</p> - <p>{accept_timeout, integer()} sets the wanted timeout value for - the server to set up a request connection.</p> - - <marker id="using_http_server_api"></marker> + configuration.</p></item> + <tag><c>{debug, debug()}</c></tag> + <item><p>Can enable trace on all functions or only exported functions + on chosen modules.</p></item> + <tag><c>{accept_timeout, integer()}</c></tag> + <item><p>Sets the wanted time-out value for + the server to set up a request connection.</p></item> + </taglist> </section> <section> - <title>Using the HTTP Server API</title> + <title>Getting Started</title> + <marker id="using_http_server_api"></marker> + <p>Start <c>Inets</c>:</p> <code type="none"> 1 > inets:start(). - ok - </code> - <p> Start a HTTP server with minimal - required configuration. Note that if you - specify port 0 an arbitrary available port will be - used and you can use the info function to find out - which port number that was picked. - </p> + ok</code> + <p>Start an HTTP server with minimal required configuration. + If you specify port <c>0</c>, an arbitrary available port is + used, and you can use function <c>info</c> to find which port + number that was picked:</p> <code type="none"> 2 > {ok, Pid} = inets:start(httpd, [{port, 0}, {server_name,"httpd_test"}, {server_root,"/tmp"}, {document_root,"/tmp/htdocs"}, {bind_address, "localhost"}]). - {ok, 0.79.0} - </code> + {ok, 0.79.0} </code> + <p>Call <c>info</c>:</p> <code type="none"> 3 > httpd:info(Pid). [{mime_types,[{"html","text/html"},{"htm","text/html"}]}, @@ -144,336 +137,324 @@ {bind_address, {127,0,0,1}}, {server_root,"/tmp"}, {port,59408}, - {document_root,"/tmp/htdocs"}] - </code> + {document_root,"/tmp/htdocs"}]</code> - <p> Reload the configuration without restarting the server. - Note port and bind_address can not be changed. Clients - trying to access the server during the reload will - get a service temporary unavailable answer. + <p>Reload the configuration without restarting the server: + </p> <code type="none"> 4 > httpd:reload_config([{port, 59408}, {server_name,"httpd_test"}, {server_root,"/tmp/www_test"}, {document_root,"/tmp/www_test/htdocs"}, {bind_address, "localhost"}], non_disturbing). - ok. - </code> + ok.</code> + + <note><p><c>port</c> and <c>bind_address</c> cannot be changed. + Clients trying to access the server during the reload + get a service temporary unavailable answer.</p></note> <code type="none"> 5 > httpd:info(Pid, [server_root, document_root]). - [{server_root,"/tmp/www_test"},{document_root,"/tmp/www_test/htdocs"}] - </code> + [{server_root,"/tmp/www_test"},{document_root,"/tmp/www_test/htdocs"}] </code> <code type="none"> - 6 > ok = inets:stop(httpd, Pid). - </code> + 6 > ok = inets:stop(httpd, Pid).</code> - <p> Alternative:</p> + <p>Alternative:</p> <code type="none"> - 6 > ok = inets:stop(httpd, {{127,0,0,1}, 59408}). - </code> + 6 > ok = inets:stop(httpd, {{127,0,0,1}, 59408}).</code> - <p>Note that bind_address has to be - the ip address reported by the info function and can - not be the hostname that is allowed when inputting bind_address.</p> - - <marker id="htaccess"></marker> + <p>Notice that <c>bind_address</c> must be the IP address reported + by function <c>info</c> and cannot be the hostname that is allowed + when putting in <c>bind_address</c>.</p> </section> <section> - <title>Htaccess - User Configurable Authentication.</title> - <p>If users of the web server needs to manage authentication of - web pages that are local to their user and do not have - server administrative privileges. They can use the - per-directory runtime configurable user-authentication scheme - that Inets calls htaccess. It works the following way: </p> + <title>Htaccess - User Configurable Authentication</title> + <marker id="htaccess"></marker> + <p>Web server users without server administrative privileges + that need to manage authentication of web pages that are local + to their user can use the per-directory runtime configurable + user-authentication scheme <c>htaccess</c>. + It works as follows:</p> <list type="bulleted"> <item>Each directory in the path to the requested asset is - searched for an access-file (default .htaccess), that restricts - the web servers rights to respond to a request. If an access-file - is found the rules in that file is applied to the - request. </item> - <item>The rules in an access-file applies both to files in the same - directories and in subdirectories. If there exists more than one - access-file in the path to an asset, the rules in the - access-file nearest the requested asset will be applied.</item> - <item>To change the rules that restricts the use of - an asset. The user only needs to have write access - to the directory where the asset exists.</item> - <item>All the access-files in the path to a requested asset is read - once per request, this means that the load on the server will - increase when this scheme is used.</item> - <item>If a directory is - limited both by auth directives in the HTTP server configuration - file and by the htaccess files. The user must be allowed to get - access the file by both methods for the request to succeed.</item> + searched for an access file (default is <c>.htaccess</c>), which + restricts the web servers rights to respond to a request. + If an access file is found, the rules in that file is applied to the + request.</item> + <item>The rules in an access file apply to files in the same + directory and in subdirectories. If there exists more than one + access file in the path to an asset, the rules in the + access file nearest the requested asset is applied.</item> + <item>To change the rules that restrict the use of + an asset, the user only needs write access + to the directory where the asset is.</item> + <item>All access files in the path to a requested asset are read + once per request. This means that the load on the server + increases when <c>htaccess</c> is used.</item> + <item>If a directory is limited both by authentication directives + in the HTTP server configuration file and by the <c>htaccess</c> + files, the user must be allowed to get access to the file by both + methods for the request to succeed.</item> </list> <section> <title>Access Files Directives</title> - <p>In every directory under the <c>DocumentRoot</c> or under an - <c>Alias</c> a user can place an access-file. An access-file - is a plain text file that specify the restrictions that - shall be considered before the web server answer to a - request. If there are more than one access-file in the path - to the requested asset, the directives in the access-file in - the directory nearest the asset will be used.</p> - <list type="bulleted"> + <p>In every directory under <c>DocumentRoot</c> or under an + <c>Alias</c> a user can place an access file. An access file + is a plain text file that specifies the restrictions to + consider before the web server answers to a + request. If there are more than one access file in the path + to the requested asset, the directives in the access file in + the directory nearest the asset is used.</p> + <taglist> + <tag><em>"allow"</em></tag> <item> - <p><em>DIRECTIVE: "allow"</em></p> - <p><em>Syntax:</em><c>Allow</c> from subnet subnet|from all <br></br> -<em>Default:</em><c>from all </c> <br></br> -</p> - <p>Same as the directive allow for the server config file. </p> + <p><em>Syntax:</em> <c>Allow</c> from subnet <c>subnet | from all</c></p> + <p><em>Default:</em> <c>from all</c></p> + <p>Same as directive <c>allow</c> for the server configuration file.</p> </item> - <item> - <p><em>DIRECTIVE: "AllowOverRide"</em></p> - <p><em>Syntax:</em><c>AllowOverRide</c> all | none | - Directives <br></br> -<em>Default:</em><c>- None -</c> <br></br> -<c>AllowOverRide</c> Specify which parameters that not - access-files in subdirectories are allowed to alter the value - for. If the parameter is set to none no more - access-files will be parsed. + <tag><em>"AllowOverRide"</em></tag> + <item> + <p><em>Syntax:</em> <c>AllowOverRide</c> <c>all | none | Directives</c></p> + <p><em>Default:</em> <c>none</c></p> + <p><c>AllowOverRide</c> specifies the parameters that + access files in subdirectories are not allowed to alter the value + for. If the parameter is set to <c>none</c>, no further + access files is parsed. </p> - <p>If only one access-file exists setting this parameter to - none can lessen the burden on the server since the server - will stop looking for access-files.</p> + <p>If only one access file exists, setting this parameter to + <c>none</c> can ease the burden on the server as the server + then stops looking for access files.</p> </item> + <tag><em>"AuthGroupfile"</em></tag> <item> - <p><em>DIRECTIVE: "AuthGroupfile"</em></p> - <p><em>Syntax:</em><c>AuthGroupFile</c> Filename <br></br> -<em>Default:</em><c>- None -</c> <br></br> -</p> - <p>AuthGroupFile indicates which file that contains the list - of groups. Filename must contain the absolute path to the - file. The format of the file is one group per row and + <p><em>Syntax:</em> <c>AuthGroupFile</c> Filename</p> + <p><em>Default:</em> <c>none</c></p> + <p><c>AuthGroupFile</c> indicates which file that contains the list + of groups. The filename must contain the absolute path to the + file. The format of the file is one group per row and every row contains the name of the group and the members - of the group separated by a space, for example:</p> + of the group, separated by a space, for example:</p> <pre> -GroupName: Member1 Member2 .... MemberN - </pre> +GroupName: Member1 Member2 .... MemberN</pre> </item> + <tag><em>"AuthName"</em></tag> <item> - <p><em>DIRECTIVE: "AuthName"</em></p> - <p><em>Syntax:</em><c>AuthName</c> auth-domain <br></br> -<em>Default:</em><c>- None -</c> <br></br> -</p> - <p>Same as the directive AuthName for the server config file. </p> + <p><em>Syntax:</em> <c>AuthName</c> auth-domain</p> + <p><em>Default:</em> <c>none</c></p> + <p>Same as directive <c>AuthName</c> for the server + configuration file.</p> </item> + <tag><em>"AuthType"</em></tag> <item> - <p><em>DIRECTIVE: "AuthType"</em></p> - <p><em>Syntax:</em><c>AuthType</c> Basic <br></br> -<em>Default:</em><c>Basic</c> <br></br> -</p> - <p><c>AuthType</c> Specify which authentication scheme that shall - be used. Today only Basic Authenticating using UUEncoding of - the password and user ID is implemented. </p> + <p><em>Syntax:</em> <c>AuthType</c> <c>Basic</c></p> + <p><em>Default:</em> <c>Basic</c></p> + <p><c>AuthType</c> specifies which authentication scheme to + be used. Only Basic Authenticating using UUEncoding of + the password and user ID is implemented.</p> </item> + <tag><em>"AuthUserFile"</em></tag> <item> - <p><em>DIRECTIVE: "AuthUserFile"</em></p> - <p><em>Syntax:</em><c>AuthUserFile</c> Filename <br></br> -<em>Default:</em><c>- None -</c> <br></br> -</p> - <p><c>AuthUserFile</c> indicate which file that contains the list - of users. Filename must contain the absolute path to the - file. The users name and password are not encrypted so do not + <p><em>Syntax:</em> <c>AuthUserFile</c> Filename</p> + <p><em>Default:</em><c>none</c></p> + <p><c>AuthUserFile</c> indicates which file that contains the list + of users. The filename must contain the absolute path to the + file. The username and password are not encrypted so do not place the file with users in a directory that is accessible - via the web server. The format of the file is one user per row - and every row contains User Name and Password separated by a - colon, for example:</p> + through the web server. The format of the file is one user per row. + Every row contains <c>UserName</c> and <c>Password</c> separated + by a colon, for example:</p> <pre> UserName:Password -UserName:Password - </pre> +UserName:Password</pre> </item> + <tag><em>"deny"</em></tag> <item> - <p><em>DIRECTIVE: "deny"</em></p> - <p><em>Syntax:</em><c>deny</c> from subnet subnet|from all <br></br> -<em>Context:</em> Limit</p> - <p>Same as the directive deny for the server config file. </p> + <p><em>Syntax:</em> <c>deny</c> from subnet <c>subnet | from all</c></p> + <p><em>Context:</em> Limit</p> + <p>Same as directive <c>deny</c> for the server configuration file.</p> </item> - <item> - <p><em>DIRECTIVE: "Limit"</em> <br></br> -</p> - <p><em>Syntax:</em><c><![CDATA[<Limit]]></c> RequestMethods<c>></c> <br></br> -<em>Default:</em> - None - <br></br> -</p> - <p><c><![CDATA[<Limit>]]></c> and </Limit> are used to enclose - a group of directives which applies only to requests using - the specified methods. If no request method is specified + <tag><em>"Limit"</em></tag> + <item> + <p><em>Syntax:</em> <c><![CDATA[<Limit]]></c> RequestMethods<c>></c></p> + <p><em>Default:</em> <c>none</c></p> + <p><c><![CDATA[<Limit>]]></c> and <c></Limit></c> are used to enclose + a group of directives applying only to requests using + the specified methods. If no request method is specified, all request methods are verified against the restrictions.</p> + <p>Example:</p> <pre> <Limit POST GET HEAD> order allow deny require group group1 allow from 123.145.244.5 -</Limit> - </pre> +</Limit></pre> </item> - <item> - <p><em>DIRECTIVE: "order"</em> <br></br> -<em>Syntax:</em><c>order</c> allow deny | deny allow <br></br> -<em>Default:</em> allow deny <br></br> -</p> - <p><c>order</c>, defines if the deny or allow control shall - be preformed first.</p> - <p>If the order is set to allow deny, then first the users - network address is controlled to be in the allow subset. If - the users network address is not in the allowed subset he will - be denied to get the asset. If the network-address is in the - allowed subset then a second control will be preformed, that - the users network address is not in the subset of network - addresses that shall be denied as specified by the deny - parameter.</p> - <p>If the order is set to deny allow then only users from networks - specified to be in the allowed subset will succeed to request + <tag><em>"order"</em></tag> + <item> + <p><em>Syntax:</em> <c>order</c> <c>allow deny | deny allow</c></p> + <p><em>Default:</em> <c>allow deny</c></p> + <p><c>order</c> defines if the deny or allow control is to + be performed first.</p> + <p>If the order is set to <c>allow deny</c>, the users + network address is first controlled to be in the allow subset. + If the user network address is not in the allowed subset, the user + is denied to get the asset. If the network address is in the + allowed subset, a second control is performed. That is, + the user network address is not in the subset of network + addresses to be denied as specified by parameter <c>deny</c>.</p> + <p>If the order is set to <c>deny allow</c>, only users from networks + specified to be in the allowed subset succeeds to request assets in the limited area.</p> </item> - <item> - <p><em>DIRECTIVE: "require"</em></p> - <p><em>Syntax:</em><c>require</c> - group group1 group2...|user user1 user2... <br></br> -<em>Default:</em><c>- None -</c> <br></br> -<em>Context:</em> Limit <br></br> -</p> - <p>See the require directive in the documentation of mod_auth(3) - for more information.</p> + <tag><em>"require"</em></tag> + <item> + <p><em>Syntax:</em> <c>require</c> + <c>group group1 group2... | user user1 user2...</c></p> + <p><em>Default:</em> <c>none</c></p> + <p><em>Context:</em> Limit</p> + <p>For more information, see directive <c>require</c> in + <seealso marker="mod_auth">mod_auth(3)</seealso>.</p> </item> - </list> + </taglist> </section> - - <marker id="dynamic_we_pages"></marker> </section> <section> <title>Dynamic Web Pages</title> - <p>The Inets HTTP server provides two ways of creating dynamic web - pages, each with its own advantages and disadvantages. </p> - <p>First there are CGI-scripts that can be written in any programming - language. CGI-scripts are standardized and supported by most - web servers. The drawback with CGI-scripts is that they are resource - intensive because of their design. CGI requires the server to fork a - new OS process for each executable it needs to start. </p> - <p>Second there are ESI-functions that provide a tight and efficient - interface to the execution of Erlang functions, this interface - on the other hand is Inets specific. </p> - + <marker id="dynamic_we_pages"></marker> + <p><c>Inets</c> HTTP server provides two ways of creating dynamic web + pages, each with its own advantages and disadvantages:</p> + <taglist> + <tag><em>CGI scripts</em></tag> + <item><p>Common Gateway Interface (CGI) scripts can be written + in any programming language. CGI scripts are standardized and + supported by most web servers. The drawback with CGI scripts is that + they are resource-intensive because of their design. CGI requires the + server to fork a new OS process for each executable it needs to start. + </p></item> + <tag><em>ESI-functions</em></tag> + <item><p>Erlang Server Interface (ESI) functions provide a tight and efficient + interface to the execution of Erlang functions. This interface, + on the other hand, is <c>Inets</c> specific.</p></item> + </taglist> + <section> - <title>The Common Gateway Interface (CGI) Version 1.1, RFC 3875.</title> - <p>The mod_cgi module makes it possible to execute CGI scripts - in the server. A file that matches the definition of a - ScriptAlias config directive is treated as a CGI script. A CGI + <title>CGI Version 1.1, RFC 3875</title> + <p>The module <c>mod_cgi</c> enables execution of + <url href="http://www.ietf.org/rfc/rfc3875.txt">CGI scripts</url> + on the server. A file matching the definition of a + ScriptAlias config directive is treated as a CGI script. A CGI script is executed by the server and its output is returned to - the client. </p> - <p>The CGI Script response comprises a message-header and a - message-body, separated by a blank line. The message-header - contains one or more header fields. The body may be - empty. Example: </p> + the client.</p> + <p>The CGI script response comprises a message header and a + message body, separated by a blank line. The message header + contains one or more header fields. The body can be + empty.</p> + <p>Example:</p> <code>"Content-Type:text/plain\nAccept-Ranges:none\n\nsome very - plain text" </code> + plain text"</code> - <p>The server will interpret the cgi-headers and most of them - will be transformed into HTTP headers and sent back to the - client together with the body.</p> - <p>Support for CGI-1.1 is implemented in accordance with the RFC - 3875. </p> + <p>The server interprets the message headers and most of them + are transformed into HTTP headers and sent back to the + client together with the message-body.</p> + <p>Support for CGI-1.1 is implemented in accordance with + <url href="http://www.ietf.org/rfc/rfc3875.txt">RFC 3875</url>.</p> </section> <section> - <title>Erlang Server Interface (ESI)</title> - <p>The erlang server interface is implemented by the - module mod_esi.</p> + <title>ESI</title> + <p>The Erlang server interface is implemented by + module <c>mod_esi</c>.</p> <section> - <title>ERL Scheme </title> + <title>ERL Scheme</title> <p>The erl scheme is designed to mimic plain CGI, but without - the extra overhead. An URL which calls an Erlang erl function + the extra overhead. An URL that calls an Erlang <c>erl</c> function has the following syntax (regular expression): </p> <code type="none"> -http://your.server.org/***/Module[:/]Function(?QueryString|/PathInfo) - </code> - <p>*** above depends on how the ErlScriptAlias config - directive has been used</p> - <p>The module (Module) referred to must be found in the code - path, and it must define a function (Function) with an arity - of two or three. It is preferable to implement a funtion - with arity three as it permits you to send chunks of the - webpage beeing generated to the client during the generation +http://your.server.org/***/Module[:/]Function(?QueryString|/PathInfo)</code> + <p>*** depends on how the ErlScriptAlias config + directive has been used.</p> + <p>The module <c>Module</c> referred to must be found in the code + path, and it must define a function <c>Function</c> with an arity + of two or three. It is preferable to implement a function + with arity three, as it permits to send chunks of the + web page to the client during the generation phase instead of first generating the whole web page and then sending it to the client. The option to implement a function with arity two is only kept for backwards compatibility reasons. - See <seealso marker="mod_esi">mod_esi(3)</seealso> for - implementation details of the esi callback function.</p> + For implementation details of the ESI callback function, + see <seealso marker="mod_esi">mod_esi(3)</seealso>.</p> </section> <section> - <title>EVAL Scheme </title> + <title>EVAL Scheme</title> <p>The eval scheme is straight-forward and does not mimic the - behavior of plain CGI. An URL which calls an Erlang eval + behavior of plain CGI. An URL that calls an Erlang <c>eval</c> function has the following syntax:</p> <code type="none"> -http://your.server.org/***/Mod:Func(Arg1,...,ArgN) - </code> - <p>*** above depends on how the ErlScriptAlias config - directive has been used</p> - <p>The module (Mod) referred to must be found in the code - path, and data returned by the function (Func) is passed +http://your.server.org/***/Mod:Func(Arg1,...,ArgN)</code> + <p>*** depends on how the ErlScriptAlias config + directive has been used.</p> + <p>The module <c>Mod</c> referred to must be found in the code + path and data returned by the function <c>Func</c> is passed back to the client. Data returned from the - function must furthermore take the form as specified in - the CGI specification. See <seealso marker="mod_esi">mod_esi(3)</seealso> for implementation details of the esi - callback function.</p> + function must take the form as specified in + the CGI specification. For implementation details of the ESI + callback function, + see <seealso marker="mod_esi">mod_esi(3)</seealso>.</p> <note> <p>The eval scheme can seriously threaten the - integrity of the Erlang node housing a Web server, for - example: </p> + integrity of the Erlang node housing a web server, for + example:</p> <code type="none"> -http://your.server.org/eval?httpd_example:print(atom_to_list(apply(erlang,halt,[]))) - </code> - <p>which effectively will close down the Erlang node, - therefor, use the erl scheme instead, until this - security breach has been fixed.</p> - <p>Today there are no good way of solving this problem - and therefore Eval Scheme may be removed in future - release of Inets. </p> +http://your.server.org/eval?httpd_example:print(atom_to_list(apply(erlang,halt,[])))</code> + <p>This effectively closes down the Erlang node. + Therefore, use the erl scheme instead, until this + security breach is fixed.</p> + <p>Today there are no good ways of solving this problem + and therefore the eval scheme can be removed in future + release of <c>Inets</c>.</p> </note> </section> </section> - - <marker id="logging"></marker> </section> <section> - <title>Logging </title> - <p>There are three types of logs supported. Transfer logs, - security logs and error logs. The de-facto standard Common + <title>Logging</title> + <marker id="logging"></marker> + <p>Three types of logs are supported: transfer logs, + security logs, and error logs. The de-facto standard Common Logfile Format is used for the transfer and security logging. There are numerous statistics programs available to analyze Common Logfile Format. The Common Logfile Format looks as follows: </p> <p><em>remotehost rfc931 authuser [date] "request" status bytes</em></p> + <p>Here:</p> <taglist> <tag><em>remotehost</em></tag> - <item>Remote hostname</item> + <item>Remote hostname.</item> <tag><em>rfc931</em></tag> - <item>The client's remote username (RFC 931).</item> + <item>The client remote username (<url href="http://www.ietf.org/rfc/rfc931.txt">RFC 931</url>).</item> <tag><em>authuser</em></tag> - <item>The username with which the user authenticated himself.</item> + <item>The username used for authentication.</item> <tag><em>[date]</em></tag> - <item>Date and time of the request (RFC 1123).</item> + <item>Date and time of the request (<url href="http://www.ietf.org/rfc/rfc1123.txt">RFC 1123</url>).</item> <tag><em>"request"</em></tag> - <item>The request line exactly as it came from the client (RFC 1945).</item> + <item>The request line exactly as it came from the client (<url href="http://www.ietf.org/rfc/rfc1945.txt">RFC 1945</url>).</item> <tag><em>status</em></tag> - <item>The HTTP status code returned to the client (RFC 1945).</item> + <item>The HTTP status code returned to the client (<url href="http://www.ietf.org/rfc/rfc1945.txt">RFC 1945</url>).</item> <tag><em>bytes</em></tag> <item>The content-length of the document transferred. </item> </taglist> <p>Internal server errors are recorded in the error log file. The - format of this file is a more ad hoc format than the logs using + format of this file is a more unplanned format than the logs using Common Logfile Format, but conforms to the following syntax: </p> <p><em>[date]</em> access to <em>path</em> failed for @@ -481,73 +462,79 @@ http://your.server.org/eval?httpd_example:print(atom_to_list(apply(erlang,halt,[ </section> <section> - <title>The Erlang Web Server API</title> - <p>The process of handling a HTTP request involves several steps + <title>Erlang Web Server API</title> + <p>The process of handling an HTTP request involves several steps, such as:</p> <list type="bulleted"> - <item>Seting up connections, sending and receiving data.</item> - <item>URI to filename translation</item> - <item>Authenication/access checks.</item> - <item>Retriving/generating the response.</item> - <item>Logging</item> + <item>Setting up connections, sending and receiving data.</item> + <item>URI to filename translation.</item> + <item>Authentication/access checks.</item> + <item>Retrieving/generating the response.</item> + <item>Logging.</item> </list> - <p>To provide customization and extensibility of the HTTP servers - request handling most of these steps are handled by one or more - modules that may be replaced or removed at runtime, and of course - new ones can be added. For each request all modules will be - traversed in the order specified by the modules directive in the - server configuration file. Some parts mainly the communication - related steps are considered server core functionality and are - not implemented using the Erlang Web Server API. A description of - functionality implemented by the Erlang Webserver API is described - in the section Inets Webserver Modules.</p> + <p>To provide customization and extensibility of the request + handling of the HTTP servers, most of these steps are handled by + one or more modules. These modules can be replaced or removed at + runtime and new ones can be added. For each request, all modules are + traversed in the order specified by the module directive in the + server configuration file. Some parts, mainly the communication- + related steps, are considered server core functionality and are + not implemented using the Erlang web server API. A description of + functionality implemented by the Erlang webserver API is described + in <seealso marker="#Inets_Web_Server_Modules">Section + Inets Web Server Modules</seealso>.</p> + <p>A module can use data generated by previous modules in the - Erlang Webserver API module sequence or generate data to be used - by consecutive Erlang Web Server API modules. This is made - possible due to an internal list of key-value tuples, also referred to - as interaction data. </p> + Erlang webserver API module sequence or generate data to be used + by consecutive Erlang Web Server API modules. This is + possible owing to an internal list of key-value tuples, referred to + as interaction data.</p> <note> <p>Interaction data enforces module dependencies and - should be avoided if possible. This means the order - of modules in the Modules property is significant.</p> + is to be avoided if possible. This means that the order + of modules in the modules property is significant.</p> </note> <section> <title>API Description</title> - <p>Each module implements server functionality - using the Erlang Web Server API should implement the following + <p>Each module that implements server functionality + using the Erlang web server API is to implement the following call back functions:</p> <list type="bulleted"> - <item>do/1 (mandatory) - the function called when - a request should be handled.</item> - <item>load/2</item> - <item>store/2</item> - <item>remove/1</item> + <item><c>do/1</c> (mandatory) - the function called when + a request is to be handled</item> + <item><c>load/2</c></item> + <item><c>store/2</c></item> + <item><c>remove/1</c></item> </list> <p>The latter functions are needed only when new config - directives are to be introduced. For details see - <seealso marker="httpd">httpd(3)</seealso></p> + directives are to be introduced. For details, see + <seealso marker="httpd">httpd(3)</seealso>.</p> </section> </section> <section> - <title>Inets Web Server Modules</title> <p>The convention is that - all modules implementing some webserver functionality has the - name mod_*. When configuring the web server an appropriate - selection of these modules should be present in the Module - directive. Please note that there are some interaction dependencies - to take into account so the order of the modules can not be - totally random.</p> + <title>Inets Web Server Modules</title> + <marker id="Inets_Web_Server_Modules"></marker> + <p>The convention is that + all modules implementing some web server functionality has the + name <c>mod_*</c>. When configuring the web server, an appropriate + selection of these modules is to be present in the module + directive. Notice that there are some interaction dependencies + to take into account, so the order of the modules cannot be + random.</p> <section> - <title>mod_action - Filetype/Method-Based Script Execution.</title> - <p>Runs CGI scripts whenever a file of a - certain type or HTTP method (See RFC 1945) is requested. + <title>mod_action - Filetype/Method-Based Script Execution</title> + <p>This module runs CGI scripts whenever a file of a + certain type or HTTP method (see + <url href="http://tools.ietf.org/html/rfc1945">RFC 1945</url>) + is requested. </p> <p>Uses the following Erlang Web Server API interaction data: </p> <list type="bulleted"> - <item>real_name - from mod_alias</item> + <item><c>real_name</c> - from <seealso marker="mod_alias">mod_alias</seealso>.</item> </list> <p>Exports the following Erlang Web Server API interaction data, if possible: </p> @@ -559,48 +546,51 @@ http://your.server.org/eval?httpd_example:print(atom_to_list(apply(erlang,halt,[ <section> <title>mod_alias - URL Aliasing</title> - <p>This module makes it possible to map different parts of the - host file system into the document tree e.i. creates aliases and + <p>The <seealso marker="mod_alias">mod_alias</seealso> + module makes it possible to map different parts of the + host file system into the document tree, that is, creates aliases and redirections.</p> <p>Exports the following Erlang Web Server API interaction data, if possible: </p> <taglist> <tag><c>{real_name, PathData}</c></tag> - <item>PathData is the argument used for API function mod_alias:path/3.</item> + <item><c>PathData</c> is the argument used for API function + <seealso marker="mod_alias#path/3">mod_alias:path/3</seealso>.</item> </taglist> </section> <section> - <title>mod_auth - User Authentication </title> - <p>This module provides for basic user authentication using - textual files, dets databases as well as mnesia databases.</p> + <title>mod_auth - User Authentication</title> + <p>The <seealso marker="mod_auth">mod_auth(3)</seealso> + module provides for basic user authentication using + textual files, <c>Dets</c> databases as well as <c>Mnesia</c> databases.</p> <p>Uses the following Erlang Web Server API interaction data: </p> <list type="bulleted"> - <item>real_name - from mod_alias</item> + <item><c>real_name</c> - from <seealso marker="mod_alias">mod_alias</seealso></item> </list> <p>Exports the following Erlang Web Server API interaction data: </p> <taglist> <tag><c>{remote_user, User}</c></tag> - <item>The user name with which the user has authenticated himself.</item> + <item>The username used for authentication.</item> </taglist> <section> - <title>Mnesia as Authentication Database</title> + <title>Mnesia As Authentication Database</title> - <p> If Mnesia is used as storage method, Mnesia must be - started prio to the HTTP server. The first time Mnesia is - started the schema and the tables must be created before - Mnesia is started. A naive example of a module with two - functions that creates and start mnesia is provided - here. The function shall be used the first - time. first_start/0 creates the schema and the tables. The - second function start/0 shall be used in consecutive - startups. start/0 Starts Mnesia and wait for the tables to + <p>If <c>Mnesia</c> is used as storage method, <c>Mnesia</c> must be + started before the HTTP server. The first time <c>Mnesia</c> is + started, the schema and the tables must be created before + <c>Mnesia</c> is started. A simple example of a module with two + functions that creates and start <c>Mnesia</c> is provided + here. Function <c>first_start/0</c> is to be used the first + time. It creates the schema and the tables. + <c>start/0</c> is to be used in consecutive startups. + <c>start/0</c> starts <c>Mnesia</c> and waits for the tables to be initiated. This function must only be used when the - schema and the tables already is created. </p> + schema and the tables are already created.</p> <code> -module(mnesia_test). @@ -624,28 +614,28 @@ first_start() -> start() -> mnesia:start(), - mnesia:wait_for_tables([httpd_user, httpd_group], 60000). - </code> + mnesia:wait_for_tables([httpd_user, httpd_group], 60000). </code> - <p>To create the Mnesia tables we use two records defined in - mod_auth.hrl so the file must be included. The first - function first_start/0 creates a schema that specify on - which nodes the database shall reside. Then it starts Mnesia - and creates the tables. The first argument is the name of - the tables, the second argument is a list of options how the - table will be created, see Mnesia documentation for more - information. Since the current implementation of the - mod_auth_mnesia saves one row for each user the type must be - bag. When the schema and the tables is created the second - function start/0 shall be used to start Mensia. It starts - Mnesia and wait for the tables to be loaded. Mnesia use the - directory specified as mnesia_dir at startup if specified, - otherwise Mnesia use the current directory. For security - reasons, make sure that the Mnesia tables are stored outside - the document tree of the HTTP server. If it is placed in the - directory which it protects, clients will be able to - download the tables. Only the dets and mnesia storage - methods allow writing of dynamic user data to disk. plain is + <p>To create the <c>Mnesia</c> tables, we use two records defined in + <c>mod_auth.hrl</c>, so that file must be included. <c>first_start/0</c> + creates a schema that specifies on which nodes the database is to reside. + Then it starts <c>Mnesia</c> and creates the tables. The first argument + is the name of the tables, the second argument is a list of options of + how to create the table, see + <seealso marker="mnesia:mnesia"><c>mnesia</c></seealso>, documentation for + more information. As the implementation of the <c>mod_auth_mnesia</c> + saves one row for each user, the type must be <c>bag</c>. + When the schema and the tables are created, function + <seealso marker="mnesia:mnesia#start-0">mnesia:start/0</seealso> + is used to start <c>Mnesia</c> and + waits for the tables to be loaded. <c>Mnesia</c> uses the + directory specified as <c>mnesia_dir</c> at startup if specified, + otherwise <c>Mnesia</c> uses the current directory. For security + reasons, ensure that the <c>Mnesia</c> tables are stored outside + the document tree of the HTTP server. If they are placed in the + directory which it protects, clients can download the tables. + Only the <c>Dets</c> and <c>Mnesia</c> storage + methods allow writing of dynamic user data to disk. <c>plain</c> is a read only method.</p> </section> @@ -653,19 +643,19 @@ start() -> <section> <title>mod_cgi - CGI Scripts</title> - <p>This module handles invoking of CGI scripts</p> + <p>This module handles invoking of CGI scripts.</p> </section> <section> <title>mod_dir - Directories</title> <p>This module generates an HTML directory listing (Apache-style) if a client sends a request for a directory - instead of a file. This module needs to be removed from the + instead of a file. This module must be removed from the Modules config directive if directory listings is unwanted.</p> <p>Uses the following Erlang Web Server API interaction data: </p> <list type="bulleted"> - <item>real_name - from mod_alias</item> + <item><c>real_name</c> - from <seealso marker="mod_alias">mod_alias</seealso></item> </list> <p>Exports the following Erlang Web Server API interaction data: </p> @@ -677,27 +667,27 @@ start() -> </section> <section> - <title>mod_disk_log - Logging Using disk_log.</title> + <title>mod_disk_log - Logging Using Disk_Log.</title> <p>Standard logging using the "Common Logfile Format" and - disk_log(3).</p> + <seealso marker="kernel:disk_log">kernel:disk_log(3)</seealso>.</p> <p>Uses the following Erlang Web Server API interaction data: </p> <list type="bulleted"> - <item>remote_user - from mod_auth</item> + <item><c>remote_user</c> - from <c>mod_auth</c></item> </list> </section> <section> <title>mod_esi - Erlang Server Interface</title> - <p>This module implements - the Erlang Server Interface (ESI) that provides a tight and - efficient interface to the execution of Erlang functions. </p> - <p>Uses the following Erlang Web Server API interaction data: + <p>The <seealso marker="mod_esi">mod_esi(3)</seealso> + module implements the Erlang Server Interface (ESI) providing a + tight and efficient interface to the execution of Erlang functions.</p> + <p>Uses the following Erlang web server API interaction data: </p> <list type="bulleted"> - <item>remote_user - from mod_auth</item> + <item><c>remote_user</c> - from <c>mod_auth</c></item> </list> - <p>Exports the following Erlang Web Server API interaction data: + <p>Exports the following Erlang web server API interaction data: </p> <taglist> <tag><c>{mime_type, MimeType}</c></tag> @@ -709,11 +699,11 @@ start() -> <section> <title>mod_get - Regular GET Requests</title> <p>This module is responsible for handling GET requests to regular - files. GET requests for parts of files is handled by mod_range.</p> - <p>Uses the following Erlang Web Server API interaction data: + files. GET requests for parts of files is handled by <c>mod_range</c>.</p> + <p>Uses the following Erlang web server API interaction data: </p> <list type="bulleted"> - <item>real_name - from mod_alias</item> + <item><c>real_name</c> - from <seealso marker="mod_alias">mod_alias</seealso></item> </list> </section> @@ -725,7 +715,7 @@ start() -> <p>Uses the following Erlang Web Server API interaction data: </p> <list type="bulleted"> - <item>real_name - from mod_alias</item> + <item><c>real_name</c> - from <seealso marker="mod_alias">mod_alias</seealso></item> </list> </section> @@ -736,13 +726,13 @@ start() -> <p>Uses the following Erlang Web Server API interaction data: </p> <list type="bulleted"> - <item>real_name - from mod_alias</item> + <item><c>real_name</c> - from <seealso marker="mod_alias">mod_alias</seealso></item> </list> <p>Exports the following Erlang Web Server API interaction data: </p> <taglist> <tag><c>{remote_user_name, User}</c></tag> - <item>The user name with which the user has authenticated himself.</item> + <item>The username used for authentication.</item> </taglist> </section> @@ -750,84 +740,83 @@ start() -> <title>mod_log - Logging Using Text Files.</title> <p>Standard logging using the "Common Logfile Format" and text files.</p> - <p>Uses the following Erlang Webserver API interaction data: + <p>Uses the following Erlang Web Server API interaction data: </p> <list type="bulleted"> - <item>remote_user - from mod_auth</item> + <item><c>remote_user</c> - from <c>mod_auth</c></item> </list> </section> <section> <title>mod_range - Requests with Range Headers</title> - <p>This module response to requests for one or many ranges of a - file. This is especially useful when downloading large files, - since a broken download may be resumed.</p> - <p>Note that request for multiple parts of a document will report a + <p>This module responses to requests for one or many ranges of a + file. This is especially useful when downloading large files, + as a broken download can be resumed.</p> + <p>Notice that request for multiple parts of a document report a size of zero to the log file.</p> - <p>Uses the following Erlang Webserver API interaction data: + <p>Uses the following Erlang Web Server API interaction data: </p> <list type="bulleted"> - <item>real_name - from mod_alias</item> + <item><c>real_name</c> - from <seealso marker="mod_alias">mod_alias</seealso></item> </list> </section> <section> <title>mod_response_control - Requests with If* Headers</title> - <p>This module controls that the conditions in the requests is - fulfilled. For example a request may specify that the answer - only is of interest if the content is unchanged since last - retrieval. Or if the content is changed the range-request shall - be converted to a request for the whole file instead.</p> <p>If - a client sends more then one of the header fields that restricts - the servers right to respond, the standard does not specify how - this shall be handled. httpd will control each field in the - following order and if one of the fields not match the current - state the request will be rejected with a proper response. - <br></br> + <p>This module controls that the conditions in the requests are + fulfilled. For example, a request can specify that the answer + only is of interest if the content is unchanged since the last + retrieval. If the content is changed, the range request is to + be converted to a request for the whole file instead.</p> + <p>If a client sends more than one of the header fields that + restricts the servers right to respond, the standard does not + specify how this is to be handled. + <seealso marker="httpd">httpd(3)</seealso> controls each + field in the following order and if one of the fields does not + match the current state, the request is rejected with a proper + response:</p> + <p><c>If-modified</c></p> + <p><c>If-Unmodified</c></p> + <p><c>If-Match</c></p> + <p><c>If-Nomatch</c></p> - 1.If-modified <br></br> - - 2.If-Unmodified <br></br> - - 3.If-Match <br></br> - - 4.If-Nomatch <br></br> -</p> - <p>Uses the following Erlang Webserver API interaction data: + <p>Uses the following Erlang Web Server API interaction data: </p> <list type="bulleted"> - <item>real_name - from mod_alias</item> + <item><c>real_name</c> - from <seealso marker="mod_alias">mod_alias</seealso></item> </list> - <p>Exports the following Erlang Webserver API interaction data: + <p>Exports the following Erlang Web Server API interaction data: </p> <taglist> <tag><c>{if_range, send_file}</c></tag> - <item>The conditions for the range request was not fulfilled. + <item>The conditions for the range request are not fulfilled. The response must not be treated as a range request, instead it - must be treated as a ordinary get request. </item> + must be treated as an ordinary get request.</item> </taglist> </section> <section> <title>mod_security - Security Filter</title> - <p>This module serves as a filter for authenticated requests - handled in mod_auth. It provides possibility to restrict users - from access for a specified amount of time if they fail to + <p>The <seealso marker="mod_security">mod_security</seealso> + module serves as a filter for authenticated requests + handled in <seealso marker="mod_auth">mod_auth(3)</seealso>. + It provides a possibility to restrict users from + access for a specified amount of time if they fail to authenticate several times. It logs failed authentication as - well as blocking of users, and it also calls a configurable - call-back module when the events occur. </p> + well as blocking of users, and it calls a configurable + callback module when the events occur.</p> <p>There is also an - API to manually block, unblock and list blocked users or users, - who have been authenticated within a configurable amount of - time.</p> + API to block or unblock users manually. This API can also list + blocked users or users who have been authenticated within a + configurable amount of time.</p> </section> <section> <title>mod_trace - TRACE Request</title> - <p>mod_trace is responsible for handling of TRACE requests. + <p><c>mod_trace</c> is responsible for handling of TRACE requests. Trace is a new request method in HTTP/1.1. The intended use of trace requests is for testing. The body of the trace response is - the request message that the responding Web server or proxy + the request message that the responding web server or proxy received.</p> </section> </section> diff --git a/lib/inets/doc/src/http_uri.xml b/lib/inets/doc/src/http_uri.xml index 4b59c0c7a2..8e0301c520 100644 --- a/lib/inets/doc/src/http_uri.xml +++ b/lib/inets/doc/src/http_uri.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2012</year><year>2013</year> + <year>2012</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -35,67 +35,90 @@ <description> <p>This module provides utility functions for working with URIs, - according to RFC 3986. </p> - + according to + <url href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</url>.</p> </description> <section> - <title>COMMON DATA TYPES </title> + <title>DATA TYPES</title> <p>Type definitions that are used more than once in this module:</p> - <code type="none"><![CDATA[ -boolean() = true | false -string() = list of ASCII characters - ]]></code> + <p><c>boolean() = true | false</c></p> + <p><c>string()</c> = list of ASCII characters</p> </section> <section> - <title>URI DATA TYPES </title> + <title>URI DATA TYPES</title> <p>Type definitions that are related to URI:</p> - <p>For more information about URI, see RFC 3986. </p> - - <code type="none"><![CDATA[ -uri() = string() - Syntax according to the URI definition in rfc 3986, - e.g.: "http://www.erlang.org/" -user_info() = string() -scheme() = atom() - Example: http, https -host() = string() -port() = pos_integer() -path() = string() - Representing a file path or directory path -query() = string() -fragment() = string() - ]]></code> - + +<taglist> + <tag><c>uri() = string()</c></tag> + <item><p>Syntax according to the URI definition in RFC 3986, + for example, "http://www.erlang.org/"</p></item> + <tag><c>user_info() = string()</c></tag> + <item><p></p></item> + <tag><c>scheme() = atom()</c></tag> + <item><p>Example: http, https</p></item> + <tag><c>host() = string()</c></tag> + <item><p></p></item> + <tag><c>port() = pos_integer()</c></tag> + <item><p></p></item> + <tag><c>path() = string()</c></tag> + <item><p>Represents a file path or directory path</p></item> + <tag><c>query() = string()</c></tag> + <item><p></p></item> + <tag><c>fragment() = string()</c></tag> + <item><p></p></item> + </taglist> + + <p>For more information about URI, see + <url href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</url>.</p> <marker id="scheme_defaults"></marker> </section> <funcs> <func> - <name>scheme_defaults() -> SchemeDefaults</name> - <fsummary>A list of scheme and their default ports</fsummary> + <name>decode(HexEncodedURI) -> URI</name> + + <fsummary>Decodes a hexadecimal encoded URI.</fsummary> <type> - <v>SchemeDefaults = [{scheme(), default_scheme_port_number()}] </v> - <v>default_scheme_port_number() = pos_integer()</v> + <v>HexEncodedURI = string() - A possibly hexadecimal encoded URI</v> + <v>URI = uri()</v> </type> + <desc> - <p>This function provides a list of the scheme and their default - port numbers currently supported (by default) by this utility. </p> + <p>Decodes a possibly hexadecimal encoded URI.</p> - <marker id="parse"></marker> + </desc> + </func> + <func> + <name>encode(URI) -> HexEncodedURI</name> + + <fsummary>Encodes a hexadecimal encoded URI.</fsummary> + <type> + <v>URI = uri()</v> + <v>HexEncodedURI = string() - Hexadecimal encoded URI</v> + </type> + + <desc> + <p>Encodes a hexadecimal encoded URI.</p> + + <marker id="decode"></marker> </desc> </func> <func> <name>parse(URI) -> {ok, Result} | {error, Reason}</name> <name>parse(URI, Options) -> {ok, Result} | {error, Reason}</name> - <fsummary>Parse an URI</fsummary> + <fsummary>Parses a URI.</fsummary> <type> - <v>URI = uri() </v> - <v>Options = [Option] </v> + <v>URI = uri()</v> + <v>Options = [Option]</v> <v>Option = {ipv6_host_with_brackets, boolean()} | {scheme_defaults, scheme_defaults()} | - {fragment, boolean()}]</v> + {fragment, boolean()} | + {schema_validation_fun, fun()}]</v> <v>Result = {Scheme, UserInfo, Host, Port, Path, Query} | {Scheme, UserInfo, Host, Port, Path, Query, Fragment}</v> <v>UserInfo = user_info()</v> @@ -104,62 +127,59 @@ fragment() = string() <v>Path = path()</v> <v>Query = query()</v> <v>Fragment = fragment()</v> - <v>Reason = term() </v> + <v>Reason = term()</v> </type> <desc> - <p>This function is used to parse an URI. If no scheme defaults - are provided, the value of + <p>Parses a URI. If no scheme defaults + are provided, the value of the <seealso marker="#scheme_defaults">scheme_defaults</seealso> - function will be used. </p> + function is used.</p> - <p>Note that when parsing an URI with an unknown scheme (that is, - a scheme not found in the scheme defaults) a port number must be - provided or else the parsing will fail. </p> + <p>When parsing a URI with an unknown scheme (that is, + a scheme not found in the scheme defaults), a port number must be + provided, otherwise the parsing fails.</p> - <p>If the fragment option is true, the URI fragment will be returned as - part of the parsing result, otherwise it is completely ignored.</p> + <p>If the fragment option is <c>true</c>, the URI fragment is returned as + part of the parsing result, otherwise it is ignored.</p> - <marker id="encode"></marker> - </desc> - </func> + <p>Scheme validation fun is to be defined as follows:</p> - <func> - <name>encode(URI) -> HexEncodedURI</name> - - <fsummary>Hex encode an URI</fsummary> - <type> - <v>URI = uri()</v> - <v>HexEncodedURI = string() - Hex encoded uri</v> - </type> + <code> +fun(SchemeStr :: string()) -> + valid | {error, Reason :: term()}. + </code> - <desc> - <p>Hex encode an URI. </p> + <p>It is called before scheme string gets converted into scheme atom and + thus possible atom leak could be prevented</p> - <marker id="decode"></marker> + <marker id="encode"></marker> </desc> </func> <func> - <name>decode(HexEncodedURI) -> URI</name> - - <fsummary>Decode a hex encoded URI</fsummary> + <name>scheme_defaults() -> SchemeDefaults</name> + <fsummary>A list of the scheme and their default ports.</fsummary> <type> - <v>HexEncodedURI = string() - A possibly hex encoded uri</v> - <v>URI = uri()</v> + <v>SchemeDefaults = [{scheme(), default_scheme_port_number()}] </v> + <v>default_scheme_port_number() = pos_integer()</v> </type> - <desc> - <p>Decode a possibly hex encoded URI. </p> + <p>Provides a list of the scheme and their default + port numbers supported (by default) by this utility.</p> + <marker id="parse"></marker> </desc> </func> + + </funcs> <!-- <section> <title>SEE ALSO</title> - <p>RFC 2616, <seealso marker="inets">inets(3)</seealso>, + <p><url href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</url>, + <seealso marker="inets">inets(3)</seealso>, <seealso marker="kernel:gen_tcp">gen_tcp(3)</seealso>, <seealso marker="ssl:ssl">ssl(3)</seealso> </p> diff --git a/lib/inets/doc/src/httpc.xml b/lib/inets/doc/src/httpc.xml index 05eec9cfd3..ca9b268a03 100644 --- a/lib/inets/doc/src/httpc.xml +++ b/lib/inets/doc/src/httpc.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2004</year><year>2013</year> + <year>2004</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -31,143 +31,252 @@ </header> <module>httpc</module> - <modulesummary>An HTTP/1.1 client </modulesummary> + <modulesummary>An HTTP/1.1 client</modulesummary> <description> - <p>This module provides the API to a HTTP/1.1 compatible client according - to RFC 2616, caching is currently not supported.</p> + <p>This module provides the API to an HTTP/1.1 compatible client according + to <url href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</url>. + Caching is not supported.</p> <note> - <p>When starting the Inets application a manager process for the - default profile will be started. The functions in this API - that do not explicitly use a profile will access the + <p>When starting the <c>Inets</c> application, a manager process for the + default profile is started. The functions in this API + that do not explicitly use a profile accesses the default profile. A profile keeps track of proxy options, - cookies and other options that can be applied to more than one - request. </p> + cookies, and other options that can be applied to more than one + request.</p> - <p>If the scheme https is used the ssl application needs to be - started. When https links needs to go through a proxy the + <p>If the scheme <c>https</c> is used, the <c>SSL</c> application must + be started. When <c>https</c> links need to go through a proxy, the CONNECT method extension to HTTP-1.1 is used to establish a - tunnel and then the connection is upgraded to TLS, - however "TLS upgrade" according to RFC 2817 is not + tunnel and then the connection is upgraded to TLS. + However, "TLS upgrade" according to <url href="http://www.ietf.org/rfc/rfc2817.txt">RFC 2817</url>is not supported.</p> - <p>Also note that pipelining will only be used if the pipeline - timeout is set, otherwise persistent connections without - pipelining will be used e.i. the client always waits for + <p>Pipelining is only used if the pipeline + time-out is set, otherwise persistent connections without + pipelining are used. That is, the client always waits for the previous response before sending the next request.</p> </note> - <p>There are some usage examples in the <seealso - marker="http_client">Inets User's Guide.</seealso></p> + <p>Some examples are provided in the <seealso + marker="http_client">Inets User's Guide</seealso>.</p> </description> <section> - <title>COMMON DATA TYPES </title> + <title>DATA TYPES</title> + <marker id="DATA_TYPES"></marker> <p>Type definitions that are used more than once in this module:</p> - <code type="none"><![CDATA[ -boolean() = true | false -string() = list of ASCII characters -request_id() = ref() -profile() = atom() -path() = string() representing a file path or directory path -ip_address() = See inet(3) -socket_opt() = See the Options used by gen_tcp(3) and - ssl(3) connect(s) - ]]></code> - + <p><c>boolean() = true | false</c></p> + <p><c>string()</c> = list of ASCII characters</p> + <p><c>request_id() = ref()</c></p> + <p><c>profile() = atom()</c></p> + <p><c>path() = string()</c> representing a file path or directory path</p> + <p><c>ip_address()</c> = See the + <seealso marker="kernel:inet">inet(3)</seealso> manual page in <c>Kernel</c>.</p> + <p><c>socket_opt()</c> = See the options used by + <seealso marker="kernel:gen_tcp">gen_tcp(3)</seealso> <c>gen_tcp(3)</c> and + <seealso marker="ssl:ssl">ssl(3)</seealso> connect(s)</p> + </section> <section> - <title>HTTP DATA TYPES </title> - <p>Type definitions that are related to HTTP:</p> - <p>For more information about HTTP see rfc 2616</p> - - <code type="none"><![CDATA[ -method() = head | get | put | post | trace | options | delete -request() = {url(), headers()} | - {url(), headers(), content_type(), body()} -url() = string() - Syntax according to the URI definition in rfc 2396, ex: "http://www.erlang.org" -status_line() = {http_version(), status_code(), reason_phrase()} -http_version() = string() ex: "HTTP/1.1" -status_code() = integer() -reason_phrase() = string() -content_type() = string() -headers() = [header()] -header() = {field(), value()} -field() = string() -value() = string() -body() = string() | - binary() | - {fun(accumulator()) -> body_processing_result(), - accumulator()} | - {chunkify, - fun(accumulator()) -> body_processing_result(), - accumulator()} -body_processing_result() = eof | {ok, iolist(), accumulator()} -accumulator() = term() -filename() = string() - ]]></code> + <title>HTTP DATA TYPES</title> + <p>Type definitions related to HTTP:</p> - </section> + <p><c>method() = head | get | put | post | trace | options | delete</c></p> + <taglist> + <tag><c>request()</c></tag> + <item><p>= <c>{url(), headers()}</c></p> + <p>| <c>{url(), headers(), content_type(), body()}</c></p> + </item> + </taglist> + <p><c>url() = string()</c> syntax according to the URI definition in + <url href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</url>, + for example <c>"http://www.erlang.org"</c></p> + <p><c>status_line() = {http_version(), status_code(), reason_phrase()}</c></p> + <p><c>http_version() = string()</c>, for example, <c>"HTTP/1.1"</c></p> + <p><c>status_code() = integer()</c></p> + <p><c>reason_phrase() = string()</c></p> + <p><c>content_type() = string()</c></p> + <p><c>headers() = [header()]</c></p> + <p><c>header() = {field(), value()}</c></p> + <p><c>field() = string()</c></p> + <p><c>value() = string()</c></p> + <taglist> + <tag><c>body()</c></tag> + <item><p>= <c>string() | binary()</c></p> + <p>| <c>{fun(accumulator())</c></p> + <p><c> -> body_processing_result(), accumulator()}</c></p> + <p>| <c>{chunkify, fun(accumulator())</c></p> + <p><c> -> body_processing_result(), accumulator()}</c></p> + </item> + </taglist> + <p><c>body_processing_result() = eof | {ok, iolist(), accumulator()}</c></p> + <p><c>accumulator() = term()</c></p> + <p><c>filename() = string()</c></p> + <p>For more information about HTTP, see + <url href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</url>.</p> +</section> <section> - <title>SSL DATA TYPES </title> + <title>SSL DATA TYPES</title> <p>See <seealso marker="ssl:ssl">ssl(3)</seealso> for information - about ssl options (<c>ssloptions()</c>). </p> + about <c>SSL</c> options (<c>ssloptions()</c>). </p> </section> <section> - <title>HTTP CLIENT SERVICE START/STOP </title> + <title>HTTP CLIENT SERVICE START/STOP</title> - <p>A HTTP client can be configured to start when starting the inets + <p>An HTTP client can be configured to start when starting the <c>Inets</c> application or started dynamically in runtime by calling the - inets application API <c>inets:start(httpc, ServiceConfig)</c>, or - <c>inets:start(httpc, ServiceConfig, How)</c> - see <seealso marker="inets">inets(3)</seealso>. Below follows a - description of the available configuration options.</p> + <c>Inets</c> application API <c>inets:start(httpc, ServiceConfig)</c> + or <c>inets:start(httpc, ServiceConfig, How)</c>, + see <seealso marker="inets">inets(3)</seealso>. + The configuration options are as follows:</p> <taglist> <tag>{profile, profile()}</tag> - <item>Name of the profile, see - common data types below, this option is mandatory.</item> + <item><p>Name of the profile, see + <seealso marker="#DATA_TYPES">DATA TYPES</seealso>. + This option is mandatory.</p></item> <tag>{data_dir, path()}</tag> - <item>Directory where the profile - may save persistent data, if omitted all cookies will be treated - as session cookies.</item> + <item><p>Directory where the profile + can save persistent data. If omitted, all cookies are treated + as session cookies.</p></item> </taglist> <p>The client can be stopped using <c>inets:stop(httpc, Pid)</c> or <c>inets:stop(httpc, Profile)</c>.</p> - - <marker id="request1"></marker> </section> <funcs> + + <func> + <name>cancel_request(RequestId) -></name> + <name>cancel_request(RequestId, Profile) -> ok</name> + <fsummary>Cancels an asynchronous HTTP request.</fsummary> + <type> + <v>RequestId = request_id() - A unique identifier as returned + by request/4</v> + <v>Profile = profile() | pid()</v> + <d>When started <c>stand_alone</c> only the pid can be used.</d> + </type> + <desc> + <p>Cancels an asynchronous HTTP request. Notice that this does not guarantee + that the request response is not delivered. Because it is asynchronous, + the request can already have been completed when the cancellation arrives. + </p> + </desc> + </func> + + <func> + <name>cookie_header(Url) -> </name> + <name>cookie_header(Url, Profile | Opts) -> header() | {error, Reason}</name> + <name>cookie_header(Url, Opts, Profile) -> header() | {error, Reason}</name> + <fsummary>Returns the cookie header that would have been sent when + making a request to URL using the profile <c>Profile</c>.</fsummary> + <type> + <v>Url = url()</v> + <v>Opts = [cookie_header_opt()]</v> + <v>Profile = profile() | pid()</v> + <d>When started <c>stand_alone</c>.</d> + <v>cookie_header_opt() = {ipv6_host_with_brackets, boolean()}</v> + </type> + <desc> + <p>Returns the cookie header that would have been sent + when making a request to <c>Url</c> using profile <c>Profile</c>. + If no profile is specified, the default profile is used.</p> + <p>Option <c>ipv6_host_with_bracket</c> deals with how to + parse IPv6 addresses. For details, + see argument <c>Options</c> of + <seealso marker="#request-4">request/[4,5]</seealso>.</p> + </desc> + </func> + + <func> + <name>get_options(OptionItems) -> {ok, Values} | {error, Reason}</name> + <name>get_options(OptionItems, Profile) -> {ok, Values} | {error, Reason}</name> + <fsummary>Gets the currently used options.</fsummary> + <type> + <v>OptionItems = all | [option_item()]</v> + <v>option_item() = proxy | + https_proxy | + max_sessions | + keep_alive_timeout | + max_keep_alive_length | + pipeline_timeout | + max_pipeline_length | + cookies | + ipfamily | + ip | + port | + socket_opts | + verbose</v> + <v>Profile = profile() | pid()</v> + <d>When started <c>stand_alone</c> only the pid can used.</d> + <v>Values = [{option_item(), term()}]</v> + <v>Reason = term()</v> + </type> + <desc> + <p>Retrieves the options currently used by the client.</p> + </desc> + </func> + + <func> + <name>info() -> list()</name> + <name>info(Profile) -> list()</name> + <fsummary>Produces a list of miscellaneous information.</fsummary> + <type> + <v>Profile = profile() | pid()</v> + <d>When started <c>stand_alone</c> only the pid can be used.</d> + </type> + <desc> + <p>Produces a list of miscellaneous information. + Intended for debugging. + If no profile is specified, the default profile is used.</p> + </desc> + </func> + + + <func> + <name>reset_cookies() -> void()</name> + <name>reset_cookies(Profile) -> void()</name> + <fsummary>Resets the cookie database.</fsummary> + <type> + <v>Profile = profile() | pid()</v> + <d>When started <c>stand_alone</c> only the pid can be used.</d> + </type> + <desc> + <p>Resets (clears) the cookie database for the specified + <c>Profile</c>. If no profile is specified the default profile + is used.</p> + </desc> + </func> + <func> <name>request(Url) -> </name> <name>request(Url, Profile) -> {ok, Result} | {error, Reason}</name> - <fsummary>Sends a get HTTP-request</fsummary> + <fsummary>Sends a get HTTP request.</fsummary> <type> - <v>Url = url() </v> + <v>Url = url()</v> <v>Result = {status_line(), headers(), Body} | - {status_code(), Body} | request_id() </v> + {status_code(), Body} | request_id()</v> <v>Body = string() | binary()</v> - <v>Profile = profile() | pid() (when started <c>stand_alone</c>)</v> - <v>Reason = term() </v> + <v>Profile = profile() | pid()</v> + <d>When started <c>stand_alone</c> only the pid can be used.</d> + <v>Reason = term()</v> </type> <desc> <p>Equivalent to <c>httpc:request(get, {Url, []}, [], [])</c>.</p> - - <marker id="request2"></marker> </desc> </func> <func> - <name>request(Method, Request, HTTPOptions, Options) -> </name> + <name>request(Method, Request, HTTPOptions, Options) -></name> <name>request(Method, Request, HTTPOptions, Options, Profile) -> {ok, Result} | {ok, saved_to_file} | {error, Reason}</name> - <fsummary>Sends a HTTP-request</fsummary> + <fsummary>Sends an HTTP request.</fsummary> <type> - <v>Method = method() </v> + <v>Method = method()</v> <v>Request = request()</v> <v>HTTPOptions = http_options()</v> <v>http_options() = [http_option()]</v> @@ -191,215 +300,200 @@ filename() = string() {socket_opts, socket_opts()} | {receiver, receiver()}, {ipv6_host_with_brackets, boolean()}}</v> - <v>stream_to() = none | self | {self, once} | filename() </v> + <v>stream_to() = none | self | {self, once} | filename()</v> <v>socket_opts() = [socket_opt()]</v> - <v>receiver() = pid() | function()/1 | {Module, Function, Args} </v> - <v>Module = atom() </v> - <v>Function = atom() </v> - <v>Args = list() </v> - <v>body_format() = string | binary </v> + <v>receiver() = pid() | function()/1 | {Module, Function, Args}</v> + <v>Module = atom()</v> + <v>Function = atom()</v> + <v>Args = list()</v> + <v>body_format() = string | binary</v> <v>Result = {status_line(), headers(), Body} | - {status_code(), Body} | request_id() </v> + {status_code(), Body} | request_id()</v> <v>Body = string() | binary()</v> - <v>Profile = profile() | pid() (when started <c>stand_alone</c>)</v> + <v>Profile = profile() | pid()</v> + <d>When started <c>stand_alone</c> only the pid can be used.</d> <v>Reason = {connect_failed, term()} | - {send_failed, term()} | term() </v> + {send_failed, term()} | term()</v> </type> <desc> - <p>Sends a HTTP-request. The function can be both synchronous - and asynchronous. In the later case the function will return - <c>{ok, RequestId}</c> and later on the information will be delivered - to the <c>receiver</c> depending on that value. </p> + <p>Sends an HTTP request. The function can be both synchronous + and asynchronous. In the latter case, the function returns + <c>{ok, RequestId}</c> and then the information is delivered + to the <c>receiver</c> depending on that value.</p> - <p>Http option (<c>http_option()</c>) details: </p> + <p>HTTP option (<c>http_option()</c>) details:</p> <marker id="request2_http_options"></marker> <taglist> <tag><c><![CDATA[timeout]]></c></tag> <item> - <p>Timeout time for the request. </p> - <p>The clock starts ticking as soon as the request has been - sent. </p> - <p>Time is in milliseconds. </p> - <p>Defaults to <c>infinity</c>. </p> + <p>Time-out time for the request.</p> + <p>The clock starts ticking when the request is sent.</p> + <p>Time is in milliseconds.</p> + <p>Default is <c>infinity</c>.</p> </item> <tag><c><![CDATA[connect_timeout]]></c></tag> <item> - <p>Connection timeout time, used during the initial request, - when the client is <em>connecting</em> to the server. </p> - <p>Time is in milliseconds. </p> - <p>Defaults to the value of the <c>timeout</c> option. </p> + <p>Connection time-out time, used during the initial request, + when the client is <em>connecting</em> to the server.</p> + <p>Time is in milliseconds.</p> + <p>Default is the value of option <c>timeout</c>.</p> </item> <tag><c><![CDATA[ssl]]></c></tag> <item> - <p>This is the default ssl config option, currently defaults to - <c>essl</c>, see below. </p> - <p>Defaults to <c>[]</c>. </p> - </item> - - <tag><c><![CDATA[essl]]></c></tag> - <item> - <p>If using the Erlang based implementation of SSL, - these SSL-specific options are used. </p> - <p>Defaults to <c>[]</c>. </p> + <p>This is the <c>SSL/TLS</c> connectin configuration option.</p> + <p>Defaults to <c>[]</c>. See <seealso marker="ssl:ssl">ssl:connect/[2, 3,4]</seealso> for availble options.</p> </item> <tag><c><![CDATA[autoredirect]]></c></tag> <item> - <p>Should the client automatically retrieve the information - from the new URI and return that as the result instead - of a 30X-result code. </p> - <p>Note that for some 30X-result codes automatic redirect - is not allowed. In these cases the 30X-result will always - be returned. </p> - <p>Defaults to <c>true</c>. </p> + <p>The client automatically retrieves the information + from the new URI and returns that as the result, instead + of a 30X-result code.</p> + <p>For some 30X-result codes, automatic redirect + is not allowed. In these cases the 30X-result is always + returned.</p> + <p>Default is <c>true</c>.</p> </item> <tag><c><![CDATA[proxy_auth]]></c></tag> <item> - <p>A proxy-authorization header using the provided user name and - password will be added to the request. </p> + <p>A proxy-authorization header using the provided username and + password is added to the request.</p> </item> <tag><c><![CDATA[version]]></c></tag> <item> <p>Can be used to make the client act as an <c>HTTP/1.0</c> or <c>HTTP/0.9</c> client. By default this is an <c>HTTP/1.1</c> - client. When using <c>HTTP/1.0</c> persistent connections will - not be used. </p> - <p>Defaults to the string <c>"HTTP/1.1"</c>. </p> + client. When using <c>HTTP/1.0</c> persistent connections are + not used.</p> + <p>Default is the string <c>"HTTP/1.1"</c>.</p> </item> <tag><c><![CDATA[relaxed]]></c></tag> <item> - <p>If set to <c>true</c> workarounds for known server deviations - from the HTTP-standard are enabled. </p> - <p>Defaults to <c>false</c>. </p> + <p>If set to <c>true</c>, workarounds for known server deviations + from the HTTP-standard are enabled.</p> + <p>Default is <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 + <p>Applies Percent-encoding, also known as URL encoding on the URL.</p> - <p>Defaults to <c>false</c>. </p> + <p>Default is <c>false</c>.</p> </item> </taglist> - <p>Option (<c>option()</c>) details: </p> + <p>Option (<c>option()</c>) details:</p> <taglist> <tag><c><![CDATA[sync]]></c></tag> <item> - <p>Shall the request be synchronous or asynchronous. </p> - <p>Defaults to <c>true</c>. </p> + <p>Option for the request to be synchronous or asynchronous.</p> + <p>Default is <c>true</c>.</p> </item> <tag><c><![CDATA[stream]]></c></tag> <item> <p>Streams the body of a 200 or 206 response to the calling process or to a file. When streaming to the calling process - using the option <c>self</c> the following stream messages - will be sent to that process: <c>{http, {RequestId, + using option <c>self</c>, the following stream messages + are sent to that process: <c>{http, {RequestId, stream_start, Headers}}, {http, {RequestId, stream, - BinBodyPart}}, {http, {RequestId, stream_end, Headers}}</c>. When - streaming to the calling processes using the option - <c>{self, once}</c> the first message will have an additional - element e.i. <c>{http, {RequestId, stream_start, Headers, Pid}}</c>, - this is the process id that should be used as an argument to + BinBodyPart}}, and {http, {RequestId, stream_end, Headers}}</c>.</p> + <p>When streaming to the calling processes using option + <c>{self, once}</c>, the first message has an extra + element, that is, <c>{http, {RequestId, stream_start, Headers, Pid}}</c>. + This is the process id to be used as an argument to <c>http:stream_next/1</c> to trigger the next message to be sent to - the calling process. </p> - <p>Note that it is possible that chunked encoding will add + the calling process.</p> + <p>Notice that chunked encoding can add headers so that there are more headers in the <c>stream_end</c> - message than in the <c>stream_start</c>. - When streaming to a file and the request is asynchronous the - message <c>{http, {RequestId, saved_to_file}}</c> will be sent. </p> - <p>Defaults to <c>none</c>. </p> + message than in <c>stream_start</c>. + When streaming to a file and the request is asynchronous, the + message <c>{http, {RequestId, saved_to_file}}</c> is sent.</p> + <p>Default is <c>none</c>.</p> </item> <tag><c><![CDATA[body_format]]></c></tag> <item> - <p>Defines if the body shall be delivered as a string or as a + <p>Defines if the body is to be delivered as a string or binary. This option is only valid for the synchronous - request. </p> - <p>Defaults to <c>string</c>. </p> + request.</p> + <p>Default is <c>string</c>.</p> </item> <tag><c><![CDATA[full_result]]></c></tag> <item> - <p>Should a "full result" be returned to the caller (that is, - the body, the headers and the entire status-line) or not - (the body and the status code). </p> - <p>Defaults to <c>true</c>. </p> + <p>Defines if a "full result" is to be returned to the caller (that is, + the body, the headers, and the entire status line) or not + (the body and the status code).</p> + <p>Default is <c>true</c>.</p> </item> <tag><c><![CDATA[headers_as_is]]></c></tag> <item> - <p>Shall the headers provided by the user be made - lower case or be regarded as case sensitive. </p> - <p>Note that the http standard requires them to be - case insenstive. This feature should only be used if there is + <p>Defines if the headers provided by the user are to be made + lower case or to be regarded as case sensitive.</p> + <p>The HTTP standard requires them to be + case insensitive. Use this feature only if there is no other way to communicate with the server or for testing - purpose. Also note that when this option is used no headers - will be automatically added, all necessary headers have to be - provided by the user. </p> - <p>Defaults to <c>false</c>. </p> + purpose. When this option is used, no headers + are automatically added. All necessary headers must be + provided by the user.</p> + <p>Default is <c>false</c>.</p> </item> <tag><c><![CDATA[socket_opts]]></c></tag> <item> <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> - function. </p> - <p>Note that the validity of the options are <em>not</em> - checked in any way. </p> - <p>Note that this may change the socket behaviour - (see <seealso marker="kernel:inet#setopts/2">inet:setopts/2</seealso>) - for an already existing one, and therefore an already connected - request handler. </p> - <p>By default the socket options set by the - <seealso marker="#set_options">set_options/1,2</seealso> - function are used when establishing a connection. </p> + requests.</p> + <p>Overrides any value set by function + <seealso marker="#set_options-1">set_options</seealso>.</p> + <p>The validity of the options is <em>not</em> checked by + the HTTP client they are assumed to be correct and passed + on to ssl application and inet driver, which may reject + them if they are not correct. Note that the current + implementation assumes the requests to the same host, port + combination will use the same socket options. + </p> + + <p>By default the socket options set by function + <seealso marker="#set_options-1">set_options/[1,2]</seealso> + are used when establishing a connection.</p> </item> <tag><c><![CDATA[receiver]]></c></tag> <item> - <p>Defines how the client will deliver the result of an - asynchronous request (<c>sync</c> has the value - <c>false</c>). </p> + <p>Defines how the client delivers the result of an + asynchronous request (<c>sync</c> has the value + <c>false</c>).</p> <taglist> <tag><c><![CDATA[pid()]]></c></tag> <item> - <p>Message(s) will be sent to this process in the format: </p> -<pre> -{http, ReplyInfo} -</pre> + <p>Messages are sent to this process in the format + <c>{http, ReplyInfo}</c>.</p> </item> <tag><c><![CDATA[function/1]]></c></tag> <item> - <p>Information will be delivered to the receiver via calls - to the provided fun: </p> -<pre> -Receiver(ReplyInfo) -</pre> + <p>Information is delivered to the receiver through calls + to the provided fun <c>Receiver(ReplyInfo)</c>.</p> </item> <tag><c><![CDATA[{Module, Function, Args}]]></c></tag> <item> - <p>Information will be delivered to the receiver via calls - to the callback function: </p> -<pre> -apply(Module, Function, [ReplyInfo | Args]) -</pre> + <p>Information is delivered to the receiver through calls + to the callback function + <c>apply(Module, Function, [ReplyInfo | Args])</c>.</p> </item> - </taglist> - <p>In all of the above cases, <c>ReplyInfo</c> has the following - structure: </p> + <p>In all of these cases, <c>ReplyInfo</c> has the following + structure:</p> <pre> {RequestId, saved_to_file} @@ -407,11 +501,10 @@ apply(Module, Function, [ReplyInfo | Args]) {RequestId, Result} {RequestId, stream_start, Headers} {RequestId, stream_start, Headers, HandlerPid} -{RequestId, stream, BinBodyPart} -{RequestId, stream_end, Headers} -</pre> +{RequestId, stream, BinBodyPart} +{RequestId, stream_end, Headers}</pre> - <p>Defaults to the <c>pid()</c> of the process calling the request + <p>Default is the <c>pid</c> of the process calling the request function (<c>self()</c>). </p> <marker id="ipv6_host_with_brackets"></marker> @@ -419,276 +512,178 @@ apply(Module, Function, [ReplyInfo | Args]) <tag><c><![CDATA[ipv6_host_with_brackets]]></c></tag> <item> - <p>When parsing the Host-Port part of an URI with a IPv6 address - with brackets, shall we retain those brackets (<c>true</c>) or - strip them (<c>false</c>). </p> - <p>Defaults to <c>false</c>. </p> + <p>Defines when parsing the Host-Port part of an URI with an IPv6 address + with brackets, if those brackets are to be retained (<c>true</c>) + or stripped (<c>false</c>).</p> + <p>Default is <c>false</c>.</p> </item> </taglist> - - <marker id="cancel_request"></marker> - </desc> - </func> - - <func> - <name>cancel_request(RequestId) -> </name> - <name>cancel_request(RequestId, Profile) -> ok</name> - <fsummary>Cancels an asynchronous HTTP-request.</fsummary> - <type> - <v>RequestId = request_id() - A unique identifier as returned - by request/4</v> - <v>Profile = profile() | pid() (when started <c>stand_alone</c>)</v> - </type> - <desc> - <p>Cancels an asynchronous HTTP-request. Note this does not guarantee - that the request response will not be delivered, as it is asynchronous the - the request may already have been completed when the cancellation arrives. - </p> - - <marker id="set_options"></marker> </desc> </func> + <func> <name>set_options(Options) -> </name> <name>set_options(Options, Profile) -> ok | {error, Reason}</name> <fsummary>Sets options to be used for subsequent requests.</fsummary> <type> <v>Options = [Option]</v> - <v>Option = {proxy, {Proxy, NoProxy}} | - {https_proxy, {Proxy, NoProxy}} | - {max_sessions, MaxSessions} | - {max_keep_alive_length, MaxKeepAlive} | - {keep_alive_timeout, KeepAliveTimeout} | - {max_pipeline_length, MaxPipeline} | - {pipeline_timeout, PipelineTimeout} | - {cookies, CookieMode} | - {ipfamily, IpFamily} | - {ip, IpAddress} | - {port, Port} | - {socket_opts, socket_opts()} | - {verbose, VerboseMode} </v> - + <v>Option = {proxy, {Proxy, NoProxy}}</v> + <v>| {https_proxy, {Proxy, NoProxy}}</v> + <v>| {max_sessions, MaxSessions}</v> + <v>| {max_keep_alive_length, MaxKeepAlive}</v> + <v>| {keep_alive_timeout, KeepAliveTimeout}</v> + <v>| {max_pipeline_length, MaxPipeline}</v> + <v>| {pipeline_timeout, PipelineTimeout}</v> + <v>| {cookies, CookieMode}</v> + <v>| {ipfamily, IpFamily}</v> + <v>| {ip, IpAddress}</v> + <v>| {port, Port}</v> + <v>| {socket_opts, socket_opts()}</v> + <v>| {verbose, VerboseMode}</v> <v>Proxy = {Hostname, Port}</v> - <v>Hostname = string() </v> - <d>ex: "localhost" or "foo.bar.se"</d> + <v>Hostname = string()</v> + <d>Example: "localhost" or "foo.bar.se"</d> <v>Port = integer()</v> - <d>ex: 8080 </d> + <d>Example: 8080</d> <v>NoProxy = [NoProxyDesc]</v> <v>NoProxyDesc = DomainDesc | HostName | IPDesc</v> <v>DomainDesc = "*.Domain"</v> - <d>ex: "*.ericsson.se"</d> + <d>Example: "*.ericsson.se"</d> <v>IpDesc = string()</v> - <d>ex: "134.138" or "[FEDC:BA98" (all IP-addresses starting with 134.138 or FEDC:BA98), "66.35.250.150" or "[2010:836B:4179::836B:4179]" (a complete IP-address).</d> - - <d>proxy defaults to {undefined, []} e.i. no proxy is configured and https_proxy defaults to - the value of proxy.</d> - - <v>MaxSessions = integer() </v> - <d>Default is <c>2</c>. - Maximum number of persistent connections to a host.</d> - <v>MaxKeepAlive = integer() </v> - <d>Default is <c>5</c>. - Maximum number of outstanding requests on the same connection to - a host.</d> - <v>KeepAliveTimeout = integer() </v> - <d>Default is <c>120000</c> (= 2 min). - If a persistent connection is idle longer than the + <d>Example: "134.138" or "[FEDC:BA98" + (all IP addresses starting with 134.138 or FEDC:BA98), + "66.35.250.150" or "[2010:836B:4179::836B:4179]" (a complete IP address). + <c>proxy</c> defaults to <c>{undefined, []}</c>, + that is, no proxy is configured and + <c>https_proxy</c> defaults to the value of <c>proxy</c>.</d> + <v>MaxSessions = integer()</v> + <d>Maximum number of persistent connections to a host. + Default is <c>2</c>.</d> + <v>MaxKeepAlive = integer()</v> + <d>Maximum number of outstanding requests on the same connection to + a host. Default is <c>5</c>.</d> + <v>KeepAliveTimeout = integer()</v> + <d>If a persistent connection is idle longer than the <c>keep_alive_timeout</c> in milliseconds, - the client will close the connection. - The server may also have such a time out but you should - not count on it!</d> - <v>MaxPipeline = integer() </v> - <d>Default is <c>2</c>. - Maximum number of outstanding requests on a pipelined connection - to a host.</d> - <v>PipelineTimeout = integer() </v> - <d>Default is <c>0</c>, - which will result in pipelining not being used. - If a persistent connection is idle longer than the + the client closes the connection. + The server can also have such a time-out but do not take that for granted. + Default is <c>120000</c> (= 2 min).</d> + <v>MaxPipeline = integer()</v> + <d>Maximum number of outstanding requests on a pipelined connection + to a host. Default is <c>2</c>.</d> + <v>PipelineTimeout = integer()</v> + <d>If a persistent connection is idle longer than the <c>pipeline_timeout</c> in milliseconds, - the client will close the connection. </d> - <v>CookieMode = enabled | disabled | verify </v> - <d>Default is <c>disabled</c>. - If Cookies are enabled all valid cookies will automatically be - saved in the client manager's cookie database. - If the option <c>verify</c> is used the function <c>store_cookies/2</c> - has to be called for the cookies to be saved.</d> - <v>IpFamily = inet | inet6 | inet6fb4 </v> - <d>By default <c>inet</c>. - When it is set to <c>inet6fb4</c> you can use both ipv4 and ipv6. - It first tries <c>inet6</c> and if that does not works falls back to <c>inet</c>. - The option is here to provide a workaround for buggy ipv6 stacks to ensure that - ipv4 will always work.</d> - <v>IpAddress = ip_address() </v> - <d>If the host has several network interfaces, this option specifies which one to use. - See <seealso marker="kernel:gen_tcp#connect">gen_tcp:connect/3,4</seealso> for more info. </d> - <v>Port = integer() </v> - <d>Specify which local port number to use. - See <seealso marker="kernel:gen_tcp#connect">gen_tcp:connect/3,4</seealso> for more info. </d> + the client closes the connection. Default is <c>0</c>, + which results in pipelining not being used.</d> + <v>CookieMode = enabled | disabled | verify</v> + <d>If cookies are enabled, all valid cookies are automatically + saved in the cookie database of the client manager. + If option <c>verify</c> is used, function <c>store_cookies/2</c> + has to be called for the cookies to be saved. + Default is <c>disabled</c>.</d> + <v>IpFamily = inet | inet6 </v> + <d>Default is <c>inet</c>.</d> + <v>IpAddress = ip_address()</v> + <d>If the host has several network interfaces, this option specifies + which one to use. + See <seealso marker="kernel:gen_tcp#connect">gen_tcp:connect/3,4</seealso> + for details.</d> + <v>Port = integer()</v> + <d>Local port number to use. + See <seealso marker="kernel:gen_tcp#connect">gen_tcp:connect/3,4</seealso> + for details.</d> <v>socket_opts() = [socket_opt()]</v> <d>The options are appended to the socket options used by the - client. </d> - <d>These are the default values when a new request handler + client. + These are the default values when a new request handler is started (for the initial connect). They are passed directly - to the underlying transport (gen_tcp or ssl) <em>without</em> - verification! </d> - <v>VerboseMode = false | verbose | debug | trace </v> + to the underlying transport (<c>gen_tcp</c> or <c>SSL</c>) + <em>without</em> verification.</d> + <v>VerboseMode = false | verbose | debug | trace</v> <d>Default is <c>false</c>. This option is used to switch on (or off) - different levels of erlang trace on the client. + different levels of Erlang trace on the client. It is a debug feature.</d> - <v>Profile = profile() | pid() (when started <c>stand_alone</c>)</v> + <v>Profile = profile() | pid()</v> + <d>When started <c>stand_alone</c> only the pid can be used.</d> </type> <desc> <p>Sets options to be used for subsequent requests.</p> <note> - <p>If possible the client will keep its connections - alive and use persistent connections - with or without pipeline depending on configuration + <p>If possible, the client keeps its connections + alive and uses persistent connections + with or without pipeline depending on configuration and current circumstances. The HTTP/1.1 specification does not - provide a guideline for how many requests would be - ideal to be sent on a persistent connection, - this very much depends on the - application. Note that a very long queue of requests may cause a - user perceived delay as earlier requests may take a long time - to complete. The HTTP/1.1 specification does suggest a - limit of 2 persistent connections per server, which is the - default value of the <c>max_sessions</c> option. </p> + provide a guideline for how many requests that are + ideal to be sent on a persistent connection. + This depends much on the application.</p> + <p>A long queue of requests can cause a + user-perceived delay, as earlier requests can take a long time + to complete. The HTTP/1.1 specification suggests a + limit of two persistent connections per server, which is the + default value of option <c>max_sessions</c>.</p> </note> <marker id="get_options"></marker> </desc> </func> - - <func> - <name>get_options(OptionItems) -> {ok, Values} | {error, Reason}</name> - <name>get_options(OptionItems, Profile) -> {ok, Values} | {error, Reason}</name> - <fsummary>Gets the currently used options.</fsummary> - <type> - <v>OptionItems = all | [option_item()]</v> - <v>option_item() = proxy | - https_proxy - max_sessions | - keep_alive_timeout | - max_keep_alive_length | - pipeline_timeout | - max_pipeline_length | - cookies | - ipfamily | - ip | - port | - socket_opts | - verbose</v> - <v>Profile = profile() | pid() (when started <c>stand_alone</c>)</v> - <v>Values = [{option_item(), term()}]</v> - <v>Reason = term() </v> - </type> - <desc> - <p>Retrieves the options currently used by the client.</p> - - <marker id="stream_next"></marker> - </desc> - </func> - - <func> - <name>stream_next(Pid) -> ok</name> - <fsummary> Triggers the next message to be streamed, e.i. - same behavior as active once for sockets. - </fsummary> - <type> - <v>Pid = pid() - as received in the stream_start message</v> - </type> - <desc> - <p>Triggers the next message to be streamed, e.i. - same behavior as active once for sockets. </p> - - <marker id="verify_cookies"></marker> - <marker id="store_cookies"></marker> - </desc> - </func> - + <func> <name>store_cookies(SetCookieHeaders, Url) -> </name> <name>store_cookies(SetCookieHeaders, Url, Profile) -> ok | {error, Reason}</name> - <fsummary>Saves the cookies defined in SetCookieHeaders in the client profile's cookie database.</fsummary> + <fsummary>Saves the cookies defined in <c>SetCookieHeaders</c> in the + client profile cookie database.</fsummary> <type> <v>SetCookieHeaders = headers() - where field = "set-cookie"</v> <v>Url = url()</v> - <v>Profile = profile() | pid() (when started <c>stand_alone</c>)</v> - </type> - <desc> - <p>Saves the cookies defined in SetCookieHeaders - in the client profile's cookie database. You need to - call this function if you have set the option <c>cookies</c> - to <c>verify</c>. - If no profile is specified the default profile will be used. </p> - - <marker id="cookie_header"></marker> - </desc> - </func> - - <func> - <name>cookie_header(Url) -> </name> - <name>cookie_header(Url, Profile | Opts) -> header() | {error, Reason}</name> - <name>cookie_header(Url, Opts, Profile) -> header() | {error, Reason}</name> - <fsummary>Returns the cookie header that would be sent when - making a request to Url using the profile <c>Profile</c>.</fsummary> - <type> - <v>Url = url()</v> - <v>Opts = [cookie_header_opt()]</v> - <v>Profile = profile() | pid() (when started <c>stand_alone</c>)</v> - <v>cookie_header_opt() = {ipv6_host_with_brackets, boolean()}</v> + <v>Profile = profile() | pid()</v> + <d>When started <c>stand_alone</c> only the pid can be used.</d> </type> <desc> - <p>Returns the cookie header that would be sent - when making a request to <c>Url</c> using the profile <c>Profile</c>. - If no profile is specified the default profile will be used. </p> - <p>The option <c>ipv6_host_with_bracket</c> deals with how to - parse IPv6 addresses. - See the <c>Options</c> argument of the - <seealso marker="#request2">request/4,5</seealso> for more info. </p> - - <marker id="reset_cookies"></marker> + <p>Saves the cookies defined in <c>SetCookieHeaders</c> + in the client profile cookie database. + Call this function if option <c>cookies</c> is set to <c>verify</c>. + If no profile is specified, the default profile is used.</p> </desc> </func> - <func> - <name>reset_cookies() -> void()</name> - <name>reset_cookies(Profile) -> void()</name> - <fsummary>Reset the cookie database.</fsummary> + <name>stream_next(Pid) -> ok</name> + <fsummary>Triggers the next message to be streamed, that is, + the same behavior as active one for sockets. + </fsummary> <type> - <v>Profile = profile() | pid() (when started <c>stand_alone</c>)</v> + <v>Pid = pid()</v> + <d>As received in the <c>stream_start message</c></d> </type> <desc> - <p>Resets (clears) the cookie database for the specified - <c>Profile</c>. If no profile is specified the default profile - will be used. </p> + <p>Triggers the next message to be streamed, that is, + the same behavior as active ones for sockets.</p> - <marker id="which_cookies"></marker> + <marker id="verify_cookies"></marker> + <marker id="store_cookies"></marker> </desc> </func> - - + <func> <name>which_cookies() -> cookies()</name> <name>which_cookies(Profile) -> cookies()</name> - <fsummary>Dumps out the entire cookie database.</fsummary> + <fsummary>Dumps the entire cookie database.</fsummary> <type> - <v>Profile = profile() | pid() (when started <c>stand_alone</c>)</v> + <v>Profile = profile() | pid()</v> + <d>When started <c>stand_alone</c> only the pid can be used.</d> <v>cookies() = [cookie_stores()]</v> <v>cookie_stores() = {cookies, cookies()} | {session_cookies, cookies()}</v> <v>cookies() = [cookie()]</v> <v>cookie() = term()</v> </type> <desc> - <p>This function produces a list of the entire cookie database. - It is intended for debugging/testing purposes. - If no profile is specified the default profile will be used. </p> - - <marker id="which_sessions"></marker> + <p>Produces a list of the entire cookie database. + Intended for debugging/testing purposes. + If no profile is specified, the default profile is used.</p> </desc> </func> @@ -697,41 +692,29 @@ apply(Module, Function, [ReplyInfo | Args]) <name>which_sessions(Profile) -> session_info()</name> <fsummary>Produces a slightly processed dump of the sessions database.</fsummary> <type> - <v>Profile = profile() | pid() (when started <c>stand_alone</c>)</v> + <v>Profile = profile() | pid()</v> + <d>When started <c>stand_alone</c> only the pid can be used.</d> <v>session_info() = {GoodSessions, BadSessions, NonSessions}</v> <v>GoodSessions = session()</v> <v>BadSessions = tuple()</v> <v>NonSessions = term()</v> </type> <desc> - <p>This function produces a slightly processed dump of the session + <p>Produces a slightly processed dump of the session database. It is intended for debugging. - If no profile is specified the default profile will be used. </p> - - <marker id="info"></marker> + If no profile is specified, the default profile is used.</p> </desc> </func> - <func> - <name>info() -> list()</name> - <name>info(Profile) -> list()</name> - <fsummary>Produces a list of miscelleneous info</fsummary> - <type> - <v>Profile = profile() | pid() (when started <c>stand_alone</c>)</v> - </type> - <desc> - <p>This function produces a list of miscelleneous info. - It is intended for debugging. - If no profile is specified the default profile will be used. </p> - </desc> - </func> + </funcs> <section> <title>SEE ALSO</title> - <p>RFC 2616, <seealso marker="inets">inets(3)</seealso>, - <seealso marker="kernel:gen_tcp">gen_tcp(3)</seealso>, - <seealso marker="ssl:ssl">ssl(3)</seealso> + <p><url href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</url>, + <seealso marker="inets">inets(3)</seealso>, + <seealso marker="kernel:gen_tcp">gen_tcp(3)</seealso>, + <seealso marker="ssl:ssl">ssl(3)</seealso> </p> </section> diff --git a/lib/inets/doc/src/httpd.xml b/lib/inets/doc/src/httpd.xml index 7ea9b9318f..62b92b8356 100644 --- a/lib/inets/doc/src/httpd.xml +++ b/lib/inets/doc/src/httpd.xml @@ -30,192 +30,182 @@ <file>httpd.sgml</file> </header> <module>httpd</module> - <modulesummary>An implementation of an HTTP - 1.1 compliant Web server, as defined in RFC 2616. + <modulesummary> + HTTP server API </modulesummary> <description> - <p>Documents the HTTP server start options, some administrative - functions and also specifies the Erlang Web server callback - API</p> + <p>An implementation of an HTTP 1.1 compliant web server, as defined in + <url href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</url>. + Provides web server start options, administrative functions, and + an Erlang callback API.</p> </description> <section> - <title>COMMON DATA TYPES </title> + <title>DATA TYPES</title> <p>Type definitions that are used more than once in this module:</p> - <p><c>boolean() = true | false </c></p> - <p><c>string() = list of ASCII characters</c></p> - <p><c>path() = string() - representing a file or directory path.</c></p> - <p><c> ip_address() = {N1,N2,N3,N4} % IPv4 + <p><c>boolean() = true | false</c></p> + <p><c>string()</c> = list of ASCII characters</p> + <p><c>path() = string()</c> representing a file or a directory path</p> + <p><c> ip_address() = {N1,N2,N3,N4} % IPv4 | {K1,K2,K3,K4,K5,K6,K7,K8} % IPv6</c></p> - <p><c>hostname() = string() - representing a host ex "foo.bar.com"</c></p> + <p><c>hostname() = string()</c> representing a host, for example, + "foo.bar.com"</p> <p><c>property() = atom()</c></p> </section> <section> - <title>ERLANG HTTP SERVER SERVICE START/STOP </title> - <p>A web server can be configured to start when starting the inets - application or started dynamically in runtime by calling the - Inets application API <c>inets:start(httpd, ServiceConfig)</c>, or + <title>ERLANG HTTP SERVER SERVICE START/STOP</title> + <p>A web server can be configured to start when starting the <c>Inets</c> + application, or dynamically in runtime by calling the + <c>Inets</c> application API <c>inets:start(httpd, ServiceConfig)</c> or <c>inets:start(httpd, ServiceConfig, How)</c>, - see <seealso marker="inets">inets(3)</seealso> Below follows a - description of the available configuration options, also called - properties.</p> + see <seealso marker="inets">inets(3)</seealso>. + The configuration options, also called + properties, are as follows:</p> <marker id="props_file"></marker> - <p><em>File properties</em></p> + <p><em>File Properties</em></p> <p>When the web server is started - at application start time the properties should be fetched from a - configuration file that could consist of a regular erlang property - list, e.i. <c>[{Option, Value}] </c> where <c> Option = property() + at application start time, the properties are to be fetched from a + configuration file that can consist of a regular Erlang property + list, that is, <c>[{Option, Value}]</c>, where <c> Option = property() </c> and <c>Value = term()</c>, followed by a full stop, or for - backwards compatibility an Apache like configuration file. If the - web server is started dynamically at runtime you may still specify - a file but you could also just specify the complete property + backwards compatibility, an Apache-like configuration file. If the + web server is started dynamically at runtime, + a file can still be specified but also the complete property list.</p> <taglist> - <marker id="prop_proplist_file"></marker> - <tag>{proplist_file, path()}</tag> + <tag><marker id="prop_proplist_file"></marker>{proplist_file, path()}</tag> <item> - <p>If this property is defined inets will expect to find - all other properties defined in this file. Note that the + <p>If this property is defined, <c>Inets</c> expects to find + all other properties defined in this file. The file must include all properties listed under mandatory - properties. </p> + properties.</p> </item> - <marker id="prop_file"></marker> - <tag>{file, path()}</tag> + <tag><marker id="prop_file"></marker>{file, path()}</tag> <item> - <p>If this property is defined inets will expect to find all - other properties defined in this file, that uses Apache like - syntax. Note that the file must include all properties listed - under mandatory properties. The Apache like syntax is the property, + <p>If this property is defined, <c>Inets</c> expects to find all + other properties defined in this file, which uses Apache-like + syntax. The file must include all properties listed + under mandatory properties. The Apache-like syntax is the property, written as one word where each new word begins with a capital, - followed by a white-space followed by the value followed by a - new line. Ex: </p> - + followed by a white-space, followed by the value, followed by a + new line.</p> + <p>Example:</p> <code> -{server_root, "/urs/local/www"} -> ServerRoot /usr/local/www - </code> +{server_root, "/urs/local/www"} -> ServerRoot /usr/local/www</code> - <p>With a few exceptions, that are documented + <p>A few exceptions are documented for each property that behaves differently, - and the special case {directory, {path(), PropertyList}} and - {security_directory, {Dir, PropertyList}} that are represented + and the special cases <c>{directory, {path(), PropertyList}}</c> + and <c>{security_directory, {Dir, PropertyList}}</c>, are represented as:</p> <pre> <![CDATA[ <Directory Dir> <Properties handled as described above> </Directory> - ]]> - </pre> + ]]></pre> </item> </taglist> <note> - <p>The properties proplist_file and file are mutually exclusive.</p> + <p>The properties <c>proplist_file</c> and <c>file</c> are mutually exclusive. Also newer properties may not be supported as Apache-like options, this is a legacy feature.</p> </note> <marker id="props_mand"></marker> - <p><em>Mandatory properties</em></p> + <p><em>Mandatory Properties</em></p> <taglist> - <marker id="prop_port"></marker> - <tag>{port, integer()} </tag> + <tag><marker id="prop_port"></marker>{port, integer()} </tag> <item> - <p>The port that the HTTP server shall listen on. + <p>The port that the HTTP server listen to. If zero is specified as port, an arbitrary available port - will be picked and you can use the httpd:info/2 function to find - out which port was picked. </p> + is picked and function <c>httpd:info/2</c> can be used to + determine which port was picked.</p> </item> - <marker id="prop_server_name"></marker> - <tag>{server_name, string()} </tag> + <tag><marker id="prop_server_name"></marker>{server_name, string()}</tag> <item> - <p>The name of your server, normally a fully qualified domain name. </p> + <p>The name of your server, normally a fully qualified domain name.</p> </item> - <marker id="prop_server_root"></marker> - <tag>{server_root, path()} </tag> + <tag><marker id="prop_server_root"></marker>{server_root, path()}</tag> <item> - <p>Defines the server's home directory where log files etc can - be stored. Relative paths specified in other properties refer - to this directory. </p> + <p>Defines the home directory of the server, where log files, and so on, + can be stored. Relative paths specified in other properties refer + to this directory.</p> </item> - <marker id="prop_doc_root"></marker> - <tag>{document_root, path()}</tag> + <tag> <marker id="prop_doc_root"></marker>{document_root, path()}</tag> <item> - Defines the top directory for the documents that - are available on the HTTP server. + <p>Defines the top directory for the documents that + are available on the HTTP server.</p> </item> </taglist> <marker id="props_comm"></marker> - <p><em>Communication properties</em> </p> + <p><em>Communication Properties</em></p> <taglist> - <marker id="prop_bind_address"></marker> - <tag>{bind_address, ip_address() | hostname() | any} </tag> + <tag><marker id="prop_bind_address"></marker>{bind_address, ip_address() | hostname() | any}</tag> <item> - <p>Defaults to <c>any</c>. Note that <c>any</c> is denoted <em>*</em> - in the apache like configuration file. </p> + <p>Default is <c>any</c>. <c>any</c> is denoted <em>*</em> + in the Apache-like configuration file.</p> </item> - <marker id="profile"></marker> - <tag>{profile, atom()}</tag> + <tag><marker id="profile"></marker>{profile, atom()}</tag> <item> - <p>Used together with <seealso marker="prop_bind_address"><c>bind_address</c></seealso> - and <seealso marker="prop_port"><c>port</c></seealso> to uniquely identify + <p>Used together with <seealso marker="#prop_bind_address"><c>bind_address</c></seealso> + and <seealso marker="#prop_port"><c>port</c></seealso> to uniquely identify a HTTP server. This can be useful in a virtualized environment, where there can be more that one server that has the same bind_address and port. If this property is not explicitly set, it is assumed that the - <seealso marker="prop_bind_address"><c>bind_address</c></seealso> and - <seealso marker="prop_port"><c>port</c></seealso>uniquely identifies the HTTP server. + <seealso marker="#prop_bind_address"><c>bind_address</c></seealso> and + <seealso marker="#prop_port"><c>port</c></seealso>uniquely identifies the HTTP server. </p> </item> - <marker id="prop_socket_type"></marker> - <tag>{socket_type, ip_comm | {essl, Config::proplist()}}</tag> + <tag><marker id="prop_socket_type"></marker>{socket_type, ip_comm | {ip_comm, Config::proplist()} | {essl, Config::proplist()}}</tag> <item> - <p> For ssl configuration options see <seealso marker="ssl:ssl#listen-2">ssl:listen/2</seealso> </p> - <p>Defaults to <c>ip_comm</c>. </p> + <p>For <c>ip_comm</c> configuration options, see + <seealso marker="kernel:gen_tcp#listen-2">gen_tcp:listen/2</seealso>, some options + that are used internally by httpd can not be set.</p> + <p>For <c>SSL</c> configuration options, see + <seealso marker="ssl:ssl#listen-2">ssl:listen/2</seealso>.</p> + <p>Default is <c>ip_comm</c>.</p> </item> - <marker id="prop_ipfamily"></marker> - <tag>{ipfamily, inet | inet6 | inet6fb4}</tag> + <tag><marker id="prop_ipfamily"></marker>{ipfamily, inet | inet6}</tag> <item> - <p>Defaults to <c>inet6fb4. </c> </p> - <p>Note that this option is only used when the option - <c>socket_type</c> has the value <c>ip_comm</c>. </p> + <p>Default is <c>inet</c>, legacy option <c>inet6fb4</c> no longer makes sense and will be translated + to inet.</p> </item> - - <marker id="prop_minimum_bytes_per_second"></marker> - <tag>{minimum_bytes_per_second, integer()}</tag> + <tag><marker id="prop_minimum_bytes_per_second"></marker>{minimum_bytes_per_second, integer()}</tag> <item> - <p>If given, sets a minimum bytes per second value for connections.</p> - <p>If the value is not reached, the socket will close for that connection.</p> - <p>The option is good for reducing the risk of "slow dos" attacks.</p> + <p>If given, sets a minimum of bytes per second value for connections.</p> + <p>If the value is unreached, the socket closes for that connection.</p> + <p>The option is good for reducing the risk of "slow DoS" attacks.</p> </item> </taglist> <marker id="props_api_modules"></marker> - <p><em>Erlang Web server API modules</em> </p> + <p><em>Erlang Web Server API Modules</em> </p> <taglist> - <marker id="prop_modules"></marker> - <tag>{modules, [atom()]} </tag> + <tag><marker id="prop_modules"></marker>{modules, [atom()]} </tag> <item> - <p>Defines which modules the HTTP server will use to handle - requests. Defaults to: <c>[mod_alias, mod_auth, mod_esi, + <p>Defines which modules the HTTP server uses when handling + requests. Default is <c>[mod_alias, mod_auth, mod_esi, mod_actions, mod_cgi, mod_dir, mod_get, mod_head, mod_log, - mod_disk_log] </c> - Note that some mod-modules are dependent on - others, so the order can not be entirely arbitrary. See the - <seealso marker="http_server"> Inets Web server Modules in the - Users guide</seealso> for more information. </p> + mod_disk_log]</c>. + Notice that some <c>mod</c>-modules are dependent on + others, so the order cannot be entirely arbitrary. See the + <seealso marker="http_server">Inets Web Server Modules</seealso> in the + User's Guide for details.</p> </item> </taglist> @@ -223,739 +213,686 @@ <p><em>Limit properties</em> </p> <taglist> - <marker id="prop_customize"></marker> - <tag>{customize, atom()}</tag> + <tag><marker id="prop_customize"></marker>{customize, atom()}</tag> <item> <p>A callback module to customize the inets HTTP servers behaviour - see <seealso marker="http_custom_api"> httpd_custom_api</seealso> </p> + see <seealso marker="httpd_custom_api"> httpd_custom_api</seealso> </p> </item> - <marker id="prop_disable_chunked_encoding"></marker> - <tag>{disable_chunked_transfer_encoding_send, boolean()}</tag> + <tag><marker id="prop_disable_chunked_encoding"></marker>{disable_chunked_transfer_encoding_send, boolean()}</tag> <item> - <p>This property allows you to disable chunked - transfer-encoding when sending a response to a HTTP/1.1 - client, by default this is false. </p> + <p>Allows you to disable chunked + transfer-encoding when sending a response to an HTTP/1.1 + client. Default is <c>false</c>.</p> </item> - <marker id="prop_keep_alive"></marker> - <tag>{keep_alive, boolean()}</tag> + <tag><marker id="prop_keep_alive"></marker>{keep_alive, boolean()}</tag> <item> - <p>Instructs the server whether or not to use persistent + <p>Instructs the server whether to use persistent connections when the client claims to be HTTP/1.1 - compliant, default is true. </p> + compliant. Default is <c>true</c>.</p> </item> - <marker id="prop_keep_alive_timeout"></marker> - <tag>{keep_alive_timeout, integer()}</tag> + <tag><marker id="prop_keep_alive_timeout"></marker>{keep_alive_timeout, integer()}</tag> <item> - <p>The number of seconds the server will wait for a + <p>The number of seconds the server waits for a subsequent request from the client before closing the - connection. Default is 150. </p> + connection. Default is <c>150</c>.</p> </item> - <marker id="prop_max_body_size"></marker> - <tag>{max_body_size, integer()}</tag> + <tag><marker id="prop_max_body_size"></marker>{max_body_size, integer()}</tag> <item> - <p>Limits the size of the message body of HTTP request. - By the default there is no limit. </p> + <p>Limits the size of the message body of an HTTP request. + Default is no limit.</p> </item> - <marker id="prop_max_clients"></marker> - <tag>{max_clients, integer()}</tag> + <tag><marker id="prop_max_clients"></marker>{max_clients, integer()}</tag> <item> <p>Limits the number of simultaneous requests that can be - supported. Defaults to 150. </p> + supported. Default is <c>150</c>.</p> </item> - <marker id="prop_max_header_size"></marker> - <tag>{max_header_size, integer()}</tag> + <tag><marker id="prop_max_header_size"></marker>{max_header_size, integer()}</tag> <item> - <p>Limits the size of the message header of HTTP request. - Defaults to 10240. </p> + <p>Limits the size of the message header of an HTTP request. + Default is <c>10240</c>.</p> </item> - <marker id="prop_max_content_length"></marker> - <tag>{max_content_length, integer()}</tag> + <tag><marker id="prop_max_content_length"></marker>{max_content_length, integer()}</tag> <item> - <p>Maximum Content-Length in an incoming request, in bytes. Requests - with content larger than this are answered with Status 413. - Defaults to 100000000 (100 MB). + <p>Maximum content-length in an incoming request, in bytes. Requests + with content larger than this are answered with status 413. + Default is <c>100000000</c> (100 MB). </p> </item> - <marker id="prop_max_uri"></marker> - <tag>{max_uri_size, integer()}</tag> + <tag><marker id="prop_max_uri"></marker>{max_uri_size, integer()}</tag> <item> - <p>Limits the size of the HTTP request URI. By - default there is no limit. </p> + <p>Limits the size of the HTTP request URI. + Default is no limit.</p> </item> - <marker id="prop_max_keep_alive_req"></marker> - <tag>{max_keep_alive_request, integer()}</tag> + <tag><marker id="prop_max_keep_alive_req"></marker>{max_keep_alive_request, integer()}</tag> <item> - <p>The number of request that a client can do on one + <p>The number of requests that a client can do on one connection. When the server has responded to the number of - requests defined by max_keep_alive_requests the server close the - connection. The server will close it even if there are queued - request. Defaults to no limit. </p> + requests defined by <c>max_keep_alive_requests</c>, the server + closes the connection. The server closes it even if there are + queued request. Default is no limit.</p> </item> </taglist> <marker id="props_admin"></marker> - <p><em>Administrative properties</em></p> + <p><em>Administrative Properties</em></p> <taglist> - <marker id="prop_mime_types"></marker> - <tag>{mime_types, [{MimeType, Extension}] | path()}</tag> + <tag><marker id="prop_mime_types"></marker>{mime_types, [{MimeType, Extension}] | path()}</tag> <item> - <p>Where MimeType = string() and Extension = string(). + <p><c>MimeType = string()</c> and <c>Extension = string()</c>. Files delivered to the client are MIME typed according to RFC 1590. File suffixes are mapped to MIME types before file delivery. The mapping between file suffixes and MIME types can be specified - as an Apache like file as well as directly in the property list. Such - a file may look like:</p> + as an Apache-like file or directly in the property list. Such + a file can look like the follwoing:</p> <pre> # MIME type Extension text/html html htm -text/plain asc txt - </pre> +text/plain asc txt</pre> - <p>Defaults to [{"html","text/html"},{"htm","text/html"}]</p> + <p>Default is [{"html","text/html"},{"htm","text/html"}].</p> </item> - <marker id="prop_mime_type"></marker> - <tag>{mime_type, string()}</tag> + <tag><marker id="prop_mime_type"></marker>{mime_type, string()}</tag> <item> - <p>When the server is asked to provide a document type which - cannot be determined by the MIME Type Settings, the server will - use this default type. </p> + <p>When the server is asked to provide a document type that + cannot be determined by the MIME Type Settings, the server + uses this default type.</p> </item> - <marker id="prop_server_admin"></marker> - <tag>{server_admin, string()}</tag> + <tag><marker id="prop_server_admin"></marker>{server_admin, string()}</tag> <item> - <p>ServerAdmin defines the email-address of the server - administrator, to be included in any error messages returned by - the server. </p> + <p>Defines the email-address of the server + administrator to be included in any error messages returned by + the server.</p> </item> - <marker id="prop_server_tokens"></marker> - <tag>{server_tokens, none|prod|major|minor|minimal|os|full|{private, string()}}</tag> + <tag><marker id="prop_server_tokens"></marker>{server_tokens, none|prod|major|minor|minimal|os|full|{private, string()}}</tag> <item> - <p>ServerTokens defines how the value of the server header - should look. </p> - <p>Example: Assuming the version of inets is 5.8.1, - here is what the server header string could look like for - the different values of server-tokens: </p> - <pre> -none "" % A Server: header will not be generated -prod "inets" -major "inets/5" -minor "inets/5.8" -minimal "inets/5.8.1" -os "inets/5.8.1 (unix)" -full "inets/5.8.1 (unix/linux) OTP/R15B" -{private, "foo/bar"} "foo/bar" - </pre> - <p>By default, the value is as before, which is <c>minimal</c>. </p> - </item> - - <marker id="prop_log_format"></marker> - <tag>{log_format, common | combined}</tag> + <p>Defines the look of the value of the server header.</p> + <p>Example: Assuming the version of <c>Inets</c> is 5.8.1, + the server header string can look as follows for + the different values of server-tokens:</p> + <taglist> + <tag><c>none</c></tag> + <item><p>"" % A Server: header will not be generated</p></item> + <tag><c>prod</c></tag> + <item><p>"inets"</p></item> + <tag><c>major</c></tag> + <item><p>"inets/5"</p></item> + <tag><c>minor</c></tag> + <item><p>"inets/5.8"</p></item> + <tag><c>minimal</c></tag> + <item><p>"inets/5.8.1"</p></item> + <tag><c>os</c></tag> + <item><p>"inets/5.8.1 (unix)"</p></item> + <tag><c>full</c></tag> + <item><p>"inets/5.8.1 (unix/linux) OTP/R15B"</p></item> + <tag><c>{private, "foo/bar"}</c></tag> + <item><p>"foo/bar"</p></item> + </taglist> + <p>By default, the value is as before, that is, <c>minimal</c>.</p> + </item> + + <tag><marker id="prop_log_format"></marker>{log_format, common | combined}</tag> <item> - <p>Defines if access logs should be written according to the common - log format or to the extended common log format. - The <c>common</c> format is one line that looks like this: - <c>remotehost rfc931 authuser [date] "request" status bytes</c></p> - - <pre> -remotehost - Remote -rfc931 - The client's remote username (RFC 931). -authuser - The username with which the user authenticated - himself. -[date] - Date and time of the request (RFC 1123). -"request" - The request line exactly as it came from the client - (RFC 1945). -status - The HTTP status code returned to the client - (RFC 1945). -bytes - The content-length of the document transferred. - </pre> - - <p>The <c>combined</c> format is on line that look like this: + <p>Defines if access logs are to be written according to the <c>common</c> + log format or the extended common log format. + The <c>common</c> format is one line looking like this: + <c>remotehost rfc931 authuser [date] "request" status bytes</c>.</p> + <p>Here:</p> + <taglist> + <tag><c>remotehost</c></tag> + <item>Remote.</item> + <tag><c>rfc931</c></tag> + <item>The remote username of the client (<url href="http://www.ietf.org/rfc/rfc931.txt">RFC 931</url>).</item> + <tag><c>authuser</c></tag> + <item>The username used for authentication.</item> + <tag><c>[date]</c></tag> + <item>Date and time of the request (<url href="http://www.ietf.org/rfc/rfc1123.txt">RFC 1123</url>).</item> + <tag><c>"request"</c></tag> + <item>The request line as it came from the client (<url href="http://www.ietf.org/rfc/rfc1945.txt">RFC 1945</url>).</item> + <tag><c>status</c></tag> + <item>The HTTP status code returned to the client (<url href="http://www.ietf.org/rfc/rfc1945.txt">RFC 1945</url>).</item> + <tag><c>bytes</c></tag> + <item>The content-length of the document transferred.</item> + </taglist> + + <p>The <c>combined</c> format is one line looking like this: <c>remotehost rfc931 authuser [date] "request" status bytes "referer" "user_agent" </c></p> + <p>In addition to the earlier:</p> + <taglist> + <tag><c>"referer"</c></tag> + <item>The URL the client was on before + requesting the URL (if it could not be determined, + a minus sign is placed in this field).</item> + <tag><c>"user_agent"</c></tag> + <item>The software the client claims to be using (if it + could not be determined, a minus sign is placed in + this field).</item> + </taglist> - <pre> -"referer" - The url the client was on before - requesting your url. (If it could not be determined - a minus sign will be placed in this field) -"user_agent" - The software the client claims to be using. (If it - could not be determined a minus sign will be placed in - this field) - </pre> - - <p>This affects the access logs written by mod_log and mod_disk_log. - </p> - + <p>This affects the access logs written by <c>mod_log</c> and + <c>mod_disk_log</c>. + </p> </item> - <marker id="prop_elog_format"></marker> - <tag>{error_log_format, pretty | compact}</tag> + <tag><marker id="prop_elog_format"></marker>{error_log_format, pretty | compact}</tag> <item> - <p>Defaults to pretty. If the error log is meant to be read - directly by a human <c>pretty</c> will be the best - option. <c>pretty</c> has the format corresponding to: - </p> + <p>Default is <c>pretty</c>. If the error log is meant to be read + directly by a human, <c>pretty</c> is the best option.</p> + <p><c>pretty</c> has a format corresponding to:</p> - <code>io:format("[~s] ~s, reason: ~n ~p ~n~n", [Date, Msg, Reason]). - </code> + <code>io:format("[~s] ~s, reason: ~n ~p ~n~n", [Date, Msg, Reason]).</code> - <p><c>compact</c> has the format corresponding to:</p> + <p><c>compact</c> has a format corresponding to:</p> - <code>io:format("[~s] ~s, reason: ~w ~n", [Date, Msg, Reason]). - </code> + <code>io:format("[~s] ~s, reason: ~w ~n", [Date, Msg, Reason]).</code> - <p>This affects the error logs written by mod_log and mod_disk_log. + <p>This affects the error logs written by <c>mod_log</c> and + <c>mod_disk_log</c>. </p> </item> </taglist> <marker id="props_alias"></marker> - <p><em>URL aliasing properties - requires mod_alias</em></p> + <p><em>URL Aliasing Properties - Requires mod_alias</em></p> <taglist> - <marker id="prop_alias"></marker> - <tag>{alias, {Alias, RealName}}</tag> + <tag><marker id="prop_alias"></marker>{alias, {Alias, RealName}}</tag> <item> - <p>Where Alias = string() and RealName = string(). - The Alias property allows documents to be stored in the local file - system instead of the document_root location. URLs with a path that - begins with url-path is mapped to local files that begins with - directory-filename, for example: + <p><c>Alias = string()</c> and <c>RealName = string()</c>. + <c>alias</c> allows documents to be stored in the local file + system instead of the <c>document_root</c> location. URLs with a path + beginning with url-path is mapped to local files beginning with + directory-filename, for example:</p> <code>{alias, {"/image", "/ftp/pub/image"}}</code> - and an access to http://your.server.org/image/foo.gif would refer to - the file /ftp/pub/image/foo.gif. </p> + <p>Access to http://your.server.org/image/foo.gif would refer to + the file /ftp/pub/image/foo.gif.</p> </item> - <marker id="prop_re_write"></marker> - <tag>{re_write, {Re, Replacement}}</tag> + <tag><marker id="prop_re_write"></marker>{re_write, {Re, Replacement}}</tag> <item> - <p>Where Re = string() and Replacement = string(). - The ReWrite property allows documents to be stored in the local file - system instead of the document_root location. URLs are rewritten - by re:replace/3 to produce a path in the local filesystem. - For example: + <p><c>Re = string()</c> and <c>Replacement = string()</c>. + <c>re_write</c> allows documents to be stored in the local file + system instead of the <c>document_root</c> location. URLs are rewritten + by <c>re:replace/3</c> to produce a path in the local file-system, + for example:</p> <code>{re_write, {"^/[~]([^/]+)(.*)$", "/home/\\1/public\\2"}}</code> - and an access to http://your.server.org/~bob/foo.gif would refer to + <p>Access to http://your.server.org/~bob/foo.gif would refer to the file /home/bob/public/foo.gif. - In an Apache like configuration file the Re is separated - from Replacement with one single space, and as expected - backslashes do not need to be backslash escaped so the - same example would become: + In an Apache-like configuration file, <c>Re</c> is separated + from <c>Replacement</c> with one single space, and as expected + backslashes do not need to be backslash escaped, the + same example would become:</p> <code>ReWrite ^/[~]([^/]+)(.*)$ /home/\1/public\2</code> - 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="stdlib:re">re(3)</seealso>. </p> + <p>Beware of trailing space in <c>Replacement</c> to be used. + If you must have a space in <c>Re</c>, use, for example, the character + encoding <c>\040</c>, see + <seealso marker="stdlib:re">re(3)</seealso>.</p> </item> - <marker id="prop_dir_idx"></marker> - <tag>{directory_index, [string()]}</tag> + <tag><marker id="prop_dir_idx"></marker>{directory_index, [string()]}</tag> <item> - <p>DirectoryIndex specifies a list of resources to look for - if a client requests a directory using a / at the end of the - directory name. file depicts the name of a file in the - directory. Several files may be given, in which case the server - will return the first it finds, for example: + <p><c>directory_index</c> specifies a list of resources to look for + if a client requests a directory using a <c>/</c> at the end of the + directory name. <c>file</c> depicts the name of a file in the + directory. Several files can be given, in which case the server + returns the first it finds, for example:</p> <code>{directory_index, ["index.hml", "welcome.html"]}</code> - and access to http://your.server.org/docs/ would return + <p>Access to http://your.server.org/docs/ would return http://your.server.org/docs/index.html or - http://your.server.org/docs/welcome.html if index.html do not - exist. </p> + http://your.server.org/docs/welcome.html if index.html does not + exist.</p> </item> </taglist> <marker id="props_cgi"></marker> - <p><em>CGI properties - requires mod_cgi</em></p> + <p><em>CGI Properties - Requires mod_cgi</em></p> <taglist> - <marker id="prop_script_alias"></marker> - <tag>{script_alias, {Alias, RealName}}</tag> + <tag><marker id="prop_script_alias"></marker>{script_alias, {Alias, RealName}}</tag> <item> - <p>Where Alias = string() and RealName = string(). - Has the same behavior as the Alias property, except that - it also marks the target directory as containing CGI + <p><c>Alias = string()</c> and <c>RealName = string()</c>. + Have the same behavior as property <c>alias</c>, except that + they also mark the target directory as containing CGI scripts. URLs with a path beginning with url-path are mapped to - scripts beginning with directory-filename, for example: + scripts beginning with directory-filename, for example:</p> <code>{script_alias, {"/cgi-bin/", "/web/cgi-bin/"}}</code> - and an access to http://your.server.org/cgi-bin/foo would cause - the server to run the script /web/cgi-bin/foo. </p> + <p>Access to http://your.server.org/cgi-bin/foo would cause + the server to run the script /web/cgi-bin/foo.</p> </item> - <marker id="prop_script_re_write"></marker> - <tag>{script_re_write, {Re, Replacement}}</tag> + <tag><marker id="prop_script_re_write"></marker>{script_re_write, {Re, Replacement}}</tag> <item> - <p>Where Re = string() and Replacement = string(). - Has the same behavior as the ReWrite property, except that - it also marks the target directory as containing CGI + <p><c>Re = string()</c> and <c>Replacement = string()</c>. + Have the same behavior as property <c>re_write</c>, except that + they also mark the target directory as containing CGI scripts. URLs with a path beginning with url-path are mapped to - scripts beginning with directory-filename, for example: + scripts beginning with directory-filename, for example:</p> <code>{script_re_write, {"^/cgi-bin/(\\d+)/", "/web/\\1/cgi-bin/"}}</code> - and an access to http://your.server.org/cgi-bin/17/foo would cause - the server to run the script /web/17/cgi-bin/foo. </p> + <p>Access to http://your.server.org/cgi-bin/17/foo would cause + the server to run the script /web/17/cgi-bin/foo.</p> </item> - <marker id="prop_script_nocache"></marker> - <tag>{script_nocache, boolean()}</tag> + <tag><marker id="prop_script_nocache"></marker>{script_nocache, boolean()}</tag> <item> - <p>If ScriptNoCache is set to true the HTTP server will by - default add the header fields necessary to prevent proxies from - caching the page. Generally this is something you want. Defaults - to false. </p> + <p>If <c>script_nocache</c> is set to <c>true</c>, the HTTP server by + default adds the header fields necessary to prevent proxies from + caching the page. Generally this is preferred. + Default to <c>false</c>.</p> </item> - <marker id="prop_script_timeout"></marker> - <tag>{script_timeout, integer()}</tag> + <tag><marker id="prop_script_timeout"></marker>{script_timeout, integer()}</tag> <item> - <p>The time in seconds the web server will wait between each - chunk of data from the script. If the CGI-script not delivers - any data before the timeout the connection to the client will be - closed. Defaults to 15. </p> + <p>The time in seconds the web server waits between each + chunk of data from the script. If the CGI script does not deliver + any data before the timeout, the connection to the client is + closed. Default is <c>15</c>.</p> </item> - <marker id="prop_action"></marker> - <tag>{action, {MimeType, CgiScript}} - requires mod_action</tag> + <tag><marker id="prop_action"></marker>{action, {MimeType, CgiScript}} - requires mod_action</tag> <item> - <p>Where MimeType = string() and CgiScript = string(). - Action adds an action, which will activate a cgi-script - whenever a file of a certain mime-type is requested. It + <p><c>MimeType = string()</c> and <c>CgiScript = string()</c>. + <c>action</c> adds an action activating a CGI script + whenever a file of a certain MIME type is requested. It propagates the URL and file path of the requested document using the standard CGI PATH_INFO and PATH_TRANSLATED environment - variables. + variables.</p> + <p>Example:</p> <code>{action, {"text/plain", "/cgi-bin/log_and_deliver_text"}}</code> - </p> </item> - <marker id="prop_script"></marker> - <tag>{script, {Method, CgiScript}} - requires mod_action</tag> + <tag><marker id="prop_script"></marker>{script, {Method, CgiScript}} - requires mod_action</tag> <item> - <p>Where Method = string() and CgiScript = string(). - Script adds an action, which will activate a cgi-script + <p><c>Method = string()</c> and <c>CgiScript = string()</c>. + <c>script</c> adds an action activating a CGI script whenever a file is requested using a certain HTTP method. The - method is either GET or POST as defined in RFC 1945. It + method is either GET or POST, as defined in <url href="http://www.ietf.org/rfc/rfc1945.txt">RFC 1945</url>. It propagates the URL and file path of the requested document using the standard CGI PATH_INFO and PATH_TRANSLATED environment - variables. + variables.</p> + <p>Example:</p> <code>{script, {"PUT", "/cgi-bin/put"}}</code> - </p> </item> </taglist> <marker id="props_esi"></marker> - <p><em>ESI properties - requires mod_esi</em></p> + <p><em>ESI Properties - Requires mod_esi</em></p> <taglist> - <marker id="prop_esi_alias"></marker> - <tag>{erl_script_alias, {URLPath, [AllowedModule]}}</tag> + <tag><marker id="prop_esi_alias"></marker>{erl_script_alias, {URLPath, [AllowedModule]}}</tag> <item> - <p>Where URLPath = string() and AllowedModule = atom(). - erl_script_alias marks all URLs matching url-path as erl + <p><c>URLPath = string()</c> and <c>AllowedModule = atom()</c>. + <c>erl_script_alias</c> marks all URLs matching url-path as erl scheme scripts. A matching URL is mapped into a specific module - and function. For example: + and function, for example:</p> - <code>{erl_script_alias, {"/cgi-bin/example", [httpd_example]}} - </code> + <code>{erl_script_alias, {"/cgi-bin/example", [httpd_example]}}</code> - and a request to + <p>A request to http://your.server.org/cgi-bin/example/httpd_example:yahoo - would refer to httpd_example:yahoo/3 or, if that did not exist, + would refer to httpd_example:yahoo/3 or, if that does not exist, httpd_example:yahoo/2 and http://your.server.org/cgi-bin/example/other:yahoo would - not be allowed to execute. </p> + not be allowed to execute.</p> </item> - <marker id="prop_esi_nocache"></marker> - <tag>{erl_script_nocache, boolean()}</tag> + <tag><marker id="prop_esi_nocache"></marker>{erl_script_nocache, boolean()}</tag> <item> - <p>If erl_script_nocache is set to true the server will add - http header fields that prevents proxies from caching the - page. This is generally a good idea for dynamic content, since - the content often vary between each request. - Defaults to false. </p> + <p>If <c>erl_script_nocache</c> is set to <c>true</c>, the server adds + HTTP header fields preventing proxies from caching the + page. This is generally a good idea for dynamic content, as + the content often varies between each request. + Default is <c>false</c>.</p> </item> - <marker id="prop_esi_timeout"></marker> - <tag>{erl_script_timeout, integer()}</tag> + <tag><marker id="prop_esi_timeout"></marker>{erl_script_timeout, integer()}</tag> <item> - <p>If erl_script_timeout sets the time in seconds the server will - wait between each chunk of data to be delivered through - mod_esi:deliver/2. Defaults to 15. This is only relevant - for scripts that uses the erl scheme. </p> + <p>If <c>erl_script_timeout</c> sets the time in seconds the server + waits between each chunk of data to be delivered through + <c>mod_esi:deliver/2</c>. Default is <c>15</c>. This is only relevant + for scripts that use the erl scheme.</p> </item> - <marker id="prop_esi_timeout"></marker> - <tag>{eval_script_alias, {URLPath, [AllowedModule]}}</tag> + <tag><marker id="prop_esi_timeout"></marker>{eval_script_alias, {URLPath, [AllowedModule]}}</tag> <item> - <p>Where URLPath = string() and AllowedModule = atom(). - Same as erl_script_alias but for scripts - using the eval scheme. Note that this is only supported - for backwards compatibility. The eval scheme is deprecated. </p> + <p><c>URLPath = string()</c> and <c>AllowedModule = atom()</c>. + Same as <c>erl_script_alias</c> but for scripts + using the eval scheme. This is only supported + for backwards compatibility. The eval scheme is deprecated.</p> </item> </taglist> <marker id="props_log"></marker> - <p><em>Log properties - requires mod_log</em></p> + <p><em>Log Properties - Requires mod_log</em></p> <taglist> - <marker id="prop_elog"></marker> - <tag>{error_log, path()}</tag> + <tag><marker id="prop_elog"></marker>{error_log, path()}</tag> <item> <p>Defines the filename of the error log file to be used to log - server errors. If the filename does not begin with a slash (/) - it is assumed to be relative to the server_root. </p> + server errors. If the filename does not begin with a slash (/), + it is assumed to be relative to the <c>server_root</c>.</p> </item> - <marker id="prop_slog"></marker> - <tag>{security_log, path()}</tag> + <tag><marker id="prop_slog"></marker>{security_log, path()}</tag> <item> <p>Defines the filename of the access log file to be used to log security events. If the filename does not begin with a slash - (/) it is assumed to be relative to the server_root. </p> + (/), it is assumed to be relative to the <c>server_root</c>.</p> </item> - <marker id="prop_tlog"></marker> - <tag>{transfer_log, path()}</tag> + <tag><marker id="prop_tlog"></marker>{transfer_log, path()}</tag> <item> <p>Defines the filename of the access log file to be used to log incoming requests. If the filename does not begin with a - slash (/) it is assumed to be relative to the server_root. </p> + slash (/), it is assumed to be relative to the <c>server_root</c>.</p> </item> </taglist> <marker id="props_dlog"></marker> - <p><em>Disk Log properties - requires mod_disk_log</em></p> + <p><em>Disk Log Properties - Requires mod_disk_log</em></p> <taglist> - <marker id="prop_dlog_format"></marker> - <tag>{disk_log_format, internal | external}</tag> + <tag><marker id="prop_dlog_format"></marker>{disk_log_format, internal | external}</tag> <item> - <p>Defines the file-format of the log files see disk_log for - more information. If the internal file-format is used, the - logfile will be repaired after a crash. When a log file is - repaired data might get lost. When the external file-format is - used httpd will not start if the log file is broken. Defaults to - external. </p> + <p>Defines the file format of the log files. See <c>disk_log</c> for + details. If the internal file format is used, the + log file is repaired after a crash. When a log file is + repaired, data can disappear. When the external file format is + used, <c>httpd</c> does not start if the log file is broken. Default is + <c>external</c>.</p> </item> - <marker id="prop_edlog"></marker> - <tag>{error_disk_log, path()}</tag> + <tag><marker id="prop_edlog"></marker>{error_disk_log, path()}</tag> <item> - <p>Defines the filename of the (disk_log(3)) error log file + <p>Defines the filename of the (<c>disk_log(3)</c>) error log file to be used to log server errors. If the filename does not begin - with a slash (/) it is assumed to be relative to the server_root. </p> + with a slash (/), it is assumed to be relative to the <c>server_root</c>.</p> </item> - <marker id="prop_edlog_size"></marker> - <tag>{error_disk_log_size, {MaxBytes, MaxFiles}}</tag> + <tag><marker id="prop_edlog_size"></marker>{error_disk_log_size, {MaxBytes, MaxFiles}}</tag> <item> - <p>Where MaxBytes = integer() and MaxFiles = integer(). - Defines the properties of the (disk_log(3)) error log - file. The disk_log(3) error log file is of type wrap log and - max-bytes will be written to each file and max-files will be - used before the first file is truncated and reused. </p> + <p><c>MaxBytes = integer()</c> and <c>MaxFiles = integer()</c>. + Defines the properties of the (<c>disk_log(3)</c>) error log + file. This file is of type wrap log and + max bytes is written to each file and max files is + used before the first file is truncated and reused.</p> </item> - <marker id="prop_sdlog"></marker> - <tag>{security_disk_log, path()}</tag> + <tag><marker id="prop_sdlog"></marker>{security_disk_log, path()}</tag> <item> - <p>Defines the filename of the (disk_log(3)) access log file - which logs incoming security events i.e authenticated - requests. If the filename does not begin with a slash (/) it - is assumed to be relative to the server_root. </p> + <p>Defines the filename of the (<c>disk_log(3)</c>) access log file + logging incoming security events, that is, authenticated + requests. If the filename does not begin with a slash (/), it + is assumed to be relative to the <c>server_root</c>.</p> </item> - <marker id="prop_sdlog_size"></marker> - <tag>{security_disk_log_size, {MaxBytes, MaxFiles}}</tag> + <tag><marker id="prop_sdlog_size"></marker>{security_disk_log_size, {MaxBytes, MaxFiles}}</tag> <item> - <p>Where MaxBytes = integer() and MaxFiles = integer(). - Defines the properties of the disk_log(3) access log - file. The disk_log(3) access log file is of type wrap log and - max-bytes will be written to each file and max-files will be - used before the first file is truncated and reused. </p> + <p><c>MaxBytes = integer()</c> and <c>MaxFiles = integer()</c>. + Defines the properties of the <c>disk_log(3)</c> access log + file. This file is of type wrap log and + max bytes is written to each file and max files is + used before the first file is truncated and reused.</p> </item> - <marker id="prop_tdlog"></marker> - <tag>{transfer_disk_log, path()}</tag> + <tag><marker id="prop_tdlog"></marker>{transfer_disk_log, path()}</tag> <item> - <p>Defines the filename of the (disk_log(3)) access log file - which logs incoming requests. If the filename does not begin - with a slash (/) it is assumed to be relative to the - server_root. </p> + <p>Defines the filename of the (<c>disk_log(3)</c>) access log file + logging incoming requests. If the filename does not begin + with a slash (/), it is assumed to be relative to the + <c>server_root</c>.</p> </item> - <marker id="prop_tdlog_size"></marker> - <tag>{transfer_disk_log_size, {MaxBytes, MaxFiles}}</tag> + <tag><marker id="prop_tdlog_size"></marker>{transfer_disk_log_size, {MaxBytes, MaxFiles}}</tag> <item> - <p>Where MaxBytes = integer() and MaxFiles = integer(). - Defines the properties of the disk_log(3) access log - file. The disk_log(3) access log file is of type wrap log and - max-bytes will be written to each file and max-files will be - used before the first file is truncated and reused. </p> + <p><c>MaxBytes = integer()</c> and <c>MaxFiles = integer()</c>. + Defines the properties of the <c>disk_log(3)</c> access log + file. This file is of type wrap log and + max bytes is written to each file and max files is + used before the first file is truncated and reused.</p> </item> </taglist> <marker id="props_auth"></marker> - <p><em>Authentication properties - requires mod_auth</em></p> + <p><em>Authentication Properties - Requires mod_auth</em></p> <marker id="prop_dri"></marker> <p><em>{directory, {path(), [{property(), term()}]}}</em></p> <marker id="props_dir"></marker> - <p>Here follows the valid properties for directories </p> + <p>The properties for directories are as follows:</p> <taglist> - <marker id="prop_allow_from"></marker> - <tag>{allow_from, all | [RegxpHostString]}</tag> + <tag><marker id="prop_allow_from"></marker>{allow_from, all | [RegxpHostString]}</tag> <item> - <p>Defines a set of hosts which should be granted access to a - given directory. - - For example: + <p>Defines a set of hosts to be granted access to a + given directory, for example:</p> <code>{allow_from, ["123.34.56.11", "150.100.23"]}</code> - The host 123.34.56.11 and all machines on the 150.100.23 - subnet are allowed access. </p> + <p>The host <c>123.34.56.11</c> and all machines on the <c>150.100.23</c> + subnet are allowed access.</p> </item> - <marker id="prop_deny_from"></marker> - <tag>{deny_from, all | [RegxpHostString]}</tag> + <tag><marker id="prop_deny_from"></marker>{deny_from, all | [RegxpHostString]}</tag> <item> <p>Defines a set of hosts - which should be denied access to a given directory. - For example: + to be denied access to a given directory, for example:</p> <code>{deny_from, ["123.34.56.11", "150.100.23"]}</code> - The host 123.34.56.11 and all machines on the 150.100.23 - subnet are not allowed access. </p> + <p>The host <c>123.34.56.11</c> and all machines on the <c>150.100.23</c> + subnet are not allowed access.</p> </item> - <marker id="prop_auth_type"></marker> - <tag>{auth_type, plain | dets | mnesia}</tag> + <tag><marker id="prop_auth_type"></marker>{auth_type, plain | dets | mnesia}</tag> <item> <p>Sets the type of authentication database that is used for the - directory.The key difference between the different methods is - that dynamic data can be saved when Mnesia and Dets is used. - This property is called AuthDbType in the Apache like - configuration files. </p> + directory. The key difference between the different methods is + that dynamic data can be saved when <c>Mnesia</c> and <c>Dets</c> + are used. + This property is called <c>AuthDbType</c> in the Apache-like + configuration files.</p> </item> - <marker id="prop_auth_user_file"></marker> - <tag>{auth_user_file, path()}</tag> + <tag><marker id="prop_auth_user_file"></marker>{auth_user_file, path()}</tag> <item> - <p>Sets the name of a file which contains the list of users and - passwords for user authentication. filename can be either + <p>Sets the name of a file containing the list of users and + passwords for user authentication. The filename can be either absolute or relative to the <c>server_root</c>. If using the - plain storage method, this file is a plain text file, where - each line contains a user name followed by a colon, followed - by the non-encrypted password. If user names are duplicated, - the behavior is undefined. For example: + plain storage method, this file is a plain text file where + each line contains a username followed by a colon, followed + by the non-encrypted password. If usernames are duplicated, + the behavior is undefined.</p> + <p>Example:</p> <code> ragnar:s7Xxv7 edward:wwjau8 </code> - If using the dets storage method, the user database is - maintained by dets and should not be edited by hand. Use the - API functions in mod_auth module to create / edit the user - database. This directive is ignored if using the mnesia - storage method. For security reasons, make sure that the - <c>auth_user_file</c> is stored outside the document tree of the Web - server. If it is placed in the directory which it protects, - clients will be able to download it. </p> + <p>If the <c>Dets</c> storage method is used, the user database is + maintained by <c>Dets</c> and must not be edited by hand. Use the + API functions in module <c>mod_auth</c> to create/edit the user + database. This directive is ignored if the <c>Mnesia</c> + storage method is used. For security reasons, ensure that + <c>auth_user_file</c> is stored outside the document tree of the web + server. If it is placed in the directory that it protects, + clients can download it.</p> </item> - <marker id="prop_auth_group_file"></marker> - <tag>{auth_group_file, path()}</tag> + <tag><marker id="prop_auth_group_file"></marker>{auth_group_file, path()}</tag> <item> - <p>Sets the name of a file which contains the list of user - groups for user authentication. Filename can be either - absolute or relative to the <c>server_root</c>. If you use the plain - storage method, the group file is a plain text file, where + <p>Sets the name of a file containing the list of user + groups for user authentication. The filename can be either + absolute or relative to the <c>server_root</c>. If the plain + storage method is used, the group file is a plain text file, where each line contains a group name followed by a colon, followed - by the member user names separated by spaces. For example: + by the members usernames separated by spaces.</p> + <p>Example:</p> <code>group1: bob joe ante</code> - If using the dets storage method, the group database is - maintained by dets and should not be edited by hand. Use the - API for mod_auth module to create / edit the group database. - This directive is ignored if using the mnesia storage method. - For security reasons, make sure that the <c>auth_group_file</c> is - stored outside the document tree of the Web server. If it is - placed in the directory which it protects, clients will be - able to download it. </p> - </item> - - <marker id="prop_auth_name"></marker> - <tag>{auth_name, string()}</tag> + <p>If the <c>Dets</c> storage method is used, the group database is + maintained by <c>Dets</c> and must not be edited by hand. Use the + API for module <c>mod_auth</c> to create/edit the group database. + This directive is ignored if the <c>Mnesia</c> storage method is used. + For security reasons, ensure that the <c>auth_group_file</c> is + stored outside the document tree of the web server. If it is + placed in the directory that it protects, clients + can download it.</p> + </item> + + <tag><marker id="prop_auth_name"></marker>{auth_name, string()}</tag> <item> <p>Sets the name of the authorization realm (auth-domain) for - a directory. This string informs the client about which user - name and password to use. </p> + a directory. This string informs the client about which + username and password to use.</p> </item> - <marker id="prop_auth_access_passwd"></marker> - <tag>{auth_access_password, string()}</tag> + <tag><marker id="prop_auth_access_passwd"></marker>{auth_access_password, string()}</tag> <item> - <p>If set to other than "NoPassword" the password is required - for all API calls. If the password is set to "DummyPassword" the + <p>If set to other than "NoPassword", the password is required + for all API calls. If the password is set to "DummyPassword", the password must be changed before any other API calls. To secure - the authenticating data the password must be changed after the - web server is started since it otherwise is written in clear - text in the configuration file. </p> + the authenticating data, the password must be changed after the + web server is started. Otherwise it is written in clear + text in the configuration file.</p> </item> - <marker id="prop_req_user"></marker> - <tag>{require_user, [string()]}</tag> + <tag><marker id="prop_req_user"></marker>{require_user, [string()]}</tag> <item> - <p>Defines users which should be granted access to a given - directory using a secret password. </p> + <p>Defines users to grant access to a given + directory using a secret password.</p> </item> - <marker id="prop_req_grp"></marker> - <tag>{require_group, [string()]}</tag> + <tag><marker id="prop_req_grp"></marker>{require_group, [string()]}</tag> <item> - <p>Defines users which should be granted access to a given - directory using a secret password. </p> + <p>Defines users to grant access to a given + directory using a secret password.</p> </item> </taglist> <marker id="props_htaccess"></marker> - <p><em>Htaccess authentication properties - requires mod_htaccess</em></p> + <p><em>Htaccess Authentication Properties - Requires mod_htaccess</em></p> <taglist> - <marker id="prop_access_files"></marker> - <tag>{access_files, [path()]}</tag> + <tag><marker id="prop_access_files"></marker>{access_files, [path()]}</tag> <item> - <p>Specify which filenames that are used for - access-files. When a request comes every directory in the path - to the requested asset will be searched after files with the - names specified by this parameter. If such a file is found the - file will be parsed and the restrictions specified in it will - be applied to the request. </p> + <p>Specifies the filenames that are used for + access files. When a request comes, every directory in the path + to the requested asset are searched after files with the + names specified by this parameter. If such a file is found, the + file is parsed and the restrictions specified in it are + applied to the request.</p> </item> </taglist> <marker id="props_sec"></marker> - <p><em>Security properties - requires mod_security </em></p> + <p><em>Security Properties - Requires mod_security</em></p> <marker id="prop_sec_dir"></marker> <p><em>{security_directory, {path(), [{property(), term()}]}}</em></p> <marker id="props_sdir"></marker> - <p>Here follows the valid properties for security directories</p> + <p>The properties for the security directories are as follows:</p> <taglist> - <marker id="prop_data_file"></marker> - <tag>{data_file, path()}</tag> + <tag><marker id="prop_data_file"></marker>{data_file, path()}</tag> <item> - <p>Name of the security data file. The filename can either - absolute or relative to the server_root. This file is used to - store persistent data for the mod_security module. </p> + <p>Name of the security data file. The filename can either be + absolute or relative to the <c>server_root</c>. This file is used to + store persistent data for module <c>mod_security</c>.</p> </item> - <marker id="prop_max_retries"></marker> - <tag>{max_retries, integer()}</tag> + <tag><marker id="prop_max_retries"></marker>{max_retries, integer()}</tag> <item> - <p>Specifies the maximum number of tries to authenticate a - user has before the user is blocked out. If a user - successfully authenticates when the user has been blocked, the - user will receive a 403 (Forbidden) response from the - server. If the user makes a failed attempt while blocked the - server will return 401 (Unauthorized), for security + <p>Specifies the maximum number of attempts to authenticate a + user before the user is blocked out. If a user + successfully authenticates while blocked, the + user receives a 403 (Forbidden) response from the + server. If the user makes a failed attempt while blocked, the + server returns 401 (Unauthorized), for security reasons. - Defaults to 3 may also be set to infinity. </p> + Default is <c>3</c>. Can be set to infinity.</p> </item> - <marker id="prop_block_time"></marker> - <tag>{block_time, integer()}</tag> + <tag><marker id="prop_block_time"></marker>{block_time, integer()}</tag> <item> <p>Specifies the number of minutes a user is blocked. After - this amount of time, he automatically regains access. - Defaults to 60. </p> + this timehas passed, the user automatically regains access. + Default is <c>60</c>.</p> </item> - <marker id="prop_fail_exp_time"></marker> - <tag>{fail_expire_time, integer()}</tag> + <tag><marker id="prop_fail_exp_time"></marker>{fail_expire_time, integer()}</tag> <item> <p>Specifies the number of minutes a failed user authentication - is remembered. If a user authenticates after this amount of - time, his previous failed authentications are + is remembered. If a user authenticates after this + time has passed, the previous failed authentications are forgotten. - Defaults to 30. </p> + Default is <c>30</c>.</p> </item> - <marker id="prop_auth_timeout"></marker> - <tag>{auth_timeout, integer()}</tag> + <tag><marker id="prop_auth_timeout"></marker>{auth_timeout, integer()}</tag> <item> Specifies the number of seconds a successful user authentication is remembered. After this time has passed, the - authentication will no longer be reported. Defaults to 30. + authentication is no longer reported. Default is <c>30</c>. </item> </taglist> </section> <funcs> <func> - <marker id="info1"></marker> <name>info(Pid) -></name> <name>info(Pid, Properties) -> [{Option, Value}]</name> - <fsummary>Fetches information about the HTTP server</fsummary> + <fsummary>Fetches information about the HTTP server.</fsummary> <type> <v>Properties = [property()]</v> - <v>Option = property()</v> + <v>Option = property()</v> <v>Value = term()</v> </type> <desc> <p>Fetches information about the HTTP server. When called - with only the pid all properties are fetched, when called - with a list of specific properties they are fetched. - Available properties are the same as the server's start options. + with only the pid, all properties are fetched. When called + with a list of specific properties, they are fetched. + The available properties are the same as the start options + of the server. </p> - <note><p>Pid is the pid returned from inets:start/[2,3]. - Can also be retrieved form inets:services/0, inets:services_info/0 - see <seealso marker="inets">inets(3)</seealso> + <note><p>Pid is the pid returned from <c>inets:start/[2,3]</c>. + Can also be retrieved form <c>inets:services/0</c> and + <c>inets:services_info/0</c>, + see <seealso marker="inets">inets(3)</seealso>. </p></note> </desc> </func> <func> - <marker id="info2"></marker> <name>info(Address, Port) -> </name> <name>info(Address, Port, Profile) -> </name> <name>info(Address, Port, Profile, Properties) -> [{Option, Value}] </name> <name>info(Address, Port, Properties) -> [{Option, Value}] </name> - <fsummary>Fetches information about the HTTP server</fsummary> + <fsummary>Fetches information about the HTTP server.</fsummary> <type> <v>Address = ip_address()</v> <v>Port = integer()</v> @@ -966,20 +903,19 @@ bytes </type> <desc> <p>Fetches information about the HTTP server. When called with - only the Address, Port and Profile, if relevant, all properties are fetched. - When called with a list of specific properties they are fetched. - Available properties are the same as the server's start - options. + only <c>Address</c> and <c>Port</c>, all properties are + fetched. When called with a list of specific properties, they + are fetched. The available properties are the same as the + start options of the server. </p> - <note><p> Address has to be the ip-address and can not be + <note><p>The address must be the IP address and cannot be the hostname. </p></note> </desc> </func> <func> - <marker id="reload_config"></marker> <name>reload_config(Config, Mode) -> ok | {error, Reason}</name> <fsummary>Reloads the HTTP server configuration without restarting the server.</fsummary> @@ -991,24 +927,26 @@ bytes </type> <desc> <p>Reloads the HTTP server configuration without restarting the - server. Incoming requests will be answered with a temporary - down message during the time the it takes to reload.</p> + server. Incoming requests are answered with a temporary + down message during the reload time.</p> - <note><p>Available properties are the same as the server's - start options, although the properties bind_address and - port can not be changed.</p></note> + <note><p>Available properties are the same as the + start options of the server, but the properties + <c>bind_address</c> and <c>port</c> + cannot be changed.</p></note> - <p>If mode is disturbing, the server is blocked forcefully and - all ongoing requests are terminated and the reload will - start immediately. If mode is non-disturbing, no new - connections are accepted, but the ongoing requests are + <p>If mode is disturbing, the server is blocked forcefully, + all ongoing requests terminates, and the reload + starts immediately. If mode is non-disturbing, no new + connections are accepted, but ongoing requests are allowed to complete before the reload is done.</p> </desc> </func> </funcs> <section> - <title>ERLANG WEB SERVER API DATA TYPES </title> + <title>ERLANG WEB SERVER API DATA TYPES</title> + <p>The Erlang web server API data types are as follows:</p> <code type="none"> ModData = #mod{} @@ -1025,73 +963,75 @@ bytes parsed_header = [], entity_body, connection - }). - </code> + }).</code> - <p>To acess the record in your callback-module use </p> - <code> -include_lib("inets/include/httpd.hrl"). </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>The fields of record <c>mod</c> have the following meaning: </p> <taglist> <tag><c>data</c></tag> - <item>Type <c>[{InteractionKey,InteractionValue}]</c> is used to + <item><p>Type <c>[{InteractionKey,InteractionValue}]</c> is used to propagate data between modules. Depicted - <c>interaction_data()</c> in function type declarations. + <c>interaction_data()</c> in function type declarations.</p> </item> <tag><c>socket_type</c></tag> - <item><c>socket_type()</c>, - Indicates whether it is an ip socket or a ssl socket. + <item><p><c>socket_type()</c> + indicates whether it is an IP socket or an <c>ssl</c> socket.</p> </item> <tag><c>socket</c></tag> - <item>The actual socket in <c>ip_comm</c> or <c>ssl</c> format - depending on the <c>socket_type</c>. + <item><p>The socket, in format <c>ip_comm</c> or <c>ssl</c>, + depending on <c>socket_type</c>.</p> </item> <tag><c>config_db</c></tag> - <item>The config file directives stored as key-value tuples in - an ETS-table. Depicted <c>config_db()</c> in function type - declarations. + <item><p>The config file directives stored as key-value tuples in + an ETS table. Depicted <c>config_db()</c> in function type + declarations.</p> </item> <tag><c>method</c></tag> - <item>Type <c>"GET" | "POST" | "HEAD" | "TRACE"</c>, that is the - HTTP method. + <item><p>Type <c>"GET" | "POST" | "HEAD" | "TRACE"</c>, that is, the + HTTP method.</p> </item> <tag><c>absolute_uri</c></tag> - <item>If the request is a HTTP/1.1 - request the URI might be in the absolute URI format. In that - case httpd will save the absolute URI in this field. An Example - of an absolute URI could - be<c>"http://ServerName:Part/cgi-bin/find.pl?person=jocke"</c></item> + <item><p>If the request is an HTTP/1.1 + request, the URI can be in the absolute URI format. In that + case, <c>httpd</c> saves the absolute URI in this field. An Example + of an absolute URI is + <c>"http://ServerName:Part/cgi-bin/find.pl?person=jocke"</c></p></item> <tag><c>request_uri</c></tag> - <item>The <c>Request-URI</c> as defined - in RFC 1945, for example <c>"/cgi-bin/find.pl?person=jocke"</c></item> + <item><p>The <c>Request-URI</c> as defined + in <url href="http://www.ietf.org/rfc/rfc1945.txt">RFC 1945</url>, for example, <c>"/cgi-bin/find.pl?person=jocke"</c>.</p> + </item> <tag><c>http_version</c></tag> - <item>The <c>HTTP</c> version of the - request, that is "HTTP/0.9", "HTTP/1.0", or "HTTP/1.1". + <item><p>The <c>HTTP</c> version of the + request, that is, "HTTP/0.9", "HTTP/1.0", or "HTTP/1.1".</p> </item> <tag><c>request_line</c></tag> - <item>The <c>Request-Line</c> as - defined in RFC 1945, for example <c>"GET /cgi-bin/find.pl?person=jocke HTTP/1.0"</c>. + <item><p>The <c>Request-Line</c> as + defined in<url href="http://www.ietf.org/rfc/rfc1945.txt">RFC 1945</url>, for example, + <c>"GET /cgi-bin/find.pl?person=jocke HTTP/1.0"</c>.</p> </item> <tag><c>parsed_header</c></tag> - <item>Type <c>[{HeaderKey,HeaderValue}]</c>, + <item>Type <c>[{HeaderKey,HeaderValue}]</c>. <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"} </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. + HTTP request stored in a list as key-value tuples. See + <url href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</url> + for a listing of all header fields. For example, the date field + is 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 can be in lower case or upper case. <c>httpd</c> + ensures that all header field names are in lower case. </item> <tag><c>entity_body</c></tag> - <item>The <c>Entity-Body</c> as defined - in RFC 2616, for example data sent from a CGI-script using the - POST method. + <item><p>The <c>entity-Body</c> as defined + in <url href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</url>, for example, data sent from a CGI script using the + POST method.</p> </item> <tag><c>connection</c></tag> - <item><c>true | false</c> If set to true the connection to the - client is a persistent connection and will not be closed when - the request is served.</item> + <item><p><c>true | false</c>. If set to <c>true</c>, the connection to the + client is a persistent connection and is not closed when + the request is served.</p></item> </taglist> </section> @@ -1100,56 +1040,63 @@ bytes </section> <funcs> <func> - <marker id="module_do"></marker> <name>Module:do(ModData)-> {proceed, OldData} | {proceed, NewData} | {break, NewData} | done</name> - <fsummary>Called for each request to the Web server.</fsummary> + <fsummary>Called for each request to the web server.</fsummary> <type> <v>OldData = list()</v> - <v>NewData = [{response,{StatusCode,Body}}] | [{response,{response,Head,Body}}] | [{response,{already_sent,Statuscode,Size}}] </v> + <v>NewData = [{response,{StatusCode,Body}}]</v> + <v>| [{response,{response,Head,Body}}]</v> + <v>| [{response,{already_sent,Statuscode,Size}}]</v> <v>StatusCode = integer()</v> <v>Body = io_list() | nobody | {Fun, Arg}</v> <v>Head = [HeaderOption]</v> <v>HeaderOption = {Option, Value} | {code, StatusCode}</v> - <v>Option = accept_ranges | allow | cache_control | content_MD5 | content_encoding | content_language | content_length | content_location | content_range | content_type | date | etag | expires | last_modified | location | pragma | retry_after | server | trailer | transfer_encoding</v> + <v>Option = accept_ranges | allow</v> + <v>| cache_control | content_MD5</v> + <v>| content_encoding | content_language</v> + <v>| content_length | content_location</v> + <v>| content_range | content_type | date</v> + <v>| etag | expires | last_modified</v> + <v>| location | pragma | retry_after</v> + <v>| server | trailer | transfer_encoding</v> <v>Value = string()</v> <v>Fun = fun( Arg ) -> sent| close | Body </v> <v>Arg = [term()]</v> </type> <desc> - <p>When a valid request reaches httpd it calls <c>do/1</c> in - each module defined by the Modules configuration - option. The function may generate data for other modules - or a response that can be sent back to the client.</p> - <p>The field <c>data</c> in ModData is a list. This list will be + <p>When a valid request reaches <c>httpd</c>, it calls <c>do/1</c> in + each module, defined by the configuration + option of <c>Module</c>. The function can generate data for other + modules or a response that can be sent back to the client.</p> + <p>The field <c>data</c> in <c>ModData</c> is a list. This list is the list returned from the last call to <c>do/1</c>.</p> - <p><c>Body</c> is the body of the http-response that will be - sent back to the client an appropriate header will be - appended to the message. <c>StatusCode</c> will be the - status code of the response see RFC2616 for the appropriate - values.</p> + <p><c>Body</c> is the body of the HTTP response that is + sent back to the client. An appropriate header is + appended to the message. <c>StatusCode</c> is the + status code of the response, see + <url href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</url> + for the appropriate values.</p> <p><c>Head</c> is a key value list of HTTP header fields. The - server will construct a HTTP header from this data. See RFC - 2616 for the appropriate value for each header field. If the - client is a HTTP/1.0 client then the server will filter the - list so that only HTTP/1.0 header fields will be sent back - to the client.</p> + server constructs an HTTP header from this data. See <url href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</url> for the appropriate value for each header field. If the + client is an HTTP/1.0 client, the server filters the + list so that only HTTP/1.0 header fields are sent back + to the client.</p> <p>If <c>Body</c> is returned and equal to <c>{Fun,Arg}</c>, - the Web server will try <c>apply/2</c> on <c>Fun</c> with - <c>Arg</c> as argument and expect that the fun either - returns a list <c>(Body)</c> that is a HTTP-repsonse or the - atom sent if the HTTP-response is sent back to the - client. If close is returned from the fun something has gone - wrong and the server will signal this to the client by + the web server tries <c>apply/2</c> on <c>Fun</c> with + <c>Arg</c> as argument. The web server expects that the fun either + returns a list <c>(Body)</c> that is an HTTP repsonse, or the + atom <c>sent</c> if the HTTP response is sent back to the + client. If <c>close</c> is returned from the fun, something has gone + wrong and the server signals this to the client by closing the connection.</p> </desc> </func> <func> - <marker id="module_load"></marker> - <name>Module:load(Line, AccIn)-> eof | ok | {ok, AccOut} | {ok, AccOut, {Option, Value}} | {ok, AccOut, [{Option, Value}]} | {error, Reason} </name> - <fsummary>Load is used to convert a line in a Apache like config - file to a <c>{Option, Value}</c> tuple.</fsummary> + <name>Module:load(Line, AccIn)-> eof | ok | {ok, AccOut} | {ok, AccOut, {Option, Value}} | {ok, AccOut, [{Option, Value}]} | {error, Reason}</name> + <fsummary>Converts a line in an Apache-like config + file to an <c>{Option, Value}</c> tuple.</fsummary> <type> <v>Line = string()</v> <v>AccIn = [{Option, Value}]</v> @@ -1159,55 +1106,53 @@ bytes <v>Reason = term()</v> </type> <desc> - <p>Load is used to convert a line in a Apache like - configuration file to a <c>{Option, Value}</c> tuple. Some - more complex configuration options such as <c>directory</c> - and <c>security_directory</c> will create an - accumulator.This function does only need clauses for the + <p>Converts a line in an Apache-like + configuration file to an <c>{Option, Value}</c> tuple. Some + more complex configuration options, such as <c>directory</c> + and <c>security_directory</c>, create an + accumulator. This function only needs clauses for the options implemented by this particular callback module. </p> </desc> </func> - + + <func> + <name>Module:remove(ConfigDB) -> ok | {error, Reason} </name> + <fsummary>Callback function that is called when the web server is closed.</fsummary> + <type> + <v>ConfigDB = ets_table()</v> + <v>Reason = term()</v> + </type> + <desc> + <p>When <c>httpd</c> is shut down, it tries to execute + <c>remove/1</c> in each Erlang web server callback module. The + programmer can use this function to clean up resources + created in the store function.</p> + </desc> + </func> + <func> - <marker id="module_store"></marker> - <name>Module:store({Option, Value}, Config)-> {ok, {Option, NewValue}} | {error, Reason} </name> - <fsummary></fsummary> + <name>Module:store({Option, Value}, Config)-> {ok, {Option, NewValue}} | {error, Reason}</name> + <fsummary>Checks the validity of the configuration options.</fsummary> <type> <v>Line = string()</v> <v>Option = property()</v> <v>Config = [{Option, Value}]</v> - <v>Value = term() </v> + <v>Value = term()</v> <v>Reason = term()</v> </type> <desc> - <p>This function is used to check the validity of the + <p>Checks the validity of the configuration options before saving them in the internal - database. This function may also have a side effect - e.i. setup necessary extra resources implied by the + database. This function can also have a side effect, + that is, setup of necessary extra resources implied by the configuration option. It can also resolve possible dependencies among configuration options by changing the value of the option. - This function does only need clauses for the options + This function only needs clauses for the options implemented by this particular callback module.</p> </desc> </func> - - <func> - <marker id="module_remove"></marker> - <name>Module:remove(ConfigDB) -> ok | {error, Reason} </name> - <fsummary>Callback function that is called when the Web server is closed.</fsummary> - <type> - <v>ConfigDB = ets_table()</v> - <v>Reason = term()</v> - </type> - <desc> - <p>When httpd is shutdown it will try to execute - <c>remove/1</c> in each Erlang web server callback module. The - programmer may use this function to clean up resources - that may have been created in the store function.</p> - </desc> - </func> </funcs> <section> @@ -1215,9 +1160,8 @@ bytes </section> <funcs> <func> - <marker id="parse_query"></marker> - <name>parse_query(QueryString) -> [{Key,Value}]</name> - <fsummary>Parse incoming data to <c>erl </c>and <c>eval </c>scripts.</fsummary> + <name>parse_query(QueryString) -> [{Key,Value}]</name> + <fsummary>Parses incoming data to <c>erl</c> and <c>eval</c> scripts.</fsummary> <type> <v>QueryString = string()</v> <v>Key = string()</v> @@ -1225,8 +1169,9 @@ bytes </type> <desc> <p><c>parse_query/1</c> parses incoming data to <c>erl</c> and - <c>eval</c> scripts (See <seealso marker="mod_esi">mod_esi(3)</seealso>) as defined in the standard - URL format, that is '+' becomes 'space' and decoding of + <c>eval</c> scripts (see <seealso marker="mod_esi">mod_esi(3)</seealso>) + as defined in the standard + URL format, that is, '+' becomes 'space' and decoding of hexadecimal characters (<c>%xx</c>).</p> </desc> </func> @@ -1234,8 +1179,9 @@ bytes <section> <title>SEE ALSO</title> - <p>RFC 2616, <seealso marker="inets">inets(3)</seealso>, - <seealso marker="ssl:ssl">ssl(3)</seealso> + <p><url href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</url>, + <seealso marker="inets">inets(3)</seealso>, + <seealso marker="ssl:ssl">ssl(3)</seealso> </p> </section> diff --git a/lib/inets/doc/src/httpd_conf.xml b/lib/inets/doc/src/httpd_conf.xml deleted file mode 100644 index 54a5885eb4..0000000000 --- a/lib/inets/doc/src/httpd_conf.xml +++ /dev/null @@ -1,163 +0,0 @@ -<?xml version="1.0" encoding="utf-8" ?> -<!DOCTYPE erlref SYSTEM "erlref.dtd"> - -<erlref> - <header> - <copyright> - <year>1997</year><year>2013</year> - <holder>Ericsson AB. All Rights Reserved.</holder> - </copyright> - <legalnotice> - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - </legalnotice> - - <title>httpd_conf</title> - <prepared>Joakim Grebenö</prepared> - <docno></docno> - <date>1997-10-14</date> - <rev>2.2</rev> - <file>httpd_conf.sgml</file> - </header> - <module>httpd_conf</module> - <modulesummary>Configuration utility functions to be used by the Erlang - Web server API programmer.</modulesummary> - <description> - <p>This module provides the Erlang Webserver API programmer with - utility functions for adding run-time configuration directives.</p> - - <marker id="check_enum"></marker> - </description> - - <funcs> - <func> - <name>check_enum(EnumString, ValidEnumStrings) -> Result</name> - <fsummary>Check if string is a valid enumeration.</fsummary> - <type> - <v>EnumString = string()</v> - <v>ValidEnumStrings = [string()]</v> - <v>Result = {ok,atom()} | {error,not_valid}</v> - </type> - <desc> - <marker id="check_enum"></marker> - <p><c>check_enum/2</c> checks if <c>EnumString</c> is a valid - enumeration of <c>ValidEnumStrings</c> in which case it is - returned as an atom.</p> - - <marker id="clean"></marker> - </desc> - </func> - - <func> - <name>clean(String) -> Stripped</name> - <fsummary>Remove leading and/or trailing white spaces.</fsummary> - <type> - <v>String = Stripped = string()</v> - </type> - <desc> - <marker id="clean"></marker> - <p><c>clean/1</c> removes leading and/or trailing white spaces - from <c>String</c>.</p> - - <marker id="custom_clean"></marker> - </desc> - </func> - - <func> - <name>custom_clean(String,Before,After) -> Stripped</name> - <fsummary>Remove leading and/or trailing white spaces and custom characters.</fsummary> - <type> - <v>Before = After = regexp()</v> - <v>String = Stripped = string()</v> - </type> - <desc> - <marker id="custom_clean"></marker> - <p><c>custom_clean/3</c> removes leading and/or trailing white - spaces and custom characters from <c>String</c>. <c>Before</c> - and <c>After</c> are regular expressions, as defined in - <c>regexp(3)</c>, describing the custom characters.</p> - - <marker id="is_directory"></marker> - </desc> - </func> - - <func> - <name>is_directory(FilePath) -> Result</name> - <fsummary>Check if a file path is a directory.</fsummary> - <type> - <v>FilePath = string()</v> - <v>Result = {ok,Directory} | {error,Reason}</v> - <v>Directory = string()</v> - <v>Reason = string() | enoent | eacces | enotdir | FileInfo</v> - <v>FileInfo = File info record</v> - </type> - <desc> - <marker id="is_directory"></marker> - <p><c>is_directory/1</c> checks if <c>FilePath</c> is a - directory in which case it is returned. Please read - <c>file(3)</c> for a description of <c>enoent</c>, - <c>eacces</c> and <c>enotdir</c>. The definition of - the file info record can be found by including <c>file.hrl</c> - from the kernel application, see file(3).</p> - - <marker id="is_file"></marker> - </desc> - </func> - - <func> - <name>is_file(FilePath) -> Result</name> - <fsummary>Check if a file path is a regular file.</fsummary> - <type> - <v>FilePath = string()</v> - <v>Result = {ok,File} | {error,Reason}</v> - <v>File = string()</v> - <v>Reason = string() | enoent | eacces | enotdir | FileInfo</v> - <v>FileInfo = File info record</v> - </type> - <desc> - <marker id="is_file"></marker> - <p><c>is_file/1</c> checks if <c>FilePath</c> is a regular - file in which case it is returned. Read <c>file(3)</c> for a - description of <c>enoent</c>, <c>eacces</c> and - <c>enotdir</c>. The definition of the file info record can be - found by including <c>file.hrl</c> from the kernel application, - see file(3).</p> - - <marker id="make_integer"></marker> - </desc> - </func> - - <func> - <name>make_integer(String) -> Result</name> - <fsummary>Return an integer representation of a string.</fsummary> - <type> - <v>String = string()</v> - <v>Result = {ok,integer()} | {error,nomatch}</v> - </type> - <desc> - <marker id="make_integer"></marker> - <p><c>make_integer/1</c> returns an integer representation of - <c>String</c>.</p> - </desc> - </func> - </funcs> - - <section> - <marker id="see_also"></marker> - <title>SEE ALSO</title> - <p><seealso marker="httpd">httpd(3)</seealso></p> - </section> - -</erlref> - - diff --git a/lib/inets/doc/src/httpd_custom_api.xml b/lib/inets/doc/src/httpd_custom_api.xml index 5840641b37..d2e5441895 100644 --- a/lib/inets/doc/src/httpd_custom_api.xml +++ b/lib/inets/doc/src/httpd_custom_api.xml @@ -29,10 +29,24 @@ <modulesummary>Behaviour with optional callbacks to customize the inets HTTP server.</modulesummary> <description> <p> The module implementing this behaviour shall be supplied to to the servers - configuration with the option <seealso marker="httpd:prop_customize"> customize</seealso></p> + configuration with the option <seealso marker="httpd#prop_customize"> customize</seealso></p> </description> <funcs> + <func> + <name>response_default_headers() -> [Header] </name> + <fsummary>Provide default headers for the HTTP servers responses.</fsummary> + <type> + <v>Header = {HeaderName :: string(), HeaderValue::string()}</v> + <d>string:to_lower/1 will be performed on the HeaderName</d> + </type> + <desc> + <p>Provide default headers for the HTTP servers responses. Note that this + option may override built-in defaults. + </p> + </desc> + </func> + <func> <name>response_header({HeaderName, HeaderValue}) -> {true, Header} | false </name> <fsummary>Filter and possible alter HTTP response headers.</fsummary> diff --git a/lib/inets/doc/src/httpd_socket.xml b/lib/inets/doc/src/httpd_socket.xml index c0368c2b39..f71dac90b2 100644 --- a/lib/inets/doc/src/httpd_socket.xml +++ b/lib/inets/doc/src/httpd_socket.xml @@ -31,12 +31,12 @@ </header> <module>httpd_socket</module> <modulesummary>Communication utility functions to be used by the Erlang - Web server API programmer.</modulesummary> + web server API programmer.</modulesummary> <description> - <p>This module provides the Erlang Web server API module programmer + <p>This module provides the Erlang web server API module programmer with utility functions for generic sockets communication. The appropriate communication mechanism is transparently used, that - is <c>ip_comm</c> or <c>ssl</c>.</p> + is, <c>ip_comm</c> or <c>ssl</c>.</p> <marker id="deliver"></marker> </description> @@ -44,7 +44,7 @@ <funcs> <func> <name>deliver(SocketType, Socket, Data) -> Result</name> - <fsummary>Send binary data over socket.</fsummary> + <fsummary>Sends binary data over socket.</fsummary> <type> <v>SocketType = socket_type()</v> <v>Socket = socket()</v> @@ -53,10 +53,10 @@ </type> <desc> <marker id="deliver"></marker> - <p><c>deliver/3</c> sends the <c>Binary</c> over the - <c>Socket</c> using the specified <c>SocketType</c>. Socket - and SocketType should be the socket and the socket_type form - the mod record as defined in httpd.hrl</p> + <p><c>deliver/3</c> sends <c>Data</c> over + <c>Socket</c> using the specified <c>SocketType</c>. <c>Socket</c> + and <c>SocketType</c> is to be the socket and the <c>socket_type</c> + form the <c>mod</c> record as defined in <c>httpd.hrl</c></p> <marker id="peername"></marker> </desc> @@ -64,7 +64,7 @@ <func> <name>peername(SocketType,Socket) -> {Port,IPAddress}</name> - <fsummary>Return the port and IP-address of the remote socket.</fsummary> + <fsummary>Returns the port and IP address of the remote socket.</fsummary> <type> <v>SocketType = socket_type()</v> <v>Socket = socket()</v> @@ -73,8 +73,8 @@ </type> <desc> <marker id="peername"></marker> - <p><c>peername/3</c> returns the <c>Port</c> and - <c>IPAddress</c> of the remote <c>Socket</c>. </p> + <p><c>peername/2</c> returns the <c>Port</c> and + <c>IPAddress</c> of the remote <c>Socket</c>.</p> <marker id="resolve"></marker> </desc> @@ -82,7 +82,7 @@ <func> <name>resolve() -> HostName</name> - <fsummary>Return the official name of the current host.</fsummary> + <fsummary>Returns the official name of the current host.</fsummary> <type> <v>HostName = string()</v> </type> diff --git a/lib/inets/doc/src/httpd_util.xml b/lib/inets/doc/src/httpd_util.xml index a48e141368..0f498ba2fc 100644 --- a/lib/inets/doc/src/httpd_util.xml +++ b/lib/inets/doc/src/httpd_util.xml @@ -30,9 +30,10 @@ <file>httpd_util.sgml</file> </header> <module>httpd_util</module> - <modulesummary>Miscellaneous utility functions to be used when implementing Erlang Web server API modules.</modulesummary> + <modulesummary>Miscellaneous utility functions to be used when implementing + Erlang web server API modules.</modulesummary> <description> - <p>This module provides the Erlang Web Server API module + <p>This module provides the Erlang web server API module programmer with miscellaneous utility functions.</p> <marker id="convert_request_date"></marker> @@ -41,7 +42,7 @@ <funcs> <func> <name>convert_request_date(DateString) -> ErlDate|bad_date</name> - <fsummary>Convert The the date to the Erlang date format.</fsummary> + <fsummary>Converts the date to the Erlang date format.</fsummary> <type> <v>DateString = string()</v> <v>ErlDate = {{Year,Month,Date},{Hour,Min,Sec}}</v> @@ -49,10 +50,9 @@ </type> <desc> <p><c>convert_request_date/1</c> converts <c>DateString</c> to - the Erlang date format. DateString must be in one of the three - date formats that is defined in the RFC 2616.</p> - - <marker id="create_etag"></marker> + the Erlang date format. <c>DateString</c> must be in one of the + three date formats defined in + <url href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</url>.</p> </desc> </func> @@ -64,128 +64,84 @@ <v>Etag = string()</v> </type> <desc> - <p><c>create_etag/1</c> calculates the Etag for a file, from its - size and time for last modification. fileinfo is a record defined - in <c>kernel/include/file.hrl</c></p> - - <marker id="decode_hex"></marker> + <p><c>create_etag/1</c> calculates the Etag for a file from its + size and time for last modification. <c>FileInfo</c> is a record defined + in <c>kernel/include/file.hrl</c>.</p> </desc> </func> - - <func> - <name>decode_hex(HexValue) -> DecValue</name> - <fsummary>Convert a hex value into its decimal equivalent.</fsummary> - <type> - <v>HexValue = DecValue = string()</v> - </type> - <desc> - <p>Converts the hexadecimal value <c>HexValue</c> into its - decimal equivalent (<c>DecValue</c>).</p> - - <marker id="day"></marker> - </desc> - </func> - + <func> <name>day(NthDayOfWeek) -> DayOfWeek</name> - <fsummary>Convert the day of the week (integer [1-7]) to an abbreviated string.</fsummary> + <fsummary>Converts the day of the week + (integer [1-7]) to an abbreviated string.</fsummary> <type> <v>NthDayOfWeek = 1-7</v> <v>DayOfWeek = string()</v> </type> <desc> - <marker id="day"></marker> <p><c>day/1</c> converts the day of the week - (<c>NthDayOfWeek</c>) as an integer (1-7) to an abbreviated - string, that is: </p> + (<c>NthDayOfWeek</c>) from an integer (1-7) to an abbreviated + string, that is:</p> <p>1 = "Mon", 2 = "Tue", ..., 7 = "Sat".</p> - - <marker id="flatlength"></marker> </desc> </func> <func> - <name>flatlength(NestedList) -> Size</name> - <fsummary>Compute the size of a possibly nested list.</fsummary> + <name>decode_hex(HexValue) -> DecValue</name> + <fsummary>Converts a hexadecimal value into its decimal equivalent.</fsummary> <type> - <v>NestedList = list()</v> - <v>Size = integer()</v> + <v>HexValue = DecValue = string()</v> </type> <desc> - <marker id="flatlength"></marker> - <p><c>flatlength/1</c> computes the size of the possibly nested - list <c>NestedList</c>. Which may contain binaries.</p> - - <marker id="hexlist_to_integer"></marker> + <p>Converts the hexadecimal value <c>HexValue</c> into its + decimal equivalent (<c>DecValue</c>).</p> </desc> </func> - -<!-- + <func> - <name>header(StatusCode,PersistentConn)</name> - <name>header(StatusCode,Date)</name> - <name>header(StatusCode,MimeType,Date)</name> - <name>header(StatusCode,MimeType,PersistentConn,Date) -> HTTPHeader</name> - <fsummary>Generate a HTTP 1.1 header.</fsummary> + <name>flatlength(NestedList) -> Size</name> + <fsummary>Computes the size of a possibly nested list.</fsummary> <type> - <v>StatusCode = integer()</v> - <v>Date = rfc1123_date()</v> - <v>MimeType = string()</v> - <v>PersistentConn = true | false</v> + <v>NestedList = list()</v> + <v>Size = integer()</v> </type> <desc> - <marker id="header"></marker> - <p><c>header</c> returns a HTTP 1.1 header string. The - <c>StatusCode</c> is one of the status codes defined in RFC - 2616 and the <c>Date</c> string is RFC 1123 - compliant. (See <seealso marker="#rfc1123_date">rfc1123_date/0</seealso>). - </p> - <p>Note that the two version of <c>header/n</c> that does not - has a <c>PersistentConn</c> argument is there only for - backward compatibility, and must not be used in new Erlang - Webserver API modules. that will support persistent - connections.</p> - - <marker id="hexlist_to_integer"></marker> + <p><c>flatlength/1</c> computes the size of the possibly nested + list <c>NestedList</c>, which can contain binaries.</p> </desc> </func> ---> <func> <name>hexlist_to_integer(HexString) -> Number</name> - <fsummary>Convert a hexadecimal string to an integer.</fsummary> + <fsummary>Converts a hexadecimal string to an integer.</fsummary> <type> <v>Number = integer()</v> <v>HexString = string()</v> </type> <desc> - <p><c>hexlist_to_integer</c> Convert the Hexadecimal value of - HexString to an integer.</p> - - <marker id="integer_to_hexlist"></marker> + <p><c>hexlist_to_integer</c> converts the hexadecimal value of + <c>HexString</c> to an integer.</p> </desc> </func> <func> <name>integer_to_hexlist(Number) -> HexString</name> - <fsummary>Convert an integer to a hexadecimal string.</fsummary> + <fsummary>Converts an integer to a hexadecimal string.</fsummary> <type> <v>Number = integer()</v> <v>HexString = string()</v> </type> <desc> - <marker id="integer_to_hexlist"></marker> - <p><c>integer_to_hexlist/1</c> Returns a string that represents - the Number in a Hexadecimal form.</p> - - <marker id="lookup"></marker> + <p><c>integer_to_hexlist/1</c> returns a string representing + <c>Number</c> in a hexadecimal form.</p> </desc> </func> <func> <name>lookup(ETSTable,Key) -> Result</name> <name>lookup(ETSTable,Key,Undefined) -> Result</name> - <fsummary>Extract the first value associated with a key in an ETS table.</fsummary> + <fsummary>Extracts the first value associated with a <c>Key</c> + in an ETS table.</fsummary> <type> <v>ETSTable = ets_table()</v> <v>Key = term()</v> @@ -195,20 +151,18 @@ <desc> <p><c>lookup</c> extracts <c>{Key,Value}</c> tuples from <c>ETSTable</c> and returns the <c>Value</c> associated - with <c>Key</c>. If <c>ETSTable</c> is of type <c>bag</c> + with <c>Key</c>. If <c>ETSTable</c> is of type <c>bag</c>, only the first <c>Value</c> associated with <c>Key</c> is returned. <c>lookup/2</c> returns <c>undefined</c> and <c>lookup/3</c> returns <c>Undefined</c> if no <c>Value</c> is found.</p> - - <marker id="lookup_mime"></marker> </desc> </func> <func> <name>lookup_mime(ConfigDB,Suffix)</name> <name>lookup_mime(ConfigDB,Suffix,Undefined) -> MimeType</name> - <fsummary>Return the mime type associated with a specific file suffix. </fsummary> + <fsummary>Returns the MIME type associated with a specific file suffix.</fsummary> <type> <v>ConfigDB = ets_table()</v> <v>Suffix = string()</v> @@ -216,20 +170,19 @@ <v>Undefined = term()</v> </type> <desc> - <marker id="lookup_mime"></marker> - <p><c>lookup_mime</c> returns the mime type associated with a - specific file suffix as specified in the <c>mime.types</c> - file (located in the - <path unix="$SERVER_ROOT/conf/mime.types" windows="%SERVER_ROOT%\conf\mime.types">config directory</path>).</p> - - <marker id="lookup_mime_default"></marker> + <p><c>lookup_mime</c> returns the MIME type associated with a + specific file suffix as specified in the file <c>mime.types</c> + (located in the + <path unix="$SERVER_ROOT/conf/mime.types" windows="%SERVER_ROOT%\conf\mime.types"> + config directory</path>).</p> </desc> </func> <func> <name>lookup_mime_default(ConfigDB,Suffix)</name> <name>lookup_mime_default(ConfigDB,Suffix,Undefined) -> MimeType</name> - <fsummary>Return the mime type associated with a specific file suffix or the value of the DefaultType.</fsummary> + <fsummary>Returns the MIME type associated with a specific file suffix + or the value of the DefaultType.</fsummary> <type> <v>ConfigDB = ets_table()</v> <v>Suffix = string()</v> @@ -237,22 +190,19 @@ <v>Undefined = term()</v> </type> <desc> - <marker id="lookup_mime_default"></marker> - <p><c>lookup_mime_default</c> returns the mime type associated + <p><c>lookup_mime_default</c> returns the MIME type associated with a specific file suffix as specified in the <c>mime.types</c> file (located in the - <path unix="$SERVER_ROOT/conf/mime.types" windows="%SERVER_ROOT%\conf\mime.types">config directory</path>). - If no appropriate association can be found - the value of DefaultType is + <path unix="$SERVER_ROOT/conf/mime.types" windows="%SERVER_ROOT%\conf\mime.types"> + config directory</path>). + If no appropriate association is found, the value of <c>DefaultType</c> is returned.</p> - - <marker id="message"></marker> </desc> </func> <func> <name>message(StatusCode,PhraseArgs,ConfigDB) -> Message</name> - <fsummary>Return an informative HTTP 1.1 status string in HTML.</fsummary> + <fsummary>Returns an informative HTTP 1.1 status string in HTML.</fsummary> <type> <v>StatusCode = 301 | 400 | 403 | 404 | 500 | 501 | 504</v> <v>PhraseArgs = term()</v> @@ -260,53 +210,48 @@ <v>Message = string()</v> </type> <desc> - <marker id="message"></marker> <p><c>message/3</c> returns an informative HTTP 1.1 status string in HTML. Each <c>StatusCode</c> requires a specific <c>PhraseArgs</c>: </p> <taglist> <tag><c>301</c></tag> - <item><c>string()</c>: A URL pointing at the new document - position.</item> + <item><p><c>string()</c>: A URL pointing at the new document + position.</p></item> <tag><c>400 | 401 | 500</c></tag> - <item><c>none</c> (No <c>PhraseArgs</c>)</item> + <item><p><c>none</c> (no <c>PhraseArgs</c>).</p></item> <tag><c>403 | 404</c></tag> - <item><c>string()</c>: A <c>Request-URI</c> as described in - RFC 2616.</item> + <item><p><c>string()</c>: A <c>Request-URI</c> as described in + <url href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</url>.</p> + </item> <tag><c>501</c></tag> - <item><c>{Method,RequestURI,HTTPVersion}</c>: The HTTP - <c>Method</c>, <c>Request-URI</c> and <c>HTTP-Version</c> - as defined in RFC 2616.</item> + <item><p><c>{Method,RequestURI,HTTPVersion}</c>: The HTTP + <c>Method</c>, <c>Request-URI</c>, and <c>HTTP-Version</c> + as defined in RFC 2616.</p></item> <tag><c>504</c></tag> - <item><c>string()</c>: A string describing why the service - was unavailable.</item> + <item><p><c>string()</c>: A string describing why the service + was unavailable.</p></item> </taglist> - - <marker id="month"></marker> </desc> </func> <func> <name>month(NthMonth) -> Month</name> - <fsummary>Convert the month as an integer (1-12) to an abbreviated string.</fsummary> + <fsummary>Converts the month as an integer (1-12) to an abbreviated string.</fsummary> <type> <v>NthMonth = 1-12</v> <v>Month = string()</v> </type> <desc> - <marker id="month"></marker> <p><c>month/1</c> converts the month <c>NthMonth</c> as an integer (1-12) to an abbreviated string, that is: </p> <p>1 = "Jan", 2 = "Feb", ..., 12 = "Dec".</p> - - <marker id="multi_lookup"></marker> </desc> </func> <func> <name>multi_lookup(ETSTable,Key) -> Result</name> - <fsummary>Extract the values associated with a key in a ETS table.</fsummary> + <fsummary>Extracts the values associated with a key in an ETS table.</fsummary> <type> <v>ETSTable = ets_table()</v> <v>Key = term()</v> @@ -314,49 +259,44 @@ </type> <desc> <p><c>multi_lookup</c> extracts all <c>{Key,Value}</c> tuples - from an <c>ETSTable</c> and returns <em>all</em><c>Values</c> associated with the <c>Key</c> in a list.</p> - - <marker id="reason phrase"></marker> + from an <c>ETSTable</c> and returns <em>all</em> <c>Values</c> + associated with <c>Key</c> in a list.</p> </desc> </func> <func> <name>reason_phrase(StatusCode) -> Description</name> - <fsummary>Return the description of an HTTP 1.1 status code.</fsummary> + <fsummary>Returns the description of an HTTP 1.1 status code.</fsummary> <type> - <v>StatusCode = 100| 200 | 201 | 202 | 204 | 205 | 206 | 300 | 301 | 302 | 303 | 304 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 410 411 | 412 | 413 | 414 415 | 416 | 417 | 500 | 501 | 502 | 503 | 504 | 505</v> + <v>StatusCode = 100| 200 | 201 | 202 | 204 | 205 | 206 | 300 | 301 | 302 | 303 | 304 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 410 411 | 412 | 413 | 414 415 | 416 | 417 | 500 | 501 | 502 | 503 | 504 | 505</v> <v>Description = string()</v> </type> <desc> - <p><c>reason_phrase</c> returns the <c>Description</c> of an - HTTP 1.1 <c>StatusCode</c>, for example 200 is "OK" and 201 - is "Created". Read RFC 2616 for further information.</p> - - <marker id="rfc1123_date"></marker> + <p><c>reason_phrase</c> returns <c>Description</c> of an + HTTP 1.1 <c>StatusCode</c>, for example, 200 is "OK" and 201 + is "Created". For more information, see + <url href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</url>.</p> </desc> </func> <func> <name>rfc1123_date() -> RFC1123Date</name> <name>rfc1123_date({{YYYY,MM,DD},{Hour,Min,Sec}}) -> RFC1123Date</name> - <fsummary>Return the current date in RFC 1123 format.</fsummary> + <fsummary>Returns the current date in RFC 1123 format.</fsummary> <type> <v>YYYY = MM = DD = Hour = Min = Sec = integer()</v> <v>RFC1123Date = string()</v> </type> <desc> - <marker id="rfc1123_date"></marker> <p><c>rfc1123_date/0</c> returns the current date in RFC 1123 format. <c>rfc_date/1</c> converts the date in the Erlang format to the RFC 1123 date format.</p> - - <marker id="split"></marker> </desc> </func> <func> <name>split(String,RegExp,N) -> SplitRes</name> - <fsummary>Split a string in N chunks using a regular expression.</fsummary> + <fsummary>Splits a string in N chunks using a regular expression.</fsummary> <type> <v>String = RegExp = string()</v> <v>SplitRes = {ok, FieldList} | {error, errordesc()}</v> @@ -364,96 +304,86 @@ <v>N = integer</v> </type> <desc> - <marker id="split"></marker> - <p><c>split/3</c> splits the <c>String</c> in <c>N</c> chunks - using the <c>RegExp</c>. <c>split/3</c> is is equivalent to - <c>regexp:split/2</c> with one exception, that is <c>N</c> - defines the number of maximum number of fields in the + <p><c>split/3</c> splits <c>String</c> in <c>N</c> chunks + using <c>RegExp</c>. <c>split/3</c> is equivalent to + <c>regexp:split/2</c> with the exception that <c>N</c> + defines the maximum number of fields in <c>FieldList</c>.</p> - - <marker id="split_script_path"></marker> </desc> </func> <func> <name>split_script_path(RequestLine) -> Splitted</name> - <fsummary>Split a <c>RequestLine</c>in a file reference to an executable and a<c>QueryString</c>or a <c>PathInfo</c>string.</fsummary> + <fsummary>Splits a <c>RequestLine</c> in a file reference to an executable, + and a <c>QueryString</c> or a <c>PathInfo</c>string.</fsummary> <type> <v>RequestLine = string()</v> <v>Splitted = not_a_script | {Path, PathInfo, QueryString}</v> <v>Path = QueryString = PathInfo = string()</v> </type> <desc> - <marker id="split_script_path"></marker> <p><c>split_script_path/1</c> is equivalent to <c>split_path/1</c> with one exception. If the longest - possible path is not a regular, accessible and executable - file <c>not_a_script</c> is returned.</p> - - <marker id="split_path"></marker> + possible path is not a regular, accessible, and executable + file, then <c>not_a_script</c> is returned.</p> </desc> </func> <func> <name>split_path(RequestLine) -> {Path,QueryStringOrPathInfo}</name> - <fsummary>Split a <c>RequestLine</c>in a file reference and a <c>QueryString</c>or a<c>PathInfo</c>string.</fsummary> + <fsummary>Splits a <c>RequestLine</c> in a file reference, and a + <c>QueryString</c> or a <c>PathInfo</c> string.</fsummary> <type> <v>RequestLine = Path = QueryStringOrPathInfo = string()</v> </type> <desc> - <marker id="split_path"></marker> - <p><c>split_path/1</c> splits the <c>RequestLine</c> in a file - reference (<c>Path</c>) and a <c>QueryString</c> or a - <c>PathInfo</c> string as specified in RFC 2616. A - <c>QueryString</c> is isolated from the <c>Path</c> with a + <p><c>split_path/1</c> splits <c>RequestLine</c> in a file + reference (<c>Path</c>), and a <c>QueryString</c> or a + <c>PathInfo</c> string as specified in + <url href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</url>. + A <c>QueryString</c> is isolated from <c>Path</c> with a question mark (<c>?</c>) and <c>PathInfo</c> with a slash (/). In the case of a <c>QueryString</c>, everything before - the <c>?</c> is a <c>Path</c> and everything after a - <c>QueryString</c>. In the case of a <c>PathInfo</c> the + <c>?</c> is a <c>Path</c> and everything after <c>?</c> is a + <c>QueryString</c>. In the case of a <c>PathInfo</c>, <c>RequestLine</c> is scanned from left-to-right on the hunt for longest possible <c>Path</c> being a file or a directory. Everything after the longest possible <c>Path</c>, isolated with a <c>/</c>, is regarded as <c>PathInfo</c>. The resulting <c>Path</c> is decoded using <c>decode_hex/1</c> before delivery.</p> - - <marker id="strip"></marker> </desc> </func> <func> <name>strip(String) -> Stripped</name> - <fsummary>Returns String where the leading and trailing space and tabs has been removed.</fsummary> + <fsummary>Returns <c>String</c> where the leading and trailing space + tabs are removed.</fsummary> <type> <v>String = Stripped = string()</v> </type> <desc> - <marker id="strip"></marker> <p><c>strip/1</c> removes any leading or trailing linear white - space from the string. Linear white space should be read as + space from the string. Linear white space is to be read as horizontal tab or space.</p> - - <marker id="suffix"></marker> </desc> </func> <func> <name>suffix(FileName) -> Suffix</name> - <fsummary>Extract the file suffix from a given filename.</fsummary> + <fsummary>Extracts the file suffix from a given filename.</fsummary> <type> <v>FileName = Suffix = string()</v> </type> <desc> - <marker id="suffix"></marker> <p><c>suffix/1</c> is equivalent to - <c>filename:extension/1</c> with one exception, that is - <c>Suffix</c> is returned without a leading dot (<c>.</c>). </p> + <c>filename:extension/1</c> with the exception that + <c>Suffix</c> is returned without a leading dot (<c>.</c>).</p> </desc> </func> </funcs> <section> - <marker id="see_also"></marker> <title>SEE ALSO</title> <p><seealso marker="httpd">httpd(3)</seealso></p> </section> diff --git a/lib/inets/doc/src/inets.xml b/lib/inets/doc/src/inets.xml index f96ff5f8fb..5d071c9a48 100644 --- a/lib/inets/doc/src/inets.xml +++ b/lib/inets/doc/src/inets.xml @@ -30,21 +30,21 @@ <rev></rev> </header> <module>inets</module> - <modulesummary>The inets services API</modulesummary> + <modulesummary>The Inets services API.</modulesummary> <description> <p>This module provides the most basic API to the - clients and servers, that are part of the Inets application, - such as start and stop. </p> + clients and servers that are part of the <c>Inets</c> application, + such as start and stop.</p> <marker id="common_data_types"></marker> </description> <section> - <title>COMMON DATA TYPES </title> + <title>DATA TYPES</title> <p>Type definitions that are used more than once in - this module: </p> - <p><c> service() = ftpc | tftp | httpc | httpd</c></p> - <p><c> property() = atom() </c></p> + this module:</p> + <p><c>service() = ftpc | tftp | httpc | httpd</c></p> + <p><c>property() = atom()</c></p> <marker id="functions"></marker> <marker id="services"></marker> </section> @@ -52,7 +52,7 @@ <funcs> <func> <name>services() -> [{Service, Pid}]</name> - <fsummary>Returns a list of currently running services. </fsummary> + <fsummary>Returns a list of currently running services.</fsummary> <type> <v>Service = service()</v> <v>Pid = pid()</v> @@ -60,7 +60,7 @@ <desc> <p>Returns a list of currently running services.</p> <note> - <p>Services started as <c>stand_alone</c> will not be listed.</p> + <p>Services started as <c>stand_alone</c> are not listed.</p> </note> <marker id="services_info"></marker> @@ -70,8 +70,8 @@ <func> <name>services_info() -> [{Service, Pid, Info}]</name> <fsummary>Returns a list of currently running services where - each service is described by a [{Option, Value}] - list. </fsummary> + each service is described by an <c>[{Option, Value}]</c> + list.</fsummary> <type> <v>Service = service()</v> <v>Pid = pid()</v> @@ -81,11 +81,10 @@ </type> <desc> <p>Returns a list of currently running services where each - service is described by a [{Option, Value}] list. The - information given in the list is specific for each service - and it is probable that each service will have its own info - function that gives you even more details about the - service.</p> + service is described by an <c>[{Option, Value}]</c> list. The + information in the list is specific for each service + and each service has probably its own info + function that gives more details about the service.</p> <marker id="service_names"></marker> </desc> @@ -107,59 +106,48 @@ <func> <name>start() -> </name> <name>start(Type) -> ok | {error, Reason}</name> - <fsummary>Starts the Inets application. </fsummary> + <fsummary>Starts the <c>Inets</c> application.</fsummary> <type> <v>Type = permanent | transient | temporary</v> </type> <desc> - <p>Starts the Inets application. Default type - is temporary. See also - <seealso marker="kernel:application">application(3)</seealso>. </p> + <p>Starts the <c>Inets</c> application. Default type + is <c>temporary</c>. See also + <seealso marker="kernel:application">application(3)</seealso>.</p> <marker id="stop"></marker> </desc> </func> <func> - <name>stop() -> ok </name> - <fsummary>Stops the inets application.</fsummary> - <desc> - <p>Stops the inets application. See also - <seealso marker="kernel:application">application(3)</seealso>. </p> - - <marker id="start2"></marker> - </desc> - </func> - - <func> <name>start(Service, ServiceConfig) -> {ok, Pid} | {error, Reason}</name> <name>start(Service, ServiceConfig, How) -> {ok, Pid} | {error, Reason}</name> - <fsummary>Dynamically starts an inets - service after the inets application has been started. </fsummary> + <fsummary>Dynamically starts an <c>Inets</c> + service after the <c>Inets</c> application has been started.</fsummary> <type> <v>Service = service()</v> <v>ServiceConfig = [{Option, Value}]</v> <v>Option = property()</v> <v>Value = term()</v> - <v>How = inets | stand_alone - default is inets</v> + <v>How = inets | stand_alone - default is inets.</v> </type> <desc> - <p>Dynamically starts an inets service after the inets - application has been started. </p> + <p>Dynamically starts an <c>Inets</c> service after the <c>Inets</c> + application has been started.</p> <note> - <p>Dynamically started services will not be handled by - application takeover and failover behavior when inets is - run as a distributed application. Nor will they be - automatically restarted when the inets application is - restarted, but as long as the inets application is up and - running they will be supervised and may be soft code - upgraded. Services started as <c>stand_alone</c>, - e.i. the service is not started as part of the inets - application, will lose all OTP application benefits such - as soft upgrade. The "stand_alone-service" will be linked to - the process that started it. In most cases some of the - supervision functionality will still be in place and in - some sense the calling process has now become the top + <p>Dynamically started services are not handled by + application takeover and failover behavior when <c>Inets</c> is + run as a distributed application. Nor are they + automatically restarted when the <c>Inets</c> application is + restarted. As long as the <c>Inets</c> application is operational, + they are supervised and can be soft code upgraded.</p> + <p>A service started as <c>stand_alone</c>, that is, the service + is not started as part of the <c>Inets</c> application, + lose all OTP application benefits, such as soft upgrade. + The <c>stand_alone</c>-service is linked to + the process that started it. Usually some + supervision functionality is still in place and in + some sense the calling process becomes the top supervisor.</p> </note> @@ -167,19 +155,30 @@ </desc> </func> + <func> + <name>stop() -> ok </name> + <fsummary>Stops the <c>Inets</c> application.</fsummary> + <desc> + <p>Stops the <c>Inets</c> application. See also + <seealso marker="kernel:application">application(3)</seealso>.</p> + + <marker id="start2"></marker> + </desc> + </func> + <func> <name>stop(Service, Reference) -> ok | {error, Reason} </name> - <fsummary>Stops a started service of the inets application or takes - down a "stand_alone-service" gracefully.</fsummary> + <fsummary>Stops a started service of the <c>Inets</c> application or takes + down a <c>stand_alone </c>service gracefully.</fsummary> <type> <v>Service = service() | stand_alone</v> - <v>Reference = pid() | term() - service specified reference</v> + <v>Reference = pid() | term() - service-specified reference</v> <v>Reason = term()</v> </type> <desc> - <p>Stops a started service of the inets application or takes - down a "stand_alone-service" gracefully. When the - <c>stand_alone</c> option is used in start, + <p>Stops a started service of the <c>Inets</c> application or takes + down a <c>stand_alone</c>-service gracefully. When option + <c>stand_alone</c> is used in start, only the pid is a valid argument to stop.</p> <marker id="see_also"></marker> diff --git a/lib/inets/doc/src/inets_services.xml b/lib/inets/doc/src/inets_services.xml index f78485cb64..d100216ebb 100644 --- a/lib/inets/doc/src/inets_services.xml +++ b/lib/inets/doc/src/inets_services.xml @@ -22,7 +22,7 @@ </legalnotice> - <title>Introduction</title> + <title>Inets</title> <prepared>Ingela Anderton Andin</prepared> <responsible></responsible> <docno></docno> @@ -34,45 +34,26 @@ </header> <section> - <title>Purpose</title> - <p>Inets is a container for Internet clients and - servers. Currently, an <term id="HTTP"></term>client and server, a - TFPT client and server, and a FTP client has been incorporated - into Inets. The HTTP server and client is HTTP 1.1 compliant as - defined in <term id="RFC"></term>2616.</p> - </section> - - <section> - <title>Prerequisites</title> - <p>It is assumed that the reader is familiar with the Erlang - programming language, concepts of OTP and has a basic - understanding of the HTTP, TFTP and FTP protocols.</p> - </section> - - <section> - <title>The Service Concept</title> - <p>Each client and server in inets is viewed as service. Services - may be configured to be started at application startup or - started dynamically in runtime. If you want to run inets as an - distributed application that should handle application failover - and takeover, services should be configured to be started at - application startup. When starting the inets application - the inets top supervisor will start a number of subsupervisors - and worker processes for handling the different services - provided. When starting services dynamically new children will - be added to the supervision tree, unless the service is started - with the stand alone option, in which case the service is linked - to the calling process and all OTP application features such as - soft upgrade are lost.</p> - <p>Services that should be configured for startup at application - startup time should be put into the erlang node configuration file - on the form: </p> + <title>Service Concept</title> + <p>Each client and server in <c>Inets</c> is viewed as a service. + Services can be configured to be started at application startup or + dynamically in runtime. To run <c>Inets</c> as a distributed + application that handles application failover and takeover, + configure the services to be started at application startup. + When starting the <c>Inets</c> application, the <c>Inets</c> + top supervisor starts a number of subsupervisors and worker + processes for handling the provided services. + When starting services dynamically, new children are added to the + supervision tree, unless the service is started with the standalone + option. In this case the service is linked to the calling process + and all OTP application features, such as soft upgrade, are lost.</p> + <p>Services to be configured for startup at application startup are to + be put into the Erlang node configuration file + on the following form:</p> <pre> - [{inets, [{services, ListofConfiguredServices}]}]. - </pre> - <p>For details of exactly what to put in the list of configured - services see the documentation for the services that should be - configured.</p> + [{inets, [{services, ListofConfiguredServices}]}].</pre> + <p>For details of what to put in the list of configured services, + see the documentation for the services to be configured.</p> </section> </chapter> diff --git a/lib/inets/doc/src/introduction.xml b/lib/inets/doc/src/introduction.xml new file mode 100644 index 0000000000..491835f852 --- /dev/null +++ b/lib/inets/doc/src/introduction.xml @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1997</year><year>2013</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Introduction</title> + <prepared>Ingela Anderton Andin</prepared> + <responsible></responsible> + <docno></docno> + <approved></approved> + <checked></checked> + <date>2004-09-28</date> + <rev>A</rev> + <file>introduction.xml</file> + </header> + + <section> + <title>Purpose</title> + <p><c>Inets</c> is a container for Internet clients and servers + including the following:</p> + <list type="bulleted"> + <item>An FTP client</item> + <item>A TFTP client and server</item> + <item>An <term id="HTTP"></term> client and server</item> + </list> + <p>The HTTP client and server are HTTP 1.1 compliant as + defined in + <url href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</url>.</p> + </section> + + <section> + <title>Prerequisites</title> + <p>It is assumed that the reader is familiar with the Erlang + programming language, concepts of OTP, and has a basic + understanding of the FTP, TFTP, and HTTP protocols.</p> + </section> +</chapter> + + diff --git a/lib/inets/doc/src/mod_alias.xml b/lib/inets/doc/src/mod_alias.xml index d073b5c5b8..87c950cc6b 100644 --- a/lib/inets/doc/src/mod_alias.xml +++ b/lib/inets/doc/src/mod_alias.xml @@ -32,8 +32,8 @@ <module>mod_alias</module> <modulesummary>URL aliasing.</modulesummary> <description> - <p>Erlang Webserver Server internal API for handling of things - such as interaction data exported by the mod_alias module.</p> + <p>Erlang web server internal API for handling of, for example, + interaction data exported by module <c>mod_alias</c>.</p> <marker id="default_index"></marker> </description> @@ -41,7 +41,7 @@ <funcs> <func> <name>default_index(ConfigDB, Path) -> NewPath</name> - <fsummary>Return a new path with the default resource or file appended.</fsummary> + <fsummary>Returns a new path with the default resource or file appended.</fsummary> <type> <v>ConfigDB = config_db()</v> <v>Path = NewPath = string()</v> @@ -50,14 +50,14 @@ <marker id="default_index"></marker> <p>If <c>Path</c> is a directory, <c>default_index/2</c>, it starts searching for resources or files that are specified in the config - directive DirectoryIndex. + directive <c>DirectoryIndex</c>. If an appropriate resource or file is found, it is appended to the end of <c>Path</c> and then returned. <c>Path</c> is - returned unaltered, if no appropriate - file is found, or if <c>Path</c> is not a directory. + returned unaltered if no appropriate + file is found or if <c>Path</c> is not a directory. <c>config_db()</c> is the server config file in ETS table format as described in - <seealso marker="http_server">Inets Users Guide.</seealso>.</p> + <seealso marker="http_server">Inets User's Guide</seealso>.</p> <marker id="path"></marker> </desc> @@ -65,7 +65,7 @@ <func> <name>path(PathData, ConfigDB, RequestURI) -> Path</name> - <fsummary>Return the actual file path to a URL.</fsummary> + <fsummary>Returns the file path to a URL.</fsummary> <type> <v>PathData = interaction_data()</v> <v>ConfigDB = config_db()</v> @@ -73,15 +73,16 @@ </type> <desc> <marker id="path"></marker> - <p><c>path/3</c> returns the actual file <c>Path</c> in the - <c>RequestURI</c> (See RFC 1945). If the interaction data - <c>{real_name,{Path,AfterPath}}</c> has been exported by - mod_alias; + <p><c>path/3</c> returns the file <c>Path</c> in the + <c>RequestURI</c> (see + <url href="http://www.rfc-base.org/rfc-1945.html">RFC 1945</url>). + If the interaction data <c>{real_name,{Path,AfterPath}}</c> + has been exported by <c>mod_alias</c>, <c>Path</c> is returned. If no interaction data has been - exported, ServerRoot is used to + exported, <c>ServerRoot</c> is used to generate a file <c>Path</c>. <c>config_db()</c> and <c>interaction_data()</c> are as defined in - <seealso marker="http_server">Inets Users Guide</seealso>.</p> + <seealso marker="http_server">Inets User's Guide</seealso>.</p> <marker id="real_name"></marker> </desc> @@ -89,7 +90,7 @@ <func> <name>real_name(ConfigDB, RequestURI, Aliases) -> Ret</name> - <fsummary>Expand a request uri using Alias config directives.</fsummary> + <fsummary>Expands a request URI using <c>Aliases</c> config directives.</fsummary> <type> <v>ConfigDB = config_db()</v> <v>RequestURI = string()</v> @@ -101,18 +102,18 @@ <marker id="real_name"></marker> <p><c>real_name/3</c> traverses <c>Aliases</c>, typically extracted from <c>ConfigDB</c>, and matches each - <c>FakeName</c> with <c>RequestURI</c>. If a match is found + <c>FakeName</c> with <c>RequestURI</c>. If a match is found, <c>FakeName</c> is replaced with <c>RealName</c> in the - match. The resulting path is split into two parts, that - is <c>ShortPath</c> and <c>AfterPath</c> as defined in - <seealso marker="httpd_util#split_path">httpd_util:split_path/1</seealso>. - <c>Path</c> is generated from <c>ShortPath</c>, that is + match. The resulting path is split into two parts, + <c>ShortPath</c> and <c>AfterPath</c>, as defined in + <seealso marker="httpd_util#split_path-1">httpd_util:split_path/1</seealso>. + <c>Path</c> is generated from <c>ShortPath</c>, that is, the result from <seealso marker="#default_index">default_index/2</seealso> with <c>ShortPath</c> as an argument. <c>config_db()</c> is the server config file in ETS table format as described in - <seealso marker="http_server">Inets User Guide.</seealso>. </p> + <seealso marker="http_server">Inets User's Guide</seealso>.</p> <marker id="real_script_name"></marker> </desc> @@ -120,7 +121,8 @@ <func> <name>real_script_name(ConfigDB, RequestURI, ScriptAliases) -> Ret</name> - <fsummary>Expand a request uri using ScriptAlias config directives.</fsummary> + <fsummary>Expands a request URI using <c>ScriptAliases</c> + config directives.</fsummary> <type> <v>ConfigDB = config_db()</v> <v>RequestURI = string()</v> @@ -132,14 +134,16 @@ <marker id="real_script_name"></marker> <p><c>real_script_name/3</c> traverses <c>ScriptAliases</c>, typically extracted from <c>ConfigDB</c>, and matches each - <c>FakeName</c> with <c>RequestURI</c>. If a match is found + <c>FakeName</c> with <c>RequestURI</c>. If a match is found, <c>FakeName</c> is replaced with <c>RealName</c> in the - match. If the resulting match is not an executable script - <c>not_a_script</c> is returned. If it is a script the - resulting script path is in two parts, that is - <c>ShortPath</c> and <c>AfterPath</c> as defined in <seealso marker="httpd_util#split_script_path">httpd_util:split_script_path/1</seealso>. + match. If the resulting match is not an executable script, + <c>not_a_script</c> is returned. If it is a script, the + resulting script path is in two parts, + <c>ShortPath</c> and <c>AfterPath</c>, as defined in + <seealso marker="httpd_util#split_script_path-1">httpd_util:split_script_path/1</seealso>. <c>config_db()</c> is the server config file in ETS table - format as described in <seealso marker="http_server">Inets Users Guide.</seealso>.</p> + format as described in + <seealso marker="http_server">Inets User's Guide</seealso>.</p> </desc> </func> </funcs> diff --git a/lib/inets/doc/src/mod_auth.xml b/lib/inets/doc/src/mod_auth.xml index fda945cf73..2da2be37ed 100644 --- a/lib/inets/doc/src/mod_auth.xml +++ b/lib/inets/doc/src/mod_auth.xml @@ -30,299 +30,267 @@ <file>mod_auth.sgml</file> </header> <module>mod_auth</module> - <modulesummary>User authentication using text files, dets or mnesia database.</modulesummary> + <modulesummary>User authentication using text files, Dets, or Mnesia database.</modulesummary> <description> <p>This module provides for basic user authentication using - textual files, dets databases as well as mnesia databases. </p> - - <marker id="add_user"></marker> + textual files, <c>Dets</c> databases, or <c>Mnesia</c> databases.</p> </description> <funcs> + <func> + <name>add_group_member(GroupName, UserName, Options) -> true | {error, Reason}</name> + <name>add_group_member(GroupName, UserName, Port, Dir) -> true | {error, Reason}</name> + <name>add_group_member(GroupName, UserName, Address, Port, Dir) -> true | {error, Reason}</name> + <fsummary>Adds a user to a group.</fsummary> + <type> + <v>GroupName = string()</v> + <v>UserName = string()</v> + <v>Options = [Option]</v> + <v>Option = {port,Port} | {addr,Address} | {dir,Directory} | {authPassword,AuthPassword}</v> + <v>Port = integer()</v> + <v>Address = {A,B,C,D} | string() | undefined</v> + <v>Dir = string()</v> + <v>AuthPassword = string()</v> + <v>Reason = term()</v> + </type> + <desc> + <p><c>add_group_member/3, add_group_member/4</c>, and + <c>add_group_member/5</c> each + adds a user to a group. If the group does not exist, it + is created and the user is added to the group. Upon successful + operation, this function returns <c>true</c>. + When <c>add_group_members/3</c> + is called, options <c>Port</c> and <c>Dir</c> are mandatory.</p> + </desc> + </func> + <func> - <name>add_user(UserName, Options) -> true| {error, Reason}</name> + <name>add_user(UserName, Options) -> true| {error, Reason}</name> <name>add_user(UserName, Password, UserData, Port, Dir) -> true | {error, Reason}</name> <name>add_user(UserName, Password, UserData, Address, Port, Dir) -> true | {error, Reason}</name> - <fsummary>Add a user to the user database.</fsummary> + <fsummary>Adds a user to the user database.</fsummary> <type> - <v>UserName = string()</v> - <v>Options = [Option]</v> - <v>Option = {password,Password} | {userData,UserData} | {port,Port} | {addr,Address} | {dir,Directory} | {authPassword,AuthPassword}</v> - <v>Password = string()</v> - <v>UserData = term()</v> - <v>Port = integer()</v> - <v>Address = {A,B,C,D} | string() | undefined</v> - <v>Dir = string()</v> + <v>UserName = string()</v> + <v>Options = [Option]</v> + <v>Option = {password,Password} | {userData,UserData} | {port,Port} | {addr,Address} | {dir,Directory} | {authPassword,AuthPassword}</v> + <v>Password = string()</v> + <v>UserData = term()</v> + <v>Port = integer()</v> + <v>Address = {A,B,C,D} | string() | undefined</v> + <v>Dir = string()</v> <v>AuthPassword =string()</v> - <v>Reason = term()</v> + <v>Reason = term()</v> </type> <desc> - <marker id="user_api"></marker> - <marker id="add_user"></marker> - <p><c>add_user/2, add_user/5</c> and <c>add_user/6</c> adds a - user to the user - database. If the operation is successful, this function returns - <c>true</c>. If an error occurs, <c>{error,Reason}</c> is returned. - When <c>add_user/2</c> is called the Password, - UserData Port and Dir options is mandatory.</p> - - <marker id="delete_user"></marker> + <p><c>add_user/2, add_user/5</c>, and <c>add_user/6</c> each adds a + user to the user database. If the operation is successful, + this function returns <c>true</c>. If an error occurs, + <c>{error,Reason}</c> is returned. + When <c>add_user/2</c> is called, options <c>Password</c>, + <c>UserData</c>, <c>Port</c>, and <c>Dir</c> are mandatory.</p> </desc> </func> - <func> - <name>delete_user(UserName,Options) -> true | {error, Reason}</name> - <name>delete_user(UserName, Port, Dir) -> true | {error, Reason}</name> - <name>delete_user(UserName, Address, Port, Dir) -> true | {error, Reason}</name> - <fsummary>Delete a user from the user database.</fsummary> + <func> + <name>delete_group(GroupName, Options) -> true | {error,Reason} <name>delete_group(GroupName, Port, Dir) -> true | {error, Reason}</name> + <name>delete_group(GroupName, Address, Port, Dir) -> true | {error, Reason}</name> + <fsummary>Deletes a group.</fsummary> <type> - <v>UserName = string()</v> - <v>Options = [Option]</v> - <v>Option = {port,Port} | {addr,Address} | {dir,Directory} | {authPassword,AuthPassword}</v> - <v>Port = integer()</v> - <v>Address = {A,B,C,D} | string() | undefined</v> - <v>Dir = string()</v> + <v>Options = [Option]</v> + <v>Option = {port,Port} | {addr,Address} | {dir,Directory} | {authPassword,AuthPassword}</v> + <v>Port = integer()</v> + <v>Address = {A,B,C,D} | string() | undefined</v> + <v>Dir = string()</v> + <v>GroupName = string()</v> <v>AuthPassword = string()</v> - <v>Reason = term()</v> + <v>Reason = term()</v> </type> <desc> - <marker id="delete_user"></marker> - <p><c>delete_user/2, delete_user/3</c> and <c>delete_user/4</c> - deletes a user from the user database. - If the operation is successful, this function returns <c>true</c>. - If an error occurs, <c>{error,Reason}</c> is returned. - When <c>delete_user/2</c> is called the Port and Dir options - are mandatory.</p> - - <marker id="get_user"></marker> + <p><c>delete_group/2, delete_group/3</c>, and <c>delete_group/4</c> + each deletes the group specified and returns <c>true</c>. + If there is an error, <c>{error, Reason}</c> is returned. + When <c>delete_group/2</c> is called, option + <c>Port</c> and <c>Dir</c> are mandatory.</p> </desc> </func> - <func> - <name>get_user(UserName,Options) -> {ok, #httpd_user} |{error, Reason}</name> - <name>get_user(UserName, Port, Dir) -> {ok, #httpd_user} | {error, Reason}</name> - <name>get_user(UserName, Address, Port, Dir) -> {ok, #httpd_user} | {error, Reason}</name> - <fsummary>Returns a user from the user database.</fsummary> + <func> + <name>delete_group_member(GroupName, UserName, Options) -> true | {error, Reason}</name> + <name>delete_group_member(GroupName, UserName, Port, Dir) -> true | {error, Reason}</name> + <name>delete_group_member(GroupName, UserName, Address, Port, Dir) -> true | {error, Reason}</name> + <fsummary>Removes a user from a group.</fsummary> <type> - <v>UserName = string()</v> - <v>Options = [Option]</v> - <v>Option = {port,Port} | {addr,Address} | {dir,Directory} | {authPassword,AuthPassword}</v> - <v>Port = integer()</v> - <v>Address = {A,B,C,D} | string() | undefined</v> - <v>Dir = string()</v> + <v>GroupName = string()</v> + <v>UserName = string()</v> + <v>Options = [Option]</v> + <v>Option = {port,Port} | {addr,Address} | {dir,Directory} | {authPassword,AuthPassword}</v> + <v>Port = integer()</v> + <v>Address = {A,B,C,D} | string() | undefined</v> + <v>Dir = string()</v> <v>AuthPassword = string()</v> - <v>Reason = term()</v> + <v>Reason = term()</v> </type> <desc> - <marker id="get_user"></marker> - <p><c>get_user/2, get_user/3</c> and <c>get_user/4</c> returns a - <c>httpd_user</c> record containing the userdata for a - specific user. If the user cannot be found, <c>{error, Reason}</c> - is returned. When <c>get_user/2</c> is called the Port and Dir - options are mandatory.</p> - - <marker id="list_users"></marker> + <p><c>delete_group_member/3, delete_group_member/4</c>, and + <c>delete_group_member/5</c> each deletes a user from a group. + If the group or the user does not exist, + this function returns an error, otherwise <c>true</c>. + When <c>delete_group_member/3</c> is called, the options <c>Port</c> + and <c>Dir</c> are mandatory.</p> </desc> </func> - + <func> - <name>list_users(Options) -> {ok, Users} | {error, Reason}</name> - <name>list_users(Port, Dir) -> {ok, Users} | {error, Reason}</name> - <name>list_users(Address, Port, Dir) -> {ok, Users} | {error, Reason}</name> - <fsummary>List users in the user database.</fsummary> + <name>delete_user(UserName,Options) -> true | {error, Reason}</name> + <name>delete_user(UserName, Port, Dir) -> true | {error, Reason}</name> + <name>delete_user(UserName, Address, Port, Dir) -> true | {error, Reason}</name> + <fsummary>Deletes a user from the user database.</fsummary> <type> - <v>Options = [Option]</v> - <v>Option = {port,Port} | {addr,Address} | {dir,Directory} | {authPassword,AuthPassword}</v> - <v>Port = integer()</v> - <v>Address = {A,B,C,D} | string() | undefined</v> - <v>Dir = string()</v> - <v>Users = list()</v> + <v>UserName = string()</v> + <v>Options = [Option]</v> + <v>Option = {port,Port} | {addr,Address} | {dir,Directory} | {authPassword,AuthPassword}</v> + <v>Port = integer()</v> + <v>Address = {A,B,C,D} | string() | undefined</v> + <v>Dir = string()</v> <v>AuthPassword = string()</v> - <v>Reason = atom()</v> + <v>Reason = term()</v> </type> <desc> - <marker id="list_users"></marker> - <p><c>list_users/1, list_users/2</c> and <c>list_users/3</c> - returns a list - of users in the user database for a specific <c>Port/Dir</c>. - When <c>list_users/1</c> is called the Port and Dir - options are mandatory.</p> - - <marker id="add_group_member"></marker> + <p><c>delete_user/2, delete_user/3</c>, and <c>delete_user/4</c> + each deletes a user from the user database. + If the operation is successful, this function returns <c>true</c>. + If an error occurs, <c>{error,Reason}</c> is returned. + When <c>delete_user/2</c> is called, options <c>Port</c> and <c>Dir</c> + are mandatory.</p> </desc> </func> <func> - <name>add_group_member(GroupName, UserName, Options) -> true | {error, Reason}</name> - <name>add_group_member(GroupName, UserName, Port, Dir) -> true | {error, Reason}</name> - <name>add_group_member(GroupName, UserName, Address, Port, Dir) -> true | {error, Reason}</name> - <fsummary>Add a user to a group.</fsummary> + <name>get_user(UserName,Options) -> {ok, #httpd_user} |{error, Reason}</name> + <name>get_user(UserName, Port, Dir) -> {ok, #httpd_user} | {error, Reason}</name> + <name>get_user(UserName, Address, Port, Dir) -> {ok, #httpd_user} | {error, Reason}</name> + <fsummary>Returns a user from the user database.</fsummary> <type> - <v>GroupName = string()</v> - <v>UserName = string()</v> - <v>Options = [Option]</v> - <v>Option = {port,Port} | {addr,Address} | {dir,Directory} | {authPassword,AuthPassword}</v> - <v>Port = integer()</v> - <v>Address = {A,B,C,D} | string() | undefined</v> - <v>Dir = string()</v> + <v>UserName = string()</v> + <v>Options = [Option]</v> + <v>Option = {port,Port} | {addr,Address} | {dir,Directory} | {authPassword,AuthPassword}</v> + <v>Port = integer()</v> + <v>Address = {A,B,C,D} | string() | undefined</v> + <v>Dir = string()</v> <v>AuthPassword = string()</v> - <v>Reason = term()</v> + <v>Reason = term()</v> </type> <desc> - <marker id="add_group_member"></marker> - <p><c>add_group_member/3, add_group_member/4</c> and - <c>add_group_member/5</c> - adds a user to a group. If the group does not exist, it - is created and the user is added to the group. Upon successful - operation, this function returns <c>true</c>. - When <c>add_group_members/3</c> - is called the Port and Dir options are mandatory.</p> - - <marker id="delete_group_member"></marker> + <p><c>get_user/2, get_user/3</c>, and <c>get_user/4</c> each + returns an <c>httpd_user</c> record containing the userdata for a + specific user. If the user cannot be found, <c>{error, Reason}</c> + is returned. When <c>get_user/2</c> is called, options <c>Port</c> and <c>Dir</c> + are mandatory.</p> </desc> </func> - <func> - <name>delete_group_member(GroupName, UserName, Options) -> true | {error, Reason}</name> - <name>delete_group_member(GroupName, UserName, Port, Dir) -> true | {error, Reason}</name> - <name>delete_group_member(GroupName, UserName, Address, Port, Dir) -> true | {error, Reason}</name> - <fsummary>Remove a user from a group.</fsummary> + <func> + <name>list_groups(Options) -> {ok, Groups} | {error, Reason}</name> + <name>list_groups(Port, Dir) -> {ok, Groups} | {error, Reason}</name> + <name>list_groups(Address, Port, Dir) -> {ok, Groups} | {error, Reason}</name> + <fsummary>Lists all the groups.</fsummary> <type> - <v>GroupName = string()</v> - <v>UserName = string()</v> - <v>Options = [Option]</v> - <v>Option = {port,Port} | {addr,Address} | {dir,Directory} | {authPassword,AuthPassword}</v> - <v>Port = integer()</v> - <v>Address = {A,B,C,D} | string() | undefined</v> - <v>Dir = string()</v> + <v>Options = [Option]</v> + <v>Option = {port,Port} | {addr,Address} | {dir,Directory} | {authPassword,AuthPassword}</v> + <v>Port = integer()</v> + <v>Address = {A,B,C,D} | string() | undefined</v> + <v>Dir = string()</v> + <v>Groups = list()</v> <v>AuthPassword = string()</v> - <v>Reason = term()</v> + <v>Reason = term()</v> </type> <desc> - <marker id="delete_group_member"></marker> - <p><c>delete_group_member/3, delete_group_member/4</c> and - <c>delete_group_member/5</c> deletes a user from a group. - If the group or the user does not exist, - this function returns an error, otherwise it returns <c>true</c>. - When <c>delete_group_member/3</c> is called the Port and Dir options - are mandatory.</p> - - <marker id="list_group_members"></marker> + <p><c>list_groups/1, list_groups/2</c>, and <c>list_groups/3</c> + each lists all the groups available. + If there is an error, <c>{error, Reason}</c> is returned. + When <c>list_groups/1</c> is called, options <c>Port</c> + and <c>Dir</c> are mandatory.</p> </desc> </func> - + <func> <name>list_group_members(GroupName, Options) -> {ok, Users} | {error, Reason}</name> <name>list_group_members(GroupName, Port, Dir) -> {ok, Users} | {error, Reason}</name> <name>list_group_members(GroupName, Address, Port, Dir) -> {ok, Users} | {error, Reason}</name> - <fsummary>List the members of a group.</fsummary> + <fsummary>Lists the members of a group.</fsummary> <type> - <v>GroupName = string()</v> - <v>Options = [Option]</v> - <v>Option = {port,Port} | {addr,Address} | {dir,Directory} | {authPassword,AuthPassword}</v> - <v>Port = integer()</v> - <v>Address = {A,B,C,D} | string() | undefined</v> - <v>Dir = string()</v> - <v>Users = list()</v> + <v>GroupName = string()</v> + <v>Options = [Option]</v> + <v>Option = {port,Port} | {addr,Address} | {dir,Directory} | {authPassword,AuthPassword}</v> + <v>Port = integer()</v> + <v>Address = {A,B,C,D} | string() | undefined</v> + <v>Dir = string()</v> + <v>Users = list()</v> <v>AuthPassword = string()</v> - <v>Reason = term()</v> + <v>Reason = term()</v> </type> <desc> - <marker id="list_group_members"></marker> - <p><c>list_group_members/2, list_group_members/3</c> and - <c>list_group_members/4</c> + <p><c>list_group_members/2, list_group_members/3</c>, and + <c>list_group_members/4</c> each lists the members of a specified group. If the group does not exist or there is an error, <c>{error, Reason}</c> is returned. - When <c>list_group_members/2</c> is called the Port and Dir options - are mandatory.</p> - - <marker id="list_groups"></marker> + When <c>list_group_members/2</c> is called, options <c>Port</c> + and <c>Dir</c> are mandatory.</p> </desc> </func> - <func> - <name>list_groups(Options) -> {ok, Groups} | {error, Reason}</name> - <name>list_groups(Port, Dir) -> {ok, Groups} | {error, Reason}</name> - <name>list_groups(Address, Port, Dir) -> {ok, Groups} | {error, Reason}</name> - <fsummary>List all the groups.</fsummary> + <func> + <name>list_users(Options) -> {ok, Users} | {error, Reason}</name> + <name>list_users(Port, Dir) -> {ok, Users} | {error, Reason}</name> + <name>list_users(Address, Port, Dir) -> {ok, Users} | {error, Reason}</name> + <fsummary>Lists users in the user database.</fsummary> <type> - <v>Options = [Option]</v> - <v>Option = {port,Port} | {addr,Address} | {dir,Directory} | {authPassword,AuthPassword}</v> - <v>Port = integer()</v> - <v>Address = {A,B,C,D} | string() | undefined</v> - <v>Dir = string()</v> - <v>Groups = list()</v> + <v>Options = [Option]</v> + <v>Option = {port,Port} | {addr,Address} | {dir,Directory} | {authPassword,AuthPassword}</v> + <v>Port = integer()</v> + <v>Address = {A,B,C,D} | string() | undefined</v> + <v>Dir = string()</v> + <v>Users = list()</v> <v>AuthPassword = string()</v> - <v>Reason = term()</v> + <v>Reason = atom()</v> </type> <desc> - <marker id="list_groups"></marker> - <p><c>list_groups/1, list_groups/2</c> and <c>list_groups/3</c> - lists all the groups available. - If there is an error, <c>{error, Reason}</c> is returned. - When <c>list_groups/1</c> is called the Port and Dir options + <p><c>list_users/1, list_users/2</c>, and <c>list_users/3</c> + each returns a list + of users in the user database for a specific <c>Port/Dir</c>. + When <c>list_users/1</c> is called, options <c>Port</c> and <c>Dir</c> are mandatory.</p> - - <marker id="delete_group"></marker> </desc> </func> - - <func> - <name>delete_group(GroupName, Options) -> true | {error,Reason} <name>delete_group(GroupName, Port, Dir) -> true | {error, Reason}</name> - <name>delete_group(GroupName, Address, Port, Dir) -> true | {error, Reason}</name> - <fsummary>Deletes a group</fsummary> - <type> - <v>Options = [Option]</v> - <v>Option = {port,Port} | {addr,Address} | {dir,Directory} | {authPassword,AuthPassword}</v> - <v>Port = integer()</v> - <v>Address = {A,B,C,D} | string() | undefined</v> - <v>Dir = string()</v> - <v>GroupName = string()</v> - <v>AuthPassword = string()</v> - <v>Reason = term()</v> - </type> - <desc> - <marker id="delete_group"></marker> - <p><c>delete_group/2, delete_group/3</c> and <c>delete_group/4</c> - deletes the group specified and returns <c>true</c>. - If there is an error, <c>{error, Reason}</c> is returned. - When <c>delete_group/2</c> is called the - Port and Dir options are mandatory.</p> - - <marker id="update_password"></marker> - </desc> - </func> - + <func> <name>update_password(Port, Dir, OldPassword, NewPassword, NewPassword) -> ok | {error, Reason}</name> <name>update_password(Address,Port, Dir, OldPassword, NewPassword, NewPassword) -> ok | {error, Reason}</name> - <fsummary>Change the AuthAcessPassword</fsummary> + <fsummary>Changes <c>AuthAcessPassword</c>.</fsummary> <type> - <v>Port = integer()</v> - <v>Address = {A,B,C,D} | string() | undefined</v> - <v>Dir = string()</v> - <v>GroupName = string()</v> - <v>OldPassword = string()</v> - <v>NewPassword = string()</v> - <v>Reason = term()</v> + <v>Port = integer()</v> + <v>Address = {A,B,C,D} | string() | undefined</v> + <v>Dir = string()</v> + <v>GroupName = string()</v> + <v>OldPassword = string()</v> + <v>NewPassword = string()</v> + <v>Reason = term()</v> </type> <desc> - <marker id="update_password"></marker> - <p><c>update_password/5</c> and <c>update_password/6</c> - Updates the AuthAccessPassword for the specified directory. - If NewPassword is equal to "NoPassword" no password is requires to + <p><c>update_password/5</c> and <c>update_password/6</c> each + updates <c>AuthAccessPassword</c> for the specified directory. + If <c>NewPassword</c> is equal to "NoPassword", no password is required to change authorisation data. - If NewPassword is equal to "DummyPassword" no changes can be done + If <c>NewPassword</c> is equal to "DummyPassword", no changes can be done without changing the password first.</p> </desc> </func> </funcs> <section> - <marker id="see_also"></marker> <title>SEE ALSO</title> <p><seealso marker="httpd">httpd(3)</seealso>, - <seealso marker="mod_alias">mod_alias(3)</seealso>,</p> + <seealso marker="mod_alias">mod_alias(3)</seealso></p> </section> </erlref> diff --git a/lib/inets/doc/src/mod_esi.xml b/lib/inets/doc/src/mod_esi.xml index 8044f46242..c2fb60c416 100644 --- a/lib/inets/doc/src/mod_esi.xml +++ b/lib/inets/doc/src/mod_esi.xml @@ -23,26 +23,72 @@ </legalnotice> <title>mod_esi</title> - <prepared>Joakim Grebenö</prepared> - <docno></docno> - <date>1997-10-14</date> - <rev>2.2</rev> <file>mod_esi.sgml</file> </header> <module>mod_esi</module> - <modulesummary>Erlang Server Interface </modulesummary> + <modulesummary>Erlang Server Interface</modulesummary> <description> <p>This module defines the Erlang Server Interface (ESI) API. - It is a more efficient way of writing erlang scripts - for your Inets web server than writing them as common CGI scripts.</p> + It is a more efficient way of writing Erlang scripts + for your <c>Inets</c> web server than writing them as common CGI scripts.</p> <marker id="deliver"></marker> </description> + <section> + <title>DATA TYPES</title> + <p>The following data types are used in the functions for mod_esi:</p> + + <taglist> + <tag><c>env() = </c></tag> + <item> <p><c>{EnvKey()::atom(), Value::term()}</c></p> + </item> + + <p>Currently supported key value pairs</p> + <taglist> + + <tag><c>{server_software, string()}</c></tag> + <item><p>Indicates the inets version.</p></item> + + <tag><c>{server_name, string()}</c></tag> + <item><p>The local hostname. </p></item> + + <tag><c>{gateway_interface, string()}</c></tag> + <item><p>Legacy string used in CGI, just ignore.</p> </item> + + <tag><c>{server_protocol, string()}</c></tag> + <item><p> HTTP version, currently "HTTP/1.1"</p></item> + + <tag>{server_port, integer()}</tag> + <item><p>Servers port number.</p></item> + + <tag><c>{request_method, "GET | "PUT" | "DELETE | "POST" | "PATCH"}</c></tag> + + <tag><c>{remote_adress, inet:ip_address()} </c></tag> + <item><p>The clients ip address.</p></item> + + <tag><c>{peer_cert, undefined | no_peercert | DER:binary()</c></tag> + <item> + <p>For TLS connections where client certificates are used this will + be an ASN.1 DER-encoded X509-certificate as an Erlang binary. + If client certificates are not used the value will be <c>no_peercert</c>, + and if TLS is not used (HTTP or connection is lost due to network failure) + the value will be <c>undefined</c>. + </p></item> + + <tag><c>{script_name, string()}</c></tag> + <item><p>Request URI</p></item> + + <tag><c>{http_LowerCaseHTTPHeaderName, string()}</c></tag> + <item><p>example: {http_content_type, "text/html"}</p></item> + </taglist> + + </taglist> + <funcs> <func> <name>deliver(SessionID, Data) -> ok | {error, Reason}</name> - <fsummary>Sends Data back to client.</fsummary> + <fsummary>Sends <c>Data</c> back to client.</fsummary> <type> <v>SessionID = term()</v> <v>Data = string() | io_list() | binary()</v> @@ -53,75 +99,72 @@ <p>This function is <em>only</em> intended to be used from functions called by the Erl Scheme interface to deliver parts of the content to the user.</p> - <p>Sends data from a Erl Scheme script back to the client.</p> + <p>Sends data from an Erl Scheme script back to the client.</p> <note> - <p>Note that if any HTTP-header fields should be added by the - script they must be in the first call to deliver/2 and the - data in the call must be a string. Calls after the headers - are complete may contain binary data to reduce copying - overhead. Do not assume anything about the data type of - SessionID, the SessionID must be the value given as input to - the esi call back function that you implemented.</p> - </note> + <p>If any HTTP header fields are added by the + script, they must be in the first call to <c>deliver/2</c>, + and the data in the call must be a string. Calls after the headers + are complete can contain binary data to reduce copying + overhead. Do not assume anything about the data type of + <c>SessionID</c>. <c>SessionID</c> must be the value given + as input to the ESI callback function that you implemented.</p> + </note> </desc> </func> </funcs> - + </section> <section> <title>ESI Callback Functions</title> </section> <funcs> <func> <name>Module:Function(SessionID, Env, Input)-> _ </name> - <fsummary>Creates a dynamic web page and returns it chunk by chunk to the server process by calling mod_esi:deliver/2.</fsummary> + <fsummary>Creates a dynamic web page and returns it chunk by chunk + to the server process by calling <c>mod_esi:deliver/2</c>.</fsummary> <type> <v>SessionID = term()</v> - <v>Env = [EnvironmentDirectives] ++ ParsedHeader</v> - <v>EnvironmentDirectives = {Key,Value}</v> - <v>Key = query_string | content_length | server_software | gateway_interface | server_protocol | server_port | request_method | remote_addr | script_name</v> + <v>Env = env()</v> <v>Input = string()</v> </type> <desc> - <p>The <c>Module</c> must be found in the code path and export - <c>Function</c> with an arity of three. An erlScriptAlias must - also be set up in the configuration file for the Web server.</p> - <p>If the HTTP request is a 'post' request and a body is sent - then content_length will be the length of the posted - data. If 'get' is used query_string will be the data after - <em>?</em> in the url.</p> - <p>ParsedHeader is the HTTP request as a key value tuple - list. The keys in parsed header will be the in lower case.</p> - <p>SessionID is a identifier - the server uses when <c>deliver/2</c> is called; do not + <p><c>Module</c> must be found in the code path and export + <c>Function</c> with an arity of three. An <c>erlScriptAlias</c> must + also be set up in the configuration file for the web server.</p> + <p>If the HTTP request is a 'post' request and a body is sent, + <c>content_length</c> is the length of the posted + data. If 'get' is used, <c>query_string</c> is the data after + <em>?</em> in the URL.</p> + <p><c>ParsedHeader</c> is the HTTP request as a key-value tuple + list. The keys in <c>ParsedHeader</c> are in lower case.</p> + <p><c>SessionID</c> is an identifier + the server uses when <c>deliver/2</c> is called. Do not assume anything about the datatype.</p> - <p>Use this callback function to dynamically generate dynamic web - content. When a part of the page is generated send the - data back to the client through <c>deliver/2</c>. Note + <p>Use this callback function to generate dynamic web + content dynamically. When a part of the page is generated, send the + data back to the client through <c>deliver/2</c>. Notice that the first chunk of data sent to the client must at least contain all HTTP header fields that the response will generate. If the first chunk does not contain the - <em>End of HTTP header</em>, that is <c>"\r\n\r\n",</c> - the server will - assume that no HTTP header fields will be generated.</p> + <em>end of HTTP header</em>, that is, <c>"\r\n\r\n",</c> + the server assumes that no HTTP header fields will be generated.</p> </desc> </func> <func> <name>Module:Function(Env, Input)-> Response </name> - <fsummary>Creates a dynamic web page and return it as a list. This functions is deprecated and only kept for backwards compatibility.</fsummary> + <fsummary>Creates a dynamic web page and returns it as a list. + This function is deprecated and is only kept for backwards compatibility.</fsummary> <type> - <v>Env = [EnvironmentDirectives] ++ ParsedHeader</v> - <v>EnvironmentDirectives = {Key,Value}</v> - <v>Key = query_string | content_length | server_software | gateway_interface | server_protocol | server_port | request_method | remote_addr | script_name.</v> + <v>Env = env()</v> <v>Input = string()</v> <v>Response = string()</v> </type> <desc> - <p>This callback format consumes a lot of memory since the + <p>This callback format consumes much memory, as the whole response must be generated before it is sent to the - user. This function is deprecated and only kept for backwards + user. This function is deprecated and is only kept for backwards compatibility. - For new development Module:Function/3 should be used.</p> + For new development, use <c>Module:Function/3</c>.</p> </desc> </func> </funcs> diff --git a/lib/inets/doc/src/mod_security.xml b/lib/inets/doc/src/mod_security.xml index 467c68d364..9dc32b971b 100644 --- a/lib/inets/doc/src/mod_security.xml +++ b/lib/inets/doc/src/mod_security.xml @@ -35,24 +35,45 @@ <p>Security Audit and Trailing Functionality</p> </description> <funcs> + + <func> + <name>block_user(User, Port, Dir, Seconds) -> true | {error, Reason}</name> + <name>block_user(User, Address, Port, Dir, Seconds) -> true | {error, Reason}</name> + <fsummary>Blocks a user from access to a directory for a certain amount of time.</fsummary> + <type> + <v>User = string()</v> + <v>Port = integer()</v> + <v>Address = {A,B,C,D} | string() | undefined</v> + <v>Dir = string()</v> + <v>Seconds = integer() | infinity</v> + <v>Reason = no_such_directory</v> + </type> + <desc> + <p><c>block_user/4</c> and <c>block_user/5</c> each blocks the user + <c>User</c> from directory <c>Dir</c> for a specified + amount of time.</p> + </desc> + </func> + <func> <name>list_auth_users(Port) -> Users | []</name> <name>list_auth_users(Address, Port) -> Users | []</name> <name>list_auth_users(Port, Dir) -> Users | []</name> <name>list_auth_users(Address, Port, Dir) -> Users | []</name> - <fsummary>List users that have authenticated within the SecurityAuthTimeout time for a given address (if specified), port number and directory (if specified).</fsummary> + <fsummary>Lists users that have authenticated within the <c>SecurityAuthTimeout</c> + time for a given address (if specified), port number, and directory + (if specified).</fsummary> <type> - <v>Port = integer()</v> + <v>Port = integer()</v> <v>Address = {A,B,C,D} | string() | undefined</v> - <v>Dir = string()</v> - <v>Users = list() = [string()]</v> + <v>Dir = string()</v> + <v>Users = list() = [string()]</v> </type> <desc> - <marker id="list_auth_users"></marker> - <p><c>list_auth_users/1</c>, <c>list_auth_users/2</c> and - <c>list_auth_users/3</c> returns a list of users that are + <p><c>list_auth_users/1</c>, <c>list_auth_users/2</c>, and + <c>list_auth_users/3</c> each returns a list of users that are currently authenticated. Authentications are stored for - SecurityAuthTimeout seconds, and are then discarded.</p> + <c>SecurityAuthTimeout</c> seconds, and then discarded.</p> </desc> </func> <func> @@ -60,96 +81,83 @@ <name>list_blocked_users(Address, Port) -> Users | []</name> <name>list_blocked_users(Port, Dir) -> Users | []</name> <name>list_blocked_users(Address, Port, Dir) -> Users | []</name> - <fsummary>List users that are currently blocked from access to a specified port number, for a given address (if specified).</fsummary> + <fsummary>Lists users that are currently blocked from access to a + specified port number, for a given address (if specified).</fsummary> <type> - <v>Port = integer()</v> + <v>Port = integer()</v> <v>Address = {A,B,C,D} | string() | undefined</v> - <v>Dir = string()</v> - <v>Users = list() = [string()]</v> + <v>Dir = string()</v> + <v>Users = list() = [string()]</v> </type> <desc> - <marker id="list_blocked_users"></marker> - <p><c>list_blocked_users/1</c>, <c>list_blocked_users/2</c> and - <c>list_blocked_users/3</c> returns a list of users that are + <p><c>list_blocked_users/1</c>, <c>list_blocked_users/2</c>, and + <c>list_blocked_users/3</c> each returns a list of users that are currently blocked from access.</p> </desc> </func> + <func> - <name>block_user(User, Port, Dir, Seconds) -> true | {error, Reason}</name> - <name>block_user(User, Address, Port, Dir, Seconds) -> true | {error, Reason}</name> - <fsummary>Block user from access to a directory for a certain amount of time.</fsummary> - <type> - <v>User = string()</v> - <v>Port = integer()</v> - <v>Address = {A,B,C,D} | string() | undefined</v> - <v>Dir = string()</v> - <v>Seconds = integer() | infinity</v> - <v>Reason = no_such_directory</v> - </type> - <desc> - <marker id="block_user"></marker> - <p><c>block_user/4</c> and <c>block_user/5</c> blocks the user - <c>User</c> from the directory <c>Dir</c> for a specified - amount of time.</p> - </desc> - </func> - <func> - <name>unblock_user(User, Port) -> true | {error, Reason}</name> + <name>unblock_user(User, Port) -> true | {error, Reason}</name> <name>unblock_user(User, Address, Port) -> true | {error, Reason}</name> - <name>unblock_user(User, Port, Dir) -> true | {error, Reason}</name> + <name>unblock_user(User, Port, Dir) -> true | {error, Reason}</name> <name>unblock_user(User, Address, Port, Dir) -> true | {error, Reason}</name> - <fsummary>Remove a blocked user from the block list</fsummary> + <fsummary>Removes a blocked user from the block list.</fsummary> <type> - <v>User = string()</v> - <v>Port = integer()</v> + <v>User = string()</v> + <v>Port = integer()</v> <v>Address = {A,B,C,D} | string() | undefined</v> - <v>Dir = string()</v> + <v>Dir = string()</v> <v>Reason = term()</v> </type> <desc> - <marker id="unblock_user"></marker> - <p><c>unblock_user/2</c>, <c>unblock_user/3</c> and - <c>unblock_user/4</c> removes the user <c>User</c> from - the list of blocked users for the Port (and Dir) specified.</p> + <p><c>unblock_user/2</c>, <c>unblock_user/3</c>, and + <c>unblock_user/4</c> each removes the user <c>User</c> from + the list of blocked users for <c>Port</c> (and <c>Dir</c>).</p> </desc> </func> </funcs> <section> <marker id="callback_module"></marker> - <title>The SecurityCallbackModule</title> - <p>The SecurityCallbackModule is a user written module that can receive - events from the mod_security Erlang Webserver API module. - This module only exports the function(s), - <seealso marker="#callback_module_event">event/4,5</seealso>, - which are described below. + <title>SecurityCallbackModule</title> + <p>The <c>SecurityCallbackModule</c> is a user-written module that can receive + events from the <c>mod_security</c> Erlang web server API module. + This module only exports the functions event/[4,5] + which are described here. </p> </section> <funcs> <func> - <name>event(What, Port, Dir, Data) -> ignored</name> - <name>event(What, Address, Port, Dir, Data) -> ignored</name> - <fsummary>This function is called whenever an event occurs in mod_security</fsummary> + <name>Module:event(What, Port, Dir, Data) -> ignored</name> + <name>Module:event(What, Address, Port, Dir, Data) -> ignored</name> + <fsummary>Called whenever an event occurs in <c>mod_security</c>.</fsummary> <type> - <v>What = atom()</v> - <v>Port = integer()</v> + <v>What = atom()</v> + <v>Port = integer()</v> <v>Address = {A,B,C,D} | string() <v>Dir = string()</v> - <v>Data = [Info]</v> - <v>Info = {Name, Value}</v> + <v>Data = [Info]</v> + <v>Info = {Name, Value}</v> </type> <desc> <marker id="callback_module_event"></marker> - <p><c>event/4</c> or <c>event/4</c> is called whenever an event - occurs in the mod_security Erlang Webserver API module (<c>event/4</c> is - called if Address is undefined and <c>event/5</c> otherwise). - The <c>What</c> argument specifies the type of event that has - occurred, and should be one of the following reasons; - <c>auth_fail</c> (a failed user authentication), - <c>user_block</c> (a user is being blocked from access) or - <c>user_unblock</c> (a user is being removed from the block list).</p> + <p><c>event/4</c> or <c>event/5</c> is called whenever an event + occurs in the <c>mod_security</c> Erlang web server API module. + (<c>event/4</c> is called if <c>Address</c> is undefined, + otherwise <c>event/5</c>. + Argument <c>What</c> specifies the type of event that has + occurred and is one of the following reasons: + </p> + <taglist> + <tag><c>auth_fail</c></tag> + <item><p>A failed user authentication.</p></item> + <tag><c>user_block</c></tag> + <item><p>A user is being blocked from access.</p></item> + <tag><c>user_unblock</c></tag> + <item><p>A user is being removed from the block list.</p></item> + </taglist> <note> - <p>Note that the <c>user_unblock</c> event is not triggered when + <p>The event <c>user_unblock</c> is not triggered when a user is removed from the block list explicitly using the <c>unblock_user</c> function.</p> </note> diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml index d1bfa28013..6593be02dc 100644 --- a/lib/inets/doc/src/notes.xml +++ b/lib/inets/doc/src/notes.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2002</year><year>2014</year> + <year>2002</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -33,7 +33,309 @@ <file>notes.xml</file> </header> - <section><title>Inets 6.0</title> + <section><title>Inets 6.2.4</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Handle multiple \t in mime types file</p> + <p> + Own Id: OTP-13663 Aux Id: seq13132 </p> + </item> + </list> + </section> + +</section> + +<section><title>Inets 6.2.3</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Put back unused module inets_regexp and remove it in OTP + 19 instead as it is an incompatibility, although it is an + undocumented module and should not affect other + applications.</p> + <p> + Own Id: OTP-13533</p> + </item> + </list> + </section> + +</section> + +<section><title>Inets 6.2.2</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Add environment information item peer_cert to mod_esi</p> + <p> + Own Id: OTP-13510</p> + </item> + </list> + </section> + +</section> + +<section><title>Inets 6.2.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Mend ipv6_host_with_brackets option in httpc</p> + <p> + Own Id: OTP-13417</p> + </item> + </list> + </section> + +</section> + +<section><title>Inets 6.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The TFTP client/server has been fixed to allow file sizes + larger than 32MB block by allowing the 16 bit block + counter to wrap. Since this is a commonly accepted + behavior we regard it as a bug fix.</p> + <p> + Own Id: OTP-13403</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Handle HTTP PATCH method in client.</p> + <p> + Own Id: OTP-13286</p> + </item> + <item> + <p> + Expected termination should not be logged as an + application error.</p> + <p> + Own Id: OTP-13389</p> + </item> + </list> + </section> + +</section> + +<section><title>Inets 6.1.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + mod_alias now traverses all aliases picking the longest + match and not the first match.</p> + <p> + Own Id: OTP-13248</p> + </item> + </list> + </section> + +</section> + +<section><title>Inets 6.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Replace obs-folds with spaces instead of failing</p> + <p> + Own Id: OTP-13069</p> + </item> + <item> + <p> + Add validation fun for URI scheme to http_uri API</p> + <p> + Own Id: OTP-13071</p> + </item> + <item> + <p> + Handle stream bodies as documented.</p> + <p> + Own Id: OTP-13093</p> + </item> + <item> + <p> + Correct error handling of mod_esi generated chunks. Send + warning headers in chunk trailers instead of generating + an unexpected additional 500 request response, when + problems, such as a timeout occurs.</p> + <p> + Own Id: OTP-13110</p> + </item> + <item> + <p> + HTTP client terminates gracefully when an invalid chunked + length header is encountered.</p> + <p> + Own Id: OTP-13117</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Add default for SNI (Server Name Indication) when running + https using the inets HTTP-client.</p> + <p> + Own Id: OTP-12985</p> + </item> + <item> + <p> + Be forgiving to chunked sizes that have trailing + whitespaces as prior implementation was. Also some legacy + embedded devices does actually have trailing whitespaces + even though this in not according to the spec.</p> + <p> + Own Id: OTP-13116</p> + </item> + </list> + </section> + +</section> + +<section><title>Inets 6.0.3</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Improved error handling and gracfully termination when an + invalid chunked length header is encountered.</p> + <p> + Own Id: OTP-13061</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Add possibility to set socket options, such as nodelay, + for httpd. Also phase out legacy option value inet6bf4 + for the ipfamily option. This value will be translated to + the value inet.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-13062</p> + </item> + </list> + </section> + +</section> + +<section><title>Inets 6.0.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Avoid crash in mod_auth_server and mod_security_server + due to using an atom instead of a string when creating a + name.</p> + <p> + Own Id: OTP-13022</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Add function response_default_headers/0 to httpd + customize API, to allow user to specify default values + for HTTP response headers.</p> + <p> + Own Id: OTP-13013</p> + </item> + </list> + </section> + +</section> + +<section><title>Inets 6.0.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix broken socket feature, that is on Linux systems a + socket may be opened before starting Erlang and then + passed to Erlang's httpd daemon. This is useful as the + wrap program can open a privileged port and Erlang does + not have to be run as root.</p> + <p> + Own Id: OTP-12875 Aux Id: seq12878 </p> + </item> + <item> + <p> + Fix broken socket feature, that is on Linux systems a + socket may be opened before starting Erlang and then + passed to Erlangs tftp daemon. This is useful as the wrap + program can open a privileged port and Erlang does not + have to be run as root.</p> + <p> + Own Id: OTP-12898 Aux Id: seq12900 </p> + </item> + <item> + <p> + httpc_handler should react properly to cancel requests + even when the request to be canceled was already finished + but httpc_manager did not get notified about that yet.</p> + <p> + Own Id: OTP-12922</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Added format_status function to httpd process to avoid + sensitive information to be printed in supervisor logs.</p> + <p> + Own Id: OTP-12976</p> + </item> + <item> + <p> + Return meaningful error reason disregarding whether a + http proxy is used or not.</p> + <p> + Own Id: OTP-12984</p> + </item> + </list> + </section> + +</section> + +<section><title>Inets 6.0</title> <section><title>Fixed Bugs and Malfunctions</title> <list> @@ -765,9 +1067,9 @@ <p>Better handling of errorI(s) during update of the session database. </p> <p>Also added and updated some debugging functions - <seealso marker="httpc#which_sessions">which_sessions/10,1</seealso> + <seealso marker="httpc#which_sessions-0">which_sessions/[0,1]</seealso> and - <seealso marker="httpc#info">info/0</seealso>. </p> + <seealso marker="httpc#info-0">info/0</seealso>. </p> <p>Own Id: OTP-10093</p> <p>Aux Id: Seq 12062</p> </item> @@ -861,7 +1163,7 @@ <item> <p>[httpc] Add function for retrieving current options, - <seealso marker="httpc#get_options">get_options/1,2</seealso>. </p> + <seealso marker="httpc#get_options-1">get_options/[1,2]</seealso>. </p> <p>Own Id: OTP-9979</p> </item> @@ -1038,15 +1340,11 @@ <section> <title>Incompatibilities</title> -<!-- - <p>-</p> ---> - <list> <item> <p>[httpc] Deprecated interface module <c>http</c> has been removed. It has (long) been replaced by http client interface module - <seealso marker="httpc#">httpc</seealso>. </p> + <seealso marker="httpc">httpc</seealso>. </p> <p>Own Id: OTP-9359</p> </item> @@ -1234,15 +1532,13 @@ <section><title>Inets 5.6</title> <section><title>Improvements and New Features</title> -<!-- - <p>-</p> ---> + <list> <item> <p>[httpc] Add support for upload body streaming (PUT and POST).</p> <p>For more info, see the definition of the <c>Body</c> argument of the - <seealso marker="httpc#request2">request/4,5</seealso> + <seealso marker="httpc#request-4">request/[4,5]</seealso> function. </p> <p>Filipe David Manana</p> <p>Own Id: OTP-9094</p> @@ -1255,7 +1551,7 @@ <item> <p>[httpd] - <seealso marker="mod_esi#deliver">mod_esi:deliver/2</seealso> + <seealso marker="mod_esi#deliver-2">mod_esi:deliver/2</seealso> made to accept binary data. </p> <p>Bernard Duggan</p> <p>Own Id: OTP-9123</p> @@ -1283,7 +1579,7 @@ for using file descriptors has been improved. It is now possible to add the file descriptor to the config (option fd) when calling the - <seealso marker="inets#start2">inets:start(httpd, ...)</seealso> + <seealso marker="inets#start-2">inets:start(httpd, ...)</seealso> function. </p> <p>Attila Rajmund Nohl</p> <p>Own Id: OTP-9202</p> @@ -1297,7 +1593,7 @@ <p>See the httpd <seealso marker="httpd#props_comm">socket_type</seealso> communication property or the httpc - <seealso marker="httpc#request2">request/4,5</seealso> function + <seealso marker="httpc#request-4">request/[4,5]</seealso> function for more info. </p> <p>Own Id: OTP-9230</p> <p>*** POTENTIAL INCOMPATIBILITY ***</p> @@ -1497,7 +1793,7 @@ <p>[httpc|httpd] - Now allow the use of the "new" ssl, by using the <c>essl</c> tag instead. </p> <p>See the <c>http_option</c> option in the - <seealso marker="httpc#request2">request/4,5</seealso> or + <seealso marker="httpc#request-4">request/[4,5]</seealso> or the <seealso marker="httpd#props_comm">socket-type</seealso> section of the Communication properties chapter for more info, </p> <p>Own Id: OTP-7907</p> @@ -1692,23 +1988,21 @@ <item> <p>[httpd] - Issues with ESI erl_script_timeout. </p> - <p> - <list type="bulleted"> - <item> - <p>The <c>erl_script_timeout</c> config option is ducumented - as a number of seconds. But when parsing the config, in the - new format (not a config file), it was handled as if in - number of milliseconds. </p> - </item> - <item> - <p>When the erl-script-timeout time was exceeded, the server - incorrectly marked the answer as sent, thereby leaving - client hanging (with an incomplete answer). - This has been changed, so that now the socket will be - closed. </p> - </item> - </list> - </p> + <list type="bulleted"> + <item> + <p>The <c>erl_script_timeout</c> config option is ducumented + as a number of seconds. But when parsing the config, in the + new format (not a config file), it was handled as if in + number of milliseconds. </p> + </item> + <item> + <p>When the erl-script-timeout time was exceeded, the server + incorrectly marked the answer as sent, thereby leaving + client hanging (with an incomplete answer). + This has been changed, so that now the socket will be + closed. </p> + </item> + </list> <p>Own Id: OTP-8509</p> </item> </list> @@ -1729,8 +2023,8 @@ <p>[httpc] - Allow users to pass socket options to the transport module when making requests. </p> <p>See the <c>socket_opts</c> option in the - <seealso marker="httpc#request2">request/4</seealso> or - <seealso marker="httpc#set_options">set_options/1,2</seealso> + <seealso marker="httpc#request-4">request/4</seealso> or + <seealso marker="httpc#set_options-1">set_options/[1,2]</seealso> for more info, </p> <p>Own Id: OTP-8352</p> </item> @@ -1771,7 +2065,7 @@ deliver an async reply to more receivers then the calling process. </p> <p>See the - <seealso marker="httpc#request2">receiver</seealso> + <seealso marker="httpc#request-2">receiver</seealso> option for more info, </p> <p>Own Id: OTP-8106</p> </item> @@ -1784,20 +2078,19 @@ <item> <p>[httpc] Several more or less critical fixes:</p> - <p> - <list type="bulleted"> - <item> - <p>Initial call between the httpc manager and request - handler was synchronous. </p> - <p>When the manager starts a new request handler, - this is no longer a synchronous operation. Previously, - the new request handler made the connection to the - server and issuing of the first request (the reason - for starting it) in the gen_server init function. - If the connection for some reason "took some time", - the manager hanged, leaving all other activities by - that manager also hanging. </p> - </item> + <list type="bulleted"> + <item> + <p>Initial call between the httpc manager and request + handler was synchronous. </p> + <p>When the manager starts a new request handler, + this is no longer a synchronous operation. Previously, + the new request handler made the connection to the + server and issuing of the first request (the reason + for starting it) in the gen_server init function. + If the connection for some reason "took some time", + the manager hanged, leaving all other activities by + that manager also hanging. </p> + </item> <!-- <item> <p>Copying of data between processes</p> @@ -1808,8 +2101,7 @@ <p>TBD</p> </item> --> - </list> - </p> + </list> <p>As a side-effect of these changes, some modules was also renamed, and a new api module, <seealso marker="httpc">httpc</seealso>, has been introduced @@ -2040,7 +2332,7 @@ request, when the client connects to the server. Default value is that of the <c>timeout</c> option. </p> <p>See the - <seealso marker="httpc#request2">request/4,5</seealso> + <seealso marker="httpc#request-4">request/[4,5]</seealso> function for more info. </p> <p>Own Id: OTP-7298</p> <!-- <p>Aux Id: seq11086</p> --> @@ -2147,7 +2439,7 @@ the client connects to the server. </p> <p>As a side-effect of this, the option <c>ipv6</c> has been removed and replaced by the <c>ipfamily</c> option. </p> - <p>See <seealso marker="httpc#set_options">http:set_options/1,2</seealso> + <p>See <seealso marker="httpc#set_options-1">http:set_options/[1,2]</seealso> for more info. </p> <p>*** POTENTIAL INCOMPATIBILITY ***</p> <p>Own Id: OTP-8004</p> diff --git a/lib/inets/doc/src/part.xml b/lib/inets/doc/src/part.xml index 1640ff507c..3b817eecf2 100644 --- a/lib/inets/doc/src/part.xml +++ b/lib/inets/doc/src/part.xml @@ -30,10 +30,18 @@ <file>part.sgml</file> </header> <description> - <p>The <em>Inets Application </em> provides a set of Internet - related services. Currently supported are a HTTP client, a HTTP - server a FTP client and a TFTP client and server.</p> + <p>The <c>Inets</c> application provides a set of + Internet-related services as follows:</p> + <list type="bulleted"> + <item>An FTP client</item> + <item>A TFTP client and server</item> + <item>An <term id="HTTP"></term> client and server</item> + </list> + <p>The HTTP client and server are HTTP 1.1 compliant as + defined in + <url href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</url>.</p> </description> + <xi:include href="introduction.xml"/> <xi:include href="inets_services.xml"/> <xi:include href="ftp_client.xml"/> <xi:include href="http_client.xml"/> diff --git a/lib/inets/doc/src/ref_man.xml b/lib/inets/doc/src/ref_man.xml index bcebcc0fd4..27021ea09a 100644 --- a/lib/inets/doc/src/ref_man.xml +++ b/lib/inets/doc/src/ref_man.xml @@ -30,16 +30,15 @@ <file>ref_man.xml</file> </header> <description> - <p>Inets is a container for Internet clients and - servers. Currently a FTP client, a HTTP client and server, and - a tftp client and server has been incorporated in Inets.</p> + <p><c>Inets</c> is a container for Internet clients and + servers. An FTP client, an HTTP client and server, and + a TFTP client and server are incorporated in <c>Inets</c>.</p> </description> <xi:include href="inets.xml"/> <xi:include href="ftp.xml"/> <xi:include href="tftp.xml"/> <xi:include href="httpc.xml"/> <xi:include href="httpd.xml"/> - <xi:include href="httpd_conf.xml"/> <xi:include href="httpd_custom_api.xml"/> <xi:include href="httpd_socket.xml"/> <xi:include href="httpd_util.xml"/> diff --git a/lib/inets/doc/src/tftp.xml b/lib/inets/doc/src/tftp.xml index e70712fd1e..10398f5088 100644 --- a/lib/inets/doc/src/tftp.xml +++ b/lib/inets/doc/src/tftp.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2006</year><year>2013</year> + <year>2006</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -29,173 +29,170 @@ <rev></rev> </header> <module>tftp</module> - <modulesummary>Trivial FTP</modulesummary> + <modulesummary>Trivial FTP.</modulesummary> <description> <p>This is a complete implementation of the following IETF standards:</p> <list type="bulleted"> - <item>RFC 1350, The TFTP Protocol (revision 2).</item> - <item>RFC 2347, TFTP Option Extension.</item> - <item>RFC 2348, TFTP Blocksize Option.</item> - <item>RFC 2349, TFTP Timeout Interval and Transfer Size Options.</item> + <item>RFC 1350, The TFTP Protocol (revision 2)</item> + <item>RFC 2347, TFTP Option Extension</item> + <item>RFC 2348, TFTP Blocksize Option</item> + <item>RFC 2349, TFTP Timeout Interval and Transfer Size Options</item> </list> - <p>The only feature that not is implemented in this release is + <p>The only feature that not is implemented is the "netascii" transfer mode.</p> <p>The <seealso marker="#start/1">start/1</seealso> function starts - a daemon process which listens for UDP packets on a port. When it - receives a request for read or write it spawns a temporary server - process which handles the actual transfer of the file.</p> - <p>On the client side - the <seealso marker="#read_file/3">read_file/3</seealso> + a daemon process listening for UDP packets on a port. When it + receives a request for read or write, it spawns a temporary server + process handling the transfer.</p> + <p>On the client side, + function <seealso marker="#read_file/3">read_file/3</seealso> and <seealso marker="#write_file/3">write_file/3</seealso> - functions spawns a temporary client process which establishes - contact with a TFTP daemon and performs the actual transfer of - the file.</p> - <p><c>tftp</c> uses a callback module to handle the actual file + spawn a temporary client process establishing + contact with a TFTP daemon and perform the file transfer.</p> + <p><c>tftp</c> uses a callback module to handle the file transfer. Two such callback modules are provided, <c>tftp_binary</c> and <c>tftp_file</c>. See <seealso marker="#read_file/3">read_file/3</seealso> and - <seealso marker="#write_file/3">write_file/3</seealso> for - more information about these. The user can also implement own - callback modules, see <seealso marker="#tftp_callback">CALLBACK FUNCTIONS</seealso> below. A callback module provided by - the user is registered using the <c>callback</c> option, see - <seealso marker="#options">DATA TYPES</seealso> below.</p> + <seealso marker="#write_file/3">write_file/3</seealso> for details. + You can also implement your own callback modules, see + <seealso marker="#tftp_callback">CALLBACK FUNCTIONS</seealso>. + A callback module provided by + the user is registered using option <c>callback</c>, see + <seealso marker="#options">DATA TYPES</seealso>.</p> </description> <section> - <title>TFTP SERVER SERVICE START/STOP </title> + <title>TFTP SERVER SERVICE START/STOP</title> <p>A TFTP server can be configured to start statically when starting - the Inets application. Alternatively it can be started dynamically - (when Inets already is started) by calling the Inets application API - <c>inets:start(tftpd, ServiceConfig)</c>, or + the <c>Inets</c> application. Alternatively, it can be started dynamically + (when <c>Inets</c> is already started) by calling the <c>Inets</c> application + API <c>inets:start(tftpd, ServiceConfig)</c> or <c>inets:start(tftpd, ServiceConfig, How)</c>, see <seealso marker="inets">inets(3)</seealso> for details. - The <c>ServiceConfig</c> for TFTP is described below in - the <seealso marker="#options">COMMON DATA TYPES</seealso> + The <c>ServiceConfig</c> for TFTP is described in + the <seealso marker="#options">DATA TYPES</seealso> section.</p> <p>The TFTP server can be stopped using <c>inets:stop(tftpd, Pid)</c>, see <seealso marker="inets">inets(3)</seealso> for details.</p> <p>The TPFT client is of such a temporary nature that it is not - handled as a service in the Inets service framework.</p> + handled as a service in the <c>Inets</c> service framework.</p> </section> <section> <marker id="options"></marker> - <title>COMMON DATA TYPES</title> - <pre> - ServiceConfig = Options - Options = [option()] - option() -- see below - </pre> + <title>DATA TYPES</title> + <p><c>ServiceConfig = Options</c></p> + <p><c>Options = [option()]</c></p> <p>Most of the options are common for both the client and the server - side, but some of them differs a little. Here are the available - options:</p> + side, but some of them differs a little. + The available <c>option()</c>s are as follows:</p> <taglist> <tag><c>{debug, Level}</c></tag> <item> <p><c>Level = none | error | warning | brief | normal | verbose | all</c></p> - <p>Controls the level of debug printouts. The default is - <c>none</c>.</p> + <p>Controls the level of debug printouts. + Default is <c>none</c>.</p> </item> <tag><c>{host, Host}</c></tag> <item> - <p><c>Host = hostname()</c> see - <seealso marker="kernel:inet">inet(3)</seealso></p> + <p><c>Host = hostname()</c>, see + <seealso marker="kernel:inet">inet(3)</seealso>.</p> <p>The name or IP address of the host where the TFTP daemon resides. This option is only used by the client.</p> </item> <tag><c>{port, Port}</c></tag> <item> <p><c>Port = int()</c></p> - <p>The TFTP port where the daemon listens. It defaults to - the standardized number 69. On the server side it may - sometimes make sense to set it to 0, which means that - the daemon just will pick a free port (which one is - returned by the <c>info/1</c> function).</p> - <p>If a socket has somehow already has been connected, the - {udp, [{fd, integer()}]} option can be used to pass the - open file descriptor to gen_udp. This can be automated - a bit by using a command line argument stating the + <p>The TFTP port where the daemon listens. Defaults is + the standardized number 69. On the server side, it can + sometimes make sense to set it to 0, meaning that + the daemon just picks a free port (which one is + returned by function <c>info/1</c>).</p> + <p>If a socket is connected already, option + <c>{udp, [{fd, integer()}]}</c> can be used to pass the + open file descriptor to <c>gen_udp</c>. This can be automated + by using a command-line argument stating the prebound file descriptor number. For example, if the - Port is 69 and the file descriptor 22 has been opened by - setuid_socket_wrap. Then the command line argument - "-tftpd_69 22" will trigger the prebound file + port is 69 and file descriptor 22 is opened by + <c>setuid_socket_wrap</c>, the command-line argument + "-tftpd_69 22" triggers the prebound file descriptor 22 to be used instead of opening port 69. - The UDP option {udp, [{fd, 22}]} automatically be added. - See init:get_argument/ about command line arguments and - gen_udp:open/2 about UDP options.</p> + The UDP option <c>{udp, [{fd, 22}]}</c> is automatically added. + See <c>init:get_argument/</c> about command-line arguments and + <c>gen_udp:open/2</c> about UDP options.</p> </item> <tag><c>{port_policy, Policy}</c></tag> <item> - <p><c>Policy = random | Port | {range, MinPort, MaxPort}</c> <br></br> -<c>Port = MinPort = MaxPort = int()</c></p> - <p>Policy for the selection of the temporary port which is used - by the server/client during the file transfer. It defaults to - <c>random</c> which is the standardized policy. With this - policy a randomized free port used. A single port or a range - of ports can be useful if the protocol should pass through a + <p><c>Policy = random | Port | {range, MinPort, MaxPort}</c></p> + <p><c>Port = MinPort = MaxPort = int()</c></p> + <p>Policy for the selection of the temporary port that is used + by the server/client during the file transfer. Default is + <c>random</c>, which is the standardized policy. With this + policy a randomized free port is used. A single port or a range + of ports can be useful if the protocol passes through a firewall.</p> </item> <tag><c>{udp, Options}</c></tag> <item> - <p><c>Options = [Opt]</c> see - <seealso marker="kernel:gen_udp#open/1">gen_udp:open/2</seealso></p> + <p><c>Options = [Opt]</c>, see + <seealso marker="kernel:gen_udp#open/1">gen_udp:open/2</seealso>.</p> </item> <tag><c>{use_tsize, Bool}</c></tag> <item> <p><c>Bool = bool()</c></p> - <p>Flag for automated usage of the <c>tsize</c> option. With - this set to true, the <c>write_file/3</c> client will - determine the filesize and send it to the server as + <p>Flag for automated use of option <c>tsize</c>. With + this set to <c>true</c>, the <c>write_file/3</c> client + determines the filesize and sends it to the server as the standardized <c>tsize</c> option. A <c>read_file/3</c> - client will just acquire filesize from the server by sending + client acquires only a filesize from the server by sending a zero <c>tsize</c>.</p> </item> <tag><c>{max_tsize, MaxTsize}</c></tag> <item> <p><c>MaxTsize = int() | infinity</c></p> <p>Threshold for the maximal filesize in bytes. The transfer - will be aborted if the limit is exceeded. It defaults to - <c>infinity</c>.</p> + is aborted if the limit is exceeded. + Default is <c>infinity</c>.</p> </item> <tag><c>{max_conn, MaxConn}</c></tag> <item> <p><c>MaxConn = int() | infinity</c></p> <p>Threshold for the maximal number of active connections. - The daemon will reject the setup of new connections if - the limit is exceeded. It defaults to <c>infinity</c>.</p> + The daemon rejects the setup of new connections if + the limit is exceeded. Default is <c>infinity</c>.</p> </item> <tag><c>{TftpKey, TftpVal}</c></tag> <item> <p><c>TftpKey = string()</c> <br></br> <c>TftpVal = string()</c></p> - <p>The name and value of a TFTP option.</p> + <p>Name and value of a TFTP option.</p> </item> <tag><c>{reject, Feature}</c></tag> <item> <p><c>Feature = Mode | TftpKey</c> <br></br> <c> Mode = read | write</c> <br></br> <c> TftpKey = string()</c></p> - <p>Control which features that should be rejected. This is - mostly useful for the server as it may restrict usage of - certain TFTP options or read/write access.</p> + <p>Controls which features to reject. This is + mostly useful for the server as it can restrict the use + of certain TFTP options or read/write access.</p> </item> <tag><c>{callback, {RegExp, Module, State}}</c></tag> <item> <p><c>RegExp = string()</c> <br></br> <c>Module = atom()</c> <br></br> -<c>State = term()</c></p> +<c>State = term()</c></p> <p>Registration of a callback module. When a file is to be - transferred, its local filename will be matched to the regular + transferred, its local filename is matched to the regular expressions of the registered callbacks. The first matching - callback will be used the during the transfer. See + callback is used during the transfer. See <seealso marker="#read_file/3">read_file/3</seealso> and <seealso marker="#write_file/3">write_file/3</seealso>. </p> - <p>The callback module must implement the <c>tftp</c> behavior, + <p>The callback module must implement the <c>tftp</c> behavior, see <seealso marker="#tftp_callback">CALLBACK FUNCTIONS</seealso>.</p> </item> @@ -203,9 +200,9 @@ <item> <p><c>Module = module()()</c></p> - <p>Callback module for customized logging of error, warning and - info messages. >The callback module must implement the - <c>tftp_logger</c> behavior, + <p>Callback module for customized logging of errors, warnings, and + info messages. The callback module must implement the + <c>tftp_logger</c> behavior, see <seealso marker="#tftp_logger">LOGGER FUNCTIONS</seealso>. The default module is <c>tftp_logger</c>.</p> </item> @@ -215,199 +212,169 @@ <p><c>MaxRetries = int()</c></p> <p>Threshold for the maximal number of retries. By default - the server/client will try to resend a message up to - <c>5</c> times when the timeout expires.</p> + the server/client tries to resend a message up to + five times when the time-out expires.</p> </item> </taglist> - - <marker id="start1"></marker> </section> <funcs> <func> - <name>start(Options) -> {ok, Pid} | {error, Reason}</name> - <fsummary>Start a daemon process</fsummary> + <name>change_config(daemons, Options) -> [{Pid, Result}]</name> + <fsummary>Changes configuration for all daemons. + </fsummary> <type> <v>Options = [option()]</v> <v>Pid = pid()</v> + <v>Result = ok | {error, Reason}</v> <v>Reason = term()</v> </type> <desc> - <p>Starts a daemon process which listens for udp packets on a - port. When it receives a request for read or write it spawns - a temporary server process which handles the actual transfer - of the (virtual) file.</p> - - <marker id="read_file"></marker> + <p>Changes configuration for all TFTP daemon processes. </p> </desc> </func> <func> - <name>read_file(RemoteFilename, LocalFilename, Options) -> {ok, LastCallbackState} | {error, Reason}</name> - <fsummary>Read a (virtual) file from a TFTP server</fsummary> + <name>change_config(servers, Options) -> [{Pid, Result}]</name> + <fsummary>Changes configuration for all servers. + </fsummary> <type> - <v>RemoteFilename = string()</v> - <v>LocalFilename = binary | string()</v> <v>Options = [option()]</v> - <v>LastCallbackState = term()</v> + <v>Pid = pid()</v> + <v>Result = ok | {error, Reason}</v> <v>Reason = term()</v> </type> <desc> - <p>Reads a (virtual) file <c>RemoteFilename</c> from a TFTP - server.</p> - <p>If <c>LocalFilename</c> is the atom <c>binary</c>, - <c>tftp_binary</c> is used as callback module. It concatenates - all transferred blocks and returns them as one single binary - in <c>LastCallbackState</c>.</p> - <p>If <c>LocalFilename</c> is a string and there are no - registered callback modules, <c>tftp_file</c> is used as - callback module. It writes each transferred block to the file - named <c>LocalFilename</c> and returns the number of - transferred bytes in <c>LastCallbackState</c>.</p> - <p>If <c>LocalFilename</c> is a string and there are registered - callback modules, <c>LocalFilename</c> is tested against - the regexps of these and the callback module corresponding to - the first match is used, or an error tuple is returned if no - matching regexp is found.</p> + <p>Changes configuration for all TFTP server processes.</p> </desc> - - <marker id="write_file"></marker> </func> <func> - <name>write_file(RemoteFilename, LocalFilename, Options) -> {ok, LastCallbackState} | {error, Reason}</name> - <fsummary>Write a (virtual) file to a TFTP server</fsummary> + <name>change_config(Pid, Options) -> Result</name> + <fsummary>Changes configuration for a TFTP daemon, server, + or client process.</fsummary> <type> - <v>RemoteFilename = string()</v> - <v>LocalFilename = binary() | string()</v> + <v>Pid = pid()</v> <v>Options = [option()]</v> - <v>LastCallbackState = term()</v> + <v>Result = ok | {error, Reason}</v> <v>Reason = term()</v> </type> <desc> - <p>Writes a (virtual) file <c>RemoteFilename</c> to a TFTP - server.</p> - <p>If <c>LocalFilename</c> is a binary, <c>tftp_binary</c> is - used as callback module. The binary is transferred block by - block and the number of transferred bytes is returned in - <c>LastCallbackState</c>.</p> - <p>If <c>LocalFilename</c> is a string and there are no - registered callback modules, <c>tftp_file</c> is used as - callback module. It reads the file named <c>LocalFilename</c> - block by block and returns the number of transferred bytes - in <c>LastCallbackState</c>.</p> - <p>If <c>LocalFilename</c> is a string and there are registered - callback modules, <c>LocalFilename</c> is tested against - the regexps of these and the callback module corresponding to - the first match is used, or an error tuple is returned if no - matching regexp is found.</p> - - <marker id="info_daemons"></marker> + <p>Changes configuration for a TFTP daemon, server, or client process.</p> </desc> </func> - + <func> <name>info(daemons) -> [{Pid, Options}]</name> - <fsummary>Return information about all daemons</fsummary> + <fsummary>Returns information about all daemons.</fsummary> <type> <v>Pid = [pid()()]</v> <v>Options = [option()]</v> <v>Reason = term()</v> </type> <desc> - <p>Returns info about all TFTP daemon processes. </p> - - <marker id="info_servers"></marker> + <p>Returns information about all TFTP daemon processes.</p> </desc> </func> <func> <name>info(servers) -> [{Pid, Options}]</name> - <fsummary>Return information about all servers</fsummary> + <fsummary>Returns information about all servers.</fsummary> <type> <v>Pid = [pid()()]</v> <v>Options = [option()]</v> <v>Reason = term()</v> </type> <desc> - <p>Returns info about all TFTP server processes. </p> - - <marker id="info_pid"></marker> + <p>Returns information about all TFTP server processes. </p> </desc> </func> <func> <name>info(Pid) -> {ok, Options} | {error, Reason}</name> - <fsummary>Return information about a daemon, server or client process</fsummary> + <fsummary>Returns information about a daemon, server, or client process.</fsummary> <type> <v>Options = [option()]</v> <v>Reason = term()</v> </type> <desc> - <p>Returns info about a TFTP daemon, server or client process.</p> - - <marker id="change_config_daemons"></marker> + <p>Returns information about a TFTP daemon, server, or client process.</p> </desc> </func> - - <func> - <name>change_config(daemons, Options) -> [{Pid, Result}]</name> - <fsummary>Changes config for all daemons - </fsummary> + + <func> + <name>read_file(RemoteFilename, LocalFilename, Options) -> {ok, LastCallbackState} | {error, Reason}</name> + <fsummary>Reads a (virtual) file from a TFTP server.</fsummary> <type> + <v>RemoteFilename = string()</v> + <v>LocalFilename = binary | string()</v> <v>Options = [option()]</v> - <v>Pid = pid()</v> - <v>Result = ok | {error, Reason}</v> + <v>LastCallbackState = term()</v> <v>Reason = term()</v> </type> <desc> - <p>Changes config for all TFTP daemon processes. </p> - - <marker id="change_config_servers"></marker> - </desc> + <p>Reads a (virtual) file <c>RemoteFilename</c> from a TFTP + server.</p> + <p>If <c>LocalFilename</c> is the atom <c>binary</c>, + <c>tftp_binary</c> is used as callback module. It concatenates + all transferred blocks and returns them as one single binary + in <c>LastCallbackState</c>.</p> + <p>If <c>LocalFilename</c> is a string and there are no + registered callback modules, <c>tftp_file</c> is used as + callback module. It writes each transferred block to the file + named <c>LocalFilename</c> and returns the number of + transferred bytes in <c>LastCallbackState</c>.</p> + <p>If <c>LocalFilename</c> is a string and there are registered + callback modules, <c>LocalFilename</c> is tested against + the regexps of these and the callback module corresponding to + the first match is used, or an error tuple is returned if no + matching regexp is found.</p> + </desc> </func> - + <func> - <name>change_config(servers, Options) -> [{Pid, Result}]</name> - <fsummary>Changes config for all servers - </fsummary> + <name>start(Options) -> {ok, Pid} | {error, Reason}</name> + <fsummary>Starts a daemon process.</fsummary> <type> <v>Options = [option()]</v> <v>Pid = pid()</v> - <v>Result = ok | {error, Reason}</v> <v>Reason = term()</v> </type> <desc> - <p>Changes config for all TFTP server processes. </p> - - <marker id="change_config_pid"></marker> + <p>Starts a daemon process listening for UDP packets on a + port. When it receives a request for read or write, it spawns + a temporary server process handling the actual transfer + of the (virtual) file.</p> </desc> </func> <func> - <name>change_config(Pid, Options) -> Result</name> - <fsummary>Changes config for a TFTP daemon, server or client process</fsummary> + <name>write_file(RemoteFilename, LocalFilename, Options) -> {ok, LastCallbackState} | {error, Reason}</name> + <fsummary>Writes a (virtual) file to a TFTP server.</fsummary> <type> - <v>Pid = pid()</v> + <v>RemoteFilename = string()</v> + <v>LocalFilename = binary() | string()</v> <v>Options = [option()]</v> - <v>Result = ok | {error, Reason}</v> - <v>Reason = term()</v> - </type> - <desc> - <p>Changes config for a TFTP daemon, server or client process</p> - - <marker id="start2"></marker> - </desc> - </func> - - <func> - <name>start() -> ok | {error, Reason}</name> - <fsummary>Start the Inets application</fsummary> - <type> + <v>LastCallbackState = term()</v> <v>Reason = term()</v> </type> <desc> - <p>Starts the Inets application.</p> + <p>Writes a (virtual) file <c>RemoteFilename</c> to a TFTP + server.</p> + <p>If <c>LocalFilename</c> is a binary, <c>tftp_binary</c> is + used as callback module. The binary is transferred block by + block and the number of transferred bytes is returned in + <c>LastCallbackState</c>.</p> + <p>If <c>LocalFilename</c> is a string and there are no + registered callback modules, <c>tftp_file</c> is used as + callback module. It reads the file named <c>LocalFilename</c> + block by block and returns the number of transferred bytes + in <c>LastCallbackState</c>.</p> + <p>If <c>LocalFilename</c> is a string and there are registered + callback modules, <c>LocalFilename</c> is tested against + the regexps of these and the callback module corresponding to + the first match is used, or an error tuple is returned if no + matching regexp is found.</p> </desc> </func> </funcs> @@ -415,40 +382,41 @@ <section> <marker id="tftp_callback"></marker> <title>CALLBACK FUNCTIONS</title> - <p>A <c>tftp</c> callback module should be implemented as a - <c>tftp</c> behavior and export the functions listed below.</p> - <p>On the server side the callback interaction starts with a call to + <p>A <c>tftp</c> callback module is to be implemented as a + <c>tftp</c> behavior and export the functions listed + in the following.</p> + <p>On the server side, the callback interaction starts with a call to <c>open/5</c> with the registered initial callback state. <c>open/5</c> is expected to open the (virtual) file. Then either - the <c>read/1</c> or <c>write/2</c> functions are invoked - repeatedly, once per transferred block. At each function call + function <c>read/1</c> or <c>write/2</c> is invoked + repeatedly, once per transferred block. At each function call, the state returned from the previous call is obtained. When - the last block has been encountered the <c>read/1</c> or - <c>write/2</c> functions is expected to close the (virtual) file - and return its last state. The <c>abort/3</c> function is only - used in error situations. <c>prepare/5</c> is not used on + the last block is encountered, function <c>read/1</c> or + <c>write/2</c> is expected to close the (virtual) file + and return its last state. Function <c>abort/3</c> is only + used in error situations. Function <c>prepare/5</c> is not used on the server side.</p> - <p>On the client side the callback interaction is the same, but it + <p>On the client side, the callback interaction is the same, but it starts and ends a bit differently. It starts with a call to <c>prepare/5</c> with the same arguments as <c>open/5</c> takes. - <c>prepare/5</c> is expected to validate the TFTP options, - suggested by the user and return the subset of them that it - accepts. Then the options is sent to the server which will perform + <c>prepare/5</c> is expected to validate the TFTP options + suggested by the user and to return the subset of them that it + accepts. Then the options are sent to the server, which performs the same TFTP option negotiation procedure. The options that are - accepted by the server are forwarded to the <c>open/5</c> function - on the client side. On the client side the <c>open/5</c> function - must accept all option as is or reject the transfer. Then + accepted by the server are forwarded to function <c>open/5</c> + on the client side. On the client side, function <c>open/5</c> + must accept all option as-is or reject the transfer. Then the callback interaction follows the same pattern as described - above for the server side. When the last block is encountered in - <c>read/1</c> or <c>write/2</c> the returned state is forwarded to + for the server side. When the last block is encountered in + <c>read/1</c> or <c>write/2</c>, the returned state is forwarded to the user and returned from <c>read_file</c>/3 or <c>write_file/3</c>.</p> - <p> If a callback (which performs the file access + <p> If a callback (performing the file access in the TFTP server) takes too long time (more than - the double TFTP timeout), the server will abort the - connection and send an error reply to the client. - This implies that the server will release resources + the double TFTP time-out), the server aborts the + connection and sends an error reply to the client. + This implies that the server releases resources attached to the connection faster than before. The server simply assumes that the client has given up.</p> @@ -456,21 +424,45 @@ <p>If the TFTP server receives yet another request from the same client (same host and port) while it already has an active connection to the client, it - will simply ignore the new request if the request is - equal with the first one (same filename and options). + ignores the new request if the request is + equal to the first one (same filename and options). This implies that the (new) client will be served by the already ongoing connection on the server side. By not setting up yet another connection, in - parallel with the ongoing one, the server will - consumer lesser resources. </p> + parallel with the ongoing one, the server + consumes less resources.</p> <marker id="prepare"></marker> </section> <funcs> - <func> - <name>prepare(Peer, Access, Filename, Mode, SuggestedOptions, InitialState) -> {ok, AcceptedOptions, NewState} | {error, {Code, Text}}</name> - <fsummary>Prepare to open a file on the client side</fsummary> + <func> + <name>Module:abort(Code, Text, State) -> ok</name> + <fsummary>Aborts the file transfer.</fsummary> + <type> + <v>Code = undef | enoent | eacces | enospc</v> + <v> | badop | eexist | baduser | badopt</v> + <v> | int()</v> + <v>Text = string()</v> + <v>State = term()</v> + </type> + <desc> + <p>Invoked when the file transfer is aborted.</p> + <p>The callback function is expected to clean + up its used resources after the aborted file + transfer, such as closing open file + descriptors and so on. The function is not + invoked if any of the other callback + functions returns an error, as it is + expected that they already have cleaned up + the necessary resources. However, it is + invoked if the functions fail (crash).</p> + </desc> + </func> + + <func> + <name>Module:open(Peer, Access, Filename, Mode, SuggestedOptions, State) -> {ok, AcceptedOptions, NewState} | {error, {Code, Text}}</name> + <fsummary>Opens a file for read or write access.</fsummary> <type> <v>Peer = {PeerType, PeerHost, PeerPort}</v> <v>PeerType = inet | inet6</v> @@ -481,7 +473,8 @@ <v>Mode = string()</v> <v>SuggestedOptions = AcceptedOptions = [{Key, Value}]</v> <v> Key = Value = string()</v> - <v>InitialState = [] | [{root_dir, string()}]</v> + <v>State = InitialState | term()</v> + <v> InitialState = [] | [{root_dir, string()}]</v> <v>NewState = term()</v> <v>Code = undef | enoent | eacces | enospc</v> <v> | badop | eexist | baduser | badopt</v> @@ -489,23 +482,22 @@ <v>Text = string()</v> </type> <desc> - <p>Prepares to open a file on the client side.</p> - <p>No new options may be added, but the ones that are present in - <c>SuggestedOptions</c> may be omitted or replaced with new - values in <c>AcceptedOptions</c>.</p> - <p>Will be followed by a call to <c>open/4</c> before any - read/write access is performed. <c>AcceptedOptions</c> is - sent to the server which replies with those options that it - accepts. These will be forwarded to <c>open/4</c> as - <c>SuggestedOptions</c>.</p> + <p>Opens a file for read or write access.</p> + <p>On the client side, where the <c>open/5</c> call has been + preceded by a call to <c>prepare/5</c>, all options must be + accepted or rejected.</p> + <p>On the server side, where there is no preceding + <c>prepare/5</c> call, no new options can be added, but + those present in <c>SuggestedOptions</c> can be + omitted or replaced with new values in <c>AcceptedOptions</c>.</p> - <marker id="open"></marker> + <marker id="read"></marker> </desc> </func> - + <func> - <name>open(Peer, Access, Filename, Mode, SuggestedOptions, State) -> {ok, AcceptedOptions, NewState} | {error, {Code, Text}}</name> - <fsummary>Open a file for read or write access</fsummary> + <name>Module:prepare(Peer, Access, Filename, Mode, SuggestedOptions, InitialState) -> {ok, AcceptedOptions, NewState} | {error, {Code, Text}}</name> + <fsummary>Prepares to open a file on the client side.</fsummary> <type> <v>Peer = {PeerType, PeerHost, PeerPort}</v> <v>PeerType = inet | inet6</v> @@ -516,8 +508,7 @@ <v>Mode = string()</v> <v>SuggestedOptions = AcceptedOptions = [{Key, Value}]</v> <v> Key = Value = string()</v> - <v>State = InitialState | term()</v> - <v> InitialState = [] | [{root_dir, string()}]</v> + <v>InitialState = [] | [{root_dir, string()}]</v> <v>NewState = term()</v> <v>Code = undef | enoent | eacces | enospc</v> <v> | badop | eexist | baduser | badopt</v> @@ -525,22 +516,23 @@ <v>Text = string()</v> </type> <desc> - <p>Opens a file for read or write access.</p> - <p>On the client side where the <c>open/5</c> call has been - preceded by a call to <c>prepare/5</c>, all options must be - accepted or rejected.</p> - <p>On the server side, where there is no preceding - <c>prepare/5</c> call, no new options may be added, but - the ones that are present in <c>SuggestedOptions</c> may be - omitted or replaced with new values in <c>AcceptedOptions</c>.</p> + <p>Prepares to open a file on the client side.</p> + <p>No new options can be added, but those present in + <c>SuggestedOptions</c> can be omitted or replaced with new + values in <c>AcceptedOptions</c>.</p> + <p>This is followed by a call to <c>open/4</c> before any + read/write access is performed. <c>AcceptedOptions</c> is + sent to the server, which replies with the options that it + accepts. These are then forwarded to <c>open/4</c> as + <c>SuggestedOptions</c>.</p> - <marker id="read"></marker> + <marker id="open"></marker> </desc> </func> <func> - <name>read(State) -> {more, Bin, NewState} | {last, Bin, FileSize} | {error, {Code, Text}}</name> - <fsummary>Read a chunk from the file</fsummary> + <name>Module:read(State) -> {more, Bin, NewState} | {last, Bin, FileSize} | {error, {Code, Text}}</name> + <fsummary>Reads a chunk from the file.</fsummary> <type> <v>State = NewState = term()</v> <v>Bin = binary()</v> @@ -551,13 +543,13 @@ <v>Text = string()</v> </type> <desc> - <p>Read a chunk from the file.</p> + <p>Reads a chunk from the file.</p> <p>The callback function is expected to close the file when the last file chunk is - encountered. When an error is encountered + encountered. When an error is encountered, the callback function is expected to clean up after the aborted file transfer, such as - closing open file descriptors etc. In both + closing open file descriptors, and so on. In both cases there will be no more calls to any of the callback functions.</p> @@ -566,8 +558,8 @@ </func> <func> - <name>write(Bin, State) -> {more, NewState} | {last, FileSize} | {error, {Code, Text}}</name> - <fsummary>Write a chunk to the file</fsummary> + <name>Module:write(Bin, State) -> {more, NewState} | {last, FileSize} | {error, {Code, Text}}</name> + <fsummary>Writes a chunk to the file.</fsummary> <type> <v>Bin = binary()</v> <v>State = NewState = term()</v> @@ -578,99 +570,75 @@ <v>Text = string()</v> </type> <desc> - <p>Write a chunk to the file.</p> + <p>Writes a chunk to the file.</p> <p>The callback function is expected to close the file when the last file chunk is - encountered. When an error is encountered + encountered. When an error is encountered, the callback function is expected to clean up after the aborted file transfer, such as - closing open file descriptors etc. In both + closing open file descriptors, and so on. In both cases there will be no more calls to any of the callback functions.</p> <marker id="abort"></marker> </desc> </func> - - <func> - <name>abort(Code, Text, State) -> ok</name> - <fsummary>Abort the file transfer</fsummary> - <type> - <v>Code = undef | enoent | eacces | enospc</v> - <v> | badop | eexist | baduser | badopt</v> - <v> | int()</v> - <v>Text = string()</v> - <v>State = term()</v> - </type> - <desc> - <p>Invoked when the file transfer is aborted.</p> - <p>The callback function is expected to clean - up its used resources after the aborted file - transfer, such as closing open file - descriptors etc. The function will not be - invoked if any of the other callback - functions returns an error, as it is - expected that they already have cleaned up - the necessary resources. It will however be - invoked if the functions fails (crashes).</p> - </desc> - </func> </funcs> <section> <marker id="tftp_logger"></marker> <title>LOGGER FUNCTIONS</title> - <p>A <c>tftp_logger</c> callback module should be implemented as a - <c>tftp_logger</c> behavior and export the functions listed below.</p> + <p>A <c>tftp_logger</c> callback module is to be implemented as a + <c>tftp_logger</c> behavior and export the following functions:</p> <marker id="error_msg"></marker> </section> <funcs> <func> - <name>error_msg(Format, Data) -> ok | exit(Reason)</name> - <fsummary>Log an error message</fsummary> + <name>Logger:error_msg(Format, Data) -> ok | exit(Reason)</name> + <fsummary>Logs an error message.</fsummary> <type> <v>Format = string()</v> <v>Data = [term()]</v> <v>Reason = term()</v> </type> <desc> - <p>Log an error message. - See <c>error_logger:error_msg/2 for details.</c> </p> + <p>Logs an error message. + See <c>error_logger:error_msg/2</c> for details.</p> <marker id="warning_msg"></marker> </desc> </func> <func> - <name>warning_msg(Format, Data) -> ok | exit(Reason)</name> - <fsummary>Log an error message</fsummary> + <name>Logger:info_msg(Format, Data) -> ok | exit(Reason)</name> + <fsummary>Logs an info message.</fsummary> <type> <v>Format = string()</v> <v>Data = [term()]</v> <v>Reason = term()</v> </type> <desc> - <p>Log a warning message. - See <c>error_logger:warning_msg/2 for details.</c> </p> - - <marker id="info_msg"></marker> + <p>Logs an info message. + See <c>error_logger:info_msg/2</c> for details.</p> </desc> </func> - + <func> - <name>info_msg(Format, Data) -> ok | exit(Reason)</name> - <fsummary>Log an error message</fsummary> + <name>Logger:warning_msg(Format, Data) -> ok | exit(Reason)</name> + <fsummary>Logs a warning message.</fsummary> <type> <v>Format = string()</v> <v>Data = [term()]</v> <v>Reason = term()</v> </type> <desc> - <p>Log an info message. - See <c>error_logger:info_msg/2 for details.</c> </p> + <p>Logs a warning message. + See <c>error_logger:warning_msg/2</c> for details.</p> + + <marker id="info_msg"></marker> </desc> </func> </funcs> diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl index e4a6f8f748..4554881d79 100644 --- a/lib/inets/src/http_client/httpc.erl +++ b/lib/inets/src/http_client/httpc.erl @@ -101,7 +101,8 @@ request(Url, Profile) -> %% {ok, {StatusLine, Headers, Body}} | {ok, {Status, Body}} | %% {ok, RequestId} | {error,Reason} | {ok, {saved_as, FilePath} %% -%% Method - atom() = head | get | put | post | trace | options| delete +%% Method - atom() = head | get | put | patch | post | trace | +%% options | delete %% Request - {Url, Headers} | {Url, Headers, ContentType, Body} %% Url - string() %% HTTPOptions - [HttpOption] @@ -176,8 +177,8 @@ request(Method, request(Method, {Url, Headers, ContentType, Body}, HTTPOptions, Options, Profile) - when ((Method =:= post) orelse (Method =:= put) orelse (Method =:= delete)) andalso - (is_atom(Profile) orelse is_pid(Profile)) -> + when ((Method =:= post) orelse (Method =:= patch) orelse (Method =:= put) orelse + (Method =:= delete)) andalso (is_atom(Profile) orelse is_pid(Profile)) -> ?hcrt("request", [{method, Method}, {url, Url}, {headers, Headers}, @@ -555,7 +556,7 @@ handle_request(Method, Url, Request = #request{from = Receiver, scheme = Scheme, - address = {Host, Port}, + address = {host_address(Host, BracketedHost), Port}, path = MaybeEscPath, pquery = MaybeEscQuery, method = Method, @@ -1267,3 +1268,7 @@ child_name(Pid, [_ | Children]) -> %% d(_, _, _) -> %% ok. +host_address(Host, false) -> + Host; +host_address(Host, true) -> + string:strip(string:strip(Host, right, $]), left, $[). diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl index 3f979de078..d1c52dcc78 100644 --- a/lib/inets/src/http_client/httpc_handler.erl +++ b/lib/inets/src/http_client/httpc_handler.erl @@ -26,6 +26,7 @@ -include_lib("inets/src/http_lib/http_internal.hrl"). -include("httpc_internal.hrl"). +-define(IS_STREAMED(Code), ((Code =:= 200) orelse (Code =:= 206))). %%-------------------------------------------------------------------- %% Internal Application API @@ -163,22 +164,22 @@ info(Pid) -> %% Request should not be streamed stream(BodyPart, #request{stream = none} = Request, _) -> ?hcrt("stream - none", []), - {BodyPart, Request}; + {false, BodyPart, Request}; %% Stream to caller stream(BodyPart, #request{stream = Self} = Request, Code) - when ((Code =:= 200) orelse (Code =:= 206)) andalso + when ?IS_STREAMED(Code) andalso ((Self =:= self) orelse (Self =:= {self, once})) -> ?hcrt("stream - self", [{stream, Self}, {code, Code}]), httpc_response:send(Request#request.from, {Request#request.id, stream, BodyPart}), - {<<>>, Request}; + {true, <<>>, Request}; %% Stream to file %% This has been moved to start_stream/3 %% We keep this for backward compatibillity... stream(BodyPart, #request{stream = Filename} = Request, Code) - when ((Code =:= 200) orelse (Code =:= 206)) andalso is_list(Filename) -> + when ?IS_STREAMED(Code) andalso is_list(Filename) -> ?hcrt("stream - filename", [{stream, Filename}, {code, Code}]), case file:open(Filename, [write, raw, append, delayed_write]) of {ok, Fd} -> @@ -190,18 +191,18 @@ stream(BodyPart, #request{stream = Filename} = Request, Code) %% Stream to file stream(BodyPart, #request{stream = Fd} = Request, Code) - when ((Code =:= 200) orelse (Code =:= 206)) -> + when ?IS_STREAMED(Code) -> ?hcrt("stream to file", [{stream, Fd}, {code, Code}]), case file:write(Fd, BodyPart) of ok -> - {<<>>, Request}; + {true, <<>>, Request}; {error, Reason} -> exit({stream_to_file_failed, Reason}) end; stream(BodyPart, Request,_) -> % only 200 and 206 responses can be streamed ?hcrt("stream - ignore", [{request, Request}]), - {BodyPart, Request}. + {false, BodyPart, Request}. %%==================================================================== @@ -421,6 +422,16 @@ handle_cast({cancel, RequestId}, {profile, ProfileName}, {canceled, Canceled}]), {noreply, State#state{canceled = [RequestId | Canceled]}}; +handle_cast({cancel, RequestId}, + #state{profile_name = ProfileName, + request = undefined, + canceled = Canceled} = State) -> + ?hcrv("cancel", [{request_id, RequestId}, + {curr_req_id, undefined}, + {profile, ProfileName}, + {canceled, Canceled}]), + {noreply, State}; + handle_cast(stream_next, #state{session = Session} = State) -> activate_once(Session), @@ -464,18 +475,18 @@ handle_info({Proto, _Socket, Data}, {Module, whole_body, [Body, Length]} -> ?hcrd("data processed - whole body", [{length, Length}]), {_, Code, _} = StatusLine, - {NewBody, NewRequest} = stream(Body, Request, Code), + {Streamed, NewBody, NewRequest} = stream(Body, Request, Code), %% When we stream we will not keep the already %% streamed data, that would be a waste of memory. NewLength = - case Stream of - none -> + case Streamed of + false -> Length; - _ -> + true -> Length - size(Body) end, - NewState = next_body_chunk(State), + NewState = next_body_chunk(State, Code), NewMFA = {Module, whole_body, [NewBody, NewLength]}, {noreply, NewState#state{mfa = NewMFA, request = NewRequest}}; @@ -487,8 +498,8 @@ handle_info({Proto, _Socket, Data}, %% The response body is chunk-encoded. Steal decoded %% chunks as much as possible to stream. {_, Code, _} = StatusLine, - {NewBody, NewRequest} = stream(BodySoFar, Request, Code), - NewState = next_body_chunk(State), + {_, NewBody, NewRequest} = stream(BodySoFar, Request, Code), + NewState = next_body_chunk(State, Code), NewMFA = {Module, decode_size, [TotalChunk, HexList, {MaxBodySize, NewBody, AccLength, MaxHeaderSize}]}, @@ -507,8 +518,8 @@ handle_info({Proto, _Socket, Data}, NewChunkSize = ChunkSize - ChunkSizeToSteal, {_, Code, _} = StatusLine, - {NewBody, NewRequest} = stream(StolenBody, Request, Code), - NewState = next_body_chunk(State), + {_, NewBody, NewRequest} = stream(StolenBody, Request, Code), + NewState = next_body_chunk(State, Code), NewMFA = {Module, decode_data, [NewChunkSize, NewTotalChunk, {MaxBodySize, NewBody, AccLength, MaxHeaderSize}]}, @@ -1061,13 +1072,13 @@ handle_http_msg({ChunkedHeaders, Body}, ?hcrt("handle_http_msg", [{chunked_headers, ChunkedHeaders}, {headers, Headers}]), NewHeaders = http_chunk:handle_headers(Headers, ChunkedHeaders), - {NewBody, NewRequest} = stream(Body, State#state.request, Code), + {_, NewBody, NewRequest} = stream(Body, State#state.request, Code), handle_response(State#state{headers = NewHeaders, body = NewBody, request = NewRequest}); handle_http_msg(Body, #state{status_line = {_,Code, _}} = State) -> ?hcrt("handle_http_msg", [{code, Code}]), - {NewBody, NewRequest} = stream(Body, State#state.request, Code), + {_, NewBody, NewRequest} = stream(Body, State#state.request, Code), handle_response(State#state{body = NewBody, request = NewRequest}). handle_http_body(_, #state{status = {ssl_tunnel, _}, @@ -1102,14 +1113,14 @@ handle_http_body(Body, #state{headers = Headers, case case_insensitive_header(TransferEnc) of "chunked" -> ?hcrt("handle_http_body - chunked", []), - case http_chunk:decode(Body, State#state.max_body_size, - State#state.max_header_size) of + try http_chunk:decode(Body, State#state.max_body_size, + State#state.max_header_size) of {Module, Function, Args} -> ?hcrt("handle_http_body - new mfa", [{module, Module}, {function, Function}, {args, Args}]), - NewState = next_body_chunk(State), + NewState = next_body_chunk(State, Code), {noreply, NewState#state{mfa = {Module, Function, Args}}}; {ok, {ChunkedHeaders, NewBody}} -> @@ -1123,11 +1134,18 @@ handle_http_body(Body, #state{headers = Headers, handle_response(State#state{headers = NewHeaders, body = NewBody}); _ -> - {NewBody2, _NewRequest} = + {_, NewBody2, _} = stream(NewBody, Request, Code), handle_response(State#state{headers = NewHeaders, body = NewBody2}) end + catch throw:{error, Reason} -> + NewState = + answer_request(Request, + httpc_response:error(Request, + Reason), + State), + {stop, normal, NewState} end; Enc when Enc =:= "identity"; Enc =:= undefined -> ?hcrt("handle_http_body - identity", []), @@ -1137,12 +1155,12 @@ handle_http_body(Body, #state{headers = Headers, true -> case httpc_response:whole_body(Body, Length) of {ok, Body} -> - {NewBody, NewRequest} = + {_, NewBody, NewRequest} = stream(Body, Request, Code), handle_response(State#state{body = NewBody, request = NewRequest}); MFA -> - NewState = next_body_chunk(State), + NewState = next_body_chunk(State, Code), {noreply, NewState#state{mfa = MFA}} end; false -> @@ -1636,21 +1654,21 @@ start_stream({_Version, _Code, _ReasonPhrase}, _Headers, {ok, Request}; start_stream({_Version, Code, _ReasonPhrase}, Headers, #request{stream = self} = Request) - when (Code =:= 200) orelse (Code =:= 206) -> + when ?IS_STREAMED(Code) -> ?hcrt("start stream - self", [{code, Code}]), Msg = httpc_response:stream_start(Headers, Request, ignore), httpc_response:send(Request#request.from, Msg), {ok, Request}; start_stream({_Version, Code, _ReasonPhrase}, Headers, #request{stream = {self, once}} = Request) - when (Code =:= 200) orelse (Code =:= 206) -> + when ?IS_STREAMED(Code) -> ?hcrt("start stream - self:once", [{code, Code}]), Msg = httpc_response:stream_start(Headers, Request, self()), httpc_response:send(Request#request.from, Msg), {ok, Request}; start_stream({_Version, Code, _ReasonPhrase}, _Headers, #request{stream = Filename} = Request) - when ((Code =:= 200) orelse (Code =:= 206)) andalso is_list(Filename) -> + when ?IS_STREAMED(Code) andalso is_list(Filename) -> ?hcrt("start stream", [{code, Code}, {filename, Filename}]), case file:open(Filename, [write, raw, append, delayed_write]) of {ok, Fd} -> @@ -1702,13 +1720,15 @@ end_stream(SL, R) -> next_body_chunk(#state{request = #request{stream = {self, once}}, once = once, - session = Session} = State) -> + session = Session} = State, + Code) when ?IS_STREAMED(Code) -> activate_once(Session), State#state{once = inactive}; next_body_chunk(#state{request = #request{stream = {self, once}}, - once = inactive} = State) -> + once = inactive} = State, + Code) when ?IS_STREAMED(Code) -> State; %% Wait for user to call stream_next -next_body_chunk(#state{session = Session} = State) -> +next_body_chunk(#state{session = Session} = State, _) -> activate_once(Session), State. @@ -1807,13 +1827,15 @@ host_header(_, URI) -> tls_upgrade(#state{status = {ssl_tunnel, #request{settings = - #http_options{ssl = {_, TLSOptions} = SocketType}} = Request}, + #http_options{ssl = {_, TLSOptions0} = SocketType}, + address = {Host, _} = Address} = Request}, session = #session{socket = TCPSocket} = Session0, options = Options} = State) -> + TLSOptions = maybe_add_sni(Host, TLSOptions0), + case ssl:connect(TCPSocket, TLSOptions) of {ok, TLSSocket} -> - Address = Request#request.address, ClientClose = httpc_request:is_client_closing(Request#request.headers), SessionType = httpc_manager:session_type(Options), Session = Session0#session{ @@ -1834,10 +1856,23 @@ tls_upgrade(#state{status = status = new }, {noreply, activate_request_timeout(NewState)}; - {error, _Reason} -> + {error, Reason} -> + Error = httpc_response:error(Request, {failed_connect, + [{to_address, Address}, + {tls, TLSOptions, Reason}]}), + maybe_send_answer(Request, Error, State), {stop, normal, State#state{request = Request}} end. +maybe_add_sni(Host, Options) -> + case http_util:is_hostname(Host) andalso + not lists:keymember(server_name_indication, 1, Options) of + true -> + [{server_name_indication, Host} | Options]; + false -> + Options + end. + %% --------------------------------------------------------------------- %% Session wrappers %% --------------------------------------------------------------------- diff --git a/lib/inets/src/http_client/httpc_request.erl b/lib/inets/src/http_client/httpc_request.erl index e4451401f4..af4c3f75f2 100644 --- a/lib/inets/src/http_client/httpc_request.erl +++ b/lib/inets/src/http_client/httpc_request.erl @@ -187,7 +187,8 @@ is_client_closing(Headers) -> %%% Internal functions %%%======================================================================== post_data(Method, Headers, {ContentType, Body}, HeadersAsIs) - when (Method =:= post) orelse (Method =:= put) -> + when (Method =:= post) orelse (Method =:= put) + orelse (Method =:= patch) -> NewBody = case Headers#http_request_h.expect of "100-continue" -> ""; diff --git a/lib/inets/src/http_client/httpc_response.erl b/lib/inets/src/http_client/httpc_response.erl index 10af1949a4..4bf2ba2b9b 100644 --- a/lib/inets/src/http_client/httpc_response.erl +++ b/lib/inets/src/http_client/httpc_response.erl @@ -328,7 +328,7 @@ status_service_unavailable(Response = {_, Headers, _}, Request) -> undefined -> status_server_error_50x(Response, Request); Time when (length(Time) < 3) -> % Wait only 99 s or less - NewTime = list_to_integer(Time) * 100, % time in ms + NewTime = list_to_integer(Time) * 1000, % time in ms {_, Data} = format_response(Response), {retry, {NewTime, Request}, Data}; _ -> diff --git a/lib/inets/src/http_lib/http_chunk.erl b/lib/inets/src/http_lib/http_chunk.erl index 9476ea9f5f..7325f24809 100644 --- a/lib/inets/src/http_lib/http_chunk.erl +++ b/lib/inets/src/http_lib/http_chunk.erl @@ -25,7 +25,7 @@ -include("http_internal.hrl"). %% API --export([decode/3, encode/1, encode_last/0, handle_headers/2]). +-export([decode/3, encode/1, encode_last/0, encode_last/1, handle_headers/2]). %% Callback API - used for example if the chunkedbody is received a %% little at a time on a socket. -export([decode_size/1, ignore_extensions/1, decode_data/1, decode_trailer/1]). @@ -57,7 +57,7 @@ %%------------------------------------------------------------------------- decode(ChunkedBody, MaxBodySize, MaxHeaderSize) -> %% Note decode_size will call decode_data. - decode_size([ChunkedBody, <<>>, [], + decode_size([ChunkedBody, <<>>, [], 0, {MaxBodySize, <<>>, 0, MaxHeaderSize}]). %%------------------------------------------------------------------------- @@ -85,6 +85,11 @@ encode(Chunk) when is_list(Chunk)-> encode_last() -> <<$0, ?CR, ?LF, ?CR, ?LF >>. +encode_last([]) -> + encode_last(); +encode_last(Trailers0) -> + Trailers = list_to_binary(encode_trailers(Trailers0)), + <<$0, ?CR, ?LF, Trailers/binary>>. %%------------------------------------------------------------------------- %% handle_headers(HeaderRecord, ChunkedHeaders) -> NewHeaderRecord @@ -120,65 +125,80 @@ handle_headers(ResponseHeaderRecord = #http_response_h{}, ChunkedHeaders) -> %% Functions that may be returned during the decoding process %% if the input data is incompleate. -decode_size([Bin, Rest, HexList, Info]) -> - decode_size(<<Rest/binary, Bin/binary>>, HexList, Info). +decode_size([Bin, Rest, HexList, AccSize, Info]) -> + decode_size(<<Rest/binary, Bin/binary>>, HexList, AccSize, Info). -ignore_extensions([Bin, Rest, NextFunction]) -> - ignore_extensions(<<Rest/binary, Bin/binary>>, NextFunction). +ignore_extensions([Bin, Rest, RemainingSize, TotalMaxHeaderSize, NextFunction]) -> + ignore_extensions(<<Rest/binary, Bin/binary>>, RemainingSize, TotalMaxHeaderSize, NextFunction). decode_data([Bin, ChunkSize, TotalChunk, Info]) -> decode_data(ChunkSize, <<TotalChunk/binary, Bin/binary>>, Info). -decode_trailer([Bin, Rest, Header, Headers, MaxHeaderSize, Body, - BodyLength]) -> +decode_trailer([Bin, Rest, Header, Headers, Body, + BodyLength, RemainingSize, TotalMaxHeaderSize]) -> decode_trailer(<<Rest/binary, Bin/binary>>, - Header, Headers, MaxHeaderSize, Body, BodyLength). + Header, Headers, Body, BodyLength, RemainingSize, TotalMaxHeaderSize). %%%======================================================================== %%% Internal functions %%%======================================================================== -decode_size(<<>>, HexList, Info) -> - {?MODULE, decode_size, [<<>>, HexList, Info]}; -decode_size(Data = <<?CR, ?LF, ChunkRest/binary>>, HexList, +decode_size(_, _, AccHeaderSize, {_,_,_, MaxHeaderSize}) when + AccHeaderSize > MaxHeaderSize -> + throw({error, {header_too_long, {max, MaxHeaderSize}}}); + +decode_size(<<>>, HexList, AccHeaderSize, Info) -> + {?MODULE, decode_size, [<<>>, HexList, AccHeaderSize, Info]}; +decode_size(Data = <<?CR, ?LF, ChunkRest/binary>>, HexList, AccHeaderSize, {MaxBodySize, Body, AccLength, MaxHeaderSize}) -> - ChunkSize = http_util:hexlist_to_integer(lists:reverse(HexList)), - case ChunkSize of + try http_util:hexlist_to_integer(lists:reverse(string:strip(HexList, left))) of 0 -> % Last chunk, there was no data - ignore_extensions(Data, {?MODULE, decode_trailer, - [<<>>, [],[], MaxHeaderSize, - Body, - integer_to_list(AccLength)]}); - _ -> + ignore_extensions(Data, remaing_size(MaxHeaderSize, AccHeaderSize), MaxHeaderSize, + {?MODULE, decode_trailer, + [<<>>, [],[], + Body, + integer_to_list(AccLength)]}); + ChunkSize -> %% Note decode_data may call decode_size again if there %% is more than one chunk, hence here is where the last parameter %% to this function comes in. decode_data(ChunkSize, ChunkRest, {MaxBodySize, Body, - ChunkSize + AccLength , + ChunkSize + AccLength, MaxHeaderSize}) + catch + _:_ -> + throw({error, {chunk_size, lists:reverse(HexList)}}) end; -decode_size(<<";", Rest/binary>>, HexList, Info) -> +decode_size(<<";", Rest/binary>>, HexList, AccHeaderSize, {_,_,_, MaxHeaderSize} = Info) -> %% Note ignore_extensions will call decode_size/1 again when %% it ignored all extensions. - ignore_extensions(Rest, {?MODULE, decode_size, [<<>>, HexList, Info]}); -decode_size(<<?CR>> = Data, HexList, Info) -> - {?MODULE, decode_size, [Data, HexList, Info]}; -decode_size(<<Octet, Rest/binary>>, HexList, Info) -> - decode_size(Rest, [Octet | HexList], Info). + ignore_extensions(Rest, remaing_size(MaxHeaderSize, AccHeaderSize), MaxHeaderSize, + {?MODULE, decode_size, [<<>>, HexList, AccHeaderSize, Info]}); +decode_size(<<?CR>> = Data, HexList, AccHeaderSize, Info) -> + {?MODULE, decode_size, [Data, HexList, AccHeaderSize, Info]}; +decode_size(<<Octet, Rest/binary>>, HexList, AccHeaderSize, Info) -> + decode_size(Rest, [Octet | HexList], AccHeaderSize + 1, Info). %% "All applications MUST ignore chunk-extension extensions they %% do not understand.", see RFC 2616 Section 3.6.1 We don't %% understand any extension... -ignore_extensions(<<>>, NextFunction) -> - {?MODULE, ignore_extensions, [<<>>, NextFunction]}; -ignore_extensions(Data = <<?CR, ?LF, _ChunkRest/binary>>, +ignore_extensions(_, 0, TotalMaxHeaderSize, _) -> + throw({error, {header_too_long, {max, TotalMaxHeaderSize}}}); +ignore_extensions(<<>>, RemainingSize, TotalMaxHeaderSize, NextFunction) -> + {?MODULE, ignore_extensions, [<<>>, RemainingSize, TotalMaxHeaderSize, NextFunction]}; +ignore_extensions(Data = <<?CR, ?LF, _ChunkRest/binary>>, RemainingSize, TotalMaxHeaderSize, {Module, Function, Args}) -> - Module:Function([Data | Args]); -ignore_extensions(<<?CR>> = Data, NextFunction) -> - {?MODULE, ignore_extensions, [Data, NextFunction]}; -ignore_extensions(<<_Octet, Rest/binary>>, NextFunction) -> - ignore_extensions(Rest, NextFunction). + case Function of + decode_trailer -> + Module:Function([Data | Args ++ [RemainingSize, TotalMaxHeaderSize]]); + _ -> + Module:Function([Data | Args]) + end; +ignore_extensions(<<?CR>> = Data, RemainingSize, TotalMaxHeaderSize, NextFunction) -> + {?MODULE, ignore_extensions, [Data, RemainingSize, TotalMaxHeaderSize, NextFunction]}; +ignore_extensions(<<_Octet, Rest/binary>>, RemainingSize, TotalMaxHeaderSize, NextFunction) -> + ignore_extensions(Rest, remaing_size(RemainingSize, 1), TotalMaxHeaderSize, NextFunction). decode_data(ChunkSize, TotalChunk, Info = {MaxBodySize, BodySoFar, AccLength, MaxHeaderSize}) @@ -190,83 +210,89 @@ decode_data(ChunkSize, TotalChunk, %% once it ignored all extensions. {?MODULE, ignore_extensions, [<<>>, - {?MODULE, decode_trailer, [<<>>, [],[], MaxHeaderSize, + {?MODULE, decode_trailer, [<<>>, [],[], <<BodySoFar/binary, Data/binary>>, integer_to_list(AccLength)]}]}; <<Data:ChunkSize/binary, ?CR, ?LF, "0", ";", Rest/binary>> -> %% Note ignore_extensions will call decode_trailer/1 %% once it ignored all extensions. - ignore_extensions(Rest, {?MODULE, decode_trailer, - [<<>>, [],[], MaxHeaderSize, + ignore_extensions(Rest, MaxHeaderSize, MaxHeaderSize, + {?MODULE, decode_trailer, + [<<>>, [],[], <<BodySoFar/binary, Data/binary>>, integer_to_list(AccLength)]}); <<Data:ChunkSize/binary, ?CR, ?LF, "0", ?CR, ?LF>> -> - {?MODULE, decode_trailer, [<<?CR, ?LF>>, [],[], MaxHeaderSize, + {?MODULE, decode_trailer, [<<?CR, ?LF>>, [],[], <<BodySoFar/binary, Data/binary>>, - integer_to_list(AccLength)]}; + integer_to_list(AccLength), MaxHeaderSize, MaxHeaderSize]}; <<Data:ChunkSize/binary, ?CR, ?LF, "0", ?CR, ?LF, Rest/binary>> -> - decode_trailer(<<?CR, ?LF, Rest/binary>>, [],[], MaxHeaderSize, + decode_trailer(<<?CR, ?LF, Rest/binary>>, [],[], <<BodySoFar/binary, Data/binary>>, - integer_to_list(AccLength)); - %% There are more chunks, so here we go agin... + integer_to_list(AccLength), MaxHeaderSize, MaxHeaderSize); + %% There are more chunks, so here we go again... <<Data:ChunkSize/binary, ?CR, ?LF>> -> NewBody = <<BodySoFar/binary, Data/binary>>, - {?MODULE, decode_size, [<<>>, [], {MaxBodySize, NewBody, AccLength, MaxHeaderSize}]}; + {?MODULE, decode_size, [<<>>, [], 0, {MaxBodySize, NewBody, AccLength, MaxHeaderSize}]}; <<Data:ChunkSize/binary, ?CR, ?LF, Rest/binary>> when (AccLength < MaxBodySize) or (MaxBodySize == nolimit) -> - decode_size(Rest, [], + decode_size(Rest, [], 0, {MaxBodySize, <<BodySoFar/binary, Data/binary>>, AccLength, MaxHeaderSize}); <<_:ChunkSize/binary, ?CR, ?LF, _/binary>> -> - throw({error, body_too_big}); + throw({error, {body_too_big, {max, MaxBodySize}}}); _ -> {?MODULE, decode_data, [ChunkSize, TotalChunk, Info]} end; decode_data(ChunkSize, TotalChunk, Info) -> {?MODULE, decode_data, [ChunkSize, TotalChunk, Info]}. -decode_trailer(<<>>, Header, Headers, MaxHeaderSize, Body, BodyLength) -> - {?MODULE, decode_trailer, [<<>>, Header, Headers, MaxHeaderSize, Body, - BodyLength]}; - +decode_trailer(_,_,_,_,_, 0, TotalMaxHeaderSize) -> + throw({error, {header_too_long, {max, TotalMaxHeaderSize}}}); +decode_trailer(<<>>, Header, Headers, Body, BodyLength, RemainingSize, TotalMaxHeaderSize) -> + {?MODULE, decode_trailer, [<<>>, Header, Headers, Body, + BodyLength, RemainingSize, TotalMaxHeaderSize]}; %% Note: If Bin is not empty it is part of a pipelined request/response. -decode_trailer(<<?CR,?LF,?CR,?LF, Bin/binary>>, [], [], _, Body, BodyLength) -> +decode_trailer(<<?CR,?LF,?CR,?LF, Bin/binary>>, [], [], Body, BodyLength, _, _) -> {ok, {["content-length:" ++ BodyLength], <<Body/binary, Bin/binary>>}}; decode_trailer(<<?CR,?LF,?CR,?LF, Bin/binary>>, - Header, Headers, MaxHeaderSize, Body, BodyLength) -> + Header, Headers, Body, BodyLength, _, _) -> NewHeaders = case Header of [] -> Headers; _ -> [lists:reverse(Header) | Headers] end, - Length = length(NewHeaders), - case Length > MaxHeaderSize of - true -> - throw({error, {header_too_long, MaxHeaderSize, - MaxHeaderSize-Length}}); - false -> - {ok, {["content-length:" ++ BodyLength | NewHeaders], - <<Body/binary, Bin/binary>>}} - end; -decode_trailer(<<?CR,?LF,?CR>> = Data, Header, Headers, MaxHeaderSize, - Body, BodyLength) -> - {?MODULE, decode_trailer, [Data, Header, Headers, MaxHeaderSize, Body, - BodyLength]}; -decode_trailer(<<?CR,?LF>> = Data, Header, Headers, MaxHeaderSize, - Body, BodyLength) -> - {?MODULE, decode_trailer, [Data, Header, Headers, MaxHeaderSize, Body, - BodyLength]}; -decode_trailer(<<?CR>> = Data, Header, Headers, MaxHeaderSize, - Body, BodyLength) -> - {?MODULE, decode_trailer, [Data, Header, Headers, MaxHeaderSize, Body, - BodyLength]}; -decode_trailer(<<?CR, ?LF, Rest/binary>>, Header, Headers, - MaxHeaderSize, Body, BodyLength) -> + {ok, {["content-length:" ++ BodyLength | NewHeaders], + <<Body/binary, Bin/binary>>}}; +decode_trailer(<<?CR,?LF,?CR>> = Data, Header, Headers, + Body, BodyLength, RemainingSize, TotalMaxHeaderSize) -> + {?MODULE, decode_trailer, [Data, Header, Headers, Body, + BodyLength, RemainingSize, TotalMaxHeaderSize]}; +decode_trailer(<<?CR,?LF>> = Data, Header, Headers, + Body, BodyLength, RemainingSize, TotalMaxHeaderSize) -> + {?MODULE, decode_trailer, [Data, Header, Headers, Body, + BodyLength, RemainingSize, TotalMaxHeaderSize]}; +decode_trailer(<<?CR>> = Data, Header, Headers, + Body, BodyLength, RemainingSize, TotalMaxHeaderSize) -> + {?MODULE, decode_trailer, [Data, Header, Headers, Body, + BodyLength, RemainingSize, TotalMaxHeaderSize]}; +decode_trailer(<<?CR, ?LF, Rest/binary>>, Header, Headers, Body, BodyLength, RemainingSize, TotalMaxHeaderSize) -> decode_trailer(Rest, [], [lists:reverse(Header) | Headers], - MaxHeaderSize, Body, BodyLength); + Body, BodyLength, RemainingSize, TotalMaxHeaderSize); +decode_trailer(<<Octet, Rest/binary>>, Header, Headers, Body, + BodyLength, RemainingSize, TotalMaxHeaderSize) -> + decode_trailer(Rest, [Octet | Header], Headers, + Body, BodyLength, remaing_size(RemainingSize, 1), TotalMaxHeaderSize). + +remaing_size(nolimit, _) -> + nolimit; +remaing_size(Total, Consumed) -> + Total - Consumed. -decode_trailer(<<Octet, Rest/binary>>, Header, Headers, MaxHeaderSize, Body, - BodyLength) -> - decode_trailer(Rest, [Octet | Header], Headers, MaxHeaderSize, - Body, BodyLength). +encode_trailers(Trailers) -> + encode_trailers(Trailers, ""). + +encode_trailers([], Acc) -> + Acc ++ ?CRLF ++ ?CRLF; +encode_trailers([{Header, Value} | Rest], Acc) -> + encode_trailers(Rest, Header ++ ":" ++ Value ++ ?CRLF ++ Acc). diff --git a/lib/inets/src/http_lib/http_response.erl b/lib/inets/src/http_lib/http_response.erl index 58b30c4e9e..42e5dd263d 100644 --- a/lib/inets/src/http_lib/http_response.erl +++ b/lib/inets/src/http_lib/http_response.erl @@ -31,16 +31,11 @@ %% Value - string() %% %% Description: Creates a http_response_h-record used internally to -%% handle http-headers. +%% handle http-headers, assumes reversed list of headers +%% to unfold multiline headers with obs-folds %%------------------------------------------------------------------------- -headers([], Headers) -> - Headers; - -headers([Header | Tail], Headers) -> - {Key, [$: | Value]} = - lists:splitwith(fun($:) -> false; (_) -> true end, Header), - headers(Tail, headers(http_util:to_lower(string:strip(Key)), - string:strip(Value), Headers)). +headers(RevLines, Headers) -> + fill_headers(RevLines, [], Headers). %%------------------------------------------------------------------------- %% headers(#http_response_h{}) -> HeaderList @@ -68,6 +63,25 @@ header_list(Headers) -> %%%======================================================================== %%% Internal functions %%%======================================================================== +fill_headers([], _, Headers) -> + Headers; +fill_headers([[]], _, Headers) -> + Headers; +fill_headers([[Ch|HeaderFold]|Tail], Folded, Headers) + when Ch == $\t; Ch == $\s -> + fill_headers(Tail, [HeaderFold|Folded], Headers); +fill_headers([Header | Tail], Folded, Headers) -> + Unfolded = unfold([Header|Folded]), + {Key, [$: | Value]} = + lists:splitwith(fun($:) -> false; (_) -> true end, Unfolded), + fill_headers(Tail, [], headers(http_util:to_lower(string:strip(Key)), + string:strip(Value), Headers)). + +unfold([L]) -> + L; +unfold(Folded) -> + string:join(Folded, " "). + headers("cache-control", Value, Headers) -> Headers#http_response_h{'cache-control'= Value}; headers("connection", Value, Headers) -> diff --git a/lib/inets/src/http_lib/http_transport.erl b/lib/inets/src/http_lib/http_transport.erl index bbe3ec9e4c..ab6afe9c6c 100644 --- a/lib/inets/src/http_lib/http_transport.erl +++ b/lib/inets/src/http_lib/http_transport.erl @@ -40,12 +40,6 @@ -include_lib("inets/src/inets_app/inets_internal.hrl"). -include("http_internal.hrl"). --define(SERVICE, httpl). --define(hlri(Label, Content), ?report_important(Label, ?SERVICE, Content)). --define(hlrv(Label, Content), ?report_verbose(Label, ?SERVICE, Content)). --define(hlrd(Label, Content), ?report_debug(Label, ?SERVICE, Content)). --define(hlrt(Label, Content), ?report_trace(Label, ?SERVICE, Content)). - %%%========================================================================= %%% Internal application API @@ -55,38 +49,27 @@ %% start(SocketType) -> ok | {error, Reason} %% SocketType = ip_comm | {ssl, _} %% -%% Description: Makes sure inet_db or ssl is started. +%% Description: Makes sure ssl is started. %%------------------------------------------------------------------------- start(ip_comm) -> - do_start_ip_comm(); - -%% This is just for backward compatibillity + ok; +start({ip_comm, _}) -> + ok; start({ssl, _}) -> do_start_ssl(); start({essl, _}) -> do_start_ssl(). - -do_start_ip_comm() -> - case inet_db:start() of - {ok, _} -> - ok; - {error, {already_started, _}} -> - ok; - Error -> - Error - end. - do_start_ssl() -> - case ssl:start() of - ok -> - ok; - {error, {already_started,_}} -> - ok; - Error -> - Error + try lists:foreach(fun(App) -> + ok = application:ensure_started(App) + end, + [crypto, asn1, public_key, ssl]) + catch + _:Reason -> + {error, Reason} end. - + %%------------------------------------------------------------------------- %% connect(SocketType, Address, Options, Timeout) -> @@ -103,12 +86,8 @@ do_start_ssl() -> connect(SocketType, Address, Opts) -> connect(SocketType, Address, Opts, infinity). - -connect(ip_comm = _SocketType, {Host, Port}, Opts0, Timeout) - when is_list(Opts0) -> - Opts = [binary, {packet, 0}, {active, false}, {reuseaddr, true} | Opts0], - ?hlrt("connect using gen_tcp", - [{host, Host}, {port, Port}, {opts, Opts}, {timeout, Timeout}]), +connect(ip_comm, {Host, Port}, Opts0, Timeout) -> + Opts = [binary, {packet, 0}, {active, false}, {reuseaddr, true} | Opts0 ], try gen_tcp:connect(Host, Port, Opts, Timeout) of {ok, _} = OK -> OK; @@ -127,11 +106,6 @@ connect({ssl, SslConfig}, Address, Opts, Timeout) -> connect({essl, SslConfig}, {Host, Port}, Opts0, Timeout) -> Opts = [binary, {active, false}, {ssl_imp, new} | Opts0] ++ SslConfig, - ?hlrt("connect using essl", - [{host, Host}, - {port, Port}, - {ssl_config, SslConfig}, - {timeout, Timeout}]), case (catch ssl:connect(Host, Port, Opts, Timeout)) of {'EXIT', Reason} -> {error, {eoptions, Reason}}; @@ -156,29 +130,23 @@ connect({essl, SslConfig}, {Host, Port}, Opts0, Timeout) -> %% reason for this to enable a HTTP-server not running as root to use %% port 80. %%------------------------------------------------------------------------- -listen(ip_comm = _SocketType, Addr, Port, Fd, IpFamily) -> - listen_ip_comm(Addr, Port, Fd, IpFamily); - +listen(ip_comm, Addr, Port, Fd, IpFamily) -> + listen_ip_comm(Addr, Port, [], Fd, IpFamily); + +listen({ip_comm, SockOpts}, Addr, Port, Fd, IpFamily) -> + listen_ip_comm(Addr, Port, SockOpts, Fd, IpFamily); + listen({essl, SSLConfig}, Addr, Port, Fd, IpFamily) -> listen_ssl(Addr, Port, Fd, SSLConfig, IpFamily, []). -listen(ip_comm = _SocketType, Addr, Port, IpFamily) -> - listen_ip_comm(Addr, Port, undefined, IpFamily); +listen(ip_comm, Addr, Port, IpFamily) -> + listen_ip_comm(Addr, Port, [], undefined, IpFamily); %% Wrapper for backaward compatibillity listen({ssl, SSLConfig}, Addr, Port, IpFamily) -> - ?hlrt("listen (wrapper)", - [{addr, Addr}, - {port, Port}, - {ssl_config, SSLConfig}]), listen({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Addr, Port, IpFamily); - listen({essl, SSLConfig}, Addr, Port, IpFamily) -> - ?hlrt("listen (essl)", - [{addr, Addr}, - {port, Port}, - {ssl_config, SSLConfig}]), {SSLConfig2, ExtraOpts} = case proplists:get_value(log_alert, SSLConfig, undefined) of undefined -> {SSLConfig, []}; @@ -187,89 +155,36 @@ listen({essl, SSLConfig}, Addr, Port, IpFamily) -> end, listen_ssl(Addr, Port, undefined, SSLConfig2, IpFamily, ExtraOpts). -listen_ip_comm(Addr, Port, Fd, IpFamily) -> - case (catch do_listen_ip_comm(Addr, Port, Fd, IpFamily)) of +listen_ip_comm(Addr, Port, SockOpts, Fd, IpFamily) -> + case (catch do_listen_ip_comm(Addr, Port, SockOpts, Fd, IpFamily)) of {'EXIT', Reason} -> {error, {exit, Reason}}; Else -> Else end. -do_listen_ip_comm(Addr, Port, Fd, IpFamily) -> - {NewPort, Opts} = get_socket_info(Addr, Port, Fd), - case IpFamily of - inet6fb4 -> - Opts2 = [inet6 | Opts], - ?hlrt("try ipv6 listen", [{port, NewPort}, {opts, Opts2}]), - case (catch gen_tcp:listen(NewPort, Opts2)) of - {error, Reason} when ((Reason =:= nxdomain) orelse - (Reason =:= eafnosupport)) -> - Opts3 = [inet | Opts], - ?hlrt("ipv6 listen failed - try ipv4 instead", - [{reason, Reason}, {port, NewPort}, {opts, Opts3}]), - gen_tcp:listen(NewPort, Opts3); - - %% This is when a given hostname has resolved to a - %% IPv4-address. The inet6-option together with a - %% {ip, IPv4} option results in badarg - {'EXIT', Reason} -> - Opts3 = [inet | Opts], - ?hlrt("ipv6 listen exit - try ipv4 instead", - [{reason, Reason}, {port, NewPort}, {opts, Opts3}]), - gen_tcp:listen(NewPort, Opts3); - - Other -> - ?hlrt("ipv6 listen done", [{other, Other}]), - Other - end; - _ -> - Opts2 = [IpFamily | Opts], - ?hlrt("listen", [{port, NewPort}, {opts, Opts2}]), - gen_tcp:listen(NewPort, Opts2) - end. +do_listen_ip_comm(Addr, Port, SockOpts, Fd, IpFamily) -> + Backlog = proplists:get_value(backlog, SockOpts, 128), + {NewPort, Opts} = get_socket_info(Addr, Port, Fd, + [{backlog, Backlog}, {reuseaddr, true} | SockOpts]), + Opts2 = [IpFamily | Opts], + gen_tcp:listen(NewPort, Opts2). listen_ssl(Addr, Port, Fd, Opts0, IpFamily, ExtraOpts) -> - {NewPort, SockOpt} = get_socket_info(Addr, Port, Fd), + Backlog = proplists:get_value(backlog, Opts0, 128), + {NewPort, SockOpt} = get_socket_info(Addr, Port, Fd, + [{backlog, Backlog}, {reuseaddr, true}]), Opts = SockOpt ++ Opts0, - case IpFamily of - inet6fb4 -> - Opts2 = [inet6 | Opts] ++ ExtraOpts, - ?hlrt("try ipv6 listen", [{opts, Opts2}]), - case (catch ssl:listen(Port, Opts2)) of - {error, Reason} when ((Reason =:= nxdomain) orelse - (Reason =:= eafnosupport)) -> - Opts3 = [inet | Opts] ++ ExtraOpts, - ?hlrt("ipv6 listen failed - try ipv4 instead", - [{reason, Reason}, {opts, Opts3}]), - ssl:listen(NewPort, Opts3); - - {'EXIT', Reason} -> - Opts3 = [inet | Opts] ++ ExtraOpts, - ?hlrt("ipv6 listen exit - try ipv4 instead", - [{reason, Reason}, {opts, Opts3}]), - ssl:listen(NewPort, Opts3); - - Other -> - ?hlrt("ipv6 listen done", [{other, Other}]), - Other - end; - - _ -> - Opts2 = [IpFamily | Opts], - ?hlrt("listen", [{opts, Opts2}]), - ssl:listen(NewPort, Opts2 ++ ExtraOpts) - end. + Opts2 = [IpFamily | Opts], + ssl:listen(NewPort, Opts2 ++ ExtraOpts). - - -get_socket_info(Addr, Port, Fd) -> - BaseOpts = [{backlog, 128}, {reuseaddr, true}], +get_socket_info(Addr, Port, Fd, BaseOpts) -> %% The presence of a file descriptor takes precedence case Fd of undefined -> {Port, sock_opts(Addr, BaseOpts)}; Fd -> - {0, sock_opts(Addr, [{fd, Fd} | BaseOpts])} + {0, sock_opts([{fd, Fd} | BaseOpts])} end. %%------------------------------------------------------------------------- @@ -288,6 +203,8 @@ accept(SocketType, ListenSocket) -> accept(ip_comm, ListenSocket, Timeout) -> gen_tcp:accept(ListenSocket, Timeout); +accept({ip_comm, _}, ListenSocket, Timeout) -> + gen_tcp:accept(ListenSocket, Timeout); %% Wrapper for backaward compatibillity accept({ssl, SSLConfig}, ListenSocket, Timeout) -> @@ -307,6 +224,8 @@ accept({essl, _SSLConfig}, ListenSocket, Timeout) -> %%------------------------------------------------------------------------- controlling_process(ip_comm, Socket, NewOwner) -> gen_tcp:controlling_process(Socket, NewOwner); +controlling_process({ip_comm, _}, Socket, NewOwner) -> + gen_tcp:controlling_process(Socket, NewOwner); %% Wrapper for backaward compatibillity controlling_process({ssl, SSLConfig}, Socket, NewOwner) -> @@ -325,7 +244,8 @@ controlling_process({essl, _}, Socket, NewOwner) -> %% gen_tcp or ssl. %%------------------------------------------------------------------------- setopts(ip_comm, Socket, Options) -> - ?hlrt("ip_comm setopts", [{socket, Socket}, {options, Options}]), + inet:setopts(Socket, Options); +setopts({ip_comm, _}, Socket, Options) -> inet:setopts(Socket, Options); %% Wrapper for backaward compatibillity @@ -333,10 +253,7 @@ setopts({ssl, SSLConfig}, Socket, Options) -> setopts({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket, Options); setopts({essl, _}, Socket, Options) -> - ?hlrt("[e]ssl setopts", [{socket, Socket}, {options, Options}]), - Reason = (catch ssl:setopts(Socket, Options)), - ?hlrt("[e]ssl setopts result", [{reason, Reason}]), - Reason. + (catch ssl:setopts(Socket, Options)). %%------------------------------------------------------------------------- @@ -350,8 +267,10 @@ getopts(SocketType, Socket) -> Opts = [packet, packet_size, recbuf, sndbuf, priority, tos, send_timeout], getopts(SocketType, Socket, Opts). +getopts({ip_comm, _}, Socket, Options) -> + getopts(ip_comm, Socket, Options); + getopts(ip_comm, Socket, Options) -> - ?hlrt("ip_comm getopts", [{socket, Socket}, {options, Options}]), case inet:getopts(Socket, Options) of {ok, SocketOpts} -> SocketOpts; @@ -364,7 +283,6 @@ getopts({ssl, SSLConfig}, Socket, Options) -> getopts({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket, Options); getopts({essl, _}, Socket, Options) -> - ?hlrt("essl getopts", [{socket, Socket}, {options, Options}]), getopts_ssl(Socket, Options). getopts_ssl(Socket, Options) -> @@ -384,7 +302,6 @@ getopts_ssl(Socket, Options) -> %% Description: Gets the socket stats values for the socket %%------------------------------------------------------------------------- getstat(ip_comm = _SocketType, Socket) -> - ?hlrt("ip_comm getstat", [{socket, Socket}]), case inet:getstat(Socket) of {ok, Stats} -> Stats; @@ -409,6 +326,8 @@ getstat({essl, _} = _SocketType, _Socket) -> %%------------------------------------------------------------------------- send(ip_comm, Socket, Message) -> gen_tcp:send(Socket, Message); +send({ip_comm, _}, Socket, Message) -> + gen_tcp:send(Socket, Message); %% Wrapper for backaward compatibillity send({ssl, SSLConfig}, Socket, Message) -> @@ -417,7 +336,6 @@ send({ssl, SSLConfig}, Socket, Message) -> send({essl, _}, Socket, Message) -> ssl:send(Socket, Message). - %%------------------------------------------------------------------------- %% close(SocketType, Socket) -> ok | {error, Reason} %% SocketType = ip_comm | {ssl, _} @@ -427,6 +345,8 @@ send({essl, _}, Socket, Message) -> %%------------------------------------------------------------------------- close(ip_comm, Socket) -> gen_tcp:close(Socket); +close({ip_comm, []}, Socket) -> + gen_tcp:close(Socket); %% Wrapper for backaward compatibillity close({ssl, SSLConfig}, Socket) -> @@ -448,6 +368,8 @@ close({essl, _}, Socket) -> %%------------------------------------------------------------------------- peername(ip_comm, Socket) -> do_peername(inet:peername(Socket)); +peername({ip_comm, _}, Socket) -> + do_peername(inet:peername(Socket)); %% Wrapper for backaward compatibillity peername({ssl, SSLConfig}, Socket) -> @@ -480,7 +402,8 @@ do_peername({error, _}) -> %%------------------------------------------------------------------------- sockname(ip_comm, Socket) -> do_sockname(inet:sockname(Socket)); - +sockname({ip_comm, _}, Socket) -> + do_sockname(inet:sockname(Socket)); %% Wrapper for backaward compatibillity sockname({ssl, SSLConfig}, Socket) -> sockname({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket); @@ -555,28 +478,13 @@ sock_opts(Opts) -> %% -- negotiate -- negotiate(ip_comm,_,_) -> - ?hlrt("negotiate(ip_comm)", []), + ok; +negotiate({ip_comm, _},_,_) -> ok; negotiate({ssl, SSLConfig}, Socket, Timeout) -> - ?hlrt("negotiate(ssl)", []), negotiate({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket, Timeout); negotiate({essl, _}, Socket, Timeout) -> - ?hlrt("negotiate(essl)", []), negotiate_ssl(Socket, Timeout). negotiate_ssl(Socket, Timeout) -> - ?hlrt("negotiate_ssl", [{socket, Socket}, {timeout, Timeout}]), - case ssl:ssl_accept(Socket, Timeout) of - ok -> - ok; - {error, Reason} -> - ?hlrd("negotiate_ssl - accept failed", [{reason, Reason}]), - %% Look for "valid" error reasons - ValidReasons = [timeout, econnreset, esslaccept, esslerrssl], - case lists:member(Reason, ValidReasons) of - true -> - {error, normal}; - false -> - {error, Reason} - end - end. + ssl:ssl_accept(Socket, Timeout). diff --git a/lib/inets/src/http_lib/http_uri.erl b/lib/inets/src/http_lib/http_uri.erl index 79591eec29..9940136f5a 100644 --- a/lib/inets/src/http_lib/http_uri.erl +++ b/lib/inets/src/http_lib/http_uri.erl @@ -138,16 +138,33 @@ parse_scheme(AbsURI, Opts) -> {error, no_scheme} -> {error, no_scheme}; {SchemeStr, Rest} -> - Scheme = list_to_atom(http_util:to_lower(SchemeStr)), - SchemeDefaults = which_scheme_defaults(Opts), - case lists:keysearch(Scheme, 1, SchemeDefaults) of - {value, {Scheme, DefaultPort}} -> - {Scheme, DefaultPort, Rest}; - false -> - {Scheme, no_default_port, Rest} + case extract_scheme(SchemeStr, Opts) of + {error, Error} -> + {error, Error}; + {ok, Scheme} -> + SchemeDefaults = which_scheme_defaults(Opts), + case lists:keysearch(Scheme, 1, SchemeDefaults) of + {value, {Scheme, DefaultPort}} -> + {Scheme, DefaultPort, Rest}; + false -> + {Scheme, no_default_port, Rest} + end end end. +extract_scheme(Str, Opts) -> + case lists:keysearch(scheme_validation_fun, 1, Opts) of + {value, {scheme_validation_fun, Fun}} when is_function(Fun) -> + case Fun(Str) of + valid -> + {ok, list_to_atom(http_util:to_lower(Str))}; + {error, Error} -> + {error, Error} + end; + _ -> + {ok, list_to_atom(http_util:to_lower(Str))} + end. + parse_uri_rest(Scheme, DefaultPort, "//" ++ URIPart, Opts) -> {Authority, PathQueryFragment} = split_uri(URIPart, "[/?#]", {URIPart, ""}, 1, 0), @@ -179,10 +196,10 @@ parse_host_port(_Scheme, DefaultPort, HostPort, _Opts) -> {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))}; + case re:run(UriPart, SplitChar, [{capture, first}]) of + {match, [{Match, _}]} -> + {string:substr(UriPart, 1, Match + 1 - SkipLeft), + string:substr(UriPart, Match + 1 + SkipRight, length(UriPart))}; nomatch -> NoMatchResult end. diff --git a/lib/inets/src/http_lib/http_util.erl b/lib/inets/src/http_lib/http_util.erl index 0d07231302..aafa97afee 100644 --- a/lib/inets/src/http_lib/http_util.erl +++ b/lib/inets/src/http_lib/http_util.erl @@ -152,27 +152,11 @@ convert_netscapecookie_date([_D,_A,_Y, _SP, Sec=list_to_integer([S1,S2]), {{Year,Month,Day},{Hour,Min,Sec}}. -hexlist_to_integer([]) -> - empty; -%%When the string only contains one value its eaasy done. -%% 0-9 -hexlist_to_integer([Size]) when (Size >= 48) andalso (Size =< 57) -> - Size - 48; -%% A-F -hexlist_to_integer([Size]) when (Size >= 65) andalso (Size =< 70) -> - Size - 55; -%% a-f -hexlist_to_integer([Size]) when (Size >= 97) andalso (Size =< 102) -> - Size - 87; -hexlist_to_integer([_Size]) -> - not_a_num; +hexlist_to_integer(List) -> + list_to_integer(List, 16). -hexlist_to_integer(Size) -> - Len = string:span(Size, "1234567890abcdefABCDEF"), - hexlist_to_integer2(Size, 16 bsl (4 *(Len-2)),0). - -integer_to_hexlist(Num)-> - integer_to_hexlist(Num, get_size(Num), []). +integer_to_hexlist(Int) -> + integer_to_list(Int, 16). convert_month("Jan") -> 1; convert_month("Feb") -> 2; @@ -213,51 +197,6 @@ html_encode(Chars) -> %%%======================================================================== %%% Internal functions %%%======================================================================== -hexlist_to_integer2([],_Pos,Sum)-> - Sum; -hexlist_to_integer2([HexVal | HexString], Pos, Sum) - when HexVal >= 48, HexVal =< 57 -> - hexlist_to_integer2(HexString, Pos bsr 4, Sum + ((HexVal-48) * Pos)); - -hexlist_to_integer2([HexVal | HexString], Pos, Sum) - when HexVal >= 65, HexVal =<70 -> - hexlist_to_integer2(HexString, Pos bsr 4, Sum + ((HexVal-55) * Pos)); - -hexlist_to_integer2([HexVal | HexString], Pos, Sum) - when HexVal>=97, HexVal=<102 -> - hexlist_to_integer2(HexString, Pos bsr 4, Sum + ((HexVal-87) * Pos)); - -hexlist_to_integer2(_AfterHexString, _Pos, Sum)-> - Sum. - -integer_to_hexlist(Num, Pot, Res) when Pot < 0 -> - convert_to_ascii([Num | Res]); - -integer_to_hexlist(Num,Pot,Res) -> - Position = (16 bsl (Pot*4)), - PosVal = Num div Position, - integer_to_hexlist(Num - (PosVal*Position), Pot-1, [PosVal | Res]). - -get_size(Num)-> - get_size(Num, 0). - -get_size(Num, Pot) when Num < (16 bsl(Pot *4)) -> - Pot-1; - -get_size(Num, Pot) -> - get_size(Num, Pot+1). - -convert_to_ascii(RevesedNum) -> - convert_to_ascii(RevesedNum, []). - -convert_to_ascii([], Num)-> - Num; -convert_to_ascii([Num | Reversed], Number) - when (Num > -1) andalso (Num < 10) -> - convert_to_ascii(Reversed, [Num + 48 | Number]); -convert_to_ascii([Num | Reversed], Number) - when (Num > 9) andalso (Num < 16) -> - convert_to_ascii(Reversed, [Num + 55 | Number]). char_to_html_entity(Char, Reserved) -> case sets:is_element(Char, Reserved) of diff --git a/lib/inets/src/http_server/Makefile b/lib/inets/src/http_server/Makefile index b09877550d..1c05d454a5 100644 --- a/lib/inets/src/http_server/Makefile +++ b/lib/inets/src/http_server/Makefile @@ -40,6 +40,10 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) # ---------------------------------------------------- # Target Specs # ---------------------------------------------------- + +BEHAVIOUR_MODULES= \ + httpd_custom_api + MODULES = \ httpd \ httpd_acceptor \ @@ -86,10 +90,13 @@ MODULES = \ HRL_FILES = httpd.hrl httpd_internal.hrl mod_auth.hrl -ERL_FILES = $(MODULES:%=%.erl) +ERL_FILES = $(MODULES:%=%.erl)\ + $(BEHAVIOUR_MODULES:%=%.erl) TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) +BEHAVIOUR_TARGET_FILES= $(BEHAVIOUR_MODULES:%=$(EBIN)/%.$(EMULATOR)) + INETS_FLAGS = -D'SERVER_SOFTWARE="$(APPLICATION)/$(VSN)"' @@ -109,11 +116,12 @@ ERL_COMPILE_FLAGS += \ # ---------------------------------------------------- # Targets # ---------------------------------------------------- +$(TARGET_FILES): $(BEHAVIOUR_TARGET_FILES) debug opt: $(TARGET_FILES) clean: - rm -f $(TARGET_FILES) + rm -f $(TARGET_FILES) $(BEHAVIOUR_TARGET_FILES) rm -f core docs: @@ -129,7 +137,7 @@ release_spec: opt $(INSTALL_DIR) "$(RELSYSDIR)/src/http_server" $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) "$(RELSYSDIR)/src/http_server" $(INSTALL_DIR) "$(RELSYSDIR)/ebin" - $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin" + $(INSTALL_DATA) $(TARGET_FILES) $(BEHAVIOUR_TARGET_FILES) "$(RELSYSDIR)/ebin" release_docs_spec: diff --git a/lib/inets/src/http_server/httpd.erl b/lib/inets/src/http_server/httpd.erl index cf02c0e072..e6377b4882 100644 --- a/lib/inets/src/http_server/httpd.erl +++ b/lib/inets/src/http_server/httpd.erl @@ -43,7 +43,7 @@ %%%======================================================================== parse_query(String) -> - {ok, SplitString} = inets_regexp:split(String,"[&;]"), + SplitString = re:split(String,"[&;]", [{return, list}]), foreach(SplitString). reload_config(Config = [Value| _], Mode) when is_tuple(Value) -> @@ -239,14 +239,14 @@ unblock(Addr, Port, Profile) when is_integer(Port) -> foreach([]) -> []; foreach([KeyValue|Rest]) -> - {ok, Plus2Space, _} = inets_regexp:gsub(KeyValue,"[\+]"," "), - case inets_regexp:split(Plus2Space,"=") of - {ok,[Key|Value]} -> - [{http_uri:decode(Key), - http_uri:decode(lists:flatten(Value))}|foreach(Rest)]; - {ok,_} -> - foreach(Rest) - end. + Plus2Space = re:replace(KeyValue,"[\+]"," ", [{return,list}, global]), + case re:split(Plus2Space,"=", [{return, list}]) of + [Key|Value] -> + [{http_uri:decode(Key), + http_uri:decode(lists:flatten(Value))}|foreach(Rest)]; + _ -> + foreach(Rest) + end. make_name(Addr, Port, Profile) -> diff --git a/lib/inets/src/http_server/httpd_conf.erl b/lib/inets/src/http_server/httpd_conf.erl index 7d31989244..132e1b5b7a 100644 --- a/lib/inets/src/http_server/httpd_conf.erl +++ b/lib/inets/src/http_server/httpd_conf.erl @@ -156,7 +156,7 @@ load("BindAddress " ++ Address0, []) -> case string:tokens(Address0, [$|]) of [Address1] -> ?hdrv("load BindAddress", [{address1, Address1}]), - {clean_address(Address1), inet6fb4}; + {clean_address(Address1), inet}; [Address1, IpFamilyStr] -> ?hdrv("load BindAddress", [{address1, Address1}, @@ -232,7 +232,7 @@ load("KeepAliveTimeout " ++ Timeout, []) -> end; load("Modules " ++ Modules, []) -> - {ok, ModuleList} = inets_regexp:split(Modules," "), + ModuleList = re:split(Modules," ", [{return, list}]), {ok, [], {modules,[list_to_atom(X) || X <- ModuleList]}}; load("ServerAdmin " ++ ServerAdmin, []) -> @@ -353,14 +353,21 @@ clean_address(Addr) -> make_ipfamily(IpFamilyStr) -> - IpFamily = list_to_atom(IpFamilyStr), - case lists:member(IpFamily, [inet, inet6, inet6fb4]) of - true -> - IpFamily; - false -> - throw({error, {bad_ipfamily, IpFamilyStr}}) - end. - + validate_ipfamily(list_to_atom(IpFamilyStr)). + +validate_ipfamily(inet) -> + inet; +validate_ipfamily(inet6) -> + inet6; +%% Backwards compatibility wrapper, +%% fallback to the default, IPV4, +%% as it will most proably work. +%% IPv6 standard moved away from +%% beeing able to fallback to ipv4 +validate_ipfamily(inet6fb4) -> + inet; +validate_ipfamily(IpFamilyStr) -> + throw({error, {bad_ipfamily, IpFamilyStr}}). %% %% load_mime_types/1 -> {ok, MimeTypes} | {error, Reason} @@ -393,20 +400,16 @@ validate_properties2(Properties) -> undefined -> case proplists:get_value(sock_type, Properties, ip_comm) of ip_comm -> - case proplists:get_value(ipfamily, Properties) of - undefined -> - [{bind_address, any}, - {ipfamily, inet6fb4} | Properties]; - _ -> - [{bind_address, any} | Properties] - end; + add_inet_defaults(Properties); + {ip_comm, _} -> + add_inet_defaults(Properties); _ -> [{bind_address, any} | Properties] end; any -> Properties; Address0 -> - IpFamily = proplists:get_value(ipfamily, Properties, inet6fb4), + IpFamily = proplists:get_value(ipfamily, Properties, inet), case httpd_util:ip_address(Address0, IpFamily) of {ok, Address} -> Properties1 = proplists:delete(bind_address, Properties), @@ -418,6 +421,16 @@ validate_properties2(Properties) -> throw(Error) end end. + +add_inet_defaults(Properties) -> + case proplists:get_value(ipfamily, Properties) of + undefined -> + [{bind_address, any}, + {ipfamily, inet} | Properties]; + _ -> + [{bind_address, any} | Properties] + end. + check_minimum_bytes_per_second(Properties) -> case proplists:get_value(minimum_bytes_per_second, Properties, false) of false -> @@ -487,12 +500,11 @@ validate_config_params([{server_tokens, Value} | _]) -> validate_config_params([{socket_type, ip_comm} | Rest]) -> validate_config_params(Rest); -validate_config_params([{socket_type, Value} | Rest]) - when Value == ssl; Value == essl -> - validate_config_params(Rest); - -validate_config_params([{socket_type, {Value, _}} | Rest]) - when Value == essl orelse Value == ssl -> +validate_config_params([{socket_type, {Value, Opts}} | Rest]) when Value == ip_comm; + Value == ssl; + Value == essl -> + %% Make sure not to set socket values used internaly + validate_config_params(Opts), validate_config_params(Rest); validate_config_params([{socket_type, Value} | _]) -> @@ -622,21 +634,32 @@ validate_config_params([{disable_chunked_transfer_encoding_send, Value} | validate_config_params([{disable_chunked_transfer_encoding_send, Value} | _ ]) -> throw({disable_chunked_transfer_encoding_send, Value}); +validate_config_params([{Name, _} = Opt | _]) when Name == packet; + Name == mode; + Name == active; + Name == reuseaddr -> + throw({internaly_handled_opt_can_not_be_set, Opt}); validate_config_params([_| Rest]) -> validate_config_params(Rest). -%% It is actually pointless to check bind_address in this way since -%% we need ipfamily to do it properly... is_bind_address(any) -> true; is_bind_address(Value) -> - case httpd_util:ip_address(Value, inet6fb4) of + case is_bind_address(Value, inet) of + false -> + is_bind_address(Value, inet6); + True -> + True + end. + +is_bind_address(Value, IpFamily) -> + case httpd_util:ip_address(Value, IpFamily) of {ok, _} -> true; _ -> false end. - + store(ConfigList0) -> ?hdrd("store", []), try validate_config_params(ConfigList0) of @@ -776,28 +799,6 @@ remove(ConfigDB) -> ets:delete(ConfigDB), ok. -%% config(ConfigDB) -> -%% case httpd_util:lookup(ConfigDB, socket_type, ip_comm) of -%% ssl -> -%% case ssl_certificate_file(ConfigDB) of -%% undefined -> -%% {error, -%% "Directive SSLCertificateFile " -%% "not found in the config file"}; -%% SSLCertificateFile -> -%% {ssl, -%% SSLCertificateFile++ -%% ssl_certificate_key_file(ConfigDB)++ -%% ssl_verify_client(ConfigDB)++ -%% ssl_ciphers(ConfigDB)++ -%% ssl_password(ConfigDB)++ -%% ssl_verify_depth(ConfigDB)++ -%% ssl_ca_certificate_file(ConfigDB)} -%% end; -%% ip_comm -> -%% ip_comm -%% end. - get_config(Address, Port, Profile) -> Tab = httpd_util:make_name("httpd_conf", Address, Port, Profile), @@ -836,6 +837,8 @@ lookup_socket_type(ConfigDB) -> case httpd_util:lookup(ConfigDB, socket_type, ip_comm) of ip_comm -> ip_comm; + {ip_comm, _} = Type -> + Type; {Tag, Conf} -> {Tag, Conf}; SSL when (SSL =:= ssl) orelse (SSL =:= essl) -> @@ -876,7 +879,7 @@ bootstrap([]) -> bootstrap([Line|Config]) -> case Line of "Modules " ++ Modules -> - {ok, ModuleList} = inets_regexp:split(Modules," "), + ModuleList = re:split(Modules," ", [{return, list}]), TheMods = [list_to_atom(X) || X <- ModuleList], case verify_modules(TheMods) of ok -> @@ -1001,7 +1004,8 @@ read_config_file(Stream, SoFar) -> %% Ignore commented lines for efficiency later .. read_config_file(Stream, SoFar); Line -> - {ok, NewLine, _}=inets_regexp:sub(clean(Line),"[\t\r\f ]"," "), + NewLine = re:replace(white_space_clean(Line), + "[\t\r\f ]"," ", [{return,list}, global]), case NewLine of [] -> %% Also ignore empty lines .. @@ -1017,7 +1021,7 @@ parse_mime_types(Stream,MimeTypesList) -> eof -> eof; String -> - white_space_clean(String) + re:replace(white_space_clean(String), "[\t\r\f ]"," ", [{return,list}, global]) end, parse_mime_types(Stream, MimeTypesList, Line). parse_mime_types(Stream, MimeTypesList, eof) -> @@ -1028,17 +1032,19 @@ parse_mime_types(Stream, MimeTypesList, "") -> parse_mime_types(Stream, MimeTypesList, [$#|_]) -> parse_mime_types(Stream, MimeTypesList); parse_mime_types(Stream, MimeTypesList, Line) -> - case inets_regexp:split(Line, " ") of - {ok, [NewMimeType|Suffixes]} -> + case re:split(Line, " ", [{return, list}]) of + [NewMimeType|Suffixes] -> parse_mime_types(Stream, lists:append(suffixes(NewMimeType,Suffixes), MimeTypesList)); - {ok, _} -> + _ -> {error, ?NICE(Line)} end. suffixes(_MimeType,[]) -> []; +suffixes(MimeType,[""|Rest]) -> + suffixes(MimeType, Rest); suffixes(MimeType,[Suffix|Rest]) -> [{Suffix,MimeType}|suffixes(MimeType,Rest)]. @@ -1204,9 +1210,8 @@ error_report(Where,M,F,Error) -> error_logger:error_report([{?MODULE, Where}, {apply, {M, F, []}}, Error]). white_space_clean(String) -> - {ok,CleanedString,_} = - inets_regexp:gsub(String, "^[ \t\n\r\f]*|[ \t\n\r\f]*\$",""), - CleanedString. + re:replace(String, "^[ \t\n\r\f]*|[ \t\n\r\f]*\$","", + [{return,list}, global]). %%%========================================================================= @@ -1243,22 +1248,23 @@ is_file(_Type,_Access,FileInfo,_File) -> {error,FileInfo}. make_integer(String) -> - case inets_regexp:match(string:strip(String),"[0-9]+") of - {match, _, _} -> + case re:run(string:strip(String),"[0-9]+", [{capture, none}]) of + match -> {ok, list_to_integer(string:strip(String))}; nomatch -> {error, nomatch} end. clean(String) -> - {ok,CleanedString,_} = - inets_regexp:gsub(String, "^[ \t\n\r\f]*|[ \t\n\r\f]*\$",""), - CleanedString. + re:replace(String, "^[ \t\n\r\f]*|[ \t\n\r\f]*\$","", + [{return,list}, global]). custom_clean(String,MoreBefore,MoreAfter) -> - {ok,CleanedString,_} = inets_regexp:gsub(String,"^[ \t\n\r\f"++MoreBefore++ - "]*|[ \t\n\r\f"++MoreAfter++"]*\$",""), - CleanedString. + re:replace(String, + "^[ \t\n\r\f"++MoreBefore++ + "]*|[ \t\n\r\f"++MoreAfter++"]*\$","", + [{return,list}, global]). + check_enum(_Enum,[]) -> {error, not_valid}; diff --git a/lib/inets/src/http_server/httpd_custom.erl b/lib/inets/src/http_server/httpd_custom.erl index a1fe058bd1..2b9701ef75 100644 --- a/lib/inets/src/http_server/httpd_custom.erl +++ b/lib/inets/src/http_server/httpd_custom.erl @@ -20,16 +20,27 @@ %% -module(httpd_custom). --export([response_header/1, request_header/1]). --export([customize_headers/3]). +-export([response_header/1, request_header/1, response_default_headers/0]). +-export([customize_headers/3, response_default_headers/1]). --include_lib("inets/src/inets_app/inets_internal.hrl"). +-include("../inets_app/inets_internal.hrl"). + +-behaviour(httpd_custom_api). + +%%-------------------------------------------------------------------- +%% Behavior API ----------------------------------- +%%-------------------------------------------------------------------- response_header(Header) -> {true, httpify(Header)}. request_header(Header) -> {true, Header}. +response_default_headers() -> + []. +%%-------------------------------------------------------------------- +%% Internal API ----------------------------------- +%%-------------------------------------------------------------------- customize_headers(?MODULE, Function, Arg) -> ?MODULE:Function(Arg); customize_headers(Module, Function, Arg) -> @@ -43,6 +54,20 @@ customize_headers(Module, Function, Arg) -> ?MODULE:Function(Arg) end. +response_default_headers(?MODULE) -> + response_default_headers(); +response_default_headers(Module) -> + try Module:response_default_headers() of + Defaults -> + [{http_util:to_lower(Key), Value} || {Key, Value} <- Defaults, + is_list(Key), is_list(Value)] + catch + _:_ -> + ?MODULE:response_default_headers() + end. +%%-------------------------------------------------------------------- +%% Internal functions ----------------------------------- +%%-------------------------------------------------------------------- httpify({Key0, Value}) -> %% make sure first letter is capital (defacto standard) Words1 = string:tokens(Key0, "-"), diff --git a/lib/inets/src/http_server/httpd_custom_api.erl b/lib/inets/src/http_server/httpd_custom_api.erl new file mode 100644 index 0000000000..d5a6fa8715 --- /dev/null +++ b/lib/inets/src/http_server/httpd_custom_api.erl @@ -0,0 +1,32 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2015-2015. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(httpd_custom_api). + +-callback response_default_headers() -> + [{Key::string(), Value::string()}]. +-callback response_header({Key::string(), Value::string()}) -> + {true, {Key::string(), Value::string()}} | false | + {true, string()}. %% Used internally to avoid traversing headers twice +-callback request_header({Key::string(), Value::string()}) -> + {true, {Key::string(), Value::string()}} | false. + +-optional_callbacks([response_default_headers/0, response_header/1, + request_header/1]). diff --git a/lib/inets/src/http_server/httpd_example.erl b/lib/inets/src/http_server/httpd_example.erl index d729affd6d..ad29b5b29a 100644 --- a/lib/inets/src/http_server/httpd_example.erl +++ b/lib/inets/src/http_server/httpd_example.erl @@ -20,11 +20,11 @@ %% -module(httpd_example). -export([print/1]). --export([get/2, post/2, yahoo/2, test1/2, get_bin/2]). +-export([get/2, post/2, yahoo/2, test1/2, get_bin/2, peer/2]). -export([newformat/3]). %% These are used by the inets test-suite --export([delay/1]). +-export([delay/1, chunk_timeout/3]). print(String) -> @@ -94,10 +94,26 @@ default(Env,Input) -> io_lib:format("~p",[httpd:parse_query(Input)]),"\n", footer()]. +peer(Env, Input) -> + Header = + case proplists:get_value(peer_cert, Env) of + undefined -> + header("text/html", "Peer-Cert-Exist:false"); + _ -> + header("text/html", "Peer-Cert-Exist:true") + end, + [Header, + top("Test peer_cert environment option"), + "<B>Peer cert:</B> ", + io_lib:format("~p",[proplists:get_value(peer_cert, Env)]),"\n", + footer()]. + header() -> header("text/html"). header(MimeType) -> "Content-type: " ++ MimeType ++ "\r\n\r\n". +header(MimeType, Other) -> + "Content-type: " ++ MimeType ++ "\r\n" ++ Other ++ "\r\n\r\n". top(Title) -> "<HTML> @@ -142,3 +158,11 @@ i(F) -> i(F,[]). i(F,A) -> io:format(F ++ "~n",A). sleep(T) -> receive after T -> ok end. + +%% ------------------------------------------------------ + +chunk_timeout(SessionID, _, StrInt) -> + mod_esi:deliver(SessionID, "Tranfer-Encoding:chunked/html\r\n\r\n"), + mod_esi:deliver(SessionID, top("Test chunk encoding timeout")), + timer:sleep(20000), + mod_esi:deliver(SessionID, footer()). diff --git a/lib/inets/src/http_server/httpd_request.erl b/lib/inets/src/http_server/httpd_request.erl index abcc0ce898..749f58c197 100644 --- a/lib/inets/src/http_server/httpd_request.erl +++ b/lib/inets/src/http_server/httpd_request.erl @@ -86,7 +86,8 @@ body_data(Headers, Body) -> %%------------------------------------------------------------------------- %% validate(Method, Uri, Version) -> ok | {error, {bad_request, Reason} | %% {error, {not_supported, {Method, Uri, Version}} -%% Method = "HEAD" | "GET" | "POST" | "TRACE" | "PUT" | "DELETE" +%% Method = "HEAD" | "GET" | "POST" | "PATCH" | "TRACE" | "PUT" +%% | "DELETE" %% Uri = uri() %% Version = "HTTP/N.M" %% Description: Checks that HTTP-request-line is valid. @@ -105,6 +106,8 @@ validate("DELETE", Uri, "HTTP/1." ++ _N) -> validate_uri(Uri); validate("POST", Uri, "HTTP/1." ++ _N) -> validate_uri(Uri); +validate("PATCH", Uri, "HTTP/1." ++ _N) -> + validate_uri(Uri); validate("TRACE", Uri, "HTTP/1." ++ N) when hd(N) >= $1 -> validate_uri(Uri); validate(Method, Uri, Version) -> diff --git a/lib/inets/src/http_server/httpd_request_handler.erl b/lib/inets/src/http_server/httpd_request_handler.erl index 25aea56568..8fae9ac46e 100644 --- a/lib/inets/src/http_server/httpd_request_handler.erl +++ b/lib/inets/src/http_server/httpd_request_handler.erl @@ -30,7 +30,7 @@ %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, - terminate/2, code_change/3]). + terminate/2, code_change/3, format_status/2]). -include("httpd.hrl"). -include("http_internal.hrl"). @@ -102,8 +102,8 @@ init([Manager, ConfigDB, AcceptTimeout]) -> KeepAliveTimeOut = 1000 * httpd_util:lookup(ConfigDB, keep_alive_timeout, 150), case http_transport:negotiate(SocketType, Socket, ?HANDSHAKE_TIMEOUT) of - {error, _Error} -> - exit(shutdown); %% Can be 'normal'. + {error, Error} -> + exit({shutdown, Error}); %% Can be 'normal'. ok -> continue_init(Manager, ConfigDB, SocketType, Socket, KeepAliveTimeOut) end. @@ -294,7 +294,10 @@ handle_info(Info, #state{mod = ModData} = State) -> %% cleaning up. When it returns, the gen_server terminates with Reason. %% The return value is ignored. %%-------------------------------------------------------------------- -terminate(normal, State) -> +terminate(Reason, State) when Reason == normal; + Reason == shutdown -> + do_terminate(State); +terminate({shutdown,_}, State) -> do_terminate(State); terminate(Reason, #state{response_sent = false, mod = ModData} = State) -> httpd_response:send_status(ModData, 500, none), @@ -310,6 +313,18 @@ do_terminate(#state{mod = ModData} = State) -> cancel_request_timeout(State), httpd_socket:close(ModData#mod.socket_type, ModData#mod.socket). +format_status(normal, [_, State]) -> + [{data, [{"StateData", State}]}]; +format_status(terminate, [_, State]) -> + Mod = (State#state.mod), + case Mod#mod.socket_type of + ip_comm -> + [{data, [{"StateData", State}]}]; + {essl, _} -> + %% Do not print ssl options in superviosr reports + [{data, [{"StateData", + State#state{mod = Mod#mod{socket_type = 'TLS'}}}]}] + end. %%-------------------------------------------------------------------- %% code_change(OldVsn, State, Extra) -> {ok, NewState} @@ -431,7 +446,7 @@ handle_body(#state{headers = Headers, body = Body, mod = ModData} = State, MaxHeaderSize, MaxBodySize) -> case Headers#http_request_h.'transfer-encoding' of "chunked" -> - case http_chunk:decode(Body, MaxBodySize, MaxHeaderSize) of + try http_chunk:decode(Body, MaxBodySize, MaxHeaderSize) of {Module, Function, Args} -> http_transport:setopts(ModData#mod.socket_type, ModData#mod.socket, @@ -443,6 +458,14 @@ handle_body(#state{headers = Headers, body = Body, mod = ModData} = State, http_chunk:handle_headers(Headers, ChunkedHeaders), handle_response(State#state{headers = NewHeaders, body = NewBody}) + catch + throw:Error -> + httpd_response:send_status(ModData, 400, + "Bad input"), + Reason = io_lib:format("Chunk decoding failed: ~p~n", + [Error]), + error_log(Reason, ModData), + {stop, normal, State#state{response_sent = true}} end; Encoding when is_list(Encoding) -> httpd_response:send_status(ModData, 501, @@ -610,21 +633,10 @@ decrease(N) when is_integer(N) -> decrease(N) -> N. -error_log(ReasonString, Info) -> +error_log(ReasonString, #mod{config_db = ConfigDB}) -> Error = lists:flatten( io_lib:format("Error reading request: ~s", [ReasonString])), - error_log(mod_log, Info, Error), - error_log(mod_disk_log, Info, Error). - -error_log(Mod, #mod{config_db = ConfigDB} = Info, String) -> - Modules = httpd_util:lookup(ConfigDB, modules, - [mod_get, mod_head, mod_log]), - case lists:member(Mod, Modules) of - true -> - Mod:error_log(Info, String); - _ -> - ok - end. + httpd_util:error_log(ConfigDB, Error). %%-------------------------------------------------------------------- diff --git a/lib/inets/src/http_server/httpd_response.erl b/lib/inets/src/http_server/httpd_response.erl index 7e73da7060..c0b5f09faf 100644 --- a/lib/inets/src/http_server/httpd_response.erl +++ b/lib/inets/src/http_server/httpd_response.erl @@ -20,8 +20,8 @@ %% -module(httpd_response). -export([generate_and_send_response/1, send_status/3, send_header/3, - send_body/3, send_chunk/3, send_final_chunk/2, split_header/2, - is_disable_chunked_send/1, cache_headers/2]). + send_body/3, send_chunk/3, send_final_chunk/2, send_final_chunk/3, + split_header/2, is_disable_chunked_send/1, cache_headers/2]). -export([map_status_code/2]). -include_lib("inets/src/inets_app/inets_internal.hrl"). @@ -89,8 +89,7 @@ traverse_modules(ModData,[Module|Rest]) -> "~n Error: ~p" "~n Stack trace: ~p", [Module, T, E, ?STACK()])), - report_error(mod_log, ModData#mod.config_db, String), - report_error(mod_disk_log, ModData#mod.config_db, String), + httpd_util:error_log(ModData#mod.config_db, String), send_status(ModData, 500, none), done end. @@ -245,7 +244,6 @@ send_chunk(_, <<>>, _) -> ok; send_chunk(_, [], _) -> ok; - send_chunk(#mod{http_version = "HTTP/1.1", socket_type = Type, socket = Sock}, Response0, false) -> Response = http_chunk:encode(Response0), @@ -254,10 +252,13 @@ send_chunk(#mod{http_version = "HTTP/1.1", send_chunk(#mod{socket_type = Type, socket = Sock} = _ModData, Response, _) -> httpd_socket:deliver(Type, Sock, Response). +send_final_chunk(Mod, IsDisableChunkedSend) -> + send_final_chunk(Mod, [], IsDisableChunkedSend). + send_final_chunk(#mod{http_version = "HTTP/1.1", - socket_type = Type, socket = Sock}, false) -> - httpd_socket:deliver(Type, Sock, http_chunk:encode_last()); -send_final_chunk(#mod{socket_type = Type, socket = Sock}, _) -> + socket_type = Type, socket = Sock}, Trailers, false) -> + httpd_socket:deliver(Type, Sock, http_chunk:encode_last(Trailers)); +send_final_chunk(#mod{socket_type = Type, socket = Sock}, _, _) -> httpd_socket:close(Type, Sock). is_disable_chunked_send(Db) -> @@ -287,14 +288,21 @@ create_header(ConfigDb, KeyValueTupleHeaders) -> Date = httpd_util:rfc1123_date(), ContentType = "text/html", Server = server(ConfigDb), - Headers0 = add_default_headers([{"date", Date}, - {"content-type", ContentType} - | if Server=="" -> []; - true -> [{"server", Server}] - end - ], - KeyValueTupleHeaders), CustomizeCB = httpd_util:lookup(ConfigDb, customize, httpd_custom), + + CustomDefaults = httpd_custom:response_default_headers(CustomizeCB), + SystemDefaultes = ([{"date", Date}, + {"content-type", ContentType} + | if Server=="" -> []; + true -> [{"server", Server}] + end + ]), + + %% System defaults not present in custom defaults will be added + %% to defaults + Defaults = add_default_headers(SystemDefaultes, CustomDefaults), + + Headers0 = add_default_headers(Defaults, KeyValueTupleHeaders), lists:filtermap(fun(H) -> httpd_custom:customize_headers(CustomizeCB, response_header, H) end, @@ -390,16 +398,6 @@ send_response_old(#mod{socket_type = Type, content_length(Body)-> integer_to_list(httpd_util:flatlength(Body)). -report_error(Mod, ConfigDB, Error) -> - Modules = httpd_util:lookup(ConfigDB, modules, - [mod_get, mod_head, mod_log]), - case lists:member(Mod, Modules) of - true -> - Mod:report_error(ConfigDB, Error); - _ -> - ok - end. - handle_headers([], NewHeaders) -> {ok, NewHeaders}; diff --git a/lib/inets/src/http_server/httpd_script_env.erl b/lib/inets/src/http_server/httpd_script_env.erl index 21b22f4420..1c5d828b46 100644 --- a/lib/inets/src/http_server/httpd_script_env.erl +++ b/lib/inets/src/http_server/httpd_script_env.erl @@ -61,6 +61,19 @@ which_port(#mod{config_db = ConfigDb}) -> which_peername(#mod{init_data = #init_data{peername = {_, RemoteAddr}}}) -> RemoteAddr. +which_peercert(#mod{socket_type = {Type, _}, socket = Socket}) when Type == essl; + Type == ssl -> + case ssl:peercert(Socket) of + {ok, Cert} -> + Cert; + {error, no_peercert} -> + no_peercert; + _ -> + undefined + end; +which_peercert(_) -> %% Not an ssl connection + undefined. + which_resolve(#mod{init_data = #init_data{resolve = Resolve}}) -> Resolve. @@ -78,6 +91,7 @@ create_basic_elements(esi, ModData) -> {server_port, which_port(ModData)}, {request_method, which_method(ModData)}, {remote_addr, which_peername(ModData)}, + {peer_cert, which_peercert(ModData)}, {script_name, which_request_uri(ModData)}]; create_basic_elements(cgi, ModData) -> @@ -104,7 +118,7 @@ create_http_header_elements(ScriptType, [{Name, [Value | _] = Values } | create_http_header_elements(ScriptType, [{Name, Value} | Headers], Acc) when is_list(Value) -> - {ok, NewName, _} = inets_regexp:gsub(Name,"-","_"), + NewName = re:replace(Name,"-","_", [{return,list}, global]), Element = http_env_element(ScriptType, NewName, Value), create_http_header_elements(ScriptType, Headers, [Element | Acc]). diff --git a/lib/inets/src/http_server/httpd_sup.erl b/lib/inets/src/http_server/httpd_sup.erl index de08624d44..bf40cedd5c 100644 --- a/lib/inets/src/http_server/httpd_sup.erl +++ b/lib/inets/src/http_server/httpd_sup.erl @@ -185,12 +185,16 @@ httpd_child_spec(ConfigFile, AcceptTimeoutDef, DebugDef) -> end. httpd_child_spec(Config, AcceptTimeout, Debug, Addr, Port, Profile) -> - Fd = proplists:get_value(fd, Config, undefined), - case Port == 0 orelse Fd =/= undefined of - true -> - httpd_child_spec_listen(Config, AcceptTimeout, Debug, Addr, Port, Profile); - false -> - httpd_child_spec_nolisten(Config, AcceptTimeout, Debug, Addr, Port, Profile) + case get_fd(Port) of + {ok, Fd} -> + case Port == 0 orelse Fd =/= undefined of + true -> + httpd_child_spec_listen(Config, AcceptTimeout, Debug, Addr, Port, Profile); + false -> + httpd_child_spec_nolisten(Config, AcceptTimeout, Debug, Addr, Port, Profile) + end; + Error -> + Error end. httpd_child_spec_listen(Config, AcceptTimeout, Debug, Addr, Port, Profile) -> @@ -236,8 +240,8 @@ listen(Address, Port, Config) -> SocketType -> case http_transport:start(SocketType) of ok -> - Fd = proplists:get_value(fd, Config), - IpFamily = proplists:get_value(ipfamily, Config, inet6fb4), + {ok, Fd} = get_fd(Port), + IpFamily = proplists:get_value(ipfamily, Config, inet), case http_transport:listen(SocketType, Address, Port, Fd, IpFamily) of {ok, ListenSocket} -> NewConfig = proplists:delete(port, Config), @@ -282,6 +286,8 @@ socket_type(Config) -> socket_type(ip_comm = SocketType, _) -> SocketType; +socket_type({ip_comm, _} = SocketType, _) -> + SocketType; socket_type({essl, _} = SocketType, _) -> SocketType; socket_type(_, Config) -> @@ -355,3 +361,19 @@ ssl_ca_certificate_file(Config) -> File -> [{cacertfile, File}] end. + +get_fd(0) -> + {ok, undefined}; +get_fd(Port) -> + FdKey = list_to_atom("httpd_" ++ integer_to_list(Port)), + case init:get_argument(FdKey) of + {ok, [[Value]]} -> + case (catch list_to_integer(Value)) of + N when is_integer(N) -> + {ok, N}; + _ -> + {error, {bad_descriptor, Value}} + end; + _ -> + {ok, undefined} + end. diff --git a/lib/inets/src/http_server/httpd_util.erl b/lib/inets/src/http_server/httpd_util.erl index fc69baf829..6dd6db6a0c 100644 --- a/lib/inets/src/http_server/httpd_util.erl +++ b/lib/inets/src/http_server/httpd_util.erl @@ -31,7 +31,7 @@ convert_netscapecookie_date/1, enable_debug/1, valid_options/3, modules_validate/1, module_validate/1, dir_validate/2, file_validate/2, mime_type_validate/1, - mime_types_validate/1, custom_date/0]). + mime_types_validate/1, custom_date/0, error_log/2]). -export([encode_hex/1, decode_hex/1]). -include_lib("kernel/include/file.hrl"). @@ -42,17 +42,7 @@ ip_address({_,_,_,_,_,_,_,_} = Address, _IpFamily) -> {ok, Address}; ip_address(Host, IpFamily) when ((IpFamily =:= inet) orelse (IpFamily =:= inet6)) -> - inet:getaddr(Host, IpFamily); -ip_address(Host, inet6fb4 = _IpFamily) -> - Inet = case gen_tcp:listen(0, [inet6]) of - {ok, Dummyport} -> - gen_tcp:close(Dummyport), - inet6; - _ -> - inet - end, - inet:getaddr(Host, Inet). - + inet:getaddr(Host, IpFamily). %% lookup @@ -430,11 +420,11 @@ flatlength([],L) -> %% split_path split_path(Path) -> - case inets_regexp:match(Path,"[\?].*\$") of + case re:run(Path,"[\?].*\$", [{capture, first}]) of %% A QUERY_STRING exists! - {match,Start,Length} -> - {http_uri:decode(string:substr(Path,1,Start-1)), - string:substr(Path,Start,Length)}; + {match,[{Start,Length}]} -> + {http_uri:decode(string:substr(Path,1,Start)), + string:substr(Path,Start+1,Length)}; %% A possible PATH_INFO exists! nomatch -> split_path(Path,[]) @@ -532,25 +522,8 @@ remove_ws(Rest) -> %% split -split(String,RegExp,Limit) -> - case inets_regexp:parse(RegExp) of - {error,Reason} -> - {error,Reason}; - {ok,_} -> - {ok,do_split(String,RegExp,Limit)} - end. - -do_split(String, _RegExp, 1) -> - [String]; - -do_split(String,RegExp,Limit) -> - case inets_regexp:first_match(String,RegExp) of - {match,Start,Length} -> - [string:substr(String,1,Start-1)| - do_split(lists:nthtail(Start+Length-1,String),RegExp,Limit-1)]; - nomatch -> - [String] - end. +split(String,RegExp,N) -> + {ok, re:split(String, RegExp, [{parts, N}, {return, list}])}. %% make_name/2, make_name/3 %% Prefix -> string() @@ -786,3 +759,17 @@ do_enable_debug([{Level,Modules}|Rest]) ok end, do_enable_debug(Rest). + +error_log(ConfigDb, Error) -> + error_log(mod_log, ConfigDb, Error), + error_log(mod_disk_log, ConfigDb, Error). + +error_log(Mod, ConfigDB, Error) -> + Modules = httpd_util:lookup(ConfigDB, modules, + [mod_get, mod_head, mod_log]), + case lists:member(Mod, Modules) of + true -> + Mod:report_error(ConfigDB, Error); + _ -> + ok + end. diff --git a/lib/inets/src/http_server/mod_actions.erl b/lib/inets/src/http_server/mod_actions.erl index d879328876..154fde294e 100644 --- a/lib/inets/src/http_server/mod_actions.erl +++ b/lib/inets/src/http_server/mod_actions.erl @@ -81,18 +81,18 @@ script(RequestURI, Method, [_ | Rest]) -> %% load load("Action "++ Action, []) -> - case inets_regexp:split(Action, " ") of - {ok,[MimeType, CGIScript]} -> - {ok,[],{action, {MimeType, CGIScript}}}; - {ok,_} -> - {error,?NICE(string:strip(Action)++" is an invalid Action")} + case re:split(Action, " ", [{return, list}]) of + [MimeType, CGIScript] -> + {ok,[],{action, {MimeType, CGIScript}}}; + _ -> + {error,?NICE(string:strip(Action)++" is an invalid Action")} end; load("Script " ++ Script,[]) -> - case inets_regexp:split(Script, " ") of - {ok,[Method, CGIScript]} -> - {ok,[],{script, {Method, CGIScript}}}; - {ok,_} -> - {error,?NICE(string:strip(Script)++" is an invalid Script")} + case re:split(Script, " ", [{return, list}]) of + [Method, CGIScript] -> + {ok,[],{script, {Method, CGIScript}}}; + _ -> + {error,?NICE(string:strip(Script)++" is an invalid Script")} end. store({action, {MimeType, CGIScript}} = Conf, _) when is_list(MimeType), diff --git a/lib/inets/src/http_server/mod_alias.erl b/lib/inets/src/http_server/mod_alias.erl index 8dd4871821..727f6e0ce3 100644 --- a/lib/inets/src/http_server/mod_alias.erl +++ b/lib/inets/src/http_server/mod_alias.erl @@ -113,32 +113,52 @@ real_name(ConfigDB, RequestURI, []) -> httpd_util:split_path(default_index(ConfigDB, RealName)), {ShortPath, Path, AfterPath}; -real_name(ConfigDB, RequestURI, [{MP,Replacement}|Rest]) +real_name(ConfigDB, RequestURI, [{MP,Replacement}| _] = Aliases) when element(1, MP) =:= re_pattern -> - case re:run(RequestURI, MP, [{capture,[]}]) of - match -> + case longest_match(Aliases, RequestURI) of + {match, {MP, Replacement}} -> NewURI = re:replace(RequestURI, MP, Replacement, [{return,list}]), {ShortPath,_} = httpd_util:split_path(NewURI), {Path,AfterPath} = httpd_util:split_path(default_index(ConfigDB, NewURI)), {ShortPath, Path, AfterPath}; nomatch -> - real_name(ConfigDB, RequestURI, Rest) + real_name(ConfigDB, RequestURI, []) end; -real_name(ConfigDB, RequestURI, [{FakeName,RealName}|Rest]) -> - case inets_regexp:match(RequestURI, "^" ++ FakeName) of - {match, _, _} -> - {ok, ActualName, _} = inets_regexp:sub(RequestURI, - "^" ++ FakeName, RealName), +real_name(ConfigDB, RequestURI, [{_,_}|_] = Aliases) -> + case longest_match(Aliases, RequestURI) of + {match, {FakeName, RealName}} -> + ActualName = re:replace(RequestURI, + "^" ++ FakeName, RealName, [{return,list}]), {ShortPath, _AfterPath} = httpd_util:split_path(ActualName), {Path, AfterPath} = - httpd_util:split_path(default_index(ConfigDB, ActualName)), + httpd_util:split_path(default_index(ConfigDB, ActualName)), {ShortPath, Path, AfterPath}; - nomatch -> - real_name(ConfigDB, RequestURI, Rest) + nomatch -> + real_name(ConfigDB, RequestURI, []) end. +longest_match(Aliases, RequestURI) -> + longest_match(Aliases, RequestURI, _LongestNo = 0, _LongestAlias = undefined). + +longest_match([{FakeName, RealName} | Rest], RequestURI, LongestNo, LongestAlias) -> + case re:run(RequestURI, "^" ++ FakeName, [{capture, first}]) of + {match, [{_, Length}]} -> + if + Length > LongestNo -> + longest_match(Rest, RequestURI, Length, {FakeName, RealName}); + true -> + longest_match(Rest, RequestURI, LongestNo, LongestAlias) + end; + nomatch -> + longest_match(Rest, RequestURI, LongestNo, LongestAlias) + end; +longest_match([], _RequestURI, 0, _LongestAlias) -> + nomatch; +longest_match([], _RequestURI, _LongestNo, LongestAlias) -> + {match, LongestAlias}. + %% real_script_name real_script_name(_ConfigDB, _RequestURI, []) -> @@ -146,7 +166,7 @@ real_script_name(_ConfigDB, _RequestURI, []) -> real_script_name(ConfigDB, RequestURI, [{MP,Replacement} | Rest]) when element(1, MP) =:= re_pattern -> - case re:run(RequestURI, MP, [{capture,[]}]) of + case re:run(RequestURI, MP, [{capture, none}]) of match -> ActualName = re:replace(RequestURI, MP, Replacement, [{return,list}]), @@ -156,10 +176,10 @@ real_script_name(ConfigDB, RequestURI, [{MP,Replacement} | Rest]) end; real_script_name(ConfigDB, RequestURI, [{FakeName,RealName} | Rest]) -> - case inets_regexp:match(RequestURI, "^" ++ FakeName) of - {match,_,_} -> - {ok, ActualName, _} = - inets_regexp:sub(RequestURI, "^" ++ FakeName, RealName), + case re:run(RequestURI, "^" ++ FakeName, [{capture, none}]) of + match -> + ActualName = + re:replace(RequestURI, "^" ++ FakeName, RealName, [{return,list}]), httpd_util:split_script_path(default_index(ConfigDB, ActualName)); nomatch -> real_script_name(ConfigDB, RequestURI, Rest) @@ -206,26 +226,26 @@ path(Data, ConfigDB, RequestURI) -> %% load load("DirectoryIndex " ++ DirectoryIndex, []) -> - {ok, DirectoryIndexes} = inets_regexp:split(DirectoryIndex," "), + DirectoryIndexes = re:split(DirectoryIndex," ", [{return, list}]), {ok,[], {directory_index, DirectoryIndexes}}; load("Alias " ++ Alias, []) -> - case inets_regexp:split(Alias," ") of - {ok, [FakeName, RealName]} -> + case re:split(Alias," ", [{return, list}]) of + [FakeName, RealName] -> {ok,[],{alias,{FakeName,RealName}}}; - {ok, _} -> + _ -> {error,?NICE(string:strip(Alias)++" is an invalid Alias")} end; load("ReWrite " ++ Rule, Acc) -> load_re_write(Rule, Acc, "ReWrite", re_write); load("ScriptAlias " ++ ScriptAlias, []) -> - case inets_regexp:split(ScriptAlias, " ") of - {ok, [FakeName, RealName]} -> + case re:split(ScriptAlias, " ", [{return, list}]) of + [FakeName, RealName] -> %% Make sure the path always has a trailing slash.. RealName1 = filename:join(filename:split(RealName)), {ok, [], {script_alias, {FakeName, RealName1++"/"}}}; - {ok, _} -> + _ -> {error, ?NICE(string:strip(ScriptAlias)++ - " is an invalid ScriptAlias")} + " is an invalid ScriptAlias")} end; load("ScriptReWrite " ++ Rule, Acc) -> load_re_write(Rule, Acc, "ScriptReWrite", script_re_write). diff --git a/lib/inets/src/http_server/mod_auth.erl b/lib/inets/src/http_server/mod_auth.erl index 6195e1c69f..b03629cabe 100644 --- a/lib/inets/src/http_server/mod_auth.erl +++ b/lib/inets/src/http_server/mod_auth.erl @@ -168,38 +168,38 @@ load("AuthDBType " ++ Type, end; load("require " ++ Require,[{directory, {Directory, DirData}}|Rest]) -> - case inets_regexp:split(Require," ") of - {ok,["user"|Users]} -> + case re:split(Require," ", [{return, list}]) of + ["user" | Users] -> {ok,[{directory, {Directory, - [{require_user,Users}|DirData]}} | Rest]}; - {ok,["group"|Groups]} -> + [{require_user,Users}|DirData]}} | Rest]}; + ["group"|Groups] -> {ok,[{directory, {Directory, - [{require_group,Groups}|DirData]}} | Rest]}; - {ok,_} -> + [{require_group,Groups}|DirData]}} | Rest]}; + _ -> {error,?NICE(string:strip(Require) ++" is an invalid require")} end; load("allow " ++ Allow,[{directory, {Directory, DirData}}|Rest]) -> - case inets_regexp:split(Allow," ") of - {ok,["from","all"]} -> + case re:split(Allow," ", [{return, list}]) of + ["from","all"] -> {ok,[{directory, {Directory, [{allow_from,all}|DirData]}} | Rest]}; - {ok,["from"|Hosts]} -> + ["from"|Hosts] -> {ok,[{directory, {Directory, [{allow_from,Hosts}|DirData]}} | Rest]}; - {ok,_} -> + _ -> {error,?NICE(string:strip(Allow) ++" is an invalid allow")} end; load("deny " ++ Deny,[{directory, {Directory, DirData}}|Rest]) -> - case inets_regexp:split(Deny," ") of - {ok, ["from", "all"]} -> + case re:split(Deny," ", [{return, list}]) of + ["from", "all"] -> {ok,[{{directory, Directory, [{deny_from, all}|DirData]}} | Rest]}; - {ok, ["from"|Hosts]} -> + ["from"|Hosts] -> {ok,[{{directory, Directory, [{deny_from, Hosts}|DirData]}} | Rest]}; - {ok, _} -> + _ -> {error,?NICE(string:strip(Deny) ++" is an invalid deny")} end; @@ -561,12 +561,12 @@ secret_path(_Path, [], to_be_found) -> secret_path(_Path, [], Directory) -> {yes, Directory}; secret_path(Path, [[NewDirectory] | Rest], Directory) -> - case inets_regexp:match(Path, NewDirectory) of - {match, _, _} when Directory =:= to_be_found -> + case re:run(Path, NewDirectory, [{capture, first}]) of + {match, _} when Directory =:= to_be_found -> secret_path(Path, Rest, NewDirectory); - {match, _, Length} when Length > length(Directory)-> + {match, [{_, Length}]} when Length > length(Directory)-> secret_path(Path, Rest,NewDirectory); - {match, _, _Length} -> + {match, _} -> secret_path(Path, Rest, Directory); nomatch -> secret_path(Path, Rest, Directory) @@ -588,8 +588,8 @@ validate_addr(_RemoteAddr, none) -> % When called from 'deny' validate_addr(_RemoteAddr, []) -> false; validate_addr(RemoteAddr, [HostRegExp | Rest]) -> - case inets_regexp:match(RemoteAddr, HostRegExp) of - {match,_,_} -> + case re:run(RemoteAddr, HostRegExp, [{capture, none}]) of + match -> true; nomatch -> validate_addr(RemoteAddr,Rest) diff --git a/lib/inets/src/http_server/mod_auth_plain.erl b/lib/inets/src/http_server/mod_auth_plain.erl index e85d3b8776..1a3120e03c 100644 --- a/lib/inets/src/http_server/mod_auth_plain.erl +++ b/lib/inets/src/http_server/mod_auth_plain.erl @@ -244,11 +244,11 @@ parse_group(Stream, GroupList, "") -> parse_group(Stream, GroupList, [$#|_]) -> parse_group(Stream, GroupList); parse_group(Stream, GroupList, Line) -> - case inets_regexp:split(Line, ":") of - {ok, [Group,Users]} -> - {ok, UserList} = inets_regexp:split(Users," "), + case re:split(Line, ":", [{return, list}]) of + [Group,Users] -> + UserList = re:split(Users," ", [{return, list}]), parse_group(Stream, [{Group,UserList}|GroupList]); - {ok, _} -> + _ -> {error, ?NICE(Line)} end. @@ -278,10 +278,10 @@ parse_passwd(Stream, PasswdList, "") -> parse_passwd(Stream, PasswdList, [$#|_]) -> parse_passwd(Stream, PasswdList); parse_passwd(Stream, PasswdList, Line) -> - case inets_regexp:split(Line,":") of - {ok, [User,Password]} -> + case re:split(Line,":", [{return, list}]) of + [User,Password] -> parse_passwd(Stream, [{User,Password, []}|PasswdList]); - {ok,_} -> + _ -> {error, ?NICE(Line)} end. diff --git a/lib/inets/src/http_server/mod_auth_server.erl b/lib/inets/src/http_server/mod_auth_server.erl index 3685c2e617..7d1e1a3431 100644 --- a/lib/inets/src/http_server/mod_auth_server.erl +++ b/lib/inets/src/http_server/mod_auth_server.erl @@ -316,7 +316,7 @@ lookup(Db, Key) -> make_name(Addr, Port, Profile) -> - httpd_util:make_name(?MODULE, Addr, Port, Profile). + httpd_util:make_name(?MODULE_STRING, Addr, Port, Profile). call(Name, Req) -> diff --git a/lib/inets/src/http_server/mod_browser.erl b/lib/inets/src/http_server/mod_browser.erl index ca643ab728..e3c41793ae 100644 --- a/lib/inets/src/http_server/mod_browser.erl +++ b/lib/inets/src/http_server/mod_browser.erl @@ -98,9 +98,9 @@ getBrowser1(Info) -> getBrowser(AgentString) -> LAgentString = http_util:to_lower(AgentString), - case inets_regexp:first_match(LAgentString,"^[^ ]*") of - {match,Start,Length} -> - Browser = lists:sublist(LAgentString,Start,Length), + case re:run(LAgentString,"^[^ ]*", [{capture, first}]) of + {match,[{Start,Length}]} -> + Browser = lists:sublist(LAgentString,Start+1,Length), case browserType(Browser) of {mozilla,Vsn} -> {getMozilla(LAgentString, @@ -164,8 +164,8 @@ operativeSystem(OpString,[{RetVal,RegExps}|Rest]) -> controlOperativeSystem(_OpString,[]) -> false; controlOperativeSystem(OpString,[Regexp|Regexps]) -> - case inets_regexp:match(OpString,Regexp) of - {match,_,_} -> + case re:run(OpString,Regexp, [{capture, none}]) of + match -> true; nomatch -> controlOperativeSystem(OpString,Regexps) @@ -182,18 +182,19 @@ controlOperativeSystem(OpString,[Regexp|Regexps]) -> getMozilla(_AgentString,[],Default) -> Default; getMozilla(AgentString,[{Agent,AgentRegExp}|Rest],Default) -> - case inets_regexp:match(AgentString,AgentRegExp) of - {match,_,_} -> + case re:run(AgentString,AgentRegExp, [{capture, none}]) of + match -> {Agent,getMozVersion(AgentString,AgentRegExp)}; nomatch -> getMozilla(AgentString,Rest,Default) end. getMozVersion(AgentString, AgentRegExp) -> - case inets_regexp:match(AgentString,AgentRegExp++"[0-9\.\ \/]*") of - {match,Start,Length} when length(AgentRegExp) < Length -> + case re:run(AgentString,AgentRegExp++"[0-9\.\ \/]*", + [{capture, first}]) of + {match, [{Start,Length}]} when length(AgentRegExp) < Length -> %% Ok we got the number split it out - RealStart = Start+length(AgentRegExp), + RealStart = Start+1+length(AgentRegExp), RealLength = Length-length(AgentRegExp), VsnString = string:substr(AgentString,RealStart,RealLength), %% case string:strip(VsnString,both,$\ ) of diff --git a/lib/inets/src/http_server/mod_cgi.erl b/lib/inets/src/http_server/mod_cgi.erl index 25d9f05028..ec8b9be32e 100644 --- a/lib/inets/src/http_server/mod_cgi.erl +++ b/lib/inets/src/http_server/mod_cgi.erl @@ -337,6 +337,8 @@ script_elements(#mod{method = "GET"}, {PathInfo, QueryString}) -> [{query_string, QueryString}, {path_info, PathInfo}]; script_elements(#mod{method = "POST", entity_body = Body}, _) -> [{entity_body, Body}]; +script_elements(#mod{method = "PATCH", entity_body = Body}, _) -> + [{entity_body, Body}]; script_elements(#mod{method = "PUT", entity_body = Body}, _) -> [{entity_body, Body}]; script_elements(_, _) -> diff --git a/lib/inets/src/http_server/mod_dir.erl b/lib/inets/src/http_server/mod_dir.erl index 9d848ac013..2d8f27af3c 100644 --- a/lib/inets/src/http_server/mod_dir.erl +++ b/lib/inets/src/http_server/mod_dir.erl @@ -125,12 +125,13 @@ header(Path,RequestURI) -> RequestURI ++ "</H1>\n<PRE><IMG SRC=\"" ++ icon(blank) ++ "\" ALT=" "> Name Last modified " "Size Description <HR>\n", - case inets_regexp:sub(RequestURI,"[^/]*\$","") of - {ok,"/",_} -> + case re:replace(RequestURI,"[^/]*\$","", [{return,list}]) of + "/" -> Header; - {ok,ParentRequestURI,_} -> - {ok,ParentPath,_} = - inets_regexp:sub(string:strip(Path,right,$/),"[^/]*\$",""), + ParentRequestURI -> + ParentPath = + re:replace(string:strip(Path,right,$/),"[^/]*\$","", + [{return,list}]), Header++format(ParentPath,ParentRequestURI) end. diff --git a/lib/inets/src/http_server/mod_disk_log.erl b/lib/inets/src/http_server/mod_disk_log.erl index a0ff929a34..5e395a2118 100644 --- a/lib/inets/src/http_server/mod_disk_log.erl +++ b/lib/inets/src/http_server/mod_disk_log.erl @@ -138,8 +138,8 @@ do(Info) -> %% Description: See httpd(3) ESWAPI CALLBACK FUNCTIONS %%------------------------------------------------------------------------- load("TransferDiskLogSize " ++ TransferDiskLogSize, []) -> - case inets_regexp:split(TransferDiskLogSize," ") of - {ok,[MaxBytes,MaxFiles]} -> + try re:split(TransferDiskLogSize, " ", [{return, list}]) of + [MaxBytes, MaxFiles] -> case make_integer(MaxBytes) of {ok,MaxBytesInteger} -> case make_integer(MaxFiles) of @@ -151,17 +151,20 @@ load("TransferDiskLogSize " ++ TransferDiskLogSize, []) -> ?NICE(string:strip(TransferDiskLogSize)++ " is an invalid TransferDiskLogSize")} end; - {error,_} -> + _ -> {error,?NICE(string:strip(TransferDiskLogSize)++ - " is an invalid TransferDiskLogSize")} + " is an invalid TransferDiskLogSize")} end + catch _:_ -> + {error,?NICE(string:strip(TransferDiskLogSize) ++ + " is an invalid TransferDiskLogSize")} end; load("TransferDiskLog " ++ TransferDiskLog,[]) -> {ok,[],{transfer_disk_log,string:strip(TransferDiskLog)}}; load("ErrorDiskLogSize " ++ ErrorDiskLogSize, []) -> - case inets_regexp:split(ErrorDiskLogSize," ") of - {ok,[MaxBytes,MaxFiles]} -> + try re:split(ErrorDiskLogSize," ", [{return, list}]) of + [MaxBytes,MaxFiles] -> case make_integer(MaxBytes) of {ok,MaxBytesInteger} -> case make_integer(MaxFiles) of @@ -176,13 +179,16 @@ load("ErrorDiskLogSize " ++ ErrorDiskLogSize, []) -> {error,?NICE(string:strip(ErrorDiskLogSize)++ " is an invalid ErrorDiskLogSize")} end + catch _:_ -> + {error,?NICE(string:strip(ErrorDiskLogSize) ++ + " is an invalid TransferDiskLogSize")} end; load("ErrorDiskLog " ++ ErrorDiskLog, []) -> {ok, [], {error_disk_log, string:strip(ErrorDiskLog)}}; load("SecurityDiskLogSize " ++ SecurityDiskLogSize, []) -> - case inets_regexp:split(SecurityDiskLogSize, " ") of - {ok, [MaxBytes, MaxFiles]} -> + try re:split(SecurityDiskLogSize, " ", [{return, list}]) of + [MaxBytes, MaxFiles] -> case make_integer(MaxBytes) of {ok, MaxBytesInteger} -> case make_integer(MaxFiles) of @@ -198,6 +204,9 @@ load("SecurityDiskLogSize " ++ SecurityDiskLogSize, []) -> {error, ?NICE(string:strip(SecurityDiskLogSize) ++ " is an invalid SecurityDiskLogSize")} end + catch _:_ -> + {error,?NICE(string:strip(SecurityDiskLogSize) ++ + " is an invalid SecurityDiskLogSize")} end; load("SecurityDiskLog " ++ SecurityDiskLog, []) -> {ok, [], {security_disk_log, string:strip(SecurityDiskLog)}}; diff --git a/lib/inets/src/http_server/mod_esi.erl b/lib/inets/src/http_server/mod_esi.erl index b9a0797977..2978ac9095 100644 --- a/lib/inets/src/http_server/mod_esi.erl +++ b/lib/inets/src/http_server/mod_esi.erl @@ -96,26 +96,27 @@ do(ModData) -> %% Description: See httpd(3) ESWAPI CALLBACK FUNCTIONS %%------------------------------------------------------------------------- load("ErlScriptAlias " ++ ErlScriptAlias, []) -> - case inets_regexp:split(ErlScriptAlias," ") of - {ok, [ErlName | StrModules]} -> + try re:split(ErlScriptAlias," ", [{return, list}]) of + [ErlName | StrModules] -> Modules = lists:map(fun(Str) -> list_to_atom(string:strip(Str)) end, StrModules), - {ok, [], {erl_script_alias, {ErlName, Modules}}}; - {ok, _} -> + {ok, [], {erl_script_alias, {ErlName, Modules}}} + catch _:_ -> {error, ?NICE(string:strip(ErlScriptAlias) ++ - " is an invalid ErlScriptAlias")} + " is an invalid ErlScriptAlias")} end; load("EvalScriptAlias " ++ EvalScriptAlias, []) -> - case inets_regexp:split(EvalScriptAlias, " ") of - {ok, [EvalName | StrModules]} -> + try re:split(EvalScriptAlias, " ", [{return, list}]) of + [EvalName | StrModules] -> Modules = lists:map(fun(Str) -> list_to_atom(string:strip(Str)) end, StrModules), - {ok, [], {eval_script_alias, {EvalName, Modules}}}; - {ok, _} -> + {ok, [], {eval_script_alias, {EvalName, Modules}}} + catch + _:_ -> {error, ?NICE(string:strip(EvalScriptAlias) ++ - " is an invalid EvalScriptAlias")} + " is an invalid EvalScriptAlias")} end; load("ErlScriptTimeout " ++ Timeout, [])-> case catch list_to_integer(string:strip(Timeout)) of @@ -224,8 +225,8 @@ match_esi_script(_, [], _) -> no_match; match_esi_script(RequestURI, [{Alias,Modules} | Rest], AliasType) -> AliasMatchStr = alias_match_str(Alias, AliasType), - case inets_regexp:first_match(RequestURI, AliasMatchStr) of - {match, 1, Length} -> + case re:run(RequestURI, AliasMatchStr, [{capture, first}]) of + {match, [{0, Length}]} -> {string:substr(RequestURI, Length + 1), Modules}; nomatch -> match_esi_script(RequestURI, Rest, AliasType) @@ -281,6 +282,15 @@ erl(#mod{request_uri = ReqUri, ?NICE("Erl mechanism doesn't support method DELETE")}}| Data]}; +erl(#mod{request_uri = ReqUri, + method = "PATCH", + http_version = Version, + data = Data}, _ESIBody, _Modules) -> + ?hdrt("erl", [{method, patch}]), + {proceed, [{status,{501,{"PATCH", ReqUri, Version}, + ?NICE("Erl mechanism doesn't support method PATCH")}}| + Data]}; + erl(#mod{method = "POST", entity_body = Body} = ModData, ESIBody, Modules) -> ?hdrt("erl", [{method, post}]), @@ -376,7 +386,6 @@ erl_scheme_webpage_chunk(Mod, Func, Env, Input, ModData) -> end), Response = deliver_webpage_chunk(ModData, Pid), - process_flag(trap_exit,false), Response. @@ -418,7 +427,6 @@ deliver_webpage_chunk(#mod{config_db = Db} = ModData, Pid, Timeout) -> ?hdrv("deliver_webpage_chunk - timeout", []), send_headers(ModData, 504, [{"connection", "close"}]), httpd_socket:close(ModData#mod.socket_type, ModData#mod.socket), - process_flag(trap_exit,false), {proceed,[{response, {already_sent, 200, 0}} | ModData#mod.data]} end. @@ -446,7 +454,6 @@ send_headers(ModData, StatusCode, HTTPHeaders) -> ExtraHeaders ++ HTTPHeaders). handle_body(_, #mod{method = "HEAD"} = ModData, _, _, Size, _) -> - process_flag(trap_exit,false), {proceed, [{response, {already_sent, 200, Size}} | ModData#mod.data]}; handle_body(Pid, ModData, Body, Timeout, Size, IsDisableChunkedSend) -> @@ -454,34 +461,54 @@ handle_body(Pid, ModData, Body, Timeout, Size, IsDisableChunkedSend) -> httpd_response:send_chunk(ModData, Body, IsDisableChunkedSend), receive {esi_data, Data} when is_binary(Data) -> - ?hdrt("handle_body - received binary data (esi)", []), handle_body(Pid, ModData, Data, Timeout, Size + byte_size(Data), IsDisableChunkedSend); {esi_data, Data} -> - ?hdrt("handle_body - received data (esi)", []), handle_body(Pid, ModData, Data, Timeout, Size + length(Data), IsDisableChunkedSend); {ok, Data} -> - ?hdrt("handle_body - received data (ok)", []), handle_body(Pid, ModData, Data, Timeout, Size + length(Data), IsDisableChunkedSend); {'EXIT', Pid, normal} when is_pid(Pid) -> - ?hdrt("handle_body - exit:normal", []), httpd_response:send_final_chunk(ModData, IsDisableChunkedSend), {proceed, [{response, {already_sent, 200, Size}} | ModData#mod.data]}; {'EXIT', Pid, Reason} when is_pid(Pid) -> - ?hdrv("handle_body - exit", [{reason, Reason}]), - httpd_response:send_final_chunk(ModData, IsDisableChunkedSend), - exit({mod_esi_linked_process_died, Pid, Reason}) - + Error = lists:flatten(io_lib:format("mod_esi process failed with reason ~p", [Reason])), + httpd_util:error_log(ModData#mod.config_db, Error), + httpd_response:send_final_chunk(ModData, + [{"Warning", "199 inets server - body maybe incomplete, " + "internal server error"}], + IsDisableChunkedSend), + done after Timeout -> - ?hdrv("handle_body - timeout", []), - process_flag(trap_exit,false), - httpd_response:send_final_chunk(ModData, IsDisableChunkedSend), - exit({mod_esi_linked_process_timeout, Pid}) + kill_esi_delivery_process(Pid), + httpd_response:send_final_chunk(ModData, [{"Warning", "199 inets server - " + "body maybe incomplete, timed out"}], + IsDisableChunkedSend), + done end. +kill_esi_delivery_process(Pid) -> + exit(Pid, kill), + receive + {'EXIT', Pid, killed} -> + %% Clean message queue + receive + {esi_data, _} -> + ok + after 0 -> + ok + end, + receive + {ok, _} -> + ok + after 0 -> + ok + end + end. + + erl_script_timeout(Db) -> httpd_util:lookup(Db, erl_script_timeout, ?DEFAULT_ERL_TIMEOUT). @@ -567,9 +594,9 @@ generate_webpage(ESIBody) -> is_authorized(_ESIBody, [all]) -> true; is_authorized(ESIBody, Modules) -> - case inets_regexp:match(ESIBody, "^[^\:(%3A)]*") of - {match, Start, Length} -> - lists:member(list_to_atom(string:substr(ESIBody, Start, Length)), + case re:run(ESIBody, "^[^\:(%3A)]*", [{capture, first}]) of + {match, [{Start, Length}]} -> + lists:member(list_to_atom(string:substr(ESIBody, Start+1, Length)), Modules); nomatch -> false diff --git a/lib/inets/src/http_server/mod_htaccess.erl b/lib/inets/src/http_server/mod_htaccess.erl index c6ae20ced7..f229c96f2d 100644 --- a/lib/inets/src/http_server/mod_htaccess.erl +++ b/lib/inets/src/http_server/mod_htaccess.erl @@ -327,9 +327,9 @@ memberNetwork(Networks,UserNetwork,IfTrue,IfFalse)-> %ipadresses or subnet addresses. memberNetwork(Networks,UserNetwork)-> case lists:filter(fun(Net)-> - case inets_regexp:match(UserNetwork, - formatRegexp(Net)) of - {match,1,_}-> + case re:run(UserNetwork, + formatRegexp(Net), [{capture, first}]) of + {match,[{0,_}]}-> true; _NotSubNet -> false @@ -638,13 +638,8 @@ getHtAccessFileNames(Info)-> %HtAccessFileNames=["accessfileName1",..."AccessFileName2"] %---------------------------------------------------------------------- getData(Path,Info,HtAccessFileNames)-> - case inets_regexp:split(Path,"/") of - {error,Error}-> - {error,Error}; - {ok,SplittedPath}-> - getData2(HtAccessFileNames,SplittedPath,Info) - end. - + SplittedPath = re:split(Path, "/", [{return, list}]), + getData2(HtAccessFileNames,SplittedPath,Info). %---------------------------------------------------------------------- %Add to together the data in the Splittedpath up to the path @@ -942,20 +937,16 @@ getAuthorizationType(AuthType)-> %Returns a list of the specified methods to limit or the atom all %---------------------------------------------------------------------- getLimits(Limits)-> - case inets_regexp:split(Limits,">")of - {ok,[_NoEndOnLimit]}-> + case re:split(Limits,">", [{return, list}])of + [_NoEndOnLimit]-> error; - {ok, [Methods | _Crap]}-> - case inets_regexp:split(Methods," ") of - {ok,[]}-> + [Methods | _Crap]-> + case re:split(Methods," ", [{return, list}]) of + [[]]-> all; - {ok,SplittedMethods}-> - SplittedMethods; - {error, _Error}-> - error - end; - {error,_Error}-> - error + SplittedMethods -> + SplittedMethods + end end. diff --git a/lib/inets/src/http_server/mod_security.erl b/lib/inets/src/http_server/mod_security.erl index 20f87619c1..1f936d598a 100644 --- a/lib/inets/src/http_server/mod_security.erl +++ b/lib/inets/src/http_server/mod_security.erl @@ -273,12 +273,12 @@ secret_path(_Path, [], to_be_found) -> secret_path(_Path, [], Dir) -> {yes, Dir}; secret_path(Path, [[NewDir]|Rest], Dir) -> - case inets_regexp:match(Path, NewDir) of - {match, _, _} when Dir =:= to_be_found -> + case re:run(Path, NewDir, [{capture, first}]) of + {match, _} when Dir =:= to_be_found -> secret_path(Path, Rest, NewDir); - {match, _, Length} when Length > length(Dir) -> + {match, [{_, Length}]} when Length > length(Dir) -> secret_path(Path, Rest, NewDir); - {match, _, _} -> + {match, _} -> secret_path(Path, Rest, Dir); nomatch -> secret_path(Path, Rest, Dir) diff --git a/lib/inets/src/http_server/mod_security_server.erl b/lib/inets/src/http_server/mod_security_server.erl index 81561493a0..f9281b0fdc 100644 --- a/lib/inets/src/http_server/mod_security_server.erl +++ b/lib/inets/src/http_server/mod_security_server.erl @@ -523,10 +523,10 @@ unblock_user(Info, User, Dir, Addr, Port, Profile, ETS, DETS, CBModule) -> ets:match_delete(ETS, {blocked_user, {User, Addr, Port, Profile, Dir, '_'}}). make_name(Addr,Port, Profile) -> - httpd_util:make_name(?MODULE,Addr,Port, Profile). + httpd_util:make_name(?MODULE_STRING, Addr, Port, Profile). make_name(Addr,Port, Profile, Num) -> - httpd_util:make_name(?MODULE,Addr,Port, + httpd_util:make_name(?MODULE_STRING, Addr,Port, atom_to_list(Profile) ++ "__" ++ integer_to_list(Num)). auth_fail_event(Mod,Addr,Port,Dir,User,Passwd) -> diff --git a/lib/inets/src/inets_app/Makefile b/lib/inets/src/inets_app/Makefile index 82cda6aaf0..7f51676dc5 100644 --- a/lib/inets/src/inets_app/Makefile +++ b/lib/inets/src/inets_app/Makefile @@ -47,10 +47,10 @@ MODULES = \ inets_service \ inets_app \ inets_sup \ - inets_regexp \ inets_trace \ inets_lib \ - inets_time_compat + inets_time_compat \ + inets_regexp INTERNAL_HRL_FILES = inets_internal.hrl EXTERNAL_HRL_FILES = ../../include/httpd.hrl \ diff --git a/lib/inets/src/inets_app/inets.app.src b/lib/inets/src/inets_app/inets.app.src index 2b9b8f5f32..c09139872f 100644 --- a/lib/inets/src/inets_app/inets.app.src +++ b/lib/inets/src/inets_app/inets.app.src @@ -26,10 +26,10 @@ inets_sup, inets_app, inets_service, - inets_regexp, inets_trace, inets_lib, inets_time_compat, + inets_regexp, %% FTP ftp, @@ -65,6 +65,7 @@ httpd_connection_sup, httpd_conf, httpd_custom, + httpd_custom_api, httpd_esi, httpd_example, httpd_file, diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src index d3da76d789..a9fbb1c3f7 100644 --- a/lib/inets/src/inets_app/inets.appup.src +++ b/lib/inets/src/inets_app/inets.appup.src @@ -18,9 +18,11 @@ %% %CopyrightEnd% {"%VSN%", [ + {<<"6\\..*">>,[{restart_application, inets}]}, {<<"5\\..*">>,[{restart_application, inets}]} ], [ + {<<"6\\..*">>,[{restart_application, inets}]}, {<<"5\\..*">>,[{restart_application, inets}]} ] }. diff --git a/lib/inets/src/tftp/tftp_engine.erl b/lib/inets/src/tftp/tftp_engine.erl index fa44cd61ce..493a29a68f 100644 --- a/lib/inets/src/tftp/tftp_engine.erl +++ b/lib/inets/src/tftp/tftp_engine.erl @@ -128,8 +128,8 @@ daemon_start(Options) when is_list(Options) -> daemon_init(Config) when is_record(Config, config), is_pid(Config#config.parent_pid) -> process_flag(trap_exit, true), - UdpOptions = prepare_daemon_udp(Config), - case catch gen_udp:open(Config#config.udp_port, UdpOptions) of + {Port, UdpOptions} = prepare_daemon_udp(Config), + case catch gen_udp:open(Port, UdpOptions) of {ok, Socket} -> {ok, ActualPort} = inet:port(Socket), proc_lib:init_ack({ok, self()}), @@ -157,7 +157,7 @@ prepare_daemon_udp(#config{udp_port = Port, udp_options = UdpOptions} = Config) case lists:keymember(fd, 1, UdpOptions) of true -> %% Use explicit fd - UdpOptions; + {Port, UdpOptions}; false -> %% Use fd from setuid_socket_wrap, such as -tftpd_69 InitArg = list_to_atom("tftpd_" ++ integer_to_list(Port)), @@ -165,7 +165,7 @@ prepare_daemon_udp(#config{udp_port = Port, udp_options = UdpOptions} = Config) {ok, [[FdStr]] = Badarg} when is_list(FdStr) -> case catch list_to_integer(FdStr) of Fd when is_integer(Fd) -> - [{fd, Fd} | UdpOptions]; + {0, [{fd, Fd} | lists:keydelete(ip, 1, UdpOptions)]}; {'EXIT', _} -> Text = lists:flatten(io_lib:format("Illegal prebound fd ~p: ~p", [InitArg, Badarg])), print_debug_info(Config, daemon, open, ?ERROR(open, undef, Text, "")), @@ -176,7 +176,7 @@ prepare_daemon_udp(#config{udp_port = Port, udp_options = UdpOptions} = Config) print_debug_info(Config, daemon, open, ?ERROR(open, undef, Text, "")), exit({badarg, {prebound_fd, InitArg, Badarg}}); error -> - UdpOptions + {Port, UdpOptions} end end. @@ -656,22 +656,11 @@ common_read(Config, Callback, Req, _LocalAccess, ExpectedBlockNo, ActualBlockNo, do_common_read(Config, Callback, Req, LocalAccess, BlockNo, Data, Prepared) when is_binary(Data), is_record(Prepared, prepared) -> - NextBlockNo = BlockNo + 1, - case NextBlockNo =< 65535 of - true -> - Reply = #tftp_msg_data{block_no = NextBlockNo, data = Data}, - {Config2, Callback2, TransferRes} = - transfer(Config, Callback, Req, Reply, LocalAccess, NextBlockNo, Prepared), - ?MODULE:common_loop(Config2, Callback2, Req, TransferRes, LocalAccess, NextBlockNo); - false -> - Code = badblk, - Text = "Too big transfer ID = " ++ - integer_to_list(NextBlockNo) ++ " > 65535", - {undefined, Error} = - callback({abort, {Code, Text}}, Config, Callback, Req), - send_msg(Config, Req, Error), - terminate(Config, Req, ?ERROR(read, Code, Text, Req#tftp_msg_req.filename)) - end. + NextBlockNo = (BlockNo + 1) rem 65536, + Reply = #tftp_msg_data{block_no = NextBlockNo, data = Data}, + {Config2, Callback2, TransferRes} = + transfer(Config, Callback, Req, Reply, LocalAccess, NextBlockNo, Prepared), + ?MODULE:common_loop(Config2, Callback2, Req, TransferRes, LocalAccess, NextBlockNo). -spec common_write(#config{}, #callback{}, _, 'write', integer(), integer(), _, #prepared{}) -> no_return(). @@ -715,21 +704,10 @@ common_write(Config, Callback, Req, _, ExpectedBlockNo, ActualBlockNo, Data, Pre common_ack(Config, Callback, Req, LocalAccess, BlockNo, Prepared) when is_record(Prepared, prepared) -> Reply = #tftp_msg_ack{block_no = BlockNo}, - NextBlockNo = BlockNo + 1, + NextBlockNo = (BlockNo + 1) rem 65536, {Config2, Callback2, TransferRes} = transfer(Config, Callback, Req, Reply, LocalAccess, NextBlockNo, Prepared), - case NextBlockNo =< 65535 of - true -> - ?MODULE:common_loop(Config2, Callback2, Req, TransferRes, LocalAccess, NextBlockNo); - false -> - Code = badblk, - Text = "Too big transfer ID = " ++ - integer_to_list(NextBlockNo) ++ " > 65535", - {undefined, Error} = - callback({abort, {Code, Text}}, Config, Callback2, Req), - send_msg(Config, Req, Error), - terminate(Config, Req, ?ERROR(read, Code, Text, Req#tftp_msg_req.filename)) - end. + ?MODULE:common_loop(Config2, Callback2, Req, TransferRes, LocalAccess, NextBlockNo). pre_terminate(Config, Req, Result) -> if @@ -1153,8 +1131,8 @@ match_callback(Filename, Callbacks) -> end. do_match_callback(Filename, [C | Tail]) when is_record(C, callback) -> - case catch inets_regexp:match(Filename, C#callback.internal) of - {match, _, _} -> + case catch re:run(Filename, C#callback.internal, [{capture, none}]) of + match -> {ok, C}; nomatch -> do_match_callback(Filename, Tail); diff --git a/lib/inets/src/tftp/tftp_lib.erl b/lib/inets/src/tftp/tftp_lib.erl index 71327f8023..01dea97d07 100644 --- a/lib/inets/src/tftp/tftp_lib.erl +++ b/lib/inets/src/tftp/tftp_lib.erl @@ -184,7 +184,7 @@ do_parse_config([{Key, Val} | Tail], Config) when is_record(Config, config) -> callback -> case Val of {RegExp, Mod, State} when is_list(RegExp), is_atom(Mod) -> - case inets_regexp:parse(RegExp) of + case re:compile(RegExp) of {ok, Internal} -> Callback = #callback{regexp = RegExp, internal = Internal, @@ -253,7 +253,7 @@ do_parse_config(Options, Config) when is_record(Config, config) -> add_default_callbacks(Callbacks) -> RegExp = "", - {ok, Internal} = inets_regexp:parse(RegExp), + {ok, Internal} = re:compile(RegExp), File = #callback{regexp = RegExp, internal = Internal, module = tftp_file, diff --git a/lib/inets/test/Makefile b/lib/inets/test/Makefile index cae77a05f3..607ec7c182 100644 --- a/lib/inets/test/Makefile +++ b/lib/inets/test/Makefile @@ -174,7 +174,8 @@ MODULES = \ inets_appup_test \ tftp_test_lib \ tftp_SUITE \ - uri_SUITE + uri_SUITE \ + inets_socketwrap_SUITE EBIN = . @@ -203,7 +204,7 @@ INETS_FILES = inets.config $(INETS_SPECS) # inets_ftp_suite \ # inets_tftp_suite -INETS_DATADIRS = inets_SUITE_data inets_sup_SUITE_data +INETS_DATADIRS = inets_SUITE_data inets_socketwrap_SUITE_data HTTPD_DATADIRS = httpd_test_data httpd_SUITE_data httpd_basic_SUITE_data old_httpd_SUITE_data HTTPC_DATADIRS = httpc_SUITE_data httpc_proxy_SUITE_data FTP_DATADIRS = ftp_SUITE_data @@ -250,7 +251,7 @@ ERL_COMPILE_FLAGS += \ # 1) INETS_PRIV_DIR must be created # ---------------------------------------------------- -tests debug opt: $(BUILDTARGET) +tests debug opt: $(BUILDTARGET) targets: $(TARGET_FILES) diff --git a/lib/inets/test/http_format_SUITE.erl b/lib/inets/test/http_format_SUITE.erl index a97b51601f..e977bd1b9b 100644 --- a/lib/inets/test/http_format_SUITE.erl +++ b/lib/inets/test/http_format_SUITE.erl @@ -20,26 +20,12 @@ %% -module(http_format_SUITE). --author('[email protected]'). -include_lib("common_test/include/ct.hrl"). --include("test_server_line.hrl"). -include("http_internal.hrl"). -%% Test server specific exports --export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, init_per_testcase/2, end_per_testcase/2]). - -%% Test cases must be exported. --export([ chunk_decode/1, chunk_encode/1, - chunk_extensions_otp_6005/1, chunk_decode_otp_6264/1, - chunk_decode_empty_chunk_otp_6511/1, - chunk_decode_trailer/1, - http_response/1, http_request/1, validate_request_line/1, - esi_parse_headers/1, cgi_parse_headers/1, - is_absolut_uri/1, convert_netscapecookie_date/1, - check_content_length_encoding/1]). - -suite() -> [{ct_hooks,[ts_install_cth]}]. +%% Note: This directive should only be used in test suites. +-compile(export_all). all() -> [{group, chunk}, http_response, http_request, @@ -52,7 +38,8 @@ groups() -> [chunk_decode, chunk_encode, chunk_extensions_otp_6005, chunk_decode_otp_6264, chunk_decode_empty_chunk_otp_6511, - chunk_decode_trailer]}]. + chunk_whitespace_suffix, + chunk_decode_trailer, chunk_max_headersize, chunk_max_bodysize, chunk_not_hex]}]. init_per_suite(Config) -> Config. @@ -81,12 +68,8 @@ end_per_testcase(_, Config) -> %% Test cases starts here. %%------------------------------------------------------------------------- - -%%------------------------------------------------------------------------- -chunk_decode(doc) -> - ["Test http_chunk:decode/3"]; -chunk_decode(suite) -> - []; +chunk_decode() -> + [{doc, "Test http_chunk:decode/3"}]. chunk_decode(Config) when is_list(Config) -> ReqHeaders = #http_request_h{'transfer-encoding' = "chunked"}, ChunkedBody = "A" ++ ?CRLF ++ "1234567890" ++ ?CRLF ++ "4" ++ @@ -109,15 +92,11 @@ chunk_decode(Config) when is_list(Config) -> ?HTTP_MAX_BODY_SIZE, ?HTTP_MAX_HEADER_SIZE), {_, Body} = parse(Module, Function, Args, tl(NewChunkedBody)), - "1234567890HEJ!" = binary_to_list(Body), - - ok. + "1234567890HEJ!" = binary_to_list(Body). %%------------------------------------------------------------------------- -chunk_extensions_otp_6005(doc) -> - ["Make sure so called extensions are ignored"]; -chunk_extensions_otp_6005(suite) -> - []; +chunk_extensions_otp_6005() -> + [{doc, "Make sure so called extensions are ignored"}]. chunk_extensions_otp_6005(Config) when is_list(Config)-> ChunkedBody = "A;ignore this" ++ ?CRLF ++ "1234567890" ++ ?CRLF ++ "4" ++ ?CRLF ++ "HEJ!"++ ?CRLF ++ "0" ++ @@ -136,14 +115,11 @@ chunk_extensions_otp_6005(Config) when is_list(Config)-> ?HTTP_MAX_BODY_SIZE, ?HTTP_MAX_HEADER_SIZE), {_, NewBody} = parse(Module1, Function1, Args1, tl(ChunkedBody1)), - "1234567890HEJ!" = binary_to_list(NewBody), - ok. + "1234567890HEJ!" = binary_to_list(NewBody). %%------------------------------------------------------------------------- -chunk_decode_otp_6264(doc) -> - ["Check that 0 in the body does not count as the last chunk"]; -chunk_decode_otp_6264(suite) -> - []; +chunk_decode_otp_6264() -> + [{doc, "Check that 0 in the body does not count as the last chunk"}]. chunk_decode_otp_6264(Config) when is_list(Config)-> ChunkedBody = "A;ignore this" ++ ?CRLF ++ "1234567890" ++ ?CRLF ++ "4" ++ ?CRLF ++ "0123"++ ?CRLF ++ "0" ++ @@ -173,27 +149,33 @@ chunk_decode_otp_6264(Config) when is_list(Config)-> ?HTTP_MAX_BODY_SIZE, ?HTTP_MAX_HEADER_SIZE), {_, NewBody} = parse(Module1, Function1, Args1, tl(NewChunkedBody1)), - "12345678900" = binary_to_list(NewBody), - - ok. + "12345678900" = binary_to_list(NewBody). %%------------------------------------------------------------------------- -chunk_decode_empty_chunk_otp_6511(doc) -> - [""]; -chunk_decode_empty_chunk_otp_6511(suite) -> - []; chunk_decode_empty_chunk_otp_6511(Config) when is_list(Config) -> ChunkedBody = "0" ++ ?CRLF ++ ?CRLF, {ok,{["content-length:0"],<<>>}} = http_chunk:decode(list_to_binary(ChunkedBody), - ?HTTP_MAX_BODY_SIZE, ?HTTP_MAX_HEADER_SIZE), - ok. + ?HTTP_MAX_BODY_SIZE, ?HTTP_MAX_HEADER_SIZE). %%------------------------------------------------------------------------- -chunk_decode_trailer(doc) -> - ["Make sure trailers are handled correctly. Trailers should" - "become new headers"]; -chunk_decode_trailer(suite) -> - []; +chunk_whitespace_suffix() -> + [{doc, "Test whitespace after chunked length header"}]. +chunk_whitespace_suffix(Config) when is_list(Config) -> + ChunkedBody = "1a ; ignore-stuff-here" ++ ?CRLF ++ + "abcdefghijklmnopqrstuvwxyz" ++ ?CRLF ++ "10 " ++ ?CRLF + ++ "1234567890abcdef" ++ ?CRLF ++ "0 " ++ ?CRLF + ++ "some-footer:some-value" ++ ?CRLF + ++ "another-footer:another-value" ++ ?CRLF ++ ?CRLF, + {ok, {["content-length:42", "another-footer:another-value", + "some-footer:some-value", ""], + <<"abcdefghijklmnopqrstuvwxyz1234567890abcdef">>}} = + http_chunk:decode(list_to_binary(ChunkedBody), + ?HTTP_MAX_BODY_SIZE, ?HTTP_MAX_HEADER_SIZE). + +%%------------------------------------------------------------------------- +chunk_decode_trailer() -> + [{doc,"Make sure trailers are handled correctly. Trailers should" + "become new headers"}]. chunk_decode_trailer(Config) when is_list(Config)-> ChunkedBody = "1a; ignore-stuff-here" ++ ?CRLF ++ "abcdefghijklmnopqrstuvwxyz" ++ ?CRLF ++ "10" ++ ?CRLF @@ -249,30 +231,79 @@ chunk_decode_trailer(Config) when is_list(Config)-> ?HTTP_MAX_BODY_SIZE, ?HTTP_MAX_HEADER_SIZE), {_, NewBody} = parse(Module1, Function1, Args1, tl(ChunkedBody3)), - "abcdefghijklmnopqrstuvwxyz1234567890abcdef" = binary_to_list(NewBody), - - ok. + "abcdefghijklmnopqrstuvwxyz1234567890abcdef" = binary_to_list(NewBody). %%------------------------------------------------------------------------- -chunk_encode(doc) -> - ["Test http_chunk:encode/1 & http_chunk:encode_last/0"]; -chunk_encode(suite) -> - []; +chunk_encode() -> + [{doc, "Test http_chunk:encode/1 & http_chunk:encode_last/0"}]. chunk_encode(Config) when is_list(Config) -> <<54, ?CR, ?LF, 102,111,111,98,97,114, ?CR, ?LF>> = http_chunk:encode(list_to_binary("foobar")), ["6", ?CR, ?LF,"foobar", ?CR, ?LF] = http_chunk:encode("foobar"), - <<$0, ?CR, ?LF, ?CR, ?LF >> = http_chunk:encode_last(), - ok. - + <<$0, ?CR, ?LF, ?CR, ?LF >> = http_chunk:encode_last(). +%%------------------------------------------------------------------------- +chunk_max_headersize() -> + [{doc, "Test max header limit"}]. +chunk_max_headersize(Config) when is_list(Config) -> + ChunkedBody = "1a; ignore-stuff-here" ++ ?CRLF ++ + "abcdefghijklmnopqrstuvwxyz" ++ ?CRLF ++ "10" ++ ?CRLF + ++ "1234567890abcdef" ++ ?CRLF ++ "0" ++ ?CRLF + ++ "some-footer:some-value" ++ ?CRLF + ++ "another-footer:another-value" ++ ?CRLF ++ ?CRLF, + + {ok, {_, _}} = + http_chunk:decode(list_to_binary(ChunkedBody), + ?HTTP_MAX_BODY_SIZE, ?HTTP_MAX_HEADER_SIZE), + + %% Too long in length header + {error,{header_too_long, {max, 1}}} = + (catch http_chunk:decode(list_to_binary(ChunkedBody), + ?HTTP_MAX_BODY_SIZE, 1)), + + %% Too long in extension field + {error,{header_too_long, {max, 10}}} = + (catch http_chunk:decode(list_to_binary(ChunkedBody), + ?HTTP_MAX_BODY_SIZE, 10)), + + %% Too long in trailer + {error,{header_too_long, {max, 30}}} = + (catch http_chunk:decode(list_to_binary(ChunkedBody), + ?HTTP_MAX_BODY_SIZE, 30)). +%%------------------------------------------------------------------------- +chunk_not_hex() -> + [{doc, "Test bad chunked length header"}]. +chunk_not_hex(Config) when is_list(Config) -> + ChunkedBody = "åäö; ignore-stuff-here" ++ ?CRLF ++ + "abcdefghijklmnopqrstuvwxyz" ++ ?CRLF ++ "10" ++ ?CRLF + ++ "1234567890abcdef" ++ ?CRLF ++ "0" ++ ?CRLF + ++ "some-footer:some-value" ++ ?CRLF + ++ "another-footer:another-value" ++ ?CRLF ++ ?CRLF, + {error,{chunk_size, "åäö"}} = + (catch http_chunk:decode(list_to_binary(ChunkedBody), + ?HTTP_MAX_BODY_SIZE, ?HTTP_MAX_HEADER_SIZE)). +%%------------------------------------------------------------------------- +chunk_max_bodysize() -> + [{doc, "Test max body limit"}]. +chunk_max_bodysize(Config) when is_list(Config) -> + ChunkedBody = "1a; ignore-stuff-here" ++ ?CRLF ++ + "abcdefghijklmnopqrstuvwxyz" ++ ?CRLF ++ "10" ++ ?CRLF + ++ "1234567890abcdef" ++ ?CRLF ++ "0" ++ ?CRLF + ++ "some-footer:some-value" ++ ?CRLF + ++ "another-footer:another-value" ++ ?CRLF ++ ?CRLF, + {ok, {_, _}} = + http_chunk:decode(list_to_binary(ChunkedBody), + ?HTTP_MAX_BODY_SIZE, ?HTTP_MAX_HEADER_SIZE), + + %% Too long body + {error,{body_too_big, {max, 10}}} = + (catch http_chunk:decode(list_to_binary(ChunkedBody), + 10, ?HTTP_MAX_HEADER_SIZE)). %%------------------------------------------------------------------------- -http_response(doc) -> - ["Test httpc_response:parse*. This test case will simulate that the " +http_response() -> + [{doc, "Test httpc_response:parse*. This test case will simulate that the " "message will be recived a little at the time on a socket and the " - "package may be broken up into smaller parts at arbitrary point."]; -http_response(suite) -> - []; + "package may be broken up into smaller parts at arbitrary point."}]. http_response(Config) when is_list(Config) -> HttpHead1 = ["HTTP", "/1.1 ", "20", "0 ", "ok", [?CR, ?LF], @@ -340,12 +371,10 @@ http_response(Config) when is_list(Config) -> [<<>>,Length1], HttpBody1)), ok. %%------------------------------------------------------------------------- -http_request(doc) -> - ["Test httpd_request:parse* This test case will simulate that the " +http_request() -> + [{doc, "Test httpd_request:parse* This test case will simulate that the " "message will be recived a little at the time on a socket and the " - "package may be broken up into smaller parts at arbitrary point."]; -http_request(suite) -> - []; + "package may be broken up into smaller parts at arbitrary point."}]. http_request(Config) when is_list(Config) -> HttpHead = ["GE", "T ", "http://www.erlang", ".org ", "HTTP", @@ -407,15 +436,12 @@ http_request(Config) when is_list(Config) -> NewBody1 = binary_to_list(parse (httpd_request, whole_body, - [<<>>, Length1], HttpBody1)), - ok. + [<<>>, Length1], HttpBody1)). %%------------------------------------------------------------------------- -validate_request_line(doc) -> - ["Test httpd_request:validate/3. Makes sure you can not get past" +validate_request_line() -> + [{doc, "Test httpd_request:validate/3. Makes sure you can not get past" " the server_root and that the request is recognized by the server" - " and protcol version." ]; -validate_request_line(suite) -> - []; + " and protcol version."}]. validate_request_line(Config) when is_list(Config) -> %% HTTP/0.9 only has GET requests @@ -468,16 +494,12 @@ validate_request_line(Config) when is_list(Config) -> NewForbiddenUri1 = "http://127.0.0.1:8888/../home/ingela/test.html", {error, {bad_request, {forbidden, NewForbiddenUri1}}} = - httpd_request:validate("GET", NewForbiddenUri1, "HTTP/1.1"), - - ok. + httpd_request:validate("GET", NewForbiddenUri1, "HTTP/1.1"). %%------------------------------------------------------------------------- -check_content_length_encoding(doc) -> - ["Test http_request:headers/2. Check that the content-length is" - " encoded even when it is zero." ]; -check_content_length_encoding(suite) -> - []; +check_content_length_encoding() -> + [{doc, "Test http_request:headers/2. Check that the content-length is" + " encoded even when it is zero."}]. check_content_length_encoding(Config) when is_list(Config) -> %% Check that the content-length is preserved. @@ -486,16 +508,12 @@ check_content_length_encoding(Config) when is_list(Config) -> true = (string:str(Header1, "content-length: 123\r\n") > 0), %% Check that content-length=0 is handled correctly. Header2 = http_request:http_headers(#http_request_h{'content-length'="0"}), - true = (string:str(Header2, "content-length: 0\r\n") > 0), - - ok. + true = (string:str(Header2, "content-length: 0\r\n") > 0). %%------------------------------------------------------------------------- -esi_parse_headers(doc) -> - ["Test httpd_esi:*. All header values are received in the same" - " erlang message."]; -esi_parse_headers(suite) -> - []; +esi_parse_headers() -> + [{doc, "Test httpd_esi:*. All header values are received in the same" + " erlang message."}]. esi_parse_headers(Config) when is_list(Config) -> ESIResult = "content-type:text/html\r\ndate:Thu, 28 Oct 2004 07:57:43 " @@ -522,16 +540,14 @@ esi_parse_headers(Config) when is_list(Config) -> httpd_esi:handle_headers(Headers2), {proceed,"/foo/bar.html"} = - httpd_esi:handle_headers("location:/foo/bar.html\r\n"), - ok. + httpd_esi:handle_headers("location:/foo/bar.html\r\n"). %%-------------------------------------------------------------------- -cgi_parse_headers(doc) -> - ["Test httpd_cgi:*. This test case will simulate that the " +cgi_parse_headers() -> + [{doc, "Test httpd_cgi:*. This test case will simulate that the " "message will be recived a little at the time on a socket and the " - "package may be broken up into smaller parts at arbitrary point."]; -cgi_parse_headers(suite) -> - []; + "package may be broken up into smaller parts at arbitrary point."}]. + cgi_parse_headers(Config) when is_list(Config) -> CGIResult = ["content-type:text", "/html\ndate:Thu, 28 Oct 2004 07:57:43 " @@ -567,26 +583,18 @@ cgi_parse_headers(Config) when is_list(Config) -> {ok,[{"content-type","text/html"}, {"connection","close"}, {"content-language","en"}, - {"age","4711"}], {200,"ok"}} = httpd_cgi:handle_headers(Headers3), - - ok. - + {"age","4711"}], {200,"ok"}} = httpd_cgi:handle_headers(Headers3). %%------------------------------------------------------------------------- -is_absolut_uri(doc) -> - ["Test http_request:is_absolut_uri/1."]; -is_absolut_uri(suite) -> - []; +is_absolut_uri() -> + [{doc, "Test http_request:is_absolut_uri/1."}]. is_absolut_uri(Config) when is_list(Config) -> true = http_request:is_absolut_uri("http://www.erlang.org"), true = http_request:is_absolut_uri("https://www.erlang.org"), false = http_request:is_absolut_uri("index.html"). - %%------------------------------------------------------------------------- -convert_netscapecookie_date(doc) -> - ["Test http_util:convert_netscapecookie_date/1."]; -convert_netscapecookie_date(suite) -> - []; +convert_netscapecookie_date() -> + [{doc, "Test http_util:convert_netscapecookie_date/1."}]. convert_netscapecookie_date(Config) when is_list(Config) -> {{2006,1,6},{8,59,38}} = http_util:convert_netscapecookie_date("Mon, 06-Jan-2006 08:59:38 GMT"), @@ -619,9 +627,7 @@ convert_netscapecookie_date(Config) when is_list(Config) -> {{2006,12,12},{8,59,38}} = http_util:convert_netscapecookie_date("Sun 12-Dec-06 08:59:38 GMT"), {{2036,1,1},{8,0,1}} = - http_util:convert_netscapecookie_date("Tue Jan 01 08:00:01 2036 GMT"), - ok. - + http_util:convert_netscapecookie_date("Tue Jan 01 08:00:01 2036 GMT"). %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index 5b40d08859..93b96e101f 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -68,6 +68,7 @@ real_requests()-> get, post, post_stream, + patch, async, pipeline, persistent_connection, @@ -98,13 +99,17 @@ only_simulated() -> stream_once, stream_single_chunk, stream_no_length, + not_streamed_once, + stream_large_not_200_or_206, no_content_204, tolerate_missing_CR, userinfo, bad_response, internal_server_error, invalid_http, + invalid_chunk_size, headers_dummy, + headers_with_obs_fold, empty_response_header, remote_socket_close, remote_socket_close_async, @@ -253,6 +258,28 @@ post(Config) when is_list(Config) -> "text/plain", "foobar"}, [], []). %%-------------------------------------------------------------------- +patch() -> + [{"Test http patch request against local server. We do in this case " + "only care about the client side of the the patch. The server " + "script will not actually use the patch data."}]. +patch(Config) when is_list(Config) -> + CGI = case test_server:os_type() of + {win32, _} -> + "/cgi-bin/cgi_echo.exe"; + _ -> + "/cgi-bin/cgi_echo" + end, + + URL = url(group_name(Config), CGI, Config), + + %% Cgi-script expects the body length to be 100 + Body = lists:duplicate(100, "1"), + + {ok, {{_,200,_}, [_ | _], [_ | _]}} = + httpc:request(patch, {URL, [{"expect","100-continue"}], + "text/plain", Body}, [], []). + +%%-------------------------------------------------------------------- post_stream() -> [{"Test streaming http post request against local server. " "We only care about the client side of the the post. " @@ -407,6 +434,21 @@ stream_no_length(Config) when is_list(Config) -> stream_test(Request1, {stream, self}), Request2 = {url(group_name(Config), "/http_1_0_no_length_multiple.html", Config), []}, stream_test(Request2, {stream, self}). +%%------------------------------------------------------------------------- +stream_large_not_200_or_206() -> + [{doc, "Test the option stream for large responses with status codes " + "other than 200 or 206" }]. +stream_large_not_200_or_206(Config) when is_list(Config) -> + Request = {url(group_name(Config), "/large_404_response.html", Config), []}, + {404, _} = not_streamed_test(Request, {stream, self}). +%%------------------------------------------------------------------------- +not_streamed_once() -> + [{doc, "Test not streamed responses with once streaming"}]. +not_streamed_once(Config) when is_list(Config) -> + Request0 = {url(group_name(Config), "/404.html", Config), []}, + {404, _} = not_streamed_test(Request0, {stream, {self, once}}), + Request1 = {url(group_name(Config), "/404_chunked.html", Config), []}, + {404, _} = not_streamed_test(Request1, {stream, {self, once}}). %%------------------------------------------------------------------------- @@ -747,6 +789,22 @@ invalid_http(Config) when is_list(Config) -> ct:print("Parse error: ~p ~n", [Reason]). %%------------------------------------------------------------------------- + +invalid_chunk_size(doc) -> + ["Test parse error of HTTP chunk size"]; +invalid_chunk_size(suite) -> + []; +invalid_chunk_size(Config) when is_list(Config) -> + + URL = url(group_name(Config), "/invalid_chunk_size.html", Config), + + {error, {chunk_size, _} = Reason} = + httpc:request(get, {URL, []}, [], []), + + ct:print("Parse error: ~p ~n", [Reason]). + +%%------------------------------------------------------------------------- + emulate_lower_versions(doc) -> [{doc, "Perform request as 0.9 and 1.0 clients."}]; emulate_lower_versions(Config) when is_list(Config) -> @@ -893,6 +951,13 @@ headers_dummy(Config) when is_list(Config) -> %%------------------------------------------------------------------------- +headers_with_obs_fold(Config) when is_list(Config) -> + Request = {url(group_name(Config), "/obs_folded_headers.html", Config), []}, + {ok, {{_,200,_}, Headers, [_|_]}} = httpc:request(get, Request, [], []), + "a b" = proplists:get_value("folded", Headers). + +%%------------------------------------------------------------------------- + invalid_headers(Config) -> Request = {url(group_name(Config), "/dummy.html", Config), [{"cookie", undefined}]}, {error, _} = httpc:request(get, Request, [], []). @@ -1109,6 +1174,19 @@ stream_test(Request, To) -> Body = binary_to_list(StreamedBody). +not_streamed_test(Request, To) -> + {ok, {{_,Code,_}, [_ | _], Body}} = + httpc:request(get, Request, [], [{body_format, binary}]), + {ok, RequestId} = + httpc:request(get, Request, [], [{body_format, binary}, {sync, false}, To]), + + receive + {http, {RequestId, {{_, Code, _}, _Headers, Body}}} -> + {Code, binary_to_list(Body)}; + {http, Msg} -> + ct:fail(Msg) + end. + url(http, End, Config) -> Port = ?config(port, Config), {ok,Host} = inet:gethostname(), @@ -1640,6 +1718,11 @@ handle_uri(_,"/307.html",Port,_,Socket,_) -> "Content-Length:" ++ integer_to_list(length(Body)) ++ "\r\n\r\n" ++ Body; +handle_uri(_,"/404.html",_,_,_,_) -> + "HTTP/1.1 404 not found\r\n" ++ + "Content-Length:14\r\n\r\n" ++ + "Page not found"; + handle_uri(_,"/500.html",_,_,_,_) -> "HTTP/1.1 500 Internal Server Error\r\n" ++ "Content-Length:47\r\n\r\n" ++ @@ -1713,6 +1796,13 @@ handle_uri(_,"/dummy_headers.html",_,_,Socket,_) -> send(Socket, http_chunk:encode("obar</BODY></HTML>")), http_chunk:encode_last(); +handle_uri(_,"/obs_folded_headers.html",_,_,_,_) -> + "HTTP/1.1 200 ok\r\n" + "Content-Length:5\r\n" + "Folded: a\r\n" + " b\r\n\r\n" + "Hello"; + handle_uri(_,"/capital_transfer_encoding.html",_,_,Socket,_) -> Head = "HTTP/1.1 200 ok\r\n" ++ "Transfer-Encoding:Chunked\r\n\r\n", @@ -1768,6 +1858,15 @@ handle_uri(_,"/once_chunked.html",_,_,Socket,_) -> http_chunk:encode("obar</BODY></HTML>")), http_chunk:encode_last(); +handle_uri(_,"/404_chunked.html",_,_,Socket,_) -> + Head = "HTTP/1.1 404 not found\r\n" ++ + "Transfer-Encoding:Chunked\r\n\r\n", + send(Socket, Head), + send(Socket, http_chunk:encode("<HTML><BODY>Not ")), + send(Socket, + http_chunk:encode("found</BODY></HTML>")), + http_chunk:encode_last(); + handle_uri(_,"/single_chunk.html",_,_,Socket,_) -> Chunk = "HTTP/1.1 200 ok\r\n" ++ "Transfer-Encoding:Chunked\r\n\r\n" ++ @@ -1792,6 +1891,17 @@ handle_uri(_,"/http_1_0_no_length_multiple.html",_,_,Socket,_) -> send(Socket, string:copies("other multiple packets ", 200)), close(Socket); +handle_uri(_,"/large_404_response.html",_,_,Socket,_) -> + %% long body to make sure it will be sent in multiple tcp packets + Body = string:copies("other multiple packets ", 200), + Head = io_lib:format("HTTP/1.1 404 not found\r\n" + "Content-length: ~B\r\n" + "Content-type: text/plain\r\n\r\n", + [length(Body)]), + send(Socket, Head), + send(Socket, Body), + close(Socket); + handle_uri(_,"/once.html",_,_,Socket,_) -> Head = "HTTP/1.1 200 ok\r\n" ++ "Content-Length:32\r\n\r\n", @@ -1806,6 +1916,10 @@ handle_uri(_,"/invalid_http.html",_,_,_,_) -> "HTTP/1.1 301\r\nDate:Sun, 09 Dec 2007 13:04:18 GMT\r\n" ++ "Transfer-Encoding:chunked\r\n\r\n"; +handle_uri(_,"/invalid_chunk_size.html",_,_,_,_) -> + "HTTP/1.1 200 ok\r\n" ++ + "Transfer-Encoding:chunked\r\n\r\nåäö\r\n"; + handle_uri(_,"/missing_reason_phrase.html",_,_,_,_) -> "HTTP/1.1 200\r\n" ++ "Content-Length: 32\r\n\r\n" diff --git a/lib/inets/test/httpc_proxy_SUITE.erl b/lib/inets/test/httpc_proxy_SUITE.erl index 786de1bc42..6d7af4ea5d 100644 --- a/lib/inets/test/httpc_proxy_SUITE.erl +++ b/lib/inets/test/httpc_proxy_SUITE.erl @@ -58,7 +58,7 @@ groups() -> [http_emulate_lower_versions |local_proxy_cases()]}, {local_proxy_https,[], - local_proxy_cases()}]. + local_proxy_cases() ++ local_proxy_https_cases()}]. %% internal functions @@ -77,6 +77,9 @@ local_proxy_cases() -> http_stream, http_not_modified_otp_6821]. +local_proxy_https_cases() -> + [https_connect_error]. + %%-------------------------------------------------------------------- init_per_suite(Config0) -> @@ -432,6 +435,21 @@ header_value(Name, [{HeaderName,HeaderValue}|Headers]) -> end. %%-------------------------------------------------------------------- +https_connect_error(doc) -> + ["Error from CONNECT tunnel should be returned"]; +https_connect_error(Config) when is_list(Config) -> + {HttpServer,HttpPort} = ?config(http, Config), + Method = get, + %% using HTTPS scheme with HTTP port to trigger connection error + URL = "https://" ++ HttpServer ++ ":" ++ + integer_to_list(HttpPort) ++ "/index.html", + Opts = [], + HttpOpts = [], + Request = {URL,[]}, + {error,{failed_connect,[_,{tls,_,_}]}} = + httpc:request(Method, Request, HttpOpts, Opts). + +%%-------------------------------------------------------------------- %% Internal Functions ------------------------------------------------ %%-------------------------------------------------------------------- diff --git a/lib/inets/test/httpc_proxy_SUITE_data/server_proxy.sh b/lib/inets/test/httpc_proxy_SUITE_data/server_proxy.sh index 9d1698c386..473024ae63 100755 --- a/lib/inets/test/httpc_proxy_SUITE_data/server_proxy.sh +++ b/lib/inets/test/httpc_proxy_SUITE_data/server_proxy.sh @@ -169,6 +169,8 @@ MaxRequestsPerChild 0 ViaProxyName "tinyproxy" ConnectPort $APACHE_HTTPS_PORT +# to test connect error +ConnectPort $APACHE_HTTP_PORT EOF (tinyproxy -d -c tinyproxy.conf 1>/dev/null 2>&1 </dev/null &)& wait_for_pidfile tinyproxy.pid diff --git a/lib/inets/test/httpd_1_1.erl b/lib/inets/test/httpd_1_1.erl index dd9d21bbfc..d3a1e3672a 100644 --- a/lib/inets/test/httpd_1_1.erl +++ b/lib/inets/test/httpd_1_1.erl @@ -24,7 +24,7 @@ -include_lib("kernel/include/file.hrl"). -export([host/4, chunked/4, expect/4, range/4, if_test/5, trace/4, - head/4, mod_cgi_chunked_encoding_test/5]). + head/4, mod_cgi_chunked_encoding_test/5, mod_esi_chunk_timeout/4]). %% -define(all_keys_lower_case,true). -ifndef(all_keys_lower_case). @@ -274,6 +274,15 @@ mod_cgi_chunked_encoding_test(Type, Port, Host, Node, [Request| Rest])-> [{statuscode, 200}]), mod_cgi_chunked_encoding_test(Type, Port, Host, Node, Rest). + +mod_esi_chunk_timeout(Type, Port, Host, Node) -> + ok = httpd_test_lib:verify_request(Type, Host, Port, Node, + "GET /cgi-bin/erl/httpd_example/chunk_timeout?input=20000 HTTP/1.1\r\n" + "Host:"++ Host ++"\r\n" + "\r\n", + [{statuscode, 200}, + {header, "warning"}]). + %%-------------------------------------------------------------------- %% Internal functions %%-------------------------------------------------------------------- @@ -361,18 +370,18 @@ validateRangeRequest2(Socket, Head, Body, ValidBody, BodySize) validateMultiPartRangeRequest(Body, ValidBody, Boundary)-> - case inets_regexp:split(Body,"--"++Boundary++"--") of + case re:split(Body,"--"++Boundary++"--", [{return, list}]) of %%Last is the epilogue and must be ignored - {ok,[First | _Last]}-> + [First | _Last]-> %%First is now the actuall http request body. - case inets_regexp:split(First, "--" ++ Boundary) of + case re:split(First, "--" ++ Boundary, [{return, list}]) of %%Parts is now a list of ranges and the heads for each range %%Gues we try to split out the body - {ok,Parts}-> + Parts-> case lists:flatten(lists:map(fun splitRange/1,Parts)) of ValidBody-> ok; - ParsedBody-> + ParsedBody-> error = ParsedBody end end; @@ -382,8 +391,8 @@ validateMultiPartRangeRequest(Body, ValidBody, Boundary)-> splitRange(Part)-> - case inets_regexp:split(Part, "\r\n\r\n") of - {ok,[_, Body]} -> + case re:split(Part, "\r\n\r\n", [{return, list}]) of + [_, Body] -> string:substr(Body, 1, length(Body) - 2); _ -> [] @@ -403,13 +412,13 @@ getRangeSize(Head)-> {multiPart, BoundaryString}-> {multiPart, BoundaryString}; _X1 -> - case inets_regexp:match(Head, ?CONTENT_RANGE "bytes=.*\r\n") of - {match, Start, Lenght} -> + case re:run(Head, ?CONTENT_RANGE "bytes=.*\r\n", [{capture, first}]) of + {match, [{Start, Lenght}]} -> %% Get the range data remove the fieldname and the %% end of line. - RangeInfo = string:substr(Head, Start + 20, - Lenght - (20 - 2)), - rangeSize(RangeInfo); + RangeInfo = string:substr(Head, Start + 1 + 20, + Lenght - (20 +2)), + rangeSize(string:strip(RangeInfo)); _X2 -> error end @@ -445,10 +454,10 @@ num(_CharVal, false) -> true. controlMimeType(Head)-> - case inets_regexp:match(Head,?CONTENT_TYPE "multipart/byteranges.*\r\n") of - {match,Start,Length}-> + case re:run(Head,?CONTENT_TYPE "multipart/byteranges.*\r\n", [{capture, first}]) of + {match, [{Start,Length}]}-> FieldNameLen = length(?CONTENT_TYPE "multipart/byteranges"), - case clearBoundary(string:substr(Head, Start + FieldNameLen, + case clearBoundary(string:substr(Head, Start + 1 + FieldNameLen, Length - (FieldNameLen+2))) of error -> error; @@ -462,10 +471,10 @@ controlMimeType(Head)-> end. clearBoundary(Boundary)-> - case inets_regexp:match(Boundary, "boundary=.*\$") of - {match, Start1, Length1}-> + case re:run(Boundary, "boundary=.*\$", [{capture, first}]) of + {match, [{Start1, Length1}]}-> BoundLen = length("boundary="), - string:substr(Boundary, Start1 + BoundLen, Length1 - BoundLen); + string:substr(Boundary, Start1 + 1 + BoundLen, Length1 - BoundLen); _ -> error end. @@ -480,12 +489,12 @@ end_of_header(HeaderPart) -> end. get_body_size(Head) -> - case inets_regexp:match(Head,?CONTENT_LENGTH ".*\r\n") of - {match, Start, Length} -> + case re:run(Head,?CONTENT_LENGTH ".*\r\n", [{capture, first}]) of + {match, [{Start, Length}]} -> %% 15 is length of Content-Length, %% 17 Is length of Content-Length and \r\ S = list_to_integer( - string:strip(string:substr(Head, Start + 15, Length-17))), + string:strip(string:substr(Head, Start +1 + 15, Length-17))), S; _-> 0 diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl index a6236f828a..87c504af74 100644 --- a/lib/inets/test/httpd_SUITE.erl +++ b/lib/inets/test/httpd_SUITE.erl @@ -70,7 +70,8 @@ all() -> {group, https_security}, {group, http_reload}, {group, https_reload}, - {group, http_mime_types} + {group, http_mime_types}, + mime_types_format ]. groups() -> @@ -97,7 +98,7 @@ groups() -> {https_reload, [], [{group, reload}]}, {http_mime_types, [], [alias_1_1, alias_1_0, alias_0_9]}, {limit, [], [max_clients_1_1, max_clients_1_0, max_clients_0_9]}, - {custom, [], [customize]}, + {custom, [], [customize, add_default]}, {reload, [], [non_disturbing_reconfiger_dies, disturbing_reconfiger_dies, non_disturbing_1_1, @@ -117,7 +118,7 @@ groups() -> {htaccess, [], [htaccess_1_1, htaccess_1_0, htaccess_0_9]}, {security, [], [security_1_1, security_1_0]}, %% Skip 0.9 as causes timing issus in test code {http_1_1, [], [host, chunked, expect, cgi, cgi_chunked_encoding_test, - trace, range, if_modified_since] ++ http_head() ++ http_get() ++ load()}, + trace, range, if_modified_since, mod_esi_chunk_timeout] ++ http_head() ++ http_get() ++ load()}, {http_1_0, [], [host, cgi, trace] ++ http_head() ++ http_get() ++ load()}, {http_0_9, [], http_head() ++ http_get() ++ load()} ]. @@ -755,7 +756,18 @@ esi(Config) when is_list(Config) -> %% Check "ErlScriptNoCache" directive (default: false) ok = http_status("GET /cgi-bin/erl/httpd_example:get ", Config, [{statuscode, 200}, - {no_header, "cache-control"}]). + {no_header, "cache-control"}]), + ok = http_status("GET /cgi-bin/erl/httpd_example:peer ", + Config, [{statuscode, 200}, + {header, "peer-cert-exist", peer(Config)}]). + +%%------------------------------------------------------------------------- +mod_esi_chunk_timeout(Config) when is_list(Config) -> + ok = httpd_1_1:mod_esi_chunk_timeout(?config(type, Config), + ?config(port, Config), + ?config(host, Config), + ?config(node, Config)). + %%------------------------------------------------------------------------- cgi() -> [{doc, "Test mod_cgi"}]. @@ -1003,10 +1015,23 @@ customize(Config) when is_list(Config) -> {no_header, "Server"}, {version, Version}]). -response_header({"server", _}) -> - false; -response_header(Header) -> - {true, Header}. +add_default() -> + [{doc, "Test adding default header with custom callback"}]. + +add_default(Config) when is_list(Config) -> + Version = "HTTP/1.1", + Host = ?config(host, Config), + Type = ?config(type, Config), + ok = httpd_test_lib:verify_request(?config(type, Config), Host, + ?config(port, Config), + transport_opts(Type, Config), + ?config(node, Config), + http_request("GET /index.html ", Version, Host), + [{statuscode, 200}, + {header, "Content-Type", "text/html"}, + {header, "Date", "Override-date"}, + {header, "X-Frame-Options"}, + {version, Version}]). %%------------------------------------------------------------------------- max_header() -> @@ -1267,6 +1292,115 @@ non_disturbing(Config) when is_list(Config)-> inets_test_lib:close(Type, Socket), [{server_name, "httpd_non_disturbing_" ++ Version}] = httpd:info(Server, [server_name]). +%%------------------------------------------------------------------------- +mime_types_format(Config) when is_list(Config) -> + DataDir = proplists:get_value(data_dir, Config), + MimeTypes = filename:join(DataDir, "mime_types.txt"), + {ok,[{"wrl","x-world/x-vrml"}, + {"vrml","x-world/x-vrml"}, + {"ice","x-conference/x-cooltalk"}, + {"movie","video/x-sgi-movie"}, + {"avi","video/x-msvideo"}, + {"qt","video/quicktime"}, + {"mov","video/quicktime"}, + {"mpeg","video/mpeg"}, + {"mpg","video/mpeg"}, + {"mpe","video/mpeg"}, + {"sgml","text/x-sgml"}, + {"sgm","text/x-sgml"}, + {"etx","text/x-setext"}, + {"tsv","text/tab-separated-values"}, + {"rtx","text/richtext"}, + {"txt","text/plain"}, + {"html","text/html"}, + {"htm","text/html"}, + {"css","text/css"}, + {"xwd","image/x-xwindowdump"}, + {"xpm","image/x-xpixmap"}, + {"xbm","image/x-xbitmap"}, + {"rgb","image/x-rgb"}, + {"ppm","image/x-portable-pixmap"}, + {"pgm","image/x-portable-graymap"}, + {"pbm","image/x-portable-bitmap"}, + {"pnm","image/x-portable-anymap"}, + {"ras","image/x-cmu-raster"}, + {"tiff","image/tiff"}, + {"tif","image/tiff"}, + {"png","image/png"}, + {"jpeg","image/jpeg"}, + {"jpg","image/jpeg"}, + {"jpe","image/jpeg"}, + {"ief","image/ief"}, + {"gif","image/gif"}, + {"pdb","chemical/x-pdb"}, + {"xyz","chemical/x-pdb"}, + {"wav","audio/x-wav"}, + {"ra","audio/x-realaudio"}, + {"rpm","audio/x-pn-realaudio-plugin"}, + {"ram","audio/x-pn-realaudio"}, + {"aif","audio/x-aiff"}, + {"aiff","audio/x-aiff"}, + {"aifc","audio/x-aiff"}, + {"mpga","audio/mpeg"}, + {"mp2","audio/mpeg"}, + {"au","audio/basic"}, + {"snd","audio/basic"}, + {"zip","application/zip"}, + {"src","application/x-wais-source"}, + {"ustar","application/x-ustar"}, + {"ms","application/x-troff-ms"}, + {"me","application/x-troff-me"}, + {"man","application/x-troff-man"}, + {"t","application/x-troff"}, + {"tr","application/x-troff"}, + {"roff","application/x-troff"}, + {"texinfo","application/x-texinfo"}, + {"texi","application/x-texinfo"}, + {"tex","application/x-tex"}, + {"tcl","application/x-tcl"}, + {"tar","application/x-tar"}, + {"sv4crc","application/x-sv4crc"}, + {"sv4cpio","application/x-sv4cpio"}, + {"sit","application/x-stuffit"}, + {"shar","application/x-shar"}, + {"sh","application/x-sh"}, + {"nc","application/x-netcdf"}, + {"cdf","application/x-netcdf"}, + {"mif","application/x-mif"}, + {"latex","application/x-latex"}, + {"skp","application/x-koan"}, + {"skd","application/x-koan"}, + {"skt","application/x-koan"}, + {"skm","application/x-koan"}, + {"cgi","application/x-httpd-cgi"}, + {"hdf","application/x-hdf"}, + {"gz","application/x-gzip"}, + {"gtar","application/x-gtar"}, + {"dvi","application/x-dvi"}, + {"dcr","application/x-director"}, + {"dir","application/x-director"}, + {"dxr","application/x-director"}, + {"csh","application/x-csh"}, + {"cpio","application/x-cpio"}, + {"Z","application/x-compress"}, + {"vcd","application/x-cdlink"}, + {"bcpio","application/x-bcpio"}, + {"rtf","application/rtf"}, + {"ppt","application/powerpoint"}, + {"ai","application/postscript"}, + {"eps","application/postscript"}, + {"ps","application/postscript"}, + {"pdf","application/pdf"}, + {"oda","application/oda"}, + {"bin","application/octet-stream"}, + {"dms","application/octet-stream"}, + {"lha","application/octet-stream"}, + {"lzh","application/octet-stream"}, + {"exe","application/octet-stream"}, + {"class","application/octet-stream"}, + {"doc","application/msword"}, + {"cpt","application/mac-compactpro"}, + {"hqx","application/mac-binhex40"}]} = httpd_conf:load_mime_types(MimeTypes). %%-------------------------------------------------------------------- %% Internal functions ----------------------------------- @@ -1421,13 +1555,15 @@ server_config(http_reload, Config) -> server_config(https_reload, Config) -> [{keep_alive_timeout, 2}] ++ server_config(https, Config); server_config(http_limit, Config) -> - [{max_clients, 1}, - %% Make sure option checking code is run - {max_content_length, 100000002}] ++ server_config(http, Config); + Conf = [{max_clients, 1}, + %% Make sure option checking code is run + {max_content_length, 100000002}] ++ server_config(http, Config), + ct:pal("Received message ~p~n", [Conf]), + Conf; server_config(http_custom, Config) -> - [{custom, ?MODULE}] ++ server_config(http, Config); + [{customize, ?MODULE}] ++ server_config(http, Config); server_config(https_custom, Config) -> - [{custom, ?MODULE}] ++ server_config(https, Config); + [{customize, ?MODULE}] ++ server_config(https, Config); server_config(https_limit, Config) -> [{max_clients, 1}] ++ server_config(https, Config); server_config(http_basic_auth, Config) -> @@ -1473,6 +1609,7 @@ server_config(http_mime_types, Config0) -> server_config(http, Config) -> ServerRoot = ?config(server_root, Config), [{port, 0}, + {socket_type, {ip_comm, [{nodelay, true}]}}, {server_name,"httpd_test"}, {server_root, ServerRoot}, {document_root, ?config(doc_root, Config)}, @@ -1494,13 +1631,14 @@ server_config(http, Config) -> server_config(https, Config) -> PrivDir = ?config(priv_dir, Config), [{socket_type, {essl, - [{cacertfile, - filename:join(PrivDir, "public_key_cacert.pem")}, - {certfile, - filename:join(PrivDir, "public_key_cert.pem")}, - {keyfile, - filename:join(PrivDir, "public_key_cert_key.pem")} - ]}}] ++ server_config(http, Config). + [{nodelay, true}, + {cacertfile, + filename:join(PrivDir, "public_key_cacert.pem")}, + {certfile, + filename:join(PrivDir, "public_key_cert.pem")}, + {keyfile, + filename:join(PrivDir, "public_key_cert_key.pem")} + ]}}] ++ proplists:delete(socket_type, server_config(http, Config)). init_httpd(Group, Config0) -> Config1 = proplists:delete(port, Config0), @@ -2030,3 +2168,22 @@ typestr(ip_comm) -> "tcp"; typestr(_) -> "ssl". + +response_header({"server", _}) -> + false; +response_header(Header) -> + {true, Header}. + +response_default_headers() -> + [%% Add new header + {"X-Frame-Options", "SAMEORIGIN"}, + %% Override built-in default + {"Date", "Override-date"}]. + +peer(Config) -> + case proplists:get_value(type, Config) of + ssl -> + "true"; + _ -> + "false" + end.
\ No newline at end of file diff --git a/lib/inets/test/httpd_SUITE_data/Makefile.src b/lib/inets/test/httpd_SUITE_data/Makefile.src index b0fdb43d8d..cea40dd8cb 100644 --- a/lib/inets/test/httpd_SUITE_data/Makefile.src +++ b/lib/inets/test/httpd_SUITE_data/Makefile.src @@ -10,5 +10,10 @@ all: $(PROGS) cgi_echo@exe@: cgi_echo@obj@ $(LD) $(CROSSLDFLAGS) -o cgi_echo cgi_echo@obj@ @LIBS@ +@IFEQ@ (@CC@, cl -nologo) +cgi_echo@obj@: cgi_echo.c + $(CC) /c /Focgi_echo@obj@ $(CFLAGS) cgi_echo.c +@ELSE@ cgi_echo@obj@: cgi_echo.c $(CC) -c -o cgi_echo@obj@ $(CFLAGS) cgi_echo.c +@ENDIF@ diff --git a/lib/inets/test/httpd_SUITE_data/mime_types.txt b/lib/inets/test/httpd_SUITE_data/mime_types.txt new file mode 100644 index 0000000000..3149a119d5 --- /dev/null +++ b/lib/inets/test/httpd_SUITE_data/mime_types.txt @@ -0,0 +1,100 @@ +# This is a comment. I love comments. + + +application/activemessage +application/andrew-inset +application/applefile +application/atomicmail +application/dca-rft +application/dec-dx +application/mac-binhex40 hqx +application/mac-compactpro cpt +application/macwriteii +application/msword doc +application/news-message-id +application/news-transmission +application/octet-stream bin dms lha lzh exe class +application/oda oda +application/pdf pdf +application/postscript ai eps ps +application/powerpoint ppt +application/remote-printing +application/rtf rtf +application/slate +application/wita +application/wordperfect5.1 +application/x-bcpio bcpio +application/x-cdlink vcd +application/x-compress Z +application/x-cpio cpio +application/x-csh csh +application/x-director dcr dir dxr +application/x-dvi dvi +application/x-gtar gtar +application/x-gzip gz +application/x-hdf hdf +application/x-httpd-cgi cgi +application/x-koan skp skd skt skm +application/x-latex latex +application/x-mif mif +application/x-netcdf nc cdf +application/x-sh sh +application/x-shar shar +application/x-stuffit sit +application/x-sv4cpio sv4cpio +application/x-sv4crc sv4crc +application/x-tar tar +application/x-tcl tcl +application/x-tex tex +application/x-texinfo texinfo texi +application/x-troff t tr roff +application/x-troff-man man +application/x-troff-me me +application/x-troff-ms ms +application/x-ustar ustar +application/x-wais-source src +application/zip zip +audio/basic au snd +audio/mpeg mpga mp2 +audio/x-aiff aif aiff aifc +audio/x-pn-realaudio ram +audio/x-pn-realaudio-plugin rpm +audio/x-realaudio ra +audio/x-wav wav +chemical/x-pdb pdb xyz +image/gif gif +image/ief ief +image/jpeg jpeg jpg jpe +image/png png +image/tiff tiff tif +image/x-cmu-raster ras +image/x-portable-anymap pnm +image/x-portable-bitmap pbm +image/x-portable-graymap pgm +image/x-portable-pixmap ppm +image/x-rgb rgb +image/x-xbitmap xbm +image/x-xpixmap xpm +image/x-xwindowdump xwd +message/external-body +message/news +message/partial +message/rfc822 +multipart/alternative +multipart/appledouble +multipart/digest +multipart/mixed +multipart/parallel +text/css css +text/html html htm +text/plain txt +text/richtext rtx +text/tab-separated-values tsv +text/x-setext etx +text/x-sgml sgml sgm +video/mpeg mpeg mpg mpe +video/quicktime qt mov +video/x-msvideo avi +video/x-sgi-movie movie +x-conference/x-cooltalk ice +x-world/x-vrml wrl vrml diff --git a/lib/inets/test/httpd_poll.erl b/lib/inets/test/httpd_poll.erl index aca7b70376..4a570fb512 100644 --- a/lib/inets/test/httpd_poll.erl +++ b/lib/inets/test/httpd_poll.erl @@ -259,11 +259,11 @@ validate(ExpStatusCode,Socket,Response) -> vtrace("validate -> Entry with ~p bytes response",[Sz]), Size = trash_the_rest(Socket,Sz), close(Socket), - case inets_regexp:split(Response," ") of - {ok,["HTTP/1.0",ExpStatusCode|_]} -> + case re:split(Response," ", [{return, list}]) of + ["HTTP/1.0",ExpStatusCode|_] -> vlog("response (~p bytes) was ok",[Size]), ok; - {ok,["HTTP/1.0",StatusCode|_]} -> + ["HTTP/1.0",StatusCode|_] -> verror("unexpected response status received: ~s => ~s", [StatusCode,status_to_message(StatusCode)]), log("unexpected result to GET of '~s': ~s => ~s", diff --git a/lib/inets/test/httpd_test_lib.erl b/lib/inets/test/httpd_test_lib.erl index cb2e86c81e..71e201f826 100644 --- a/lib/inets/test/httpd_test_lib.erl +++ b/lib/inets/test/httpd_test_lib.erl @@ -96,10 +96,10 @@ verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, Options, Ti try inets_test_lib:connect_bin(SocketType, Host, Port, TranspOpts) of {ok, Socket} -> ok = inets_test_lib:send(SocketType, Socket, RequestStr), - State = case inets_regexp:match(RequestStr, "printenv") of + State = case re:run(RequestStr, "printenv", [{capture, none}]) of nomatch -> #state{}; - _ -> + match -> #state{print = true} end, @@ -235,11 +235,17 @@ validate(RequestStr, #state{status_line = {Version, StatusCode, _}, _ -> ok end, - do_validate(http_response:header_list(Headers), Options, N, P), - check_body(RequestStr, StatusCode, - Headers#http_response_h.'content-type', - list_to_integer(Headers#http_response_h.'content-length'), - Body). + HList = http_response:header_list(Headers), + do_validate(HList, Options, N, P), + case lists:keysearch("warning", 1, HList) of + {value, _} -> + ok; + _ -> + check_body(RequestStr, StatusCode, + Headers#http_response_h.'content-type', + list_to_integer(Headers#http_response_h.'content-length'), + Body) + end. %-------------------------------------------------------------------- %% Internal functions @@ -294,9 +300,9 @@ do_validate(Header, [{header, HeaderField, Value}|Rest],N,P) -> {value, {LowerHeaderField, Value}} -> ok; false -> - ct:fail({wrong_header_field_value, LowerHeaderField, Header}); + ct:fail({wrong_header_field_value, LowerHeaderField, Header, Value}); _ -> - ct:fail({wrong_header_field_value, LowerHeaderField, Header}) + ct:fail({wrong_header_field_value, LowerHeaderField, Header, Value}) end, do_validate(Header, Rest, N, P); do_validate(Header,[{no_header, HeaderField}|Rest],N,P) -> @@ -311,10 +317,10 @@ do_validate(Header, [_Unknown | Rest], N, P) -> do_validate(Header, Rest, N, P). is_expect(RequestStr) -> - case inets_regexp:match(RequestStr, "xpect:100-continue") of - {match, _, _}-> + case re:run(RequestStr, "xpect:100-continue", [{capture, none}]) of + match-> true; - _ -> + nomatch -> false end. diff --git a/lib/inets/test/httpd_time_test.erl b/lib/inets/test/httpd_time_test.erl index 7c0acb5a99..1b4d74b28e 100644 --- a/lib/inets/test/httpd_time_test.erl +++ b/lib/inets/test/httpd_time_test.erl @@ -386,31 +386,31 @@ validate(ExpStatusCode, _SocketType, _Socket, Response) -> %% Sz = sz(Response), %% trash_the_rest(Socket, Sz), %% inets_test_lib:close(SocketType, Socket), - case inets_regexp:split(Response," ") of - {ok, ["HTTP/1.0", ExpStatusCode|_]} -> + case re:split(Response," ", [{return, list}]) of + ["HTTP/1.0", ExpStatusCode|_] -> ok; - {ok, ["HTTP/1.0", StatusCode|_]} -> + ["HTTP/1.0", StatusCode|_] -> error_msg("Unexpected status code: ~p (~s). " "Expected status code: ~p (~s)", [StatusCode, status_to_message(StatusCode), ExpStatusCode, status_to_message(ExpStatusCode)]), exit({unexpected_response_code, StatusCode, ExpStatusCode}); - {ok, ["HTTP/1.1", ExpStatusCode|_]} -> + ["HTTP/1.1", ExpStatusCode|_] -> ok; - {ok, ["HTTP/1.1", StatusCode|_]} -> + ["HTTP/1.1", StatusCode|_] -> error_msg("Unexpected status code: ~p (~s). " "Expected status code: ~p (~s)", [StatusCode, status_to_message(StatusCode), ExpStatusCode, status_to_message(ExpStatusCode)]), exit({unexpected_response_code, StatusCode, ExpStatusCode}); - {ok, Unexpected} -> - error_msg("Unexpected response split: ~p (~s)", - [Unexpected, Response]), - exit({unexpected_response, Unexpected, Response}); - {error, Reason} -> + {error, Reason} -> error_msg("Failed processing response: ~p (~s)", [Reason, Response]), - exit({failed_response_processing, Reason, Response}) + exit({failed_response_processing, Reason, Response}); + Unexpected -> + error_msg("Unexpected response split: ~p (~s)", + [Unexpected, Response]), + exit({unexpected_response, Unexpected, Response}) end. diff --git a/lib/inets/test/inets_SUITE.erl b/lib/inets/test/inets_SUITE.erl index c3586f09e3..928d9dc391 100644 --- a/lib/inets/test/inets_SUITE.erl +++ b/lib/inets/test/inets_SUITE.erl @@ -21,7 +21,6 @@ -module(inets_SUITE). -include_lib("common_test/include/ct.hrl"). --include("test_server_line.hrl"). -include("inets_test_lib.hrl"). %% Note: This directive should only be used in test suites. @@ -37,8 +36,12 @@ all() -> groups() -> [{services_test, [], - [start_inets, start_httpc, start_httpd, start_ftpc, - start_tftpd]}, + [start_inets, + start_httpc, + start_httpd, + start_ftpc, + start_tftpd + ]}, {app_test, [], [{inets_app_test, all}]}, {appup_test, [], [{inets_appup_test, all}]}]. @@ -48,9 +51,6 @@ init_per_group(_GroupName, Config) -> end_per_group(_GroupName, Config) -> Config. - - - %%-------------------------------------------------------------------- %% Function: init_per_suite(Config) -> Config %% Config - [tuple()] @@ -103,14 +103,8 @@ end_per_testcase(_, Config) -> %% Test cases starts here. %%------------------------------------------------------------------------- - - -%%------------------------------------------------------------------------- - -start_inets(doc) -> - ["Test inets API functions"]; -start_inets(suite) -> - []; +start_inets() -> + [{doc, "Test inets API functions"}]. start_inets(Config) when is_list(Config) -> [_|_] = inets:service_names(), @@ -134,134 +128,85 @@ start_inets(Config) when is_list(Config) -> ok = inets:start(permanent), ok = inets:stop(). - %%------------------------------------------------------------------------- -start_httpc(doc) -> - ["Start/stop of httpc service"]; -start_httpc(suite) -> - []; +start_httpc() -> + [{doc, "Start/stop of httpc service"}]. start_httpc(Config) when is_list(Config) -> process_flag(trap_exit, true), - tsp("start_httpc -> entry with" - "~n Config: ~p", [Config]), - PrivDir = ?config(priv_dir, Config), - tsp("start_httpc -> start (empty) inets"), ok = inets:start(), - - tsp("start_httpc -> start httpc (as inets service) with profile foo"), {ok, Pid0} = inets:start(httpc, [{profile, foo}]), - tsp("start_httpc -> check running services"), Pids0 = [ServicePid || {_, ServicePid} <- inets:services()], true = lists:member(Pid0, Pids0), [_|_] = inets:services_info(), - tsp("start_httpc -> stop httpc"), inets:stop(httpc, Pid0), - tsp("start_httpc -> sleep some"), test_server:sleep(100), - tsp("start_httpc -> check running services"), Pids1 = [ServicePid || {_, ServicePid} <- inets:services()], false = lists:member(Pid0, Pids1), - tsp("start_httpc -> start httpc (stand-alone) with profile bar"), {ok, Pid1} = inets:start(httpc, [{profile, bar}], stand_alone), - tsp("start_httpc -> check running services"), Pids2 = [ServicePid || {_, ServicePid} <- inets:services()], false = lists:member(Pid1, Pids2), - tsp("start_httpc -> stop httpc"), ok = inets:stop(stand_alone, Pid1), receive {'EXIT', Pid1, shutdown} -> ok after 100 -> - tsf(stand_alone_not_shutdown) + ct:fail(stand_alone_not_shutdown) end, - tsp("start_httpc -> stop inets"), ok = inets:stop(), - tsp("start_httpc -> unload inets"), application:load(inets), - - tsp("start_httpc -> set inets environment (httpc profile foo)"), application:set_env(inets, services, [{httpc,[{profile, foo}, {data_dir, PrivDir}]}]), - - tsp("start_httpc -> start inets"), ok = inets:start(), - tsp("start_httpc -> check running services"), (?NUM_DEFAULT_SERVICES + 1) = length(inets:services()), - tsp("start_httpc -> unset inets env"), application:unset_env(inets, services), - - tsp("start_httpc -> stop inets"), ok = inets:stop(), - - tsp("start_httpc -> start (empty) inets"), ok = inets:start(), - tsp("start_httpc -> start inets httpc service with profile foo"), {ok, Pid3} = inets:start(httpc, [{profile, foo}]), - - tsp("start_httpc -> stop inets service httpc with profile foo"), ok = inets:stop(httpc, foo), - - tsp("start_httpc -> check running services"), Pids3 = [ServicePid || {_, ServicePid} <- inets:services()], false = lists:member(Pid3, Pids3), - - tsp("start_httpc -> stop inets"), - ok = inets:stop(), - - tsp("start_httpc -> done"), - ok. - + ok = inets:stop(). %%------------------------------------------------------------------------- -start_httpd(doc) -> - ["Start/stop of httpd service"]; -start_httpd(suite) -> - []; +start_httpd() -> + [{doc, "Start/stop of httpd service"}]. start_httpd(Config) when is_list(Config) -> process_flag(trap_exit, true), - i("start_httpd -> entry with" - "~n Config: ~p", [Config]), PrivDir = ?config(priv_dir, Config), HttpdConf = [{server_name, "httpd_test"}, {server_root, PrivDir}, - {document_root, PrivDir}, {bind_address, "localhost"}], + {document_root, PrivDir}, {bind_address, any}], - i("start_httpd -> start inets"), ok = inets:start(), - - i("start_httpd -> start httpd service"), {ok, Pid0} = inets:start(httpd, [{port, 0}, {ipfamily, inet} | HttpdConf]), Pids0 = [ServicePid || {_, ServicePid} <- inets:services()], true = lists:member(Pid0, Pids0), [_|_] = inets:services_info(), - i("start_httpd -> stop httpd service"), inets:stop(httpd, Pid0), test_server:sleep(500), Pids1 = [ServicePid || {_, ServicePid} <- inets:services()], false = lists:member(Pid0, Pids1), - i("start_httpd -> start (stand-alone) httpd service"), {ok, Pid1} = inets:start(httpd, [{port, 0}, {ipfamily, inet} | HttpdConf], stand_alone), Pids2 = [ServicePid || {_, ServicePid} <- inets:services()], false = lists:member(Pid1, Pids2), - i("start_httpd -> stop (stand-alone) httpd service"), ok = inets:stop(stand_alone, Pid1), receive {'EXIT', Pid1, shutdown} -> @@ -269,7 +214,6 @@ start_httpd(Config) when is_list(Config) -> after 100 -> test_server:fail(stand_alone_not_shutdown) end, - i("start_httpd -> stop inets"), ok = inets:stop(), File0 = filename:join(PrivDir, "httpd.conf"), {ok, Fd0} = file:open(File0, [write]), @@ -277,17 +221,12 @@ start_httpd(Config) when is_list(Config) -> ok = file:write(Fd0, Str), file:close(Fd0), - i("start_httpd -> [application] load inets"), application:load(inets), - i("start_httpd -> [application] set httpd services env with proplist-file"), application:set_env(inets, services, [{httpd, [{proplist_file, File0}]}]), - i("start_httpd -> start inets"), ok = inets:start(), (?NUM_DEFAULT_SERVICES + 1) = length(inets:services()), - i("start_httpd -> [application] unset services env"), application:unset_env(inets, services), - i("start_httpd -> stop inets"), ok = inets:stop(), File1 = filename:join(PrivDir, "httpd_apache.conf"), @@ -300,68 +239,46 @@ start_httpd(Config) when is_list(Config) -> file:write(Fd1, "Port 0\r\n"), file:close(Fd1), - i("start_httpd -> [application] load inets"), application:load(inets), - i("start_httpd -> [application] set httpd services env with file"), application:set_env(inets, services, [{httpd, [{file, File1}]}]), - i("start_httpd -> start inets"), ok = inets:start(), (?NUM_DEFAULT_SERVICES + 1) = length(inets:services()), - i("start_httpd -> [application] unset services env"), application:unset_env(inets, services), - i("start_httpd -> stop inets"), ok = inets:stop(), %% OLD format - i("start_httpd -> [application] load inets"), application:load(inets), - i("start_httpd -> [application] set httpd services OLD env"), application:set_env(inets, services, [{httpd, File1}]), - i("start_httpd -> start inets"), ok = inets:start(), (?NUM_DEFAULT_SERVICES + 1) = length(inets:services()), - i("start_httpd -> [application] unset services enc"), application:unset_env(inets, services), - i("start_httpd -> stop inets"), ok = inets:stop(), - - i("start_httpd -> start inets"), ok = inets:start(), - i("start_httpd -> try (and fail) start httpd service - server_name"), {error, {missing_property, server_name}} = inets:start(httpd, [{port, 0}, {server_root, PrivDir}, {document_root, PrivDir}, {bind_address, "localhost"}]), - i("start_httpd -> try (and fail) start httpd service - missing document_root"), {error, {missing_property, document_root}} = inets:start(httpd, [{port, 0}, {server_name, "httpd_test"}, {server_root, PrivDir}, {bind_address, "localhost"}]), - i("start_httpd -> try (and fail) start httpd service - missing server_root"), {error, {missing_property, server_root}} = inets:start(httpd, [{port, 0}, {server_name, "httpd_test"}, {document_root, PrivDir}, {bind_address, "localhost"}]), - i("start_httpd -> try (and fail) start httpd service - missing port"), {error, {missing_property, port}} = inets:start(httpd, HttpdConf), - i("start_httpd -> stop inets"), - ok = inets:stop(), - i("start_httpd -> done"), - ok. - + ok = inets:stop(). %%------------------------------------------------------------------------- start_ftpc(doc) -> - ["Start/stop of ftpc service"]; -start_ftpc(suite) -> - []; + [{doc, "Start/stop of ftpc service"}]; start_ftpc(Config) when is_list(Config) -> process_flag(trap_exit, true), ok = inets:start(), @@ -389,7 +306,7 @@ start_ftpc(Config) when is_list(Config) -> {'EXIT', Pid1, shutdown} -> ok after 100 -> - tsf(stand_alone_not_shutdown) + ct:fail(stand_alone_not_shutdown) end, ok = inets:stop(), ok; @@ -401,15 +318,11 @@ start_ftpc(Config) when is_list(Config) -> throw:{error, not_found} -> {skip, "No available FTP servers"} end. - - %%------------------------------------------------------------------------- -start_tftpd(doc) -> - ["Start/stop of tfpd service"]; -start_tftpd(suite) -> - []; +start_tftpd() -> + [{doc, "Start/stop of tfpd service"}]. start_tftpd(Config) when is_list(Config) -> process_flag(trap_exit, true), ok = inets:start(), @@ -441,16 +354,12 @@ start_tftpd(Config) when is_list(Config) -> application:unset_env(inets, services), ok = inets:stop(). - %%------------------------------------------------------------------------- -httpd_reload(doc) -> - ["Reload httpd configuration without restarting service"]; -httpd_reload(suite) -> - []; +httpd_reload() -> + [{doc, "Reload httpd configuration without restarting service"}]. httpd_reload(Config) when is_list(Config) -> process_flag(trap_exit, true), - i("httpd_reload -> starting"), PrivDir = ?config(priv_dir, Config), DataDir = ?config(data_dir, Config), HttpdConf = [{server_name, "httpd_test"}, @@ -458,23 +367,18 @@ httpd_reload(Config) when is_list(Config) -> {document_root, PrivDir}, {bind_address, "localhost"}], - i("httpd_reload -> start inets"), - ok = inets:start(), test_server:sleep(5000), - i("httpd_reload -> inets started - start httpd service"), - {ok, Pid0} = inets:start(httpd, [{port, 0}, {ipfamily, inet} | HttpdConf]), + {ok, Pid0} = inets:start(httpd, [{port, 0}, + {ipfamily, inet} | HttpdConf]), test_server:sleep(5000), - i("httpd_reload -> httpd service started (~p) - get port", [Pid0]), [{port, Port0}] = httpd:info(Pid0, [port]), test_server:sleep(5000), - i("httpd_reload -> Port: ~p - get document root", [Port0]), [{document_root, PrivDir}] = httpd:info(Pid0, [document_root]), test_server:sleep(5000), - i("httpd_reload -> document root: ~p - reload config", [PrivDir]), ok = httpd:reload_config([{port, Port0}, {ipfamily, inet}, {server_name, "httpd_test"}, @@ -482,11 +386,8 @@ httpd_reload(Config) when is_list(Config) -> {document_root, DataDir}, {bind_address, "localhost"}], non_disturbing), test_server:sleep(5000), - io:format("~w:~w:httpd_reload - reloaded - get document root~n", [?MODULE, ?LINE]), - [{document_root, DataDir}] = httpd:info(Pid0, [document_root]), test_server:sleep(5000), - i("httpd_reload -> document root: ~p - reload config", [DataDir]), ok = httpd:reload_config([{port, Port0}, {ipfamily, inet}, {server_name, "httpd_test"}, @@ -539,23 +440,5 @@ httpd_reload(Config) when is_list(Config) -> ok = inets:stop(httpd, Pid1), application:unset_env(inets, services), - ok = inets:stop(), - i("httpd_reload -> starting"), - ok. - - -tsf(Reason) -> - test_server:fail(Reason). - -tsp(F) -> - tsp(F, []). -tsp(F, A) -> - Timestamp = inets_lib:formated_timestamp(), - test_server:format("** ~s ** ~p ~p:" ++ F ++ "~n", [Timestamp, self(), ?MODULE | A]). - -i(F) -> - i(F, []). + ok = inets:stop(). -i(F, A) -> - Timestamp = inets_lib:formated_timestamp(), - io:format("*** ~s ~w:" ++ F ++ "~n", [Timestamp, ?MODULE | A]). diff --git a/lib/inets/test/inets_socketwrap_SUITE.erl b/lib/inets/test/inets_socketwrap_SUITE.erl new file mode 100644 index 0000000000..cfbda3ccf5 --- /dev/null +++ b/lib/inets/test/inets_socketwrap_SUITE.erl @@ -0,0 +1,154 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2015. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(inets_socketwrap_SUITE). + +-include_lib("common_test/include/ct.hrl"). +-include("inets_test_lib.hrl"). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +suite() -> + [{ct_hooks,[ts_install_cth]}]. + +all() -> + [start_httpd_fd, start_tftpd_fd]. + +init_per_suite(Config) -> + case os:type() of + {unix, linux} -> + Config; + _ -> + {skip, linux_feature} + end. + +end_per_suite(_Config) -> + ok. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + +init_per_testcase(Case, Config) -> + end_per_testcase(Case, Config), + Config. + +end_per_testcase(_, Config) -> + inets:stop(), + Config. + +%%------------------------------------------------------------------------- +start_httpd_fd() -> + [{doc, "Start/stop of httpd service with socket wrapper"}]. +start_httpd_fd(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + DataDir = ?config(data_dir, Config), + HttpdConf = [{port, 80}, {ipfamily, inet}, + {server_name, "httpd_fd_test"}, {server_root, PrivDir}, + {document_root, PrivDir}, {bind_address, any}], + case setup_node_info(node()) of + {skip, _} = Skip -> + Skip; + {Node, NodeArg} -> + InetPort = inets_test_lib:inet_port(node()), + ct:pal("Node: ~p Port ~p~n", [Node, InetPort]), + Wrapper = filename:join(DataDir, "setuid_socket_wrap"), + Cmd = Wrapper ++ + " -s -httpd_80,0:" ++ integer_to_list(InetPort) + ++ " -p " ++ os:find_executable("erl") ++ + " -- " ++ NodeArg, + ct:pal("cmd: ~p~n", [Cmd]), + case open_port({spawn, Cmd}, [stderr_to_stdout]) of + Port when is_port(Port) -> + wait_node_up(Node, 10), + ct:pal("~p", [rpc:call(Node, init, get_argument, [httpd_80])]), + ok = rpc:call(Node, inets, start, []), + {ok, Pid} = rpc:call(Node, inets, start, [httpd, HttpdConf]), + [{port, InetPort}] = rpc:call(Node, httpd, info, [Pid, [port]]), + rpc:call(Node, erlang, halt, []); + _ -> + ct:fail(open_port_failed) + end + end. +%%------------------------------------------------------------------------- +start_tftpd_fd() -> + [{doc, "Start/stop of tfpd service with socket wrapper"}]. +start_tftpd_fd(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + case setup_node_info(node()) of + {skip, _} = Skip -> + Skip; + {Node, NodeArg} -> + InetPort = inets_test_lib:inet_port(node()), + ct:pal("Node: ~p~n", [Node]), + Wrapper = filename:join(DataDir, "setuid_socket_wrap"), + Cmd = Wrapper ++ + " -s -tftpd_69,0:" ++ integer_to_list(InetPort) + ++ " -p " ++ os:find_executable("erl") ++ + " -- " ++ NodeArg, + ct:pal("cmd: ~p~n", [Cmd]), + case open_port({spawn, Cmd}, [stderr_to_stdout]) of + Port when is_port(Port) -> + wait_node_up(Node, 10), + ct:pal("~p", [rpc:call(Node, init, get_argument, [tftpd_69])]), + ok = rpc:call(Node, inets, start, []), + {ok, Pid} = rpc:call(Node, inets, start, + [tftpd,[{host, "localhost"}]]), + {ok, Info} = rpc:call(Node, tftp, info, [Pid]), + {value,{port, InetPort}} = lists:keysearch(port, 1, Info), + rpc:call(Node, erlang, halt, []); + _ -> + ct:fail(open_port_failed) + end + end. +%%------------------------------------------------------------------------- +%% Internal functions +%%------------------------------------------------------------------------- +setup_node_info(nonode@nohost) -> + {skip, needs_distributed_node}; +setup_node_info(Node) -> + Static = "-detached -noinput", + Name = "inets_fd_test", + NameSw = case net_kernel:longnames() of + false -> "-sname "; + _ -> "-name " + end, + StrNode = + Static ++ " " + ++ NameSw ++ " " ++ Name ++ " " + ++ "-setcookie " ++ atom_to_list(erlang:get_cookie()), + [_, Location] = string:tokens(atom_to_list(Node), "$@"), + TestNode = Name ++ "@" ++ Location, + {list_to_atom(TestNode), StrNode}. + +wait_node_up(Node, 0) -> + ct:fail({failed_to_start_node, Node}); +wait_node_up(Node, N) -> + ct:pal("(Node ~p: net_adm:ping(~p)~n", [node(), Node]), + case net_adm:ping(Node) of + pong -> + ok; + pang -> + ct:sleep(5000), + wait_node_up(Node, N-1) + end. diff --git a/lib/inets/test/inets_socketwrap_SUITE_data/Makefile.src b/lib/inets/test/inets_socketwrap_SUITE_data/Makefile.src new file mode 100644 index 0000000000..0933815b58 --- /dev/null +++ b/lib/inets/test/inets_socketwrap_SUITE_data/Makefile.src @@ -0,0 +1,39 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2015-2015. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# %CopyrightEnd% +# + +CC = @CC@ +LD = @LD@ +CFLAGS = @CFLAGS@ +CROSSLDFLAGS = @CROSSLDFLAGS@ + +PROGS = setuid_socket_wrap@exe@ + +.PHONY: all +@IFEQ@ (@os@, linux-gnu) +all: $(PROGS) +@ELSE@ +all: +@ENDIF@ + +setuid_socket_wrap@exe@: setuid_socket_wrap@obj@ + $(LD) $(CROSSLDFLAGS) -o setuid_socket_wrap setuid_socket_wrap@obj@ @LIBS@ + +setuid_socket_wrap@obj@: setuid_socket_wrap.c + $(CC) -c $(CFLAGS) -o setuid_socket_wrap@obj@ setuid_socket_wrap.c diff --git a/lib/inets/test/inets_socketwrap_SUITE_data/setuid_socket_wrap.c b/lib/inets/test/inets_socketwrap_SUITE_data/setuid_socket_wrap.c new file mode 100644 index 0000000000..b28f6b1c08 --- /dev/null +++ b/lib/inets/test/inets_socketwrap_SUITE_data/setuid_socket_wrap.c @@ -0,0 +1,259 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * %CopyrightEnd% + */ +/* + * setuid_socket_wrap.c + * + * ./a.out [-s [tag,][addr]:[port]]* [-d [tag,][addr]:[port]]* + * [-r [tag,]proto]* [-p erl_path]* -- program args + * + * Where: -s = stream socket, -d datagram socket and -r means raw socket. + * + */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> + +#ifndef INADDR_NONE +#define INADDR_NONE 0xffffffff +#endif + +struct sock_list { + struct sock_list *next; + int fd; + int type; + int protocol; + struct sockaddr_in addr; + char *arg; +}; + +int parse_addr(addr, str) + struct sockaddr_in *addr; + char *str; +{ + int port = 0; + char *cp; + struct hostent *hp; + struct servent *se; + + if ((cp = strrchr(str, (int)':')) != NULL) + *cp++ = '\0'; + if (cp) { + if (!isdigit((int)cp[0])) { + if ((se = getservbyname(cp, "tcp")) != NULL) { + port = ntohs(se->s_port); + } else { + fprintf(stderr, "unknown port %s\n", cp); + return -1; + } + } else { + port = atoi(cp); + } + } + if (port < 0 || port > 0xffff) { + fprintf(stderr, "bad port number %d\n", port); + return -1; + } + + bzero(addr, sizeof(*addr)); + addr->sin_family = AF_INET; + addr->sin_port = htons(port); + if (*str == '\000') { + addr->sin_addr.s_addr = INADDR_ANY; + } else { + if ((addr->sin_addr.s_addr = inet_addr(str)) == INADDR_NONE) { + if ((hp = gethostbyname(str)) == NULL) { + fprintf(stderr, "\"%s\" unknown host or address!\n", str); + return -1; + } else { + bcopy(hp->h_addr_list[0], &addr->sin_addr.s_addr,hp->h_length); + } + } + } + return 0; +} + +struct sock_list *new_entry(type, argstr) + int type; + char *argstr; +{ + struct sock_list *sle; + char *cp; + + sle = (struct sock_list *)malloc(sizeof(struct sock_list)); + if (!sle) + return NULL; + sle->next = NULL; + sle->fd = -1; + + if ((cp = strchr(argstr, (int)',')) != NULL) { + *cp++ = '\0'; + sle->arg = argstr; + argstr = cp; + } else { + sle->arg = "-fd"; + } + sle->type = type; + switch (type) { + case SOCK_RAW: { + struct protoent *pe; + pe = getprotobyname(argstr); + if (!pe) { + fprintf(stderr, "Unknown protocol: %s\n", argstr); + free(sle); + return NULL; + } + sle->protocol = pe->p_proto; + break; + } + case SOCK_STREAM: + case SOCK_DGRAM: + sle->protocol = 0; + if (parse_addr(&sle->addr, argstr) < 0) { + free(sle); + return NULL; + } + break; + } + return sle; +} + +int open_socket(sle) + struct sock_list *sle; +{ + sle->fd = socket(AF_INET, sle->type, sle->protocol); + if (sle->fd < 0) { + perror("socket"); + return -1; + } + if (sle->type != SOCK_RAW) { +#if 0 + printf("binding fd %d to %s:%d\n", sle->fd, + inet_ntoa(sle->addr.sin_addr), ntohs(sle->addr.sin_port)); +#endif + if (bind(sle->fd, (struct sockaddr *)&sle->addr, sizeof(sle->addr))<0){ + perror("bind"); + close(sle->fd); + return -1; + } + } + return sle->fd; +} + +int main(argc, argv) + int argc; + char *argv[]; +{ + struct sock_list *sl = NULL, *sltmp = NULL; + int count = 0; + int c; + char *run_prog = NULL; + + while ((c = getopt(argc, argv, "s:d:r:p:")) != EOF) + switch (c) { + case 's': + sltmp = new_entry(SOCK_STREAM, optarg); + if (!sltmp) { + exit(1); + } + sltmp->next = sl; + sl = sltmp; + count++; + break; + case 'd': + sltmp = new_entry(SOCK_DGRAM, optarg); + if (!sltmp) { + exit(1); + } + sltmp->next = sl; + sl = sltmp; + count++; + break; + case 'r': + sltmp = new_entry(SOCK_RAW, optarg); + if (!sltmp) { + exit(1); + } + sltmp->next = sl; + sl = sltmp; + count++; + break; + case 'p': + run_prog = optarg; + break; + default: + exit(1); + } + argc -= optind; + argv += optind; + + for(sltmp = sl; sltmp != NULL; sltmp = sltmp->next) + if (open_socket(sltmp) < 0) { + fprintf(stderr, "failed to create socket!\n"); + exit(1); + } + + setuid(getuid()); + + { + int i; + char **newargv; + char *run_prog_name; + + newargv = (char **)malloc((1 + 2*count + argc + 1) * sizeof(char*)); + + if ((run_prog_name = strrchr(run_prog, (int)'/')) == NULL) + run_prog_name = run_prog; + else + run_prog_name++; + + i = 0; + newargv[i++] = run_prog_name; + + for (; argc; argc--, argv++, i++) + newargv[i] = *argv; + for(sltmp = sl; sltmp != NULL; ) { + char *fd_str = (char *)malloc(8); + if (!fd_str) exit(1); + sprintf(fd_str, "%d", sltmp->fd); + if (sltmp->arg && *(sltmp->arg)) + newargv[i++] = sltmp->arg; + newargv[i++] = fd_str; + sl = sltmp; + sltmp = sltmp->next; + free(sl); + } + newargv[i] = (char *)NULL; + execv(run_prog, newargv); + perror("exec"); + exit(1); + } + exit(0); +} diff --git a/lib/inets/test/inets_test_lib.erl b/lib/inets/test/inets_test_lib.erl index b471dcf784..f1185f7574 100644 --- a/lib/inets/test/inets_test_lib.erl +++ b/lib/inets/test/inets_test_lib.erl @@ -563,3 +563,12 @@ stop_apps(Apps) -> application:stop(App) end, Apps). +inet_port(Node) -> + {Port, Socket} = do_inet_port(Node), + rpc:call(Node, gen_tcp, close, [Socket]), + Port. + +do_inet_port(Node) -> + {ok, Socket} = rpc:call(Node, gen_tcp, listen, [0, [{reuseaddr, true}]]), + {ok, Port} = rpc:call(Node, inet, port, [Socket]), + {Port, Socket}. diff --git a/lib/inets/test/tftp_SUITE.erl b/lib/inets/test/tftp_SUITE.erl index d29d210d7d..497a50e654 100644 --- a/lib/inets/test/tftp_SUITE.erl +++ b/lib/inets/test/tftp_SUITE.erl @@ -76,7 +76,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [simple, extra, reuse_connection, resend_client, - resend_server]. + resend_server, large_file]. groups() -> []. @@ -902,6 +902,41 @@ reuse_connection(Config) when is_list(Config) -> ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Large file: transfer > 65535 blocks +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +large_file(doc) -> + ["Start the daemon and test transfer of files greater than 32M."]; +large_file(suite) -> + []; +large_file(Config) when is_list(Config) -> + ?VERIFY(ok, application:start(inets)), + + {Port, DaemonPid} = ?IGNORE(?START_DAEMON(0, [{debug, brief}])), + + %% Read fail + RemoteFilename = "tftp_temporary_large_file_remote_test_file.txt", + LocalFilename = "tftp_temporary_large_file_local_test_file.txt", + + {ok, FH} = file:open(LocalFilename, [write,exclusive]), + {ok, Size} = file:position(FH, {eof, 2*512*65535}), + ok = file:truncate(FH), + ?IGNORE(file:close(FH)), + + %% Write and read + ?VERIFY({ok, Size}, tftp:write_file(RemoteFilename, LocalFilename, [{port, Port}])), + ?IGNORE(file:delete(LocalFilename)), + ?VERIFY({ok, Size}, tftp:read_file(RemoteFilename, LocalFilename, [{port, Port}])), + + %% Cleanup + unlink(DaemonPid), + exit(DaemonPid, kill), + ?VERIFY(ok, file:delete(LocalFilename)), + ?VERIFY(ok, file:delete(RemoteFilename)), + ?VERIFY(ok, application:stop(inets)), + ok. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Goodies %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/inets/test/uri_SUITE.erl b/lib/inets/test/uri_SUITE.erl index bfcd7bd339..2642b8fd4e 100644 --- a/lib/inets/test/uri_SUITE.erl +++ b/lib/inets/test/uri_SUITE.erl @@ -49,7 +49,8 @@ all() -> queries, fragments, escaped, - hexed_query + hexed_query, + scheme_validation ]. %%-------------------------------------------------------------------- @@ -175,6 +176,26 @@ hexed_query(Config) when is_list(Config) -> verify_uri(URI2, Verify2), verify_uri(URI3, Verify3). +scheme_validation(Config) when is_list(Config) -> + {ok, {http,[],"localhost",80,"/",""}} = + http_uri:parse("http://localhost#fragment"), + + ValidationFun = + fun("http") -> valid; + (_) -> {error, bad_scheme} + end, + + {ok, {http,[],"localhost",80,"/",""}} = + http_uri:parse("http://localhost#fragment", + [{scheme_validation_fun, ValidationFun}]), + {error, bad_scheme} = + http_uri:parse("https://localhost#fragment", + [{scheme_validation_fun, ValidationFun}]), + %% non-fun scheme_validation_fun works as no option passed + {ok, {https,[],"localhost",443,"/",""}} = + http_uri:parse("https://localhost#fragment", + [{scheme_validation_fun, none}]). + %%-------------------------------------------------------------------- %% Internal Functions ------------------------------------------------ diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk index 5395df1d07..12ac75a4b9 100644 --- a/lib/inets/vsn.mk +++ b/lib/inets/vsn.mk @@ -19,6 +19,6 @@ # %CopyrightEnd% APPLICATION = inets -INETS_VSN = 6.0 +INETS_VSN = 6.2.4 PRE_VSN = APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)" diff --git a/lib/jinterface/doc/src/notes.xml b/lib/jinterface/doc/src/notes.xml index d9f7ae9f92..e66bcda0c1 100644 --- a/lib/jinterface/doc/src/notes.xml +++ b/lib/jinterface/doc/src/notes.xml @@ -31,6 +31,28 @@ </header> <p>This document describes the changes made to the Jinterface application.</p> +<section><title>Jinterface 1.6.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Add missing Term tag matching switch statement that was + missing an external fun tag.</p> + <p> + Own Id: OTP-13106</p> + </item> + <item> + <p> + fixed writing small compressed values.</p> + <p> + Own Id: OTP-13165</p> + </item> + </list> + </section> + +</section> + <section><title>Jinterface 1.6</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangMap.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangMap.java index 0fd7d3ce37..30126db3fd 100644 --- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangMap.java +++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangMap.java @@ -19,7 +19,7 @@ */ package com.ericsson.otp.erlang; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set; @@ -37,13 +37,22 @@ public class OtpErlangMap extends OtpErlangObject { // don't change this! private static final long serialVersionUID = -6410770117696198497L; - private HashMap<OtpErlangObject, OtpErlangObject> map; + private OtpMap map; + + private static class OtpMap + extends LinkedHashMap<OtpErlangObject, OtpErlangObject> { + private static final long serialVersionUID = -2666505810905455082L; + + public OtpMap() { + super(); + } + } /** * Create an empty map. */ public OtpErlangMap() { - map = new HashMap<OtpErlangObject, OtpErlangObject>(); + map = new OtpMap(); } /** @@ -93,7 +102,7 @@ public class OtpErlangMap extends OtpErlangObject { throw new java.lang.IllegalArgumentException( "Map keys and values must have same arity"); } - map = new HashMap<OtpErlangObject, OtpErlangObject>(vcount); + map = new OtpMap(); OtpErlangObject key, val; for (int i = 0; i < vcount; i++) { if ((key = keys[kstart + i]) == null) { @@ -125,7 +134,7 @@ public class OtpErlangMap extends OtpErlangObject { final int arity = buf.read_map_head(); if (arity > 0) { - map = new HashMap<OtpErlangObject, OtpErlangObject>(arity); + map = new OtpMap(); for (int i = 0; i < arity; i++) { OtpErlangObject key, val; key = buf.read_any(); @@ -133,7 +142,7 @@ public class OtpErlangMap extends OtpErlangObject { put(key, val); } } else { - map = new HashMap<OtpErlangObject, OtpErlangObject>(); + map = new OtpMap(); } } @@ -350,7 +359,7 @@ public class OtpErlangMap extends OtpErlangObject { @SuppressWarnings("unchecked") public Object clone() { final OtpErlangMap newMap = (OtpErlangMap) super.clone(); - newMap.map = (HashMap<OtpErlangObject, OtpErlangObject>) map.clone(); + newMap.map = (OtpMap) map.clone(); return newMap; } } diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpInputStream.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpInputStream.java index 35280f9571..fa0815fbf0 100644 --- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpInputStream.java +++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpInputStream.java @@ -1243,6 +1243,9 @@ public class OtpInputStream extends ByteArrayInputStream { case OtpExternal.funTag: return new OtpErlangFun(this); + case OtpExternal.externalFunTag: + return new OtpErlangExternalFun(this); + default: throw new OtpErlangDecodeException("Uknown data type: " + tag); } diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpOutputStream.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpOutputStream.java index 2830a7842e..4faae2a157 100644 --- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpOutputStream.java +++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpOutputStream.java @@ -922,8 +922,22 @@ public class OtpOutputStream extends ByteArrayOutputStream { oos.writeTo(dos); dos.close(); // note: closes this, too! } catch (final IllegalArgumentException e) { - // discard further un-compressed data - // -> if not called, there may be memory leaks! + /* + * Discard further un-compressed data (if not called, there may + * be memory leaks). + * + * After calling java.util.zip.Deflater.end(), the deflater + * should not be used anymore, not even the close() method of + * dos. Calling dos.close() before def.end() is prevented since + * an unfinished DeflaterOutputStream will try to deflate its + * unprocessed data to the (fixed) byte array which is prevented + * by ensureCapacity() and would also unnecessarily process + * further data that is discarded anyway. + * + * Since we are re-using the byte array of this object below, we + * must not call close() in e.g. a finally block either (with or + * without a call to def.end()). + */ def.end(); // could not make the value smaller than originally // -> reset to starting count, write uncompressed @@ -942,11 +956,6 @@ public class OtpOutputStream extends ByteArrayOutputStream { "Intermediate stream failed for Erlang object " + o); } finally { fixedSize = Integer.MAX_VALUE; - try { - dos.close(); - } catch (final IOException e) { - // ignore - } } } } diff --git a/lib/jinterface/test/nc_SUITE.erl b/lib/jinterface/test/nc_SUITE.erl index 9679b90a0d..c5f3198c21 100644 --- a/lib/jinterface/test/nc_SUITE.erl +++ b/lib/jinterface/test/nc_SUITE.erl @@ -215,6 +215,7 @@ decompress_roundtrip(Config) when is_list(Config) -> 0.0, math:sqrt(2), <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,31:5>>, + "{}", RandomBin1k, RandomBin1M, RandomBin10M, @@ -244,6 +245,7 @@ compress_roundtrip(Config) when is_list(Config) -> 0.0, math:sqrt(2), <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,31:5>>, + "{}", RandomBin1k, RandomBin1M, RandomBin10M, diff --git a/lib/jinterface/vsn.mk b/lib/jinterface/vsn.mk index 4df01d1151..41e670528a 100644 --- a/lib/jinterface/vsn.mk +++ b/lib/jinterface/vsn.mk @@ -1 +1 @@ -JINTERFACE_VSN = 1.6 +JINTERFACE_VSN = 1.6.1 diff --git a/lib/kernel/doc/src/app.xml b/lib/kernel/doc/src/app.xml index 1591d589af..35feec144e 100644 --- a/lib/kernel/doc/src/app.xml +++ b/lib/kernel/doc/src/app.xml @@ -191,7 +191,7 @@ RTDeps [ApplicationVersion] [] start phases must be a subset of the set of phases defined for the primary application. Refer to <em>OTP Design Principles</em> for more information.</p> </item> - <tag><marker id="runtime_dependencies"><c>runtime_dependencies</c></marker></tag> + <tag><marker id="runtime_dependencies"></marker><c>runtime_dependencies</c></tag> <item><p>A list of application versions that the application depends on. An example of such an application version is <c>"kernel-3.0"</c>. Application versions specified as runtime @@ -201,7 +201,7 @@ RTDeps [ApplicationVersion] [] how to compare application versions see <seealso marker="doc/system_principles:versions">the documentation of versions in the system principles - guide</seealso>. Note that that the application version + guide</seealso>. Note that the application version specifies a source code version. An additional indirect requirement is that installed binary application of the specified version has been built so that it is diff --git a/lib/kernel/doc/src/application.xml b/lib/kernel/doc/src/application.xml index 0fe774a73f..4d8e6ce94b 100644 --- a/lib/kernel/doc/src/application.xml +++ b/lib/kernel/doc/src/application.xml @@ -60,8 +60,9 @@ </datatype> <datatype> <!-- Parameterized opaque types are NYI: --> - <name><marker id="type-tuple_of">tuple_of(T)</marker></name> - <desc><p>A tuple where the elements are of type <c>T</c>.</p></desc> + <name>tuple_of(T)</name> + <desc><p><marker id="type-tuple_of"/> + A tuple where the elements are of type <c>T</c>.</p></desc> </datatype> </datatypes> <funcs> diff --git a/lib/kernel/doc/src/auth.xml b/lib/kernel/doc/src/auth.xml index 9ebc6f8f1a..71b1863e96 100644 --- a/lib/kernel/doc/src/auth.xml +++ b/lib/kernel/doc/src/auth.xml @@ -50,7 +50,7 @@ be established in this case. Returns <c>no</c> if <c><anno>Node</anno></c> does not exist or communication is not authorized (it has another cookie than <c>auth</c> thinks it has).</p> - <p>Use <seealso marker="net_adm#ping/1">net_adm:ping(<anno>Node</anno>)</seealso> + <p>Use <seealso marker="net_adm#ping/1">net_adm:ping(<c><anno>Node</anno></c>)</seealso> instead.</p> </desc> </func> @@ -71,7 +71,7 @@ </type_desc> <desc> <p>Use - <seealso marker="erts:erlang#erlang:set_cookie/2">erlang:set_cookie(node(), <anno>Cookie</anno>)</seealso> + <seealso marker="erts:erlang#erlang:set_cookie/2">erlang:set_cookie(node(), <c><anno>Cookie</anno></c>)</seealso> instead.</p> </desc> </func> @@ -94,8 +94,8 @@ <p>Sets the magic cookie of <c><anno>Node</anno></c> to <c><anno>Cookie</anno></c>, and verifies the status of the authorization. Equivalent to calling - <seealso marker="erts:erlang#erlang:set_cookie/2">erlang:set_cookie(<anno>Node</anno>, <anno>Cookie</anno>)</seealso>, followed by - <seealso marker="#is_auth/1">auth:is_auth(<anno>Node</anno>)</seealso>.</p> + <seealso marker="erts:erlang#erlang:set_cookie/2">erlang:set_cookie(<c><anno>Node</anno></c>, <c><anno>Cookie</anno>)</c></seealso>, followed by + <seealso marker="#is_auth/1">auth:is_auth(<c><anno>Node</anno></c>)</seealso>.</p> </desc> </func> </funcs> diff --git a/lib/kernel/doc/src/code.xml b/lib/kernel/doc/src/code.xml index 7cdedfa0ba..1bd52040a0 100644 --- a/lib/kernel/doc/src/code.xml +++ b/lib/kernel/doc/src/code.xml @@ -180,7 +180,7 @@ example, the call <c>erl_prim_loader:list_dir( "/otp/root/lib/mnesia-4.4.7.ez/mnesia-4.4.7/examples/bench)"</c> would list the contents of a directory inside an archive. - See <seealso marker="erts:erl_prim_loader">erl_prim_loader(3)</seealso></p>. + See <seealso marker="erts:erl_prim_loader">erl_prim_loader(3)</seealso>.</p> <p>An application archive file and a regular application directory may coexist. This may be useful when there is a need of having @@ -230,7 +230,7 @@ <c>-code_path_choice Choice</c>. If the flag is set to <c>relaxed</c>, the code server will instead choose a suitable directory depending on the actual file structure. If there exists a regular - application ebin directory,situation it will be chosen. But if it does + application ebin directory, it will be chosen. But if it does not exist, the ebin directory in the archive is chosen if it exists. If neither of them exists the original directory will be chosen.</p> @@ -242,7 +242,7 @@ particular useful to set the flag to <c>relaxed</c> when you want to elaborate with code loading from archives without editing the <c>boot script</c>. The default is <c>relaxed</c>. See <seealso - marker="erts:init">init(3)</seealso></p> </section> + marker="erts:init">init(3)</seealso></p></section> <section> @@ -282,11 +282,51 @@ <p>From the R12B release, functions in this module will generally fail with an exception if they are passed an incorrect type (for instance, an integer or a tuple - where an atom was expected). An error tuple will be returned if type of argument + where an atom was expected). An error tuple will be returned if the type of the argument was correct, but there was some other error (for instance, a non-existing directory - given to <c>set_path/1</c>.</p> + was given to <c>set_path/1</c>).</p> </section> + <section> + <marker id="error_reasons"></marker> + <title>Error Reasons for Code-Loading Functions</title> + + <p>Functions that load code (such as <c>load_file/1</c>) will + return <c>{error,Reason}</c> if the load operation fails. + Here follows a description of the common reasons.</p> + + <taglist> + <tag><c>badfile</c></tag> + <item> + <p>The object code has an incorrect format or the module + name in the object code is not the expected module name.</p> + </item> + + <tag><c>nofile</c></tag> + <item> + <p>No file with object code was found.</p> + </item> + + <tag><c>not_purged</c></tag> + <item> + <p>The object code could not be loaded because an old version + of the code already existed.</p> + </item> + + <tag><c>on_load_failure</c></tag> + <item> + <p>The module has an + <seealso marker="doc/reference_manual:code_loading#on_load">-on_load function</seealso> + that failed when it was called.</p> + </item> + + <tag><c>sticky_directory</c></tag> + <item> + <p>The object code resides in a sticky directory.</p> + </item> + + </taglist> + </section> <datatypes> <datatype> <name name="load_ret"/> @@ -411,12 +451,8 @@ be used to load object code with a module name that is different from the file name.</p> <p>Returns <c>{module, <anno>Module</anno>}</c> if successful, or - <c>{error, nofile}</c> if no object code is found, or - <c>{error, sticky_directory}</c> if the object code resides in - a sticky directory. Also if the loading fails, an error tuple is - returned. See - <seealso marker="erts:erlang#load_module/2">erlang:load_module/2</seealso> - for possible values of <c><anno>What</anno></c>.</p> + <c>{error, Reason}</c> if loading fails. + See <seealso marker="#error_reasons">Error Reasons for Code-Loading Functions</seealso> for a description of the possible error reasons.</p> </desc> </func> <func> @@ -428,7 +464,7 @@ <desc> <p>Does the same as <c>load_file(<anno>Module</anno>)</c>, but <c><anno>Filename</anno></c> is either an absolute file name, or a - relative file name. The code path is not searched. It returns + relative file name. The code path is not searched. It returns a value in the same way as <seealso marker="#load_file/1">load_file/1</seealso>. Note that <c><anno>Filename</anno></c> should not contain the extension (for @@ -444,7 +480,8 @@ <seealso marker="#load_file/1">load_file/1</seealso>, unless the module is already loaded. In embedded mode, however, it does not load a module which is not - already loaded, but returns <c>{error, embedded}</c> instead.</p> + already loaded, but returns <c>{error, embedded}</c> instead. + See <seealso marker="#error_reasons">Error Reasons for Code-Loading Functions</seealso> for a description of other possible error reasons.</p> </desc> </func> <func> @@ -461,12 +498,8 @@ comes. Accordingly, <c><anno>Filename</anno></c> is not opened and read by the code server.</p> <p>Returns <c>{module, <anno>Module</anno>}</c> if successful, or - <c>{error, sticky_directory}</c> if the object code resides in - a sticky directory, or <c>{error, badarg}</c> if any argument - is invalid. Also if the loading fails, an error tuple is - returned. See - <seealso marker="erts:erlang#load_module/2">erlang:load_module/2</seealso> - for possible values of <c><anno>What</anno></c>.</p> + <c>{error, Reason}</c> if loading fails. + See <seealso marker="#error_reasons">Error Reasons for Code-Loading Functions</seealso> for a description of the possible error reasons.</p> </desc> </func> <func> diff --git a/lib/kernel/doc/src/disk_log.xml b/lib/kernel/doc/src/disk_log.xml index 32488a9f01..7d4a9687ea 100644 --- a/lib/kernel/doc/src/disk_log.xml +++ b/lib/kernel/doc/src/disk_log.xml @@ -233,11 +233,11 @@ <func> <name name="alog" arity="2"/> <name name="balog" arity="2"/> + <fsummary>Asynchronously log an item onto a disk log.</fsummary> <type variable="Log"/> <type variable="Term" name_i="1"/> <type variable="Bytes"/> <type name="notify_ret"/> - <fsummary>Asynchronously log an item onto a disk log.</fsummary> <desc> <p>The <c>alog/2</c> and <c>balog/2</c> functions asynchronously append an item to a disk log. The function <c>alog/2</c> is @@ -288,8 +288,8 @@ <func> <name name="block" arity="1"/> <name name="block" arity="2"/> - <type name="block_error_rsn"/> <fsummary>Block a disk log.</fsummary> + <type name="block_error_rsn"/> <desc> <p>With a call to <c>block/1,2</c> a process can block a log. If the blocking process is not an owner of the log, a temporary @@ -663,8 +663,8 @@ <func> <name name="lclose" arity="1"/> <name name="lclose" arity="2"/> - <type name="lclose_error_rsn"/> <fsummary>Close a disk log on one node.</fsummary> + <type name="lclose_error_rsn"/> <desc> <p>The function <c>lclose/1</c> closes a local log or an individual distributed log on the current node. @@ -744,6 +744,7 @@ </func> <func> <name name="open" arity="1"/> + <fsummary>Open a disk log file.</fsummary> <type name="dlog_options"/> <type name="dlog_option"/> <type name="open_ret"/> @@ -753,7 +754,6 @@ <type name="open_error_rsn"/> <type name="dlog_optattr"/> <type name="dlog_size"/> - <fsummary>Open a disk log file.</fsummary> <desc> <p>The <c><anno>ArgL</anno></c> parameter is a list of options which have the following meanings:</p> @@ -1043,8 +1043,8 @@ If </func> <func> <name name="sync" arity="1"/> - <type name="sync_error_rsn"/> <fsummary>Flush the contents of a disk log to the disk.</fsummary> + <type name="sync_error_rsn"/> <desc> <p>The <c>sync/1</c> function ensures that the contents of the log are actually written to the disk. @@ -1086,8 +1086,8 @@ If </func> <func> <name name="unblock" arity="1"/> - <type name="unblock_error_rsn"/> <fsummary>Unblock a disk log.</fsummary> + <type name="unblock_error_rsn"/> <desc> <p>The <c>unblock/1</c> function unblocks a log. A log can only be unblocked by the blocking process. diff --git a/lib/kernel/doc/src/erl_ddll.xml b/lib/kernel/doc/src/erl_ddll.xml index d622725ba0..8d71883cf4 100644 --- a/lib/kernel/doc/src/erl_ddll.xml +++ b/lib/kernel/doc/src/erl_ddll.xml @@ -388,14 +388,14 @@ remove a monitor.</p> <p>The function accepts the following parameters:</p> <taglist> - <tag><em><anno>Tag</anno></em></tag> + <tag><em><c><anno>Tag</anno></c></em></tag> <item> <p>The monitor tag is always <c>driver</c> as this function can only be used to create driver monitors. In the future, driver monitors will be integrated with process monitors, why this parameter has to be given for consistence.</p> </item> - <tag><em><anno>Item</anno></em></tag> + <tag><em><c><anno>Item</anno></c></em></tag> <item> <p>The <c><anno>Item</anno></c> parameter specifies which driver one wants to monitor (the name of the driver) as well as @@ -642,7 +642,7 @@ </note> <p>The function accepts the following parameters:</p> <taglist> - <tag><em><anno>Path</anno></em></tag> + <tag><em><c><anno>Path</anno></c></em></tag> <item> <p>The filesystem path to the directory where the driver object file is situated. The filename of the object file @@ -665,7 +665,7 @@ to have <em>only one loader</em> of a driver one wants to upgrade in a running system! </p> </item> - <tag><em><anno>Name</anno></em></tag> + <tag><em><c><anno>Name</anno></c></em></tag> <item> <p>The name parameter is the name of the driver to be used in subsequent calls to <seealso marker="erts:erlang#open_port/2">open_port</seealso>. The @@ -678,14 +678,14 @@ with this <c><anno>Name</anno></c> parameter, much as a beam-file's module name much correspond to its filename.</p> </item> - <tag><em><anno>OptionList</anno></em></tag> + <tag><em><c><anno>OptionList</anno></c></em></tag> <item> <p>A number of options can be specified to control the loading operation. The options are given as a list of two-tuples, the tuples having the following values and meanings:</p> <taglist> - <tag><em>{driver_options, <anno>DriverOptionList</anno>}</em></tag> + <tag><em>{driver_options, <c><anno>DriverOptionList</anno></c>}</em></tag> <item> <p>This option is to provide options that will change its general behavior and will "stick" to the driver @@ -701,7 +701,7 @@ when the last <seealso marker="#users">user</seealso> calls <seealso marker="#try_unload/2">try_unload/2</seealso>, or the last process having loaded the driver exits.</p> </item> - <tag><em>{monitor, <anno>MonitorOption</anno>}</em></tag> + <tag><em>{monitor, <c><anno>MonitorOption</anno></c>}</em></tag> <item> <p>A <c><anno>MonitorOption</anno></c> tells <c>try_load/3</c> to trigger a driver monitor under certain @@ -732,7 +732,7 @@ <c>{monitor, pending_driver}</c> in production code (see the monitor discussion above). </p> </item> - <tag><em>{reload,<anno>ReloadOption</anno>}</em></tag> + <tag><em>{reload, <c><anno>ReloadOption</anno></c>}</em></tag> <item> <p>This option is used when one wants to <em>reload</em> a driver from disk, most often in a @@ -910,13 +910,13 @@ </taglist> <p>The function accepts the following parameters:</p> <taglist> - <tag><em><anno>Name</anno></em></tag> + <tag><em><c><anno>Name</anno></c></em></tag> <item> <p>The name parameter is the name of the driver to be unloaded. The name can be specified either as an <c>iolist()</c> or as an <c>atom()</c>. </p> </item> - <tag><em><anno>OptionList</anno></em></tag> + <tag><em><c><anno>OptionList</anno></c></em></tag> <item> <p>The <c><anno>OptionList</anno></c> argument can be used to specify certain behavior regarding ports as well as triggering @@ -934,7 +934,7 @@ unloads, one should use the driver option <c>kill_ports</c> when loading the driver instead.</p> </item> - <tag><em>{monitor, <anno>MonitorOption</anno>}</em></tag> + <tag><em>{monitor, <c><anno>MonitorOption</anno></c>}</em></tag> <item> <p>This option creates a driver monitor if the condition given in <c><anno>MonitorOption</anno></c> is true. The valid diff --git a/lib/kernel/doc/src/error_logger.xml b/lib/kernel/doc/src/error_logger.xml index f83fe53084..92e14c2bef 100644 --- a/lib/kernel/doc/src/error_logger.xml +++ b/lib/kernel/doc/src/error_logger.xml @@ -299,12 +299,12 @@ ok</pre> <name name="logfile" arity="1" clause_i="1"/> <name name="logfile" arity="1" clause_i="2"/> <name name="logfile" arity="1" clause_i="3"/> + <fsummary>Enable or disable error printouts to a file</fsummary> <type variable="Filename"/> <type variable="OpenReason" name_i="1"/> <type variable="CloseReason" name_i="2"/> <type variable="FilenameReason" name_i="3"/> <type name="open_error"/> - <fsummary>Enable or disable error printouts to a file</fsummary> <desc> <p>Enables or disables printout of standard events to a file.</p> <p>This is done by adding or deleting the standard event handler diff --git a/lib/kernel/doc/src/file.xml b/lib/kernel/doc/src/file.xml index 4954568086..831ef1c22a 100644 --- a/lib/kernel/doc/src/file.xml +++ b/lib/kernel/doc/src/file.xml @@ -87,9 +87,10 @@ <name name="deep_list"/> </datatype> <datatype> - <name><marker id="type-fd">fd()</marker></name> + <name>fd()</name> <desc> - <p>A file descriptor representing a file opened in <seealso + <p><marker id="type-fd"/> + A file descriptor representing a file opened in <seealso marker="#raw">raw</seealso> mode.</p> </desc> </datatype> @@ -491,7 +492,7 @@ <name name="list_dir" arity="1"/> <fsummary>List files in a directory</fsummary> <desc> - <p>Lists all files in a directory, <b>except</b> files + <p>Lists all files in a directory, <em>except</em> files with "raw" names. Returns <c>{ok, <anno>Filenames</anno>}</c> if successful. Otherwise, it returns <c>{error, <anno>Reason</anno>}</c>. @@ -1193,8 +1194,8 @@ and <c>read_line/1</c> are the only ways to read from a file opened in raw mode (although they work for normally opened files, too).</p> - <p>For files where <c>encoding</c> is set to something else than <c>latin1</c>, one character might be represented by more than one byte on the file. The parameter <c>Number</c> always denotes the number of <em>characters</em> read from the file, why the position in the file might be moved a lot more than this number when reading a Unicode file.</p> - <p>Also if <c>encoding</c> is set to something else than <c>latin1</c>, the <c>read/3</c> call will fail if the data contains characters larger than 255, why the <seealso marker="stdlib:io">io(3)</seealso> module is to be preferred when reading such a file.</p> + <p>For files where <c>encoding</c> is set to something else than <c>latin1</c>, one character might be represented by more than one byte on the file. The parameter <c>Number</c> always denotes the number of <em>characters</em> read from the file, while the position in the file might be moved much more than this number when reading a Unicode file.</p> + <p>Also, if <c>encoding</c> is set to something else than <c>latin1</c>, the <c>read/3</c> call will fail if the data contains characters larger than 255, which is why the <seealso marker="stdlib:io">io(3)</seealso> module is to be preferred when reading such a file.</p> <p>The function returns:</p> <taglist> <tag><c>{ok, <anno>Data</anno>}</c></tag> @@ -1307,15 +1308,15 @@ <item> <p>The current system access to the file.</p> </item> - <tag><c>atime = <seealso marker="#type-date_time">date_time()</seealso> | integer() >= 0</c></tag> + <tag><c>atime = </c><seealso marker="#type-date_time">date_time()</seealso><c> | integer() >= 0</c></tag> <item> <p>The last time the file was read.</p> </item> - <tag><c>mtime = <seealso marker="#type-date_time">date_time()</seealso> | integer() >= 0</c></tag> + <tag><c>mtime = </c><seealso marker="#type-date_time">date_time()</seealso><c> | integer() >= 0</c></tag> <item> <p>The last time the file was written.</p> </item> - <tag><c>ctime = <seealso marker="#type-date_time">date_time()</seealso> | integer() >=0</c></tag> + <tag><c>ctime = </c><seealso marker="#type-date_time">date_time()</seealso><c> | integer() >=0</c></tag> <item> <p>The interpretation of this time field depends on the operating system. On Unix, it is the last time @@ -1745,7 +1746,7 @@ See <seealso marker="gen_tcp#controlling_process-2">gen_tcp:controlling_process/2</seealso></p> <p>If the OS used does not support sendfile, an Erlang fallback using file:read and gen_tcp:send is used.</p> - <p>The option list can contain the following options: + <p>The option list can contain the following options:</p> <taglist> <tag><c>chunk_size</c></tag> <item>The chunk size used by the erlang fallback to send @@ -1760,7 +1761,6 @@ the sendfile call will return <c>{error,einval}</c>. Introduced in Erlang/OTP 17.0. Default is false.</item> </taglist> - </p> </desc> </func> <func> @@ -1851,22 +1851,21 @@ Type <c>local</c> will interpret the time set as local, <c>universal</c> will interpret it as universal time and <c>posix</c> must be seconds since or before unix time epoch which is 1970-01-01 00:00 UTC. - Default is <c>{time, local}</c>. + Default is <c>{time, local}</c>.</p> <p>If the <c>raw</c> option is set, the file server will not be called and only informations about local files will be returned.</p> - </p> <p>The following fields are used from the record, if they are given.</p> <taglist> - <tag><c>atime = <seealso marker="#type-date_time">date_time()</seealso> | integer() >= 0</c></tag> + <tag><c>atime = </c><seealso marker="#type-date_time">date_time()</seealso><c> | integer() >= 0</c></tag> <item> <p>The last time the file was read.</p> </item> - <tag><c>mtime = <seealso marker="#type-date_time">date_time()</seealso> | integer() >= 0</c></tag> + <tag><c>mtime = </c><seealso marker="#type-date_time">date_time()</seealso><c> | integer() >= 0</c></tag> <item> <p>The last time the file was written.</p> </item> - <tag><c>ctime = <seealso marker="#type-date_time">date_time()</seealso> | integer() >= 0</c></tag> + <tag><c>ctime = </c><seealso marker="#type-date_time">date_time()</seealso><c> | integer() >= 0</c></tag> <item> <p>On Unix, any value give for this field will be ignored (the "ctime" for the file will be set to the current diff --git a/lib/kernel/doc/src/gen_sctp.xml b/lib/kernel/doc/src/gen_sctp.xml index b704d90613..456108a2fe 100644 --- a/lib/kernel/doc/src/gen_sctp.xml +++ b/lib/kernel/doc/src/gen_sctp.xml @@ -77,9 +77,10 @@ <datatypes> <datatype> - <name><marker id="type-assoc_id">assoc_id()</marker></name> + <name>assoc_id()</name> <desc> - <p>An opaque term returned in for example #sctp_paddr_change{} + <p><marker id="type-assoc_id"/> + An opaque term returned in for example #sctp_paddr_change{} that identifies an association for an SCTP socket. The term is opaque except for the special value <c>0</c> that has a meaning such as "the whole endpoint" or "all future associations". @@ -98,9 +99,10 @@ <desc><marker id="type-sctp_socket"></marker></desc> </datatype> <datatype> - <name><marker id="type-sctp_socket">sctp_socket()</marker></name> + <name>sctp_socket()</name> <desc> - <p>Socket identifier returned from <c>open/*</c>.</p> + <p><marker id="type-sctp_socket"/> + Socket identifier returned from <c>open/*</c>.</p> <marker id="exports"></marker> </desc> </datatype> @@ -146,7 +148,7 @@ <c><anno>Addr</anno></c> and <c><anno>Port</anno></c>. The <c><anno>Timeout</anno></c>, is expressed in milliseconds. A socket can be associated with multiple peers.</p> - <p><b>WARNING:</b>Using a value of <c><anno>Timeout</anno></c> less than + <p><em>WARNING:</em>Using a value of <c><anno>Timeout</anno></c> less than the maximum time taken by the OS to establish an association (around 4.5 minutes if the default values from RFC 4960 are used) can result in inconsistent or incorrect return values. This is especially @@ -170,7 +172,7 @@ <p>The number of outbound and inbound streams can be set by giving an <c>sctp_initmsg</c> option to <c>connect</c> as in:</p> -<pre> connect(<anno>Socket</anno>, Ip, <anno>Port</anno>, +<pre> connect(Socket, Ip, Port>, [{sctp_initmsg,#sctp_initmsg{num_ostreams=OutStreams, max_instreams=MaxInStreams}}]) </pre> <p>All options <c><anno>Opt</anno></c> are set on the socket before the diff --git a/lib/kernel/doc/src/gen_tcp.xml b/lib/kernel/doc/src/gen_tcp.xml index 8d9f09cea7..6a19e76c4f 100644 --- a/lib/kernel/doc/src/gen_tcp.xml +++ b/lib/kernel/doc/src/gen_tcp.xml @@ -78,9 +78,10 @@ do_recv(Sock, Bs) -> <name name="listen_option"/> </datatype> <datatype> - <name><marker id="type-socket">socket()</marker></name> + <name>socket()</name> <desc> - <p>As returned by accept/1,2 and connect/3,4.</p> + <p><marker id="type-socket"/> + As returned by accept/1,2 and connect/3,4.</p> <marker id="connect"></marker> </desc> </datatype> diff --git a/lib/kernel/doc/src/gen_udp.xml b/lib/kernel/doc/src/gen_udp.xml index 6f34aba43c..79cd87dcef 100644 --- a/lib/kernel/doc/src/gen_udp.xml +++ b/lib/kernel/doc/src/gen_udp.xml @@ -43,9 +43,9 @@ <name name="option_name"/> </datatype> <datatype> - <name><marker id="type-socket">socket()</marker></name> + <name>socket()</name> <desc> - <p>As returned by open/1,2.</p> + <p><marker id="type-socket"/>As returned by open/1,2.</p> </desc> </datatype> </datatypes> diff --git a/lib/kernel/doc/src/heart.xml b/lib/kernel/doc/src/heart.xml index b9fad17ce1..9da4773f2d 100644 --- a/lib/kernel/doc/src/heart.xml +++ b/lib/kernel/doc/src/heart.xml @@ -118,6 +118,13 @@ <p>In the following descriptions, all function fails with reason <c>badarg</c> if <c>heart</c> is not started.</p> </description> + + <datatypes> + <datatype> + <name name="heart_option"/> + </datatype> + </datatypes> + <funcs> <func> <name name="set_cmd" arity="1"/> @@ -154,6 +161,62 @@ the empty string will be returned.</p> </desc> </func> + + <func> + <name name="set_callback" arity="2"/> + <fsummary>Set a validation callback</fsummary> + <desc> + <p> This validation callback will be executed before any heartbeat sent + to the port program. For the validation to succeed it needs to return + with the value <c>ok</c>. + </p> + <p> An exception within the callback will be treated as a validation failure. </p> + <p> The callback will be removed if the system reboots. </p> + </desc> + </func> + <func> + <name name="clear_callback" arity="0"/> + <fsummary>Clear the validation callback</fsummary> + <desc> + <p>Removes the validation callback call before heartbeats.</p> + </desc> + </func> + <func> + <name name="get_callback" arity="0"/> + <fsummary>Get the validation callback</fsummary> + <desc> + <p>Get the validation callback. If the callback is cleared, <c>none</c> will be returned.</p> + </desc> + </func> + + <func> + <name name="set_options" arity="1"/> + <fsummary>Set a list of options</fsummary> + <desc> + <p> Valid options <c>set_options</c> are: </p> + <taglist> + <tag><c>check_schedulers</c></tag> + <item> + <p>If enabled, a signal will be sent to each scheduler to check its + responsiveness. The system check occurs before any heartbeat sent + to the port program. If any scheduler is not responsive enough the + heart program will not receive its heartbeat and thus eventually terminate the node. + </p> + </item> + </taglist> + <p> Returns with the value <c>ok</c> if the options are valid.</p> + </desc> + </func> + <func> + <name name="get_options" arity="0"/> + <fsummary>Get the temporary reboot command</fsummary> + <desc> + <p>Returns <c>{ok, Options}</c> where <c>Options</c> is a list of current options enabled for heart. + If the callback is cleared, <c>none</c> will be returned.</p> + </desc> + </func> + + </funcs> </erlref> diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml index e5d7ce048a..088d78c1d6 100644 --- a/lib/kernel/doc/src/inet.xml +++ b/lib/kernel/doc/src/inet.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1997</year><year>2013</year> + <year>1997</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -117,8 +117,9 @@ fe80::204:acff:fe17:bf38 </desc> </datatype> <datatype> - <name><marker id="type-socket">socket()</marker></name> - <desc><p>See <seealso marker="gen_tcp#type-socket">gen_tcp(3)</seealso> + <name>socket()</name> + <desc><p><marker id="type-socket"></marker> + See <seealso marker="gen_tcp#type-socket">gen_tcp(3)</seealso> and <seealso marker="gen_udp#type-socket">gen_udp(3)</seealso>.</p> </desc> </datatype> @@ -222,7 +223,7 @@ fe80::204:acff:fe17:bf38 </p> <p> Do not rely too much on the order of <c><anno>Flag</anno></c> atoms or - <c><anno>Ifopt</anno></c> tuples. There are some rules, though: + <c><anno>Ifopt</anno></c> tuples. There are some rules, though:</p> <list> <item> Immediately after <c>{addr,_}</c> follows <c>{netmask,_}</c> @@ -238,7 +239,6 @@ fe80::204:acff:fe17:bf38 tuple concerns that address. </item> </list> - </p> <p> The <c>{hwaddr,_}</c> tuple is not returned on Solaris since the hardware address historically belongs to the link layer and only @@ -379,14 +379,14 @@ fe80::204:acff:fe17:bf38 <name name="ntoa" arity="1" /> <fsummary>Convert IPv6 / IPV4 adress to ascii</fsummary> <desc> - <p>Parses an <a href="#type-ip_address">ip_address()</a> and returns an IPv4 or IPv6 address string.</p> + <p>Parses an <seealso marker="#type-ip_address">ip_address()</seealso> and returns an IPv4 or IPv6 address string.</p> </desc> </func> <func> <name name="parse_ipv4_address" arity="1" /> <fsummary>Parse an IPv4 address</fsummary> <desc> - <p>Parses an IPv4 address string and returns an <a href="#type-ip4_address">ip4_address()</a>. + <p>Parses an IPv4 address string and returns an <seealso marker="#type-ip4_address">ip4_address()</seealso>. Accepts a shortened IPv4 shortened address string.</p> </desc> </func> @@ -394,14 +394,14 @@ fe80::204:acff:fe17:bf38 <name name="parse_ipv4strict_address" arity="1" /> <fsummary>Parse an IPv4 address strict.</fsummary> <desc> - <p>Parses an IPv4 address string containing four fields, i.e <b>not</b> shortened, and returns an <a href="#type-ip4_adress">ip4_address()</a>.</p> + <p>Parses an IPv4 address string containing four fields, i.e <em>not</em> shortened, and returns an <seealso marker="#type-ip4_address">ip4_address()</seealso>.</p> </desc> </func> <func> <name name="parse_ipv6_address" arity="1" /> <fsummary>Parse an IPv6 address</fsummary> <desc> - <p>Parses an IPv6 address string and returns an <a href="#type-ip6_address">ip6_address()</a>. + <p>Parses an IPv6 address string and returns an <seealso marker="#type-ip6_address">ip6_address()</seealso>. If an IPv4 address string is passed, an IPv4-mapped IPv6 address is returned.</p> </desc> </func> @@ -409,22 +409,22 @@ fe80::204:acff:fe17:bf38 <name name="parse_ipv6strict_address" arity="1" /> <fsummary>Parse an IPv6 address strict.</fsummary> <desc> - <p>Parses an IPv6 address string and returns an <a href="#type-ip6_address">ip6_address()</a>. - Does <b>not</b> accept IPv4 adresses.</p> + <p>Parses an IPv6 address string and returns an <seealso marker="#type-ip6_address">ip6_address()</seealso>. + Does <em>not</em> accept IPv4 adresses.</p> </desc> </func> <func> <name name="parse_address" arity="1" /> <fsummary>Parse an IPv4 or IPv6 address.</fsummary> <desc> - <p>Parses an IPv4 or IPv6 address string and returns an <a href="#type-ip4_address">ip4_address()</a> or <a href="#type-ip6_address">ip6_address()</a>. Accepts a shortened IPv4 address string.</p> + <p>Parses an IPv4 or IPv6 address string and returns an <seealso marker="#type-ip4_address">ip4_address()</seealso> or <seealso marker="#type-ip6_address">ip6_address()</seealso>. Accepts a shortened IPv4 address string.</p> </desc> </func> <func> <name name="parse_strict_address" arity="1" /> <fsummary>Parse an IPv4 or IPv6 address strict.</fsummary> <desc> - <p>Parses an IPv4 or IPv6 address string and returns an <a href="#type-ip4_address">ip4_address()</a> or <a href="#type-ip6_adress">ip6_address()</a>. Does <b>not</b> accept a shortened IPv4 address string.</p> + <p>Parses an IPv4 or IPv6 address string and returns an <seealso marker="#type-ip4_address">ip4_address()</seealso> or <seealso marker="#type-ip6_address">ip6_address()</seealso>. Does <em>not</em> accept a shortened IPv4 address string.</p> </desc> </func> <func> @@ -862,10 +862,10 @@ fe80::204:acff:fe17:bf38 <c>CAP_SYS_ADMIN</c> according to the documentation for setns(2). However, during testing also <c>CAP_SYS_PTRACE</c> and <c>CAP_DAC_READ_SEARCH</c> has proven to be necessary. - Example:<code> + Example:</p><code> setcap cap_sys_admin,cap_sys_ptrace,cap_dac_read_search+epi beam.smp </code> - Note also that the filesystem containing the virtual machine + <p>Note also that the filesystem containing the virtual machine executable (<c>beam.smp</c> in the example above) has to be local, mounted without the <c>nosetuid</c> flag, support extended attributes and that @@ -981,6 +981,11 @@ setcap cap_sys_admin,cap_sys_ptrace,cap_dac_read_search+epi beam.smp indicated length are accepted and not considered invalid due to internal buffer limitations.</p> </item> + <tag><c>{line_delimiter, Char}</c>(TCP/IP sockets)</tag> + <item> + <p>Sets the line delimiting character for line oriented protocols + (<c>line</c>). Default value is <c>$\n</c>.</p> + </item> <tag><c>{priority, Priority}</c></tag> <item> <p>Set the protocol-defined priority for all packets to be sent diff --git a/lib/kernel/doc/src/inet_res.xml b/lib/kernel/doc/src/inet_res.xml index 6a2c9b1955..851a36aba9 100644 --- a/lib/kernel/doc/src/inet_res.xml +++ b/lib/kernel/doc/src/inet_res.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2009</year><year>2013</year> + <year>2009</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -77,8 +77,11 @@ query is tried for the <c>alt_nameservers</c>.</p> </section> + <section> + <title>Resolver Types</title> + <p>The following data types concern the resolver:</p> + </section> <datatypes> - <p>Resolver types:</p> <datatype> <name name="res_option"/> </datatype> @@ -88,8 +91,13 @@ <datatype> <name name="res_error"/> </datatype> - - <p><marker id="dns_types"/>DNS types:</p> + </datatypes> + <section> + <title>DNS Types</title> + <p><marker id="dns_types"/> + The following data types concern the DNS client:</p> + </section> + <datatypes> <datatype> <name name="dns_name"/> <desc><p>A string with no adjacent dots.</p></desc> @@ -106,7 +114,7 @@ <p>This is the start of a hiearchy of opaque data structures that can be examined with access functions in inet_dns that return lists of {Field,Value} tuples. The arity 2 functions - just return the value for a given field. + just return the value for a given field.</p> <pre> dns_msg() = DnsMsg inet_dns:msg(DnsMsg) -> @@ -154,18 +162,19 @@ dns_rr() = DnsRr | {version, integer()} | {z, integer()} | {data, dns_data()} ] - inet_dns:rr(DnsRr, Field) -> Value + inet_dns:rr(DnsRr, Field) -> Value</pre> -There is an info function for the types above: +<p>There is an info function for the types above:</p> +<pre> inet_dns:record_type(dns_msg()) -> msg; inet_dns:record_type(dns_header()) -> header; inet_dns:record_type(dns_query()) -> dns_query; inet_dns:record_type(dns_rr()) -> rr; -inet_dns:record_type(_) -> undefined. +inet_dns:record_type(_) -> undefined.</pre> -So; inet_dns:(inet_dns:record_type(X))(X) will convert -any of these data structures into a {Field,Value} list.</pre></p> +<p>So; inet_dns:(inet_dns:record_type(X))(X) will convert +any of these data structures into a {Field,Value} list.</p> </desc> </datatype> <datatype> @@ -272,7 +281,7 @@ any of these data structures into a {Field,Value} list.</pre></p> <p>Resolve a DNS record of the given type and class for the given name. The returned <c>dns_msg()</c> can be examined using access functions in <c>inet_db</c> as described - in <seealso marker="#dns_types">DNS types</seealso>. + in <seealso marker="#dns_types">DNS Types</seealso>. </p><p> If <c><anno>Name</anno></c> is an <c>ip_address()</c>, the domain name to query for is generated as the standard reverse diff --git a/lib/kernel/doc/src/kernel_app.xml b/lib/kernel/doc/src/kernel_app.xml index 2cea38bae9..956c57f7c1 100644 --- a/lib/kernel/doc/src/kernel_app.xml +++ b/lib/kernel/doc/src/kernel_app.xml @@ -43,6 +43,7 @@ <item><c>erl_boot_server</c></item> <item><c>erl_ddll</c></item> <item><c>error_logger</c></item> + <item><c>error_logger_format_depth</c></item> <item><c>file</c></item> <item><c>global</c></item> <item><c>global_group</c></item> @@ -152,6 +153,42 @@ </item> </taglist> </item> + <tag><c>error_logger_format_depth = Depth</c></tag> + <item> + <marker id="error_logger_format_depth"></marker> + <p>This parameter can be used to limit the size of the + formatted output from the error logger event handlers.</p> + + <note><p>This configuration parameter was introduced in OTP 18.1. + It is currently experimental. Based on user feedback it + may be changed or improved in future releases, for example + to gain better control over how to limit the size of the + formatted output. We have no plans to entirely remove this + new feature, unless it turns out to be completely + useless. In OTP 19, the default may be changed to limit the + formatted output.</p></note> + + <p><c>Depth</c> is a positive integer that is the maximum + depth to which terms are printed by the error logger event + handlers included in OTP. Specifically, the two event handlers + defined by the <c>Kernel</c> application and the two event + handlers in the <c>SASL</c> application will use this + configuration parameter. (If you have implemented you own + error handlers, this configuration parameter will have no + effect on them.)</p> + + <p>The way <c>Depth</c> is used, is that format strings + string passed to the event handlers will be rewritten. + The "~p" and "~w" format controls will be replaced with + "~P" and "~W", respectively, and <c>Depth</c> will be + used as the depth parameter. See + <seealso marker="stdlib:io#format/2">io:format/2</seealso>.</p> + + <note><p>A reasonable starting value for <c>Depth</c> is + <c>30</c>. You should test crashing various processes in your + application and examine the logs from the crashes, and then + either increase or decrease the value.</p></note> + </item> <tag><c>global_groups = [GroupTuple]</c></tag> <item> <p>Defines global groups, see diff --git a/lib/kernel/doc/src/net_adm.xml b/lib/kernel/doc/src/net_adm.xml index 1072be44a5..4ef9d361f6 100644 --- a/lib/kernel/doc/src/net_adm.xml +++ b/lib/kernel/doc/src/net_adm.xml @@ -89,8 +89,8 @@ <func> <name name="world" arity="0"/> <name name="world" arity="1"/> - <type name="verbosity"/> <fsummary>Lookup and connect to all nodes at all hosts in <c>.hosts.erlang</c></fsummary> + <type name="verbosity"/> <desc> <p>This function calls <c>names(Host)</c> for all hosts which are specified in the Erlang host file <c>.hosts.erlang</c>, @@ -110,8 +110,8 @@ <func> <name name="world_list" arity="1"/> <name name="world_list" arity="2"/> - <type name="verbosity"/> <fsummary>Lookup and connect to all nodes at specified hosts</fsummary> + <type name="verbosity"/> <desc> <p>As <c>world/0,1</c>, but the hosts are given as argument instead of being read from <c>.hosts.erlang</c>.</p> diff --git a/lib/kernel/doc/src/net_kernel.xml b/lib/kernel/doc/src/net_kernel.xml index a0132db8db..311e0d8ea4 100644 --- a/lib/kernel/doc/src/net_kernel.xml +++ b/lib/kernel/doc/src/net_kernel.xml @@ -63,11 +63,16 @@ <funcs> <func> <name name="allow" arity="1"/> - <fsummary>Limit access to a specified set of nodes</fsummary> + <fsummary>Permit access to a specified set of nodes</fsummary> <desc> - <p>Limits access to the specified set of nodes. Any access - attempts made from (or to) nodes not in <c><anno>Nodes</anno></c> will be - rejected.</p> + <p>Permits access to the specified set of nodes.</p> + <p>Before the first call to <c>allow/1</c>, any node with the correct + cookie can be connected. When <c>allow/1</c> is called, a list + of allowed nodes is established. Any access attempts made from (or to) + nodes not in that list will be rejected.</p> + <p>Subsequent calls to <c>allow/1</c> will add the specified nodes + to the list of allowed nodes. It is not possible to remove nodes + from the list.</p> <p>Returns <c>error</c> if any element in <c><anno>Nodes</anno></c> is not an atom.</p> </desc> diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml index b8db22aba7..cf5777d4be 100644 --- a/lib/kernel/doc/src/notes.xml +++ b/lib/kernel/doc/src/notes.xml @@ -31,6 +31,190 @@ </header> <p>This document describes the changes made to the Kernel application.</p> +<section><title>Kernel 4.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p><c>code:load_abs([10100])</c> would bring down the + entire runtime system and create a crash dump. Corrected + to generate an error exception in the calling + process.</p> + <p>Also corrected specs for code loading functions and + added more information in the documentation about the + error reasons returned by code-loading functions.</p> + <p> + Own Id: OTP-9375</p> + </item> + <item> + <p> + <seealso + marker="kernel:gen_tcp#accept/2"><c>gen_tcp:accept/2</c></seealso> + was not <seealso + marker="erts:time_correction#Time_Warp_Safe_Code">time + warp safe</seealso>. This since it used the same time as + returned by <seealso + marker="erts:erlang#now/0"><c>erlang:now/0</c></seealso> + when calculating timeout. This has now been fixed.</p> + <p> + Own Id: OTP-13254 Aux Id: OTP-11997, OTP-13222 </p> + </item> + <item> + <p> Correct the contract for <c>inet:getifaddrs/1</c>. + </p> + <p> + Own Id: OTP-13335 Aux Id: ERL-95 </p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Time warp safety improvements.</p> + <p> + Introduced the options <c>monotonic_timestamp</c>, and + <c>strict_monotonic_timestamp</c> to the trace, + sequential trace, and system profile functionality. This + since the already existing <c>timestamp</c> option is not + time warp safe.</p> + <p> + Introduced the option <c>safe_fixed_monotonic_time</c> to + <c>ets:info/2</c> and <c>dets:info/2</c>. This since the + already existing <c>safe_fixed</c> option is not time + warp safe.</p> + <p> + Own Id: OTP-13222 Aux Id: OTP-11997 </p> + </item> + <item> + <p> + Add validation callback for heart</p> + <p> + The erlang heart process may now have a validation + callback installed. The validation callback will be + executed, if present, before any heartbeat to heart port + program. If the validation fails, or stalls, no heartbeat + will be sent and the node will go down.</p> + <p> + With the option <c>'check_schedulers'</c> heart executes + a responsiveness check of the schedulers before a + heartbeat is sent to the port program. If the + responsiveness check fails, the heartbeat will not be + performed (as intended).</p> + <p> + Own Id: OTP-13250</p> + </item> + <item> + <p> + Clarify documentation of <c>net_kernel:allow/1</c></p> + <p> + Own Id: OTP-13299</p> + </item> + <item> + <p> + EPMD supports both IPv4 and IPv6</p> + <p> + Also affects oldest supported windows version.</p> + <p> + Own Id: OTP-13364</p> + </item> + </list> + </section> + +</section> + +<section><title>Kernel 4.1.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Host name lookups though inet_res, the Erlang DNS + resolver, are now done case insensitively according to + RFC 4343. Patch by Holger Weiß.</p> + <p> + Own Id: OTP-12836</p> + </item> + <item> + <p> + IPv6 distribution handler has been updated to share code + with IPv4 so that all features are supported in IPv6 as + well. A bug when using an IPv4 address as hostname has + been fixed.</p> + <p> + Own Id: OTP-13040</p> + </item> + <item> + <p> + Caching of host names in the internal DNS resolver + inet_res has been made character case insensitive for + host names according to RFC 4343.</p> + <p> + Own Id: OTP-13083</p> + </item> + <item> + <p>Cooked file mode buffering has been fixed so + file:position/2 now works according to Posix on Posix + systems i.e. when file:position/2 returns an error the + file pointer is unaffected.</p> <p>The Windows system + documentation, however, is unclear on this point so the + documentation of file:position/2 still does not promise + anything.</p> <p>Cooked file mode file:pread/2,3 and + file:pwrite/2,3 have been corrected to honor character + encoding like the combination of file:position/2 and + file:read/2 or file:write/2 already does. This is + probably not very useful since the character + representation on the caller's side is latin1, + period.</p> + <p> + Own Id: OTP-13155 Aux Id: PR#646 </p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Add {line_delim, byte()} option to inet:setopts/2 and + decode_packet/3</p> + <p> + Own Id: OTP-12837</p> + </item> + </list> + </section> + +</section> + +<section><title>Kernel 4.1</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>A mechanism for limiting the amount of text that the + built-in error logger events will produce has been + introduced. It is useful for limiting both the size of + log files and the CPU time used to produce them.</p> + <p>This mechanism is experimental in the sense that it + may be changed if it turns out that it does not solve the + problem it is supposed to solve. In that case, there may + be backward incompatible improvements to this + mechanism.</p> + <p>See the documentation for the config parameter + <c>error_logger_format_depth</c> in the Kernel + application for information about how to turn on this + feature.</p> + <p> + Own Id: OTP-12864</p> + </item> + </list> + </section> + +</section> + <section><title>Kernel 4.0</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -159,6 +343,22 @@ </section> +<section><title>Kernel 3.2.0.1</title> + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>The 'raw' socket option could not be used multiple times + in one call to any e.g gen_tcp function because only one + of the occurrences were used. This bug has been fixed, + and also a small bug concerning propagating error codes + from within inet:setopts/2.</p> + <p>Own Id: OTP-11482 Aux Id: seq12872 </p> + </item> + </list> + </section> + </section> + + <section><title>Kernel 3.2</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -1192,7 +1392,7 @@ </item> <item> <p> Fix returned error from gen_tcp:accept/1,2 when - running out of ports + running out of ports.</p> <p> The {error, enfile} return value is badly misleading and confusing for this case, since the Posix ENFILE errno @@ -1201,7 +1401,7 @@ {error, system_limit}, which is consistent with e.g. various file(3) functions. inet:format_error/1 has also been updated to support system_limit in the same manner - as file:format_error/1. (Thanks to Per Hedeland)</p></p> + as file:format_error/1. (Thanks to Per Hedeland)</p> <p> Own Id: OTP-9990</p> </item> @@ -1396,7 +1596,6 @@ Own Id: OTP-9764</p> </item> <item> - <p> <list> <item><p>Correct callback spec in application module</p></item> <item><p>Refine warning about callback specs with extra ranges</p></item> <item><p>Cleanup @@ -1407,7 +1606,7 @@ analysis</p></item> <item><p>Fix crash in Dialyzer</p></item> <item><p>Variable substitution was not generalizing any unknown variables.</p></item> - </list></p> + </list> <p> Own Id: OTP-9776</p> </item> diff --git a/lib/kernel/doc/src/os.xml b/lib/kernel/doc/src/os.xml index 2d2a690fea..682d4a2eac 100644 --- a/lib/kernel/doc/src/os.xml +++ b/lib/kernel/doc/src/os.xml @@ -171,8 +171,8 @@ DirOut = os:cmd("dir"), % on Win32 platform</code> </func> <func> <name name="timestamp" arity="0"/> - <type_desc variable="Timestamp">Timestamp = {MegaSecs, Secs, MicroSecs}</type_desc> <fsummary>Current OS system time on the erlang:timestamp/0 format</fsummary> + <type_desc variable="Timestamp">Timestamp = {MegaSecs, Secs, MicroSecs}</type_desc> <desc> <p>Returns current <seealso marker="erts:time_correction#OS_System_Time">OS system time</seealso> @@ -205,7 +205,7 @@ format_utc_timestamp() -> 29 Apr 2009 9:55:30.051711 </pre> <p>OS system time can also be retreived by - <c><seealso marker="#system_time/0"><c>os:system_time/0</c></seealso></c>, + <seealso marker="#system_time/0"><c>os:system_time/0</c></seealso>, and <seealso marker="#system_time/1"><c>os:system_time/1</c></seealso>.</p> </desc> </func> diff --git a/lib/kernel/doc/src/seq_trace.xml b/lib/kernel/doc/src/seq_trace.xml index 3439111035..f4fcd222ec 100644 --- a/lib/kernel/doc/src/seq_trace.xml +++ b/lib/kernel/doc/src/seq_trace.xml @@ -127,6 +127,35 @@ seq_trace:set_token(OldToken), % activate the trace token again enables/disables a timestamp to be generated for each traced event. Default is <c>false</c>.</p> </item> + <tag><c>set_token(strict_monotonic_timestamp, <anno>Bool</anno>)</c></tag> + <item> + <p>A trace token flag (<c>true | false</c>) which + enables/disables a strict monotonic timestamp to be generated + for each traced event. Default is <c>false</c>. Timestamps will + consist of + <seealso marker="erts:time_correction#Erlang_Monotonic_Time">Erlang + monotonic time</seealso> and a monotonically increasing + integer. The time-stamp has the same format and value + as produced by <c>{erlang:monotonic_time(nano_seconds), + erlang:unique_integer([monotonic])}</c>.</p> + </item> + <tag><c>set_token(monotonic_timestamp, <anno>Bool</anno>)</c></tag> + <item> + <p>A trace token flag (<c>true | false</c>) which + enables/disables a strict monotonic timestamp to be generated + for each traced event. Default is <c>false</c>. Timestamps + will use + <seealso marker="erts:time_correction#Erlang_Monotonic_Time">Erlang + monotonic time</seealso>. The time-stamp has the same + format and value as produced by + <c>erlang:monotonic_time(nano_seconds)</c>.</p> + </item> + <p>If multiple timestamp flags are passed, <c>timestamp</c> has + precedence over <c>strict_monotonic_timestamp</c> which + in turn has precedence over <c>monotonic_timestamp</c>. All + timestamp flags are remembered, so if two are passed + and the one with highest precedence later is disabled + the other one will become active.</p> </taglist> </desc> </func> diff --git a/lib/kernel/examples/uds_dist/c_src/uds_drv.c b/lib/kernel/examples/uds_dist/c_src/uds_drv.c index e32ad69adf..8c028ba910 100644 --- a/lib/kernel/examples/uds_dist/c_src/uds_drv.c +++ b/lib/kernel/examples/uds_dist/c_src/uds_drv.c @@ -957,28 +957,24 @@ static void put_packet_length(char *b, int len) /* ** Malloc wrappers -** Note! -** The function erl_exit is actually not a pert of the -** driver interface, but it is very nice to use if one wants to halt -** with a core and an erlang crash dump. */ static void *my_malloc(size_t size) { - void erl_exit(int, char *, ...); void *ptr; if ((ptr = driver_alloc(size)) == NULL) { - erl_exit(1,"Could not allocate %lu bytes of memory",(unsigned long) size); + fprintf(stderr, "Could not allocate %lu bytes of memory",(unsigned long) size); + abort(); } return ptr; } static void *my_realloc(void *ptr, size_t size) { - void erl_exit(int, char *, ...); void *nptr; if ((nptr = driver_realloc(ptr, size)) == NULL) { - erl_exit(1,"Could not reallocate %lu bytes of memory",(unsigned long) size); + fprintf(stderr, "Could not reallocate %lu bytes of memory",(unsigned long) size); + abort(); } return nptr; } diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl index 352c02562b..7237550786 100644 --- a/lib/kernel/src/code.erl +++ b/lib/kernel/src/code.erl @@ -77,10 +77,9 @@ %%---------------------------------------------------------------------------- -type load_error_rsn() :: 'badfile' - | 'native_code' | 'nofile' | 'not_purged' - | 'on_load' + | 'on_load_failure' | 'sticky_directory'. -type load_ret() :: {'error', What :: load_error_rsn()} | {'module', Module :: module()}. @@ -135,14 +134,16 @@ load_file(Mod) when is_atom(Mod) -> -spec ensure_loaded(Module) -> {module, Module} | {error, What} when Module :: module(), - What :: embedded | badfile | native_code | nofile | on_load. + What :: embedded | badfile | nofile | on_load_failure. ensure_loaded(Mod) when is_atom(Mod) -> call({ensure_loaded,Mod}). %% XXX File as an atom is allowed only for backwards compatibility. -spec load_abs(Filename) -> load_ret() when Filename :: file:filename(). -load_abs(File) when is_list(File); is_atom(File) -> call({load_abs,File,[]}). +load_abs(File) when is_list(File); is_atom(File) -> + Mod = list_to_atom(filename:basename(File)), + call({load_abs,File,Mod}). %% XXX Filename is also an atom(), e.g. 'cover_compiled' -spec load_abs(Filename :: loaded_filename(), Module :: module()) -> load_ret(). diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl index e461c95d19..614219794c 100644 --- a/lib/kernel/src/code_server.erl +++ b/lib/kernel/src/code_server.erl @@ -313,7 +313,7 @@ handle_call(get_path, {_From,_Tag}, S) -> {reply,S#state.path,S}; %% Messages to load, delete and purge modules/files. -handle_call({load_abs,File,Mod}, Caller, S) -> +handle_call({load_abs,File,Mod}, Caller, S) when is_atom(Mod) -> case modp(File) of false -> {reply,{error,badarg},S}; @@ -1222,15 +1222,10 @@ modp(Atom) when is_atom(Atom) -> true; modp(List) when is_list(List) -> int_list(List); modp(_) -> false. -load_abs(File, Mod0, Caller, St) -> +load_abs(File, Mod, Caller, St) -> Ext = objfile_extension(), FileName0 = lists:concat([File, Ext]), FileName = absname(FileName0), - Mod = if Mod0 =:= [] -> - list_to_atom(filename:basename(FileName0, Ext)); - true -> - Mod0 - end, case erl_prim_loader:get_file(FileName) of {ok,Bin,_} -> try_load_module(FileName, Mod, Bin, Caller, St); diff --git a/lib/kernel/src/disk_log_1.erl b/lib/kernel/src/disk_log_1.erl index 9b9fd086f1..2e61363aa6 100644 --- a/lib/kernel/src/disk_log_1.erl +++ b/lib/kernel/src/disk_log_1.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2013. All Rights Reserved. +%% Copyright Ericsson AB 1997-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -79,6 +79,7 @@ log(FdC, FileName, X) -> logl(X) -> logl(X, [], 0). +-dialyzer({no_improper_lists, logl/3}). logl([X | T], Bs, Size) -> Sz = byte_size(X), BSz = <<Sz:?SIZESZ/unit:8>>, @@ -1142,6 +1143,7 @@ write_index_file(read_write, FName, NewFile, OldFile, OldCnt) -> file_error(FileName, E) end. +-dialyzer({no_improper_lists, to_8_bytes/4}). to_8_bytes(<<N:32,T/binary>>, NT, FileName, Fd) -> to_8_bytes(T, [NT | <<N:64>>], FileName, Fd); to_8_bytes(B, NT, _FileName, _Fd) when byte_size(B) =:= 0 -> @@ -1276,6 +1278,7 @@ ext_split_bins(CurB, MaxB, FirstPos, Bins) -> MaxBs = MaxB - CurB, IsFirst = CurB =:= FirstPos, ext_split_bins(MaxBs, IsFirst, [], Bins, 0, 0). +-dialyzer({no_improper_lists, ext_split_bins/6}). ext_split_bins(MaxBs, IsFirst, First, [X | Last], Bs, N) -> NBs = Bs + byte_size(X), if @@ -1296,6 +1299,7 @@ int_split_bins(CurB, MaxB, FirstPos, Bins) -> MaxBs = MaxB - CurB, IsFirst = CurB =:= FirstPos, int_split_bins(MaxBs, IsFirst, [], Bins, 0, 0). +-dialyzer({no_improper_lists, int_split_bins/6}). int_split_bins(MaxBs, IsFirst, First, [X | Last], Bs, N) -> Sz = byte_size(X), NBs = Bs + Sz + ?HEADERSZ, diff --git a/lib/kernel/src/erl_epmd.erl b/lib/kernel/src/erl_epmd.erl index 55ce9a7e64..c6202dd796 100644 --- a/lib/kernel/src/erl_epmd.erl +++ b/lib/kernel/src/erl_epmd.erl @@ -32,7 +32,7 @@ %% External exports -export([start/0, start_link/0, stop/0, port_please/2, port_please/3, names/0, names/1, - register_node/2, open/0, open/1, open/2]). + register_node/2, register_node/3, open/0, open/1, open/2]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, @@ -102,7 +102,9 @@ names(EpmdAddr) -> register_node(Name, PortNo) -> - gen_server:call(erl_epmd, {register, Name, PortNo}, infinity). + register_node(Name, PortNo, inet). +register_node(Name, PortNo, Family) -> + gen_server:call(erl_epmd, {register, Name, PortNo, Family}, infinity). %%%---------------------------------------------------------------------- %%% Callback functions from gen_server @@ -120,10 +122,10 @@ init(_) -> -spec handle_call(calls(), term(), state()) -> {'reply', term(), state()} | {'stop', 'shutdown', 'ok', state()}. -handle_call({register, Name, PortNo}, _From, State) -> +handle_call({register, Name, PortNo, Family}, _From, State) -> case State#state.socket of P when P < 0 -> - case do_register_node(Name, PortNo) of + case do_register_node(Name, PortNo, Family) of {alive, Socket, Creation} -> S = State#state{socket = Socket, port_no = PortNo, @@ -206,8 +208,12 @@ open({A,B,C,D,E,F,G,H}=EpmdAddr, Timeout) when ?ip6(A,B,C,D,E,F,G,H) -> close(Socket) -> gen_tcp:close(Socket). -do_register_node(NodeName, TcpPort) -> - case open() of +do_register_node(NodeName, TcpPort, Family) -> + Localhost = case Family of + inet -> open({127,0,0,1}); + inet6 -> open({0,0,0,0,0,0,0,1}) + end, + case Localhost of {ok, Socket} -> Name = to_string(NodeName), Extra = "", diff --git a/lib/kernel/src/file_io_server.erl b/lib/kernel/src/file_io_server.erl index bf8b9e2747..deb7b315b1 100644 --- a/lib/kernel/src/file_io_server.erl +++ b/lib/kernel/src/file_io_server.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2013. All Rights Reserved. +%% Copyright Ericsson AB 2000-2015. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -206,8 +206,8 @@ io_reply(From, ReplyAs, Reply) -> file_request({advise,Offset,Length,Advise}, #state{handle=Handle}=State) -> case ?PRIM_FILE:advise(Handle, Offset, Length, Advise) of - {error,_}=Reply -> - {stop,normal,Reply,State}; + {error,Reason}=Reply -> + {stop,Reason,Reply,State}; Reply -> {reply,Reply,State} end; @@ -215,62 +215,91 @@ file_request({allocate, Offset, Length}, #state{handle = Handle} = State) -> Reply = ?PRIM_FILE:allocate(Handle, Offset, Length), {reply, Reply, State}; +file_request({pread,At,Sz}, State) + when At =:= cur; + At =:= {cur,0} -> + case get_chars(Sz, latin1, State) of + {reply,Reply,NewState} + when is_list(Reply); + is_binary(Reply) -> + {reply,{ok,Reply},NewState}; + Other -> + Other + end; file_request({pread,At,Sz}, - #state{handle=Handle,buf=Buf,read_mode=ReadMode}=State) -> + #state{handle=Handle,buf=Buf}=State) -> case position(Handle, At, Buf) of - {ok,_Offs} -> - case ?PRIM_FILE:read(Handle, Sz) of - {ok,Bin} when ReadMode =:= list -> - std_reply({ok,binary_to_list(Bin)}, State); - Reply -> - std_reply(Reply, State) - end; - Reply -> - std_reply(Reply, State) + {error,_} = Reply -> + {error,Reply,State}; + _ -> + case get_chars(Sz, latin1, State#state{buf= <<>>}) of + {reply,Reply,NewState} + when is_list(Reply); + is_binary(Reply) -> + {reply,{ok,Reply},NewState}; + Other -> + Other + end end; +file_request({pwrite,At,Data}, + #state{buf= <<>>}=State) + when At =:= cur; + At =:= {cur,0} -> + put_chars(Data, latin1, State); file_request({pwrite,At,Data}, #state{handle=Handle,buf=Buf}=State) -> case position(Handle, At, Buf) of - {ok,_Offs} -> - std_reply(?PRIM_FILE:write(Handle, Data), State); - Reply -> - std_reply(Reply, State) + {error,_} = Reply -> + {error,Reply,State}; + _ -> + put_chars(Data, latin1, State) end; file_request(datasync, #state{handle=Handle}=State) -> case ?PRIM_FILE:datasync(Handle) of - {error,_}=Reply -> - {stop,normal,Reply,State}; + {error,Reason}=Reply -> + {stop,Reason,Reply,State}; Reply -> {reply,Reply,State} end; file_request(sync, #state{handle=Handle}=State) -> case ?PRIM_FILE:sync(Handle) of - {error,_}=Reply -> - {stop,normal,Reply,State}; + {error,Reason}=Reply -> + {stop,Reason,Reply,State}; Reply -> {reply,Reply,State} end; file_request(close, #state{handle=Handle}=State) -> - {stop,normal,?PRIM_FILE:close(Handle),State#state{buf= <<>>}}; + case ?PRIM_FILE:close(Handle) of + {error,Reason}=Reply -> + {stop,Reason,Reply,State#state{buf= <<>>}}; + Reply -> + {stop,normal,Reply,State#state{buf= <<>>}} + end; file_request({position,At}, #state{handle=Handle,buf=Buf}=State) -> - std_reply(position(Handle, At, Buf), State); + case position(Handle, At, Buf) of + {error,_} = Reply -> + {error,Reply,State}; + Reply -> + std_reply(Reply, State) + end; file_request(truncate, #state{handle=Handle}=State) -> case ?PRIM_FILE:truncate(Handle) of - {error,_Reason}=Reply -> - {stop,normal,Reply,State#state{buf= <<>>}}; + {error,Reason}=Reply -> + {stop,Reason,Reply,State#state{buf= <<>>}}; Reply -> - {reply,Reply,State} + std_reply(Reply, State) end; file_request(Unknown, #state{}=State) -> Reason = {request, Unknown}, {error,{error,Reason},State}. +%% Standard reply and clear buffer std_reply({error,_}=Reply, State) -> {error,Reply,State#state{buf= <<>>}}; std_reply(Reply, State) -> @@ -286,8 +315,8 @@ io_request({put_chars, Enc, Chars}, io_request({put_chars, Enc, Chars}, #state{handle=Handle,buf=Buf}=State) -> case position(Handle, cur, Buf) of - {error,_}=Reply -> - {stop,normal,Reply,State#state{buf= <<>>}}; + {error,Reason}=Reply -> + {stop,Reason,Reply,State}; _ -> put_chars(Chars, Enc, State#state{buf= <<>>}) end; @@ -368,23 +397,27 @@ io_request_loop([Request|Tail], %% I/O request put_chars %% put_chars(Chars, latin1, #state{handle=Handle, unic=latin1}=State) -> + NewState = State#state{buf = <<>>}, case ?PRIM_FILE:write(Handle, Chars) of - {error,_}=Reply -> - {stop,normal,Reply,State}; + {error,Reason}=Reply -> + {stop,Reason,Reply,NewState}; Reply -> - {reply,Reply,State} + {reply,Reply,NewState} end; put_chars(Chars, InEncoding, #state{handle=Handle, unic=OutEncoding}=State) -> + NewState = State#state{buf = <<>>}, case unicode:characters_to_binary(Chars,InEncoding,OutEncoding) of Bin when is_binary(Bin) -> case ?PRIM_FILE:write(Handle, Bin) of - {error,_}=Reply -> - {stop,normal,Reply,State}; + {error,Reason}=Reply -> + {stop,Reason,Reply,NewState}; Reply -> - {reply,Reply,State} + {reply,Reply,NewState} end; {error,_,_} -> - {stop,normal,{error,{no_translation, InEncoding, OutEncoding}},State} + {stop,no_translation, + {error,{no_translation, InEncoding, OutEncoding}}, + NewState} end. get_line(S, {<<>>, Cont}, OutEnc, @@ -884,11 +917,14 @@ cbv({utf32,little},_) -> %% Compensates ?PRIM_FILE:position/2 for the number of bytes %% we have buffered - -position(Handle, cur, Buf) -> - position(Handle, {cur, 0}, Buf); -position(Handle, {cur, Offs}, Buf) when is_binary(Buf) -> - ?PRIM_FILE:position(Handle, {cur, Offs-byte_size(Buf)}); -position(Handle, At, _Buf) -> - ?PRIM_FILE:position(Handle, At). - +position(Handle, At, Buf) -> + ?PRIM_FILE:position( + Handle, + case At of + cur -> + {cur, -byte_size(Buf)}; + {cur, Offs} -> + {cur, Offs-byte_size(Buf)}; + _ -> + At + end). diff --git a/lib/kernel/src/gen_tcp.erl b/lib/kernel/src/gen_tcp.erl index d7dba4ac80..8cb2a725e8 100644 --- a/lib/kernel/src/gen_tcp.erl +++ b/lib/kernel/src/gen_tcp.erl @@ -114,7 +114,8 @@ option(). -type socket() :: port(). --export_type([option/0, option_name/0, connect_option/0, listen_option/0]). +-export_type([option/0, option_name/0, connect_option/0, listen_option/0, + socket/0]). %% %% Connect a socket diff --git a/lib/kernel/src/heart.erl b/lib/kernel/src/heart.erl index 464b6919f1..eea78aabdf 100644 --- a/lib/kernel/src/heart.erl +++ b/lib/kernel/src/heart.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,7 +34,11 @@ %%% %%% It recognizes the flag '-heart' %%%-------------------------------------------------------------------- --export([start/0, init/2, set_cmd/1, clear_cmd/0, get_cmd/0, cycle/0]). +-export([start/0, init/2, + set_cmd/1, clear_cmd/0, get_cmd/0, + set_callback/2, clear_callback/0, get_callback/0, + set_options/1, get_options/0, + cycle/0]). -define(START_ACK, 1). -define(HEART_BEAT, 2). @@ -49,6 +53,16 @@ -define(CYCLE_TIMEOUT, 10000). -define(HEART_PORT_NAME, heart_port). +%% valid heart options +-define(SCHEDULER_CHECK_OPT, check_schedulers). + +-type heart_option() :: ?SCHEDULER_CHECK_OPT. + +-record(state,{port :: port(), + cmd :: [] | binary(), + options :: [heart_option()], + callback :: 'undefined' | {atom(), atom()}}). + %%--------------------------------------------------------------------- -spec start() -> 'ignore' | {'error', term()} | {'ok', pid()}. @@ -81,11 +95,11 @@ wait_for_init_ack(From) -> init(Starter, Parent) -> process_flag(trap_exit, true), process_flag(priority, max), - register(heart, self()), + register(?MODULE, self()), case catch start_portprogram() of {ok, Port} -> Starter ! {ok, self()}, - loop(Parent, Port, ""); + loop(Parent, #state{port=Port, cmd=[], options=[]}); no_heart -> Starter ! {no_heart, self()}; error -> @@ -96,33 +110,68 @@ init(Starter, Parent) -> Cmd :: string(). set_cmd(Cmd) -> - heart ! {self(), set_cmd, Cmd}, + ?MODULE ! {self(), set_cmd, Cmd}, wait(). -spec get_cmd() -> {ok, Cmd} when Cmd :: string(). get_cmd() -> - heart ! {self(), get_cmd}, + ?MODULE ! {self(), get_cmd}, wait(). -spec clear_cmd() -> ok. clear_cmd() -> - heart ! {self(), clear_cmd}, + ?MODULE ! {self(), clear_cmd}, + wait(). + +-spec set_callback(Module,Function) -> 'ok' | {'error', {'bad_callback', {Module, Function}}} when + Module :: atom(), + Function :: atom(). + +set_callback(Module, Function) -> + ?MODULE ! {self(), set_callback, {Module,Function}}, + wait(). + +-spec get_callback() -> {'ok', {Module, Function}} | 'none' when + Module :: atom(), + Function :: atom(). + +get_callback() -> + ?MODULE ! {self(), get_callback}, + wait(). + +-spec clear_callback() -> ok. + +clear_callback() -> + ?MODULE ! {self(), clear_callback}, + wait(). + +-spec set_options(Options) -> 'ok' | {'error', {'bad_options', Options}} when + Options :: [heart_option()]. + +set_options(Options) -> + ?MODULE ! {self(), set_options, Options}, wait(). +-spec get_options() -> {'ok', Options} | 'none' when + Options :: [atom()]. + +get_options() -> + ?MODULE ! {self(), get_options}, + wait(). %%% Should be used solely by the release handler!!!!!!! -spec cycle() -> 'ok' | {'error', term()}. cycle() -> - heart ! {self(), cycle}, + ?MODULE ! {self(), cycle}, wait(). wait() -> receive - {heart, Res} -> + {?MODULE, Res} -> Res end. @@ -182,8 +231,8 @@ wait_ack(Port) -> {error, Reason} end. -loop(Parent, Port, Cmd) -> - _ = send_heart_beat(Port), +loop(Parent, #state{port=Port}=S) -> + _ = send_heart_beat(S), receive {From, set_cmd, NewCmd0} -> Enc = file:native_name_encoding(), @@ -191,37 +240,72 @@ loop(Parent, Port, Cmd) -> NewCmd when is_binary(NewCmd), byte_size(NewCmd) < 2047 -> _ = send_heart_cmd(Port, NewCmd), _ = wait_ack(Port), - From ! {heart, ok}, - loop(Parent, Port, NewCmd); + From ! {?MODULE, ok}, + loop(Parent, S#state{cmd=NewCmd}); _ -> - From ! {heart, {error, {bad_cmd, NewCmd0}}}, - loop(Parent, Port, Cmd) + From ! {?MODULE, {error, {bad_cmd, NewCmd0}}}, + loop(Parent, S) end; {From, clear_cmd} -> - From ! {heart, ok}, - _ = send_heart_cmd(Port, ""), + From ! {?MODULE, ok}, + _ = send_heart_cmd(Port, []), _ = wait_ack(Port), - loop(Parent, Port, ""); + loop(Parent, S#state{cmd = []}); {From, get_cmd} -> - From ! {heart, get_heart_cmd(Port)}, - loop(Parent, Port, Cmd); + From ! {?MODULE, get_heart_cmd(Port)}, + loop(Parent, S); + {From, set_callback, Callback} -> + case Callback of + {M,F} when is_atom(M), is_atom(F) -> + From ! {?MODULE, ok}, + loop(Parent, S#state{callback=Callback}); + _ -> + From ! {?MODULE, {error, {bad_callback, Callback}}}, + loop(Parent, S) + end; + {From, get_callback} -> + Res = case S#state.callback of + undefined -> none; + Cb -> {ok, Cb} + end, + From ! {?MODULE, Res}, + loop(Parent, S); + {From, clear_callback} -> + From ! {?MODULE, ok}, + loop(Parent, S#state{callback=undefined}); + {From, set_options, Options} -> + case validate_options(Options) of + Validated when is_list(Validated) -> + From ! {?MODULE, ok}, + loop(Parent, S#state{options=Validated}); + _ -> + From ! {?MODULE, {error, {bad_options, Options}}}, + loop(Parent, S) + end; + {From, get_options} -> + Res = case S#state.options of + [] -> none; + Cb -> {ok, Cb} + end, + From ! {?MODULE, Res}, + loop(Parent, S); {From, cycle} -> %% Calls back to loop - do_cycle_port_program(From, Parent, Port, Cmd); + do_cycle_port_program(From, Parent, S); {'EXIT', Parent, shutdown} -> no_reboot_shutdown(Port); {'EXIT', Parent, Reason} -> exit(Port, Reason), exit(Reason); {'EXIT', Port, badsig} -> % we can ignore badsig-messages! - loop(Parent, Port, Cmd); + loop(Parent, S); {'EXIT', Port, _Reason} -> - exit({port_terminated, {heart, loop, [Parent, Port, Cmd]}}); + exit({port_terminated, {?MODULE, loop, [Parent, S]}}); _ -> - loop(Parent, Port, Cmd) + loop(Parent, S) after ?TIMEOUT -> - loop(Parent, Port, Cmd) + loop(Parent, S) end. -spec no_reboot_shutdown(port()) -> no_return(). @@ -233,38 +317,47 @@ no_reboot_shutdown(Port) -> exit(normal) end. -do_cycle_port_program(Caller, Parent, Port, Cmd) -> +validate_options(Opts) -> validate_options(Opts,[]). +validate_options([],Res) -> Res; +validate_options([?SCHEDULER_CHECK_OPT=Opt|Opts],Res) -> validate_options(Opts,[Opt|Res]); +validate_options(_,_) -> error. + +do_cycle_port_program(Caller, Parent, #state{port=Port} = S) -> unregister(?HEART_PORT_NAME), case catch start_portprogram() of {ok, NewPort} -> _ = send_shutdown(Port), receive {'EXIT', Port, _Reason} -> - _ = send_heart_cmd(NewPort, Cmd), - Caller ! {heart, ok}, - loop(Parent, NewPort, Cmd) + _ = send_heart_cmd(NewPort, S#state.cmd), + Caller ! {?MODULE, ok}, + loop(Parent, S#state{port=NewPort}) after ?CYCLE_TIMEOUT -> %% Huh! Two heart port programs running... %% well, the old one has to be sick not to respond %% so we'll settle for the new one... - _ = send_heart_cmd(NewPort, Cmd), - Caller ! {heart, {error, stop_error}}, - loop(Parent, NewPort, Cmd) + _ = send_heart_cmd(NewPort, S#state.cmd), + Caller ! {?MODULE, {error, stop_error}}, + loop(Parent, S#state{port=NewPort}) end; no_heart -> - Caller ! {heart, {error, no_heart}}, - loop(Parent, Port, Cmd); + Caller ! {?MODULE, {error, no_heart}}, + loop(Parent, S); error -> - Caller ! {heart, {error, start_error}}, - loop(Parent, Port, Cmd) + Caller ! {?MODULE, {error, start_error}}, + loop(Parent, S) end. %% "Beates" the heart once. -send_heart_beat(Port) -> Port ! {self(), {command, [?HEART_BEAT]}}. +send_heart_beat(#state{port=Port, callback=Cb, options=Opts}) -> + ok = check_system(Opts), + ok = check_callback(Cb), + Port ! {self(), {command, [?HEART_BEAT]}}. %% Set a new HEART_COMMAND. +-dialyzer({no_improper_lists, send_heart_cmd/2}). send_heart_cmd(Port, []) -> Port ! {self(), {command, [?CLEAR_CMD]}}; send_heart_cmd(Port, Cmd) -> @@ -277,6 +370,24 @@ get_heart_cmd(Port) -> {ok, Cmd} end. +check_system([]) -> ok; +check_system([?SCHEDULER_CHECK_OPT|Opts]) -> + ok = erts_internal:system_check(schedulers), + check_system(Opts). + +%% validate system by performing a check before the heartbeat +%% return 'ok' if everything is alright. +%% Terminate if with reason if something is a miss. +%% It is fine to timeout in the callback, in fact that is the intention +%% if something goes wront -> no heartbeat. + +check_callback(Callback) -> + case Callback of + undefined -> ok; + {M,F} -> + erlang:apply(M,F,[]) + end. + %% Sends shutdown command to the port. send_shutdown(Port) -> Port ! {self(), {command, [?SHUT_DOWN]}}. diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index da7f04089d..c1ae99ea24 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2015. All Rights Reserved. +%% Copyright Ericsson AB 1997-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -289,7 +289,7 @@ getifaddrs(Socket) -> -spec getifaddrs() -> {ok, Iflist} | {error, posix()} when Iflist :: [{Ifname,[Ifopt]}], Ifname :: string(), - Ifopt :: {flag,[Flag]} | {addr,Addr} | {netmask,Netmask} + Ifopt :: {flags,[Flag]} | {addr,Addr} | {netmask,Netmask} | {broadaddr,Broadaddr} | {dstaddr,Dstaddr} | {hwaddr,Hwaddr}, Flag :: up | broadcast | loopback | pointtopoint @@ -671,7 +671,7 @@ stats() -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% connect_options() -> [tos, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay, - header, active, packet, packet_size, buffer, mode, deliver, + header, active, packet, packet_size, buffer, mode, deliver, line_delimiter, exit_on_close, high_watermark, low_watermark, high_msgq_watermark, low_msgq_watermark, send_timeout, send_timeout_close, delay_send, raw, show_econnreset]. @@ -692,6 +692,7 @@ connect_options(Opts, Family) -> case con_opt(Opts, BaseOpts, connect_options()) of {ok, R} -> {ok, R#connect_opts { + opts = lists:reverse(R#connect_opts.opts), ifaddr = translate_ip(R#connect_opts.ifaddr, Family) }}; Error -> Error @@ -721,6 +722,8 @@ con_opt([Opt | Opts], #connect_opts{} = R, As) -> {active,N} when is_integer(N), N < 32768, N >= -32768 -> NOpts = lists:keydelete(active, 1, R#connect_opts.opts), con_opt(Opts, R#connect_opts { opts = [{active,N}|NOpts] }, As); + {line_delimiter,C} when is_integer(C), C >= 0, C =< 255 -> + con_add(line_delimiter, C, R, Opts, As); {Name,Val} when is_atom(Name) -> con_add(Name, Val, R, Opts, As); _ -> {error, badarg} end; @@ -760,6 +763,7 @@ listen_options(Opts, Family) -> case list_opt(Opts, BaseOpts, listen_options()) of {ok, R} -> {ok, R#listen_opts { + opts = lists:reverse(R#listen_opts.opts), ifaddr = translate_ip(R#listen_opts.ifaddr, Family) }}; Error -> Error @@ -818,6 +822,7 @@ udp_options(Opts, Family) -> case udp_opt(Opts, #udp_opts { }, udp_options()) of {ok, R} -> {ok, R#udp_opts { + opts = lists:reverse(R#udp_opts.opts), ifaddr = translate_ip(R#udp_opts.ifaddr, Family) }}; Error -> Error @@ -891,9 +896,12 @@ sctp_options() -> sctp_options(Opts, Mod) -> case sctp_opt(Opts, Mod, #sctp_opts{}, sctp_options()) of {ok,#sctp_opts{ifaddr=undefined}=SO} -> - {ok,SO#sctp_opts{ifaddr=Mod:translate_ip(?SCTP_DEF_IFADDR)}}; - {ok,_}=OK -> - OK; + {ok, + SO#sctp_opts{ + opts=lists:reverse(SO#sctp_opts.opts), + ifaddr=Mod:translate_ip(?SCTP_DEF_IFADDR)}}; + {ok,SO} -> + {ok,SO#sctp_opts{opts=lists:reverse(SO#sctp_opts.opts)}}; Error -> Error end. @@ -965,6 +973,8 @@ add_opt(Name, Val, Opts, As) -> case lists:member(Name, As) of true -> case prim_inet:is_sockopt_val(Name, Val) of + true when Name =:= raw -> + {ok, [{Name,Val} | Opts]}; true -> Opts1 = lists:keydelete(Name, 1, Opts), {ok, [{Name,Val} | Opts1]}; diff --git a/lib/kernel/src/inet6_tcp.erl b/lib/kernel/src/inet6_tcp.erl index 2ea017285c..1978307b3c 100644 --- a/lib/kernel/src/inet6_tcp.erl +++ b/lib/kernel/src/inet6_tcp.erl @@ -25,10 +25,29 @@ -export([controlling_process/2]). -export([fdopen/2]). +-export([family/0, mask/2, parse_address/1]). -export([getserv/1, getaddr/1, getaddr/2, getaddrs/1, getaddrs/2]). -include("inet_int.hrl"). +%% my address family +family() -> inet6. + +%% Apply netmask on address +mask({M1,M2,M3,M4,M5,M6,M7,M8}, {IP1,IP2,IP3,IP4,IP5,IP6,IP7,IP8}) -> + {M1 band IP1, + M2 band IP2, + M3 band IP3, + M4 band IP4, + M5 band IP5, + M6 band IP6, + M7 band IP7, + M8 band IP8 }. + +%% Parse address string +parse_address(Host) -> + inet_parse:ipv6strict_address(Host). + %% inet_tcp port lookup getserv(Port) when is_integer(Port) -> {ok, Port}; getserv(Name) when is_atom(Name) -> inet:getservbyname(Name,tcp). diff --git a/lib/kernel/src/inet6_tcp_dist.erl b/lib/kernel/src/inet6_tcp_dist.erl index a74a4916ba..3ab7f269bb 100644 --- a/lib/kernel/src/inet6_tcp_dist.erl +++ b/lib/kernel/src/inet6_tcp_dist.erl @@ -24,28 +24,6 @@ -export([listen/1, accept/1, accept_connection/5, setup/5, close/1, select/1, is_node_name/1]). -%% internal exports - --export([accept_loop/2,do_accept/6,do_setup/6, getstat/1,tick/1]). - --import(error_logger,[error_msg/2]). - --include("net_address.hrl"). - - - --define(to_port(Socket, Data, Opts), - case inet6_tcp:send(Socket, Data, Opts) of - {error, closed} -> - self() ! {tcp_closed, Socket}, - {error, closed}; - R -> - R - end). - - --include("dist.hrl"). --include("dist_util.hrl"). %% ------------------------------------------------------------ %% Select this protocol based on node name @@ -53,14 +31,7 @@ %% ------------------------------------------------------------ select(Node) -> - case split_node(atom_to_list(Node), $@, []) of - [_, Host] -> - case inet:getaddr(Host,inet6) of - {ok,_} -> true; - _ -> false - end; - _ -> false - end. + inet_tcp_dist:gen_select(inet6_tcp, Node). %% ------------------------------------------------------------ %% Create the listen socket, i.e. the port that this erlang @@ -68,59 +39,14 @@ select(Node) -> %% ------------------------------------------------------------ listen(Name) -> - case inet6_tcp:listen(0, [{active, false}, {packet,2}]) of - {ok, Socket} -> - TcpAddress = get_tcp_address(Socket), - {_,Port} = TcpAddress#net_address.address, - case erl_epmd:register_node(Name, Port) of - {ok, Creation} -> - {ok, {Socket, TcpAddress, Creation}}; - Error -> - Error - end; - Error -> - Error - end. + inet_tcp_dist:gen_listen(inet6_tcp, Name). %% ------------------------------------------------------------ %% Accepts new connection attempts from other Erlang nodes. %% ------------------------------------------------------------ accept(Listen) -> - spawn_opt(?MODULE, accept_loop, [self(), Listen], [link, {priority, max}]). - -accept_loop(Kernel, Listen) -> - case inet6_tcp:accept(Listen) of - {ok, Socket} -> - Kernel ! {accept,self(),Socket,inet6,tcp}, - _ = controller(Kernel, Socket), - accept_loop(Kernel, Listen); - Error -> - exit(Error) - end. - -controller(Kernel, Socket) -> - receive - {Kernel, controller, Pid} -> - flush_controller(Pid, Socket), - inet6_tcp:controlling_process(Socket, Pid), - flush_controller(Pid, Socket), - Pid ! {self(), controller}; - {Kernel, unsupported_protocol} -> - exit(unsupported_protocol) - end. - -flush_controller(Pid, Socket) -> - receive - {tcp, Socket, Data} -> - Pid ! {tcp, Socket, Data}, - flush_controller(Pid, Socket); - {tcp_closed, Socket} -> - Pid ! {tcp_closed, Socket}, - flush_controller(Pid, Socket) - after 0 -> - ok - end. + inet_tcp_dist:gen_accept(inet6_tcp, Listen). %% ------------------------------------------------------------ %% Accepts a new connection attempt from another Erlang node. @@ -128,85 +54,7 @@ flush_controller(Pid, Socket) -> %% ------------------------------------------------------------ accept_connection(AcceptPid, Socket, MyNode, Allowed, SetupTime) -> - spawn_opt(?MODULE, do_accept, - [self(), AcceptPid, Socket, MyNode, Allowed, SetupTime], - [link, {priority, max}]). - -do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) -> - receive - {AcceptPid, controller} -> - Timer = dist_util:start_timer(SetupTime), - case check_ip(Socket) of - true -> - HSData = #hs_data{ - kernel_pid = Kernel, - this_node = MyNode, - socket = Socket, - timer = Timer, - this_flags = 0, - allowed = Allowed, - f_send = fun(S,D) -> inet6_tcp:send(S,D) end, - f_recv = fun(S,N,T) -> inet6_tcp:recv(S,N,T) - end, - f_setopts_pre_nodeup = - fun(S) -> - inet:setopts(S, - [{active, false}, - {packet, 4}, - nodelay()]) - end, - f_setopts_post_nodeup = - fun(S) -> - inet:setopts(S, - [{active, true}, - {deliver, port}, - {packet, 4}, - nodelay()]) - end, - f_getll = fun(S) -> - inet:getll(S) - end, - f_address = fun get_remote_id/2, - mf_tick = fun ?MODULE:tick/1, - mf_getstat = fun ?MODULE:getstat/1 - }, - dist_util:handshake_other_started(HSData); - {false,IP} -> - error_msg("** Connection attempt from " - "disallowed IP ~w ** ~n", [IP]), - ?shutdown(no_node) - end - end. - - -%% we may not always want the nodelay behaviour -%% for performance reasons - -nodelay() -> - case application:get_env(kernel, dist_nodelay) of - undefined -> - {nodelay, true}; - {ok, true} -> - {nodelay, true}; - {ok, false} -> - {nodelay, false}; - _ -> - {nodelay, true} - end. - - -%% ------------------------------------------------------------ -%% Get remote information about a Socket. -%% ------------------------------------------------------------ - -get_remote_id(Socket, Node) -> - {ok, Address} = inet:peername(Socket), - [_, Host] = split_node(atom_to_list(Node), $@, []), - #net_address { - address = Address, - host = Host, - protocol = tcp, - family = inet6 }. + inet_tcp_dist:gen_accept_connection(inet6_tcp, AcceptPid, Socket, MyNode, Allowed, SetupTime). %% ------------------------------------------------------------ %% Setup a new connection to another Erlang node. @@ -214,214 +62,13 @@ get_remote_id(Socket, Node) -> %% ------------------------------------------------------------ setup(Node, Type, MyNode, LongOrShortNames,SetupTime) -> - spawn_opt(?MODULE, do_setup, - [self(), Node, Type, MyNode, LongOrShortNames, SetupTime], - [link, {priority, max}]). - -do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) -> - ?trace("~p~n",[{?MODULE,self(),setup,Node}]), - [Name, Address] = splitnode(Node, LongOrShortNames), - case inet:getaddr(Address, inet6) of - {ok, Ip} -> - Timer = dist_util:start_timer(SetupTime), - case erl_epmd:port_please(Name, Ip) of - {port, TcpPort, Version} -> - ?trace("port_please(~p) -> version ~p~n", - [Node,Version]), - dist_util:reset_timer(Timer), - case inet6_tcp:connect(Ip, TcpPort, - [{active, false}, - {packet,2}]) of - {ok, Socket} -> - HSData = #hs_data{ - kernel_pid = Kernel, - other_node = Node, - this_node = MyNode, - socket = Socket, - timer = Timer, - this_flags = 0, - other_version = Version, - f_send = fun inet6_tcp:send/2, - f_recv = fun inet6_tcp:recv/3, - f_setopts_pre_nodeup = - fun(S) -> - inet:setopts - (S, - [{active, false}, - {packet, 4}, - nodelay()]) - end, - f_setopts_post_nodeup = - fun(S) -> - inet:setopts - (S, - [{active, true}, - {deliver, port}, - {packet, 4}, - nodelay()]) - end, - f_getll = fun inet:getll/1, - f_address = - fun(_,_) -> - #net_address { - address = {Ip,TcpPort}, - host = Address, - protocol = tcp, - family = inet6} - end, - mf_tick = fun ?MODULE:tick/1, - mf_getstat = fun ?MODULE:getstat/1, - request_type = Type - }, - dist_util:handshake_we_started(HSData); - _ -> - %% Other Node may have closed since - %% port_please ! - ?trace("other node (~p) " - "closed since port_please.~n", - [Node]), - ?shutdown(Node) - end; - _ -> - ?trace("port_please (~p) " - "failed.~n", [Node]), - ?shutdown(Node) - end; - __Other -> - ?trace("inet_getaddr(~p) " - "failed (~p).~n", [Node,__Other]), - ?shutdown(Node) - end. + inet_tcp_dist:gen_setup(inet6_tcp, Node, Type, MyNode, LongOrShortNames, SetupTime). %% %% Close a socket. %% close(Socket) -> inet6_tcp:close(Socket). - - -%% If Node is illegal terminate the connection setup!! -splitnode(Node, LongOrShortNames) -> - case split_node(atom_to_list(Node), $@, []) of - [Name|Tail] when Tail =/= [] -> - Host = lists:append(Tail), - case split_node(Host, $., []) of - [_] when LongOrShortNames =:= longnames -> - case inet_parse:ipv6strict_address(Host) of - {ok, _} -> - [Name, Host]; - _ -> - error_msg("** System running to use " - "fully qualified " - "hostnames **~n" - "** Hostname ~s is illegal **~n", - [Host]), - ?shutdown(Node) - end; - L when length(L) > 1, LongOrShortNames =:= shortnames -> - error_msg("** System NOT running to use fully qualified " - "hostnames **~n" - "** Hostname ~s is illegal **~n", - [Host]), - ?shutdown(Node); - _ -> - [Name, Host] - end; - [_] -> - error_msg("** Nodename ~p illegal, no '@' character **~n", - [Node]), - ?shutdown(Node); - _ -> - error_msg("** Nodename ~p illegal **~n", [Node]), - ?shutdown(Node) - end. - -split_node([Chr|T], Chr, Ack) -> [lists:reverse(Ack)|split_node(T, Chr, [])]; -split_node([H|T], Chr, Ack) -> split_node(T, Chr, [H|Ack]); -split_node([], _, Ack) -> [lists:reverse(Ack)]. - -%% ------------------------------------------------------------ -%% Fetch local information about a Socket. -%% ------------------------------------------------------------ -get_tcp_address(Socket) -> - {ok, Address} = inet:sockname(Socket), - {ok, Host} = inet:gethostname(), - #net_address { - address = Address, - host = Host, - protocol = tcp, - family = inet6 - }. - -%% ------------------------------------------------------------ -%% Do only accept new connection attempts from nodes at our -%% own LAN, if the check_ip environment parameter is true. -%% ------------------------------------------------------------ -check_ip(Socket) -> - case application:get_env(check_ip) of - {ok, true} -> - case get_ifs(Socket) of - {ok, IFs, IP} -> - check_ip(IFs, IP); - _ -> - ?shutdown(no_node) - end; - _ -> - true - end. - -get_ifs(Socket) -> - case inet:peername(Socket) of - {ok, {IP, _}} -> - case inet:getif(Socket) of - {ok, IFs} -> {ok, IFs, IP}; - Error -> Error - end; - Error -> - Error - end. - -check_ip([{OwnIP, _, Netmask}|IFs], PeerIP) -> - case {mask(Netmask, PeerIP), mask(Netmask, OwnIP)} of - {M, M} -> true; - _ -> check_ip(IFs, PeerIP) - end; -check_ip([], PeerIP) -> - {false, PeerIP}. -mask({M1,M2,M3,M4,M5,M6,M7,M8}, {IP1,IP2,IP3,IP4,IP5,IP6,IP7,IP8}) -> - {M1 band IP1, - M2 band IP2, - M3 band IP3, - M4 band IP4, - M5 band IP5, - M6 band IP6, - M7 band IP7, - M8 band IP8 }. - is_node_name(Node) when is_atom(Node) -> - case split_node(atom_to_list(Node), $@, []) of - [_,_Host] -> true; - _ -> false - end; -is_node_name(_Node) -> - false. -tick(Sock) -> - ?to_port(Sock,[],[force]). -getstat(Socket) -> - case inet:getstat(Socket, [recv_cnt, send_cnt, send_pend]) of - {ok, Stat} -> - split_stat(Stat,0,0,0); - Error -> - Error - end. - -split_stat([{recv_cnt, R}|Stat], _, W, P) -> - split_stat(Stat, R, W, P); -split_stat([{send_cnt, W}|Stat], R, _, P) -> - split_stat(Stat, R, W, P); -split_stat([{send_pend, P}|Stat], R, W, _) -> - split_stat(Stat, R, W, P); -split_stat([], R, W, P) -> - {ok, R, W, P}. - + inet_tcp_dist:is_node_name(Node). diff --git a/lib/kernel/src/inet_db.erl b/lib/kernel/src/inet_db.erl index 1621efbfd7..108a803610 100644 --- a/lib/kernel/src/inet_db.erl +++ b/lib/kernel/src/inet_db.erl @@ -633,20 +633,22 @@ make_hostent(Name, Datas, Aliases, Type) -> hostent_by_domain(Domain, Type) -> ?dbg("hostent_by_domain: ~p~n", [Domain]), - hostent_by_domain(stripdot(Domain), [], Type). + hostent_by_domain(stripdot(Domain), [], [], Type). -hostent_by_domain(Domain, Aliases, Type) -> +hostent_by_domain(Domain, Aliases, LAliases, Type) -> case lookup_type(Domain, Type) of [] -> case lookup_cname(Domain) of [] -> {error, nxdomain}; [CName | _] -> - case lists:member(CName, [Domain | Aliases]) of + LDomain = tolower(Domain), + case lists:member(CName, [LDomain | LAliases]) of true -> {error, nxdomain}; false -> - hostent_by_domain(CName, [Domain | Aliases], Type) + hostent_by_domain(CName, [Domain | Aliases], + [LDomain | LAliases], Type) end end; Addrs -> @@ -671,24 +673,26 @@ lookup_rr(Domain, Class, Type) -> %% match data field directly and cache RRs. %% res_hostent_by_domain(Domain, Type, Rec) -> - res_cache_answer(Rec), - RRs = Rec#dns_rec.anlist, + RRs = lists:map(fun lower_rr/1, Rec#dns_rec.anlist), + res_cache_answer(Rec#dns_rec{anlist = RRs}), ?dbg("res_hostent_by_domain: ~p - ~p~n", [Domain, RRs]), - res_hostent_by_domain(stripdot(Domain), [], Type, RRs). + res_hostent_by_domain(stripdot(Domain), [], [], Type, RRs). -res_hostent_by_domain(Domain, Aliases, Type, RRs) -> - case res_lookup_type(Domain, Type, RRs) of +res_hostent_by_domain(Domain, Aliases, LAliases, Type, RRs) -> + LDomain = tolower(Domain), + case res_lookup_type(LDomain, Type, RRs) of [] -> - case res_lookup_type(Domain, ?S_CNAME, RRs) of + case res_lookup_type(LDomain, ?S_CNAME, RRs) of [] -> {error, nxdomain}; [CName | _] -> - case lists:member(CName, [Domain | Aliases]) of + case lists:member(tolower(CName), [LDomain | LAliases]) of true -> {error, nxdomain}; false -> res_hostent_by_domain(CName, [Domain | Aliases], - Type, RRs) + [LDomain | LAliases], Type, + RRs) end end; Addrs -> @@ -721,7 +725,8 @@ gethostbyaddr(IP) -> %% res_gethostbyaddr(IP, Rec) -> {ok, {IP1, HType, HLen}} = dnt(IP), - res_cache_answer(Rec), + RRs = lists:map(fun lower_rr/1, Rec#dns_rec.anlist), + res_cache_answer(Rec#dns_rec{anlist = RRs}), ent_gethostbyaddr(Rec#dns_rec.anlist, IP1, HType, HLen). ent_gethostbyaddr(RRs, IP, AddrType, Length) -> @@ -1378,7 +1383,7 @@ times() -> %% lookup and remove old entries do_lookup_rr(Domain, Class, Type) -> - match_rr(#dns_rr{domain = Domain, class = Class,type = Type, + match_rr(#dns_rr{domain = tolower(Domain), class = Class,type = Type, cnt = '_', tm = '_', ttl = '_', bm = '_', func = '_', data = '_'}). @@ -1400,6 +1405,11 @@ filter_rr([RR | RRs], Time) -> [RR | filter_rr(RRs, Time)]; filter_rr([], _Time) -> []. +%% Lower case the domain name before storage. +%% +lower_rr(#dns_rr{domain=Domain}=RR) when is_list(Domain) -> + RR#dns_rr { domain = tolower(Domain) }; +lower_rr(RR) -> RR. %% %% Case fold upper-case to lower-case according to RFC 4343 diff --git a/lib/kernel/src/inet_dns_record_adts.pl b/lib/kernel/src/inet_dns_record_adts.pl index 657d2b9d35..6d719d836e 100644 --- a/lib/kernel/src/inet_dns_record_adts.pl +++ b/lib/kernel/src/inet_dns_record_adts.pl @@ -57,7 +57,8 @@ while(<DATA>) { $" = ','; $\ = "\n"; -while( my ($Name, $r) = each(%Names)) { +foreach my $Name (sort keys %Names) { + my $r = $Names{$Name}; # Create substitutions for this Name my ($Record, @Fields) = @{ $r }; my @FieldMatchValues; @@ -110,7 +111,8 @@ while( my ($Name, $r) = each(%Names)) { for my $i ( 0 .. $#INDEX ) { my $line = $INDEX[$i]; if ($line =~ s/^[*]//) { - while( my ($Name, $r) = each(%Names)) { + foreach my $Name (sort keys %Names) { + my $r = $Names{$Name}; my ($Record) = @{ $r }; $_ = $line; s/Name\b/$Name/g; diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl index bfe4c9ec8c..e7c6cf8ae2 100644 --- a/lib/kernel/src/inet_int.hrl +++ b/lib/kernel/src/inet_int.hrl @@ -149,6 +149,7 @@ -define(INET_LOPT_MSGQ_LOWTRMRK, 37). -define(INET_LOPT_NETNS, 38). -define(INET_LOPT_TCP_SHOW_ECONNRESET, 39). +-define(INET_LOPT_LINE_DELIM, 40). % Specific SCTP options: separate range: -define(SCTP_OPT_RTOINFO, 100). -define(SCTP_OPT_ASSOCINFO, 101). diff --git a/lib/kernel/src/inet_tcp.erl b/lib/kernel/src/inet_tcp.erl index b5c758c02c..f551af9709 100644 --- a/lib/kernel/src/inet_tcp.erl +++ b/lib/kernel/src/inet_tcp.erl @@ -27,11 +27,25 @@ -export([controlling_process/2]). -export([fdopen/2]). +-export([family/0, mask/2, parse_address/1]). -export([getserv/1, getaddr/1, getaddr/2, getaddrs/1, getaddrs/2]). - -include("inet_int.hrl"). +%% my address family +family() -> inet. + +%% Apply netmask on address +mask({M1,M2,M3,M4}, {IP1,IP2,IP3,IP4}) -> + {M1 band IP1, + M2 band IP2, + M3 band IP3, + M4 band IP4}. + +%% Parse address string +parse_address(Host) -> + inet_parse:ipv4strict_address(Host). + %% inet_tcp port lookup getserv(Port) when is_integer(Port) -> {ok, Port}; getserv(Name) when is_atom(Name) -> inet:getservbyname(Name,tcp). diff --git a/lib/kernel/src/inet_tcp_dist.erl b/lib/kernel/src/inet_tcp_dist.erl index 1bdc1c9ed8..64b28bb49b 100644 --- a/lib/kernel/src/inet_tcp_dist.erl +++ b/lib/kernel/src/inet_tcp_dist.erl @@ -24,9 +24,13 @@ -export([listen/1, accept/1, accept_connection/5, setup/5, close/1, select/1, is_node_name/1]). +%% Generalized dist API +-export([gen_listen/2, gen_accept/2, gen_accept_connection/6, + gen_setup/6, gen_select/2]). + %% internal exports --export([accept_loop/2,do_accept/6,do_setup/6,getstat/1,tick/1]). +-export([accept_loop/3,do_accept/7,do_setup/7,getstat/1]). -import(error_logger,[error_msg/2]). @@ -34,15 +38,6 @@ --define(to_port(Socket, Data, Opts), - case inet_tcp:send(Socket, Data, Opts) of - {error, closed} -> - self() ! {tcp_closed, Socket}, - {error, closed}; - R -> - R - end). - -include("dist.hrl"). -include("dist_util.hrl"). @@ -53,8 +48,15 @@ %% ------------------------------------------------------------ select(Node) -> + gen_select(inet_tcp, Node). + +gen_select(Driver, Node) -> case split_node(atom_to_list(Node), $@, []) of - [_,_Host] -> true; + [_, Host] -> + case inet:getaddr(Host, Driver:family()) of + {ok,_} -> true; + _ -> false + end; _ -> false end. @@ -64,9 +66,12 @@ select(Node) -> %% ------------------------------------------------------------ listen(Name) -> - case do_listen([{active, false}, {packet,2}, {reuseaddr, true}]) of + gen_listen(inet_tcp, Name). + +gen_listen(Driver, Name) -> + case do_listen(Driver, [{active, false}, {packet,2}, {reuseaddr, true}]) of {ok, Socket} -> - TcpAddress = get_tcp_address(Socket), + TcpAddress = get_tcp_address(Driver, Socket), {_,Port} = TcpAddress#net_address.address, case erl_epmd:register_node(Name, Port) of {ok, Creation} -> @@ -78,7 +83,7 @@ listen(Name) -> Error end. -do_listen(Options) -> +do_listen(Driver, Options) -> {First,Last} = case application:get_env(kernel,inet_dist_listen_min) of {ok,N} when is_integer(N) -> case application:get_env(kernel, @@ -91,14 +96,14 @@ do_listen(Options) -> _ -> {0,0} end, - do_listen(First, Last, listen_options([{backlog,128}|Options])). + do_listen(Driver, First, Last, listen_options([{backlog,128}|Options])). -do_listen(First,Last,_) when First > Last -> +do_listen(_Driver, First,Last,_) when First > Last -> {error,eaddrinuse}; -do_listen(First,Last,Options) -> - case inet_tcp:listen(First, Options) of +do_listen(Driver, First,Last,Options) -> + case Driver:listen(First, Options) of {error, eaddrinuse} -> - do_listen(First+1,Last,Options); + do_listen(Driver, First+1,Last,Options); Other -> Other end. @@ -124,23 +129,26 @@ listen_options(Opts0) -> %% ------------------------------------------------------------ accept(Listen) -> - spawn_opt(?MODULE, accept_loop, [self(), Listen], [link, {priority, max}]). + gen_accept(inet_tcp, Listen). -accept_loop(Kernel, Listen) -> - case inet_tcp:accept(Listen) of +gen_accept(Driver, Listen) -> + spawn_opt(?MODULE, accept_loop, [Driver, self(), Listen], [link, {priority, max}]). + +accept_loop(Driver, Kernel, Listen) -> + case Driver:accept(Listen) of {ok, Socket} -> - Kernel ! {accept,self(),Socket,inet,tcp}, - _ = controller(Kernel, Socket), - accept_loop(Kernel, Listen); + Kernel ! {accept,self(),Socket,Driver:family(),tcp}, + _ = controller(Driver, Kernel, Socket), + accept_loop(Driver, Kernel, Listen); Error -> exit(Error) end. -controller(Kernel, Socket) -> +controller(Driver, Kernel, Socket) -> receive {Kernel, controller, Pid} -> flush_controller(Pid, Socket), - inet_tcp:controlling_process(Socket, Pid), + Driver:controlling_process(Socket, Pid), flush_controller(Pid, Socket), Pid ! {self(), controller}; {Kernel, unsupported_protocol} -> @@ -165,15 +173,18 @@ flush_controller(Pid, Socket) -> %% ------------------------------------------------------------ accept_connection(AcceptPid, Socket, MyNode, Allowed, SetupTime) -> + gen_accept_connection(inet_tcp, AcceptPid, Socket, MyNode, Allowed, SetupTime). + +gen_accept_connection(Driver, AcceptPid, Socket, MyNode, Allowed, SetupTime) -> spawn_opt(?MODULE, do_accept, - [self(), AcceptPid, Socket, MyNode, Allowed, SetupTime], + [Driver, self(), AcceptPid, Socket, MyNode, Allowed, SetupTime], [link, {priority, max}]). -do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) -> +do_accept(Driver, Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) -> receive {AcceptPid, controller} -> Timer = dist_util:start_timer(SetupTime), - case check_ip(Socket) of + case check_ip(Driver, Socket) of true -> HSData = #hs_data{ kernel_pid = Kernel, @@ -182,9 +193,8 @@ do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) -> timer = Timer, this_flags = 0, allowed = Allowed, - f_send = fun(S,D) -> inet_tcp:send(S,D) end, - f_recv = fun(S,N,T) -> inet_tcp:recv(S,N,T) - end, + f_send = fun Driver:send/2, + f_recv = fun Driver:recv/3, f_setopts_pre_nodeup = fun(S) -> inet:setopts(S, @@ -203,8 +213,8 @@ do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) -> f_getll = fun(S) -> inet:getll(S) end, - f_address = fun get_remote_id/2, - mf_tick = fun ?MODULE:tick/1, + f_address = fun(S, Node) -> get_remote_id(Driver, S, Node) end, + mf_tick = fun(S) -> tick(Driver, S) end, mf_getstat = fun ?MODULE:getstat/1 }, dist_util:handshake_other_started(HSData); @@ -235,13 +245,13 @@ nodelay() -> %% ------------------------------------------------------------ %% Get remote information about a Socket. %% ------------------------------------------------------------ -get_remote_id(Socket, Node) -> +get_remote_id(Driver, Socket, Node) -> case inet:peername(Socket) of {ok,Address} -> case split_node(atom_to_list(Node), $@, []) of [_,Host] -> #net_address{address=Address,host=Host, - protocol=tcp,family=inet}; + protocol=tcp,family=Driver:family()}; _ -> %% No '@' or more than one '@' in node name. ?shutdown(no_node) @@ -256,14 +266,18 @@ get_remote_id(Socket, Node) -> %% ------------------------------------------------------------ setup(Node, Type, MyNode, LongOrShortNames,SetupTime) -> + gen_setup(inet_tcp, Node, Type, MyNode, LongOrShortNames, SetupTime). + +gen_setup(Driver, Node, Type, MyNode, LongOrShortNames, SetupTime) -> spawn_opt(?MODULE, do_setup, - [self(), Node, Type, MyNode, LongOrShortNames, SetupTime], + [Driver, self(), Node, Type, MyNode, LongOrShortNames, SetupTime], [link, {priority, max}]). -do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) -> +do_setup(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) -> ?trace("~p~n",[{inet_tcp_dist,self(),setup,Node}]), - [Name, Address] = splitnode(Node, LongOrShortNames), - case inet:getaddr(Address, inet) of + [Name, Address] = splitnode(Driver, Node, LongOrShortNames), + AddressFamily = Driver:family(), + case inet:getaddr(Address, AddressFamily) of {ok, Ip} -> Timer = dist_util:start_timer(SetupTime), case erl_epmd:port_please(Name, Ip) of @@ -272,7 +286,7 @@ do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) -> [Node,Version]), dist_util:reset_timer(Timer), case - inet_tcp:connect( + Driver:connect( Ip, TcpPort, connect_options([{active, false}, {packet, 2}])) of @@ -285,8 +299,8 @@ do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) -> timer = Timer, this_flags = 0, other_version = Version, - f_send = fun inet_tcp:send/2, - f_recv = fun inet_tcp:recv/3, + f_send = fun Driver:send/2, + f_recv = fun Driver:recv/3, f_setopts_pre_nodeup = fun(S) -> inet:setopts @@ -311,9 +325,9 @@ do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) -> address = {Ip,TcpPort}, host = Address, protocol = tcp, - family = inet} + family = AddressFamily} end, - mf_tick = fun ?MODULE:tick/1, + mf_tick = fun(S) -> tick(Driver, S) end, mf_getstat = fun ?MODULE:getstat/1, request_type = Type }, @@ -353,18 +367,23 @@ close(Socket) -> %% If Node is illegal terminate the connection setup!! -splitnode(Node, LongOrShortNames) -> +splitnode(Driver, Node, LongOrShortNames) -> case split_node(atom_to_list(Node), $@, []) of [Name|Tail] when Tail =/= [] -> Host = lists:append(Tail), case split_node(Host, $., []) of [_] when LongOrShortNames =:= longnames -> - error_msg("** System running to use " - "fully qualified " - "hostnames **~n" - "** Hostname ~s is illegal **~n", - [Host]), - ?shutdown(Node); + case Driver:parse_address(Host) of + {ok, _} -> + [Name, Host]; + _ -> + error_msg("** System running to use " + "fully qualified " + "hostnames **~n" + "** Hostname ~s is illegal **~n", + [Host]), + ?shutdown(Node) + end; L when length(L) > 1, LongOrShortNames =:= shortnames -> error_msg("** System NOT running to use fully qualified " "hostnames **~n" @@ -390,26 +409,26 @@ split_node([], _, Ack) -> [lists:reverse(Ack)]. %% ------------------------------------------------------------ %% Fetch local information about a Socket. %% ------------------------------------------------------------ -get_tcp_address(Socket) -> +get_tcp_address(Driver, Socket) -> {ok, Address} = inet:sockname(Socket), {ok, Host} = inet:gethostname(), #net_address { address = Address, host = Host, protocol = tcp, - family = inet + family = Driver:family() }. %% ------------------------------------------------------------ %% Do only accept new connection attempts from nodes at our %% own LAN, if the check_ip environment parameter is true. %% ------------------------------------------------------------ -check_ip(Socket) -> +check_ip(Driver, Socket) -> case application:get_env(check_ip) of {ok, true} -> case get_ifs(Socket) of {ok, IFs, IP} -> - check_ip(IFs, IP); + check_ip(Driver, IFs, IP); _ -> ?shutdown(no_node) end; @@ -428,20 +447,14 @@ get_ifs(Socket) -> Error end. -check_ip([{OwnIP, _, Netmask}|IFs], PeerIP) -> - case {mask(Netmask, PeerIP), mask(Netmask, OwnIP)} of +check_ip(Driver, [{OwnIP, _, Netmask}|IFs], PeerIP) -> + case {Driver:mask(Netmask, PeerIP), Driver:mask(Netmask, OwnIP)} of {M, M} -> true; - _ -> check_ip(IFs, PeerIP) + _ -> check_ip(Driver, IFs, PeerIP) end; -check_ip([], PeerIP) -> +check_ip(_Driver, [], PeerIP) -> {false, PeerIP}. -mask({M1,M2,M3,M4}, {IP1,IP2,IP3,IP4}) -> - {M1 band IP1, - M2 band IP2, - M3 band IP3, - M4 band IP4}. - is_node_name(Node) when is_atom(Node) -> case split_node(atom_to_list(Node), $@, []) of [_, _Host] -> true; @@ -450,8 +463,14 @@ is_node_name(Node) when is_atom(Node) -> is_node_name(_Node) -> false. -tick(Sock) -> - ?to_port(Sock,[],[force]). +tick(Driver, Socket) -> + case Driver:send(Socket, [], [force]) of + {error, closed} -> + self() ! {tcp_closed, Socket}, + {error, closed}; + R -> + R + end. getstat(Socket) -> case inet:getstat(Socket, [recv_cnt, send_cnt, send_pend]) of diff --git a/lib/kernel/src/kernel.app.src b/lib/kernel/src/kernel.app.src index c9327e4f31..419dc0a2fc 100644 --- a/lib/kernel/src/kernel.app.src +++ b/lib/kernel/src/kernel.app.src @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2015. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -116,6 +116,6 @@ {applications, []}, {env, [{error_logger, tty}]}, {mod, {kernel, []}}, - {runtime_dependencies, ["erts-7.0", "stdlib-2.5", "sasl-2.4"]} + {runtime_dependencies, ["erts-7.3", "stdlib-2.6", "sasl-2.6"]} ] }. diff --git a/lib/kernel/src/kernel.appup.src b/lib/kernel/src/kernel.appup.src index 701aafc717..cc9e6f771a 100644 --- a/lib/kernel/src/kernel.appup.src +++ b/lib/kernel/src/kernel.appup.src @@ -18,7 +18,9 @@ %% %CopyrightEnd% {"%VSN%", %% Up from - max one major revision back - [{<<"3\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}], % OTP-17 + [{<<"4\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.* + {<<"3\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}], % OTP-17 %% Down to - max one major revision back - [{<<"3\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}] % OTP-17 + [{<<"4\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.* + {<<"3\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}] % OTP-17 }. diff --git a/lib/kernel/src/seq_trace.erl b/lib/kernel/src/seq_trace.erl index 07ccd3e494..a7a782c29c 100644 --- a/lib/kernel/src/seq_trace.erl +++ b/lib/kernel/src/seq_trace.erl @@ -23,7 +23,9 @@ -define(SEQ_TRACE_SEND, 1). %(1 << 0) -define(SEQ_TRACE_RECEIVE, 2). %(1 << 1) -define(SEQ_TRACE_PRINT, 4). %(1 << 2) --define(SEQ_TRACE_TIMESTAMP, 8). %(1 << 3) +-define(SEQ_TRACE_NOW_TIMESTAMP, 8). %(1 << 3) +-define(SEQ_TRACE_STRICT_MON_TIMESTAMP, 16). %(1 << 4) +-define(SEQ_TRACE_MON_TIMESTAMP, 32). %(1 << 5) -export([set_token/1, set_token/2, @@ -37,7 +39,7 @@ %%--------------------------------------------------------------------------- --type flag() :: 'send' | 'receive' | 'print' | 'timestamp'. +-type flag() :: 'send' | 'receive' | 'print' | 'timestamp' | 'monotonic_timestamp' | 'strict_monotonic_timestamp'. -type component() :: 'label' | 'serial' | flag(). -type value() :: (Integer :: non_neg_integer()) | {Previous :: non_neg_integer(), @@ -135,5 +137,9 @@ decode_flags(Flags) -> Print = (Flags band ?SEQ_TRACE_PRINT) > 0, Send = (Flags band ?SEQ_TRACE_SEND) > 0, Rec = (Flags band ?SEQ_TRACE_RECEIVE) > 0, - Ts = (Flags band ?SEQ_TRACE_TIMESTAMP) > 0, - [{print,Print},{send,Send},{'receive',Rec},{timestamp,Ts}]. + NowTs = (Flags band ?SEQ_TRACE_NOW_TIMESTAMP) > 0, + StrictMonTs = (Flags band ?SEQ_TRACE_STRICT_MON_TIMESTAMP) > 0, + MonTs = (Flags band ?SEQ_TRACE_MON_TIMESTAMP) > 0, + [{print,Print},{send,Send},{'receive',Rec},{timestamp,NowTs}, + {strict_monotonic_timestamp, StrictMonTs}, + {monotonic_timestamp, MonTs}]. diff --git a/lib/kernel/src/user_drv.erl b/lib/kernel/src/user_drv.erl index ca3c53ff93..b794d4f45e 100644 --- a/lib/kernel/src/user_drv.erl +++ b/lib/kernel/src/user_drv.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -559,6 +559,7 @@ put_int16(N, Tail) -> %% is sent back to the process sending the request. This command was added in %% OTP 18 to make sure that data sent from io:format is actually printed %% to the console before the vm stops when calling erlang:halt(integer()). +-dialyzer({no_improper_lists, io_command/1}). io_command({put_chars_sync, unicode,Cs,Reply}) -> {{command,[?OP_PUTC_SYNC|unicode:characters_to_binary(Cs,utf8)]},Reply}; io_command({put_chars, unicode,Cs}) -> diff --git a/lib/kernel/test/bif_SUITE.erl b/lib/kernel/test/bif_SUITE.erl index c3840f3d16..dd3010567a 100644 --- a/lib/kernel/test/bif_SUITE.erl +++ b/lib/kernel/test/bif_SUITE.erl @@ -33,6 +33,7 @@ spawn_failures/1, run_fun/1, + decode_packet_delim/1, wilderness/1]). -export([init_per_testcase/2, end_per_testcase/2]). @@ -516,6 +517,15 @@ fetch_proc_vals(Pid) -> {value,{heap_size,HS}} = lists:keysearch(heap_size, 1, PI), ?line {Ls, P, FA, HS}. +decode_packet_delim(doc) -> + ["Test erlang:packet_delim/3 with {line_delimiter,0} option"]; +decode_packet_delim(suite) -> + []; +decode_packet_delim(Config) when is_list(Config) -> + {ok,<<"abc",0>>,<<"efg",0>>} = + erlang:decode_packet(line, <<"abc",0,"efg",0>>, [{line_delimiter, 0}]), + {more, undefined} = erlang:decode_packet(line, <<"abc",0,"efg",0>>, []). + % This testcase should probably be moved somewhere else wilderness(doc) -> ["Test that memory allocation command line options affecting the" diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl index ef5303defd..73ade14fa1 100644 --- a/lib/kernel/test/code_SUITE.erl +++ b/lib/kernel/test/code_SUITE.erl @@ -323,6 +323,7 @@ load_abs(Config) when is_list(Config) -> {error, nofile} = code:load_abs(TestDir ++ "/duuuumy_mod"), {error, badfile} = code:load_abs(TestDir ++ "/code_a_test"), {'EXIT', _} = (catch code:load_abs({})), + {'EXIT', _} = (catch code:load_abs("Non-latin-имя-файла")), {module, code_b_test} = code:load_abs(TestDir ++ "/code_b_test"), code:stick_dir(TestDir), {error, sticky_directory} = code:load_abs(TestDir ++ "/code_b_test"), @@ -1132,9 +1133,8 @@ mult_lib_roots(Config) when is_list(Config) -> ?t:start_node(mult_lib_roots, slave, [{args,"-env ERL_LIBS "++ErlLibs}]), - TSPath = filename:dirname(code:which(test_server)), Path0 = rpc:call(Node, code, get_path, []), - [TSPath,"."|Path1] = Path0, + ["."|Path1] = Path0, [Kernel|Path2] = Path1, [Stdlib|Path3] = Path2, mult_lib_verify_lib(Kernel, "kernel"), @@ -1178,16 +1178,19 @@ mult_lib_remove_prefix([$/|T], []) -> T. bad_erl_libs(Config) when is_list(Config) -> {ok,Node} = - ?t:start_node(mult_lib_roots, slave, - [{args,"-env ERL_LIBS "}]), - + ?t:start_node(bad_erl_libs, slave, []), + Code = rpc:call(Node,code,get_path,[]), ?t:stop_node(Node), {ok,Node2} = - ?t:start_node(mult_lib_roots, slave, + ?t:start_node(bad_erl_libs, slave, [{args,"-env ERL_LIBS /no/such/dir"}]), - + Code2 = rpc:call(Node,code,get_path,[]), ?t:stop_node(Node2), + + %% Test that code path is not affected by the faulty ERL_LIBS + Code = Code2, + ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1599,6 +1602,17 @@ on_load_errors(Config) when is_list(Config) -> ok end, + %% Make sure that the code loading functions return the correct + %% error code. + Simple = simple_on_load_error, + SimpleList = atom_to_list(Simple), + {error,on_load_failure} = code:load_file(Simple), + {error,on_load_failure} = code:ensure_loaded(Simple), + {ok,SimpleCode} = file:read_file("simple_on_load_error.beam"), + {error,on_load_failure} = code:load_binary(Simple, "", SimpleCode), + {error,on_load_failure} = code:load_abs(SimpleList), + {error,on_load_failure} = code:load_abs(SimpleList, Simple), + ok. do_on_load_error(ReturnValue) -> diff --git a/lib/kernel/test/code_SUITE_data/on_load_errors/simple_on_load_error.erl b/lib/kernel/test/code_SUITE_data/on_load_errors/simple_on_load_error.erl new file mode 100644 index 0000000000..603c282257 --- /dev/null +++ b/lib/kernel/test/code_SUITE_data/on_load_errors/simple_on_load_error.erl @@ -0,0 +1,5 @@ +-module(simple_on_load_error). +-on_load(on_load/0). + +on_load() -> + nope. diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl index 8856be31c2..09d9a45197 100644 --- a/lib/kernel/test/file_SUITE.erl +++ b/lib/kernel/test/file_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2015. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -48,7 +48,7 @@ -export([cur_dir_0/1, cur_dir_1/1, make_del_dir/1, list_dir/1,list_dir_error/1, untranslatable_names/1, untranslatable_names_error/1, - pos1/1, pos2/1]). + pos1/1, pos2/1, pos3/1]). -export([close/1, consult1/1, path_consult/1, delete/1]). -export([ eval1/1, path_eval/1, script1/1, path_script/1, open1/1, @@ -80,6 +80,7 @@ -export([interleaved_read_write/1]). +-export([unicode/1]). -export([altname/1]). -export([large_file/1, large_write/1]). @@ -114,7 +115,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [altname, read_write_file, {group, dirs}, + [unicode, altname, read_write_file, {group, dirs}, {group, files}, delete, rename, names, {group, errors}, {group, compression}, {group, links}, copy, delayed_write, read_ahead, segment_read, segment_write, @@ -136,7 +137,7 @@ groups() -> [open1, old_modes, new_modes, path_open, close, access, read_write, pread_write, append, open_errors, exclusive]}, - {pos, [], [pos1, pos2]}, + {pos, [], [pos1, pos2, pos3]}, {file_info, [], [file_info_basic_file, file_info_basic_directory, file_info_bad, file_info_times, file_write_file_info]}, @@ -1370,6 +1371,27 @@ pos2(Config) when is_list(Config) -> ?line test_server:timetrap_cancel(Dog), ok. +pos3(suite) -> []; +pos3(doc) -> ["When it does not use raw mode, file:position had a bug."]; +pos3(Config) when is_list(Config) -> + ?line Dog = test_server:timetrap(test_server:seconds(5)), + ?line RootDir = ?config(data_dir, Config), + ?line Name = filename:join(RootDir, "realmen.html.gz"), + + ?line {ok, Fd} = ?FILE_MODULE:open(Name, [read, binary]), + ?line {ok, _} = ?FILE_MODULE:read(Fd, 5), + ?line {error, einval} = ?FILE_MODULE:position(Fd, {bof, -1}), + + %% Here ok had returned =( + ?line {error, einval} = ?FILE_MODULE:position(Fd, {cur, -10}), + %% That test is actually questionable since file:position/2 + %% is documented to leave the file position undefined after + %% it has returned an error. But on Posix systems the position + %% is guaranteed to be unchanged after an error return. On e.g + %% Windows there is nothing stated about this in the documentation. + + ?line test_server:timetrap_cancel(Dog), + ok. file_info_basic_file(suite) -> []; file_info_basic_file(doc) -> []; @@ -2761,6 +2783,40 @@ compress_async_crash_loop(N, Path, ExpectedData) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +unicode(Config) when is_list(Config) -> + Dir = ?config(priv_dir, Config), + Name = filename:join(Dir, "data-utf8.txt"), + Txt = lists:seq(128, 255), + D = unicode:characters_to_binary(Txt, latin1, latin1), + {ok,Fd1} = + ?FILE_MODULE:open(Name, [write,read,binary,{encoding,unicode}]), + ok = ?FILE_MODULE:truncate(Fd1), + ok = ?FILE_MODULE:write(Fd1, Txt), + {ok,0} = ?FILE_MODULE:position(Fd1, bof), + {ok,D} = ?FILE_MODULE:read(Fd1, 129), + {ok,0} = ?FILE_MODULE:position(Fd1, bof), + {ok,D1} = ?FILE_MODULE:read(Fd1, 64), + {ok,Pos} = ?FILE_MODULE:position(Fd1, cur), + {ok,D2} = ?FILE_MODULE:pread(Fd1, {cur,0}, 65), + D = <<D1/binary, D2/binary>>, + {ok,D1} = ?FILE_MODULE:pread(Fd1, bof, 64), + {ok,Pos} = ?FILE_MODULE:position(Fd1, Pos), + {ok,D2} = ?FILE_MODULE:read(Fd1, 64), + ok = ?FILE_MODULE:close(Fd1), + %% + RawD = unicode:characters_to_binary(Txt, latin1, unicode), + {ok,RawD} = ?FILE_MODULE:read_file(Name), + %% + {ok,Fd2} = ?FILE_MODULE:open(Name, [read,{encoding,unicode}]), + {ok,Txt} = ?FILE_MODULE:read(Fd2, 129), + {Txt1,Txt2} = lists:split(64, Txt), + {ok,Txt2} = ?FILE_MODULE:pread(Fd2, Pos, 65), + {ok,0} = ?FILE_MODULE:position(Fd2, bof), + {ok,Txt1} = ?FILE_MODULE:read(Fd2, 64), + ok = ?FILE_MODULE:close(Fd2). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + altname(doc) -> "Test the file:altname/1 function"; altname(suite) -> diff --git a/lib/kernel/test/gen_tcp_api_SUITE.erl b/lib/kernel/test/gen_tcp_api_SUITE.erl index a051d504b2..962471c20c 100644 --- a/lib/kernel/test/gen_tcp_api_SUITE.erl +++ b/lib/kernel/test/gen_tcp_api_SUITE.erl @@ -31,7 +31,7 @@ init_per_testcase/2, end_per_testcase/2, t_connect_timeout/1, t_accept_timeout/1, t_connect_bad/1, - t_recv_timeout/1, t_recv_eof/1, + t_recv_timeout/1, t_recv_eof/1, t_recv_delim/1, t_shutdown_write/1, t_shutdown_both/1, t_shutdown_error/1, t_shutdown_async/1, t_fdopen/1, t_fdconnect/1, t_implicit_inet6/1]). @@ -48,7 +48,7 @@ all() -> groups() -> [{t_accept, [], [t_accept_timeout]}, {t_connect, [], [t_connect_timeout, t_connect_bad]}, - {t_recv, [], [t_recv_timeout, t_recv_eof]}]. + {t_recv, [], [t_recv_timeout, t_recv_eof, t_recv_delim]}]. @@ -131,6 +131,21 @@ t_recv_eof(Config) when is_list(Config) -> ?line {error, closed} = gen_tcp:recv(Client, 0), ok. +t_recv_delim(doc) -> "Test using message delimiter $X"; +t_recv_delim(suite) -> []; +t_recv_delim(Config) when is_list(Config) -> + {ok, L} = gen_tcp:listen(0, []), + {ok, Port} = inet:port(L), + Opts = [{active,false},{packet,line},{line_delimiter,$X}], + {ok, Client} = gen_tcp:connect(localhost, Port, Opts), + {ok, A} = gen_tcp:accept(L), + ok = gen_tcp:send(A, "abcXefgX"), + {ok, "abcX"} = gen_tcp:recv(Client, 0, 0), + {ok, "efgX"} = gen_tcp:recv(Client, 0, 0), + ok = gen_tcp:close(Client), + ok = gen_tcp:close(A), + ok. + %%% gen_tcp:shutdown/2 t_shutdown_write(Config) when is_list(Config) -> diff --git a/lib/kernel/test/heart_SUITE.erl b/lib/kernel/test/heart_SUITE.erl index 83efbb4c35..39cd29cea0 100644 --- a/lib/kernel/test/heart_SUITE.erl +++ b/lib/kernel/test/heart_SUITE.erl @@ -27,6 +27,8 @@ node_start_immediately_after_crash/1, node_start_soon_after_crash/1, set_cmd/1, clear_cmd/1, get_cmd/1, + callback_api/1, + options_api/1, dont_drop/1, kill_pid/1]). -export([init_per_testcase/2, end_per_testcase/2]). @@ -66,6 +68,8 @@ all() -> [ node_start_immediately_after_crash, node_start_soon_after_crash, set_cmd, clear_cmd, get_cmd, + callback_api, + options_api, kill_pid ]. @@ -358,6 +362,69 @@ get_cmd(Config) when is_list(Config) -> stop_node(Node), ok. +callback_api(Config) when is_list(Config) -> + {ok, Node} = start_check(slave, heart_test), + none = rpc:call(Node, heart, get_callback, []), + M0 = self(), + F0 = ok, + {error, {bad_callback, {M0,F0}}} = rpc:call(Node, heart, set_callback, [M0,F0]), + none = rpc:call(Node, heart, get_callback, []), + M1 = lists:duplicate(28, $a), + F1 = lists:duplicate(28, $b), + {error, {bad_callback, {M1,F1}}} = rpc:call(Node, heart, set_callback, [M1,F1]), + none = rpc:call(Node, heart, get_callback, []), + + M2 = heart_check_module, + F2 = cb_ok, + F3 = cb_error, + Code0 = generate(M2, [], [ + atom_to_list(F2) ++ "() -> ok.", + atom_to_list(F3) ++ "() -> exit(\"callback_error (as intended)\")." + ]), + {module, M2} = rpc:call(Node, erlang, load_module, [M2, Code0]), + ok = rpc:call(Node, M2, F2, []), + ok = rpc:call(Node, heart, set_callback, [M2,F2]), + {ok, {M2,F2}} = rpc:call(Node, heart, get_callback, []), + ok = rpc:call(Node, heart, clear_callback, []), + none = rpc:call(Node, heart, get_callback, []), + ok = rpc:call(Node, heart, set_callback, [M2,F2]), + {ok, {M2,F2}} = rpc:call(Node, heart, get_callback, []), + ok = rpc:call(Node, heart, set_callback, [M2,F3]), + receive {nodedown, Node} -> ok + after 5000 -> test_server:fail(node_not_killed) + end, + stop_node(Node), + ok. + +options_api(Config) when is_list(Config) -> + {ok, Node} = start_check(slave, heart_test), + none = rpc:call(Node, heart, get_options, []), + M0 = self(), + F0 = ok, + {error, {bad_options, {M0,F0}}} = rpc:call(Node, heart, set_options, [{M0,F0}]), + none = rpc:call(Node, heart, get_options, []), + Ls = lists:duplicate(28, $b), + {error, {bad_options, Ls}} = rpc:call(Node, heart, set_options, [Ls]), + none = rpc:call(Node, heart, get_options, []), + + ok = rpc:call(Node, heart, set_options, [[check_schedulers]]), + {ok, [check_schedulers]} = rpc:call(Node, heart, get_options, []), + ok = rpc:call(Node, heart, set_options, [[]]), + none = rpc:call(Node, heart, get_options, []), + + ok = rpc:call(Node, heart, set_options, [[check_schedulers]]), + {ok, [check_schedulers]} = rpc:call(Node, heart, get_options, []), + {error, {bad_options, Ls}} = rpc:call(Node, heart, set_options, [Ls]), + {ok, [check_schedulers]} = rpc:call(Node, heart, get_options, []), + + receive after 3000 -> ok end, %% wait 3 secs + + ok = rpc:call(Node, heart, set_options, [[]]), + none = rpc:call(Node, heart, get_options, []), + stop_node(Node), + ok. + + dont_drop(suite) -> %%% Removed as it may crash epmd/distribution in colourful %%% ways. While we ARE finding out WHY, it would diff --git a/lib/kernel/test/inet_sockopt_SUITE.erl b/lib/kernel/test/inet_sockopt_SUITE.erl index 1262f36fae..cb522c8abe 100644 --- a/lib/kernel/test/inet_sockopt_SUITE.erl +++ b/lib/kernel/test/inet_sockopt_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2013. All Rights Reserved. +%% Copyright Ericsson AB 2007-2015. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -52,6 +52,7 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, simple/1, loop_all/1, simple_raw/1, simple_raw_getbin/1, + multiple_raw/1, multiple_raw_getbin/1, doc_examples_raw/1,doc_examples_raw_getbin/1, large_raw/1,large_raw_getbin/1,combined/1,combined_getbin/1, ipv6_v6only_udp/1, ipv6_v6only_tcp/1, ipv6_v6only_sctp/1, @@ -65,6 +66,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [simple, loop_all, simple_raw, simple_raw_getbin, + multiple_raw, multiple_raw_getbin, doc_examples_raw, doc_examples_raw_getbin, large_raw, large_raw_getbin, combined, combined_getbin, ipv6_v6only_udp, ipv6_v6only_tcp, ipv6_v6only_sctp, @@ -185,6 +187,84 @@ nintbin2int(<<Int:16/native>>) -> Int; nintbin2int(<<Int:8/native>>) -> Int; nintbin2int(<<>>) -> 0. + + +multiple_raw(suite) -> []; +multiple_raw(doc) -> "Test setopt/getopt of multiple raw options."; +multiple_raw(Config) when is_list(Config) -> + do_multiple_raw(Config,false). +multiple_raw_getbin(suite) -> []; +multiple_raw_getbin(doc) -> "Test setopt/getopt of multiple raw options, " + "with binaries in getopt."; +multiple_raw_getbin(Config) when is_list(Config) -> + do_multiple_raw(Config,true). + +do_multiple_raw(Config, Binary) -> + Port = start_helper(Config), + SolSocket = ask_helper(Port, ?C_GET_SOL_SOCKET), + SoKeepalive = ask_helper(Port, ?C_GET_SO_KEEPALIVE), + SoKeepaliveTrue = {raw,SolSocket,SoKeepalive,<<1:32/native>>}, + SoKeepaliveFalse = {raw,SolSocket,SoKeepalive,<<0:32/native>>}, + SoReuseaddr = ask_helper(Port, ?C_GET_SO_REUSEADDR), + SoReuseaddrTrue = {raw,SolSocket,SoReuseaddr,<<1:32/native>>}, + SoReuseaddrFalse = {raw,SolSocket,SoReuseaddr,<<0:32/native>>}, + {S1,S2} = + create_socketpair( + [SoReuseaddrFalse,SoKeepaliveTrue], + [SoKeepaliveFalse,SoReuseaddrTrue]), + {ok,[{reuseaddr,false},{keepalive,true}]} = + inet:getopts(S1, [reuseaddr,keepalive]), + {ok, + [{raw,SolSocket,SoReuseaddr,S1R1}, + {raw,SolSocket,SoKeepalive,S1K1}]} = + inet:getopts( + S1, + [{raw,SolSocket,SoReuseaddr,binarify(4, Binary)}, + {raw,SolSocket,SoKeepalive,binarify(4, Binary)}]), + true = nintbin2int(S1R1) =:= 0, + true = nintbin2int(S1K1) =/= 0, + {ok,[{keepalive,false},{reuseaddr,true}]} = + inet:getopts(S2, [keepalive,reuseaddr]), + {ok, + [{raw,SolSocket,SoKeepalive,S2K1}, + {raw,SolSocket,SoReuseaddr,S2R1}]} = + inet:getopts( + S2, + [{raw,SolSocket,SoKeepalive,binarify(4, Binary)}, + {raw,SolSocket,SoReuseaddr,binarify(4, Binary)}]), + true = nintbin2int(S2K1) =:= 0, + true = nintbin2int(S2R1) =/= 0, + %% + ok = inet:setopts( + S1, [SoReuseaddrTrue,SoKeepaliveFalse]), + ok = inet:setopts( + S2, [SoKeepaliveTrue,SoReuseaddrFalse]), + {ok, + [{raw,SolSocket,SoReuseaddr,S1R2}, + {raw,SolSocket,SoKeepalive,S1K2}]} = + inet:getopts( + S1, + [{raw,SolSocket,SoReuseaddr,binarify(4, Binary)}, + {raw,SolSocket,SoKeepalive,binarify(4, Binary)}]), + true = nintbin2int(S1R2) =/= 0, + true = nintbin2int(S1K2) =:= 0, + {ok, + [{raw,SolSocket,SoKeepalive,S2K2}, + {raw,SolSocket,SoReuseaddr,S2R2}]} = + inet:getopts( + S2, + [{raw,SolSocket,SoKeepalive,binarify(4, Binary)}, + {raw,SolSocket,SoReuseaddr,binarify(4, Binary)}]), + true = nintbin2int(S2K2) =/= 0, + true = nintbin2int(S2R2) =:= 0, + %% + gen_tcp:close(S1), + gen_tcp:close(S2), + stop_helper(Port), + ok. + + + doc_examples_raw(suite) -> []; doc_examples_raw(doc) -> "Test that the example code from the documentation " "works"; diff --git a/lib/kernel/test/seq_trace_SUITE.erl b/lib/kernel/test/seq_trace_SUITE.erl index 7df0bc3d2f..6a63f7bc9c 100644 --- a/lib/kernel/test/seq_trace_SUITE.erl +++ b/lib/kernel/test/seq_trace_SUITE.erl @@ -35,6 +35,11 @@ %-define(line_trace, 1). -include_lib("test_server/include/test_server.hrl"). +-define(TIMESTAMP_MODES, [no_timestamp, + timestamp, + monotonic_timestamp, + strict_monotonic_timestamp]). + -define(default_timeout, ?t:minutes(1)). suite() -> [{ct_hooks,[ts_install_cth]}]. @@ -75,6 +80,17 @@ end_per_testcase(_Case, Config) -> token_set_get(doc) -> []; token_set_get(suite) -> []; token_set_get(Config) when is_list(Config) -> + do_token_set_get(timestamp), + do_token_set_get(monotonic_timestamp), + do_token_set_get(strict_monotonic_timestamp). + +do_token_set_get(TsType) -> + io:format("Testing ~p~n", [TsType]), + Flags = case TsType of + timestamp -> 15; + strict_monotonic_timestamp -> 23; + monotonic_timestamp -> 39 + end, ?line Self = self(), ?line seq_trace:reset_trace(), %% Test that initial seq_trace is disabled @@ -88,22 +104,22 @@ token_set_get(Config) when is_list(Config) -> ?line {send,true} = seq_trace:get_token(send), ?line false = seq_trace:set_token('receive',true), ?line {'receive',true} = seq_trace:get_token('receive'), - ?line false = seq_trace:set_token(timestamp,true), - ?line {timestamp,true} = seq_trace:get_token(timestamp), + ?line false = seq_trace:set_token(TsType,true), + ?line {TsType,true} = seq_trace:get_token(TsType), %% Check the whole token - ?line {15,17,0,Self,0} = seq_trace:get_token(), % all flags are set + ?line {Flags,17,0,Self,0} = seq_trace:get_token(), % all flags are set %% Test setting and reading the 'serial' field ?line {0,0} = seq_trace:set_token(serial,{3,5}), ?line {serial,{3,5}} = seq_trace:get_token(serial), %% Check the whole token, test that a whole token can be set and get - ?line {15,17,5,Self,3} = seq_trace:get_token(), - ?line seq_trace:set_token({15,19,7,Self,5}), - ?line {15,19,7,Self,5} = seq_trace:get_token(), + ?line {Flags,17,5,Self,3} = seq_trace:get_token(), + ?line seq_trace:set_token({Flags,19,7,Self,5}), + ?line {Flags,19,7,Self,5} = seq_trace:get_token(), %% Check that receive timeout does not reset token ?line receive after 0 -> ok end, - ?line {15,19,7,Self,5} = seq_trace:get_token(), + ?line {Flags,19,7,Self,5} = seq_trace:get_token(), %% Check that token can be unset - ?line {15,19,7,Self,5} = seq_trace:set_token([]), + ?line {Flags,19,7,Self,5} = seq_trace:set_token([]), ?line [] = seq_trace:get_token(), %% Check that Previous serial counter survived unset token ?line 0 = seq_trace:set_token(label, 17), @@ -139,30 +155,42 @@ tracer_set_get(Config) when is_list(Config) -> print(doc) -> []; print(suite) -> []; print(Config) when is_list(Config) -> + lists:foreach(fun do_print/1, ?TIMESTAMP_MODES). + +do_print(TsType) -> ?line start_tracer(), - ?line seq_trace:set_token(print,true), + ?line set_token_flags([print, TsType]), ?line seq_trace:print(0,print1), ?line seq_trace:print(1,print2), ?line seq_trace:print(print3), ?line seq_trace:reset_trace(), - ?line [{0,{print,_,_,[],print1}}, - {0,{print,_,_,[],print3}}] = stop_tracer(2). + ?line [{0,{print,_,_,[],print1}, Ts0}, + {0,{print,_,_,[],print3}, Ts1}] = stop_tracer(2), + check_ts(TsType, Ts0), + check_ts(TsType, Ts1). send(doc) -> []; send(suite) -> []; send(Config) when is_list(Config) -> + lists:foreach(fun do_send/1, ?TIMESTAMP_MODES). + +do_send(TsType) -> ?line seq_trace:reset_trace(), ?line start_tracer(), ?line Receiver = spawn(?MODULE,one_time_receiver,[]), - ?line seq_trace:set_token(send,true), + ?line set_token_flags([send, TsType]), ?line Receiver ! send, ?line Self = self(), ?line seq_trace:reset_trace(), - ?line [{0,{send,_,Self,Receiver,send}}] = stop_tracer(1). + ?line [{0,{send,_,Self,Receiver,send}, Ts}] = stop_tracer(1), + check_ts(TsType, Ts). distributed_send(doc) -> []; distributed_send(suite) -> []; distributed_send(Config) when is_list(Config) -> + lists:foreach(fun do_distributed_send/1, ?TIMESTAMP_MODES). + +do_distributed_send(TsType) -> ?line {ok,Node} = start_node(seq_trace_other,[]), ?line {_,Dir} = code:is_loaded(?MODULE), ?line Mdir = filename:dirname(Dir), @@ -170,30 +198,39 @@ distributed_send(Config) when is_list(Config) -> ?line seq_trace:reset_trace(), ?line start_tracer(), ?line Receiver = spawn(Node,?MODULE,one_time_receiver,[]), - ?line seq_trace:set_token(send,true), + ?line set_token_flags([send,TsType]), ?line Receiver ! send, ?line Self = self(), ?line seq_trace:reset_trace(), ?line stop_node(Node), - ?line [{0,{send,_,Self,Receiver,send}}] = stop_tracer(1). + ?line [{0,{send,_,Self,Receiver,send}, Ts}] = stop_tracer(1), + check_ts(TsType, Ts). + recv(doc) -> []; recv(suite) -> []; recv(Config) when is_list(Config) -> + lists:foreach(fun do_recv/1, ?TIMESTAMP_MODES). + +do_recv(TsType) -> ?line seq_trace:reset_trace(), ?line start_tracer(), ?line Receiver = spawn(?MODULE,one_time_receiver,[]), - ?line seq_trace:set_token('receive',true), + ?line set_token_flags(['receive',TsType]), ?line Receiver ! 'receive', %% let the other process receive the message: ?line receive after 1 -> ok end, ?line Self = self(), ?line seq_trace:reset_trace(), - ?line [{0,{'receive',_,Self,Receiver,'receive'}}] = stop_tracer(1). + ?line [{0,{'receive',_,Self,Receiver,'receive'}, Ts}] = stop_tracer(1), + check_ts(TsType, Ts). distributed_recv(doc) -> []; distributed_recv(suite) -> []; distributed_recv(Config) when is_list(Config) -> + lists:foreach(fun do_distributed_recv/1, ?TIMESTAMP_MODES). + +do_distributed_recv(TsType) -> ?line {ok,Node} = start_node(seq_trace_other,[]), ?line {_,Dir} = code:is_loaded(?MODULE), ?line Mdir = filename:dirname(Dir), @@ -201,7 +238,7 @@ distributed_recv(Config) when is_list(Config) -> ?line seq_trace:reset_trace(), ?line rpc:call(Node,?MODULE,start_tracer,[]), ?line Receiver = spawn(Node,?MODULE,one_time_receiver,[]), - ?line seq_trace:set_token('receive',true), + ?line set_token_flags(['receive',TsType]), ?line Receiver ! 'receive', %% let the other process receive the message: ?line receive after 1 -> ok end, @@ -210,16 +247,20 @@ distributed_recv(Config) when is_list(Config) -> ?line Result = rpc:call(Node,?MODULE,stop_tracer,[1]), ?line stop_node(Node), ?line ok = io:format("~p~n",[Result]), - ?line [{0,{'receive',_,Self,Receiver,'receive'}}] = Result. + ?line [{0,{'receive',_,Self,Receiver,'receive'}, Ts}] = Result, + check_ts(TsType, Ts). trace_exit(doc) -> []; trace_exit(suite) -> []; trace_exit(Config) when is_list(Config) -> + lists:foreach(fun do_trace_exit/1, ?TIMESTAMP_MODES). + +do_trace_exit(TsType) -> ?line seq_trace:reset_trace(), ?line start_tracer(), ?line Receiver = spawn_link(?MODULE, one_time_receiver, [exit]), ?line process_flag(trap_exit, true), - ?line seq_trace:set_token(send,true), + ?line set_token_flags([send, TsType]), ?line Receiver ! {before, exit}, %% let the other process receive the message: ?line receive @@ -233,13 +274,18 @@ trace_exit(Config) when is_list(Config) -> ?line Result = stop_tracer(2), ?line seq_trace:reset_trace(), ?line ok = io:format("~p~n", [Result]), - ?line [{0, {send, {0,1}, Self, Receiver, {before, exit}}}, + ?line [{0, {send, {0,1}, Self, Receiver, {before, exit}}, Ts0}, {0, {send, {1,2}, Receiver, Self, - {'EXIT', Receiver, {exit, {before, exit}}}}}] = Result. + {'EXIT', Receiver, {exit, {before, exit}}}}, Ts1}] = Result, + check_ts(TsType, Ts0), + check_ts(TsType, Ts1). distributed_exit(doc) -> []; distributed_exit(suite) -> []; distributed_exit(Config) when is_list(Config) -> + lists:foreach(fun do_distributed_exit/1, ?TIMESTAMP_MODES). + +do_distributed_exit(TsType) -> ?line {ok, Node} = start_node(seq_trace_other, []), ?line {_, Dir} = code:is_loaded(?MODULE), ?line Mdir = filename:dirname(Dir), @@ -248,7 +294,7 @@ distributed_exit(Config) when is_list(Config) -> ?line rpc:call(Node, ?MODULE, start_tracer,[]), ?line Receiver = spawn_link(Node, ?MODULE, one_time_receiver, [exit]), ?line process_flag(trap_exit, true), - ?line seq_trace:set_token(send, true), + ?line set_token_flags([send, TsType]), ?line Receiver ! {before, exit}, %% let the other process receive the message: ?line receive @@ -264,7 +310,8 @@ distributed_exit(Config) when is_list(Config) -> ?line stop_node(Node), ?line ok = io:format("~p~n", [Result]), ?line [{0, {send, {1, 2}, Receiver, Self, - {'EXIT', Receiver, {exit, {before, exit}}}}}] = Result. + {'EXIT', Receiver, {exit, {before, exit}}}}, Ts}] = Result, + check_ts(TsType, Ts). call(doc) -> "Tests special forms {is_seq_trace} and {get_seq_token} " @@ -361,14 +408,22 @@ port(doc) -> "Send trace messages to a port."; port(suite) -> []; port(Config) when is_list(Config) -> + lists:foreach(fun (TsType) -> do_port(TsType, Config) end, + ?TIMESTAMP_MODES). + +do_port(TsType, Config) -> + io:format("Testing ~p~n",[TsType]), ?line Port = load_tracer(Config), ?line seq_trace:set_system_tracer(Port), - ?line seq_trace:set_token(print, true), + ?line set_token_flags([print, TsType]), ?line Small = [small,term], ?line seq_trace:print(0, Small), ?line case get_port_message(Port) of - {seq_trace,0,{print,_,_,[],Small}} -> + {seq_trace,0,{print,_,_,[],Small}} when TsType == no_timestamp -> + ok; + {seq_trace,0,{print,_,_,[],Small},Ts0} when TsType /= no_timestamp -> + check_ts(TsType, Ts0), ok; Other -> ?line seq_trace:reset_trace(), @@ -382,7 +437,10 @@ port(Config) when is_list(Config) -> ?line seq_trace:print(0, OtherSmall), ?line seq_trace:reset_trace(), ?line case get_port_message(Port) of - {seq_trace,0,{print,_,_,[],OtherSmall}} -> + {seq_trace,0,{print,_,_,[],OtherSmall}} when TsType == no_timestamp -> + ok; + {seq_trace,0,{print,_,_,[],OtherSmall}, Ts1} when TsType /= no_timestamp -> + check_ts(TsType, Ts1), ok; Other1 -> ?line ?t:fail({unexpected,Other1}) @@ -399,6 +457,8 @@ port(Config) when is_list(Config) -> Other2 -> ?line ?t:fail({unexpected,Other2}) end, + unlink(Port), + exit(Port,kill), ok. get_port_message(Port) -> @@ -734,7 +794,7 @@ simple_tracer(Data, DN) -> {seq_trace,Label,Info,Ts} -> simple_tracer([{Label,Info,Ts}|Data], DN+1); {seq_trace,Label,Info} -> - simple_tracer([{Label,Info}|Data], DN+1); + simple_tracer([{Label,Info, no_timestamp}|Data], DN+1); {stop,N,From} when DN >= N -> From ! {tracerlog,lists:reverse(Data)} end. @@ -759,7 +819,55 @@ start_tracer() -> seq_trace:set_system_tracer(Pid), Pid. - + +set_token_flags([]) -> + ok; +set_token_flags([no_timestamp|Flags]) -> + seq_trace:set_token(timestamp, false), + seq_trace:set_token(monotonic_timestamp, false), + seq_trace:set_token(strict_monotonic_timestamp, false), + set_token_flags(Flags); +set_token_flags([Flag|Flags]) -> + seq_trace:set_token(Flag, true), + set_token_flags(Flags). + +check_ts(no_timestamp, Ts) -> + try + no_timestamp = Ts + catch + _ : _ -> + ?t:fail({unexpected_timestamp, Ts}) + end, + ok; +check_ts(timestamp, Ts) -> + try + {Ms,S,Us} = Ts, + true = is_integer(Ms), + true = is_integer(S), + true = is_integer(Us) + catch + _ : _ -> + ?t:fail({unexpected_timestamp, Ts}) + end, + ok; +check_ts(monotonic_timestamp, Ts) -> + try + true = is_integer(Ts) + catch + _ : _ -> + ?t:fail({unexpected_timestamp, Ts}) + end, + ok; +check_ts(strict_monotonic_timestamp, Ts) -> + try + {MT, UMI} = Ts, + true = is_integer(MT), + true = is_integer(UMI) + catch + _ : _ -> + ?t:fail({unexpected_timestamp, Ts}) + end, + ok. start_node(Name, Param) -> test_server:start_node(Name, slave, [{args, Param}]). diff --git a/lib/kernel/test/standard_error_SUITE.erl b/lib/kernel/test/standard_error_SUITE.erl index e8917bbd47..97ead9b9fd 100644 --- a/lib/kernel/test/standard_error_SUITE.erl +++ b/lib/kernel/test/standard_error_SUITE.erl @@ -21,13 +21,13 @@ -module(standard_error_SUITE). -export([all/0,suite/0]). --export([badarg/1,getopts/1]). +-export([badarg/1,getopts/1,output/1]). suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [badarg,getopts]. + [badarg,getopts,output]. badarg(Config) when is_list(Config) -> {'EXIT',{badarg,_}} = (catch io:put_chars(standard_error, [oops])), @@ -37,3 +37,30 @@ badarg(Config) when is_list(Config) -> getopts(Config) when is_list(Config) -> [{encoding,latin1}] = io:getopts(standard_error), ok. + +%% Test that writing a lot of output to standard_error does not cause the +%% processes handling it to terminate like this: +%% +%% =ERROR REPORT==== 9-Aug-2015::23:19:23 === +%% ** Generic server standard_error_sup terminating +%% ** Last message in was {'EXIT',<0.28.0>,eagain} +%% ** When Server state == {state,standard_error,undefined,<0.28.0>, +%% {local,standard_error_sup}} +%% ** Reason for termination == +%% ** eagain +%% +%% This problem, observed with Erlang 18.0.2, was fixed in fd_driver by +%% properly handling EAGAIN if it arises on file descriptor writes. +%% +output(Config) when is_list(Config) -> + Ref = monitor(process, standard_error_sup), + Chars = [ [["1234567890" || _ <- lists:seq(1,10)], $\s, + integer_to_list(L), $\r, $\n] || L <- lists:seq(1, 100) ], + ok = io:put_chars(standard_error, Chars), + receive + {'DOWN', Ref, process, _, _} -> + error(standard_error_noproc) + after + 500 -> + ok + end. diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk index c912da0091..c8917ebc3c 100644 --- a/lib/kernel/vsn.mk +++ b/lib/kernel/vsn.mk @@ -1 +1 @@ -KERNEL_VSN = 4.0 +KERNEL_VSN = 4.2 diff --git a/lib/mnesia/doc/src/notes.xml b/lib/mnesia/doc/src/notes.xml index c4f937f183..18bb110104 100644 --- a/lib/mnesia/doc/src/notes.xml +++ b/lib/mnesia/doc/src/notes.xml @@ -39,7 +39,71 @@ thus constitutes one section in this document. The title of each section is the version number of Mnesia.</p> - <section><title>Mnesia 4.13</title> + <section><title>Mnesia 4.13.4</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Mnesia transactions could hang while waiting on a + response from a node who had stopped.</p> + <p> + Own Id: OTP-13423</p> + </item> + </list> + </section> + +</section> + +<section><title>Mnesia 4.13.3</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Avoid deadlock possibility in + <c>mnesia:del_table_copy/2</c></p> + <p> + Own Id: OTP-13284</p> + </item> + </list> + </section> + +</section> + +<section><title>Mnesia 4.13.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fixed a process and file descriptor leak in + mnesia:restore/2.</p> + <p> + Own Id: OTP-13025 Aux Id: seq12957 </p> + </item> + </list> + </section> + +</section> + +<section><title>Mnesia 4.13.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Improved index updates to avoid a timing glitch in + dirty_index_read.</p> + <p> + Own Id: OTP-12972</p> + </item> + </list> + </section> + +</section> + +<section><title>Mnesia 4.13</title> <section><title>Fixed Bugs and Malfunctions</title> <list> diff --git a/lib/mnesia/examples/bench/bench_generate.erl b/lib/mnesia/examples/bench/bench_generate.erl index 7a701812a7..e838f07fbb 100644 --- a/lib/mnesia/examples/bench/bench_generate.erl +++ b/lib/mnesia/examples/bench/bench_generate.erl @@ -153,9 +153,7 @@ generator_init(Monitor, C) -> process_flag(trap_exit, true), Tables = mnesia:system_info(tables), ok = mnesia:wait_for_tables(Tables, infinity), - {_Mega, Sec, Micro} = erlang:now(), - Uniq = lists:sum(binary_to_list(term_to_binary(make_ref()))), - random:seed(Uniq, Sec, Micro), + rand:seed(exsplus), Counters = reset_counters(C, C#config.statistics_detail), SessionTab = ets:new(bench_sessions, [public, {keypos, 1}]), generator_loop(Monitor, C, SessionTab, Counters). @@ -189,9 +187,9 @@ generator_loop(Monitor, C, SessionTab, Counters) -> after 0 -> {Name, {Nodes, Activity, Wlock}, Fun, CommitSessions} = gen_trans(C, SessionTab), - Before = erlang:now(), + Before = erlang:monotonic_time(), Res = call_worker(Nodes, Activity, Fun, Wlock, mnesia_frag), - After = erlang:now(), + After = erlang:monotonic_time(), Elapsed = elapsed(Before, After), post_eval(Monitor, C, Elapsed, Res, Name, CommitSessions, SessionTab, Counters) end. @@ -253,10 +251,8 @@ worker_loop(Parent) -> end. -elapsed({Before1, Before2, Before3}, {After1, After2, After3}) -> - After = After1 * 1000000000000 + After2 * 1000000 + After3, - Before = Before1 * 1000000000000 + Before2 * 1000000 + Before3, - After - Before. +elapsed(Before, After) -> + erlang:convert_time_unit(After-Before, native, micro_seconds). %% Lookup counters get_counters(_C, {table, Tab}) -> @@ -351,7 +347,7 @@ commit_session(Fun) when is_function(Fun, 0) -> %% Randlomly choose a transaction type according to benchmar spec gen_trans(C, SessionTab) when C#config.generator_profile == random -> - case random:uniform(100) of + case rand:uniform(100) of Rand when Rand > 0, Rand =< 25 -> gen_t1(C, SessionTab); Rand when Rand > 25, Rand =< 50 -> gen_t2(C, SessionTab); Rand when Rand > 50, Rand =< 70 -> gen_t3(C, SessionTab); @@ -369,7 +365,7 @@ gen_trans(C, SessionTab) -> end. gen_t1(C, _SessionTab) -> - SubscrId = random:uniform(C#config.n_subscribers) - 1, + SubscrId = rand:uniform(C#config.n_subscribers) - 1, SubscrKey = bench_trans:number_to_key(SubscrId, C), Location = 4711, ChangedBy = <<4711:(8*25)>>, @@ -381,7 +377,7 @@ gen_t1(C, _SessionTab) -> }. gen_t2(C, _SessionTab) -> - SubscrId = random:uniform(C#config.n_subscribers) - 1, + SubscrId = rand:uniform(C#config.n_subscribers) - 1, SubscrKey = bench_trans:number_to_key(SubscrId, C), {t2, nearest_node(SubscrId, sync_dirty, C), @@ -395,9 +391,9 @@ gen_t3(C, SessionTab) -> '$end_of_table' -> %% This generator does not have any session, %% try reading someone elses session details - SubscrId = random:uniform(C#config.n_subscribers) - 1, + SubscrId = rand:uniform(C#config.n_subscribers) - 1, SubscrKey = bench_trans:number_to_key(SubscrId, C), - ServerId = random:uniform(C#config.n_servers) - 1, + ServerId = rand:uniform(C#config.n_servers) - 1, ServerBit = 1 bsl ServerId, {t3, nearest_node(SubscrId, transaction, C), @@ -419,12 +415,12 @@ gen_t4(C, SessionTab) -> %% This generator may already have sessions, %% create a new session and hope that no other %% generator already has occupied it - SubscrId = random:uniform(C#config.n_subscribers) - 1, + SubscrId = rand:uniform(C#config.n_subscribers) - 1, SubscrKey = bench_trans:number_to_key(SubscrId, C), - ServerId = random:uniform(C#config.n_servers) - 1, + ServerId = rand:uniform(C#config.n_servers) - 1, ServerBit = 1 bsl ServerId, Details = <<4711:(8*2000)>>, - DoRollback = (random:uniform(100) =< 2), + DoRollback = (rand:uniform(100) =< 2), Insert = fun() -> ets:insert(SessionTab, {{SubscrId, SubscrKey, ServerId}, self()}) end, {t4, nearest_node(SubscrId, transaction, C), @@ -437,11 +433,11 @@ gen_t5(C, SessionTab) -> '$end_of_table' -> %% This generator does not have any session, %% try to delete someone elses session details - SubscrId = random:uniform(C#config.n_subscribers) - 1, + SubscrId = rand:uniform(C#config.n_subscribers) - 1, SubscrKey = bench_trans:number_to_key(SubscrId, C), - ServerId = random:uniform(C#config.n_servers) - 1, + ServerId = rand:uniform(C#config.n_servers) - 1, ServerBit = 1 bsl ServerId, - DoRollback = (random:uniform(100) =< 2), + DoRollback = (rand:uniform(100) =< 2), {t5, nearest_node(SubscrId, transaction, C), fun(Wlock) -> bench_trans:delete_session_from_server(Wlock, SubscrKey, ServerBit, ServerId, DoRollback) end, @@ -451,7 +447,7 @@ gen_t5(C, SessionTab) -> %% This generator do have at least one session, %% delete it. ServerBit = 1 bsl ServerId, - DoRollback = (random:uniform(100) =< 2), + DoRollback = (rand:uniform(100) =< 2), Delete = fun() -> ets:delete(SessionTab, {SubscrId, SubscrKey, ServerId}) end, {t5, nearest_node(SubscrId, transaction, C), @@ -461,7 +457,7 @@ gen_t5(C, SessionTab) -> end. gen_ping(C, _SessionTab) -> - SubscrId = random:uniform(C#config.n_subscribers) - 1, + SubscrId = rand:uniform(C#config.n_subscribers) - 1, {ping, nearest_node(SubscrId, transaction, C), fun(_Wlock) -> {do_commit, true, []} end, diff --git a/lib/mnesia/examples/mnesia_tpcb.erl b/lib/mnesia/examples/mnesia_tpcb.erl index fde6cf402e..c6eda1c448 100644 --- a/lib/mnesia/examples/mnesia_tpcb.erl +++ b/lib/mnesia/examples/mnesia_tpcb.erl @@ -164,7 +164,7 @@ -record(history, { history_id = {0, 0}, % {DriverId, DriverLocalHistoryid} - time_stamp = now(), % Time point during active transaction + time_stamp = erlang:system_time(), % Time point during active transaction branch_id = 0, % Branch associated with teller teller_id = 0, % Teller invlolved in transaction account_id = 0, % Account updated by transaction @@ -412,9 +412,8 @@ config(remote_frag2_test, ReplicaType) -> config(conflict_benchmark, ReplicaType) -> Remote = nodes(), Local = node(), - Nodes = [Local | Remote], - [{seed, {1326,448637,337711}}, - {db_nodes, Nodes}, + Nodes = [Local | Remote], + [{db_nodes, Nodes}, {driver_nodes, Nodes}, {replica_nodes, Nodes}, {n_drivers_per_node, 10}, @@ -758,7 +757,7 @@ reporter_init(Starter, RC) -> replica_type = Type }, Drivers = start_drivers(RC, TC), - Now = now_to_micros(erlang:now()), + Now = erlang:monotonic_time(), State = #reporter_state{driver_pids = Drivers, run_config = RC, starter_pid = Starter, @@ -896,7 +895,7 @@ add_time(Acc, New) -> -define(AVOID_DIV_ZERO(_What_), try (_What_) catch _:_ -> 0 end). show_report(State) -> - Now = now_to_micros(erlang:now()), + Now = erlang:timestamp(), Iters = State#reporter_state.n_iters, Cfg = State#reporter_state.run_config, Time = State#reporter_state.curr, @@ -924,14 +923,14 @@ show_report(State) -> case Cfg#run_config.send_bench_report of true -> ct_event:notify( - #event{name = benchmark_data, + #event{name = benchmark_data, data = [{suite,"mnesia_tpcb"}, {value,Tps}]}); _ -> ok end, - State#reporter_state{prev_tps = Tps, prev_micros = Now}. + State#reporter_state{prev_tps = Tps, prev_micros = Now}. signed_diff(Iters, Curr, Prev) -> case Iters > 1 of @@ -941,11 +940,6 @@ signed_diff(Iters, Curr, Prev) -> sign(N) when N > 0 -> {"+", N}; sign(N) -> {"", N}. - -now_to_micros({Mega, Secs, Micros}) -> - DT = calendar:now_to_datetime({Mega, Secs, 0}), - S = calendar:datetime_to_gregorian_seconds(DT), - (S * ?SECOND) + Micros. start_drivers(RC, TC) -> LastHistoryId = table_info(history, size), @@ -998,13 +992,11 @@ alloc_local_branches([], Specs, OrphanBranches) -> {Specs, OrphanBranches}. driver_init(DS, AllBranches) -> - case (DS#driver_state.run_config)#run_config.seed of - undefined -> - Seed = erlang:now(); - Seed -> - Seed + Seed = case (DS#driver_state.run_config)#run_config.seed of + undefined -> rand:seed(exsplus); + ExpSeed -> rand:seed(ExpSeed) end, - + DS2 = if DS#driver_state.n_local_branches =:= 0 -> @@ -1058,14 +1050,7 @@ calc_trans(DS) -> %% Generate teller_id, account_id and delta %% Time the TPC-B transaction time_trans(DS) -> - OldSeed = get(random_seed), % Avoid interference with Mnesia - put(random_seed, DS#driver_state.seed), - Random = random:uniform(), - NewSeed = get(random_seed), - case OldSeed of - undefined -> erase(random_seed); - _ -> put(random_seed, OldSeed) - end, + {Random, NewSeed} = rand:uniform_s(DS#driver_state.seed), TC = DS#driver_state.tab_config, RC = DS#driver_state.run_config, diff --git a/lib/mnesia/src/mnesia_bup.erl b/lib/mnesia/src/mnesia_bup.erl index 0e653f2bc4..8b1143a352 100644 --- a/lib/mnesia/src/mnesia_bup.erl +++ b/lib/mnesia/src/mnesia_bup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -112,7 +112,7 @@ iter(R, Header, Schema, Fun, Acc, BupItems) -> safe_apply(R, write, [_, Items]) when Items =:= [] -> R; safe_apply(R, What, Args) -> - Abort = fun(Re) -> abort_restore(R, What, Args, Re) end, + Abort = abort_restore_fun(R, What, Args), Mod = R#restore.bup_module, try apply(Mod, What, Args) of {ok, Opaque, Items} when What =:= read -> @@ -127,6 +127,10 @@ safe_apply(R, What, Args) -> Abort(Re) end. +-spec abort_restore_fun(_, _, _) -> fun((_) -> no_return()). +abort_restore_fun(R, What, Args) -> + fun(Re) -> abort_restore(R, What, Args, Re) end. + abort_restore(R = #restore{bup_module=Mod}, What, Args, Reason) -> dbg_out("Restore aborted. ~p:~p~p -> ~p~n", [Mod, What, Args, Reason]), @@ -157,10 +161,11 @@ fallback_to_schema(Fname) -> read_schema(Mod, Opaque) -> R = #restore{bup_module = Mod, bup_data = Opaque}, try read_schema_section(R) of - {_, {_Header, Schema, _}} -> Schema + {R2, {_Header, Schema, _}} -> + close_read(R2), + Schema catch throw:{error,_} = Error -> Error - after close_read(R) end. %% Open backup media and extract schema @@ -173,8 +178,13 @@ read_schema_section(R) -> do_read_schema_section(R) -> R2 = safe_apply(R, open_read, [R#restore.bup_data]), - {R3, RawSchema} = safe_apply(R2, read, [R2#restore.bup_data]), - do_read_schema_section(R3, verify_header(RawSchema), []). + try + {R3, RawSchema} = safe_apply(R2, read, [R2#restore.bup_data]), + do_read_schema_section(R3, verify_header(RawSchema), []) + catch T:E -> + close_read(R2), + erlang:raise(T,E,erlang:get_stacktrace()) + end. do_read_schema_section(R, {ok, B, C, []}, Acc) -> case safe_apply(R, read, [R#restore.bup_data]) of diff --git a/lib/mnesia/src/mnesia_controller.erl b/lib/mnesia/src/mnesia_controller.erl index 02c175760e..69ccc1d2c9 100644 --- a/lib/mnesia/src/mnesia_controller.erl +++ b/lib/mnesia/src/mnesia_controller.erl @@ -78,7 +78,7 @@ change_table_majority/1, del_active_replica/2, wait_for_tables/2, - get_network_copy/2, + get_network_copy/3, merge_schema/0, start_remote_sender/4, schedule_late_disc_load/2 @@ -329,14 +329,14 @@ release_schema_commit_lock() -> unlink(whereis(?SERVER_NAME)). %% Special for preparation of add table copy -get_network_copy(Tab, Cs) -> +get_network_copy(Tid, Tab, Cs) -> % We can't let the controller queue this one % because that may cause a deadlock between schema_operations % and initial tableloadings which both takes schema locks. % But we have to get copier_done msgs when the other side % goes down. call({add_other, self()}), - Reason = {dumper,add_table_copy}, + Reason = {dumper,{add_table_copy, Tid}}, Work = #net_load{table = Tab,reason = Reason,cstruct = Cs}, %% I'll need this cause it's linked trough the subscriber %% might be solved by using monitor in subscr instead. @@ -775,7 +775,7 @@ handle_call({net_load, Tab, Cs}, From, State) -> true -> Worker = #net_load{table = Tab, opt_reply_to = From, - reason = {dumper,add_table_copy}, + reason = {dumper,{add_table_copy, unknown}}, cstruct = Cs }, add_worker(Worker, State); @@ -1180,11 +1180,11 @@ handle_info(Done = #loader_done{worker_pid=WPid, table_name=Tab}, State0) -> Done#loader_done.needs_announce == true, Done#loader_done.needs_reply == true -> i_have_tab(Tab), - %% Should be {dumper,add_table_copy} only + %% Should be {dumper,{add_table_copy, _}} only reply(Done#loader_done.reply_to, Done#loader_done.reply); Done#loader_done.needs_reply == true -> - %% Should be {dumper,add_table_copy} only + %% Should be {dumper,{add_table_copy,_}} only reply(Done#loader_done.reply_to, Done#loader_done.reply); Done#loader_done.needs_announce == true, Tab == schema -> @@ -2148,6 +2148,10 @@ load_table_fun(#net_load{cstruct=Cs, table=Tab, reason=Reason, opt_reply_to=Repl reply_to = ReplyTo, reply = {loaded, ok} }, + AddTableCopy = case Reason of + {dumper,{add_table_copy,_}} -> true; + _ -> false + end, if ReadNode == node() -> %% Already loaded locally @@ -2157,7 +2161,7 @@ load_table_fun(#net_load{cstruct=Cs, table=Tab, reason=Reason, opt_reply_to=Repl Res = mnesia_loader:disc_load_table(Tab, load_local_content), Done#loader_done{reply = Res, needs_announce = true, needs_sync = true} end; - AccessMode == read_only, Reason /= {dumper,add_table_copy} -> + AccessMode == read_only, not AddTableCopy -> fun() -> disc_load_table(Tab, Reason, ReplyTo) end; true -> fun() -> diff --git a/lib/mnesia/src/mnesia_index.erl b/lib/mnesia/src/mnesia_index.erl index 81ed5a8f1a..0c882c0df6 100644 --- a/lib/mnesia/src/mnesia_index.erl +++ b/lib/mnesia/src/mnesia_index.erl @@ -70,17 +70,24 @@ add_index(Index, Tab, Key, Obj, Old) -> add_index2([{Pos, Ixt} |Tail], bag, Tab, K, Obj, OldRecs) -> db_put(Ixt, {element(Pos, Obj), K}), add_index2(Tail, bag, Tab, K, Obj, OldRecs); -add_index2([{Pos, Ixt} |Tail], Type, Tab, K, Obj, OldRecs) -> +add_index2([{Pos, Ixt} |Tail], Type, Tab, K, Obj, OldRecs0) -> %% Remove old tuples in index if Tab is updated - case OldRecs of - undefined -> - Old = mnesia_lib:db_get(Tab, K), - del_ixes(Ixt, Old, Pos, K); - Old -> - del_ixes(Ixt, Old, Pos, K) - end, - db_put(Ixt, {element(Pos, Obj), K}), - add_index2(Tail, Type, Tab, K, Obj, OldRecs); + OldRecs1 = case OldRecs0 of + undefined -> mnesia_lib:db_get(Tab, K); + _ -> OldRecs0 + end, + IdxVal = element(Pos, Obj), + case [Old || Old <- OldRecs1, element(Pos, Old) =/= IdxVal] of + [] when OldRecs1 =:= [] -> %% Write + db_put(Ixt, {element(Pos, Obj), K}), + add_index2(Tail, Type, Tab, K, Obj, OldRecs0); + [] -> %% when OldRecs1 =/= [] Update without modifying index field + add_index2(Tail, Type, Tab, K, Obj, OldRecs0); + OldRecs -> %% Update + db_put(Ixt, {element(Pos, Obj), K}), + del_ixes(Ixt, OldRecs, Pos, K), + add_index2(Tail, Type, Tab, K, Obj, OldRecs0) + end; add_index2([], _, _Tab, _K, _Obj, _) -> ok. delete_index(Index, Tab, K) -> diff --git a/lib/mnesia/src/mnesia_lib.erl b/lib/mnesia/src/mnesia_lib.erl index 77c7a7638d..0f1354f43e 100644 --- a/lib/mnesia/src/mnesia_lib.erl +++ b/lib/mnesia/src/mnesia_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2014. All Rights Reserved. +%% Copyright Ericsson AB 1996-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -403,6 +403,7 @@ other_val_1(Var) -> _ -> error end. +-spec pr_other(_) -> no_return(). pr_other(Var) -> Why = case is_running() of diff --git a/lib/mnesia/src/mnesia_loader.erl b/lib/mnesia/src/mnesia_loader.erl index da8549be50..41fcd76fcb 100644 --- a/lib/mnesia/src/mnesia_loader.erl +++ b/lib/mnesia/src/mnesia_loader.erl @@ -180,8 +180,7 @@ do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == disc_only_copies - -define(MAX_RAM_TRANSFERS, (?MAX_RAM_FILE_SIZE div ?MAX_TRANSFER_SIZE) + 1). -define(MAX_NOPACKETS, 20). -net_load_table(Tab, Reason, Ns, Cs) - when Reason == {dumper,add_table_copy} -> +net_load_table(Tab, {dumper,{add_table_copy, _}}=Reason, Ns, Cs) -> try_net_load_table(Tab, Reason, Ns, Cs); net_load_table(Tab, Reason, Ns, _Cs) -> try_net_load_table(Tab, Reason, Ns, val({Tab, cstruct})). @@ -233,7 +232,8 @@ do_snmpify(Tab, Us, Storage) -> set({Tab, {index, snmp}}, Snmp). %% Start the recieiver -init_receiver(Node, Tab, Storage, Cs, Reas={dumper,add_table_copy}) -> +init_receiver(Node, Tab, Storage, Cs, Reas={dumper,{add_table_copy, Tid}}) -> + rpc:call(Node, mnesia_lib, set, [{?MODULE, active_trans}, Tid]), case start_remote_sender(Node, Tab, Storage) of {SenderPid, TabSize, DetsData} -> start_receiver(Tab,Storage,Cs,SenderPid,TabSize,DetsData,Reas); @@ -307,7 +307,7 @@ table_init_fun(SenderPid) -> end. %% Add_table_copy get's it's own locks. -start_receiver(Tab,Storage,Cs,SenderPid,TabSize,DetsData,{dumper,add_table_copy}) -> +start_receiver(Tab,Storage,Cs,SenderPid,TabSize,DetsData,{dumper,{add_table_copy,_}}) -> Init = table_init_fun(SenderPid), case do_init_table(Tab,Storage,Cs,SenderPid,TabSize,DetsData,self(), Init) of Err = {error, _} -> @@ -658,9 +658,10 @@ send_table(Pid, Tab, RemoteS) -> {Init, Chunk} = reader_funcs(UseDetsChunk, Tab, Storage, KeysPerTransfer), SendIt = fun() -> - {atomic, ok} = prepare_copy(Pid, Tab, Storage), + NeedLock = need_lock(Tab), + {atomic, ok} = prepare_copy(Pid, Tab, Storage, NeedLock), send_more(Pid, 1, Chunk, Init(), Tab), - finish_copy(Pid, Tab, Storage, RemoteS) + finish_copy(Pid, Tab, Storage, RemoteS, NeedLock) end, try SendIt() of @@ -678,10 +679,10 @@ send_table(Pid, Tab, RemoteS) -> end end. -prepare_copy(Pid, Tab, Storage) -> +prepare_copy(Pid, Tab, Storage, NeedLock) -> Trans = fun() -> - mnesia:lock_table(Tab, load), + NeedLock andalso mnesia:lock_table(Tab, load), mnesia_subscr:subscribe(Pid, {table, Tab}), update_where_to_write(Tab, node(Pid)), mnesia_lib:db_fixtable(Storage, Tab, true), @@ -689,6 +690,21 @@ prepare_copy(Pid, Tab, Storage) -> end, mnesia:transaction(Trans). + +need_lock(Tab) -> + case ?catch_val({?MODULE, active_trans}) of + #tid{} = Tid -> + %% move_table_copy grabs it's own table-lock + %% do not deadlock with it + mnesia_lib:unset({?MODULE, active_trans}), + case mnesia_locker:get_held_locks(Tab) of + [{write, Tid}|_] -> false; + _Locks -> true + end; + _ -> + true + end. + update_where_to_write(Tab, Node) -> case val({Tab, access_mode}) of read_only -> @@ -783,12 +799,12 @@ send_packet(N, Pid, Chunk, {Recs, Cont}) when N < ?MAX_NOPACKETS -> send_packet(_N, _Pid, _Chunk, DataState) -> DataState. -finish_copy(Pid, Tab, Storage, RemoteS) -> +finish_copy(Pid, Tab, Storage, RemoteS, NeedLock) -> RecNode = node(Pid), DatBin = dat2bin(Tab, Storage, RemoteS), Trans = fun() -> - mnesia:read_lock_table(Tab), + NeedLock andalso mnesia:read_lock_table(Tab), A = val({Tab, access_mode}), mnesia_controller:sync_and_block_table_whereabouts(Tab, RecNode, RemoteS, A), cleanup_tab_copier(Pid, Storage, Tab), diff --git a/lib/mnesia/src/mnesia_locker.erl b/lib/mnesia/src/mnesia_locker.erl index 89feeba2c3..5766f22e92 100644 --- a/lib/mnesia/src/mnesia_locker.erl +++ b/lib/mnesia/src/mnesia_locker.erl @@ -22,7 +22,7 @@ -module(mnesia_locker). -export([ - get_held_locks/0, + get_held_locks/0, get_held_locks/1, get_lock_queue/0, global_lock/5, ixrlock/5, @@ -236,6 +236,11 @@ loop(State) -> From ! {Ref, ok}, loop(State); + {From, {is_locked, Oid}} -> + Held = ?ets_lookup(mnesia_held_locks, Oid), + reply(From, Held), + loop(State); + {'EXIT', Pid, _} when Pid == State#state.supervisor -> do_stop(); @@ -1151,6 +1156,19 @@ get_held_locks() -> Locks = receive {mnesia_held_locks, Ls} -> Ls after 5000 -> [] end, rewrite_locks(Locks, []). +%% Mnesia internal usage only +get_held_locks(Tab) when is_atom(Tab) -> + Oid = {Tab, ?ALL}, + ?MODULE ! {self(), {is_locked, Oid}}, + receive + {?MODULE, _Node, Locks} -> + case Locks of + [] -> []; + [{Oid, _Prev, What}] -> What + end + end. + + rewrite_locks([{Oid, _, Ls}|Locks], Acc0) -> Acc = rewrite_locks(Ls, Oid, Acc0), rewrite_locks(Locks, Acc); diff --git a/lib/mnesia/src/mnesia_log.erl b/lib/mnesia/src/mnesia_log.erl index 8b19e13ff6..36135418c8 100644 --- a/lib/mnesia/src/mnesia_log.erl +++ b/lib/mnesia/src/mnesia_log.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2014. All Rights Reserved. +%% Copyright Ericsson AB 1996-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -734,7 +734,7 @@ backup_schema(B, Tabs) -> safe_apply(B, write, [_, Items]) when Items == [] -> B; safe_apply(B, What, Args) -> - Abort = fun(R) -> abort_write(B, What, Args, R) end, + Abort = abort_write_fun(B, What, Args), receive {'EXIT', Pid, R} -> Abort({'EXIT', Pid, R}) after 0 -> @@ -746,6 +746,10 @@ safe_apply(B, What, Args) -> end end. +-spec abort_write_fun(_, _, _) -> fun((_) -> no_return()). +abort_write_fun(B, What, Args) -> + fun(R) -> abort_write(B, What, Args, R) end. + abort_write(B, What, Args, Reason) -> Mod = B#backup_args.module, Opaque = B#backup_args.opaque, diff --git a/lib/mnesia/src/mnesia_monitor.erl b/lib/mnesia/src/mnesia_monitor.erl index 8313c3bda5..081d746257 100644 --- a/lib/mnesia/src/mnesia_monitor.erl +++ b/lib/mnesia/src/mnesia_monitor.erl @@ -82,9 +82,9 @@ going_down = [], tm_started = false, early_connects = [], connecting, mq = [], remote_node_status = []}). --define(current_protocol_version, {8,1}). +-define(current_protocol_version, {8,2}). --define(previous_protocol_version, {8,0}). +-define(previous_protocol_version, {8,1}). start() -> gen_server:start_link({local, ?MODULE}, ?MODULE, @@ -193,7 +193,7 @@ protocol_version() -> %% A sorted list of acceptable protocols the %% preferred protocols are first in the list acceptable_protocol_versions() -> - [protocol_version(), ?previous_protocol_version, {7,6}]. + [protocol_version(), ?previous_protocol_version]. needs_protocol_conversion(Node) -> case {?catch_val({protocol, Node}), protocol_version()} of @@ -424,8 +424,6 @@ handle_call({negotiate_protocol, Mon, Version, Protocols}, From, State) case hd(Protocols) of ?previous_protocol_version -> accept_protocol(Mon, MyVersion, ?previous_protocol_version, From, State); - {7,6} -> - accept_protocol(Mon, MyVersion, {7,6}, From, State); _ -> verbose("Connection with ~p rejected. " "version = ~p, protocols = ~p, " diff --git a/lib/mnesia/src/mnesia_schema.erl b/lib/mnesia/src/mnesia_schema.erl index 593360415d..782493fb4f 100644 --- a/lib/mnesia/src/mnesia_schema.erl +++ b/lib/mnesia/src/mnesia_schema.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -646,54 +646,18 @@ cs2list(Cs) when is_record(Cs, cstruct) -> rec2list(Tags, Tags, 2, Cs); cs2list(CreateList) when is_list(CreateList) -> CreateList; -%% 4.6 + +%% since 4.6 cs2list(Cs) when element(1, Cs) == cstruct, tuple_size(Cs) == 19 -> Tags = [name,type,ram_copies,disc_copies,disc_only_copies, load_order,access_mode,majority,index,snmp,local_content, record_name,attributes, user_properties,frag_properties,storage_properties, cookie,version], - rec2list(Tags, Tags, 2, Cs); -%% 4.4.19 -cs2list(Cs) when element(1, Cs) == cstruct, tuple_size(Cs) == 18 -> - Tags = [name,type,ram_copies,disc_copies,disc_only_copies, - load_order,access_mode,majority,index,snmp,local_content, - record_name,attributes,user_properties,frag_properties, - cookie,version], - rec2list(Tags, Tags, 2, Cs); -%% 4.4.18 and earlier -cs2list(Cs) when element(1, Cs) == cstruct, tuple_size(Cs) == 17 -> - Tags = [name,type,ram_copies,disc_copies,disc_only_copies, - load_order,access_mode,index,snmp,local_content, - record_name,attributes,user_properties,frag_properties, - cookie,version], rec2list(Tags, Tags, 2, Cs). cs2list(false, Cs) -> - cs2list(Cs); -cs2list(ver4_4_18, Cs) -> %% Or earlier - Orig = record_info(fields, cstruct), - Tags = [name,type,ram_copies,disc_copies,disc_only_copies, - load_order,access_mode,index,snmp,local_content, - record_name,attributes,user_properties,frag_properties, - cookie,version], - rec2list(Tags, Orig, 2, Cs); -cs2list(ver4_4_19, Cs) -> - Orig = record_info(fields, cstruct), - Tags = [name,type,ram_copies,disc_copies,disc_only_copies, - load_order,access_mode,majority,index,snmp,local_content, - record_name,attributes,user_properties,frag_properties, - cookie,version], - rec2list(Tags, Orig, 2, Cs); -cs2list(ver4_6, Cs) -> - Orig = record_info(fields, cstruct), - Tags = [name,type,ram_copies,disc_copies,disc_only_copies, - load_order,access_mode,majority,index,snmp,local_content, - record_name,attributes, - user_properties,frag_properties,storage_properties, - cookie,version], - rec2list(Tags, Orig, 2, Cs). - + cs2list(Cs). rec2list([Tag | Tags], [Tag | Orig], Pos, Rec) -> Val = element(Pos, Rec), @@ -703,19 +667,8 @@ rec2list([], _, _Pos, _Rec) -> rec2list(Tags, [_|Orig], Pos, Rec) -> rec2list(Tags, Orig, Pos+1, Rec). -normalize_cs(Cstructs, Node) -> - %% backward-compatibility hack; normalize before returning - case need_old_cstructs([Node]) of - false -> - Cstructs; - Version -> - %% some other format - [convert_cs(Version, Cs) || Cs <- Cstructs] - end. - -convert_cs(Version, Cs) -> - Fields = [Value || {_, Value} <- cs2list(Version, Cs)], - list_to_tuple([cstruct|Fields]). +normalize_cs(Cstructs, _Node) -> + Cstructs. list2cs(List) when is_list(List) -> Name = pick(unknown, name, List, must), @@ -1142,6 +1095,7 @@ do_delete_table(Tab) -> ensure_writable(schema), insert_schema_ops(TidTs, make_delete_table(Tab, whole_table)). +-dialyzer({no_improper_lists, make_delete_table/2}). make_delete_table(Tab, Mode) -> case existed_before(Tab) of false -> @@ -1297,6 +1251,7 @@ make_del_table_copy(Tab, Node) -> _ -> ensure_active(Cs), verify_cstruct(Cs2), + get_tid_ts_and_lock(Tab, write), [{op, del_table_copy, Storage, Node, vsn_cs2list(Cs2)}] end. @@ -1324,6 +1279,7 @@ remove_node_from_tabs([Tab|Rest], Node) -> remove_node_from_tabs(Rest, Node)]; _Ns -> verify_cstruct(Cs2), + get_tid_ts_and_lock(Tab, write), [{op, del_table_copy, ram_copies, Node, vsn_cs2list(Cs2)}| remove_node_from_tabs(Rest, Node)] end @@ -1355,6 +1311,11 @@ do_move_table(schema, _FromNode, _ToNode) -> mnesia:abort({bad_type, schema}); do_move_table(Tab, FromNode, ToNode) when is_atom(FromNode), is_atom(ToNode) -> TidTs = get_tid_ts_and_lock(schema, write), + AnyOld = lists:any(fun(Node) -> mnesia_monitor:needs_protocol_conversion(Node) end, + [ToNode|val({Tab, where_to_write})]), + if AnyOld -> ignore; %% Leads to deadlock on old nodes + true -> get_tid_ts_and_lock(Tab, write) + end, insert_schema_ops(TidTs, make_move_table(Tab, FromNode, ToNode)); do_move_table(Tab, FromNode, ToNode) -> mnesia:abort({badarg, Tab, FromNode, ToNode}). @@ -1962,7 +1923,7 @@ prepare_op(Tid, {op, add_table_copy, Storage, Node, TabDef}, _WaitFor) -> end, %% Tables are created by mnesia_loader get_network code insert_cstruct(Tid, Cs, true), - case mnesia_controller:get_network_copy(Tab, Cs) of + case mnesia_controller:get_network_copy(Tid, Tab, Cs) of {loaded, ok} -> {true, optional}; {not_loaded, ErrReason} -> @@ -1993,28 +1954,11 @@ prepare_op(Tid, {op, add_table_copy, Storage, Node, TabDef}, _WaitFor) -> {true, optional} end; -prepare_op(Tid, {op, del_table_copy, _Storage, Node, TabDef}, _WaitFor) -> +prepare_op(_Tid, {op, del_table_copy, _Storage, Node, TabDef}, _WaitFor) -> Cs = list2cs(TabDef), Tab = Cs#cstruct.name, - - if - %% Schema table lock is always required to run a schema op. - %% No need to look it. - node(Tid#tid.pid) == node(), Tab /= schema -> - Self = self(), - Pid = spawn_link(fun() -> lock_del_table(Tab, Node, Cs, Self) end), - put(mnesia_lock, Pid), - receive - {Pid, updated} -> - {true, optional}; - {Pid, FailReason} -> - mnesia:abort(FailReason); - {'EXIT', Pid, Reason} -> - mnesia:abort(Reason) - end; - true -> - {true, optional} - end; + set_where_to_read(Tab, Node, Cs), + {true, optional}; prepare_op(_Tid, {op, change_table_copy_type, N, FromS, ToS, TabDef}, _WaitFor) when N == node() -> @@ -2228,46 +2172,6 @@ receive_sync(Nodes, Pids) -> {abort, Else} end. -lock_del_table(Tab, NewNode, Cs0, Father) -> - Ns = val({schema, active_replicas}), - process_flag(trap_exit,true), - Lock = fun() -> - mnesia:write_lock_table(Tab), - %% Sigh using cs record - Set = fun(Node) -> - [Cs] = normalize_cs([Cs0], Node), - rpc:call(Node, ?MODULE, set_where_to_read, [Tab, NewNode, Cs]) - end, - Res = [Set(Node) || Node <- Ns], - Filter = fun(ok) -> - false; - ({badrpc, {'EXIT', {undef, _}}}) -> - %% This will be the case we talks with elder nodes - %% than 3.8.2, they will set where_to_read without - %% getting a lock. - false; - (_) -> - true - end, - case lists:filter(Filter, Res) of - [] -> - Father ! {self(), updated}, - %% When transaction is commited the process dies - %% and the lock is released. - receive _ -> ok end; - Err -> - Father ! {self(), {bad_commit, Err}} - end, - ok - end, - case mnesia:transaction(Lock) of - {atomic, ok} -> ok; - {aborted, R} -> Father ! {self(), R} - end, - unlink(Father), - unlink(whereis(mnesia_tm)), - exit(normal). - set_where_to_read(Tab, Node, Cs) -> case mnesia_lib:val({Tab, where_to_read}) of Node -> @@ -2418,13 +2322,19 @@ undo_prepare_op(Tid, {op, add_table_copy, Storage, Node, TabDef}) -> insert_cstruct(Tid, Cs2, true) % Don't care about the version end; -undo_prepare_op(_Tid, {op, del_table_copy, _, Node, TabDef}) - when Node == node() -> - WriteLocker = get(mnesia_lock), - WriteLocker =/= undefined andalso (WriteLocker ! die), +undo_prepare_op(_Tid, {op, del_table_copy, _, Node, TabDef}) -> Cs = list2cs(TabDef), Tab = Cs#cstruct.name, - mnesia_lib:set({Tab, where_to_read}, Node); + if node() =:= Node -> + mnesia_lib:set({Tab, where_to_read}, Node); + true -> + case mnesia_lib:val({Tab, where_to_read}) of + nowhere -> + mnesia_lib:set_remote_where_to_read(Tab); + _ -> + ignore + end + end; undo_prepare_op(_Tid, {op, change_table_copy_type, N, FromS, ToS, TabDef}) when N == node() -> @@ -2885,40 +2795,11 @@ do_merge_schema(LockTabs0) -> end. fetch_cstructs(Node) -> - case need_old_cstructs([Node]) of - false -> - rpc:call(Node, mnesia_controller, get_remote_cstructs, []); - _Ver -> - case rpc:call(Node, mnesia_controller, get_cstructs, []) of - {cstructs, Cs0, RR} -> - {cstructs, [list2cs(cs2list(Cs)) || Cs <- Cs0], RR}; - Err -> Err - end - end. + rpc:call(Node, mnesia_controller, get_remote_cstructs, []). -need_old_cstructs() -> - need_old_cstructs(val({schema, where_to_write})). - -need_old_cstructs(Nodes) -> - Filter = fun(Node) -> not mnesia_monitor:needs_protocol_conversion(Node) end, - case lists:dropwhile(Filter, Nodes) of - [] -> false; - [Node|_] -> - case rpc:call(Node, mnesia_lib, val, [{schema,cstruct}]) of - #cstruct{} -> - %% mnesia_lib:warning("Mnesia on ~p do not need to convert cstruct (~p)~n", - %% [node(), Node]), - false; - {badrpc, _} -> - need_old_cstructs(lists:delete(Node,Nodes)); - Cs when element(1, Cs) == cstruct, tuple_size(Cs) == 17 -> - ver4_4_18; % Without majority - Cs when element(1, Cs) == cstruct, tuple_size(Cs) == 18 -> - ver4_4_19; % With majority - Cs when element(1, Cs) == cstruct, tuple_size(Cs) == 19 -> - ver4_6 % With storage_properties - end - end. +need_old_cstructs() -> false. + +need_old_cstructs(_Nodes) -> false. tab_to_nodes(Tab) when is_atom(Tab) -> Cs = val({Tab, cstruct}), diff --git a/lib/mnesia/src/mnesia_tm.erl b/lib/mnesia/src/mnesia_tm.erl index e7ee938312..1d3eb87036 100644 --- a/lib/mnesia/src/mnesia_tm.erl +++ b/lib/mnesia/src/mnesia_tm.erl @@ -1692,13 +1692,10 @@ commit_participant(Coord, Tid, Bin, C0, DiscNs, _RamNs) -> ?eval_debug_fun({?MODULE, commit_participant, undo_prepare}, [{tid, Tid}]); - {'EXIT', _, _} -> + {'EXIT', _MnesiaTM, Reason} -> + reply(Coord, {do_abort, Tid, self(), {bad_commit,Reason}}), mnesia_recover:log_decision(D#decision{outcome = aborted}), - ?eval_debug_fun({?MODULE, commit_participant, exit_log_abort}, - [{tid, Tid}]), - mnesia_schema:undo_prepare_commit(Tid, C0), - ?eval_debug_fun({?MODULE, commit_participant, exit_undo_prepare}, - [{tid, Tid}]); + mnesia_schema:undo_prepare_commit(Tid, C0); Msg -> verbose("** ERROR ** commit_participant ~p, got unexpected msg: ~p~n", @@ -2210,8 +2207,6 @@ reconfigure_coordinators(N, [{Tid, [Store | _]} | Coordinators]) -> true -> send_mnesia_down(Tid, Store, N) end; - aborted -> - ignore; % avoid spurious mnesia_down messages _ -> %% Tell the coordinator about the mnesia_down send_mnesia_down(Tid, Store, N) diff --git a/lib/mnesia/test/mnesia_atomicity_test.erl b/lib/mnesia/test/mnesia_atomicity_test.erl index 1d9d9c35bc..e3e0eaaf75 100644 --- a/lib/mnesia/test/mnesia_atomicity_test.erl +++ b/lib/mnesia/test/mnesia_atomicity_test.erl @@ -557,8 +557,8 @@ start_lock_waiter(BlockOpA, BlockOpB, Config) -> ?verify_mnesia([N1], [N2]). mk_tab_name(Prefix) -> - {Mega, Sec, Micro} = erlang:now(), - list_to_atom(lists:concat([Prefix , Mega, '_', Sec, '_', Micro])). + Count = erlang:unique_integer([monotonic,positive]), + list_to_atom(lists:concat([Prefix , '_', Count])). lock_waiter_fun(Op, TabName, Val) -> case Op of diff --git a/lib/mnesia/test/mnesia_config_test.erl b/lib/mnesia/test/mnesia_config_test.erl index c8a6a000c6..089fbc06dc 100644 --- a/lib/mnesia/test/mnesia_config_test.erl +++ b/lib/mnesia/test/mnesia_config_test.erl @@ -1206,7 +1206,7 @@ dynamic_ext(Config) when is_list(Config) -> end, [Check(Test) || Test <- [{tab1, ram_copies},{tab2, disc_copies},{tab3, disc_only_copies}]], - T = now(), + T = erlang:unique_integer(), ?match(ok, mnesia:dirty_write({tab0, 42, T})), ?match(ok, mnesia:dirty_write({tab1, 42, T})), ?match(ok, mnesia:dirty_write({tab2, 42, T})), @@ -1284,7 +1284,7 @@ check_storage(Me, Orig, Other) -> mnesia_test_lib:kill_mnesia([Orig]), mnesia_test_lib:kill_mnesia(Other), - T = now(), + T = erlang:unique_integer(), ?match(ok, rpc:call(Me, mnesia, dirty_write, [{tab2, 42, T}])), ?match(stopped, rpc:call(Me, mnesia, stop, [])), ?match(ok, rpc:call(Me, mnesia, start, [])), diff --git a/lib/mnesia/test/mnesia_cost.erl b/lib/mnesia/test/mnesia_cost.erl index ff0108ced1..714dbaef27 100644 --- a/lib/mnesia/test/mnesia_cost.erl +++ b/lib/mnesia/test/mnesia_cost.erl @@ -108,11 +108,11 @@ run(What, OtherInfo, Ops, F) -> run(t, What, OtherInfo, Ops, F). run(How, What, OtherInfo, Ops, F) -> - T1 = erlang:now(), + T1 = erlang:monotonic_time(), statistics(runtime), do_times(How, ?TIMES, F), {_, RunTime} = statistics(runtime), - T2 = erlang:now(), + T2 = erlang:monotonic_time(), RealTime = subtr(T1, T2), report(How, What, OtherInfo, Ops, RunTime, RealTime). @@ -140,11 +140,7 @@ report(dirty, What, OtherInfo, Ops, RunTime, RealTime) -> subtr(Before, After) -> - E =(element(1,After)*1000000000000 - +element(2,After)*1000000+element(3,After)) - - (element(1,Before)*1000000000000 - +element(2,Before)*1000000+element(3,Before)), - E div 1000. + erlang:convert_time_unit(After-Before, native, milli_seconds). do_times(t, I, F) -> do_trans_times(I, F); diff --git a/lib/mnesia/test/mnesia_dbn_meters.erl b/lib/mnesia/test/mnesia_dbn_meters.erl index f97bd973fc..5c3ea08a1d 100644 --- a/lib/mnesia/test/mnesia_dbn_meters.erl +++ b/lib/mnesia/test/mnesia_dbn_meters.erl @@ -93,7 +93,7 @@ some_meters() -> report_meter(Meter) -> Times = 100, Micros = repeat_meter(Meter,{atomic,{0,ignore}},Times) div Times, - io:format("\t~-30w ~-10w micro seconds (mean of ~p repetitions)~n",[Meter,Micros,Times]). + io:format("\t~-30w ~-10w nano seconds (mean of ~p repetitions)~n",[Meter,Micros,Times]). repeat_meter(_Meter,{atomic,{Micros,_Result}},0) -> Micros; @@ -110,9 +110,9 @@ meter(create) -> Key = 1, mnesia:transaction(fun() -> mnesia:delete({simple,Key}) end), Fun = fun() -> - BeforeT = erlang:now(), + BeforeT = erlang:monotonic_time(), R = mnesia:write(#simple{key=Key}), - AfterT = erlang:now(), + AfterT = erlang:monotonic_time(), elapsed_time(BeforeT,AfterT,R) end, mnesia:transaction(Fun); @@ -121,9 +121,9 @@ meter(open_safe_read) -> Key = 2, mnesia:transaction(fun() -> mnesia:write(#simple{key=Key}) end), Fun = fun() -> - BeforeT = erlang:now(), + BeforeT = erlang:monotonic_time(), R = mnesia:read({simple,Key}), - AfterT = erlang:now(), + AfterT = erlang:monotonic_time(), elapsed_time(BeforeT,AfterT,R) end, mnesia:transaction(Fun); @@ -132,9 +132,9 @@ meter(open_dirty_read) -> Key = 21, mnesia:transaction(fun() -> mnesia:write(#simple{key=Key}) end), Fun = fun() -> - BeforeT = erlang:now(), + BeforeT = erlang:monotonic_time(), R = mnesia:dirty_read({simple,Key}), - AfterT = erlang:now(), + AfterT = erlang:monotonic_time(), elapsed_time(BeforeT,AfterT,R) end, mnesia:transaction(Fun); @@ -144,9 +144,9 @@ meter(get_int) -> mnesia:transaction(fun() -> mnesia:write(#simple{key=Key}) end), Fun = fun() -> [Simple] = mnesia:read({simple,Key}), - BeforeT = erlang:now(), + BeforeT = erlang:monotonic_time(), Int = Simple#simple.val, - AfterT = erlang:now(), + AfterT = erlang:monotonic_time(), elapsed_time(BeforeT,AfterT,Int) end, mnesia:transaction(Fun); @@ -155,9 +155,9 @@ meter(open_update) -> Key = 3, mnesia:transaction(fun() -> mnesia:write(#simple{key=Key}) end), Fun = fun() -> - BeforeT = erlang:now(), + BeforeT = erlang:monotonic_time(), R = mnesia:wread({simple,Key}), - AfterT = erlang:now(), + AfterT = erlang:monotonic_time(), elapsed_time(BeforeT,AfterT,R) end, mnesia:transaction(Fun); @@ -167,9 +167,9 @@ meter(put_int) -> mnesia:transaction(fun() -> mnesia:write(#simple{key=Key}) end), Fun = fun() -> [Simple] = mnesia:wread({simple,Key}), - BeforeT = erlang:now(), + BeforeT = erlang:monotonic_time(), R = Simple#simple{val=7}, - AfterT = erlang:now(), + AfterT = erlang:monotonic_time(), elapsed_time(BeforeT,AfterT,R) end, mnesia:transaction(Fun); @@ -179,10 +179,10 @@ meter(put_int_and_copy) -> mnesia:transaction(fun() -> mnesia:write(#simple{key=Key}) end), Fun = fun() -> [Simple] = mnesia:wread({simple,Key}), - BeforeT = erlang:now(), + BeforeT = erlang:monotonic_time(), Simple2 = Simple#simple{val=17}, R = mnesia:write(Simple2), - AfterT = erlang:now(), + AfterT = erlang:monotonic_time(), elapsed_time(BeforeT,AfterT,R) end, mnesia:transaction(Fun); @@ -191,15 +191,15 @@ meter(dirty_put_int_and_copy) -> Key = 55, mnesia:dirty_write(#simple{key=Key}), [Simple] = mnesia:dirty_read({simple,Key}), - BeforeT = erlang:now(), + BeforeT = erlang:monotonic_time(), Simple2 = Simple#simple{val=17}, R = mnesia:dirty_write(Simple2), - AfterT = erlang:now(), + AfterT = erlang:monotonic_time(), {atomic,elapsed_time(BeforeT,AfterT,R)}; meter(start_trans) -> - BeforeT = erlang:now(), - {atomic,AfterT} = mnesia:transaction(fun() -> erlang:now() end), + BeforeT = erlang:monotonic_time(), + {atomic,AfterT} = mnesia:transaction(fun() -> erlang:monotonic_time() end), {atomic,elapsed_time(BeforeT,AfterT,ok)}; meter(commit_one_update) -> @@ -209,19 +209,19 @@ meter(commit_one_update) -> [Simple] = mnesia:wread({simple,Key}), Simple2 = Simple#simple{val=27}, _R = mnesia:write(Simple2), - erlang:now() + erlang:monotonic_time() end, {atomic,BeforeT} = mnesia:transaction(Fun), - AfterT = erlang:now(), + AfterT = erlang:monotonic_time(), {atomic,elapsed_time(BeforeT,AfterT,ok)}; meter(delete) -> Key = 7, mnesia:transaction(fun() -> mnesia:write(#simple{key=Key}) end), Fun = fun() -> - BeforeT = erlang:now(), + BeforeT = erlang:monotonic_time(), R = mnesia:delete({simple,Key}), - AfterT = erlang:now(), + AfterT = erlang:monotonic_time(), elapsed_time(BeforeT,AfterT,R) end, mnesia:transaction(Fun); @@ -229,15 +229,12 @@ meter(delete) -> meter(dirty_delete) -> Key = 75, mnesia:dirty_write(#simple{key=Key}), - BeforeT = erlang:now(), + BeforeT = erlang:monotonic_time(), R = mnesia:dirty_delete({simple,Key}), - AfterT = erlang:now(), + AfterT = erlang:monotonic_time(), {atomic, elapsed_time(BeforeT,AfterT,R)}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Calculate the elapsed time elapsed_time(BeforeT,AfterT,Result) -> - {(element(1,AfterT)*1000000000000 - +element(2,AfterT)*1000000+element(3,AfterT)) - - (element(1,BeforeT)*1000000000000 - +element(2,BeforeT)*1000000+element(3,BeforeT)),Result}. + {erlang:convert_time_unit(AfterT-BeforeT, native, nano_seconds),Result}. diff --git a/lib/mnesia/test/mnesia_dirty_access_test.erl b/lib/mnesia/test/mnesia_dirty_access_test.erl index 89aff2b3b8..0d57e5a1b1 100644 --- a/lib/mnesia/test/mnesia_dirty_access_test.erl +++ b/lib/mnesia/test/mnesia_dirty_access_test.erl @@ -401,9 +401,26 @@ dirty_index_read(Config, Storage) -> ?match({'EXIT', _}, mnesia:dirty_index_read(Tab, 2, BadValPos)), ?match({'EXIT', _}, mnesia:dirty_index_read(foo, 2, ValPos)), ?match({'EXIT', _}, mnesia:dirty_index_read([], 2, ValPos)), - + + mnesia:dirty_write({Tab, 5, 1}), + ?match(ok, index_read_loop(Tab, 0)), + ?verify_mnesia(Nodes, []). + +index_read_loop(Tab, N) when N =< 1000 -> + spawn_link(fun() -> + mnesia:transaction(fun() -> mnesia:write({Tab, 5, 1}) end) + end), + case mnesia:dirty_match_object({Tab, '_', 1}) of + [{Tab, 5, 1}] -> + index_read_loop(Tab, N+1); + Other -> {N, Other} + end; +index_read_loop(_, _) -> + ok. + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/mnesia/test/mnesia_evil_backup.erl b/lib/mnesia/test/mnesia_evil_backup.erl index 5392267f79..e605fa7926 100644 --- a/lib/mnesia/test/mnesia_evil_backup.erl +++ b/lib/mnesia/test/mnesia_evil_backup.erl @@ -229,10 +229,16 @@ restore(Config, Op) -> [mnesia:dirty_write({Tab1, N, N+1}) || N <- lists:seq(1, 11)], [mnesia:dirty_write({Tab2, N, N+1}) || N <- lists:seq(1, 11)], [mnesia:dirty_write({Tab3, N, N+1}) || N <- lists:seq(1, 11)], - _Res11 = [{Tab1, N, N+1} || N <- lists:seq(1, 11)], + Res21 = [{Tab2, N, N+1} || N <- lists:seq(1, 11)], Res31 = [[{Tab3, N, N+1}, {Tab3, N, N+44}] || N <- lists:seq(1, 10)], - + Check = fun() -> + [disk_log:pid2name(X) || + X <- processes(), Data <- [process_info(X, [current_function])], + Data =/= undefined, + element(1, element(2, lists:keyfind(current_function, 1, Data)))=:= disk_log] + end, + Before = Check(), ?match({atomic, [Tab1]}, Restore(File1, [{Op, [Tab1]}, {skip_tables, Tabs -- [Tab1]}])), case Op of @@ -319,6 +325,8 @@ restore(Config, Op) -> end, ?match(ok, file:delete(File1)), ?match(ok, file:delete(File2)), + ?match([], Check() -- Before), + ?verify_mnesia(Nodes, []). diff --git a/lib/mnesia/test/mnesia_isolation_test.erl b/lib/mnesia/test/mnesia_isolation_test.erl index 6abb1f7cdc..4dd0c01d05 100644 --- a/lib/mnesia/test/mnesia_isolation_test.erl +++ b/lib/mnesia/test/mnesia_isolation_test.erl @@ -39,7 +39,7 @@ groups() -> [{locking, [], [no_conflict, simple_queue_conflict, advanced_queue_conflict, simple_deadlock_conflict, - advanced_deadlock_conflict, lock_burst, + advanced_deadlock_conflict, schema_deadlock, lock_burst, {group, sticky_locks}, {group, unbound_locking}, {group, admin_conflict}, nasty]}, {sticky_locks, [], [basic_sticky_functionality]}, @@ -148,20 +148,32 @@ simple_queue_conflict(Config) when is_list(Config) -> fun_loop(Fun, AllSharedLocks, OneExclusiveLocks), ok. -wait_for_lock(Pid, _Nodes, 0) -> +wait_for_lock(Pid, Nodes, Retry) -> + wait_for_lock(Pid, Nodes, Retry, queue). + +wait_for_lock(Pid, _Nodes, 0, queue) -> Queue = mnesia:system_info(lock_queue), ?error("Timeout while waiting for lock on Pid ~p in queue ~p~n", [Pid, Queue]); -wait_for_lock(Pid, Nodes, N) -> - rpc:multicall(Nodes, sys, get_status, [mnesia_locker]), - List = [rpc:call(Node, mnesia, system_info, [lock_queue]) || Node <- Nodes], +wait_for_lock(Pid, _Nodes, 0, held) -> + Held = mnesia:system_info(held_locks), + ?error("Timeout while waiting for lock on Pid ~p (held) ~p~n", [Pid, Held]); +wait_for_lock(Pid, Nodes, N, Where) -> + rpc:multicall(Nodes, sys, get_status, [mnesia_locker]), + List = case Where of + queue -> + [rpc:call(Node, mnesia, system_info, [lock_queue]) || Node <- Nodes]; + held -> + [rpc:call(Node, mnesia, system_info, [held_locks]) || Node <- Nodes] + end, Q = lists:append(List), - check_q(Pid, Q, Nodes, N). + check_q(Pid, Q, Nodes, N, Where). -check_q(Pid, [{_Oid, _Op, Pid, _Tid, _WFT} | _Tail], _N, _Count) -> ok; -check_q(Pid, [_ | Tail], N, Count) -> check_q(Pid, Tail, N, Count); -check_q(Pid, [], N, Count) -> - timer:sleep(500), - wait_for_lock(Pid, N, Count - 1). +check_q(Pid, [{_Oid, _Op, Pid, _Tid, _WFT} | _Tail], _N, _Count, _Where) -> ok; +check_q(Pid, [{_Oid, _Op, {tid,_,Pid}} | _Tail], _N, _Count, _Where) -> ok; +check_q(Pid, [_ | Tail], N, Count, Where) -> check_q(Pid, Tail, N, Count, Where); +check_q(Pid, [], N, Count, Where) -> + timer:sleep(200), + wait_for_lock(Pid, N, Count - 1, Where). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -270,6 +282,43 @@ advanced_deadlock_conflict(Config) when is_list(Config) -> ?match([], mnesia:system_info(lock_queue)), ok. +%% Verify (and regression test) deadlock in del_table_copy(schema, Node) +schema_deadlock(Config) when is_list(Config) -> + Ns = [Node1, Node2] = ?acquire_nodes(2, Config), + ?match({atomic, ok}, mnesia:create_table(a, [{disc_copies, Ns}])), + ?match({atomic, ok}, mnesia:create_table(b, [{disc_copies, Ns}])), + + Tester = self(), + + Deadlocker = fun() -> + mnesia:write({a,1,1}), %% grab write lock on A + receive + continue -> + mnesia:write({b,1,1}), %% grab write lock on B + end_trans + end + end, + + ?match(stopped, rpc:call(Node2, mnesia, stop, [])), + timer:sleep(500), %% Let Node1 reconfigure + sys:get_status(mnesia_monitor), + + DoingTrans = spawn_link(fun() -> Tester ! {self(),mnesia:transaction(Deadlocker)} end), + wait_for_lock(DoingTrans, [Node1], 10, held), + %% Will grab write locks on schema, a, and b + DoingSchema = spawn_link(fun() -> Tester ! {self(), mnesia:del_table_copy(schema, Node2)} end), + timer:sleep(500), %% Let schema trans start, and try to grab locks + DoingTrans ! continue, + + ?match(ok, receive {DoingTrans, {atomic, end_trans}} -> ok after 5000 -> timeout end), + ?match(ok, receive {DoingSchema, {atomic, ok}} -> ok after 5000 -> timeout end), + + sys:get_status(whereis(mnesia_locker)), % Explicit sync, release locks is async + ?match([], mnesia:system_info(held_locks)), + ?match([], mnesia:system_info(lock_queue)), + ok. + + one_oid(Tab) -> {Tab, 1}. other_oid(Tab) -> {Tab, 2}. @@ -1127,7 +1176,9 @@ update_shared(Tab, Me, Acc) -> 0 -> case mnesia:transaction(Update) of {atomic, {ok,Term,W2}} -> - io:format("~p:~p:(~p,~p) ~w@~w~n", [erlang:now(),node(),Me,Acc,Term,W2]), + io:format("~p:~p:(~p,~p) ~w@~w~n", + [erlang:unique_integer([monotonic,positive]), + node(),Me,Acc,Term,W2]), update_shared(Tab, Me, Acc+1); Else -> ?error("Trans failed on ~p with ~p~n" diff --git a/lib/mnesia/test/mnesia_test_lib.erl b/lib/mnesia/test/mnesia_test_lib.erl index 035d6bde87..9d3b277e07 100644 --- a/lib/mnesia/test/mnesia_test_lib.erl +++ b/lib/mnesia/test/mnesia_test_lib.erl @@ -238,8 +238,8 @@ slave_start_link() -> slave_start_link(Node) -> [Local, Host] = node_to_name_and_host(Node), - {Mega, Sec, Micro} = erlang:now(), - List = [Local, "_", Mega, "_", Sec, "_", Micro], + Count = erlang:unique_integer([positive]), + List = [Local, "_", Count], Name = list_to_atom(lists:concat(List)), slave_start_link(list_to_atom(Host), Name). diff --git a/lib/mnesia/test/mnesia_tpcb.erl b/lib/mnesia/test/mnesia_tpcb.erl index 3f936591b0..c6eda1c448 100644 --- a/lib/mnesia/test/mnesia_tpcb.erl +++ b/lib/mnesia/test/mnesia_tpcb.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2013. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -100,9 +100,13 @@ replica_test/1, sticky_replica_test/1, remote_test/1, - remote_frag2_test/1 + remote_frag2_test/1, + + conflict_benchmark/1 ]). +-include_lib("common_test/include/ct_event.hrl"). + -define(SECOND, 1000000). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -160,7 +164,7 @@ -record(history, { history_id = {0, 0}, % {DriverId, DriverLocalHistoryid} - time_stamp = now(), % Time point during active transaction + time_stamp = erlang:system_time(), % Time point during active transaction branch_id = 0, % Branch associated with teller teller_id = 0, % Teller invlolved in transaction account_id = 0, % Account updated by transaction @@ -192,8 +196,10 @@ driver_nodes = [node()], n_drivers_per_node = 1, use_running_mnesia = false, + seed, stop_after = timer:minutes(15), % Minimum 15 min report_interval = timer:minutes(1), + send_bench_report = false, use_sticky_locks = false, spawn_near_branch = false, activity_type = transaction, @@ -398,8 +404,29 @@ config(remote_frag2_test, ReplicaType) -> {stop_after, timer:minutes(1)}, {report_interval, timer:seconds(10)}, {reuse_history_id, true} + ]; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Ten drivers per node, tables replicated to all nodes, single branch + +config(conflict_benchmark, ReplicaType) -> + Remote = nodes(), + Local = node(), + Nodes = [Local | Remote], + [{db_nodes, Nodes}, + {driver_nodes, Nodes}, + {replica_nodes, Nodes}, + {n_drivers_per_node, 10}, + {n_branches, 1}, + {n_accounts_per_branch, 10}, + {replica_type, ReplicaType}, + {stop_after, timer:minutes(1)}, + {report_interval, timer:seconds(10)}, + {send_bench_report, true}, + {reuse_history_id, true} ]. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% start(What, ReplicaType) -> @@ -423,6 +450,9 @@ remote_test(ReplicaType) -> remote_frag2_test(ReplicaType) -> start(remote_frag2_test, ReplicaType). +conflict_benchmark(ReplicaType) -> + start(config(conflict_benchmark, ReplicaType)). + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Args is a list of {Key, Val} tuples where Key is a field name %% in either the record tab_config or run_config. Unknown keys are ignored. @@ -727,7 +757,7 @@ reporter_init(Starter, RC) -> replica_type = Type }, Drivers = start_drivers(RC, TC), - Now = now_to_micros(erlang:now()), + Now = erlang:monotonic_time(), State = #reporter_state{driver_pids = Drivers, run_config = RC, starter_pid = Starter, @@ -865,8 +895,9 @@ add_time(Acc, New) -> -define(AVOID_DIV_ZERO(_What_), try (_What_) catch _:_ -> 0 end). show_report(State) -> - Now = now_to_micros(erlang:now()), + Now = erlang:timestamp(), Iters = State#reporter_state.n_iters, + Cfg = State#reporter_state.run_config, Time = State#reporter_state.curr, Max = Time#time.max_time, N = Time#time.n_trans, @@ -889,6 +920,16 @@ show_report(State) -> "duration of longest transaction was ~p milliseconds~n", [Tps, BruttoTps, Max div 1000]) end, + case Cfg#run_config.send_bench_report of + true -> + ct_event:notify( + #event{name = benchmark_data, + data = [{suite,"mnesia_tpcb"}, + {value,Tps}]}); + _ -> + ok + end, + State#reporter_state{prev_tps = Tps, prev_micros = Now}. signed_diff(Iters, Curr, Prev) -> @@ -899,11 +940,6 @@ signed_diff(Iters, Curr, Prev) -> sign(N) when N > 0 -> {"+", N}; sign(N) -> {"", N}. - -now_to_micros({Mega, Secs, Micros}) -> - DT = calendar:now_to_datetime({Mega, Secs, 0}), - S = calendar:datetime_to_gregorian_seconds(DT), - (S * ?SECOND) + Micros. start_drivers(RC, TC) -> LastHistoryId = table_info(history, size), @@ -956,7 +992,11 @@ alloc_local_branches([], Specs, OrphanBranches) -> {Specs, OrphanBranches}. driver_init(DS, AllBranches) -> - Seed = erlang:now(), + Seed = case (DS#driver_state.run_config)#run_config.seed of + undefined -> rand:seed(exsplus); + ExpSeed -> rand:seed(ExpSeed) + end, + DS2 = if DS#driver_state.n_local_branches =:= 0 -> @@ -1010,14 +1050,7 @@ calc_trans(DS) -> %% Generate teller_id, account_id and delta %% Time the TPC-B transaction time_trans(DS) -> - OldSeed = get(random_seed), % Avoid interference with Mnesia - put(random_seed, DS#driver_state.seed), - Random = random:uniform(), - NewSeed = get(random_seed), - case OldSeed of - undefined -> erase(random_seed); - _ -> put(random_seed, OldSeed) - end, + {Random, NewSeed} = rand:uniform_s(DS#driver_state.seed), TC = DS#driver_state.tab_config, RC = DS#driver_state.run_config, diff --git a/lib/mnesia/vsn.mk b/lib/mnesia/vsn.mk index 79dd495c4b..194bc439a0 100644 --- a/lib/mnesia/vsn.mk +++ b/lib/mnesia/vsn.mk @@ -1 +1 @@ -MNESIA_VSN = 4.13 +MNESIA_VSN = 4.13.4 diff --git a/lib/observer/doc/src/cdv.xml b/lib/observer/doc/src/cdv.xml index ee629bbd3f..df1032780a 100644 --- a/lib/observer/doc/src/cdv.xml +++ b/lib/observer/doc/src/cdv.xml @@ -4,7 +4,7 @@ <comref> <header> <copyright> - <year>2013</year> + <year>2003</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -33,16 +33,16 @@ <file>cdv.xml</file> </header> <com>cdv</com> - <comsummary>Script used for starting the Crashdump Viewer from the + <comsummary>Script to start the Crashdump Viewer from the OS command line. </comsummary> <description> - <p>The <c>cdv</c> shell script can be found under the <c>priv</c> - directory of the <c>observer</c> application. The script is used + <p>The <c>cdv</c> shell script is located in directory <c>priv</c> + of the Observer application. The script is used for starting the Crashdump Viewer tool from the OS command line.</p> - <p>For Windows users, <c>cdv.bat</c> can be found in the same + <p>For Windows users, <c>cdv.bat</c> is found in the same location.</p> </description> @@ -51,8 +51,8 @@ <name>cdv [file]</name> <fsummary>Start the Crashdump Viewer and load the given file.</fsummary> <desc> - <p>The <c>file</c> arguments is optional. If not given, a file - dialog will pop up allowing the user to select a crashdump + <p>Argument <c>file</c> is optional. If not specified, a file + dialog is displayed, allowing you to select a crashdump from the file system.</p> </desc> </func> diff --git a/lib/observer/doc/src/crashdump.xml b/lib/observer/doc/src/crashdump.xml index 76deee45f6..27e88d07e5 100644 --- a/lib/observer/doc/src/crashdump.xml +++ b/lib/observer/doc/src/crashdump.xml @@ -25,7 +25,7 @@ </legalnotice> <title>crashdump_viewer</title> - <prepared>Siri hansen</prepared> + <prepared>Siri Hansen</prepared> <responsible></responsible> <docno>1</docno> <approved></approved> @@ -41,32 +41,31 @@ <p>The Crashdump Viewer is a WxWidgets based tool for browsing Erlang crashdumps.</p> - <p>See the <seealso marker="crashdump_ug">user's guide</seealso> - for more information about how to get started with the Crashdump - Viewer.</p> + <p>For details about how to get started with the Crashdump Viewer, see the + <seealso marker="crashdump_ug"><c>User's Guide</c></seealso>.</p> </description> <funcs> <func> <name>start() -> ok</name> <name>start(File) -> ok</name> - <fsummary>Start the crashdump_viewer</fsummary> + <fsummary>Start the Crashdump Viewer.</fsummary> <type> <v>File = string()</v> - <d>The file name of the crashdump.</d> + <d>The filename of the crashdump.</d> </type> <desc> - <p>This function starts the <c>crashdump_viewer</c> GUI and - loads the given crashdump.</p> + <p>Starts the Crashdump Viewer GUI and + loads the specified crashdump.</p> - <p>If <c>File</c> is not given, a file dialog will be opened + <p>If <c>File</c> is not specified, a file dialog is opened where the crashdump can be selected.</p> </desc> </func> <func> <name>stop() -> ok</name> - <fsummary>Stop the crashdump_viewer</fsummary> + <fsummary>Terminate the Crashdump Viewer.</fsummary> <desc> - <p>This function stops the <c>crashdump_viewer</c> and closes + <p>Terminates the Crashdump Viewer and closes all GUI windows.</p> </desc> </func> diff --git a/lib/observer/doc/src/crashdump_ug.xml b/lib/observer/doc/src/crashdump_ug.xml index 3cd97f2f18..4ba057c3fb 100644 --- a/lib/observer/doc/src/crashdump_ug.xml +++ b/lib/observer/doc/src/crashdump_ug.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2003</year><year>2013</year> + <year>2003</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -39,373 +39,390 @@ <section> <title>Getting Started</title> - <p>The easiest way to start Crashdump Viewer is to use the - provided shell script named <c>cdv</c> with the full path to the - erlang crashdump as an argument. The script can be found in the - priv directory of the <c>observer</c> application. This starts the - Crashdump Viewer GUI and loads the given file. If no file name is - given, a file dialog will be opened where the file can be + <p>The easiest way to start Crashdump Viewer is to use + shell script <c>cdv</c> with the full path to the + Erlang crashdump as argument. The script is located in + directory <c>priv</c> of the Observer application. This starts the + Crashdump Viewer GUI and loads the specified file. If no filename is + specified, a file dialog is opened where the file can be selected.</p> - <p>Under Windows the batch file <c>cdv.bat</c> can be used.</p> + <p>Under Windows, the batch file <c>cdv.bat</c> can be used.</p> - <p>It is also possible to start the Crashdump Viewer from within - an erlang node by calling <seealso + <p>Crashdump Viewer can also be started from + an Erlang node by calling <seealso marker="crashdump_viewer#start/0">crashdump_viewer:start/0</seealso> or <seealso marker="crashdump_viewer#start/1">crashdump_viewer:start/1</seealso>.</p> </section> <section> - <title>The graphical interface</title> + <title>GUI</title> - <p>The main window is opened when Crashdump Viewer has loaded a - crashdump. It contains a title bar, a menu bar, a number of - information panels and a status bar.</p> + <p>The GUI main window is opened when Crashdump Viewer has loaded a + crashdump. It contains a title bar, a menu bar, + information tabs, and a status bar.</p> <p>The title bar shows the name of the currently loaded crashdump.</p> <p>The menu bar contains a <em>File</em> menu and a <em>Help</em> - menu. From the File menu a new crashdump can be loaded or the tool - can be terminated. From the Help menu this user's guide and the - chapter "How to interpret the Erlang crash dumps" from the user's - guide for Erlang runtime system can be opened. "How to interpret + menu. From the <em>File</em> menu, a new crashdump can be loaded or + the tool can be terminated. From the <em>Help</em> menu, this User's Guide + and section "How to interpret the Erlang crash dumps" from the + ERTS application can be opened. "How to interpret the Erlang crash dumps" describes the raw crashdumps in - detail. Here you will also find information about each single - field in the different information pages. This document can also - be found directly in the OTP online documentation, via the Erlang - runtime system user's guide.</p> + detail and includes information about each + field in the information pages."How to interpret the Erlang crash dumps" + is also available in the OTP online documentation.</p> - <p>The status bar at the bottom of the window will show a warning + <p>The status bar at the bottom of the window shows a warning if the currently loaded dump is truncated.</p> - <p>The centre area of the main window contains the information - panels. Each panel displays information about a specific item or a - list of items. A panel is selected by clicking the title of the - tab.</p> + <p>The center area of the main window contains the information + tabs. Each tab displays information about a specific item or a + list of items. Select a tab by clicking the tab title.</p> - <p>From panels that display lists of items, for example the - Processes- or the Ports panel, a new window with further - information can be opened by double clicking a row or by right - clicking the row and selecting an item from the drop down + <p>From tabs displaying lists of items, for example, the + <em>Processes</em> tab or the <em>Ports</em> tab, a new window with + more information can be opened by double-clicking a row or by right- + clicking the row and selecting an item from the drop-down menu. The new window is called a detail window. Detail windows can - be opened for processes, ports, nodes and modules.</p> + be opened for processes, ports, nodes, and modules.</p> - <p>The various information shown in a detail window might contain - links to processes or ports. Clicking one of these links will open + <p>The information shown in a detail window can contain + links to processes or ports. Clicking one of these links opens the detail window for the process or port in question. If the - process or port resided on a remote node, there will be no - information available. Clicking the link will then pop up a dialog - where you can choose whether to open the detail window for the - remote node or not. + process or port resides on a remote node, no + information is available. Clicking the link then displays a dialog + where you can choose to open the detail window for the + remote node. </p> - <p>Some of the panels contain a left hand menu where sub items of - the panel's information area can be selected. Click on one of the - rows, and the information will be displayed in the right hand + <p>Some tabs contain a left-hand menu where subitems of + the information area can be selected. Click one of the + rows, and the information is displayed in the right-hand information area.</p> </section> <section> - <title>Data content</title> - - <p>Each panel in the main window contains an information - page. If no information is found for an item, the page will be - empty. The reason for not finding any information about an item - can be that the dump is truncated, that it is a dump from an old - OTP release in which this item was not written or that the item - simply wasn't present in the system at the point of failure.</p> - - <p>If the dump was truncated, a warning is displayed in the - status bar of the main window.</p> - - <p>Even if some information about an item exists, there might be + <title>Tab Content</title> + + <p>Each tab in the main window contains an information + page. If no information is found for an item, the page is + empty. The reason for not finding information about an item + can be the following:</p> + <list type="bulleted"> + <item>It is a dump from an old OTP release in which this item was not written.</item> + <item>The item was not present in the system at the point of failure.</item> + <item>The dump is truncated. In this case, a warning is displayed in the + status bar of the main window.</item> + </list> + + <p></p> + + <p>Even if some information about an item exists, there can be empty fields if the dump originates from an old OTP release.</p> - <p>The value "-1" in any field means "unknown", and in most + <p>The value <c>-1</c> in any field means "unknown", and in most cases it means that the dump was truncated somewhere around this field.</p> - <p>The sections below describe some of the fields in the - different information panels. These are fields that do not exist + <p>The following sections describe some of the fields in the + information tabs. These are fields that do not exist in the raw crashdump, or in some way differ from the fields in - the raw crashdump. Details about other fields can be found in - the user's guide for the Erlang runtime system, in the chapter - "How to interpret the Erlang crash dumps". That chapter can also - be opened from the Help menu in the Crashdump Viewer's main - window, and there are also direct links from the specific - sections below to related information in "How to interpret the - Erlang crash dumps".</p> + the raw crashdump. For details about other fields, see + the + <seealso marker="erts:users_guide">ERTS User's Guide</seealso>, section + "How to interpret the Erlang crash dumps". That section can also + be opened from the <em>Help</em> menu in the main window. + There are also links from the following sections to related information + in "How to interpret the Erlang crash dumps".</p> </section> <section> <marker id="general_info"/> - <title>General information</title> + <title>General Tab</title> - <p>The <em>General information</em> panel shows a short overview + <p>Tab <em>General</em> shows a short overview of the dump.</p> - <p>The following fields are not described in the Erlang runtime - system user's guide:</p> + <p>The following fields are not described in the ERTS + User's Guide:</p> <taglist> - <tag><em>Crashdump created on</em></tag> - <item>Time of failure.</item> - - <tag><em>Memory allocated</em></tag> - <item>The total number of bytes allocated, equivalent to - <c>c:memory(total)</c>.</item> - - <tag><em>Memory maximum</em></tag> - <item>The maximum number of bytes that has been allocated during - the lifetime of the originating node. This will only be shown if - the Erlang runtime system was run instrumented.</item> - - <tag><em>Atoms</em></tag> - <item>If available in the dump, this is the total number of - atoms in the atom table. If the size of the atom table is not - available, the number of atoms visible in the dump is - presented.</item> - - <tag><em>Processes, ETS tables and Funs</em></tag> - <item>The number of processes, ETS tables and funs visible in - the dump.</item> + <tag><c>Crashdump created on</c></tag> + <item><p>Time of failure.</p></item> + + <tag><c>Memory allocated</c></tag> + <item><p>The total number of bytes allocated, equivalent to + <c>c:memory(total)</c>.</p></item> + + <tag><c>Memory maximum</c></tag> + <item><p>The maximum number of bytes that has been allocated during + the lifetime of the originating node. This is only shown if + the Erlang runtime system is run instrumented.</p></item> + + <tag><c>Atoms</c></tag> + <item><p>If available in the dump, this is the total number of + atoms in the atom table. If the size of the atom table is + unavailable, the number of atoms visible in the dump is + displayed.</p></item> + + <tag><c>Processes</c></tag> + <item><p>The number of processes visible in the dump.</p></item> + + <tag><c>ETS tables</c></tag> + <item><p>The number of ETS tables visible in the dump.</p></item> + + <tag><c>Funs</c></tag> + <item><p>The number of funs visible in the dump.</p></item> </taglist> - <p> - <seealso marker="erts:crash_dump#general_info">More...</seealso> + <p>For details, see + <seealso marker="erts:crash_dump#general_info">General Information</seealso> + in section "How to Interpret the Erlang Crash Dumps" in ERTS. </p> </section> <section> <marker id="processes"/> - <title>Processes</title> + <title>Processes Tab</title> - <p>The <em>Processes</em> panel shows a list of all processes - found in the crashdump, including some short information about - each process. By default the processes are sorted by their - pids. To sort by other topic, click the desired column - heading.</p> + <p>Tab <em>Processes</em> shows a list of all processes + found in the crashdump, including brief information about + each process. By default, the processes are sorted by their + pids. To sort by another topic, click the desired column heading.</p> - <p>The <em>Memory</em> column shows the 'Memory' field which was - added to crashdumps in R16B01. This is the total amount of memory + <p>Column <em>Memory</em> shows the 'Memory' field that was + added to crashdumps in Erlang/OTP R16B01. This is the total amount of memory used by the process. For crashdumps from earlier releases, this - column shows the 'Stack+heap' field. The value shown is always in - bytes.</p> + column shows the 'Stack+heap' field. The value is always in bytes.</p> - <p>To view detailed information about a specific process, double - click the row in the list or right click the row and select - "Properties for <pid>".</p> + <p>To view detailed information about a specific process, double- + click the row in the list, or right-click the row and select + <em>Properties for <pid></em>.</p> - <p> - <seealso marker="erts:crash_dump#processes">More...</seealso> + <p>For details, see + <seealso marker="erts:crash_dump#processes">Process Information</seealso> + in section "How to Interpret the Erlang Crash Dumps" in ERTS. </p> </section> <section> <marker id="ports"/> - <title>Ports</title> + <title>Ports Tab</title> - <p>The <em>Ports</em> panel is similar to the <em>Processes</em> - panel, except it lists all ports found in the crashdump.</p> + <p>Tab <em>Ports</em> is similar to the <em>Processes</em> + tab, except it lists all ports found in the crashdump.</p> - <p>To see more details about a specific port, dobule click the row - or right click it and select "Properties for <port>". From - the right click menu you can also select "Properties for - <pid>", where <pid> is the process connected to the + <p>To view more details about a specific port, double-click the row + or right-click it and select <em>Properties for <port></em>. From + the right-click menu, you can also select <em>Properties for + <pid></em>, where <c><pid></c> is the process connected to the port.</p> - <p> - <seealso marker="erts:crash_dump#ports"> - More...</seealso> + <p>For details, see + <seealso marker="erts:crash_dump#ports">Port Information</seealso> + in section "How to Interpret the Erlang Crash Dumps" in ERTS. </p> </section> <section> <marker id="ets_tables"/><marker id="internal_ets_tables"/> - <title>ETS tables</title> + <title>ETS Tables Tab</title> - <p>The <em>ETS Tables</em> panel shows all ETS table information - found in the dump. The 'Id' is the same as the 'Table' field found - in the raw crashdump, and 'Memory' is the 'Words' field from the - raw crashdump translated into bytes. For tree tables there will - be no value in the 'Objects' field.</p> + <p>Tab <em>ETS Tables</em> shows all ETS table information + found in the dump. <em>Id</em> is the same as the 'Table' field + in the raw crashdump. <em>Memory</em> is the 'Words' field from the + raw crashdump translated into bytes. For tree tables, there is + no value in the 'Objects' field.</p> - <p>To open the detailed information page about the table, double - click or right click the row and select "Properties for - 'Identifier'".</p> + <p>To open the detailed information page about the table, double- + click, or right-click the row and select <em>Properties for + 'Identifier'</em>.</p> <p>To open the detailed information page about the owner process - of an ETS table, right click the row and select "Properties for - <pid>".</p> + of an ETS table, right-click the row and select <em>Properties for + <pid></em>.</p> - <p> - <seealso marker="erts:crash_dump#ets_tables"> - More...</seealso> + <p>For details, see + <seealso marker="erts:crash_dump#ets_tables">ETS Tables</seealso> + in section "How to Interpret the Erlang Crash Dumps" in ERTS. </p> </section> <section> <marker id="timers"/> - <title>Timers</title> + <title>Timers Tab</title> - <p>The <em>Timers</em> panel shows all timer information found in + <p>Tab <em>Timers</em> shows all timer information found in the dump.</p> <p>To open the detailed information page about the owner process - of a timer, right click the row and select "Properties for - <pid>".</p> + of a timer, right-click the row and select <em>Properties for + <pid></em>.</p> - <p>Double clicking a row in the Timers panel has no effect.</p> + <p>Double-clicking a row in the <em>Timers</em> tab has no effect.</p> - <p> - <seealso marker="erts:crash_dump#timers">More...</seealso> + <p>For details, see + <seealso marker="erts:crash_dump#timers">Timers</seealso> + in section "How to Interpret the Erlang Crash Dumps" in ERTS. </p> </section> <section> <marker id="schedulers"/> - <title>Schedulers</title> + <title>Schedulers Tab</title> - <p>The <em>Schedulers</em> panel shows all scheduler information + <p>Tab <em>Schedulers</em> shows all scheduler information found in the dump.</p> <p>To open the detailed information page about the scheduler, - double click or right click the row and select "Properties for - 'Identifier'".</p> + double-click, or right-click the row and select <em>Properties for + 'Identifier'</em>.</p> - <p> - <seealso marker="erts:crash_dump">More...</seealso> + <p>For details, see + <seealso marker="erts:crash_dump#scheduler">Scheduler Information</seealso> + in section "How to Interpret the Erlang Crash Dumps" in ERTS. </p> </section> <section> <marker id="funs"/> - <title>Funs</title> + <title>Funs Tab</title> - <p>The <em>Funs</em> panel shows all Fun information found in the + <p>Tab <em>Funs</em> shows all fun information found in the dump.</p> <p>To open the detailed information page about the module to which - the fun belongs, right click the row and select "Properties for - <mod>".</p> + the fun belongs, right-click the row and select <em>Properties for + <mod></em>.</p> - <p>Double clicking a row in the Funs panel has no effect.</p> + <p>Double-clicking a row in the <em>Funs</em> tab has no effect.</p> - <p> - <seealso marker="erts:crash_dump#funs">More...</seealso> + <p>For details, see + <seealso marker="erts:crash_dump#funs">Fun Information</seealso> + in section "How to Interpret the Erlang Crash Dumps" in ERTS. </p> </section> <section> <marker id="atoms"/> - <title>Atoms</title> + <title>Atoms Tab</title> - <p>The <em>Atoms</em> panel lists all atoms found in the dump. By + <p>Tab <em>Atoms</em> lists all atoms found in the dump. By default the atoms are sorted in creation order from first to last. This is opposite of the raw crashdump where atoms are listed from last to first, meaning that if the dump was truncated in the - middle of the atom list only the last created atoms will be seen - in the <em>Atoms</em> panel.</p> + middle of the atom list, only the last created atoms are visible + in the <em>Atoms</em> tab.</p> - <p> - <seealso marker="erts:crash_dump#atoms">More...</seealso> + <p>For details, see + <seealso marker="erts:crash_dump#atoms">Atoms</seealso> + in section "How to Interpret the Erlang Crash Dumps" in ERTS. </p> </section> <section> <marker id="distribution_info"/> - <title>Nodes</title> + <title>Nodes Tab</title> - <p>The <em>Nodes</em> panel shows a list of all external erlang - nodes which are referenced from the crashdump.</p> + <p>Tab <em>Nodes</em> shows a list of all external Erlang + nodes that are referenced from the crashdump.</p> - <p>If the page is empty it either means that the crashed node was - not distributed, that it was distributed but had no references to - other nodes or that the dump was truncated.</p> + <p>If the page is empty, it means either of the following:</p> + <list type="bulleted"> + <item>The crashed node is not distributed.</item> + <item>The crashed node is distributed but has no references to other nodes.</item> + <item>The dump is truncated.</item> + </list> - <p>If the node was distributed, all referenced nodes are - shown. The column named <em>Connection type</em> shows if the node - is visible, hidden or not connected. Visible nodes are alive nodes + <p>If the node is distributed, all referenced nodes are + visible. Column <em>Connection type</em> shows if the node + is visible, hidden, or not connected. Visible nodes are alive nodes with a living connection to the originating node. Hidden nodes are - the same as visible nodes, except they are started with the - <c>-hidden</c> flag. Not connected nodes are nodes that are not + the same as visible nodes, except they are started with flag + <c>-hidden</c>. Not connected nodes are nodes that are not connected to the originating node anymore, but references - (i.e. process or port identifiers) exist.</p> + (that is, process or port identifiers) exist.</p> - <p>To see more detailed information about a node, double click the - row or right click the row and select "Properties for node - <node>". From the right click menu you can also select - "Properties for <port>", to open the detailed information + <p>To see more detailed information about a node, double-click the + row, or right-click the row and select <em>Properties for node + <node></em>. From the right-click menu, you can also select + <em>Properties for <port></em>, to open the detailed information window for the controlling port.</p> - <p>In the detailed information window for a node, any exsisting + <p>In the detailed information window for a node, any existing links and monitors between processes on the originating node and - the connected node are shown. <em>Extra Info</em> may contain - debug information (i.e. special information written if the - emulator is debug compiled) or error information.</p> + the connected node are displayed. <em>Extra Info</em> can contain + debug information (that is, special information written if the + emulator is debug-compiled) or error information.</p> - <p> - <seealso marker="erts:crash_dump#distribution_info"> - More...</seealso> + <p>For details, see + <seealso marker="erts:crash_dump#distribution_info">Distribution Information</seealso> + in section "How to Interpret the Erlang Crash Dumps" in ERTS. </p> </section> <section> <marker id="loaded_modules"/> - <title>Loaded modules</title> + <title>Modules Tab</title> - <p>The <em>Modules</em> panel lists all modules that were loaded - on the originating node, and the current size of the code. If old - code exsits, the old size is also shown.</p> + <p>Tab <em>Modules</em> lists all modules loaded + on the originating node, and the current code size. If old + code exists, the old size is also shown.</p> - <p>To see detailed information about a specific module, double - click the row or right click it and select "Properties for - <mod>".</p> + <p>To view detailed information about a specific module, double- + click the row, or right-click it and select <em>Properties for + <mod></em>.</p> - <p> - <seealso marker="erts:crash_dump#loaded_modules"> - More...</seealso> + <p>For details, see + <seealso marker="erts:crash_dump#loaded_modules">Loaded Module Information</seealso> + in section "How to Interpret the Erlang Crash Dumps" in ERTS. </p> </section> <section> <marker id="memory"/> - <title>Memory</title> + <title>Memory Tab</title> - <p>The <em>Memory</em> panel shows memory and allocator - information. From the left hand menu you can select:</p> + <p>Tab <em>Memory</em> shows memory and allocator + information. From the left-hand menu you can select the following:</p> - <p> - <list> + <taglist> + <tag><em>Memory</em></tag> + <item><p>See + <seealso marker="erts:crash_dump#memory">Memory Information</seealso> + in section "How to Interpret the Erlang Crash Dumps" in ERTS.</p></item> - <item><em>Memory</em> <seealso - marker="erts:crash_dump#memory">More...</seealso></item> + <tag><em>Allocator Summary</em></tag> + <item><p>This page presents a summary of values from all allocators underneath it.</p></item> - <item><em>Allocator Summary</em> - this page presents a - summary of values from all allocators below.</item> + <tag><em><Allocator></em></tag> + <item><p>One entry per allocator. See + <seealso marker="erts:crash_dump#allocator">Allocator</seealso> + in section "How to Interpret the Erlang Crash Dumps" in ERTS.</p></item> - <item><em><Allocator></em> - one entry per allocator - <seealso - marker="erts:crash_dump#allocator">More...</seealso></item> + <tag><em>Allocated Areas</em></tag> + <item><p>See + <seealso marker="erts:crash_dump#allocated_areas">Allocated Areas</seealso> + in section "How to Interpret the Erlang Crash Dumps" in ERTS.</p></item> - <item><em>Allocated Areas</em> <seealso - marker="erts:crash_dump#allocated_areas">More...</seealso></item> - - </list> - </p> + </taglist> </section> <section> <marker id="internal_tables"/> - <title>Internal tables</title> + <title>Internal Tables Tab</title> - <p>On the <em>Internal Tables</em> panel you can choose from the - left hand menu to see hash tables or index tables.</p> + <p>On tab <em>Internal Tables</em> you can from the + left-hand menu select <em>Hash Tables</em>, <em>Index Tables</em>, + or <em>Internal ETS Tables</em>.</p> - <p> - <seealso marker="erts:crash_dump#internal_tables">More...</seealso> + <p>For details, see + <seealso marker="erts:crash_dump#internal_tables">Internal Table Information</seealso> + in section "How to Interpret the Erlang Crash Dumps" in ERTS. </p> </section> </chapter> diff --git a/lib/observer/doc/src/etop.xml b/lib/observer/doc/src/etop.xml index c1e336177f..52f3b2a156 100644 --- a/lib/observer/doc/src/etop.xml +++ b/lib/observer/doc/src/etop.xml @@ -25,7 +25,7 @@ </legalnotice> <title>etop</title> - <prepared>Siri hansen</prepared> + <prepared>Siri Hansen</prepared> <responsible></responsible> <docno></docno> <approved></approved> @@ -35,89 +35,79 @@ <file></file> </header> <module>etop</module> - <modulesummary>Erlang Top is a tool for presenting information about erlang processes similar to the information presented by "top" in UNIX.</modulesummary> + <modulesummary>Erlang Top is a tool for presenting information about Erlang + processes similar to the information presented by "top" in UNIX.</modulesummary> <description> - <p><c>etop</c> should be started with the provided scripts - <c>etop</c>. This will start a hidden erlang node - which connects to the node to be measured. The measured node is - given with the <c>-node</c> option. If the measured node has a + <p>Start Erlang Top with the provided scripts + <c>etop</c>. This starts a hidden Erlang node + that connects to the node to be measured. The measured node is + specified with option <c>-node</c>. If the measured node has a different cookie than the default cookie for the user who - invokes the script, the cookie must be explicitly given witht - the <c>-setcookie</c> option.</p> + invokes the script, the cookie must be explicitly specified with + option <c>-setcookie</c>.</p> - <p>Under Windows the batch file <c>etop.bat</c> can be used.</p> + <p>Under Windows, batch file <c>etop.bat</c> can be used.</p> - <p>The following configuration parameters exist for the - <c>etop</c> tool. When executing the <c>etop</c> script, - these parameters can be given as command line options, - e.g. <c>etop -node testnode@myhost -setcookie MyCookie</c>.</p> + <p>When executing the <c>etop</c> script, configuration + parameters can be specified as command-line options, + for example, <c>etop -node testnode@myhost -setcookie MyCookie</c>. + The following configuration parameters exist for the + tool:</p> <taglist> - <tag>node</tag> - <item>The measured node. - <br></br> -Value: atom() - <br></br> -Mandatory</item> - <tag>setcookie</tag> - <item>Cookie to use for the etop node - must be the same - as the cookie on the measured node. - <br></br> -Value: atom()</item> - <tag>lines</tag> - <item>Number of lines (processes) to display. - <br></br> -Value: integer() - <br></br> -Default: 10</item> - <tag>interval</tag> - <item>The time interval (in seconds) between each update of - the display. - <br></br> -Value: integer() - <br></br> -Default: 5</item> - <tag>accumulate</tag> - <item>If <c>true</c> the execution time and reductions are - accumulated. - <br></br> -Value: boolean() - <br></br> -Default: <c>false</c></item> - <tag>sort</tag> - <item>Identifies what information to sort by. - <br></br> -Value: <c>runtime | reductions | memory | msg_q</c> <br></br> -Default: <c>runtime</c> (<c>reductions</c> if - <c>tracing=off</c>)</item> - <tag>tracing</tag> - <item><c>etop</c> uses the erlang trace facility, and thus no + <tag><c>node</c></tag> + <item><p>The measured node.</p> + <p>Value: <c>atom()</c></p> + <p>Mandatory</p></item> + <tag><c>setcookie</c></tag> + <item><p>Cookie to use for the <c>etop</c> node. Must be same as the + cookie on the measured node.</p> + <p>Value: <c>atom()</c></p></item> + <tag><c>lines</c></tag> + <item><p>Number of lines (processes) to display.</p> + <p>Value: <c>integer()</c></p> + <p>Default: <c>10</c></p></item> + <tag><c>interval</c></tag> + <item><p>Time interval (in seconds) between each update of + the display.</p> + <p>Value: <c>integer()</c></p> + <p>Default: <c>5</c></p></item> + <tag><c>accumulate</c></tag> + <item><p>If <c>true</c>, the execution time and reductions are + accumulated.</p> + <p>Value: <c>boolean()</c></p> + <p>Default: <c>false</c></p></item> + <tag><c>sort</c></tag> + <item><p>Identifies what information to sort by.</p> + <p>Value: <c>runtime | reductions | memory | msg_q</c></p> + <p>Default: <c>runtime</c> (<c>reductions</c> if <c>tracing=off</c>)</p></item> + <tag><c>tracing</c></tag> + <item><p><c>etop</c> uses the Erlang trace facility, and thus no other tracing is possible on the measured node while <c>etop</c> is running, unless this option is set to <c>off</c>. Also helpful if the <c>etop</c> tracing causes too high load on the measured node. With tracing off, runtime is - not measured. - <br></br> -Value: <c>on | off</c> <br></br> -Default: <c>on</c></item> + not measured.</p> + <p>Value: <c>on | off</c></p> + <p>Default: <c>on</c></p></item> </taglist> - <p>See the <seealso marker="etop_ug">user's guide</seealso> for - more information about the <c>etop</c> tool.</p> + <p>For detalis about Erlang Top, see the + <seealso marker="etop_ug">User's Guide</seealso>.</p> </description> <funcs> <func> <name>start() -> ok</name> - <fsummary>Start etop</fsummary> + <fsummary>Start etop.</fsummary> <desc> - <p>This function starts <c>etop</c>. - Note that etop is preferably started with the etop script.</p> + <p>Starts <c>etop</c>. + Notice that <c>etop</c> is preferably started with the <c>etop</c> script.</p> </desc> </func> <func> <name>start(Options) -> ok</name> - <fsummary>Start etop</fsummary> + <fsummary>Start etop.</fsummary> <type> <v>Options = [Option]</v> <v>Option = {Key, Value}</v> @@ -125,31 +115,30 @@ Default: <c>on</c></item> <v>Value = term()</v> </type> <desc> - <p>This function starts <c>etop</c>. Use - <seealso marker="#help/0">help/0</seealso> to see a - description of the possible options.</p> + <p>Starts <c>etop</c>. To view the possible options, use + <seealso marker="#help/0"><c>help/0</c></seealso>.</p> </desc> </func> <func> <name>help() -> ok</name> - <fsummary>Print etop's help</fsummary> + <fsummary>Display the etop help.</fsummary> <desc> - <p>This function prints the help of <c>etop</c> and + <p>Displays the help of <c>etop</c> and its options.</p> </desc> </func> <func> <name>config(Key,Value) -> Result</name> - <fsummary>Change tool's configuration</fsummary> + <fsummary>Change the configuration of the tool.</fsummary> <type> <v>Result = ok | {error,Reason}</v> <v>Key = lines | interval | accumulate | sort</v> <v>Value = term()</v> </type> <desc> - <p>This function is used to change the tool's configuration - parameters during runtime. The table above indicates the - allowed values for each parameter.</p> + <p>Changes the configuration parameters of the tool during runtime. + Allowed parameters are <c>lines</c>, <c>interval</c>, <c>accumulate</c>, + and <c>sort</c>.</p> </desc> </func> <func> @@ -160,14 +149,14 @@ Default: <c>on</c></item> <v>File = string()</v> </type> <desc> - <p>This function dumps the current display to a text file.</p> + <p>Dumps the current display to a text file.</p> </desc> </func> <func> <name>stop() -> stop</name> - <fsummary>Terminate etop</fsummary> + <fsummary>Terminate etop.</fsummary> <desc> - <p>This function terminates <c>etop</c>.</p> + <p>Terminates <c>etop</c>.</p> </desc> </func> </funcs> diff --git a/lib/observer/doc/src/etop_ug.xml b/lib/observer/doc/src/etop_ug.xml index 7059f689d3..d663b089c2 100644 --- a/lib/observer/doc/src/etop_ug.xml +++ b/lib/observer/doc/src/etop_ug.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2002</year><year>2013</year> + <year>2002</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -32,15 +32,25 @@ <section> <title>Introduction</title> - <p>Erlang Top, <c>etop</c> is a tool for presenting information - about erlang processes similar to the information presented by + <p>Erlang Top, <c>etop</c>, is a tool for presenting information + about Erlang processes similar to the information presented by <c>top</c> in UNIX. </p> </section> + <section> + <title>Getting Started</title> + <p>Start Erlang Top in either of the following ways:</p> + <list type="bulleted"> + <item>Use script <c>etop</c>.</item> + <item>Use batch file <c>etop.bat</c>, for example, + <c>etop -node tiger@durin</c>.</item> + </list> + </section> + <section> <title>Output</title> - <p>The output from <c>etop</c> looks like this:</p> + <p>The output from Erlang Top is as follows:</p> <code type="none"><![CDATA[ ======================================================================================== tiger@durin 13:40:32 @@ -65,59 +75,60 @@ Pid Name or Initial Func Time Reds Memory MsgQ Current Func <p>The header includes some system information: </p> <taglist> - <tag>Load</tag> - <item><c>cpu</c> is <c>Runtime/Wallclock</c>, i.e. the - percentage of time where the node has been - active, <c>procs</c> is the number of processes on the node, - and <c>runq</c> is the number of processes that are ready to - run.</item> - <tag>Memory</tag> - <item>This is the memory allocated by the node in kilo bytes.</item> + <tag><c>Load</c></tag> + <item> + <taglist> + <tag><c>cpu</c></tag> + <item><p><c>Runtime/Wallclock</c>, that is, the percentage of time + where the node has been active.</p></item> + <tag><c>procs</c></tag> + <item><p>The number of processes on the node.</p></item> + <tag><c>runq</c></tag> + <item><p>The number of processes that are ready to run.</p></item> + </taglist> + </item> + <tag><c>Memory</c></tag> + <item><p>The memory allocated by the node in kilobytes.</p></item> </taglist> <p>For each process the following information is presented: </p> <taglist> - <tag>Time</tag> - <item>This is the runtime for the process, i.e. the actual - time the process has been scheduled in.</item> - <tag>Reds</tag> - <item>This is the number of reductions that has been executed - on the process</item> - <tag>Memory</tag> - <item>This is the size of the process in bytes, obtained by a - call to <c>process_info(Pid,memory)</c>.</item> - <tag>MsgQ</tag> - <item>This is the length of the message queue for the process.</item> + <tag><c>Time</c></tag> + <item><p>The runtime for the process, that is, the time that the process + has been scheduled in.</p></item> + <tag><c>Reds</c></tag> + <item><p>The number of reductions executed on the process.</p></item> + <tag><c>Memory</c></tag> + <item><p>The size of the process in bytes, obtained by a + call to <c>process_info(Pid,memory)</c>.</p></item> + <tag><c>MsgQ</c></tag> + <item><p>The length of the message queue for the process.</p></item> </taglist> <note> <p><em>Time</em> and <em>Reds</em> can be presented as - accumulated values or as values since last update.</p> + accumulated values or as values since the last update.</p> </note> </section> - <section> - <title>Start</title> - <p>To start etop use the script - <c>etop</c> or the batch file <c>etop.bat</c>, e.g. <c>etop -node tiger@durin</c>, - </p> - </section> - - <section> + <section> <title>Configuration</title> <p>All configuration parameters can be set at start by adding - <c>-OptName Value</c> to the command line, e.g. <c>etop -node tiger@durin -setcookie mycookie -lines 15</c>. - </p> - <p>The parameters <c>lines</c>, <c>interval</c>, <c>accumulate</c> - and <c>sort</c> can be changed during runtime by the - function <c>etop:config/2</c>. - </p> - <p>A list of all valid configuration parameters can be found in - the reference manual for <c>etop</c>. + <c>-OptName Value</c> to the command line, for example:</p> + <pre> +% <input>etop -node tiger@durin -setcookie mycookie -lines 15</input></pre> + + <p>A list of all valid Erlang Top configuration parameters is available in + module <seealso marker="etop"><c>etop</c></seealso>. </p> - <section> - <title>Example: Change configuration with text based presentation</title> - <code type="none"><![CDATA[ + <p>The parameters <c>lines</c>, <c>interval</c>, <c>accumulate</c>, + and <c>sort</c> can be changed during runtime with function + <seealso marker="etop#config/2"><c>etop:config/2</c></seealso>. + </p> + <p><em>Example:</em></p> + <p>Change configuration parameter <c>lines</c> with text-based presentation. + Before the change, 10 lines are presented as follows:</p> + <code type="none"><![CDATA[ ======================================================================================== tiger@durin 10:12:39 Load: cpu 0 Memory: total 1858 binary 33 @@ -137,8 +148,14 @@ Pid Name or Initial Func Time Reds Memory MsgQ Current Func <127.43.0> ddll_server 0 582 3744 0 gen_server:loop/6 <127.5.0> application_controll 0 569 6756 0 gen_server:loop/6 ======================================================================================== ]]></code> - <p><em><c>etop:config(lines,5).</c></em> <br></br> -<em><c>ok</c></em></p> + <p>Function <c>etop:config/2</c> is called to change the number of showed + lines to 5:</p> + + <pre> +> <input>etop:config(lines,5).</input> +ok</pre> + + <p>After the change, 5 lines are presented as follows:</p> <code type="none"><![CDATA[ (etop@durin)2> ======================================================================================== @@ -156,19 +173,20 @@ Pid Name or Initial Func Time Reds Memory MsgQ Current Func <127.43.0> ddll_server 0 0 3744 0 gen_server:loop/6 ======================================================================================== ]]></code> - </section> </section> <section> - <title>Print to file</title> - <p>At any time, the current <c>etop</c> display can be dumped to a - text file with the function <c>etop:dump/1</c>. + <title>Print to File</title> + <p>At any time, the current Erlang Top display can be dumped to a + text file with function + <seealso marker="etop#dump/1"><c>etop:dump/1</c></seealso>. </p> </section> <section> <title>Stop</title> - <p>Use the function <c>etop:stop/0</c> to stop <c>etop</c>. + <p>To stop Erlang Top, use function + <seealso marker="etop#stop/0"><c>etop:stop/0</c></seealso>. </p> </section> </chapter> diff --git a/lib/observer/doc/src/introduction_ug.xml b/lib/observer/doc/src/introduction_ug.xml new file mode 100644 index 0000000000..21f0dc709f --- /dev/null +++ b/lib/observer/doc/src/introduction_ug.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2016</year><year>2016</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + </legalnotice> + + <title>Introduction</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>introduction_ug.xml</file> + </header> +<section> + <title>Scope</title> + <p>The Observer application is a container including the following + tools for tracing and investigation of distributed systems:</p> + <list type="bulleted"> + <item>Observer</item> + <item>Trace Tool Builder</item> + <item>Erlang Top</item> + <item>Crashdump Viewer</item> + </list> + </section> + + <section> + <title>Prerequisites</title> + <p>It is assumed that the reader is familiar with the Erlang + programming language.</p> + </section> +</chapter> diff --git a/lib/observer/doc/src/notes.xml b/lib/observer/doc/src/notes.xml index 5243f50e34..dd99f45b19 100644 --- a/lib/observer/doc/src/notes.xml +++ b/lib/observer/doc/src/notes.xml @@ -32,6 +32,51 @@ <p>This document describes the changes made to the Observer application.</p> +<section><title>Observer 2.1.2</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Documentation corrections.</p> + <p> + Own Id: OTP-12994</p> + </item> + </list> + </section> + +</section> + +<section><title>Observer 2.1.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Show ets owner pid in crashdump viewers popup window, + thanks Leo Liu.</p> + <p> + Own Id: OTP-13030</p> + </item> + <item> + <p> + Several initialisms (eg, ERTS, ETS, SMP) are used as + headings. They were being capitalized incorrectly.</p> + <p> + Own Id: OTP-13044</p> + </item> + <item> + <p> + Fixed a crash in crashdump viewer when dump contained a + truncated binary.</p> + <p> + Own Id: OTP-13163</p> + </item> + </list> + </section> + +</section> + <section><title>Observer 2.1</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -273,13 +318,12 @@ <section><title>Improvements and New Features</title> <list> <item> - <p> <list> <item> The new Memory field from a crash dump is now presented by crashdump viewer, both in the process overview and in the process detail page. </item> <item> A summary of blocks- and carriers sizes is added to the allocator information page in the crashdump viewer. - </item> </list></p> + </item> </list> <p> Own Id: OTP-10604 Aux Id: kunagi-336 [247] </p> </item> @@ -408,7 +452,6 @@ <item> <p> The following bugs in <c>ttb</c> have been corrected:</p> - <p> <list> <item><c>ttb:tracer/2</c> would earlier crash when trying to set up tracing for a diskless node to wrap files, i.e. when option @@ -421,7 +464,7 @@ <c>{file,{local,Filename}}</c></item> <item>A deadlock would sometimes occur due to an information printout from the <c>ttb_control</c> process when <c>ttb</c> was - stopped.</item> </list></p> + stopped.</item> </list> <p> Own Id: OTP-9431</p> </item> @@ -449,7 +492,6 @@ <item> <p> The following new features are added to <c>ttb</c>:</p> - <p> <list> <item>A one-command trace setup is added, <c>ttb:start_trace/4</c>.</item> <item>The following new options are added to <c>ttb:tracer/2</c>: <list> @@ -485,7 +527,7 @@ <c>disable_sort</c> is added to <c>ttb:format/2</c>. When this option is used, trace messages from different logs are not merged according to timestamps, but just appended - one log after the other. </item> </list></p> + one log after the other. </item> </list> <p> Own Id: OTP-9403</p> </item> @@ -493,7 +535,6 @@ <p> The following non backwards compatible changes are done in <c>ttb</c>:</p> - <p> <list> <item> When setting up trace with ttb, the 'timestamp' trace flag will now always be set. </item> <item> The 'fetch' option to ttb:stop/1 is removed since @@ -509,7 +550,7 @@ trace file, this is now changed so the handler state is passed not only from one trace message to the next in the same file, but also from one file to the next. </item> - </list></p> + </list> <p> *** POTENTIAL INCOMPATIBILITY ***</p> <p> diff --git a/lib/observer/doc/src/observer.xml b/lib/observer/doc/src/observer.xml index bba5b1e33c..4d43ffe39f 100644 --- a/lib/observer/doc/src/observer.xml +++ b/lib/observer/doc/src/observer.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2011</year><year>2013</year> + <year>2011</year><year>2016</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> @@ -34,24 +34,25 @@ <file>observer.xml</file> </header> <module>observer</module> - <modulesummary>A GUI tool for observing an erlang system.</modulesummary> + <modulesummary>A GUI tool for observing an Erlang system.</modulesummary> <description> - <p>The observer is gui frontend containing various tools to - inspect a system. It displays system information, application - structures, process information, ets or mnesia tables and a frontend - for tracing with <seealso marker="ttb">ttb</seealso>. + <p>Observer is a graphical tool for observing the characteristics of + Erlang systems. The tool Observer displays system information, application + supervisor trees, process information, ETS tables, Mnesia tables, + and contains a front end for Erlang tracing with module + <seealso marker="ttb"><c>ttb</c></seealso>. </p> - <p>See the <seealso marker="observer_ug">user's guide</seealso> - for more information about how to get started.</p> + <p>For detalis about how to get started, see the + <seealso marker="observer_ug"><c>User's Guide</c></seealso>.</p> </description> <funcs> <func> <name>start() -> ok</name> - <fsummary>Start the observer gui</fsummary> + <fsummary>Start the Observer GUI.</fsummary> <desc> - <p>This function starts the <c>observer</c> gui. - Close the window to stop the application. + <p>Starts the Observer GUI. + To stop the tool, close the window. </p> </desc> </func> diff --git a/lib/observer/doc/src/observer_app.xml b/lib/observer/doc/src/observer_app.xml index 543216cee9..a52d6cb4d9 100644 --- a/lib/observer/doc/src/observer_app.xml +++ b/lib/observer/doc/src/observer_app.xml @@ -4,8 +4,7 @@ <appref> <header> <copyright> - <year>2002</year> - <year>2013</year> + <year>2002</year><year>2016</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> @@ -24,7 +23,7 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>observer</title> + <title>Observer</title> <prepared>Siri Hansen</prepared> <responsible>Siri Hansen</responsible> <docno></docno> @@ -32,26 +31,21 @@ <checked></checked> <date>2002-04-08</date> <rev>PA1</rev> - <file>observer_app.sgml</file> + <file>observer_app.xml</file> </header> - <app>observer</app> + <app>Observer</app> <appsummary>The Observer Application</appsummary> <description> - <p>This chapter describes the <em>OBSERVER</em> application in - OTP, which provides tools for tracing and investigation of - distributed systems.</p> + <p>The Observer application contains tools for tracing and + investigation of distributed systems.</p> </description> <section> <title>Configuration</title> - <p>There are currently no configuration parameters available for + <p>No configuration parameters are available for this application. </p> </section> - <section> - <title>SEE ALSO</title> - <p></p> - </section> </appref> diff --git a/lib/observer/doc/src/observer_ug.xml b/lib/observer/doc/src/observer_ug.xml index 8388cb6736..ca354df864 100644 --- a/lib/observer/doc/src/observer_ug.xml +++ b/lib/observer/doc/src/observer_ug.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2011</year><year>2014</year> + <year>2011</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -32,180 +32,253 @@ <section> <title>Introduction</title> - <p>Observer, is a graphical tool for observing the characteristics of - erlang systems. Observer displays system information, application - supervisor trees, process information, ets or mnesia tables and contains - a frontend for erlang tracing. + <p>Observer is a graphical tool for observing the characteristics of + Erlang systems. Observer displays system information, application + supervisor trees, process information, ETS tables, Mnesia tables + and contains a front end for Erlang tracing. </p> </section> <section> - <title>General</title> - <p>Normally observer should be run from a standalone node to minimize - the impact of the system being observed. Example: + <title>Getting Started</title> + <p>Run Observer from a standalone node to minimize the impact of the + system being observed. </p> - <code> - > erl -sname observer -hidden -setcookie MyCookie -run observer - </code> + <p><em>Example:</em></p> + <pre> +% <input>erl -sname observer -hidden -setcookie MyCookie -run observer</input></pre> <p> - Choose which node to observe via <c>Nodes</c> menu. The <c>View/Refresh - Interval</c> controls how frequent the view should be updated. + Select the node to observe with menu <em>Nodes</em>. + Menu <em>View > Refresh interval</em> controls how often + the view is to be updated. The refresh interval is set per viewer so you can have different settings for each viewer. To minimize the system - impact only the active viewer is updated and the other - views will be updated when activated. + impact, only the active viewer is updated. Other views are updated + when activated. </p> - <p> In general the mouse buttons behaves as expected, use left click - to select objects, right click to pop up a menu with most used - choices and double click to bring up information about the - selected object. In most viewers with several columns you can change - sort order by left clicking on column header. + <p>The mouse buttons behave as expected. Use left-click + to select objects, right-click to get a menu with the most used + options, and double-click to display information about the + selected object. In most viewers with many columns, you can change + the sort order by left-clicking the column header. </p> </section> <section> - <title>Applications</title> - <p>The <c>Applications</c> view lists application information. + <title>System Tab</title> + <p>Tab <em>System</em> displays general information about the active Erlang node + and its runtime system, such as build configuration, system capabilities, and + overall use statistics. +</p> + </section> + + <section> + <title>Load Charts Tab</title> + <p>Tab <em>Load Charts</em> displays graphs of the current resource use on + the active Erlang node.</p> + <p>Graph <c>Scheduler Utilization</c> shows scheduler use per scheduler, + where each scheduler use has a unique color.</p> + <p>Graph <c>Memory Usage</c> shows the total memory use and per memory category + use, where each category has a unique color. The categories are as + follows:</p> + <taglist> + <tag><c>Total</c></tag> + <item><p>The sum of all memory categories.</p></item> + <tag><c>Processes</c></tag> + <item><p>The sum of all process memory used.</p></item> + <tag><c>Atom</c></tag> + <item><p>The size used by the atom table.</p></item> + <tag><c>Binary</c></tag> + <item><p>The sum of all off-heap binaries allocated.</p></item> + <tag><c>Code</c></tag> + <item><p>The memory allocated for code storage.</p></item> + <tag><c>Ets</c></tag> + <item><p>The used memory for all ETS tables.</p></item> + </taglist> + + <p>Graph <c>IO Usage</c> shows the current I/O load on the system.</p> + </section> + + <section> + <title>Memory Allocators Tab</title> + <p>Tab <em>Memory Allocators</em> displays detailed information of the carrier + size and current memory carriers. For details about memory carriers, + see module + <seealso marker="erts:erts_alloc"><c>erts_alloc</c></seealso> + in application ERTS.</p> + </section> + + <section> + <title>Applications Tab</title> + <p>Tab <em>Applications</em> presents application information. Select an application in the left list to display its supervisor - tree. - </p> - <p><c>Trace process</c> will add the selected process identifier - to <c>Trace Overview</c> view and the node the process resides on - will be added as well. - </p> - <p><c>Trace named process</c> will add the - registered name of the process. This can be useful when tracing on - several nodes, then processes with that name will be traced on all traced - nodes. - </p> - <p><c>Trace process tree</c> and <c>Trace named process - tree</c> will add the selected process and all processes below, - right of, it to the <c>Trace Overview</c> view. + tree. The right-click options in the tree are as follows: </p> + <taglist> + <tag>Process info</tag> + <item><p>Opens a detailed information window on the selected process, + including the following:</p> + <taglist> + <tag>Process Information</tag> + <item><p>Shows the process information.</p></item> + <tag>Messages</tag> + <item><p>Shows the process messages.</p></item> + <tag>Dictionary</tag> + <item><p>Shows the process dictionary.</p></item> + <tag>Stack Trace</tag> + <item><p>Shows the process current stack trace.</p></item> + <tag>State</tag> + <item><p>Shows the process state.</p></item> + <tag>Log</tag> + <item><p>If enabled and available, shows the process SASL + log entries.</p></item> + </taglist> + </item> + <tag>Trace process</tag> + <item><p>Adds the selected process identifier to tab <em>Trace Overview</em> + plus the node that the process resides on.</p></item> + <tag>Trace named process</tag> + <item><p>Adds the registered name of the process. This can be useful when tracing on + many nodes, as processes with that name are then traced on all traced nodes.</p></item> + <tag>Trace process tree</tag> + <item><p>Adds the selected process and all processes below, + right of it, to tab <em>Trace Overview</em>.</p></item> + <tag>Trace named process tree</tag> + <item><p>Adds the selected process and all processes below, + right of it, to tab <em>Trace Overview</em>.</p></item> + </taglist> </section> <section> - <title>Processes</title> - <p>The <c>Processes</c> view lists process information. - For each process the following information is presented: + <title>Processes Tab</title> + <p>Tab <em>Processes</em> lists process information in columns. + For each process the following information is displayed: </p> <taglist> <tag>Pid</tag> - <item>The process identifier.</item> + <item><p>The process identifier.</p></item> <tag>Reds</tag> - <item>This is the number of reductions that has been executed - on the process</item> + <item><p>The number of reductions executed on the process. + This can be presented as accumulated values or as values since the last update.</p></item> <tag>Memory</tag> - <item>This is the size of the process in bytes, obtained by a - call to <c>process_info(Pid,memory)</c>.</item> + <item><p>The size of the process, in bytes, obtained by a + call to <c>process_info(Pid,memory)</c>.</p></item> <tag>MsgQ</tag> - <item>This is the length of the message queue for the process.</item> + <item><p>The length of the message queue for the process.</p></item> </taglist> - <note> - <p><em>Reds</em> can be presented as accumulated values or as values since last update.</p> - </note> - <p><c>Process info</c> open a detailed information window on the selected process. + + <p>Option <em>Process info</em> opens a detailed information window on the selected process, + including the following:</p> <taglist> <tag>Process Information</tag> - <item>Shows the process information.</item> + <item><p>Shows the process information.</p></item> <tag>Messages</tag> - <item>Shows the process messages.</item> + <item><p>Shows the process messages.</p></item> <tag>Dictionary</tag> - <item>Shows the process dictionary.</item> + <item><p>Shows the process dictionary.</p></item> <tag>Stack Trace</tag> - <item>Shows the process current stack trace.</item> + <item><p>Shows the process current stack trace.</p></item> <tag>State</tag> - <item>Show the process state.</item> + <item><p>Shows the process state.</p></item> <tag>Log</tag> - <item>If enabled and available, show the process SASL log entries.</item> + <item><p>If enabled and available, shows the process SASL log entries.</p></item> </taglist> + <note> - <p><c>Log</c> needs SASL application to be started on the observed node, with log_mf_h as log handler. - The Observed node must be R16B02 or higher. - <c>rb</c> server must not be started on the observed node when clicking on menu 'Log/Toggle log view'. - <c>rb</c> server will be stopped on the observed node when exiting or changing observed node. + <p><em>Log</em> requires application SASL to be started on the observed node, + with <c>log_mf_h</c> as log handler. + The Observed node must be Erlang/OTP R16B02 or higher. + The <c>rb</c> server must not be started on the observed node when clicking menu + <em>Log > Toggle log view</em>. The <c>rb</c> server is stopped on the observed node + when exiting or changing the observed node. </p> </note> + + <p>Option <em>Trace Processes</em> adds the selected process identifiers to tab + <em>Trace Overview</em> plus the node that the processes reside on. </p> - <p><c>Trace Processes</c> will add the selected process identifiers to the <c>Trace Overview</c> view and the - node the processes reside on will be added as well. - <c>Trace Named Processes</c> will add the registered name of processes. This can be useful - when tracing is done on several nodes, then processes with that name will be traced on all traced nodes. - </p> + <p>Option <em>Trace Named Processes</em> adds the registered name of the processes. This can be + useful when tracing is done on many nodes, as processes with that name are then traced on + all traced nodes.</p> + </section> <section> - <title>Table Viewer</title> - <p>The <c>Table Viewer</c> view lists tables. By default ets tables - are visible and unreadable, private ets, tables and tables created by the OTP - applications are not visible. Use <c>View</c> menu to view "system" - ets tables, unreadable ets tables or mnesia tables. + <title>Table Viewer Tab</title> + <p>Tab <em>Table Viewer</em> lists tables. By default, ETS tables + are displayed whereas unreadable private ETS tables and tables created by OTP + applications are not diplayed. Use menu <em>View</em> to view "system" + ETS tables, unreadable ETS tables, or Mnesia tables. </p> - <p>Double click to view the content of the table. Select table and activate <c>View/Table Information</c> - menu to view table information. - </p> - <p>In the table viewer you can regexp search for objects, edit and delete objects. + <p>Double-click to view the table content. To view table information, select the table + and activate menu <em>View > Table information</em>.</p> + <p>You can use <seealso marker="stdlib:re">regular + expressions</seealso> and search for objects, and edit or delete them. </p> </section> <section> - <title>Trace Overview</title> - <p>The <c>Trace Overview</c> view handles tracing. Tracing is done - by selecting which processes to be traced and how to trace - them. You can trace messages, function calls and events, where - events are process related events such as <c>spawn</c>, - <c>exit</c> and several others. - </p> - - <p>When you want to trace function calls, you also need to setup - <c>trace patterns</c>. Trace patterns selects the function calls - that will be traced. The number of traced function calls can be - further reduced with <c>match specifications</c>. Match - specifications can also be used to trigger additional information + <title>Trace Overview Tab</title> + <p>Tab <em>Trace Overview</em> handles tracing. Trace + by selecting the processes to be traced and how to trace + them. You can trace messages, function calls, and events, where + events are process-related events such as <c>spawn</c>, + <c>exit</c>, and many others. + </p> + + <p>To trace function calls, you also need to set up + <em>trace patterns</em>. Trace patterns select the function calls + to be traced. The number of traced function calls can be + further reduced with <em>match specifications</em>. Match + specifications can also be used to trigger more information in the trace messages. </p> - <note><p>Trace patterns only applies to the traced processes.</p></note> + <note><p>Trace patterns only apply to the traced processes.</p></note> <p> - Processes are added from the <c>Applications</c> or <c>Processes</c> views. - A special <c>new</c> identifier, meaning all processes spawned after trace start, - can be added with the <c>Add 'new' Process</c> button. + Processes are added from the <em>Applications</em> or <em>Processes</em> tabs. + A special <em>new</em> identifier, meaning all processes spawned after trace + start, can be added with button <em>Add 'new' Process</em>. </p> <p> - When adding processes, a window with trace options will pop up. The chosen options will - be set for the selected processes. - Process options can be changed by right clicking on a process. + When adding processes, a window with trace options is displayed. The chosen + options are set for the selected processes. + Process options can be changed by right-clicking a process. </p> <p> - Processes added by process identifiers will add the nodes these - processes resides on in the node list. Additional nodes can be added by the <c>Add - Nodes</c> button. + Processes added by process identifiers add the nodes these + processes reside on in the node list. More nodes can be added by clicking + button <em>Add Nodes</em>. </p> <p> - If function calls are traced, trace patterns must be added by <c>Add Trace Pattern</c> button. - Select a module, function(s) and a match specification. - If no functions are selected, all functions in the module will be traced. + If function calls are traced, trace patterns must be added by clicking button + <em>Add Trace Pattern</em>. Select a module, function(s), and a match specification. + If no functions are selected, all functions in the module are traced. A few basic match specifications are provided in the tool, and you can provide your own match specifications. The syntax of match - specifications are described in the <seealso - marker="erts:match_spec">ERTS User's Guide</seealso>. To simplify - the writing of a match specification they can also be written as - <c>fun/1</c> see <seealso marker="stdlib:ms_transform">ms_transform manual page</seealso> for - further information. - </p> - - <p>Use the <c>Start trace</c> button to start the trace. - By default trace output is written to a new window, tracing is stopped when the - window is closed, or with <c>Stop Trace</c> button. - Trace output can be changed via <c>Options/Output</c> menu. - The trace settings, including match specifications, can be saved to, or loaded from, a file. - </p> - <p>More information about tracing can be found in <seealso - marker="runtime_tools:dbg">dbg</seealso> and in the chapter "Match - specifications in Erlang" in <seealso marker="erts:match_spec">ERTS User's - Guide</seealso> and the - <seealso marker="stdlib:ms_transform">ms_transform manual page</seealso>. + specifications is described in the <seealso + marker="erts:match_spec"><c>ERTS User's Guide</c></seealso>. To simplify + the writing of a match specification, they can also be written as + <c>fun/1</c>. For details, see module + <seealso marker="stdlib:ms_transform">ms_transform</seealso> + in application STDLIB. + </p> + + <p>Click button <em>Start Trace</em> to start the trace. + By default, trace output is written to a new window. Tracing is stopped + when the window is closed, or when clicking button <em>Stop Trace</em>. + Trace output can be changed with menu <em>Options > Output</em>. + The trace settings, including match specifications, can be saved to, + or loaded from, a file. + </p> + <p>For details about tracing, see module <seealso + marker="runtime_tools:dbg">dbg</seealso> in application Runtime_Tools + and in section "Match specifications in Erlang" in + <seealso marker="erts:match_spec"><c>ERTS User's Guide</c></seealso> + and in module + <seealso marker="stdlib:ms_transform"><c>ms_transform</c></seealso> + in application STDLIB. </p> </section> </chapter> diff --git a/lib/observer/doc/src/part.xml b/lib/observer/doc/src/part.xml index 27b4e93d2d..d8ec7664d9 100644 --- a/lib/observer/doc/src/part.xml +++ b/lib/observer/doc/src/part.xml @@ -29,9 +29,8 @@ <rev></rev> </header> <description> - <p>The <em>Observer</em> application contains tools for tracing - and investigation of distributed systems.</p> </description> + <xi:include href="introduction_ug.xml"/> <xi:include href="observer_ug.xml"/> <xi:include href="ttb_ug.xml"/> <xi:include href="etop_ug.xml"/> diff --git a/lib/observer/doc/src/ref_man.xml b/lib/observer/doc/src/ref_man.xml index 03d7dbe9df..37e20b2643 100644 --- a/lib/observer/doc/src/ref_man.xml +++ b/lib/observer/doc/src/ref_man.xml @@ -30,10 +30,7 @@ <file>application.sgml</file> </header> <description> - <p>The <em>Observer</em> application contains tools for tracing - and investigation of distributed systems.</p> - <br></br> - </description> + </description> <xi:include href="observer_app.xml"/> <xi:include href="observer.xml"/> <xi:include href="ttb.xml"/> diff --git a/lib/observer/doc/src/ttb.xml b/lib/observer/doc/src/ttb.xml index 0b064b51b8..2b637551db 100644 --- a/lib/observer/doc/src/ttb.xml +++ b/lib/observer/doc/src/ttb.xml @@ -4,8 +4,7 @@ <erlref> <header> <copyright> - <year>2002</year> - <year>2013</year> + <year>2002</year><year>2016</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> @@ -25,28 +24,28 @@ </legalnotice> <title>ttb</title> - <prepared>Siri hansen</prepared> - <prepared>Bartlomiej Puzon</prepared> + <prepared>Siri Hansen, Bartlomiej Puzon</prepared> <responsible></responsible> <docno>1</docno> <approved></approved> <checked></checked> <date>2010-08-13</date> <rev>PA1</rev> - <file>ttb.sgml</file> + <file>ttb.xml</file> </header> <module>ttb</module> <modulesummary>A base for building trace tools for distributed systems.</modulesummary> <description> - <p>The Trace Tool Builder <c>ttb</c> is a base for building trace + <p>The Trace Tool Builder, <c>ttb</c>, is a base for building trace tools for distributed systems. </p> - <p>When using <c>ttb</c>, <c>dbg</c> shall not be used in parallel.</p> + <p>When using <c>ttb</c>, do not use module <c>dbg</c> in application + Runtime_Tools in parallel.</p> </description> <funcs> <func> <name>start_trace(Nodes, Patterns, FlagSpec, Opts) -> Result</name> - <fsummary>Start a trace port on each given node.</fsummary> + <fsummary>Start a trace port on each specified node.</fsummary> <type> <v>Result = see p/2</v> <v>Nodes = see tracer/2</v> @@ -58,49 +57,56 @@ </type> <desc> <p>This function is a shortcut allowing to start a trace with one command. Each - tuple in <c>Patterns</c> is converted to list which is in turn passed to - <c>ttb:tpl</c>. - The call:<code type="none"> -ttb:start_trace([Node, OtherNode], -[{mod, foo, []}, {mod, bar, 2}], -{all, call}, -[{file, File}, {handler,{fun myhandler/4, S}}])</code> - is equivalent to <code type="none"> -ttb:start_trace([Node, OtherNode], [{file, File}, {handler,{fun myhandler/4, S}}]), + tuple in <c>Patterns</c> is converted to a list, which in turn is passed to + <c>ttb:tpl/2,3,4</c>.</p> + <p>The call:</p> + <pre> +> <input>ttb:start_trace([Node, OtherNode], + [{mod, foo, []}, {mod, bar, 2}], + {all, call}, + [{file, File}, {handler,{fun myhandler/4, S}}]).</input></pre> + <p> is equivalent to:</p> + <pre> +> <input>ttb:start_trace([Node, OtherNode], + [{file, File}, {handler,{fun myhandler/4, S}}]), ttb:tpl(mod, foo, []), ttb:tpl(mod, bar, 2, []), -ttb:p(all, call)</code> - </p> +ttb:p(all, call).</input></pre> </desc> </func> + <func> <name>tracer() -> Result</name> - <fsummary>This is equivalent to tracer(node()).</fsummary> + <fsummary>Equivalent to tracer(node()).</fsummary> <desc> - <p>This is equivalent to <c>tracer(node())</c>.</p> + <p>Equivalent to <c>tracer(node())</c>.</p> </desc> </func> + <func> <name>tracer(Shortcut) -> Result</name> - <fsummary>Handy shortcuts for common tracing settings</fsummary> + <fsummary>Handy shortcuts for common tracing settings.</fsummary> <type> <v>Shortcut = shell | dbg</v> </type> <desc> + <p>Handy shortcuts for common tracing settings.</p> <p><c>shell</c> is equivalent to <c>tracer(node(),[{file, {local, "ttb"}}, shell])</c>.</p> <p><c>dbg</c> is equivalent to <c>tracer(node(),[{shell, only}])</c>.</p> </desc> </func> + <func> <name>tracer(Nodes) -> Result</name> - <fsummary>This is equivalent to tracer(Nodes,[]).</fsummary> + <fsummary>Equivalent to tracer(Nodes,[]).</fsummary> <desc> - <p>This is equivalent to <c>tracer(Nodes,[])</c>.</p> + <p>Equivalent to <c>tracer(Nodes,[])</c>.</p> </desc> </func> + <func> <name>tracer(Nodes,Opts) -> Result</name> - <fsummary>Start a trace port on each given node.</fsummary> + <fsummary>Start a trace port on each specified node.</fsummary> <type> <v>Result = {ok, ActivatedNodes} | {error,Reason}</v> <v>Nodes = atom() | [atom()] | all | existing | new</v> @@ -122,99 +128,109 @@ ttb:p(all, call)</code> <v>ShellSpec = true | false | only</v> </type> <desc> - <p>This function starts a file trace port on all given nodes - and also points the system tracer for sequential tracing to + <p>Starts a file trace port on all specified nodes + and points the system tracer for sequential tracing to the same port. </p> - <p>The given <c>Filename</c> will be prefixed with the node - name. Default <c>Filename</c> is "ttb". - </p> - <p><c>File={wrap,Filename,Size,Count}</c> can be used if - the size of the trace logs must be limited. Default values are - <c>Size=128*1024</c> and <c>Count=8</c>. - </p> - <p>When tracing diskless nodes, <c>ttb</c> must be started + <p><em>Options:</em></p> + <taglist> + <tag><c>Filename</c></tag> + <item><p>The specified <c>Filename</c> is prefixed with the node name. + Default <c>Filename</c> is <c>ttb</c>.</p></item> + <tag><c>File={wrap,Filename,Size,Count}</c></tag> + <item><p>Can be used if the size of the trace logs must be limited. + Default values are + <c>Size=128*1024</c> and <c>Count=8</c>.</p></item> + <tag><c>Client</c></tag> + <item><p>When tracing diskless nodes, <c>ttb</c> must be started from an external "trace control node" with disk access, and <c>Client</c> must be <c>{local, File}</c>. All trace information is then sent to the trace control node where - it is written to file. - </p> - <p>The <c>process_info</c> option indicates if process - information should be collected. If <c>PI = true</c> (which is + it is written to file.</p></item> + <tag><c>process_info</c></tag> + <item><p>Indicates if process + information is to be collected. If <c>PI = true</c> (which is default), each process identifier <c>Pid</c> is replaced by a tuple <c>{Pid,ProcessInfo,Node}</c>, where <c>ProcessInfo</c> - is the process' registered name its globally registered name, - or its initial function. It is possible to turn off this - functionality by setting <c>PI = false</c>. - </p> - <p>The <c>{shell, ShellSpec}</c> option indicates that the trace messages should - be printed on the console as they are received by the tracing - process. This implies <c>{local, File}</c> trace client. If the ShellSpec - is <c>only</c> (instead of <c>true</c>), no trace logs are stored. - </p> - <p>The <c>shell</c> option is a shortcut for <c>{shell, true}</c>.</p> - <p>The <c>timer</c> option indicates that the trace should be + is the registered process name, its globally registered name, + or its initial function. To turn off this functionality, + set <c>PI = false</c>.</p></item> + <tag><c>{shell, ShellSpec}</c></tag> + <item><p>Indicates that trace messages are to be printed on the + console as they are received by the tracing process. This implies + trace client <c>{local, File}</c>. If <c>ShellSpec</c> + is <c>only</c> (instead of <c>true</c>), no trace logs are stored.</p></item> + <tag><c>shell</c></tag> + <item><p>Shortcut for <c>{shell, true}</c>.</p></item> + <tag><c>timer</c></tag> + <item><p>Indicates that the trace is to be automatically stopped after <c>MSec</c> milliseconds. <c>StopOpts</c> - are passed to <c>ttb:stop/2</c> command if specified (default is <c>[]</c>). - Note that the timing is approximate, as delays related to + are passed to command <c>ttb:stop/2</c> if specified (default is <c>[]</c>). + Notice that the timing is approximate, as delays related to network communication are always present. The timer starts after - <c>ttb:p/2</c> is issued, so you can set up your trace patterns before. - </p> - <p>The <c>overload_check</c> option allows to enable overload + <c>ttb:p/2</c> is issued, so you can set up your trace patterns before.</p></item> + <tag><c>overload_check</c></tag> + <item><p>Allows to enable overload checking on the nodes under trace. <c>Module:Function(check)</c> - is performed each <c>MSec</c> milliseconds. If the check returns - <c>true</c>, the tracing is disabled on a given node.<br/> - <c>Module:Function</c> should be able to handle at least three - atoms: <c>init</c>, <c>check</c> and <c>stop</c>. <c>init</c> and - <c>stop</c> give the user a possibility to initialize and clean - up the check environment.<br/> - When a node gets overloaded, it is not possible to issue <c>ttb:p</c> - nor any command from the <c>ttb:tp</c> family, as it would lead to + is performed each <c>MSec</c> millisecond. If the check returns + <c>true</c>, the tracing is disabled on a specified node.</p> + <p><c>Module:Function</c> must be able to handle at least three + atoms: <c>init</c>, <c>check</c>, and <c>stop</c>. <c>init</c> and + <c>stop</c> allows you to initialize and clean + up the check environment.</p> + <p>When a node gets overloaded, it is not possible to issue <c>ttb:p/2</c> + or any command from the <c>ttb:tp/2,3,4</c> family, as it would lead to inconsistent tracing state (different trace specifications on - different node). - </p> - <p>The <c>flush</c> option periodically flushes all file trace - port clients (see <c>dbg:flush_trace_port/1</c>). When enabled, - the buffers are freed each <c>MSec</c> milliseconds. This option is - not allowed with <c>{file, {local, File}}</c> tracing. - </p> - <p><c>{resume, FetchTimeout}</c> enables the autoresume feature. - Whenever enabled, remote nodes try to reconnect to the controlling node - in case they were restarted. The feature requires <c>runtime_tools</c> - application to be started (so it has to be present in the <c>.boot</c> - scripts if the traced nodes run with embedded erlang). If this is - not possible, resume may be performed manually by starting - <c>runtime_tools</c> remotely using <c>rpc:call/4</c>.<br/> - <c>ttb</c> tries to fetch all logs from a reconnecting node before - reinitializing the trace. This has to finish within FetchTimeout milliseconds - or is aborted<br/> - By default, autostart information is stored in a file called + different nodes).</p></item> + <tag><c>flush</c></tag> + <item><p>Periodically flushes all file trace + port clients (see + <seealso marker="runtime_tools:dbg#flush_trace_port/1"> + <c>dbg:flush_trace_port/1</c></seealso>). When enabled, + the buffers are freed each <c>MSec</c> millisecond. This option is + not allowed with <c>{file, {local, File}}</c> tracing.</p></item> + <tag><c>{resume, FetchTimeout}</c></tag> + <item><p>Enables the autoresume feature. + When enabled, remote nodes try to reconnect to the controlling node + if they are restarted. The feature requires application Runtime_Tools + to be started (so it has to be present in the <c>.boot</c> + scripts if the traced nodes run with embedded Erlang). If this is + not possible, resume can be performed manually by starting + <c>Runtime_Tools</c> remotely using + <seealso marker="kernel:rpc#call/4"><c>rpc:call/4</c></seealso>.</p> + <p><c>ttb</c> tries to fetch all logs from a reconnecting node before + reinitializing the trace. This must finish within <c>FetchTimeout</c> + milliseconds or is aborted.</p> + <p>By default, autostart information is stored in a file named <c>ttb_autostart.bin</c> on each node. If this is not desired - (i.e. on diskless nodes), a custom module to handle autostart + (for example, on diskless nodes), a custom module handling autostart information storage and retrieval can be provided by specifying - <c>ttb_autostart_module</c> environment variable for the <c>runtime_tools</c> - application. The module has to respond to the following API: - <taglist> + environment variable <c>ttb_autostart_module</c> for the application + Runtime_Tools. The module must respond to the following API:</p> + <taglist> <tag><c>write_config(Data) -> ok</c></tag> - <item>Store the provided data for further retrieval. It is + <item><p>Stores the provided data for further retrieval. It is important to realize that the data storage used must not - be affected by the node crash.</item> + be affected by the node crash.</p></item> <tag><c>read_config() -> {ok, Data} | {error, Error}</c></tag> - <item>Retrieve configuration stored with <c>write_config(Data)</c>.</item> + <item><p>Retrieves configuration stored with <c>write_config(Data)</c>.</p></item> <tag><c>delete_config() -> ok</c></tag> - <item>Delete configuration stored with <c>write_config(Data)</c>. - Note that after this call any subsequent calls to <c>read_config</c> - must return <c>{error, Error}</c>. + <item><p>Deletes configuration stored with <c>write_config(Data)</c>. + Notice that after this call any subsequent calls to <c>read_config</c> + must return <c>{error, Error}</c>.</p> </item> - </taglist> - </p> - <p>The <c>resume</c> option implies the default <c>FetchTimeout</c>, which is + </taglist> + <p><c>resume</c> implies the default <c>FetchTimeout</c>, which is 10 seconds</p> + </item> + </taglist> + </desc> </func> + <func> <name>p(Procs,Flags) -> Return</name> - <fsummary>Sets the given trace flags on the given processes.</fsummary> + <fsummary>Set the specified trace flags on the specified processes.</fsummary> <type> <v>Return = {ok,[{Procs,MatchDesc}]}</v> <v>Procs = Process | [Process] | all | new | existing</v> @@ -222,58 +238,64 @@ ttb:p(all, call)</code> <v>Flags = Flag | [Flag]</v> </type> <desc> - <p>This function sets the given trace flags on the given - processes. The <c>timestamp</c> flag is always turned on. + <p>Sets the specified trace flags on the specified + processes. Flag <c>timestamp</c> is always turned on. </p> - <p>Please turn to the Reference manual for module <c>dbg</c> - for details about the possible trace flags. The parameter - <c>MatchDesc</c> is the same as returned from <c>dbg:p/2</c></p> - <p>Processes can be given as registered names, globally - registered names or process identifiers. If a registered name - is given, the flags are set on processes with this name on all + <p>See the Reference Manual for module + <seealso marker="runtime_tools:dbg"><c>dbg</c></seealso> + and the possible trace flags. Parameter + <c>MatchDesc</c> is the same as returned from + <c>dbg:p/2</c>.</p> + <p>Processes can be specified as registered names, globally + registered names, or process identifiers. If a registered name + is specified, the flags are set on processes with this name on all active nodes.</p> - <p>Issuing this command starts the timer for this trace if - <c>timer</c> option was specified with <c>tracer/2</c>. + <p>Issuing this command starts the timer for this trace if option + <c>timer</c> is specified with <c>tracer/2</c>. </p> </desc> </func> + <func> <name>tp, tpl, ctp, ctpl, ctpg</name> <fsummary>Set and clear trace patterns.</fsummary> <desc> - <p>These functions should be used in combination with the - <c>call</c> trace flag for setting and clearing trace - patterns. When the <c>call</c> trace flag is set on a process, - function calls will be traced on that process if a trace - pattern has been set for the called function. Trace patterns - specifies how to trace a function by using match + <p>These functions are to be used with + trace flag <c>call</c> for setting and clearing trace + patterns. When trace flag <c>call</c> is set on a process, + function calls are traced on that process if a trace + pattern is set for the called function. Trace patterns + specify how to trace a function by using match specifications. Match specifications are described in the - User's Guide for the erlang runtime system <c>erts</c>. + <seealso marker="erts:users_guide"><c>ERTS User's Guide</c></seealso>. </p> <p>These functions are equivalent to the corresponding - functions in <c>dbg</c>, but all calls are stored in the - history. The history buffer makes it easy to create config - files so that the same trace environment can be setup several - times, e.g. if you want to compare two test runs. It also + functions in module + <seealso marker="runtime_tools:dbg">dbg</seealso>, + but all calls are stored in the + history. The history buffer makes it easy to create configuration + files; the same trace environment can be set up many + times, for example, to compare two test runs. It also reduces the amount of typing when using <c>ttb</c> from the - erlang shell. + Erlang shell. </p> <taglist> <tag><c>tp</c></tag> - <item>Set trace pattern on global function calls</item> + <item><p>Sets trace patterns on global function calls.</p></item> <tag><c>tpl</c></tag> - <item>Set trace pattern on local and global function calls</item> + <item><p>Sets trace patterns on local and global function calls.</p></item> <tag><c>ctp</c></tag> - <item>Clear trace pattern on local and global function - calls</item> + <item><p>Clears trace patterns on local and global function + calls.</p></item> <tag><c>ctpl</c></tag> - <item>Clear trace pattern on local function calls</item> + <item><p>Clears trace patterns on local function calls.</p></item> <tag><c>ctpg</c></tag> - <item>Clear trace pattern on global function calls</item> + <item><p>Clears trace patterns on global function calls.</p></item> </taglist> - <p>With <c>tp</c> and <c>tpl</c> one of match specification shortcuts - may be used (example: <c>ttb:tp(foo_module, caller)</c>). The shortcuts are: - <taglist> + <p>With <c>tp</c> and <c>tpl</c>, one of the match specification shortcuts + can be used (for example, <c>ttb:tp(foo_module, caller)</c>).</p> + <p>The shortcuts are as follows:</p> + <list type="bulleted"> <item><c>return</c> - for <c>[{'_',[],[{return_trace}]}]</c> (report the return value)</item> <item><c>caller</c> - for <c>[{'_',[],[{message,{caller}}]}]</c> @@ -281,34 +303,36 @@ ttb:p(all, call)</code> <item><c>{codestr, Str}</c> - for <c>dbg:fun2ms/1</c> arguments passed as strings (example: <c>"fun(_) -> return_trace() end"</c>) </item> - </taglist> - </p> + </list> </desc> </func> + <func> <name>list_history() -> History</name> - <fsummary>Returns all calls stored in history</fsummary> + <fsummary>Return all calls stored in history.</fsummary> <type> <v>History = [{N,Func,Args}]</v> </type> <desc> <p>All calls to <c>ttb</c> is stored in the history. This function returns the current content of the history. Any entry - can be re-executed with <c>run_history/1</c> or stored in a - config file with <c>write_config/2/3</c>.</p> + can be reexecuted with <c>run_history/1</c> or stored in a + configuration file with <c>write_config/2,3</c>.</p> </desc> </func> + <func> <name>run_history(N) -> ok | {error, Reason}</name> - <fsummary>Executes one entry of the history</fsummary> + <fsummary>Execute one entry of the history.</fsummary> <type> <v>N = integer() | [integer()]</v> </type> <desc> - <p>Executes the given entry or entries from the history - list. History can be listed with <c>list_history/0</c>.</p> + <p>Executes the specified entry or entries from the history + list. To list history, use <c>list_history/0</c>.</p> </desc> </func> + <func> <name>write_config(ConfigFile,Config)</name> <fsummary>Equivalent to write_config(ConfigFile,Config,[]).</fsummary> @@ -316,9 +340,10 @@ ttb:p(all, call)</code> <p>Equivalent to <c>write_config(ConfigFile,Config,[])</c>.</p> </desc> </func> + <func> <name>write_config(ConfigFile,Config,Opts) -> ok | {error,Reason}</name> - <fsummary>Creates a config file.</fsummary> + <fsummary>Create a configuration file.</fsummary> <type> <v>ConfigFile = string()</v> <v>Config = all | [integer()] | [{Mod,Func,Args}]</v> @@ -329,92 +354,97 @@ ttb:p(all, call)</code> <v>Opt = append</v> </type> <desc> - <p>This function creates or extends a config file which can be + <p>Creates or extends a configuration file, which can be used for restoring a specific configuration later. </p> - <p>The content of the config file can either be fetched from - the history or given directly as a list of + <p>The contents of the configuration file can either be fetched from + the history or specified directly as a list of <c>{Mod,Func,Args}</c>. </p> - <p>If the complete history is to be stored in the config file - <c>Config</c> should be <c>all</c>. If only a selected number - of entries from the history should be stored, <c>Config</c> - should be a list of integers pointing out the entries to be + <p>If the complete history is to be stored in the configuration file, + <c>Config</c> must be <c>all</c>. If only a selected number + of entries from the history are to be stored, <c>Config</c> + must be a list of integers pointing out the entries to be stored. </p> - <p>If <c>Opts</c> is not given or if it is <c>[]</c>, + <p>If <c>Opts</c> is not specified or if it is <c>[]</c>, <c>ConfigFile</c> is deleted and a new file is created. If - <c>Opts = [append]</c>, <c>ConfigFile</c> will not be deleted. - The new information will be appended at the end of the file.</p> + <c>Opts = [append]</c>, <c>ConfigFile</c> is not deleted. + The new information is appended at the end of the file.</p> </desc> </func> + <func> <name>run_config(ConfigFile) -> ok | {error,Reason}</name> - <fsummary>Executes all entries in a config file.</fsummary> + <fsummary>Execute all entries in a configuration file.</fsummary> <type> <v>ConfigFile = string()</v> </type> <desc> - <p>Executes all entries in the given config file. Note that the history - of the last trace is always available in the file named - <c>ttb_last_config</c>.</p> + <p>Executes all entries in the specified configuration file. + Notice that the history of the last trace is always available + in file <c>ttb_last_config</c>.</p> </desc> </func> + <func> <name>run_config(ConfigFile,NumList) -> ok | {error,Reason}</name> - <fsummary>Executes selected entries from a config file.</fsummary> + <fsummary>Execute selected entries from a configuration file.</fsummary> <type> <v>ConfigFile = string()</v> <v>NumList = [integer()]</v> </type> <desc> - <p>Executes selected entries from the given config + <p>Executes selected entries from the specified configuration file. <c>NumList</c> is a list of integers pointing out the entries to be executed. </p> - <p>The content of a config file can be listed with + <p>To list the contents of a configuration file, use <c>list_config/1</c>.</p> - <p> Note that the history - of the last trace is always available in the file named - <c>ttb_last_config</c>.</p> + <p>Notice that the history of the last trace is always available + in file <c>ttb_last_config</c>.</p> </desc> </func> + <func> <name>list_config(ConfigFile) -> Config | {error,Reason}</name> - <fsummary>Lists all entries in a config file.</fsummary> + <fsummary>List all entries in a configuration file.</fsummary> <type> <v>ConfigFile = string()</v> <v>Config = [{N,Func,Args}]</v> </type> <desc> - <p>Lists all entries in the given config file.</p> + <p>Lists all entries in the specified configuration file.</p> </desc> </func> + <func> <name>write_trace_info(Key,Info) -> ok</name> - <fsummary>Writes any information to the <c>.ti</c>file.</fsummary> + <fsummary>Write any information to file <c>.ti</c>.</fsummary> <type> <v>Key = term()</v> <v>Info = Data | fun() -> Data</v> <v>Data = term()</v> </type> <desc> - <p>The <c>.ti</c> file contains <c>{Key,ValueList}</c> - tuples. This function adds <c>Data</c> to the ValueList + <p>File <c>.ti</c> contains <c>{Key,ValueList}</c> + tuples. This function adds <c>Data</c> to the <c>ValueList</c> associated with <c>Key</c>. All information written with this - function will be included in the call to the format handler.</p> + function is included in the call to the format handler.</p> </desc> </func> + <func> <name>seq_trigger_ms() -> MatchSpec</name> - <fsummary>Equivalent to seq_trigger_ms(all)</fsummary> + <fsummary>Equivalent to seq_trigger_ms(all).</fsummary> <desc> - <p>Equivalent to <c>seq_trigger_ms(all)</c></p> + <p>Equivalent to <c>seq_trigger_ms(all)</c>.</p> </desc> </func> + <func> <name>seq_trigger_ms(Flags) -> MatchSpec</name> - <fsummary>Returns a match_spec() which starts sequential tracing</fsummary> + <fsummary>Return a match_spec() which starts sequential tracing.</fsummary> <type> <v>MatchSpec = match_spec()</v> <v>Flags = all | SeqTraceFlag | [SeqTraceFlag]</v> @@ -422,54 +452,55 @@ ttb:p(all, call)</code> </type> <desc> <p>A match specification can turn on or off sequential - tracing. This function returns a match specification which - turns on sequential tracing with the given <c>Flags</c>. + tracing. This function returns a match specification, which + turns on sequential tracing with the specified <c>Flags</c>. </p> - <p>This match specification can be given as the last argument - to <c>tp</c> or <c>tpl</c>. The activated <c>Item</c> will - then become a <em>trigger</em> for sequential tracing. This - means that if the item is called on a process with the - <c>call</c> trace flag set, the process will be "contaminated" - with the seq_trace token. + <p>This match specification can be specified as the last argument + to <c>tp</c> or <c>tpl</c>. The activated <c>Item</c> + then becomes a <em>trigger</em> for sequential tracing. This + means that if the item is called on a process with trace flag + <c>call</c> set, the process is "contaminated" + with token <c>seq_trace</c>. </p> <p>If <c>Flags = all</c>, all possible flags are set. </p> - <p>Please turn to the reference manual for the - <em><c>seq_trace</c></em> module in the <em><c>kernel</c></em> - application to see the possible values for - <c>SeqTraceFlag</c>. For a description of the match_spec() - syntax, please turn to the <em>User's guide</em> for the - runtime system (<em>erts</em>). The chapter <em>Match Specification in Erlang</em> explains the general match - specification "language". + <p>The possible values for <c>SeqTraceFlag</c> are available in + <seealso marker="kernel:seq_trace"><c>seq_trace</c></seealso>.</p> + <p>For a description of the <c>match_spec()</c> syntax, + see section + <seealso marker="erts:match_spec"><c>Match Specifications in Erlang</c></seealso> + in <c>ERTS</c>, which explains the general match specification "language". </p> <note> <p>The <em>system tracer</em> for sequential tracing is automatically initiated by <c>ttb</c> when a trace port is - started with <c>ttb:tracer/0/1/2</c>.</p> + started with <c>ttb:tracer/0,1,2</c>.</p> </note> - <p>Example of how to use the <c>seq_trigger_ms/0/1</c> function:</p> - <code type="none"> -(tiger@durin)5> ttb:tracer(). + <p>An example of how to use function <c>seq_trigger_ms/0,1</c> follows:</p> + <pre> +(tiger@durin)5> <input>ttb:tracer().</input> {ok,[tiger@durin]} -(tiger@durin)6> ttb:p(all,call). +(tiger@durin)6> <input>ttb:p(all,call).</input> {ok,{[all],[call]}} -(tiger@durin)7> ttb:tp(mod,func,ttb:seq_trigger_ms()). +(tiger@durin)7> <input>ttb:tp(mod,func,ttb:seq_trigger_ms()).</input> {ok,[{matched,1},{saved,1}]} -(tiger@durin)8> </code> - <p>Whenever <c>mod:func(...)</c> is called after this, the - seq_trace token will be set on the executing process.</p> +(tiger@durin)8></pre> + <p>Whenever <c>mod:func(...)</c> is called after this, + token <c>seq_trace</c> is set on the executing process.</p> </desc> </func> + <func> <name>stop()</name> - <fsummary>Equivalent to stop([])</fsummary> + <fsummary>Equivalent to stop([]).</fsummary> <desc> <p>Equivalent to <c>stop([])</c>.</p> </desc> </func> + <func> <name>stop(Opts) -> stopped | {stopped, Dir}</name> - <fsummary>Stop tracing and fetch/format logs from all nodes</fsummary> + <fsummary>Stop tracing and fetch/format logs from all nodes.</fsummary> <type> <v>Opts = Opt | [Opt]</v> <v>Opt = nofetch | {fetch_dir, Dir} | format | {format, FormatOpts} | return_fetch_dir</v> @@ -486,88 +517,103 @@ ttb:p(all, call)</code> form <c>yyyymmdd-hhmmss</c>. Even logs from nodes on the same machine as the trace control node are moved to this directory. The history list is saved to a file named <c>ttb_last_config</c> - for further reference (as it will be not longer accessible - through history and configuration management functions (like + for further reference (as it is no longer accessible + through history and configuration management functions, like <c>ttb:list_history/0</c>). </p> - <p>The <c>nofetch</c> option indicates that trace logs shall not be - collected after tracing is stopped. - </p> - <p>The <c>{fetch, Dir}</c> option allows to specify the directory + <p><em>Options:</em></p> + <taglist> + <tag><c>nofetch</c></tag> + <item><p>Indicates that trace logs are not to be + collected after tracing is stopped.</p></item> + <tag><c>{fetch, Dir}</c></tag> + <item><p>Allows specification of the directory to fetch the data to. If the directory already exists, an - error is thrown. - </p> - <p>The <c>format</c> option indicates that the trace logs - shall be formatted after tracing is stopped. All logs in the fetch directory will be merged. - You may use <c>{format, FormatOpts}</c> to pass additional - arguments to <c>format/2</c>.</p> - <p>The <c>return_fetch_dir</c> option indicates that the return value - should be <c>{stopped, Dir}</c> and not just <c>stopped</c>. - This implies <c>fetch</c>. - </p> + error is thrown.</p></item> + <tag><c>format</c></tag> + <item><p>Indicates the trace logs to be formatted after tracing + is stopped. All logs in the fetch directory are merged.</p></item> + <tag><c>return_fetch_dir</c></tag> + <item><p>Indicates the return value + to be <c>{stopped, Dir}</c> and not just <c>stopped</c>. + This implies <c>fetch</c>.</p></item> + </taglist> + </desc> </func> + <func> <name>get_et_handler()</name> - <fsummary>Returns <c>et</c> handler.</fsummary> + <fsummary>Return the <c>et</c> handler.</fsummary> <desc> - <p>The <c>et</c> handler returned by the function may be used with <c>format/2</c> - or <c>tracer/2</c>. Example: <c>ttb:format(Dir, [{handler, ttb:get_et_handler()}])</c>.</p> + <p>Returns the <c>et</c> handler, which can be used with <c>format/2</c> + or <c>tracer/2</c>.</p> + <p>Example: <c>ttb:format(Dir, [{handler, ttb:get_et_handler()}])</c>.</p> </desc> </func> + <func> <name>format(File)</name> - <fsummary>Same as <c>format(File,[])</c>.</fsummary> + <fsummary>Equivalent to <c>format(File,[])</c>.</fsummary> <desc> - <p>Same as <c>format(File,[])</c>.</p> + <p>Equivalent to <c>format(File,[])</c>.</p> </desc> </func> + <func> <name>format(File,Options) -> ok | {error, Reason}</name> - <fsummary>Format a binary trace log</fsummary> + <fsummary>Format a binary trace log.</fsummary> <type> <v>File = string() | [string()]</v> - <d>This can be the name of a binary log, a list of such logs or the name of a directory containing one or more binary logs.</d> + <d>This can be the name of a binary log, a list of such logs, + or the name of a directory containing one or more binary logs.</d> <v>Options = Opt | [Opt]</v> <v>Opt = {out,Out} | {handler,FormatHandler} | disable_sort</v> <v>Out = standard_io | string()</v> <v>FormatHandler = {Function, InitialState}</v> <v>Function = fun(Fd,Trace,TraceInfo,State) -> State</v> <v>Fd = standard_io | FileDescriptor</v> - <d>This is the file descriptor of the destination file <c>Out</c></d> + <d>File descriptor of the destination file <c>Out</c>.</d> <v>Trace = tuple()</v> - <d>This is the trace message. Please turn to the Reference manual for the <c>erlang</c>module for details.</d> + <d>The trace message. For details, see the Reference Manual for + module <c>erlang</c>.</d> <v>TraceInfo = [{Key,ValueList}]</v> - <d>This includes the keys <c>flags</c>, <c>client</c> and <c>node</c>, and if <c>handler</c> is given as option to the tracer function, this is also included. In addition all information written with the <c>write_trace_info/2</c>function is included. </d> + <d>Includes the keys <c>flags</c>, <c>client</c>, and <c>node</c>. + If <c>handler</c> is specified as option to the tracer function, this + is also included. Also, all information written with function + <c>write_trace_info/2</c> is included.</d> </type> <desc> - <p>Reads the given binary trace log(s). The logs are processed - in the order of their timestamp as long as <c>disable_sort</c> - option is not given. + <p>Reads the specified binary trace log(s). The logs are processed + in the order of their time stamps as long as option <c>disable_sort</c> + is not specified. </p> <p>If <c>FormatHandler = {Function,InitialState}</c>, - <c>Function</c> will be called for each trace message. If - <c>FormatHandler = get_et_handler()</c>, <c>et_viewer</c> in - the <em>Event Tracer</em> application (<c>et</c>) is used for presenting + <c>Function</c> is called for each trace message.</p> + <p>If <c>FormatHandler = get_et_handler()</c>, <c>et_viewer</c> in + application ET is used for presenting the trace log graphically. <c>ttb</c> provides a few different - filters which can be selected from the Filter menu in the - <c>et_viewer</c>. If <c>FormatHandler</c> is not given, a - default handler is used which presents each trace message as a - line of text. + filters that can be selected from menu <em>Filters and scaling</em> + in the <c>et_viewer</c>.</p> + <p>If <c>FormatHandler</c> is not specified, a + default handler is used presenting each trace message as a + text line. </p> - <p>The state returned from each call of <c>Function</c> is passed to the next call, - even if next call is to format a message from another log file. + <p>The state returned from each call of <c>Function</c> is passed to + the next call, even if the next call is to format a message from another + log file. </p> - <p>If <c>Out</c> is given, <c>FormatHandler</c> gets the + <p>If <c>Out</c> is specified, <c>FormatHandler</c> gets the file descriptor to <c>Out</c> as the first parameter. </p> - <p><c>Out</c> is ignored if <c>et</c> format handler is used. + <p><c>Out</c> is ignored if the <c>et</c> format handler is used. </p> - <p>Wrap logs can be formatted one by one or all in one go. To - format one of the wrap logs in a set, give the exact name of - the file. To format the whole set of wrap logs, give the name - with '*' instead of the wrap count. See examples in the - <c>ttb</c> User's Guide.</p> + <p>Wrap logs can be formatted one by one or all at once. To + format one of the wrap logs in a set, specify the exact file name. + To format the whole set of wrap logs, specify the name + with <c>*</c> instead of the wrap count. For examples, see the + <seealso marker="ttb_ug#format"><c>User's Guide</c></seealso>. + </p> </desc> </func> </funcs> diff --git a/lib/observer/doc/src/ttb_ug.xml b/lib/observer/doc/src/ttb_ug.xml index ba8c997133..34591ae8de 100644 --- a/lib/observer/doc/src/ttb_ug.xml +++ b/lib/observer/doc/src/ttb_ug.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2002</year><year>2013</year> + <year>2002</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -32,78 +32,85 @@ <section> <title>Introduction</title> - <p>The Trace Tool Builder is a base for building trace tools for - single node or distributed erlang systems. It requires the - <c>runtime_tools</c> application to be available on the traced + <p>Trace Tool Builder is a base for building trace tools for + single node or distributed Erlang systems. It requires the + Runtime_Tools application to be available on the traced node. </p> - <p>The main features of the Trace Tool Builder are:</p> + <p>The following are the main features of Trace Tool Builder:</p> <list type="bulleted"> - <item>Start tracing to file ports on several nodes with one + <item>Start tracing to file ports on many nodes with one function call.</item> - <item>Write additional information to a trace information file, + <item>Write more information to a trace information file, which is read during formatting.</item> - <item>Restoring of previous configuration by maintaining a + <item>Restore previous configuration by maintaining a history buffer and handling configuration files.</item> - <item>Some simple support for sequential tracing.</item> - <item>Formatting of binary trace logs and merging of logs from + <item>Provide some simple support for sequential tracing.</item> + <item>Format binary trace logs and merge logs from multiple nodes.</item> </list> - <p>The intention of the Trace Tool Builder is to serve - as a base for tailor made trace tools, but you may use it directly - from the erlang shell (it may mimic <c>dbg</c> behaviour while - still providing useful additions like match specification shortcuts). - The application only - allows the use of file port tracer, so if you would like - to use other types of trace clients you will be better off - using <c>dbg</c> directly instead.</p> + <p>The intention of Trace Tool Builder is to serve + as a base for tailor-made trace tools, but it can also be used directly + from the Erlang shell (it can mimic <c>dbg</c> behaviour while + still providing useful additions, such as match specification shortcuts). + Trace Tool Builder only allows the use of file port tracer, so to use + other types of trace clients it is better to use <c>dbg</c> directly.</p> </section> <section> <title>Getting Started</title> - <p>The <c>ttb</c> module is the interface to all functions in the - Trace Tool Builder. To get started the least you need to do is to - start a tracer with <c>ttb:tracer/0/1/2</c>, and set the required - trace flags on the processes you want to trace with - <c>ttb:p/2</c>. Then, when the tracing is completed, you must stop - the tracer with <c>ttb:stop/0/1</c> and format the trace log with - <c>ttb:format/1/2</c> (as long as there is anything to format, of - course). + <p>Module <c>ttb</c> is the interface to all functions in + Trace Tool Builder.</p> + <p>To get started, the least you need to do is to + start a tracer with + <seealso marker="ttb#tracer/0"><c>ttb:tracer/0,1,2</c></seealso>, + and set the required + trace flags on the processes you want to trace with + <seealso marker="ttb#p/2"><c>ttb:p/2</c></seealso>.</p> + <p>When the tracing is completed, stop the tracer with + <seealso marker="ttb#stop/0"><c>ttb:stop/0,1</c></seealso> + and format the trace log with + <seealso marker="ttb#format/1"><c>ttb:format/1,2</c></seealso> + (if there is anything to format). </p> - <p><c>ttb:tracer/0/1/2</c> opens a trace port on each node - that shall be traced. By default, trace messages are written - to binary files on remote nodes(the binary trace log). - </p> - <p><c>ttb:p/2</c> specifies which processes shall be - traced. Trace flags given in this call specify what to trace on - each process. You can call this function several times if you like - different trace flags to be set on different processes. - </p> - <p>If you want to trace function calls (i.e. if you have the - <c>call</c> trace flag set on any of your processes), you must + <p><em>Useful functions:</em></p> + <taglist> + <tag><c>ttb:tracer/0,1,2</c></tag> + <item><p>Opens a trace port on each node to be traced. By default, + trace messages are written to binary files on remote nodes (the + binary trace log).</p></item> + <tag><c>ttb:p/2</c></tag> + <item><p>Specifies the processes to be traced. Trace flags specified + in this call specify what to trace on each process. This function can be + called many times if you like different trace flags to be set on different + processes.</p></item> + <tag><c>ttb:tp/2,3,4</c> or <c>ttb:tpl/2,3,4</c></tag> + <item><p>If you want to trace function calls (that is, if you have + trace flag <c>call</c> set on any process), you must also set trace patterns on the required function(s) with - <c>ttb:tp</c> or <c>ttb:tpl</c>. A function is only traced if it - has a trace pattern. The trace pattern specifies how to trace the + <seealso marker="ttb#/0"><c>ttb:tp/2,3,4</c></seealso> or + <seealso marker="ttb#/0"><c>ttb:tpl/2,3,4</c></seealso>. + A function is only traced + if it has a trace pattern. The trace pattern specifies how to trace the function by using match specifications. Match specifications are - described in the User's Guide for the erlang runtime system - <c>erts</c>. - </p> - <p><c>ttb:stop/0/1</c> stops tracing on all nodes, deletes all - trace patterns and flushes the trace port buffer. - </p> - <p><c>ttb:format/1/2</c> translates the binary trace logs into - something readable. By default <c>ttb</c> presents each trace - message as a line of text, but you can also write your own handler - to make more complex interpretations of the trace information. A - trace log can even be presented graphically via the Event Tracer - application. Note that if you give the <c>format</c> option to - <c>ttb:stop/1</c> the formatting is automatically done when - stopping <c>ttb</c>. - </p> - + described in the + <seealso marker="erts:users_guide">ERTS User's Guide</seealso>.</p></item> + <tag><c>ttb:stop/0,1</c></tag> + <item><p>Stops tracing on all nodes, deletes all trace patterns, and + flushes the trace port buffer.</p></item> + <tag><c>ttb:format/1/2</c></tag> + <item><p>Translates the binary trace logs into something readable. + By default, <c>ttb</c> presents each trace message as a line of text, + but you can also write your own handler to make more complex interpretations + of the trace information. A trace log can also be presented graphically + with application Event Tracer (ET).</p> + <p>If option <c>format</c> is specified to <c>ttb:stop/1</c>, the formatting + is automatically done when stopping <c>ttb</c>.</p></item> + </taglist> + <section> - <title>Example: Tracing the local node from the erlang shell</title> - <p>This small module is used in the example:</p> + <title>Tracing Local Node from Erlang Shell</title> + <p>The following small module is used in the subsequent example:</p> <code type="none"> -module(m). -export([f/0]). @@ -114,25 +121,25 @@ f() -> From ! {self(),Now} end. </code> <p>The following example shows the basic use of <c>ttb</c> from - the erlang shell. Default options are used both for starting the - tracer and for formatting (the custom fetch dir is however provided). - This gives a trace log named <c>Node-ttb</c> in the newly-created - directory, where <c>Node</c> is the name of the node. The + the Erlang shell. Default options are used both for starting the + tracer and for formatting (the custom fetch directory is however provided). + This gives a trace log named <c>Node-ttb</c> in the newly created + directory, where <c>Node</c> is the node name. The default handler prints the formatted trace messages in the - shell.</p> - <code type="none"><![CDATA[ + shell:</p> + <pre> (tiger@durin)47> %% First I spawn a process running my test function -(tiger@durin)47> Pid = spawn(m,f,[]). -<0.125.0> +(tiger@durin)47> <input>Pid = spawn(m,f,[]).</input> +<0.125.0> (tiger@durin)48> (tiger@durin)48> %% Then I start a tracer... -(tiger@durin)48> ttb:tracer(). +(tiger@durin)48> <input>ttb:tracer().</input> {ok,[tiger@durin]} (tiger@durin)49> (tiger@durin)49> %% and activate the new process for tracing (tiger@durin)49> %% function calls and sent messages. -(tiger@durin)49> ttb:p(Pid,[call,send]). -{ok,[{<0.125.0>,[{matched,tiger@durin,1}]}]} +(tiger@durin)49> <input>ttb:p(Pid,[call,send]).</input> +{ok,[{<0.125.0>,[{matched,tiger@durin,1}]}]} (tiger@durin)50> (tiger@durin)50> %% Here I set a trace pattern on erlang:now/0 (tiger@durin)50> %% The trace pattern is a simple match spec @@ -140,33 +147,33 @@ f() -> (tiger@durin)50> %% traced. Refer to the reference_manual for (tiger@durin)50> %% the full list of match spec shortcuts (tiger@durin)50> %% available. -(tiger@durin)51> ttb:tp(erlang,now,return). +(tiger@durin)51> <input>ttb:tp(erlang,now,return).</input> {ok,[{matched,tiger@durin,1},{saved,1}]} (tiger@durin)52> (tiger@durin)52> %% I run my test (i.e. send a message to (tiger@durin)52> %% my new process) -(tiger@durin)52> Pid ! self(). -<0.72.0> +(tiger@durin)52> <input>Pid ! self().</input> +<0.72.0> (tiger@durin)53> (tiger@durin)53> %% And then I have to stop ttb in order to flush (tiger@durin)53> %% the trace port buffer -(tiger@durin)53> ttb:stop([return, {fetch_dir, "fetch"}]). +(tiger@durin)53> <input>ttb:stop([return, {fetch_dir, "fetch"}]).</input> {stopped, "fetch"} (tiger@durin)54> (tiger@durin)54> %% Finally I format my trace log -(tiger@durin)54> ttb:format("fetch"). -({<0.125.0>,{m,f,0},tiger@durin}) call erlang:now() -({<0.125.0>,{m,f,0},tiger@durin}) returned from erlang:now/0 -> +(tiger@durin)54> <input>ttb:format("fetch").</input> +({<0.125.0>,{m,f,0},tiger@durin}) call erlang:now() +({<0.125.0>,{m,f,0},tiger@durin}) returned from erlang:now/0 -> {1031,133451,667611} -({<0.125.0>,{m,f,0},tiger@durin}) <0.72.0> ! -{<0.125.0>,{1031,133451,667611}} -ok ]]></code> +({<0.125.0>,{m,f,0},tiger@durin}) <0.72.0> ! +{<0.125.0>,{1031,133451,667611}} +ok</pre> </section> <section> - <title>Example: Build your own tool</title> - <p>This small example shows a simple tool for "debug tracing", - i.e. tracing of function calls with return values.</p> + <title>Build Your Own Tool</title> + <p>The following example shows a simple tool for "debug tracing", + that is, tracing of function calls with return values:</p> <code type="none"><![CDATA[ -module(mydebug). -export([start/0,trc/1,stop/0,format/1]). @@ -228,124 +235,127 @@ do_print(Out,{trace_ts,P,return_from,{M,F,A},R,Ts},N) -> "Return value :~p~n~n", [N,Ts,P,M,F,A,R]). ]]></code> <p>To distinguish trace logs produced with this tool from other - logs, the <c>file</c> option is used in <c>tracer/2</c>. The - logs will therefore be fetched to a directory named + logs, option <c>file</c> is used in + <seealso marker="ttb#tracer/2"><c>tracer/2</c></seealso>. The + logs are therefore fetched to a directory named <c>ttb_upload_debug_log-YYYYMMDD-HHMMSS</c> </p> - <p>By using the <c>handler</c> option when starting the tracer, + <p>By using option <c>handler</c> when starting the tracer, the information about how to format the file is stored in the trace information file (<c>.ti</c>). This is not necessary, as - it might be given at the time of formatting instead. It can - however be useful if you e.g. want to automatically format your - trace logs by using the <c>format</c> option in - <c>ttb:stop/1</c>. It also means that you don't need any - knowledge of the content of a binary log to be able to format it - the way it was intended. If the <c>handler</c> option is given - both when starting the tracer and when formatting, the one given - when formatting is used. + it can be specified when formatting instead. However, It can + be useful if you, for example, want to format trace logs automatically + using option <c>format</c> in <c>ttb:stop/1</c>. Also, you do not need + any knowledge of the content of a binary log to format it the way it + is intended. If option <c>handler</c> is specified both when starting + the tracer and when formatting, the one specified when formatting is used. </p> - <p>The <c>call</c> trace flag is set on all processes. This - means that any function activated with the <c>trc/1</c> command - will be traced on all existing and new processes. + <p>Trace flag <c>call</c> is set on all processes. This + means that any function activated with command <c>trc/1</c> + is traced on all existing and new processes. </p> </section> </section> <section> - <title>Running the Trace Tool Builder against a remote node</title> + <title>Running Trace Tool Builder against Remote Node</title> <p>The Observer application might not always be available on the - node that shall be traced (in the following called the "traced - node"). It is still possible to run the Trace Tool Builder from + node to be traced (in the following called the "traced + node"). However, Trace Tool Builder can still be run from another node (in the following called the "trace control node") as - long as + long as the following is fulfilled: </p> <list type="bulleted"> <item>The Observer application is available on the trace control node.</item> - <item>The Runtime Tools application is available on both the + <item>The Runtime_Tools application is available on both the trace control node and the traced node.</item> </list> - <p>If the Trace Tool Builder shall be used against a remote node, + <p>If Trace Tool Builder is to be used against a remote node, it is highly recommended to start the trace control node as <em>hidden</em>. This way it can connect to the traced node - without the traced node "seeing" it, i.e. if the <c>nodes()</c> - BIF is called on the traced node, the trace control node will not - show. To start a hidden node, add the <c>-hidden</c> option to the - <c>erl</c> command, e.g.</p> - <code type="none"> -% erl -sname trace_control -hidden </code> + without being "seen" by it, that is, if the <c>nodes()</c> + BIF is called on the traced node, the trace control node does not + show. To start a hidden node, add option <c>-hidden</c> to the + <c>erl</c> command, for example:</p> + <pre> +% <input>erl -sname trace_control -hidden</input></pre> <section> - <title>Diskless node</title> + <title>Diskless Node</title> <p>If the traced node is diskless, <c>ttb</c> must be started from - a trace control node with disk access, and the <c>file</c> option - must be given to the <c>tracer/2</c> function with the value - <c>{local, File}</c>, e.g.</p> - <code type="none"> -(trace_control@durin)1> ttb:tracer(mynode@diskless,{file,{local, -{wrap,"mytrace"}}}). -{ok,[mynode@diskless]} </code> + a trace control node with disk access, and option <c>file</c> + must be specified to function <c>tracer/2</c> with value + <c>{local, File}</c>, for example:</p> + <pre> +(trace_control@durin)1> <input>ttb:tracer(mynode@diskless, + {file,{local,{wrap,"mytrace"}}}).</input> +{ok,[mynode@diskless]}</pre> </section> </section> <section> - <title>Additional tracing options</title> - <p>When setting up a trace, several features may be turned on:</p> + <title>More Tracing Options</title> + <p>When setting up a trace, the following features can also be activated:</p> <list type="bulleted"> - <item>time-constrained tracing,</item> - <item>overload protection,</item> - <item>autoresuming.</item> + <item>Time-constrained tracing</item> + <item>Overload protection</item> + <item>Autoresume</item> + <item><c>dbg</c> mode</item> </list> <section> - <title>Time-constrained tracing</title> - <p>Sometimes, it may be helpful to enable trace for a - given period of time (i.e. to monitor a system for 24 hours - or half of a second). This may be done by issuing additional - <c>{timer, TimerSpec}</c> option. If <c>TimerSpec</c> has the + <title>Time-Constrained Tracing</title> + <p>It can sometimes be helpful to enable trace for a + specified period of time (for example, to monitor a system for 24 hours + or half a second). This can be done with option + <c>{timer, TimerSpec}</c>. If <c>TimerSpec</c> has the form of <c>MSec</c>, the trace is stopped after <c>MSec</c> - milliseconds using <c>ttb:stop/0</c>. If any additional options - are provided (<c>TimerSpec = {MSec, Opts}</c>), <c>ttb:stop/1</c> - is called instead with <c>Opts</c> as the arguments. The timer - is started with <c>ttb:p/2</c>, so any trace patterns should - be set up before. <c>ttb:start_trace/4</c> - always sets up all pattern before invoking <c>ttb:p/2</c>. - Note that due to network and processing delays the the period - of tracing is approximate. - The example below shows how to set up a trace which will be - automatically stopped and formatted after 5 seconds - </p><code> -(tiger@durin)1>ttb:start_trace([node()], - [{erlang, now,[]}], - {all, call}, - [{timer, {5000, format}}]). -</code> + milliseconds using + <seealso marker="ttb#stop/0"><c>ttb:stop/0</c></seealso>. If more + options are provided (<c>TimerSpec = {MSec, Opts}</c>), + <seealso marker="ttb#stop/1"><c>ttb:stop/1</c></seealso> + is called instead with <c>Opts</c> as argument.</p> + <p>The timer is started with + <seealso marker="ttb#p/2"><c>ttb:p/2</c></seealso>, so any trace patterns + must be set up in advance. + <seealso marker="ttb#start_trace/4"><c>ttb:start_trace/4</c></seealso> + always sets up all patterns before invoking <c>ttb:p/2</c>.</p> + <p>The following example shows how to set up a trace that is + automatically stopped and formatted after 5 seconds: + </p><pre> +(tiger@durin)1> <input>ttb:start_trace([node()], + [{erlang, now,[]}], + {all, call}, + [{timer, {5000, format}}]).</input></pre> + <note><p>Because of network and processing delays, the period + of tracing is approximate.</p></note> + </section> <section> - <label>Overload protection</label> - <p>When tracing live systems, special care needs to be always taken - not to overload a node with too heavy tracing. <c>ttb</c> provides - the <c>overload</c> option to help to address the problem.</p> - <p><c>{overload, MSec, Module, Function}</c> instructs the ttb backend - (called <c>observer_backend</c>, part of the <c>runtime_tools</c> - application) to perform overload check every <c>MSec</c> milliseconds. - If the check (namely <c>Module:Function(check)</c>) returns + <title>Overload Protection</title> + <p>When tracing live systems, always take special care to not + overload a node with too heavy tracing. <c>ttb</c> provides + option <c>overload</c> to address this problem.</p> + <p><c>{overload, MSec, Module, Function}</c> instructs the <c>ttb</c> back end + (a part of the <seealso marker="runtime_tools:index">Runtime_Tools</seealso> + application) to perform overload check every <c>MSec</c> millisecond. + If the check (named <c>Module:Function(check)</c>) returns <c>true</c>, tracing is disabled on the selected node.</p> <p>Overload protection activated on one node does not affect other nodes, where the tracing continues as normal. - <c>ttb:stop/0/1</c> fetches data from all clients, including everything - that has been collected before overload protection was activated. - Note that - changing trace details (with <c>ttb:p</c> and <c>ttb:tp/tpl...</c>) - once overload protection gets activated in one of the traced - nodes is not permitted in order not to allow trace setup - to be inconsistent between nodes. - </p> - <p><c>Module:Function</c> provided with the <c>overload</c> option must - handle three calls: <c>init</c>, <c>check</c> and <c>stop</c>. <c>init</c> - and <c>stop</c> allows to perform some setup and teardown required by - the check. An overload check module could look like this (note that - <c>check</c> is always called by the same process, so <c>put</c> and - <c>get</c> are possible). - </p><code> + <c>ttb:stop/0,1</c> fetches data from all clients, including everything + collected before the activation of overload protection.</p> + + <note><p> + It is not allowed to change trace details + (with <c>ttb:p</c> and <c>ttb:tp/tpl...</c>) once overload + protection is activated in one of the traced nodes. This is to + avoid trace setup being inconsistent between nodes.</p></note> + + <p><c>Module:Function</c> provided with option <c>overload</c> must + handle three calls: <c>init</c>, <c>check</c>, and <c>stop</c>. <c>init</c> + and <c>stop</c> allow some setup and teardown required by + the check. An overload check module can look as follows: + </p><code type="none"> -module(overload). -export([check/1]). @@ -362,33 +372,37 @@ check(check) -> end; check(stop) -> get(pid) ! stop.</code> + <note><p> + <c>check</c> is always called by the same process, so <c>put</c> and + <c>get</c> are possible.</p></note> </section> <section> <title>Autoresume</title> - <p>It is possible that a node (probably a buggy one, hence traced) - crashes. In order to automatically resume tracing on the node - as soon as it gets back, <c>resume</c> has to be used. When - it is, the failing node tries to reconnect - to trace control node as soon as <c>runtime tools</c> is started. - This implies that <c>runtime_tools</c> must be included in - other node's startup chain (if it is not, one could still - resume tracing by starting <c>runtime_tools</c> manually, - i.e. by an RPC call).</p> - <p>In order not to loose the data that the failing node stored - up to the point of crash, the control node will try to fetch - it before restarting trace. This must happen within the allowed - time frame or is aborted (default is 10 seconds, can be customized with - <c>{resume, MSec}</c>). The data fetched this way is then - merged with all other traces.</p> - <p>Autostart feature requires additional data to be stored on + <p>A node can crash (probably a buggy one, hence traced). + Use <c>resume</c> to resume tracing on the node automatically + when it gets back. The failing node then tries to reconnect + to trace control node when <c>Runtime_Tools</c> is started. + This implies that <c>Runtime_Tools</c> must be included in + the startup chain of other nodes (if not, you can still + resume tracing by starting <c>Runtime_Tools</c> manually, + that is, by an RPC call).</p> + <p>To not lose the data that the failing node stored + up to the point of crash, the control node tries to fetch + it before restarting trace. This must occur within the allowed + time frame, otherwise it is aborted (default is 10 seconds, but it + can be changed with <c>{resume, MSec}</c>). The data fetched + this way is then merged with all other traces.</p> + <p>The autostart feature requires more data to be stored on traced nodes. By default, the data is stored automatically - to the file called "ttb_autostart.bin" in the traced node's cwd. - Users may decide to change this behaviour (i.e. on diskless + to the file named "ttb_autostart.bin" in the currect working directory + (cwd) of the traced node. + Users can change this behaviour (that is, on diskless nodes) by specifying their own module to handle autostart data storage and retrieval (<c>ttb_autostart_module</c> - environment variable of <c>runtime_tools</c>). Please see the - ttb's reference manual to see the module's API. This example - shows the default handler</p> + environment variable of <c>runtime_tools</c>). For information + about the API, see module + <seealso marker="ttb"><c>ttb</c></seealso>. + The following example shows the default handler:</p> <code> -module(ttb_autostart). -export([read_config/0, @@ -407,54 +421,60 @@ read_config() -> end. write_config(Data) -> - file:write_file(?AUTOSTART_FILENAME, term_to_binary(Data)). - </code> - <p>Remember that file trace ports buffer the data + file:write_file(?AUTOSTART_FILENAME, term_to_binary(Data)).</code> + + <note><p>Remember that file trace ports buffer the data by default. If the node crashes, trace messages are not - flushed to the binary log. If the chance of failure is - high, it might be a good idea to automatically flush - the buffers every now and then. Passing <c>{flush, MSec}</c> - as one of <c>ttb:tracer/2</c> option flushes all buffers - every <c>MSec</c> milliseconds.</p> + flushed to the binary log. If the risk of failure is + high, it can be a good idea to flush the buffers every + now and then automatically. Passing <c>{flush, MSec}</c> + as an option of <c>ttb:tracer/2</c> flushes all buffers + every <c>MSec</c> millisecond.</p></note> </section> <section> - <title>dbg mode</title> - <p>The <c>{shell, ShellType}</c> option allows to make <c>ttb</c> - operation similar to <c>dbg</c>. Using <c>{shell, true}</c> + <title>dbg Mode</title> + <p>Option <c>{shell, ShellType}</c> allows making <c>ttb</c> + operation similar to + <seealso marker="runtime_tools:dbg"><c>dbg</c></seealso>. + Using <c>{shell, true}</c> displays all trace messages in the shell before storing them. <c>{shell, only}</c> additionally disables message storage - (so that the tool behaves exactly like dbg). This is allowed - only with ip trace ports (<c>{trace, {local, File}}</c>). + (making the tool to behave exactly like <c>dbg</c>). This is + allowed only with IP trace ports (<c>{trace, {local, File}}</c>). </p> - <p>The command <c>ttb:tracer(dbg)</c> is a shortcut for the pure-dbg - mode (<c>{shell, only}</c>).</p> + <p>Command <c>ttb:tracer(dbg)</c> is a shortcut for the pure + <c>dbg</c> mode (<c>{shell, only}</c>).</p> </section> </section> <section> <marker id="trace_info"></marker> - <title>Trace Information and the .ti File</title> - <p>In addition to the trace log file(s), a file with the extension - <c>.ti</c> is created when the Trace Tool Builder is started. This - is the trace information file. It is a binary file, and it + <title>Trace Information and File .ti</title> + <p>In addition to the trace log file(s), a file with extension + <c>.ti</c> is created when Trace Tool Builder is started. This + is the trace information file. It is a binary file, which contains the process information, trace flags used, the name of - the node to which it belongs and all information written with the - <c>write_trace_info/2</c> function. .ti files are always fetched - with other logs when the trace is stopped. + the node to which it belongs, and all information written with + function + <seealso marker="ttb#write_trace_info/2"><c>ttb:write_trace_info/2</c></seealso>. + <c>.ti</c> files are always fetched with other logs when the trace is stopped. </p> <p>Except for the process information, everything in the trace information file is passed on to the handler function when - formatting. The <c>TI</c> parameter is a list of + formatting. Parameter <c>TI</c> is a list of <c>{Key,ValueList}</c> tuples. The keys <c>flags</c>, - <c>handler</c>, <c>file</c> and <c>node</c> are used for + <c>handler</c>, <c>file</c>, and <c>node</c> are used for information written directly by <c>ttb</c>. </p> - <p>You can add information to the trace information file by - calling <c>write_trace_info/2</c>. Note that <c>ValueList</c> - always will be a list, and if you call <c>write_trace_info/2</c> - several times with the same <c>Key</c>, the <c>ValueList</c> will - be extended with a new value each time. Example: + <p>Information to the trace information file by + can be added by calling + <seealso marker="ttb#write_trace_info/2"><c>ttb:write_trace_info/2</c></seealso>. + Notice that <c>ValueList</c> + always is a list, and if you call <c>write_trace_info/2</c> + many times with the same <c>Key</c>, the <c>ValueList</c> is + extended with a new value each time. </p> + <p><em>Example:</em></p> <p><c>ttb:write_trace_info(mykey,1)</c> gives the entry <c>{mykey,[1]}</c> in <c>TI</c>. Another call, <c>ttb:write_trace_info(mykey,2)</c>, changes this entry to @@ -467,15 +487,15 @@ write_config(Data) -> <p>If you want to limit the size of the trace logs, you can use wrap logs. This works almost like a circular buffer. You can specify the maximum number of binary logs and the maximum size of - each log. <c>ttb</c> will create a new binary log each time a log - reaches the maximum size. When the the maximum number of logs are + each log. <c>ttb</c> then creates a new binary log each time a log + reaches the maximum size. When the maximum number of logs are reached, the oldest log is deleted before a new one is created. </p> - <p>Note that the overall size of data generated by ttb may be greater - than the wrap specification would suggest - if a traced node restarts - and autoresume is enabled, old wrap log is always stored and + <note><p>The overall size of data generated by <c>ttb</c> can be greater + than the wrap specification suggests. If a traced node restarts + and autoresume is enabled, the old wrap log is always stored and a new one is created. - </p> + </p></note> <p>Wrap logs can be formatted one by one or all at once. See <seealso marker="#format">Formatting</seealso>. </p> @@ -485,52 +505,61 @@ write_config(Data) -> <marker id="format"></marker> <title>Formatting</title> <p>Formatting can be done automatically when stopping <c>ttb</c> - (see <seealso marker="#fetch_format">Automatically collect and format logs from all nodes</seealso>), or explicitly by calling - the <c>ttb:format/1/2</c> function. + (see section + <seealso marker="#fetch_format">Automatically Collect and Format Logs from All Nodes</seealso>), or explicitly by calling function + <c>ttb:format/1,2</c>. </p> <p>Formatting means to read a binary log and present it in a readable format. You can use the default format handler in <c>ttb</c> to present each trace message as a line of text, or write your own handler to make more complex interpretations of the - trace information. You can even use the Event Tracer <c>et</c> to - present the trace log graphically (see <seealso marker="#et_viewer">Presenting trace logs with Event Tracer</seealso>). + trace information. You can also use application ET to + present the trace log graphically (see section + <seealso marker="#et_viewer">Presenting Trace Logs with Event Tracer</seealso>). </p> - <p>The first argument to <c>ttb:format/1/2</c> specifies which + <p>The first argument to <c>ttb:format/1,2</c> specifies which binary log(s) to format. This is usually the name of a directory - that ttb created during log fetch. Unless there is the <c>disable_sort</c> - option provided, the logs from different files are always sorted - according to timestamp in traces. + that <c>ttb</c> created during log fetch. Unless option + <c>disable_sort</c> is provided, the logs from different files + are always sorted according to time-stamp in traces. </p> <p>The second argument to <c>ttb:format/2</c> is a list of - options. The <c>out</c> option specifies the destination where the - formatted text shall be written. Default destination is - <c>standard_io</c>, but a filename can also be given. The - <c>handler</c> option specifies the format handler to use. If this - option is not given, the <c>handler</c> option given when starting - the tracer is used. If the <c>handler</c> option was not given - when starting the tracer either, a default handler is used, which - prints each trace message as a line of text. The <c>disable_sort</c> - option indicates that there logs should not be merged according to - timestamp, but processed one file after another (this might be - a bit faster). + options as follows: </p> - <p>A format handler is a fun taking four arguments. This fun will - be called for each trace message in the binary log(s). A simple - example which only prints each trace message could be like this:</p> + <taglist> + <tag><c>out</c></tag> + <item><p>Specifies the destination to write the formatted text. + Default destination is <c>standard_io</c>, but a filename can + also be specified.</p></item> + <tag><c>handler</c></tag> + <item><p>Specifies the format handler to use. If this option is + not specified, option <c>handler</c> that is specified when starting + the tracer is used. If option <c>handler</c> is not specified + when starting the tracer either, a default handler is used, which + prints each trace message as a text line.</p></item> + <tag><c>disable_sort</c></tag> + <item><p>Indicates that the logs are not to be merged according to + time-stamp, but processed one file after another (this can be + a bit faster).</p></item> + </taglist> + <p>A format handler is a fun taking four arguments. This fun is + called for each trace message in the binary log(s). A simple + example that only prints each trace message can be as follows:</p> <code type="none"> fun(Fd, Trace, _TraceInfo, State) -> io:format(Fd, "Trace: ~p~n", [Trace]), State end. </code> - <p><c>Fd</c> is the file descriptor for the destination file, or + <p>Here, <c>Fd</c> is the file descriptor for the destination file, or the atom <c>standard_io</c>. <c>_TraceInfo</c> contains information - from the trace information file (see <seealso marker="#trace_info">Trace Information and the .ti File</seealso>). <c>State</c> is a state variable for the format - handler fun. The initial value of the <c>State</c> variable is - given with the handler option, e.g.</p> + from the trace information file (see section + <seealso marker="#trace_info">Trace Information and File .ti</seealso>). <c>State</c> is a state variable for the format + handler fun. The initial value of variable <c>State</c> is + specified with the handler option, for example:</p> <code type="none"> ttb:format("tiger@durin-ttb", [{handler, {{Mod,Fun}, initial_state}}]) ^^^^^^^^^^^^^ </code> - <p>Another format handler could be used to calculate time spent by + <p>Another format handler can be used to calculate the time spent by the garbage collector:</p> <code type="none"> fun(_Fd,{trace_ts,P,gc_start,_Info,StartTs},_TraceInfo,State) -> @@ -541,111 +570,118 @@ fun(_Fd,{trace_ts,P,gc_start,_Info,StartTs},_TraceInfo,State) -> io:format("GC in process ~w: ~w milliseconds~n", [P,Time]), State -- [{P,StartTs}] end </code> - <p>A more refined version of this format handler is the function - <c>handle_gc/4</c> in the module <c>multitrace.erl</c> which can - be found in the <c>src</c> directory of the Observer application. + <p>A more refined version of this format handler is function + <c>handle_gc/4</c> in module <c>multitrace.erl</c> + included in directory <c>src</c> of the Observer application. </p> - <p>The actual trace message is passed as the second argument (<c>Trace</c>). - The possible values of <c>Trace</c> are:</p> + <p>The trace message is passed as the second argument (<c>Trace</c>). + The possible values of <c>Trace</c> are the following:</p> <list type="bulleted"> - <item>all trace messages described in <c>erlang:trace/3</c> documentation, + <item>All trace messages described in + <seealso marker="erts:erlang#trace/3"><c>erlang:trace/3</c></seealso> </item> - <item><c>{drop, N}</c> if ip tracer is used (see <c>dbg:trace_port/2</c>), + <item><c>{drop, N}</c> if IP tracer is used (see + <seealso marker="runtime_tools:dbg#trace_port/2"><c>dbg:trace_port/2</c></seealso>) </item> - <item><c>end_of_trace</c> received once when all trace messages have - been processed.</item> + <item><c>end_of_trace</c> received once when all trace messages are + processed</item> </list> - <p>By giving the format handler <c>ttb:get_et_handler()</c>, you can have the trace - log presented graphically with <c>et_viewer</c> in the Event - Tracer application (see <seealso marker="#et_viewer">Presenting trace logs with Event Tracer</seealso>). + <p>By giving the format handler + <seealso marker="ttb#get_et_handler/0"><c>ttb:get_et_handler()</c></seealso>, + you can have the trace + log presented graphically with <c>et_viewer</c> in the ET + application (see section + <seealso marker="#et_viewer">Presenting Trace Logs with Event Tracer</seealso>). </p> - <p>You may always decide not to format the whole trace data contained - in the fetch directory, but analyze single files instead. In order - to do so, a single file (or list of files) have to be passed as - the first argument to <c>format/1/2</c>.</p> - <p>Wrap logs can be formatted one by one or all in one go. To - format one of the wrap logs in a set, give the exact name of the - file. To format the whole set of wrap logs, give the name with '*' - instead of the wrap count. An example: + <p>You can always decide not to format the whole trace data contained + in the fetch directory, but analyze single files instead. To do so, + a single file (or list of files) must be passed as the first argument + to <c>format/1,2</c>.</p> + <p>Wrap logs can be formatted one by one or all at once. To + format one of the wrap logs in a set, specify the exact file name. + To format the whole set of wrap logs, specify the name with <c>*</c> + instead of the wrap count. </p> + <p><em>Example:</em></p> <p>Start tracing:</p> - <code type="none"> -(tiger@durin)1> ttb:tracer(node(),{file,{wrap,"trace"}}). + <pre> +(tiger@durin)1> <input>ttb:tracer(node(),{file,{wrap,"trace"}}).</input> {ok,[tiger@durin]} -(tiger@durin)2> ttb:p(...) -... </code> - <p>This will give a set of binary logs, like:</p> +(tiger@durin)2> <input>ttb:p(...)</input> +...</pre> + <p>This gives a set of binary logs, for example:</p> <code type="none"> ... </code> <p>Format the whole set of logs:</p> - <code type="none"> -1> ttb:format("tiger@durin-trace.*.wrp"). + <pre> +1> <input>ttb:format("tiger@durin-trace.*.wrp").</input> .... ok -2> </code> +2> </pre> <p>Format only the first log:</p> - <code type="none"> -1> ttb:format("[email protected]"). + <pre> +1> <input>ttb:format("[email protected]").</input> .... ok -2> </code> +2> </pre> <p>To merge all wrap logs from two nodes:</p> - <code type="none"> -1> ttb:format(["tiger@durin-trace.*.wrp","lion@durin-trace.*.wrp"]). + <pre> +1> <input>ttb:format(["tiger@durin-trace.*.wrp","lion@durin-trace.*.wrp"]).</input> .... ok -2> </code> +2> </pre> <section> <marker id="et_viewer"></marker> - <title>Presenting trace logs with Event Tracer</title> - <p>For detailed information about the Event Tracer, please turn - to the User's Guide and Reference Manuals for the <c>et</c> - application. + <title>Presenting Trace Logs with Event Tracer</title> + <p>For detailed information about the Event Tracer, see the + <seealso marker="et:users_guide">ET</seealso> application. </p> - <p>By giving the format handler <c>ttb:get_et_handler()</c>, you can have the - trace log presented graphically with <c>et_viewer</c> in the - Event Tracer application. <c>ttb</c> provides a few different - filters which can be selected from the Filter menu in the - <c>et_viewer</c> window. The filters are names according to the - type of actors they present (i.e. what each vertical line in the - sequence diagram represent). Interaction between actors is shown - as red arrows between two vertical lines, and activities within - an actor are shown as blue text to the right of the actors line. + <p>By giving the format handler + <seealso marker="ttb#get_et_handler/0"><c>ttb:get_et_handler()</c></seealso>, + you can have the trace log presented graphically with + <c>et_viewer</c> in the ET application. + <c>ttb</c> provides filters that can be selected from the + menu <em>Filter</em> in the <c>et_viewer</c> window. The filters + are names according to the type of actors they present + (that is, what each vertical line in the sequence diagram represents). + Interaction between actors is shown as red arrows between two + vertical lines, and activities within an actor are shown as + blue text to the right of the actors line. </p> - <p>The <c>processes</c> filter is the only filter which will - show all trace messages from a trace log. Each vertical line in + <p>The <c>processes</c> filter is the only filter showing all + trace messages from a trace log. Each vertical line in the sequence diagram represents a process. Erlang messages, - spawn and link/unlink are typical interactions between - processes. Function calls, scheduling and garbage collection are - typical activities within a process. <c>processes</c> is the - default filter. + spawn, and link/unlink are typical interactions between + processes. Function calls, scheduling, and garbage collection, + are typical activities within a process. <c>processes</c> is + the default filter. </p> - <p>The rest of the filters will only show function calls and + <p>The remaining filters only show function calls and function returns. All other trace message are discarded. To get - the most out of these filters, <c>et_viewer</c> needs to known + the most out of these filters, <c>et_viewer</c> must know the caller of each function and the time of return. This can be - obtained by using both the <c>call</c> and <c>return_to</c> - flags when tracing. Note that the <c>return_to</c> flag only - works with local call trace, i.e. when trace patterns are set + obtained using both the <c>call</c> and <c>return_to</c> + flags when tracing. Notice that flag <c>return_to</c> only + works with local call trace, that is, when trace patterns are set with <c>ttb:tpl</c>. </p> - <p>The same result can be obtained by using the <c>call</c> flag - only and setting a match specification like this on local or - global function calls:</p> - <code type="none"> -1> dbg:fun2ms(fun(_) -> return_trace(),message(caller()) end). -[{'_',[],[{return_trace},{message,{caller}}]}] </code> - <p>This should however be done with care, since the - <c>{return_trace}</c> function in the match specification will - destroy tail recursiveness. + <p>The same result can be obtained by using the flag <c>call</c> + only and setting a match specification on local or + global function calls as follows:</p> + <pre> +1> <input>dbg:fun2ms(fun(_) -> return_trace(),message(caller()) end).</input> +[{'_',[],[{return_trace},{message,{caller}}]}]</pre> + <p>This must however be done with care, as function + <c>{return_trace}</c> in the match specification + destroys tail recursiveness. </p> <p>The <c>modules</c> filter shows each module as a vertical line in the sequence diagram. External function calls/returns - are shown as interactions between modules and internal function + are shown as interactions between modules, and internal function calls/returns are shown as activities within a module. </p> <p>The <c>functions</c> filter shows each function as a vertical @@ -656,9 +692,9 @@ ok <p>The <c>mods_and_procs</c> and <c>funcs_and_procs</c> filters are equivalent to the <c>modules</c> and <c>functions</c> filters respectively, except that each module or function can - have several vertical lines, one for each process it resides on. + have many vertical lines, one for each process it resides on. </p> - <p>In the next example, modules <c>foo</c> and <c>bar</c> are used:</p> + <p>In the following example, modules <c>foo</c> and <c>bar</c> are used:</p> <code type="none"> -module(foo). -export([start/0,go/0]). @@ -673,8 +709,9 @@ go() -> go -> bar:f1(), go() - end. -</code><code type="none"> + end.</code> + +<code type="none"> -module(bar). -export([f1/0,f3/0]). f1() -> @@ -685,57 +722,56 @@ f2() -> f3() -> ok.</code> - <p>Now let's set up the trace.</p> -<code> -(tiger@durin)1>%%First we retrieve the Pid to limit traced processes set -(tiger@durin)1>Pid = foo:start(). -(tiger@durin)2>%%Now we set up tracing -(tiger@durin)2>ttb:tracer(). -(tiger@durin)3>ttb:p(Pid, [call, return_to, procs, set_on_spawn]). -(tiger@durin)4>ttb:tpl(bar, []). -(tiger@durin)5>%%Invoke our test function and see output with et viewer -(tiger@durin)5>Pid ! go. -(tiger@durin)6>ttb:stop({format, {handler, ttb:get_et_handler()}}). -</code> - - <p>This should render a result similar to the - following: + <p>Setting up the trace:</p> +<pre> +(tiger@durin)1> %%First we retrieve the Pid to limit traced processes set +(tiger@durin)1> <input>Pid = foo:start().</input> +(tiger@durin)2> %%Now we set up tracing +(tiger@durin)2> <input>ttb:tracer().</input> +(tiger@durin)3> <input>ttb:p(Pid, [call, return_to, procs, set_on_spawn]).</input> +(tiger@durin)4> <input>ttb:tpl(bar, []).</input> +(tiger@durin)5> %%Invoke our test function and see output with et viewer +(tiger@durin)5> <input>Pid ! go.</input> +(tiger@durin)6> <input>ttb:stop({format, {handler, ttb:get_et_handler()}}).</input></pre> + + <p>This renders a result similar to the following: </p> - <p></p> <image file="et_processes.gif"> <icaption>Filter: "processes"</icaption> </image> + <p></p> <image file="et_modsprocs.gif"> <icaption>Filter: "mods_and_procs"</icaption> </image> - <p>Note, that we can use <c>ttb:start_trace/4</c> function to help - us here:</p> -<code> -(tiger@durin)1>Pid = foo:start(). -(tiger@durin)2>ttb:start_trace([node()], - [{bar,[]}], - {Pid, [call, return_to, procs, set_on_spawn]} - {handler, ttb:get_et_handler()}). -(tiger@durin)3>Pid ! go. -(tiger@durin)4>ttb:stop(format). -</code> + <p>Notice that function + <seealso marker="ttb#start_trace/4"><c>ttb:start_trace/4</c></seealso> + can be used as help as follows:</p> +<pre> +(tiger@durin)1> <input>Pid = foo:start().</input> +(tiger@durin)2> <input>ttb:start_trace([node()], + [{bar,[]}], + {Pid, [call, return_to, procs, set_on_spawn]} + {handler, ttb:get_et_handler()}).</input> +(tiger@durin)3> <input>Pid ! go.</input> +(tiger@durin)4> <input>ttb:stop(format).</input></pre> </section> </section> <section> <marker id="fetch_format"></marker> - <title>Automatically collect and format logs from all nodes</title> - <p>By default <c>ttb:stop/1</c> fetches trace logs and - trace information files from all nodes. The logs are stored in a - new directory named <c>ttb_upload-Filename-Timestamp</c> under the working - directory of the trace control node. Fetching may be disabled by - providing the <c>nofetch</c> option to <c>ttb:stop/1</c>. User can - specify a fetch directory of his choice passing the - <c>{fetch_dir, Dir}</c> option. + <title>Automatically Collect and Format Logs from All Nodes</title> + <p>By default, + + <seealso marker="ttb#stop/1"><c>ttb:stop/1</c></seealso> fetches trace logs + and trace information files from all nodes. The logs are stored in a + new directory named <c>ttb_upload-Filename-Timestamp</c> under the + working directory of the trace control node. Fetching can be disabled + by providing option <c>nofetch</c> to <c>ttb:stop/1</c>. The user can + specify a fetch directory by passing option <c>{fetch_dir, Dir}</c>. </p> - <p>If the option <c>format</c> is given to <c>ttb:stop/1</c>, the + <p>If option <c>format</c> is specified to <c>ttb:stop/1</c>, the trace logs are automatically formatted after tracing is stopped. </p> @@ -743,117 +779,122 @@ f3() -> <section> <title>History and Configuration Files</title> - <p>For the tracing functionality, <c>dbg</c> could be used instead - of the <c>ttb</c> for setting trace flags on processes and trace - patterns for call trace, i.e. the functions <c>p</c>, <c>tp</c>, - <c>tpl</c>, <c>ctp</c>, <c>ctpl</c> and <c>ctpg</c>. There are only - two things added by <c>ttb</c> for these functions: + <p>For the tracing functionality, + <seealso marker="runtime_tools:dbg"><c>dbg</c></seealso> + can be used instead + of <c>ttb</c> for setting trace flags on processes and trace + patterns for call trace, that is, the functions + <c>p</c>, <c>tp</c>, <c>tpl</c>, <c>ctp</c>, <c>ctpl</c>, and <c>ctpg</c>. Only the + following two things are added by <c>ttb</c> for these functions:</p> <list type="bulleted"> - <item>all calls are stored in the history buffer and can be + <item>All calls are stored in the history buffer and can be recalled and stored in a configuration file. This makes it - easy to setup the same trace environment e.g. if you want to - compare two test runs. It also reduces the amount of - typing when using <c>ttb</c> from the erlang shell;</item> - <item>shortcuts are provided for the most common match - specifications (in order not to force the user to use - <c>dbg:fun2ms</c> continually</item>). + easy to set up the same trace environment, for example, if you + want to compare two test runs. It also reduces the amount of + typing when using <c>ttb</c> from the Erlang shell.</item> + <item>Shortcuts are provided for the most common match + specifications (to not force you to use + <seealso marker="runtime_tools:dbg#fun2ms/1"><c>dbg:fun2ms</c></seealso> + continually).</item> </list> - </p> - <p>Use <c>list_history/0</c> to see the content of the history - buffer, and <c>run_history/1</c> to re-execute one of the entries. + <p>Use + <seealso marker="ttb#list_history/0"><c>ttb:list_history/0</c></seealso> + to see the content of the history buffer and + <seealso marker="ttb#run_history/1"><c>ttb:run_history/1</c></seealso> + to re-execute one of the entries. </p> <p>The main purpose of the history buffer is the possibility to create configuration files. Any function stored in the history buffer can be written to a configuration file and used for - creating a specific configuration at any time with one single + creating a specific configuration at any time with a single function call. </p> <p>A configuration file is created or extended with - <c>write_config/2/3</c>. Configuration files are binary files + <seealso marker="ttb#write_config/2"><c>ttb:write_config/2,3</c></seealso>. + Configuration files are binary files and can therefore only be read and written with functions provided by <c>ttb</c>. </p> - <p>You can write the complete content of the history buffer to a - config file by calling - <c>ttb:write_config(ConfigFile,all)</c>. And you can write - selected entries from the history by calling + <p>The complete content of the history buffer can be written to a + configuration file by calling + <c>ttb:write_config(ConfigFile,all)</c>. Selected entries from + the history can be written by calling <c>ttb:write_config(ConfigFile,NumList)</c>, where <c>NumList</c> is a list of integers pointing out the history entries to write. Moreover, the history buffer is always dumped - to <c>ttb_last_config</c> when <c>ttb:stop/0/1</c> is called. + to <c>ttb_last_config</c> when <c>ttb:stop/0,1</c> is called. </p> - <p>User defined entries can also be written to a config file by - calling the function - <c>ttb:write_config(ConfigFile,ConfigList)</c> where + <p>User-defined entries can also be written to a configuration file + by calling function + <c>ttb:write_config(ConfigFile,ConfigList)</c>, where <c>ConfigList</c> is a list of <c>{Module,Function,Args}</c>. </p> <p>Any existing file <c>ConfigFile</c> is deleted and a new file - is created when <c>write_config/2</c> is called. The option - <c>append</c> can be used if you wish to add something at the end - of an existing config file, e.g. + is created when <c>write_config/2</c> is called. Option + <c>append</c> can be used to add something at the end + of an existing configuration file, for example, <c>ttb:write_config(ConfigFile,What,[append])</c>. </p> - <section> - <title>Example: History and configuration files</title> - <p>See the content of the history buffer</p> - <code type="none"><![CDATA[ -(tiger@durin)191> ttb:tracer(). + <p><em>Example:</em></p> + <p>See the content of the history buffer:</p> + <pre> +(tiger@durin)191> <input>ttb:tracer().</input> {ok,[tiger@durin]} -(tiger@durin)192> ttb:p(self(),[garbage_collection,call]). -{ok,{[<0.1244.0>],[garbage_collection,call]}} -(tiger@durin)193> ttb:tp(ets,new,2,[]). +(tiger@durin)192> <input>ttb:p(self(),[garbage_collection,call]).</input> +{ok,{[<0.1244.0>],[garbage_collection,call]}} +(tiger@durin)193> <input>ttb:tp(ets,new,2,[]).</input> {ok,[{matched,1}]} -(tiger@durin)194> ttb:list_history(). +(tiger@durin)194> <input>ttb:list_history().</input> [{1,{ttb,tracer,[tiger@durin,[]]}}, - {2,{ttb,p,[<0.1244.0>,[garbage_collection,call]]}}, - {3,{ttb,tp,[ets,new,2,[]]}}] ]]></code> + {2,{ttb,p,[<0.1244.0>,[garbage_collection,call]]}}, + {3,{ttb,tp,[ets,new,2,[]]}}]</pre> <p>Execute an entry from the history buffer:</p> - <code type="none"><![CDATA[ -(tiger@durin)195> ttb:ctp(ets,new,2). + <pre> +(tiger@durin)195> <input>ttb:ctp(ets,new,2).</input> {ok,[{matched,1}]} -(tiger@durin)196> ttb:list_history(). +(tiger@durin)196> <input>ttb:list_history().</input> [{1,{ttb,tracer,[tiger@durin,[]]}}, - {2,{ttb,p,[<0.1244.0>,[garbage_collection,call]]}}, + {2,{ttb,p,[<0.1244.0>,[garbage_collection,call]]}}, {3,{ttb,tp,[ets,new,2,[]]}}, {4,{ttb,ctp,[ets,new,2]}}] -(tiger@durin)197> ttb:run_history(3). +(tiger@durin)197> <input>ttb:run_history(3).</input> ttb:tp(ets,new,2,[]) -> -{ok,[{matched,1}]} ]]></code> +{ok,[{matched,1}]}</pre> <p>Write the content of the history buffer to a configuration file:</p> - <code type="none"><![CDATA[ -(tiger@durin)198> ttb:write_config("myconfig",all). + <pre> +(tiger@durin)198> <input>ttb:write_config("myconfig",all).</input> ok -(tiger@durin)199> ttb:list_config("myconfig"). +(tiger@durin)199> <input>ttb:list_config("myconfig").</input> [{1,{ttb,tracer,[tiger@durin,[]]}}, - {2,{ttb,p,[<0.1244.0>,[garbage_collection,call]]}}, + {2,{ttb,p,[<0.1244.0>,[garbage_collection,call]]}}, {3,{ttb,tp,[ets,new,2,[]]}}, {4,{ttb,ctp,[ets,new,2]}}, - {5,{ttb,tp,[ets,new,2,[]]}}] ]]></code> + {5,{ttb,tp,[ets,new,2,[]]}}]</pre> <p>Extend an existing configuration:</p> - <code type="none"><![CDATA[ -(tiger@durin)200> ttb:write_config("myconfig",[{ttb,tp,[ets,delete,1,[]]}], -[append]). + <pre> +(tiger@durin)200> <input>ttb:write_config("myconfig",[{ttb,tp,[ets,delete,1,[]]}], +[append]).</input> ok -(tiger@durin)201> ttb:list_config("myconfig"). +(tiger@durin)201> <input>ttb:list_config("myconfig").</input> [{1,{ttb,tracer,[tiger@durin,[]]}}, - {2,{ttb,p,[<0.1244.0>,[garbage_collection,call]]}}, + {2,{ttb,p,[<0.1244.0>,[garbage_collection,call]]}}, {3,{ttb,tp,[ets,new,2,[]]}}, {4,{ttb,ctp,[ets,new,2]}}, {5,{ttb,tp,[ets,new,2,[]]}}, - {6,{ttb,tp,[ets,delete,1,[]]}}] ]]></code> + {6,{ttb,tp,[ets,delete,1,[]]}}]</pre> <p>Go back to a previous configuration after stopping Trace Tool Builder:</p> - <code type="none"><![CDATA[ -(tiger@durin)202> ttb:stop(). + <pre> +(tiger@durin)202> <input>ttb:stop().</input> ok -(tiger@durin)203> ttb:run_config("myconfig"). +(tiger@durin)203> <input>ttb:run_config("myconfig").</input> ttb:tracer(tiger@durin,[]) -> {ok,[tiger@durin]} -ttb:p(<0.1244.0>,[garbage_collection,call]) -> -{ok,{[<0.1244.0>],[garbage_collection,call]}} +ttb:p(<0.1244.0>,[garbage_collection,call]) -> +{ok,{[<0.1244.0>],[garbage_collection,call]}} ttb:tp(ets,new,2,[]) -> {ok,[{matched,1}]} @@ -867,133 +908,135 @@ ttb:tp(ets,new,2,[]) -> ttb:tp(ets,delete,1,[]) -> {ok,[{matched,1}]} -ok ]]></code> +ok</pre> <p>Write selected entries from the history buffer to a configuration file:</p> - <code type="none"><![CDATA[ -(tiger@durin)204> ttb:list_history(). + <pre> +(tiger@durin)204> <input>ttb:list_history().</input> [{1,{ttb,tracer,[tiger@durin,[]]}}, - {2,{ttb,p,[<0.1244.0>,[garbage_collection,call]]}}, + {2,{ttb,p,[<0.1244.0>,[garbage_collection,call]]}}, {3,{ttb,tp,[ets,new,2,[]]}}, {4,{ttb,ctp,[ets,new,2]}}, {5,{ttb,tp,[ets,new,2,[]]}}, {6,{ttb,tp,[ets,delete,1,[]]}}] -(tiger@durin)205> ttb:write_config("myconfig",[1,2,3,6]). +(tiger@durin)205> <input>ttb:write_config("myconfig",[1,2,3,6]).</input> ok -(tiger@durin)206> ttb:list_config("myconfig"). +(tiger@durin)206> <input>ttb:list_config("myconfig").</input> [{1,{ttb,tracer,[tiger@durin,[]]}}, - {2,{ttb,p,[<0.1244.0>,[garbage_collection,call]]}}, + {2,{ttb,p,[<0.1244.0>,[garbage_collection,call]]}}, {3,{ttb,tp,[ets,new,2,[]]}}, {4,{ttb,tp,[ets,delete,1,[]]}}] -(tiger@durin)207> ]]></code> - </section> +(tiger@durin)207></pre> </section> <section> <title>Sequential Tracing</title> <p>To learn what sequential tracing is and how it can be used, - please turn to the reference manual for the - <em><c>seq_trace</c></em> module in the <em><c>kernel</c></em> - application. + see the Reference Manual for + <seealso marker="kernel:seq_trace"><c>seq_trace</c></seealso>. </p> - <p>The support for sequential tracing provided by the Trace Tool - Builder includes </p> + <p>The support for sequential tracing provided by Trace Tool + Builder includes the following:</p> <list type="bulleted"> <item>Initiation of the system tracer. This is automatically - done when a trace port is started with <c>ttb:tracer/0/1/2</c></item> - <item>Creation of match specifications which activates - sequential tracing</item> + done when a trace port is started with + <seealso marker="ttb#tracer/0"><c>ttb:tracer/0,1,2</c></seealso>.</item> + <item>Creation of match specifications that activates + sequential tracing.</item> </list> - <p>Starting sequential tracing requires that a tracer has been - started with the <c>ttb:tracer/0/1/2</c> function. Sequential - tracing can then either be started via a trigger function with a - match specification created with <c>ttb:seq_trigger_ms/0/1</c>, - or directly by using the <c>seq_trace</c> module in the - <c>kernel</c> application. + <p>Starting sequential tracing requires that a tracer is + started with function <c>ttb:tracer/0,1,2</c>. Sequential + tracing can then be started in either of the following ways: </p> + <list type="bulleted"> + <item>Through a trigger function with a match specification + created with + <seealso marker="ttb#seq_trigger_ms/0"><c>ttb:seq_trigger_ms/0,1</c></seealso>.</item> + <item>Directly by using module + <seealso marker="kernel:seq_trace"><c>seq_trace</c></seealso>.</item> + </list> - <section> - <title>Example: Sequential tracing</title> - <p>In the following example, the function + <p><em>Example 1:</em></p> + <p>In the following example, function <c>dbg:get_tracer/0</c> is used as trigger for sequential tracing:</p> - <code type="none"><![CDATA[ -(tiger@durin)110> ttb:tracer(). + <pre> +(tiger@durin)110> <input>ttb:tracer().</input> {ok,[tiger@durin]} -(tiger@durin)111> ttb:p(self(),call). -{ok,{[<0.158.0>],[call]}} -(tiger@durin)112> ttb:tp(dbg,get_tracer,0,ttb:seq_trigger_ms(send)). +(tiger@durin)111> <input>ttb:p(self(),call).</input> +{ok,{[<0.158.0>],[call]}} +(tiger@durin)112> <input>ttb:tp(dbg,get_tracer,0,ttb:seq_trigger_ms(send)).</input> {ok,[{matched,1},{saved,1}]} -(tiger@durin)113> dbg:get_tracer(), seq_trace:reset_trace(). +(tiger@durin)113> <input>dbg:get_tracer(), seq_trace:reset_trace().</input> true -(tiger@durin)114> ttb:stop(format). -({<0.158.0>,{shell,evaluator,3},tiger@durin}) call dbg:get_tracer() -SeqTrace [0]: ({<0.158.0>,{shell,evaluator,3},tiger@durin}) -{<0.237.0>,dbg,tiger@durin} ! {<0.158.0>,{get_tracer,tiger@durin}} +(tiger@durin)114> <input>ttb:stop(format).</input> +({<0.158.0>,{shell,evaluator,3},tiger@durin}) call dbg:get_tracer() +SeqTrace [0]: ({<0.158.0>,{shell,evaluator,3},tiger@durin}) +{<0.237.0>,dbg,tiger@durin} ! {<0.158.0>,{get_tracer,tiger@durin}} [Serial: {0,1}] -SeqTrace [0]: ({<0.237.0>,dbg,tiger@durin}) -{<0.158.0>,{shell,evaluator,3},tiger@durin} ! {dbg,{ok,#Port<0.222>}} +SeqTrace [0]: ({<0.237.0>,dbg,tiger@durin}) +{<0.158.0>,{shell,evaluator,3},tiger@durin} ! {dbg,{ok,#Port<0.222>}} [Serial: {1,2}] ok -(tiger@durin)116> ]]></code> - <p>Starting sequential tracing with a trigger is actually more +(tiger@durin)116></pre> + <p><em>Example 2:</em></p> + <p>Starting sequential tracing with a trigger is more useful if the trigger function is not called directly from the shell, but rather implicitly within a larger system. When calling a function from the shell, it is simpler to start - sequential tracing directly, e.g.</p> - <code type="none"><![CDATA[ -(tiger@durin)116> ttb:tracer(). + sequential tracing directly, for example, as follows:</p> + <pre> +(tiger@durin)116> <input>ttb:tracer().</input> {ok,[tiger@durin]} -(tiger@durin)117> seq_trace:set_token(send,true), dbg:get_tracer(), -seq_trace:reset_trace(). +(tiger@durin)117> <input>seq_trace:set_token(send,true), dbg:get_tracer(), +seq_trace:reset_trace().</input> true -(tiger@durin)118> ttb:stop(format). -SeqTrace [0]: ({<0.158.0>,{shell,evaluator,3},tiger@durin}) -{<0.246.0>,dbg,tiger@durin} ! {<0.158.0>,{get_tracer,tiger@durin}} +(tiger@durin)118> <input>ttb:stop(format).</input> +SeqTrace [0]: ({<0.158.0>,{shell,evaluator,3},tiger@durin}) +{<0.246.0>,dbg,tiger@durin} ! {<0.158.0>,{get_tracer,tiger@durin}} [Serial: {0,1}] -SeqTrace [0]: ({<0.246.0>,dbg,tiger@durin}) -{<0.158.0>,{shell,evaluator,3},tiger@durin} ! {dbg,{ok,#Port<0.229>}} +SeqTrace [0]: ({<0.246.0>,dbg,tiger@durin}) +{<0.158.0>,{shell,evaluator,3},tiger@durin} ! {dbg,{ok,#Port<0.229>}} [Serial: {1,2}] ok -(tiger@durin)120> ]]></code> - <p>In both examples above, the <c>seq_trace:reset_trace/0</c> - resets the trace token immediately after the traced function in - order to avoid lots of trace messages due to the printouts in - the erlang shell. +(tiger@durin)120></pre> + <p>In both previous examples, <c>seq_trace:reset_trace/0</c> + resets the trace token immediately after the traced function + to avoid many trace messages because of the printouts in + the Erlang shell. </p> - <p>All functions in the <c>seq_trace</c> module, except - <c>set_system_tracer/1</c>, can be used after the trace port has - been started with <c>ttb:tracer/0/1/2</c>. + <p>All functions in module <c>seq_trace</c>, except + <c>set_system_tracer/1</c>, can be used after the trace port + is started with <c>ttb:tracer/0,1,2</c>. </p> - </section> </section> <section> - <title>Example: Multipurpose trace tool</title> - <p>The module <c>multitrace.erl</c> which can be found in the - <c>src</c> directory of the Observer application implements a + <title>Multipurpose Trace Tool</title> + <p>Module <c>multitrace</c> in + directory <c>src</c> of the Observer application provides a small tool with three possible trace settings. The trace messages - are written to binary files which can be formatted with the - function <em><c>multitrace:format/1/2</c></em>. + are written to binary files, which can be formatted with + function <c>multitrace:format/1,2</c>: </p> <taglist> - <tag><em><c>multitrace:debug(What)</c></em></tag> - <item>Start calltrace on all processes and trace the given + <tag><c>multitrace:debug(What)</c></tag> + <item><p>Start calltrace on all processes and trace the specified function(s). The format handler used is - <c>multitrace:handle_debug/4</c> which prints each call and - return. <c>What</c> must be an item or a list of items to trace, - given on the format <c>{Module,Function,Arity}</c>, - <c>{Module,Function}</c> or just <c>Module</c>.</item> - <tag><em><c>multitrace:gc(Procs)</c></em></tag> - <item>Trace garbage collection on the given process(es). The - format handler used is <c>multitrace:handle_gc/4</c> which - prints start and stop and the time spent for each GC.</item> - <tag><em><c>multitrace:schedule(Procs)</c></em></tag> - <item>Trace in- and out-scheduling on the given process(es). The - format handler used is <c>multitrace:handle_schedule/4</c> which - prints each in and out scheduling with process, timestamp and + <c>multitrace:handle_debug/4</c> that prints each call and + returns. <c>What</c> must be an item or a list of items to trace, + specified on the format <c>{Module,Function,Arity}</c>, + <c>{Module,Function}</c>, or only <c>Module</c>.</p></item> + <tag><c>multitrace:gc(Procs)</c></tag> + <item><p>Trace garbage collection on the specified process(es). The + format handler used is <c>multitrace:handle_gc/4</c> that + prints start, stop, and the time spent for each garbage collection.</p></item> + <tag><c>multitrace:schedule(Procs)</c></tag> + <item><p>Trace in-scheduling and out-scheduling on the specified process(es). + The format handler used is <c>multitrace:handle_schedule/4</c> that + prints each in-scheduling and out-scheduling with process, time-stamp, and current function. It also prints the total time each traced - process was scheduled in.</item> + process was scheduled in.</p></item> </taglist> </section> </chapter> diff --git a/lib/observer/src/cdv_ets_cb.erl b/lib/observer/src/cdv_ets_cb.erl index 9e6e72e08d..bac8b56fc3 100644 --- a/lib/observer/src/cdv_ets_cb.erl +++ b/lib/observer/src/cdv_ets_cb.erl @@ -97,7 +97,7 @@ info_fields() -> [{"Id", id}, {"Name", name}, {"Slot", slot}, - {"Owner", owner}, + {"Owner", pid}, {"Data Structure", data_type} ]}, {"Settings", diff --git a/lib/observer/src/crashdump_viewer.erl b/lib/observer/src/crashdump_viewer.erl index f2ce51b2af..b66b4d59c9 100644 --- a/lib/observer/src/crashdump_viewer.erl +++ b/lib/observer/src/crashdump_viewer.erl @@ -1572,7 +1572,7 @@ get_etsinfo(Fd,EtsTable = #ets_table{details=Ds},WS) -> get_etsinfo(Fd,EtsTable#ets_table{details=Ds#{fixed=>Val}},WS); "Type" -> Val = val(Fd), - get_etsinfo(Fd,EtsTable#ets_table{details=Ds#{data_type=>Val}},WS); + get_etsinfo(Fd,EtsTable#ets_table{data_type=Val},WS); "Protection" -> Val = val(Fd), get_etsinfo(Fd,EtsTable#ets_table{details=Ds#{protection=>Val}},WS); diff --git a/lib/observer/src/observer_html_lib.erl b/lib/observer/src/observer_html_lib.erl index 9d8c2d998c..f646f8ed3e 100644 --- a/lib/observer/src/observer_html_lib.erl +++ b/lib/observer/src/observer_html_lib.erl @@ -387,7 +387,9 @@ remove_lgt(Deep) -> remove_lgt_1([$<,$<|Rest]) -> [$>,$>|BinStr] = lists:reverse(Rest), - replace_lgt(lists:reverse(BinStr)). + replace_lgt(lists:reverse(BinStr)); +remove_lgt_1(TruncBin) -> + TruncBin. replace_lgt([$<|R]) -> ["<"|replace_lgt(R)]; diff --git a/lib/observer/src/observer_sys_wx.erl b/lib/observer/src/observer_sys_wx.erl index d6183d0249..dfd15380f2 100644 --- a/lib/observer/src/observer_sys_wx.erl +++ b/lib/observer/src/observer_sys_wx.erl @@ -83,11 +83,11 @@ update_syspage(#sys_wx_state{node = Node, fields=Fields, sizer=Sizer}) -> info_fields() -> Info = [{"System and Architecture", [{"System Version", otp_release}, - {"Erts Version", version}, + {"ERTS Version", version}, {"Compiled for", system_architecture}, {"Emulator Wordsize", wordsize_external}, {"Process Wordsize", wordsize_internal}, - {"Smp Support", smp_support}, + {"SMP Support", smp_support}, {"Thread Support", threads}, {"Async thread pool size", thread_pool_size} ]}, @@ -106,7 +106,7 @@ info_fields() -> {"Atoms", {bytes, atom}}, {"Binaries", {bytes, binary}}, {"Code", {bytes, code}}, - {"Ets", {bytes, ets}} + {"ETS", {bytes, ets}} ]}, {"Statistics", right, [{"Up time", {time_ms, uptime}}, diff --git a/lib/observer/src/observer_traceoptions_wx.erl b/lib/observer/src/observer_traceoptions_wx.erl index 56ac96a91f..9ba9b72b6f 100644 --- a/lib/observer/src/observer_traceoptions_wx.erl +++ b/lib/observer/src/observer_traceoptions_wx.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2012. All Rights Reserved. +%% Copyright Ericsson AB 2011-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -665,7 +665,7 @@ get_file(Text) -> Str = wxTextCtrl:getValue(Text), Dialog = wxFileDialog:new(Text, [{message, "Select a file"}, - {default_file, Str}]), + {defaultFile, Str}]), case wxDialog:showModal(Dialog) of ?wxID_OK -> Dir = wxFileDialog:getDirectory(Dialog), diff --git a/lib/observer/src/observer_tv_table.erl b/lib/observer/src/observer_tv_table.erl index 88f606b3e4..75e6919642 100644 --- a/lib/observer/src/observer_tv_table.erl +++ b/lib/observer/src/observer_tv_table.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2014. All Rights Reserved. +%% Copyright Ericsson AB 2011-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -669,6 +669,7 @@ merge([], New, _Key) -> merge(Old, New, Key) -> merge2(keysort(Key, Old), keysort(Key, New), Key). +-dialyzer({no_improper_lists, merge2/3}). merge2([[Obj|_]|Old], [Obj|New], Key) -> [[Obj]|merge2(Old, New, Key)]; merge2([[A|Op]|Old], [B|New], Key) diff --git a/lib/observer/test/crashdump_viewer_SUITE.erl b/lib/observer/test/crashdump_viewer_SUITE.erl index 84af440245..eae4ee01b9 100644 --- a/lib/observer/test/crashdump_viewer_SUITE.erl +++ b/lib/observer/test/crashdump_viewer_SUITE.erl @@ -564,22 +564,11 @@ dump_with_strange_module_name(DataDir,Rel,DumpName) -> CD. dump(Node,DataDir,Rel,DumpName) -> + Crashdump = filename:join(DataDir, dump_prefix(Rel)++DumpName), + rpc:call(Node,os,putenv,["ERL_CRASH_DUMP",Crashdump]), rpc:call(Node,erlang,halt,[DumpName]), - Crashdump0 = filename:join(filename:dirname(code:which(?t)), - "erl_crash_dump.n1"), - Crashdump1 = filename:join(DataDir, dump_prefix(Rel)++DumpName), - ok = rename(Crashdump0,Crashdump1), - Crashdump1. - -rename(From,To) -> - ok = check_complete(From), - case file:rename(From,To) of - {error,exdev} -> - {ok,_} = file:copy(From,To), - ok = file:delete(From); - ok -> - ok - end. + ok = check_complete(Crashdump), + Crashdump. check_complete(File) -> check_complete1(File,10). diff --git a/lib/observer/vsn.mk b/lib/observer/vsn.mk index 7e7e32099b..aede0858d6 100644 --- a/lib/observer/vsn.mk +++ b/lib/observer/vsn.mk @@ -1 +1 @@ -OBSERVER_VSN = 2.1 +OBSERVER_VSN = 2.1.2 diff --git a/lib/odbc/doc/src/notes.xml b/lib/odbc/doc/src/notes.xml index add8229955..59d46de02a 100644 --- a/lib/odbc/doc/src/notes.xml +++ b/lib/odbc/doc/src/notes.xml @@ -32,7 +32,31 @@ <p>This document describes the changes made to the odbc application. </p> - <section><title>ODBC 2.11</title> + <section><title>ODBC 2.11.1</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + New application variable to set timeout of internal + communication setup between the erlang code and the + c-port program that interfaces the odbc driver. This can + be useful if you have an underlying system that is slow + due to heavy load at startup.</p> + <p> + With this environment variable you can easily bypass and + tailor odbc to the needs of the underlying actual system + without changing the configuration. Which is a good thing + because this value is very system specific.</p> + <p> + Own Id: OTP-12935</p> + </item> + </list> + </section> + +</section> + +<section><title>ODBC 2.11</title> <section><title>Improvements and New Features</title> <list> diff --git a/lib/odbc/doc/src/odbc.xml b/lib/odbc/doc/src/odbc.xml index 01bc0cb7ff..6a2a3587e4 100644 --- a/lib/odbc/doc/src/odbc.xml +++ b/lib/odbc/doc/src/odbc.xml @@ -221,6 +221,18 @@ and their meanings are dependent on the database being used.</item> <item><c>Reason</c> is as per the <c>Reason</c> field when extended errors are not enabled.</item> </list> + + <note> + <p>The current implementation spawns a port programm + written in C that utilizes the actual ODBC driver. There + is a default timeout of 5000 msec for this port programm + to connect to the Erlang ODBC application. This timeout + can be changed by setting an application specific + environment variable 'port_timeout' with the number of + milliseconds for the ODBC application. E.g.: [{odbc, + [{port_timeout, 60000}]}] to set it to 60 seconds. + </p> + </note> </desc> </func> <func> diff --git a/lib/odbc/src/odbc.erl b/lib/odbc/src/odbc.erl index 4901821e9c..12560bfb6e 100644 --- a/lib/odbc/src/odbc.erl +++ b/lib/odbc/src/odbc.erl @@ -26,6 +26,8 @@ -include("odbc_internal.hrl"). +-define(ODBC_PORT_TIMEOUT, 5000). + %% API -------------------------------------------------------------------- -export([start/0, start/1, stop/0, @@ -523,10 +525,10 @@ handle_msg({connect, ODBCCmd, AutoCommitMode, SrollableCursors}, NewState = State#state{auto_commit_mode = AutoCommitMode, scrollable_cursors = SrollableCursors}, - case gen_tcp:accept(ListenSocketSup, 5000) of + case gen_tcp:accept(ListenSocketSup, port_timeout()) of {ok, SupSocket} -> gen_tcp:close(ListenSocketSup), - case gen_tcp:accept(ListenSocketOdbc, 5000) of + case gen_tcp:accept(ListenSocketOdbc, port_timeout()) of {ok, OdbcSocket} -> gen_tcp:close(ListenSocketOdbc), odbc_send(OdbcSocket, ODBCCmd), @@ -983,3 +985,6 @@ string_terminate_value(Binary) when is_binary(Binary) -> <<Binary/binary,0:16>>; string_terminate_value(null) -> null. + +port_timeout() -> + application:get_env(?MODULE, port_timeout, ?ODBC_PORT_TIMEOUT). diff --git a/lib/odbc/test/odbc_connect_SUITE.erl b/lib/odbc/test/odbc_connect_SUITE.erl index 93e949faf6..2d4173a008 100644 --- a/lib/odbc/test/odbc_connect_SUITE.erl +++ b/lib/odbc/test/odbc_connect_SUITE.erl @@ -120,7 +120,16 @@ end_per_suite(_Config) -> %% Note: This function is free to add any key/value pairs to the Config %% variable, but should NOT alter/remove any existing entries. %%-------------------------------------------------------------------- +init_per_testcase(connect_port_timeout, Config) -> + odbc:stop(), + application:load(odbc), + application:set_env(odbc, port_timeout, 0), + odbc:start(), + init_per_testcase_common(Config); init_per_testcase(_TestCase, Config) -> + init_per_testcase_common(Config). + +init_per_testcase_common(Config) -> test_server:format("ODBCINI = ~p~n", [os:getenv("ODBCINI")]), Dog = test_server:timetrap(?default_timeout), Temp = lists:keydelete(connection_ref, 1, Config), @@ -135,7 +144,16 @@ init_per_testcase(_TestCase, Config) -> %% A list of key/value pairs, holding the test case configuration. %% Description: Cleanup after each test case %%-------------------------------------------------------------------- + +end_per_testcase(connect_port_timeout, Config) -> + application:unset_env(odbc, port_timeout), + odbc:stop(), + odbc:start(), + end_per_testcase_common(Config); end_per_testcase(_TestCase, Config) -> + end_per_testcase_common(Config). + +end_per_testcase_common(Config) -> Table = ?config(tableName, Config), {ok, Ref} = odbc:connect(?RDBMS:connection_string(), odbc_test_lib:platform_options()), Result = odbc:sql_query(Ref, "DROP TABLE " ++ Table), @@ -423,6 +441,18 @@ connect_timeout(Config) when is_list(Config) -> %% Need to return ok here "{'EXIT',timeout} return value" will %% be interpreted as that the testcase has timed out. ok. + +%%------------------------------------------------------------------------- +connect_port_timeout(doc) -> + ["Test the timeout for the port program to connect back to the odbc " + "application within the connect function."]; +connect_port_timeout(suite) -> []; +connect_port_timeout(Config) when is_list(Config) -> + %% Application environment var 'port_timeout' has been set to 0 by + %% init_per_testcase/2. + {error,timeout} = odbc:connect(?RDBMS:connection_string(), + odbc_test_lib:platform_options()). + %%------------------------------------------------------------------------- timeout(doc) -> ["Test that timeouts don't cause unwanted behavior sush as receiving" diff --git a/lib/odbc/vsn.mk b/lib/odbc/vsn.mk index d4dc6bbe1d..c7c84560d1 100644 --- a/lib/odbc/vsn.mk +++ b/lib/odbc/vsn.mk @@ -1 +1 @@ -ODBC_VSN = 2.11 +ODBC_VSN = 2.11.1 diff --git a/lib/orber/doc/src/notes.xml b/lib/orber/doc/src/notes.xml index 3f7d4121fd..1da60ba486 100644 --- a/lib/orber/doc/src/notes.xml +++ b/lib/orber/doc/src/notes.xml @@ -34,7 +34,21 @@ </header> - <section><title>Orber 3.8</title> + <section><title>Orber 3.8.1</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> Suppress Dialyzer warnings. </p> + <p> + Own Id: OTP-12862</p> + </item> + </list> + </section> + +</section> + +<section><title>Orber 3.8</title> <section><title>Improvements and New Features</title> <list> @@ -169,11 +183,9 @@ <section><title>Known Bugs and Problems</title> <list> <item> - <p> - <p> - </p></p> <p> - Own Id: OTP-10675 Aux Id: seq12154 </p> + Own Id: OTP-10675 Aux Id: seq12154 + </p> </item> </list> </section> diff --git a/lib/orber/src/orber_ifr.erl b/lib/orber/src/orber_ifr.erl index cc23d9e242..70e0cb3fca 100644 --- a/lib/orber/src/orber_ifr.erl +++ b/lib/orber/src/orber_ifr.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2012. All Rights Reserved. +%% Copyright Ericsson AB 1997-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -780,6 +780,7 @@ find_repository() -> 'Repository__get_def_kind'(Objref) -> orber_ifr_repository:'_get_def_kind'(Objref). +-spec 'Repository_destroy'(_) -> no_return(). 'Repository_destroy'(Objref) -> orber_ifr_repository:destroy(Objref). 'Repository_lookup'(Objref,Search_name) -> @@ -1405,6 +1406,7 @@ find_repository() -> orber_ifr_orb:create_wstring_tc(Bound). 'ORB_create_sequence_tc'(Bound,Element_type) -> orber_ifr_orb:create_sequence_tc(Bound,Element_type). +-spec 'ORB_create_recursive_sequence_tc'(_,_) -> no_return(). 'ORB_create_recursive_sequence_tc'(Bound,Offset) -> orber_ifr_orb:create_recursive_sequence_tc(Bound,Offset). 'ORB_create_array_tc'(Length,Element_type) -> diff --git a/lib/orber/src/orber_ifr_orb.erl b/lib/orber/src/orber_ifr_orb.erl index a408a9a749..3969bbf37a 100644 --- a/lib/orber/src/orber_ifr_orb.erl +++ b/lib/orber/src/orber_ifr_orb.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -89,6 +89,7 @@ create_wstring_tc(Bound) -> create_sequence_tc(Bound, Element_type) -> {tk_sequence,Element_type,Bound}. +-spec create_recursive_sequence_tc(_, _) -> no_return(). create_recursive_sequence_tc(Bound, Offset) -> orber:dbg("[~p] ~p:create_recursive_sequence_tc(~p, ~p);~n" "Create_recursive_sequence is not implemented.~n", diff --git a/lib/orber/src/orber_ifr_repository.erl b/lib/orber/src/orber_ifr_repository.erl index 898fba99f3..8d52573e53 100644 --- a/lib/orber/src/orber_ifr_repository.erl +++ b/lib/orber/src/orber_ifr_repository.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -66,6 +66,7 @@ '_get_def_kind'({ObjType, ObjID}) ?tcheck(ir_Repository, ObjType) -> orber_ifr_irobject:'_get_def_kind'({ObjType, ObjID}). +-spec destroy(_) -> no_return(). destroy({ObjType, ObjID}) ?tcheck(ir_Repository, ObjType) -> orber:dbg("[~p] ~p:destroy(~p, ~p);~n" "Destroying a repository is an error.~n", diff --git a/lib/orber/src/orber_iiop.erl b/lib/orber/src/orber_iiop.erl index d23cd74146..8cb39c7365 100644 --- a/lib/orber/src/orber_iiop.erl +++ b/lib/orber/src/orber_iiop.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -176,7 +176,7 @@ request({Host, Port, InitObjkey, Index, TaggedProfile, HostData}, corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO}) end. - +-dialyzer({no_improper_lists, encode_request/1}). encode_request(#giop_env{interceptors = false} = Env) -> case catch cdr_encode:enc_request(Env) of {'EXCEPTION', Exc} -> diff --git a/lib/orber/src/orber_iiop_inrequest.erl b/lib/orber/src/orber_iiop_inrequest.erl index 625bfd3e86..9d84b63398 100644 --- a/lib/orber/src/orber_iiop_inrequest.erl +++ b/lib/orber/src/orber_iiop_inrequest.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% Copyright Ericsson AB 1999-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -240,6 +240,7 @@ check_context([_|Rest], Acc, Env) -> %%----------------------------------------------------------------- %% Func: call_interceptors %%----------------------------------------------------------------- +-dialyzer({no_improper_lists, call_interceptors/7}). call_interceptors(SocketType, #giop_env{interceptors = {native, Ref, PIs}, ctx = Ctx} = Env, ReqHdr, Rest, Len, ByteOrder, Msg) -> @@ -276,6 +277,7 @@ call_interceptors(SocketType, #giop_env{interceptors = {portable, _PIs}} = Env, %%----------------------------------------------------------------- %% Func: call_interceptors_out %%----------------------------------------------------------------- +-dialyzer({no_improper_lists, call_interceptors_out/7}). call_interceptors_out(#giop_env{interceptors = {native, Ref, PIs}, ctx = Ctx} = Env, ReqId, Result, Obj, Type, Operation, TypeCodes) -> ReqHdr = #request_header{object_key = Obj, diff --git a/lib/orber/src/orber_pi.erl b/lib/orber/src/orber_pi.erl index 11c489bb17..19bb7af6c0 100644 --- a/lib/orber/src/orber_pi.erl +++ b/lib/orber/src/orber_pi.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% Copyright Ericsson AB 2000-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -1030,6 +1030,7 @@ receive_exception(CRI, Mod) -> %% SlotId - ulong() %% Returns : {'EXCEPTION', #'PortableInterceptor_InvalidSlot'{}} %%------------------------------------------------------------ +-spec get_slot(_, _) -> no_return(). get_slot(_XRI, _SlotId) -> corba:raise(#'PortableInterceptor_InvalidSlot'{}). @@ -1185,6 +1186,7 @@ get_server_policy(#'ServerRequestInfo'{contexts = Ctxs}, _PolicyType) -> %% Data - #any{} %% Returns : {'EXCEPTION', #'PortableInterceptor_InvalidSlot'{}} %%------------------------------------------------------------ +-spec set_slot(_, _, _) -> no_return(). set_slot(_SRI, _SlotId, _Data) -> corba:raise(#'PortableInterceptor_InvalidSlot'{}). diff --git a/lib/orber/vsn.mk b/lib/orber/vsn.mk index 505c77de18..4947315ad0 100644 --- a/lib/orber/vsn.mk +++ b/lib/orber/vsn.mk @@ -1 +1 @@ -ORBER_VSN = 3.8 +ORBER_VSN = 3.8.1 diff --git a/lib/os_mon/doc/src/cpu_sup.xml b/lib/os_mon/doc/src/cpu_sup.xml index 524426ce86..51e1a4c9d6 100644 --- a/lib/os_mon/doc/src/cpu_sup.xml +++ b/lib/os_mon/doc/src/cpu_sup.xml @@ -63,7 +63,7 @@ measure.</p> <p>A server which receives just enough requests to never become idle will score a CPU utilization of 100%. If the server receives - 50% more requests, it will still scores 100%. When the system load + 50% more requests, it will still score 100%. When the system load is calculated with the percentage formula shown previously, the load will increase from 80% to 87%.</p> <p>The <c>avg1/0</c>, <c>avg5/0</c>, and <c>avg15/0</c> functions diff --git a/lib/parsetools/doc/src/leex.xml b/lib/parsetools/doc/src/leex.xml index 7ee0633dac..85680f58a6 100644 --- a/lib/parsetools/doc/src/leex.xml +++ b/lib/parsetools/doc/src/leex.xml @@ -47,7 +47,7 @@ Token = tuple()</code> <v>LeexRet = {ok, Scannerfile} | {ok, Scannerfile, Warnings} | error - | {error, Warnings, Errors}</v> + | {error, Errors, Warnings}</v> <v>Scannerfile = filename()</v> <v>Warnings = Errors = [{filename(), [ErrorInfo]}]</v> <v>ErrorInfo = {ErrorLine, module(), Reason}</v> diff --git a/lib/parsetools/doc/src/notes.xml b/lib/parsetools/doc/src/notes.xml index 7a9770e667..43840a3bc7 100644 --- a/lib/parsetools/doc/src/notes.xml +++ b/lib/parsetools/doc/src/notes.xml @@ -31,6 +31,22 @@ </header> <p>This document describes the changes made to the Parsetools application.</p> +<section><title>Parsetools 2.1.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Correct the documentation of the error tuple returned by + Yecc and Leex.</p> + <p> + Own Id: OTP-13031</p> + </item> + </list> + </section> + +</section> + <section><title>Parsetools 2.1</title> <section><title>Improvements and New Features</title> diff --git a/lib/parsetools/doc/src/yecc.xml b/lib/parsetools/doc/src/yecc.xml index 8c356099e7..87fdfcdaef 100644 --- a/lib/parsetools/doc/src/yecc.xml +++ b/lib/parsetools/doc/src/yecc.xml @@ -52,7 +52,7 @@ <v>Grammarfile = filename()</v> <v>Options = Option | [Option]</v> <v>Option = - see below -</v> - <v>YeccRet = {ok, Parserfile} | {ok, Parserfile, Warnings} | error | {error, Warnings, Errors}</v> + <v>YeccRet = {ok, Parserfile} | {ok, Parserfile, Warnings} | error | {error, Errors, Warnings}</v> <v>Parserfile = filename()</v> <v>Warnings = Errors = [{filename(), [ErrorInfo]}]</v> <v>ErrorInfo = {ErrorLine, module(), Reason}</v> diff --git a/lib/parsetools/vsn.mk b/lib/parsetools/vsn.mk index b99b3bb713..de3da23c8a 100644 --- a/lib/parsetools/vsn.mk +++ b/lib/parsetools/vsn.mk @@ -1 +1 @@ -PARSETOOLS_VSN = 2.1 +PARSETOOLS_VSN = 2.1.1 diff --git a/lib/public_key/asn1/PKIX1Explicit88.asn1 b/lib/public_key/asn1/PKIX1Explicit88.asn1 index 91758d7269..81fec8283e 100644 --- a/lib/public_key/asn1/PKIX1Explicit88.asn1 +++ b/lib/public_key/asn1/PKIX1Explicit88.asn1 @@ -86,22 +86,22 @@ id-at-initials AttributeType ::= { id-at 43 } id-at-generationQualifier AttributeType ::= { id-at 44 } X520name ::= CHOICE { - teletexString TeletexString (SIZE (1..ub-name)), - printableString PrintableString (SIZE (1..ub-name)), - universalString UniversalString (SIZE (1..ub-name)), - utf8String UTF8String (SIZE (1..ub-name)), - bmpString BMPString (SIZE (1..ub-name)) } + teletexString TeletexString (SIZE (1..ub-name-teletex)), + printableString PrintableString (SIZE (1..ub-name-printable)), + universalString UniversalString (SIZE (1..ub-name-universal)), + utf8String UTF8String (SIZE (1..ub-name-utf8)), + bmpString BMPString (SIZE (1..ub-name-universal)) } -- Naming attributes of type X520CommonName id-at-commonName AttributeType ::= { id-at 3 } X520CommonName ::= CHOICE { - teletexString TeletexString (SIZE (1..ub-common-name)), - printableString PrintableString (SIZE (1..ub-common-name)), - universalString UniversalString (SIZE (1..ub-common-name)), - utf8String UTF8String (SIZE (1..ub-common-name)), - bmpString BMPString (SIZE (1..ub-common-name)) } + teletexString TeletexString (SIZE (1..ub-common-name-teletex)), + printableString PrintableString (SIZE (1..ub-common-name-printable)), + universalString UniversalString (SIZE (1..ub-common-name-universal)), + utf8String UTF8String (SIZE (1..ub-common-name-utf8)), + bmpString BMPString (SIZE (1..ub-common-name-universal)) } -- Naming attributes of type X520LocalityName @@ -110,9 +110,9 @@ id-at-localityName AttributeType ::= { id-at 7 } X520LocalityName ::= CHOICE { teletexString TeletexString (SIZE (1..ub-locality-name)), printableString PrintableString (SIZE (1..ub-locality-name)), - universalString UniversalString (SIZE (1..ub-locality-name)), - utf8String UTF8String (SIZE (1..ub-locality-name)), - bmpString BMPString (SIZE (1..ub-locality-name)) } + universalString UniversalString (SIZE (1..ub-locality-name-universal)), + utf8String UTF8String (SIZE (1..ub-locality-name-utf8)), + bmpString BMPString (SIZE (1..ub-locality-name-universal)) } -- Naming attributes of type X520StateOrProvinceName @@ -121,9 +121,9 @@ id-at-stateOrProvinceName AttributeType ::= { id-at 8 } X520StateOrProvinceName ::= CHOICE { teletexString TeletexString (SIZE (1..ub-state-name)), printableString PrintableString (SIZE (1..ub-state-name)), - universalString UniversalString (SIZE (1..ub-state-name)), - utf8String UTF8String (SIZE (1..ub-state-name)), - bmpString BMPString (SIZE(1..ub-state-name)) } + universalString UniversalString (SIZE (1..ub-state-name-universal)), + utf8String UTF8String (SIZE (1..ub-state-name-utf8)), + bmpString BMPString (SIZE(1..ub-state-name-universal)) } -- Naming attributes of type X520OrganizationName @@ -131,15 +131,15 @@ id-at-organizationName AttributeType ::= { id-at 10 } X520OrganizationName ::= CHOICE { teletexString TeletexString - (SIZE (1..ub-organization-name)), + (SIZE (1..ub-organization-name-teletex)), printableString PrintableString - (SIZE (1..ub-organization-name)), + (SIZE (1..ub-organization-name-printable)), universalString UniversalString - (SIZE (1..ub-organization-name)), + (SIZE (1..ub-organization-name-universal)), utf8String UTF8String - (SIZE (1..ub-organization-name)), + (SIZE (1..ub-organization-name-utf8)), bmpString BMPString - (SIZE (1..ub-organization-name)) } + (SIZE (1..ub-organization-name-universal)) } -- Naming attributes of type X520OrganizationalUnitName @@ -147,26 +147,26 @@ id-at-organizationalUnitName AttributeType ::= { id-at 11 } X520OrganizationalUnitName ::= CHOICE { teletexString TeletexString - (SIZE (1..ub-organizational-unit-name)), + (SIZE (1..ub-organizational-unit-name-teletex)), printableString PrintableString - (SIZE (1..ub-organizational-unit-name)), + (SIZE (1..ub-organizational-unit-name-printable)), universalString UniversalString - (SIZE (1..ub-organizational-unit-name)), + (SIZE (1..ub-organizational-unit-name-universal)), utf8String UTF8String - (SIZE (1..ub-organizational-unit-name)), + (SIZE (1..ub-organizational-unit-name-utf8)), bmpString BMPString - (SIZE (1..ub-organizational-unit-name)) } + (SIZE (1..ub-organizational-unit-name-universal)) } -- Naming attributes of type X520Title id-at-title AttributeType ::= { id-at 12 } X520Title ::= CHOICE { - teletexString TeletexString (SIZE (1..ub-title)), - printableString PrintableString (SIZE (1..ub-title)), - universalString UniversalString (SIZE (1..ub-title)), - utf8String UTF8String (SIZE (1..ub-title)), - bmpString BMPString (SIZE (1..ub-title)) } + teletexString TeletexString (SIZE (1..ub-title-teletex)), + printableString PrintableString (SIZE (1..ub-title-printable)), + universalString UniversalString (SIZE (1..ub-title-universal)), + utf8String UTF8String (SIZE (1..ub-title-utf8)), + bmpString BMPString (SIZE (1..ub-title-universal)) } -- Naming attributes of type X520dnQualifier @@ -193,9 +193,9 @@ id-at-pseudonym AttributeType ::= { id-at 65 } X520Pseudonym ::= CHOICE { teletexString TeletexString (SIZE (1..ub-pseudonym)), printableString PrintableString (SIZE (1..ub-pseudonym)), - universalString UniversalString (SIZE (1..ub-pseudonym)), - utf8String UTF8String (SIZE (1..ub-pseudonym)), - bmpString BMPString (SIZE (1..ub-pseudonym)) } + universalString UniversalString (SIZE (1..ub-pseudonym-universal)), + utf8String UTF8String (SIZE (1..ub-pseudonym-utf8)), + bmpString BMPString (SIZE (1..ub-pseudonym-universal)) } -- Naming attributes of type DomainComponent (from RFC 2247) @@ -363,7 +363,7 @@ PrivateDomainName ::= CHOICE { printable PrintableString (SIZE (1..ub-domain-name-length)) } OrganizationName ::= PrintableString - (SIZE (1..ub-organization-name-length)) + (SIZE (1..ub-organization-name-printable)) -- see also teletex-organization-name NumericUserIdentifier ::= NumericString @@ -386,7 +386,7 @@ OrganizationalUnitNames ::= SEQUENCE SIZE (1..ub-organizational-units) -- see also teletex-organizational-unit-names OrganizationalUnitName ::= PrintableString (SIZE - (1..ub-organizational-unit-name-length)) + (1..ub-organizational-unit-name-printable)) -- Built-in Domain-defined Attributes @@ -415,16 +415,16 @@ ExtensionAttribute ::= SEQUENCE { common-name INTEGER ::= 1 -CommonName ::= PrintableString (SIZE (1..ub-common-name-length)) +CommonName ::= PrintableString (SIZE (1..ub-common-name-printable)) teletex-common-name INTEGER ::= 2 -TeletexCommonName ::= TeletexString (SIZE (1..ub-common-name-length)) +TeletexCommonName ::= TeletexString (SIZE (1..ub-common-name-teletex)) teletex-organization-name INTEGER ::= 3 TeletexOrganizationName ::= - TeletexString (SIZE (1..ub-organization-name-length)) + TeletexString (SIZE (1..ub-organization-name-teletex)) teletex-personal-name INTEGER ::= 4 @@ -445,7 +445,7 @@ TeletexOrganizationalUnitNames ::= SEQUENCE SIZE (1..ub-organizational-units) OF TeletexOrganizationalUnitName TeletexOrganizationalUnitName ::= TeletexString - (SIZE (1..ub-organizational-unit-name-length)) + (SIZE (1..ub-organizational-unit-name-teletex)) pds-name INTEGER ::= 7 @@ -570,16 +570,39 @@ TeletexDomainDefinedAttribute ::= SEQUENCE { -- Upper Bounds ub-name INTEGER ::= 32768 +ub-name-teletex INTEGER ::= 65536 +ub-name-printable INTEGER ::= 65536 +ub-name-universal INTEGER ::= 131072 +ub-name-utf8 INTEGER ::= 131072 ub-common-name INTEGER ::= 64 +ub-common-name-teletex INTEGER::= 128 +ub-common-name-printable INTEGER ::= 128 +ub-common-name-universal INTEGER ::= 256 +ub-common-name-utf8 INTEGER ::= 256 ub-locality-name INTEGER ::= 128 +ub-locality-name-utf8 INTEGER ::= 256 +ub-locality-name-universal INTEGER ::= 256 ub-state-name INTEGER ::= 128 +ub-state-name-universal INTEGER ::= 256 +ub-state-name-utf8 INTEGER ::= 256 ub-organization-name INTEGER ::= 64 +ub-organization-name-printable INTEGER ::= 128 +ub-organization-name-teletex INTEGER ::= 128 +ub-organization-name-universal INTEGER ::= 256 +ub-organization-name-utf8 INTEGER ::= 256 ub-organizational-unit-name INTEGER ::= 64 +ub-organizational-unit-name-printable INTEGER ::= 128 +ub-organizational-unit-name-teletex INTEGER ::= 128 +ub-organizational-unit-name-universal INTEGER ::= 256 +ub-organizational-unit-name-utf8 INTEGER ::= 256 ub-title INTEGER ::= 64 +ub-title-teletex INTEGER ::= 128 +ub-title-printable INTEGER ::= 128 +ub-title-universal INTEGER ::= 256 +ub-title-utf8 INTEGER ::= 256 ub-serial-number INTEGER ::= 64 ub-match INTEGER ::= 128 ub-emailaddress-length INTEGER ::= 255 -ub-common-name-length INTEGER ::= 64 ub-country-name-alpha-length INTEGER ::= 2 ub-country-name-numeric-length INTEGER ::= 3 ub-domain-defined-attributes INTEGER ::= 4 @@ -594,14 +617,14 @@ ub-given-name-length INTEGER ::= 16 ub-initials-length INTEGER ::= 5 ub-integer-options INTEGER ::= 256 ub-numeric-user-id-length INTEGER ::= 32 -ub-organization-name-length INTEGER ::= 64 -ub-organizational-unit-name-length INTEGER ::= 32 ub-organizational-units INTEGER ::= 4 ub-pds-name-length INTEGER ::= 16 ub-pds-parameter-length INTEGER ::= 30 ub-pds-physical-address-lines INTEGER ::= 6 ub-postal-code-length INTEGER ::= 16 ub-pseudonym INTEGER ::= 128 +ub-pseudonym-utf8 INTEGER ::= 256 +ub-pseudonym-universal INTEGER ::= 256 ub-surname-length INTEGER ::= 40 ub-terminal-id-length INTEGER ::= 24 ub-unformatted-address-length INTEGER ::= 180 diff --git a/lib/public_key/doc/src/notes.xml b/lib/public_key/doc/src/notes.xml index 87db5bd9f4..da8f62e2f8 100644 --- a/lib/public_key/doc/src/notes.xml +++ b/lib/public_key/doc/src/notes.xml @@ -35,6 +35,77 @@ <file>notes.xml</file> </header> +<section><title>Public_Key 1.1.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + An encapsulated PEM header shall be followed by a blank + line</p> + <p> + Own Id: OTP-13381 Aux Id: seq13070 </p> + </item> + </list> + </section> + +</section> + +<section><title>Public_Key 1.1</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + The 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384' and + 'ecdsa-sha2-nistp521' signature algorithms for ssh are + implemented. See RFC 5656.</p> + <p> + Own Id: OTP-12936</p> + </item> + <item> + <p> + There is now a file (public_key/priv/moduli) which lists + size-generator-modulus triples. The purpose is to give + servers the possibility to select the crypto primes + randomly among a list of pregenerated triples. This + reduces the risk for some attacks on diffie-hellman + negotiation.</p> + <p> + See the reference manual for public_key:dh_gex_group/4 + where the handling of this is described.</p> + <p> + The ssh server (ssh:daemon) uses this.</p> + <p> + Own Id: OTP-13054 Aux Id: OTP-13052 </p> + </item> + <item> + <p> + Add different upper bounds for diffrent string types as + suggested by comment in PKIX1Explicit88.</p> + <p> + Own Id: OTP-13132</p> + </item> + </list> + </section> + +</section> + +<section><title>Public_Key 1.0.1</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Document enhancements</p> + <p> + Own Id: OTP-12986</p> + </item> + </list> + </section> + +</section> + <section><title>Public_Key 1.0</title> <section><title>Improvements and New Features</title> diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml index 394fe54428..16a7497a22 100644 --- a/lib/public_key/doc/src/public_key.xml +++ b/lib/public_key/doc/src/public_key.xml @@ -108,13 +108,14 @@ <p><c>| 'SubjectPublicKeyInfo'</c></p> <p><c>| 'PrivateKeyInfo'</c></p> <p><c>| 'CertificationRequest'</c></p> + <p><c>| 'CertificateList'</c></p> <p><c>| 'ECPrivateKey'</c></p> - <p><c>| 'EcpkParameters'</c></p> + <p><c>| 'EcpkParameters'</c></p> </item> <tag><c>pem_entry () =</c></tag> - <item><p><c>{pki_asn1_type(), binary(), %% DER or encrypted DER not_encrypted</c></p> - <p><c>| cipher_info()}</c></p></item> + <item><p><c>{pki_asn1_type(), binary(), %% DER or encrypted DER</c></p> + <p><c> not_encrypted | cipher_info()}</c></p></item> <tag><c>cipher_info() = </c></tag> <item><p><c>{"RC2-CBC" | "DES-CBC" | "DES-EDE3-CBC", crypto:rand_bytes(8)</c></p> @@ -298,6 +299,37 @@ </desc> </func> + <func> + <name>dh_gex_group(MinSize, SuggestedSize, MaxSize, Groups) -> {ok, {Size,Group}} | {error,Error}</name> + <fsummary>Selects a group for Diffie-Hellman key exchange</fsummary> + <type> + <v>MinSize = positive_integer()</v> + <v>SuggestedSize = positive_integer()</v> + <v>MaxSize = positive_integer()</v> + <v>Groups = undefined | [{Size,[{G,P}]}]</v> + <v>Size = positive_integer()</v> + <v>Group = {G,P}</v> + <v>G = positive_integer()</v> + <v>P = positive_integer()</v> + </type> + <desc> + <p>Selects a group for Diffie-Hellman key exchange with the key size in the range <c>MinSize...MaxSize</c> + and as close to <c>SuggestedSize</c> as possible. If <c>Groups == undefined</c> a default set will be + used, otherwise the group is selected from <c>Groups</c>.</p> + <p>First a size, as close as possible to SuggestedSize, is selected. Then one group with that key size + is randomly selected from the specified set of groups. If no size within the limits of <c>MinSize</c> + and <c>MaxSize</c> is available, <c>{error,no_group_found}</c> is returned.</p> + <p>The default set of groups is listed in <c>lib/public_key/priv/moduli</c>. This file may be regenerated like this:</p> + <pre> + $> cd $ERL_TOP/lib/public_key/priv/ + $> generate + ---- wait until all background jobs has finished. It may take several days ! + $> cat moduli-* > moduli + $> cd ..; make + </pre> + </desc> + </func> + <func> <name>encrypt_private(PlainText, Key) -> binary()</name> <fsummary>Public-key encryption using the private key.</fsummary> @@ -433,7 +465,7 @@ <name>pkix_is_issuer(Cert, IssuerCert) -> boolean()</name> <fsummary>Checks if <c>IssuerCert</c> issued <c>Cert</c>.</fsummary> <type> - <v>Cert = der_encoded() | #'OTPCertificate'{}</v> + <v>Cert = der_encoded() | #'OTPCertificate'{} | #'CertificateList'{}</v> <v>IssuerCert = der_encoded() | #'OTPCertificate'{}</v> </type> <desc> @@ -497,13 +529,13 @@ <name>pkix_path_validation(TrustedCert, CertChain, Options) -> {ok, {PublicKeyInfo, PolicyTree}} | {error, {bad_cert, Reason}} </name> <fsummary>Performs a basic path validation according to RFC 5280.</fsummary> <type> - <v>TrustedCert = #'OTPCertificate'{} | der_encode() | atom()</v> + <v>TrustedCert = #'OTPCertificate'{} | der_encoded() | atom()</v> <d>Normally a trusted certificate, but it can also be a path-validation error that can be discovered while constructing the input to this function and that is to be run through the <c>verify_fun</c>. Examples are <c>unknown_ca</c> and <c>selfsigned_peer.</c> </d> - <v>CertChain = [der_encode()]</v> + <v>CertChain = [der_encoded()]</v> <d>A list of DER-encoded certificates in trust order ending with the peer certificate.</d> <v>Options = proplists:proplist()</v> <v>PublicKeyInfo = {?'rsaEncryption' | ?'id-dsa', @@ -698,7 +730,7 @@ fun(#'DistributionPoint'{}, #'CertificateList'{}, <name>pkix_sign(#'OTPTBSCertificate'{}, Key) -> der_encoded()</name> <fsummary>Signs certificate.</fsummary> <type> - <v>Key = rsa_public_key() | dsa_public_key()</v> + <v>Key = rsa_private_key() | dsa_private_key()</v> </type> <desc> <p>Signs an 'OTPTBSCertificate'. Returns the corresponding @@ -713,7 +745,7 @@ fun(#'DistributionPoint'{}, #'CertificateList'{}, <v>AlgorithmId = oid()</v> <d>Signature OID from a certificate or a certificate revocation list.</d> <v>DigestType = rsa_digest_type() | dss_digest_type()</v> - <v>SignatureType = rsa | dsa</v> + <v>SignatureType = rsa | dsa | ecdsa</v> </type> <desc> <p>Translates signature algorithm OID to Erlang digest and signature types. @@ -726,7 +758,7 @@ fun(#'DistributionPoint'{}, #'CertificateList'{}, <fsummary>Verifies PKIX x.509 certificate signature.</fsummary> <type> <v>Cert = der_encoded()</v> - <v>Key = rsa_public_key() | dsa_public_key()</v> + <v>Key = rsa_public_key() | dsa_public_key() | ec_public_key()</v> </type> <desc> <p>Verifies PKIX x.509 certificate signature.</p> @@ -754,13 +786,13 @@ fun(#'DistributionPoint'{}, #'CertificateList'{}, <fsummary>Decodes an SSH file-binary.</fsummary> <type> <v>SshBin = binary()</v> - <d>Example {ok, SshBin} = file:read_file("known_hosts").</d> + <d>Example <c>{ok, SshBin} = file:read_file("known_hosts")</c>.</d> <v>Type = public_key | ssh_file()</v> <d>If <c>Type</c> is <c>public_key</c> the binary can be either an RFC4716 public key or an OpenSSH public key.</d> </type> <desc> - <p>Decodes an SSH file-binary. In the case of <c>know_hosts</c> or + <p>Decodes an SSH file-binary. In the case of <c>known_hosts</c> or <c>auth_keys</c>, the binary can include one or more lines of the file. Returns a list of public keys and their attributes, possible attribute values depends on the file type represented by the @@ -810,7 +842,7 @@ fun(#'DistributionPoint'{}, #'CertificateList'{}, <v>Key = rsa_public_key() | dsa_public_key() | ec_public_key()</v> </type> <desc> - <p>Veryfies a digital signature.</p> + <p>Verifies a digital signature.</p> </desc> </func> diff --git a/lib/public_key/doc/src/public_key_records.xml b/lib/public_key/doc/src/public_key_records.xml index fb03da3150..d34f3ed9a3 100644 --- a/lib/public_key/doc/src/public_key_records.xml +++ b/lib/public_key/doc/src/public_key_records.xml @@ -57,9 +57,9 @@ <taglist> <tag><c>time() =</c></tag> - <item><p><c>uct_time() | general_time()</c></p></item> + <item><p><c>utc_time() | general_time()</c></p></item> - <tag><c>uct_time() =</c></tag> + <tag><c>utc_time() =</c></tag> <item><p><c>{utcTime, "YYMMDDHHMMSSZ"}</c></p></item> <tag><c>general_time() =</c></tag> @@ -144,7 +144,7 @@ <section> <title>DSA</title> - <p>Erlang representation of <url href="http://www.ietf.org/rfc/rfc6979.txt">Digigital Signature Algorithm (DSA)</url> keys</p> + <p>Erlang representation of <url href="http://www.ietf.org/rfc/rfc6979.txt">Digital Signature Algorithm (DSA)</url> keys</p> <code> #'DSAPrivateKey',{ version, % integer() diff --git a/lib/public_key/priv/convert.escript b/lib/public_key/priv/convert.escript new file mode 100755 index 0000000000..c7ea48c686 --- /dev/null +++ b/lib/public_key/priv/convert.escript @@ -0,0 +1,50 @@ +#!/usr/bin/env escript +%% -*- erlang -*- + +main([InFile,OutFile]) -> + {ok,In} = file:open(InFile,read), + {ok,Out} = file:open(OutFile,write), + write_file(Out, read_file(In)), + file:close(In), + file:close(Out). + +write_file(D, {ok,Ms}) -> + io:format(D,'-define(dh_default_groups,~n ~p~n ).~n',[Ms]). + +one_line(Line, Acc) when is_binary(Line) -> + one_line(binary_to_list(Line), Acc); +one_line("#"++_, Acc) -> + Acc; +one_line(Line, Acc) when is_list(Line) -> + try + [_Time,_Type,_Tests,_Tries,Size,G,P] = string:tokens(Line," \r\n"), + [{list_to_integer(Size), + {list_to_integer(G), list_to_integer(P,16)} + } | Acc] + catch + _:_ -> io:format("*** skip line ~p",[Line]), + Acc + end. + + +collect_per_size(L) -> + lists:foldr( + fun({Sz,GP}, [{Sz,GPs}|Acc]) -> [{Sz,[GP|GPs]}|Acc]; + ({Sz,GP}, Acc) -> [{Sz,[GP]}|Acc] + end, [], lists:sort(L)). + + +read_file(D) -> + read_file(D, []). + +read_file(D, Acc) -> + case io:get_line(D,"") of + {error,Error} -> + {error,Error}; + eof -> + {ok, collect_per_size(Acc)}; + Data -> + read_file(D, one_line(Data,Acc)) + end. + + diff --git a/lib/public_key/priv/generate b/lib/public_key/priv/generate new file mode 100755 index 0000000000..fd185bfd52 --- /dev/null +++ b/lib/public_key/priv/generate @@ -0,0 +1,25 @@ +#!/bin/bash + +# Generate ssh moduli files for the sizes in $moduli + +moduli="1024 1536 2048 3072 4096 6144 7168 8192" + +# In arg 1: size +# Out: a file "moduli-$1" (for example: $1=2048 -> file "moduli.2048" +function one_modulus() { + candidates=candidate-$1 + ssh-keygen -G $candidates -b $1 + ssh-keygen -T moduli-$1 -f $candidates + rm $candidates +} + + +# Generate in background +for m in $moduli +do + one_modulus $m & +done + +# When all files moduli-* are generated, do: +# cat moduli-* > moduli + diff --git a/lib/public_key/priv/moduli b/lib/public_key/priv/moduli new file mode 100644 index 0000000000..446f4b8bf4 --- /dev/null +++ b/lib/public_key/priv/moduli @@ -0,0 +1,193 @@ +20151021104105 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D182EB7 +20151021104106 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D27F94F +20151021104107 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D398EB7 +20151021104108 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D4B850F +20151021104108 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D4BF35B +20151021104108 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D5031DF +20151021104109 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D5A4933 +20151021104110 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D6434BF +20151021104111 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D70676B +20151021104111 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D7235E3 +20151021104113 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D963493 +20151021104114 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9DAABAA7 +20151021104115 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9DC2E333 +20151021104116 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9DE16A7B +20151021104117 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9DE2C5D3 +20151021104118 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9DFF382F +20151021104119 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9E158F13 +20151021104122 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9E4D9FEB +20151021104123 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9E5C1FDB +20151021104126 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9E9BB69B +20151021104126 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9E9F62D3 +20151021104127 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9EAA1C27 +20151021104128 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9EBC3313 +20151021104129 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9EC0733B +20151021104130 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9EDB7AD3 +20151021104132 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9EF56457 +20151021104132 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9EF5A9CF +20151021104133 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9F13CBB3 +20151021104218 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17BAAFFDF +20151021104222 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17BCB6D93 +20151021104225 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17BE660BB +20151021104226 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17BE676C3 +20151021104229 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17BF3E23B +20151021104230 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17BF95757 +20151021104241 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17C59BEA7 +20151021104242 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17C6231B3 +20151021104244 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17C6879BF +20151021104250 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17C9B678F +20151021104252 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17CA66A4B +20151021104253 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17CAB5543 +20151021104256 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17CB96933 +20151021104300 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17CDA8493 +20151021104308 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17D18C0C7 +20151021104310 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17D1DA5BF +20151021104318 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17D4AB15F +20151021104325 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17D7DE42F +20151021104329 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17DA03D3B +20151021104335 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17DD88BFF +20151021104338 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17DE82B5F +20151021104342 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17E07AF43 +20151021104343 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17E091E6F +20151021104346 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17E28B90F +20151021104347 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17E2A24F3 +20151021104401 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17EB074A7 +20151021104403 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17EC01B0F +20151021104406 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17ED2186F +20151021104407 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17ED55AAB +20151021104411 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17EF58773 +20151021104414 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17F0B3267 +20151021104423 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17F4DF61B +20151021104434 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17F9BBB0B +20151021104442 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17FDD6AFB +20151021104350 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE5E381EF +20151021104414 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE641C193 +20151021104422 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE659F523 +20151021104427 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE660E217 +20151021104438 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE6842F73 +20151021104441 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE689683B +20151021104455 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE6C41E3B +20151021104512 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE71E3BFF +20151021104525 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE75C804F +20151021104527 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE75DC48B +20151021104535 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE7738983 +20151021104543 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE787027B +20151021104610 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE8075A1B +20151021104625 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE84F79B3 +20151021104628 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE859F617 +20151021104641 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE8948E2F +20151021104646 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE8A571B3 +20151021104659 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE8CEA637 +20151021104705 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE8E590FF +20151021104707 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE8E7943F +20151021104731 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE95A975F +20151021104741 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE985F923 +20151021104745 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE996E20B +20151021104806 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE9FACFD7 +20151021104827 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BEA562C43 +20151021104839 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BEA8F25E3 +20151021104939 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BEBB1DA0B +20151021104941 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BEBB86153 +20151021105002 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BEC1B8883 +20151021105019 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BEC71316F +20151021105035 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BECB1D113 +20151021105042 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BECC3F3AB +20151021105045 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BECCC109B +20151021105101 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BED16353B +20151021105106 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BED24854F +20151021105109 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BED2AE4B3 +20151021105116 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BED472CF7 +20151021104612 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E360CD0C3 +20151021104628 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3620FBE7 +20151021104701 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E36490F57 +20151021105014 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E377ACADB +20151021105125 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E37E6DE07 +20151021105320 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E38C2387F +20151021105649 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3A61E46B +20151021105815 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3B0A6A4B +20151021105848 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3B47D2C3 +20151021105948 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3BBBB953 +20151021110011 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3BE3B83B +20151021110036 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3C0A3F1B +20151021110201 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3CB1970F +20151021110208 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3CB70C2B +20151021110235 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3CE4E4DF +20151021110424 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3DB68CD7 +20151021110525 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3E290717 +20151021110655 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3ED6DA83 +20151021110731 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3F14C563 +20151021110831 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3F85477F +20151021111418 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E420DE56B +20151021111430 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E421DBA2F +20151021111624 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E42F39A93 +20151021111916 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E44302363 +20151021112222 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E4585795F +20151021112245 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E45A1DAFF +20151021112339 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E4601674F +20151021112437 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E46691977 +20151021112521 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E46AF3AD3 +20151021112532 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E46BCAE97 +20151021112708 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E476520D3 +20151021112724 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E477B3317 +20151021105143 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156BA7321EB +20151021105537 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156BB3AF34B +20151021105816 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156BBC51883 +20151021110444 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156BD1A86C7 +20151021111341 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156BEDB7BBB +20151021111438 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156BF0297AB +20151021111935 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156BFF381FF +20151021113820 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C433A1BF +20151021113833 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C43B426B +20151021113900 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C45007D3 +20151021113921 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C45D8C3B +20151021113941 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C4685D5F +20151021114203 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C4F95D97 +20151021114417 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C57ED2FF +20151021114645 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C612EC33 +20151021114825 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C67219F7 +20151021114922 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C6A942BB +20151021115945 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C91E14DB +20151021120515 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CA5F5DB3 +20151021120715 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CAD0D497 +20151021121027 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CB8F9D6F +20151021121241 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CC0F677F +20151021121518 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CC9CC647 +20151021121600 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CCC0ADC3 +20151021121734 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CD1BC68B +20151021121759 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CD2A7DBF +20151021122003 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CDA3D323 +20151021122542 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CED8D107 +20151021122856 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CF8DFEE7 +20151021123548 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156D11CAC4F +20151021123633 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156D1426BBB +20151021124201 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156D2A62F0B +20151021124454 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156D353F0FB +20151021124620 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156D3AE526F +20151021125224 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156D535C4CB +20151021130254 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156D7B5CA43 +20151021111833 2 6 100 6143 5 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B239959D5A7 +20151021112931 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B239A078C1B +20151021123021 2 6 100 6143 5 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B239EC676DF +20151021131523 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23A2B9FC6B +20151021141029 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23A7BD762B +20151021143421 2 6 100 6143 5 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23A9C3EFDF +20151021144912 2 6 100 6143 5 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23AB1077AF +20151021145200 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23AB49943B +20151021145825 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23ABE06353 +20151021150910 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23ACDA0223 +20151021153131 2 6 100 6143 5 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23AE91738F +20151021154038 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23AF40D013 +20151021154300 2 6 100 6143 5 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23AF75AD97 +20151021155008 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23B01C9553 +20151021162240 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23B319431B +20151021162649 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23B35A3D2B +20151021163640 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23B439E263 +20151021171004 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23B748B983 +20151021172144 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23B8609B5B +20151021173002 2 6 100 6143 5 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23B9021E9F +20151021182612 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23BE0C1EDB +20151021190053 2 6 100 6143 5 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23C120FF97 +20151021192934 2 6 100 6143 5 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23C3BEB637 +20151021113847 2 6 100 8191 2 DC61EF13E4F3FC10CC946EEABC33F83EFCB35E0F47E4EC25C1CCBB2C7B502B2EFB0691AA231C8476DD51BA73204E6EA10B1A970FE2CF14AF01E72E1AEA87519A91D00D1499189F94A6CDA9E29C05F11F17FE74A4919A710A2787E180744465DF81C62AA65662FDA46FA6175E8A31E5B29E66DED6701C8FC4217E91D733FE94380F046680967D4CEA7BAC8F3916CDF96AA2C474FAD9650F48403FD0B5B756D34667D36A07767FA33027AE55484D0F701C3CA16632F413A14E4B8645AFAF15B78978C19A7661EDC569BEC72394B1204B166A48FCD5F56BE29840C7794CA6D3440356F15858CDCA9B429C7EA92E17242893FDC8C9C63841A382C32F20CFAB121B4BCAFD7BF9EF07FBF7CDFFECA0CEF3A49C3E2B24FA836F3318435255655E1B281071F62D5E4CD63361299B7828F72936E3FEA9E8044562A6F6ADD5321187C3101E4669C6271598FE1A866C93FE2870A4CEB9254BA32A4719E439317EA42200A335B5CFFA7946A7D0F1BD1A69AA11288B73C71C80B77FE3707CB077DDDEA5CA36A449FAB230C9625A0B12F8275D3FF82F5DA380E7A3F11B6F155FE7E91AC960BD95D9B13F7423AB9B15CC3C4DC34EF296033F009468EA16A721AD659F56C18516025050749ABF05E6D3EBD9778142A530979291F46DAA399A86B7BCDF09CC3E6EEF101419762A306DB45AEFC96C64E83F28338D55905F6A387E0F515E580C3A9B35330E21C32198CDEE3AFB355967A098F635FCA7C49CB4E1E82464B2B390EF1F259E40B9A06235C0273F76284FE6BD534EF3AF7CB01A4A5252B8B94CADC2850B2E56D53F9A31D7C029DF967D0A30C05BC64E119BED6076818FABC8CDD93F3255693E14EFC1A740A5D63A5E847FFE87BAB1DDE0506E1762EA61EFA9F9756151ECCCADD91B98A961A901A2D8B01ABDDD29EC804E8C8D28214BBA26048F924CA66316696E51A49D02FF034D20E44914B1115339CAD3819E0CB1640F0084886FEDDE5E28C29DC48ED30A8C3D789734338F5A9DF42584326E536FD1CF30BC85B8DCBD6120D127C98FE4B3614074F13C2CA4854E6D794156C185C40EB3DA7619CE96ADAF0941BD5499848B034C2B11DFECC0BDFA81C594241F759EF53FC7CDE7F2DE4F23CF81A5A0B7D62E31DABB9198D40307F7824DD130B7D1B80E9B6D322FEEDB5ACE34944F0BFB7D016762A9B2E173BFDD69303766AFBAB45FAB75D05430B4A3515858C4B7F04E23414E4AD03842CB0A20D8FF4B59B7C852BA9A5BE982A8ADA5CB70C36CE2A4D2C31A7015C9F3275E43D192C1B2924424088907A057DA7F2D32A2149922AB2E33F2147D637A3508911CB3FEA5E1AAB4525BACF27B6DD7A3E0AFA978FC3A39DE8882FB22688C3CCC92B6E69ACB0BBF575AB3368E51A2F6A20C414C6F146727CC0045F29061E695D29F7C030CE6929EB3AD11A5CBD0CDEE37347869A3 +20151021133636 2 6 100 8191 2 DC61EF13E4F3FC10CC946EEABC33F83EFCB35E0F47E4EC25C1CCBB2C7B502B2EFB0691AA231C8476DD51BA73204E6EA10B1A970FE2CF14AF01E72E1AEA87519A91D00D1499189F94A6CDA9E29C05F11F17FE74A4919A710A2787E180744465DF81C62AA65662FDA46FA6175E8A31E5B29E66DED6701C8FC4217E91D733FE94380F046680967D4CEA7BAC8F3916CDF96AA2C474FAD9650F48403FD0B5B756D34667D36A07767FA33027AE55484D0F701C3CA16632F413A14E4B8645AFAF15B78978C19A7661EDC569BEC72394B1204B166A48FCD5F56BE29840C7794CA6D3440356F15858CDCA9B429C7EA92E17242893FDC8C9C63841A382C32F20CFAB121B4BCAFD7BF9EF07FBF7CDFFECA0CEF3A49C3E2B24FA836F3318435255655E1B281071F62D5E4CD63361299B7828F72936E3FEA9E8044562A6F6ADD5321187C3101E4669C6271598FE1A866C93FE2870A4CEB9254BA32A4719E439317EA42200A335B5CFFA7946A7D0F1BD1A69AA11288B73C71C80B77FE3707CB077DDDEA5CA36A449FAB230C9625A0B12F8275D3FF82F5DA380E7A3F11B6F155FE7E91AC960BD95D9B13F7423AB9B15CC3C4DC34EF296033F009468EA16A721AD659F56C18516025050749ABF05E6D3EBD9778142A530979291F46DAA399A86B7BCDF09CC3E6EEF101419762A306DB45AEFC96C64E83F28338D55905F6A387E0F515E580C3A9B35330E21C32198CDEE3AFB355967A098F635FCA7C49CB4E1E82464B2B390EF1F259E40B9A06235C0273F76284FE6BD534EF3AF7CB01A4A5252B8B94CADC2850B2E56D53F9A31D7C029DF967D0A30C05BC64E119BED6076818FABC8CDD93F3255693E14EFC1A740A5D63A5E847FFE87BAB1DDE0506E1762EA61EFA9F9756151ECCCADD91B98A961A901A2D8B01ABDDD29EC804E8C8D28214BBA26048F924CA66316696E51A49D02FF034D20E44914B1115339CAD3819E0CB1640F0084886FEDDE5E28C29DC48ED30A8C3D789734338F5A9DF42584326E536FD1CF30BC85B8DCBD6120D127C98FE4B3614074F13C2CA4854E6D794156C185C40EB3DA7619CE96ADAF0941BD5499848B034C2B11DFECC0BDFA81C594241F759EF53FC7CDE7F2DE4F23CF81A5A0B7D62E31DABB9198D40307F7824DD130B7D1B80E9B6D322FEEDB5ACE34944F0BFB7D016762A9B2E173BFDD69303766AFBAB45FAB75D05430B4A3515858C4B7F04E23414E4AD03842CB0A20D8FF4B59B7C852BA9A5BE982A8ADA5CB70C36CE2A4D2C31A7015C9F3275E43D192C1B2924424088907A057DA7F2D32A2149922AB2E33F2147D637A3508911CB3FEA5E1AAB4525BACF27B6DD7A3E0AFA978FC3A39DE8882FB22688C3CCC92B6E69ACB0BBF575AB3368E51A2F6A20C414C6F146727CC0045F29061E695D29F7C030CE6929EB3AD11A5CBD0CDEE373914ECA3 +20151021140108 2 6 100 8191 5 DC61EF13E4F3FC10CC946EEABC33F83EFCB35E0F47E4EC25C1CCBB2C7B502B2EFB0691AA231C8476DD51BA73204E6EA10B1A970FE2CF14AF01E72E1AEA87519A91D00D1499189F94A6CDA9E29C05F11F17FE74A4919A710A2787E180744465DF81C62AA65662FDA46FA6175E8A31E5B29E66DED6701C8FC4217E91D733FE94380F046680967D4CEA7BAC8F3916CDF96AA2C474FAD9650F48403FD0B5B756D34667D36A07767FA33027AE55484D0F701C3CA16632F413A14E4B8645AFAF15B78978C19A7661EDC569BEC72394B1204B166A48FCD5F56BE29840C7794CA6D3440356F15858CDCA9B429C7EA92E17242893FDC8C9C63841A382C32F20CFAB121B4BCAFD7BF9EF07FBF7CDFFECA0CEF3A49C3E2B24FA836F3318435255655E1B281071F62D5E4CD63361299B7828F72936E3FEA9E8044562A6F6ADD5321187C3101E4669C6271598FE1A866C93FE2870A4CEB9254BA32A4719E439317EA42200A335B5CFFA7946A7D0F1BD1A69AA11288B73C71C80B77FE3707CB077DDDEA5CA36A449FAB230C9625A0B12F8275D3FF82F5DA380E7A3F11B6F155FE7E91AC960BD95D9B13F7423AB9B15CC3C4DC34EF296033F009468EA16A721AD659F56C18516025050749ABF05E6D3EBD9778142A530979291F46DAA399A86B7BCDF09CC3E6EEF101419762A306DB45AEFC96C64E83F28338D55905F6A387E0F515E580C3A9B35330E21C32198CDEE3AFB355967A098F635FCA7C49CB4E1E82464B2B390EF1F259E40B9A06235C0273F76284FE6BD534EF3AF7CB01A4A5252B8B94CADC2850B2E56D53F9A31D7C029DF967D0A30C05BC64E119BED6076818FABC8CDD93F3255693E14EFC1A740A5D63A5E847FFE87BAB1DDE0506E1762EA61EFA9F9756151ECCCADD91B98A961A901A2D8B01ABDDD29EC804E8C8D28214BBA26048F924CA66316696E51A49D02FF034D20E44914B1115339CAD3819E0CB1640F0084886FEDDE5E28C29DC48ED30A8C3D789734338F5A9DF42584326E536FD1CF30BC85B8DCBD6120D127C98FE4B3614074F13C2CA4854E6D794156C185C40EB3DA7619CE96ADAF0941BD5499848B034C2B11DFECC0BDFA81C594241F759EF53FC7CDE7F2DE4F23CF81A5A0B7D62E31DABB9198D40307F7824DD130B7D1B80E9B6D322FEEDB5ACE34944F0BFB7D016762A9B2E173BFDD69303766AFBAB45FAB75D05430B4A3515858C4B7F04E23414E4AD03842CB0A20D8FF4B59B7C852BA9A5BE982A8ADA5CB70C36CE2A4D2C31A7015C9F3275E43D192C1B2924424088907A057DA7F2D32A2149922AB2E33F2147D637A3508911CB3FEA5E1AAB4525BACF27B6DD7A3E0AFA978FC3A39DE8882FB22688C3CCC92B6E69ACB0BBF575AB3368E51A2F6A20C414C6F146727CC0045F29061E695D29F7C030CE6929EB3AD11A5CBD0CDEE373A17959F diff --git a/lib/public_key/src/Makefile b/lib/public_key/src/Makefile index 621cedadcd..786f244f85 100644 --- a/lib/public_key/src/Makefile +++ b/lib/public_key/src/Makefile @@ -50,7 +50,7 @@ MODULES = \ HRL_FILES = $(INCLUDE)/public_key.hrl -INTERNAL_HRL_FILES = +INTERNAL_HRL_FILES = pubkey_moduli.hrl ERL_FILES = $(MODULES:%=%.erl) @@ -86,6 +86,11 @@ ERL_COMPILE_FLAGS += $(PUB_KEY_ERL_FLAGS) \ debug opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(HRL_FILES) +$(EBIN)/pubkey_ssh.$(EMULATOR): pubkey_moduli.hrl + +pubkey_moduli.hrl: ../priv/moduli + escript ../priv/convert.escript $< $@ + clean: rm -f $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) rm -f core diff --git a/lib/public_key/src/pubkey_moduli.hrl b/lib/public_key/src/pubkey_moduli.hrl new file mode 100644 index 0000000000..e4beecc12a --- /dev/null +++ b/lib/public_key/src/pubkey_moduli.hrl @@ -0,0 +1,395 @@ +-define(dh_default_groups, + [{1023, + [{2, + 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840821904219}, + {2, + 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840822843699}, + {2, + 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840824293227}, + {2, + 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840824411619}, + {2, + 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840826770579}, + {2, + 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840829698867}, + {2, + 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840831699579}, + {2, + 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840831788499}, + {2, + 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840835116819}, + {2, + 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840838791147}, + {2, + 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840839741403}, + {2, + 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840843908763}, + {2, + 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840844149459}, + {2, + 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840846037779}, + {2, + 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840846316347}, + {2, + 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840848087763}, + {2, + 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840851778483}, + {5, + 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840818511543}, + {5, + 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840819546447}, + {5, + 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840820698807}, + {5, + 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840821875983}, + {5, + 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840822182367}, + {5, + 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840823493823}, + {5, + 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840828115623}, + {5, + 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840833652783}, + {5, + 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840844852263}, + {5, + 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840849785943}, + {5, + 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840849803727}]}, + {1535, + [{2, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891121581459}, + {2, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891123347643}, + {2, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891123353283}, + {2, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891124232763}, + {2, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891131462067}, + {2, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891135933003}, + {2, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891136255299}, + {2, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891137177907}, + {2, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891139347603}, + {2, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891152305467}, + {2, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891159084867}, + {2, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891161343219}, + {2, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891172563627}, + {2, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891174672243}, + {2, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891180467739}, + {2, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891185564427}, + {2, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891189869307}, + {5, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891119456223}, + {5, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891124590423}, + {5, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891130908327}, + {5, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891131873727}, + {5, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891135211407}, + {5, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891143426247}, + {5, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891143747007}, + {5, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891146699103}, + {5, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891150054447}, + {5, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891155995647}, + {5, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891157019487}, + {5, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891159178863}, + {5, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891161250063}, + {5, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891170145447}, + {5, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891171171087}, + {5, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891172350063}, + {5, + 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891176092263}]}, + {2047, + [{2, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127673160083}, + {2, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127674746147}, + {2, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127677513587}, + {2, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127677855803}, + {2, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127681703483}, + {2, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127691773067}, + {2, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127693199747}, + {2, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127694475899}, + {2, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127702886939}, + {2, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127707613619}, + {2, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127713247667}, + {2, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127727962403}, + {2, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127729070603}, + {2, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127741606979}, + {2, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127745340899}, + {2, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127764392459}, + {2, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127764820307}, + {2, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127771318403}, + {2, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127781167379}, + {2, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127782355883}, + {2, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127782887579}, + {2, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127787746619}, + {2, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127789102259}, + {5, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127666983407}, + {5, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127675200023}, + {5, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127687609343}, + {5, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127691690063}, + {5, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127708300823}, + {5, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127712140847}, + {5, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127715948087}, + {5, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127717449983}, + {5, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127717581887}, + {5, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127725119327}, + {5, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127735619543}, + {5, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127776932207}, + {5, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127788684623}, + {5, + 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127790955767}]}, + {3071, + [{2, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199506260163}, + {2, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199530244827}, + {2, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199578944619}, + {2, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199589988939}, + {2, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199594013379}, + {2, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199601609043}, + {2, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199604230203}, + {2, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199606755099}, + {2, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199618079787}, + {2, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199653718659}, + {2, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199657776483}, + {2, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199707657579}, + {2, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199722711699}, + {2, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199743456099}, + {2, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199785339603}, + {2, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199797260499}, + {5, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199507581927}, + {5, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199510208343}, + {5, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199537327623}, + {5, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199551703167}, + {5, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199617722127}, + {5, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199621084383}, + {5, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199634824407}, + {5, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199642326807}, + {5, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199665149823}, + {5, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199708695087}, + {5, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199765825887}, + {5, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199767685887}, + {5, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199773947727}, + {5, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199780743543}, + {5, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199786221207}, + {5, + 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199798706967}]}, + {4095, + [{2, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328641094123}, + {2, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328654189387}, + {2, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328663242883}, + {2, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328715041723}, + {2, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328717604779}, + {2, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328805204587}, + {2, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328806565843}, + {2, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328807451707}, + {2, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328836115507}, + {2, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328845968059}, + {2, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328887178459}, + {2, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328908234163}, + {2, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328948166083}, + {2, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328954136203}, + {2, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328963052323}, + {2, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024329023777723}, + {2, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024329047093003}, + {2, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024329058480379}, + {2, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024329090057419}, + {2, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024329132001859}, + {5, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328685618887}, + {5, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328733393407}, + {5, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328804704703}, + {5, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328808160607}, + {5, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328817663383}, + {5, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328826409727}, + {5, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328842353143}, + {5, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328915670167}, + {5, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328928173423}, + {5, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328936548223}, + {5, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328945813063}, + {5, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328955100607}, + {5, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328983302407}, + {5, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328995176167}, + {5, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024329021303887}, + {5, + 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024329064403567}]}, + {6143, + [{2, + 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255204878912539}, + {2, + 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205024824427}, + {2, + 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205108938283}, + {2, + 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205168452667}, + {2, + 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205178336083}, + {2, + 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205194695203}, + {2, + 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205234987027}, + {2, + 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205249389907}, + {2, + 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205299503899}, + {2, + 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205303762219}, + {2, + 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205318419043}, + {2, + 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205369723267}, + {2, + 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205388065627}, + {2, + 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205483192027}, + {5, + 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255204867528103}, + {5, + 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255204958533343}, + {5, + 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205142917087}, + {5, + 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205164709807}, + {5, + 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205223494543}, + {5, + 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205238451607}, + {5, + 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205398650527}, + {5, + 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205534891927}, + {5, + 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205578782263}]}, + {8191, + [{2, + 938991641448887958659860711024139841840373070892857314837350127283993531354468803860225599873491818506054401963417489724433963777795696041544477412963807403300832656512849715212168703537706302853428971073305304224008208665300028518281475780493382070018498379488833882168221853720545474425047940975435356027594634176129712250061883354535324982741923143373986406603949677080360223989497048086447454366625852264609369284140522273595340921542019308988041920995057608746115976973659704188342646944998285431473302075966106608530908140377765357842459486869512398523240695806503711124427370056638597159539032058092571318621818616699716647464298881944582194013388150591419588422793657857267906072494480713650129757905856314362270238621284311461743652666256381611674809565144562467655186251867429369336740018623120262859220669942243740953355278814789244133782043857008487446798345197999966787658254507117076710455244182794239065255535191498857182705725985655379455993825553257619502588673174759329362518373537685585117537004065137523099625519490356398330532110250061129576411957409731201790054967354938147031111368166150009421041430118523249245874882140875551501824754839814848195806919150975076831338899823813371473496616326897054534509843640848822974414341233324307292275820287661792887177523563243279340678632061899626115667671047274195425889742755327012266774742591229119994211561599405909368902449776535330722644597809098307346948888547387746758109319767106289995123864514603259977184876246412673772519845777697496361969177346826245108557971745523905955370437517039028495325595180934057507336816903052766590118820327869839202378278312909402987412274414739124292902164277499512007446916921747463997761815820546816791093343347969046462095463611789365326128045878985464594892022442144072282717352526544915821855299863549245012366815543939396712522935345161074836470227392836664033041735035699615758782980717425699108612161567924880267630103820215946940542401779795959759774248414245436455737309858403883625882609790799283421857564831362243562647683958370353023343221966296655134926556805244483888769178095889844741765908328185625663202823312608064683035802724504683124396450612201783060593269112984065572954508643688374585823409316161924407053191442613988480926581084892323451281350937867676271858142177713557970909833234285545964647506859724327822527317869059455132036566677244407755994867168874825546516623190701762311472512591018622127119388239627852234680483324150442403}, + {2, + 938991641448887958659860711024139841840373070892857314837350127283993531354468803860225599873491818506054401963417489724433963777795696041544477412963807403300832656512849715212168703537706302853428971073305304224008208665300028518281475780493382070018498379488833882168221853720545474425047940975435356027594634176129712250061883354535324982741923143373986406603949677080360223989497048086447454366625852264609369284140522273595340921542019308988041920995057608746115976973659704188342646944998285431473302075966106608530908140377765357842459486869512398523240695806503711124427370056638597159539032058092571318621818616699716647464298881944582194013388150591419588422793657857267906072494480713650129757905856314362270238621284311461743652666256381611674809565144562467655186251867429369336740018623120262859220669942243740953355278814789244133782043857008487446798345197999966787658254507117076710455244182794239065255535191498857182705725985655379455993825553257619502588673174759329362518373537685585117537004065137523099625519490356398330532110250061129576411957409731201790054967354938147031111368166150009421041430118523249245874882140875551501824754839814848195806919150975076831338899823813371473496616326897054534509843640848822974414341233324307292275820287661792887177523563243279340678632061899626115667671047274195425889742755327012266774742591229119994211561599405909368902449776535330722644597809098307346948888547387746758109319767106289995123864514603259977184876246412673772519845777697496361969177346826245108557971745523905955370437517039028495325595180934057507336816903052766590118820327869839202378278312909402987412274414739124292902164277499512007446916921747463997761815820546816791093343347969046462095463611789365326128045878985464594892022442144072282717352526544915821855299863549245012366815543939396712522935345161074836470227392836664033041735035699615758782980717425699108612161567924880267630103820215946940542401779795959759774248414245436455737309858403883625882609790799283421857564831362243562647683958370353023343221966296655134926556805244483888769178095889844741765908328185625663202823312608064683035802724504683124396450612201783060593269112984065572954508643688374585823409316161924407053191442613988480926581084892323451281350937867676271858142177713557970909833234285545964647506859724327822527317869059455132036566677244407755994867168874825546516623190701762311472512591018622127119388239627852234680483324227808419}, + {5, + 938991641448887958659860711024139841840373070892857314837350127283993531354468803860225599873491818506054401963417489724433963777795696041544477412963807403300832656512849715212168703537706302853428971073305304224008208665300028518281475780493382070018498379488833882168221853720545474425047940975435356027594634176129712250061883354535324982741923143373986406603949677080360223989497048086447454366625852264609369284140522273595340921542019308988041920995057608746115976973659704188342646944998285431473302075966106608530908140377765357842459486869512398523240695806503711124427370056638597159539032058092571318621818616699716647464298881944582194013388150591419588422793657857267906072494480713650129757905856314362270238621284311461743652666256381611674809565144562467655186251867429369336740018623120262859220669942243740953355278814789244133782043857008487446798345197999966787658254507117076710455244182794239065255535191498857182705725985655379455993825553257619502588673174759329362518373537685585117537004065137523099625519490356398330532110250061129576411957409731201790054967354938147031111368166150009421041430118523249245874882140875551501824754839814848195806919150975076831338899823813371473496616326897054534509843640848822974414341233324307292275820287661792887177523563243279340678632061899626115667671047274195425889742755327012266774742591229119994211561599405909368902449776535330722644597809098307346948888547387746758109319767106289995123864514603259977184876246412673772519845777697496361969177346826245108557971745523905955370437517039028495325595180934057507336816903052766590118820327869839202378278312909402987412274414739124292902164277499512007446916921747463997761815820546816791093343347969046462095463611789365326128045878985464594892022442144072282717352526544915821855299863549245012366815543939396712522935345161074836470227392836664033041735035699615758782980717425699108612161567924880267630103820215946940542401779795959759774248414245436455737309858403883625882609790799283421857564831362243562647683958370353023343221966296655134926556805244483888769178095889844741765908328185625663202823312608064683035802724504683124396450612201783060593269112984065572954508643688374585823409316161924407053191442613988480926581084892323451281350937867676271858142177713557970909833234285545964647506859724327822527317869059455132036566677244407755994867168874825546516623190701762311472512591018622127119388239627852234680483324244759967}]}] + ). diff --git a/lib/public_key/src/pubkey_pem.erl b/lib/public_key/src/pubkey_pem.erl index 6a722b0525..d163004c7c 100644 --- a/lib/public_key/src/pubkey_pem.erl +++ b/lib/public_key/src/pubkey_pem.erl @@ -103,7 +103,7 @@ encode_pem_entry({'PrivateKeyInfo', Der, EncParams}) -> [StartStr, "\n", b64encode_and_split(EncDer), "\n", pem_end(StartStr) ,"\n\n"]; encode_pem_entry({Type, Der, {Cipher, Salt}}) -> StartStr = pem_start(Type), - [StartStr,"\n", pem_decrypt(),"\n", pem_decrypt_info(Cipher, Salt),"\n", + [StartStr,"\n", pem_decrypt(),"\n", pem_decrypt_info(Cipher, Salt),"\n\n", b64encode_and_split(Der), "\n", pem_end(StartStr) ,"\n\n"]. decode_pem_entries([], Entries) -> diff --git a/lib/public_key/src/pubkey_ssh.erl b/lib/public_key/src/pubkey_ssh.erl index 7680d0ce59..9b281aa482 100644 --- a/lib/public_key/src/pubkey_ssh.erl +++ b/lib/public_key/src/pubkey_ssh.erl @@ -20,10 +20,17 @@ -module(pubkey_ssh). -include("public_key.hrl"). +-include("pubkey_moduli.hrl"). --export([decode/2, encode/2]). + +-export([decode/2, encode/2, + dh_gex_group/4, + dh_gex_group_sizes/0 + ]). -define(UINT32(X), X:32/unsigned-big-integer). +-define(STRING(X), ?UINT32((size(X))), (X)/binary). + %% Max encoded line length is 72, but conformance examples use 68 %% Comment from rfc 4716: "The following are some examples of public %% key files that are compliant (note that the examples all wrap @@ -31,13 +38,16 @@ %% are still compliant.)" So we choose to use 68 also. -define(ENCODED_LINE_LENGTH, 68). + %%==================================================================== %% Internal application API %%==================================================================== %%-------------------------------------------------------------------- -spec decode(binary(), public_key | public_key:ssh_file()) -> - [{public_key:public_key(), Attributes::list()}]. + [{public_key:public_key(), Attributes::list()}] + ; (binary(), ssh2_pubkey) -> public_key:public_key() + . %% %% Description: Decodes a ssh file-binary. %%-------------------------------------------------------------------- @@ -50,21 +60,71 @@ decode(Bin, public_key)-> end; decode(Bin, rfc4716_public_key) -> rfc4716_decode(Bin); +decode(Bin, ssh2_pubkey) -> + ssh2_pubkey_decode(Bin); decode(Bin, Type) -> openssh_decode(Bin, Type). %%-------------------------------------------------------------------- -spec encode([{public_key:public_key(), Attributes::list()}], public_key:ssh_file()) -> - binary(). + binary() + ; (public_key:public_key(), ssh2_pubkey) -> binary() + . %% %% Description: Encodes a list of ssh file entries. %%-------------------------------------------------------------------- +encode(Bin, ssh2_pubkey) -> + ssh2_pubkey_encode(Bin); encode(Entries, Type) -> iolist_to_binary(lists:map(fun({Key, Attributes}) -> do_encode(Type, Key, Attributes) end, Entries)). %%-------------------------------------------------------------------- +-spec dh_gex_group(integer(), integer(), integer(), + undefined | [{integer(),[{integer(),integer()}]}]) -> + {ok,{integer(),{integer(),integer()}}} | {error,any()} . +%% +%% Description: Returns Generator and Modulus given MinSize, WantedSize +%% and MaxSize +%%-------------------------------------------------------------------- +dh_gex_group(Min, N, Max, undefined) -> + dh_gex_group(Min, N, Max, ?dh_default_groups); +dh_gex_group(Min, N, Max, Groups) -> + case select_by_keylen(Min-10, N, Max+10, Groups) of + {ok,{Sz,GPs}} -> + {ok, {Sz,lists:nth(crypto:rand_uniform(1, 1+length(GPs)), GPs)}}; + Other -> + Other + end. + +dh_gex_group_sizes()-> + [KeyLen || {KeyLen,_} <- ?dh_default_groups]. + +%% Select the one with K closest to N but within the interval [Min,Max] + +select_by_keylen(Min, N, Max, [{K,_Gs}|Groups]) when K < Min -> + select_by_keylen(Min, N, Max, Groups); +select_by_keylen(Min, N, Max, [{K,Gs}|Groups]) when K =< Max -> + {ok, select_by_keylen(Min, N, Max, Groups, {K,Gs})}; +select_by_keylen(_Min, _N, _Max, _) -> + {error,no_group_found}. + +select_by_keylen(_Min, _N, Max, [{K,_Gs}|_Groups], GPprev) when K > Max -> + GPprev; +select_by_keylen(Min, N, Max, [{K,Gs}|Groups], {Kprev,GsPrev}) -> + if + N == K -> {K,Gs}; + N > K -> select_by_keylen(Min, N, Max, Groups, {K,Gs}); + N < K, (K-N) < (N-Kprev) -> {K,Gs}; + N < K -> {Kprev,GsPrev} + end; +select_by_keylen(_Min, _N, _Max, [],GPprev) -> + %% is between Min and Max + GPprev. + + +%%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- begin_marker() -> @@ -130,7 +190,12 @@ rfc4716_pubkey_decode(<<?UINT32(Len), Type:Len/binary, {erlint(SizeY, Y), #'Dss-Parms'{p = erlint(SizeP, P), q = erlint(SizeQ, Q), - g = erlint(SizeG, G)}}. + g = erlint(SizeG, G)}}; +rfc4716_pubkey_decode(<<?UINT32(Len), ECDSA_SHA2_etc:Len/binary, + ?UINT32(SizeId), Id:SizeId/binary, + ?UINT32(SizeQ), Q:SizeQ/binary>>) -> + <<"ecdsa-sha2-", Id/binary>> = ECDSA_SHA2_etc, + {#'ECPoint'{point = Q}, {namedCurve,public_key:ssh_curvename2oid(Id)}}. openssh_decode(Bin, FileType) -> Lines = binary:split(Bin, <<"\n">>, [global]), @@ -184,46 +249,42 @@ do_openssh_decode(known_hosts = FileType, [Line | Lines], Acc) -> end; do_openssh_decode(openssh_public_key = FileType, [Line | Lines], Acc) -> - case split_n(2, Line, []) of - [KeyType, Base64Enc] when KeyType == <<"ssh-rsa">>; - KeyType == <<"ssh-dss">> -> + [KeyType, Base64Enc | Comment0] = split_n(2, Line, []), + KnownKeyType = + case KeyType of + <<"ssh-rsa">> -> true; + <<"ssh-dss">> -> true; + <<"ecdsa-sha2-",Curve/binary>> -> is_ssh_curvename(Curve); + _ -> false + end, + + case Comment0 of + [] when KnownKeyType==true -> do_openssh_decode(FileType, Lines, [{openssh_pubkey_decode(KeyType, Base64Enc), []} | Acc]); - [KeyType, Base64Enc | Comment0] when KeyType == <<"ssh-rsa">>; - KeyType == <<"ssh-dss">> -> + _ when KnownKeyType==true -> Comment = string:strip(string_decode(iolist_to_binary(Comment0)), right, $\n), do_openssh_decode(FileType, Lines, [{openssh_pubkey_decode(KeyType, Base64Enc), [{comment, Comment}]} | Acc]) end. + decode_comment([]) -> []; decode_comment(Comment) -> [{comment, string_decode(iolist_to_binary(Comment))}]. -openssh_pubkey_decode(<<"ssh-rsa">>, Base64Enc) -> - <<?UINT32(StrLen), _:StrLen/binary, - ?UINT32(SizeE), E:SizeE/binary, - ?UINT32(SizeN), N:SizeN/binary>> - = base64:mime_decode(Base64Enc), - #'RSAPublicKey'{modulus = erlint(SizeN, N), - publicExponent = erlint(SizeE, E)}; -openssh_pubkey_decode(<<"ssh-dss">>, Base64Enc) -> - <<?UINT32(StrLen), _:StrLen/binary, - ?UINT32(SizeP), P:SizeP/binary, - ?UINT32(SizeQ), Q:SizeQ/binary, - ?UINT32(SizeG), G:SizeG/binary, - ?UINT32(SizeY), Y:SizeY/binary>> - = base64:mime_decode(Base64Enc), - {erlint(SizeY, Y), - #'Dss-Parms'{p = erlint(SizeP, P), - q = erlint(SizeQ, Q), - g = erlint(SizeG, G)}}; -openssh_pubkey_decode(KeyType, Base64Enc) -> - {KeyType, base64:mime_decode(Base64Enc)}. +openssh_pubkey_decode(Type, Base64Enc) -> + try + ssh2_pubkey_decode(Type, base64:mime_decode(Base64Enc)) + catch + _:_ -> + {Type, base64:mime_decode(Base64Enc)} + end. + erlint(MPIntSize, MPIntValue) -> Bits= MPIntSize * 8, @@ -347,10 +408,9 @@ line_end("") -> line_end(Comment) -> [" ", Comment, "\n"]. -key_type(#'RSAPublicKey'{}) -> - <<"ssh-rsa">>; -key_type({_, #'Dss-Parms'{}}) -> - <<"ssh-dss">>. +key_type(#'RSAPublicKey'{}) -> <<"ssh-rsa">>; +key_type({_, #'Dss-Parms'{}}) -> <<"ssh-dss">>; +key_type({#'ECPoint'{}, {namedCurve,Curve}}) -> <<"ecdsa-sha2-", (public_key:oid2ssh_curvename(Curve))/binary>>. comma_list_encode([Option], []) -> Option; @@ -380,20 +440,49 @@ ssh2_pubkey_encode({Y, #'Dss-Parms'{p = P, q = Q, g = G}}) -> PBin/binary, QBin/binary, GBin/binary, - YBin/binary>>. - -is_key_field(<<"ssh-dss">>) -> - true; -is_key_field(<<"ssh-rsa">>) -> - true; -is_key_field(<<"ecdsa-sha2-nistp256">>) -> - true; -is_key_field(<<"ecdsa-sha2-nistp384">>) -> - true; -is_key_field(<<"ecdsa-sha2-nistp521">>) -> - true; -is_key_field(_) -> - false. + YBin/binary>>; +ssh2_pubkey_encode(Key={#'ECPoint'{point = Q}, {namedCurve,OID}}) -> + TypeStr = key_type(Key), + StrLen = size(TypeStr), + IdB = public_key:oid2ssh_curvename(OID), + <<?UINT32(StrLen), TypeStr:StrLen/binary, + (string(IdB))/binary, + (string(Q))/binary>>. + + +ssh2_pubkey_decode(Bin = <<?UINT32(Len), Type:Len/binary, _/binary>>) -> + ssh2_pubkey_decode(Type, Bin). + +ssh2_pubkey_decode(<<"ssh-rsa">>, + <<?UINT32(Len), _:Len/binary, + ?UINT32(SizeE), E:SizeE/binary, + ?UINT32(SizeN), N:SizeN/binary>>) -> + #'RSAPublicKey'{modulus = erlint(SizeN, N), + publicExponent = erlint(SizeE, E)}; + +ssh2_pubkey_decode(<<"ssh-dss">>, + <<?UINT32(Len), _:Len/binary, + ?UINT32(SizeP), P:SizeP/binary, + ?UINT32(SizeQ), Q:SizeQ/binary, + ?UINT32(SizeG), G:SizeG/binary, + ?UINT32(SizeY), Y:SizeY/binary>>) -> + {erlint(SizeY, Y), + #'Dss-Parms'{p = erlint(SizeP, P), + q = erlint(SizeQ, Q), + g = erlint(SizeG, G)}}; +ssh2_pubkey_decode(<<"ecdsa-sha2-",Id/binary>>, + <<?UINT32(Len), ECDSA_SHA2_etc:Len/binary, + ?UINT32(SizeId), Id:SizeId/binary, + ?UINT32(SizeQ), Q:SizeQ/binary>>) -> + <<"ecdsa-sha2-", Id/binary>> = ECDSA_SHA2_etc, + {#'ECPoint'{point = Q}, {namedCurve,public_key:ssh_curvename2oid(Id)}}. + + + +is_key_field(<<"ssh-dss">>) -> true; +is_key_field(<<"ssh-rsa">>) -> true; +is_key_field(<<"ecdsa-sha2-",Id/binary>>) -> is_ssh_curvename(Id); +is_key_field(_) -> false. is_bits_field(Part) -> try list_to_integer(binary_to_list(Part)) of @@ -507,3 +596,14 @@ int_to_bin_neg(-1, Ds=[MSB|_]) when MSB >= 16#80 -> list_to_binary(Ds); int_to_bin_neg(X,Ds) -> int_to_bin_neg(X bsr 8, [(X band 255)|Ds]). + + +string(X) when is_binary(X) -> + << ?STRING(X) >>; +string(X) -> + << ?STRING(list_to_binary(X)) >>. + +is_ssh_curvename(Id) -> try public_key:ssh_curvename2oid(Id) of _ -> true + catch _:_ -> false + end. + diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index 2f4cc64c2a..a79badef24 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -35,6 +35,8 @@ decrypt_private/2, decrypt_private/3, encrypt_public/2, encrypt_public/3, decrypt_public/2, decrypt_public/3, + dh_gex_group/4, + dh_gex_group_sizes/0, sign/3, verify/4, generate_key/1, compute_key/2, compute_key/3, @@ -47,6 +49,7 @@ pkix_normalize_name/1, pkix_path_validation/3, ssh_decode/2, ssh_encode/2, + ssh_curvename2oid/1, oid2ssh_curvename/1, pkix_crls_validate/3, pkix_dist_point/1, pkix_dist_points/1, @@ -372,6 +375,13 @@ encrypt_private(PlainText, crypto:private_encrypt(rsa, PlainText, format_rsa_private_key(Key), Padding). %%-------------------------------------------------------------------- +dh_gex_group_sizes() -> + pubkey_ssh:dh_gex_group_sizes(). + +dh_gex_group(Min, N, Max, Groups) -> + pubkey_ssh:dh_gex_group(Min, N, Max, Groups). + +%%-------------------------------------------------------------------- -spec generate_key(#'DHParameter'{} | {namedCurve, Name ::oid()} | #'ECParameters'{}) -> {Public::binary(), Private::binary()} | #'ECPrivateKey'{}. @@ -711,7 +721,9 @@ pkix_crls_validate(OtpCert, DPAndCRLs0, Options) -> %%-------------------------------------------------------------------- --spec ssh_decode(binary(), public_key | ssh_file()) -> [{public_key(), Attributes::list()}]. +-spec ssh_decode(binary(), public_key | ssh_file()) -> [{public_key(), Attributes::list()}] + ; (binary(), ssh2_pubkey) -> public_key() + . %% %% Description: Decodes a ssh file-binary. In the case of know_hosts %% or auth_keys the binary may include one or more lines of the @@ -724,12 +736,15 @@ ssh_decode(SshBin, Type) when is_binary(SshBin), Type == rfc4716_public_key; Type == openssh_public_key; Type == auth_keys; - Type == known_hosts -> + Type == known_hosts; + Type == ssh2_pubkey -> pubkey_ssh:decode(SshBin, Type). %%-------------------------------------------------------------------- --spec ssh_encode([{public_key(), Attributes::list()}], ssh_file()) -> - binary(). +-spec ssh_encode([{public_key(), Attributes::list()}], ssh_file()) -> binary() + ; (public_key(), ssh2_pubkey) -> binary() + . +%% %% Description: Encodes a list of ssh file entries (public keys and %% attributes) to a binary. Possible attributes depends on the file %% type. @@ -738,10 +753,30 @@ ssh_encode(Entries, Type) when is_list(Entries), Type == rfc4716_public_key; Type == openssh_public_key; Type == auth_keys; - Type == known_hosts -> + Type == known_hosts; + Type == ssh2_pubkey -> pubkey_ssh:encode(Entries, Type). %%-------------------------------------------------------------------- +-spec ssh_curvename2oid(binary()) -> oid(). + +%% Description: Converts from the ssh name of elliptic curves to +%% the OIDs. +%%-------------------------------------------------------------------- +ssh_curvename2oid(<<"nistp256">>) -> ?'secp256r1'; +ssh_curvename2oid(<<"nistp384">>) -> ?'secp384r1'; +ssh_curvename2oid(<<"nistp521">>) -> ?'secp521r1'. + +%%-------------------------------------------------------------------- +-spec oid2ssh_curvename(oid()) -> binary(). + +%% Description: Converts from elliptic curve OIDs to the ssh name. +%%-------------------------------------------------------------------- +oid2ssh_curvename(?'secp256r1') -> <<"nistp256">>; +oid2ssh_curvename(?'secp384r1') -> <<"nistp384">>; +oid2ssh_curvename(?'secp521r1') -> <<"nistp521">>. + +%%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- do_verify(DigestOrPlainText, DigestType, Signature, diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl index 6f142c951c..ea5e036a7e 100644 --- a/lib/public_key/test/public_key_SUITE.erl +++ b/lib/public_key/test/public_key_SUITE.erl @@ -49,8 +49,10 @@ groups() -> [{pem_decode_encode, [], [dsa_pem, rsa_pem, encrypted_pem, dh_pem, cert_pem, pkcs7_pem, pkcs10_pem]}, {ssh_public_key_decode_encode, [], - [ssh_rsa_public_key, ssh_dsa_public_key, ssh_rfc4716_rsa_comment, - ssh_rfc4716_dsa_comment, ssh_rfc4716_rsa_subject, ssh_known_hosts, + [ssh_rsa_public_key, ssh_dsa_public_key, ssh_ecdsa_public_key, + ssh_rfc4716_rsa_comment, ssh_rfc4716_dsa_comment, + ssh_rfc4716_rsa_subject, + ssh_known_hosts, ssh_auth_keys, ssh1_known_hosts, ssh1_auth_keys, ssh_openssh_public_key_with_comment, ssh_openssh_public_key_long_header]}, {sign_verify, [], [rsa_sign_verify, dsa_sign_verify]} @@ -187,6 +189,8 @@ encrypted_pem(Config) when is_list(Config) -> erl_make_certs:der_to_pem(DesKeyFile, [Entry1]), [{'RSAPrivateKey', _, {"DES-CBC", Salt1}} =Entry2] = erl_make_certs:pem_to_der(DesKeyFile), + {ok, Pem} = file:read_file(DesKeyFile), + check_encapsulated_header(Pem), true = check_entry_type(public_key:pem_entry_decode(Entry2, "4567efgh"), 'RSAPrivateKey'). @@ -291,6 +295,32 @@ ssh_dsa_public_key(Config) when is_list(Config) -> public_key:ssh_decode(EncodedOpenSsh, public_key). %%-------------------------------------------------------------------- + +ssh_ecdsa_public_key() -> + [{doc, "ssh ecdsa public key decode/encode"}]. +ssh_ecdsa_public_key(Config) when is_list(Config) -> + Datadir = ?config(data_dir, Config), + + {ok, ECDSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_ecdsa_pub")), + [{PubKey, Attributes1}] = public_key:ssh_decode(ECDSARawSsh2, public_key), + [{PubKey, Attributes1}] = public_key:ssh_decode(ECDSARawSsh2, rfc4716_public_key), + + {ok, ECDSARawOpenSsh} = file:read_file(filename:join(Datadir, "openssh_ecdsa_pub")), + [{PubKey, Attributes2}] = public_key:ssh_decode(ECDSARawOpenSsh, public_key), + [{PubKey, Attributes2}] = public_key:ssh_decode(ECDSARawOpenSsh, openssh_public_key), + + %% Can not check EncodedSSh == ECDSARawSsh2 and EncodedOpenSsh + %% = ECDSARawOpenSsh as line breakpoints may differ + + EncodedSSh = public_key:ssh_encode([{PubKey, Attributes1}], rfc4716_public_key), + EncodedOpenSsh = public_key:ssh_encode([{PubKey, Attributes2}], openssh_public_key), + + [{PubKey, Attributes1}] = + public_key:ssh_decode(EncodedSSh, public_key), + [{PubKey, Attributes2}] = + public_key:ssh_decode(EncodedOpenSsh, public_key). + +%%-------------------------------------------------------------------- ssh_rfc4716_rsa_comment() -> [{doc, "Test comment header and rsa key"}]. ssh_rfc4716_rsa_comment(Config) when is_list(Config) -> @@ -798,6 +828,15 @@ check_entry_type(#'Certificate'{}, 'Certificate') -> check_entry_type(_,_) -> false. +check_encapsulated_header(Pem) when is_binary(Pem)-> + check_encapsulated_header( binary:split(Pem, <<"\n">>, [global])); +check_encapsulated_header([<<"DEK-Info: DES-CBC,FB7577791A9056A1">>, <<>> | _]) -> + true; +check_encapsulated_header([ _ | Rest]) -> + check_encapsulated_header(Rest); +check_encapsulated_header([]) -> + false. + strip_ending_newlines(Bin) -> string:strip(binary_to_list(Bin), right, 10). diff --git a/lib/public_key/test/public_key_SUITE_data/openssh_ecdsa_pub b/lib/public_key/test/public_key_SUITE_data/openssh_ecdsa_pub new file mode 100644 index 0000000000..a49b4264b8 --- /dev/null +++ b/lib/public_key/test/public_key_SUITE_data/openssh_ecdsa_pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBIJrVlKYIT+MlxxRx5BFXisHHkcGMAAKv2dguUeOsutsYyzs9JAczvl6c+Sypra5+qOi2LHPXw6GGluuXcOssOM= uabhnil@elxadlj3q32 diff --git a/lib/public_key/test/public_key_SUITE_data/ssh2_ecdsa_pub b/lib/public_key/test/public_key_SUITE_data/ssh2_ecdsa_pub new file mode 100644 index 0000000000..702e5c4fde --- /dev/null +++ b/lib/public_key/test/public_key_SUITE_data/ssh2_ecdsa_pub @@ -0,0 +1,6 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +Comment: "256-bit ECDSA, converted by uabhnil@elxadlj3q32 from OpenSSH" +AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBIJrVlKYIT+MlxxRx5 +BFXisHHkcGMAAKv2dguUeOsutsYyzs9JAczvl6c+Sypra5+qOi2LHPXw6GGluuXcOssOM= + +---- END SSH2 PUBLIC KEY ---- diff --git a/lib/public_key/vsn.mk b/lib/public_key/vsn.mk index 7f752529f0..f801f55073 100644 --- a/lib/public_key/vsn.mk +++ b/lib/public_key/vsn.mk @@ -1 +1 @@ -PUBLIC_KEY_VSN = 1.0 +PUBLIC_KEY_VSN = 1.1.1 diff --git a/lib/runtime_tools/c_src/trace_file_drv.c b/lib/runtime_tools/c_src/trace_file_drv.c index 7549161e05..8863b0d6ac 100644 --- a/lib/runtime_tools/c_src/trace_file_drv.c +++ b/lib/runtime_tools/c_src/trace_file_drv.c @@ -75,12 +75,8 @@ #ifdef DEBUG -#ifndef __WIN32__ -#define ASSERT(X) do {if (!(X)) {erl_exit(1,"%s",#X);} } while(0) -#else #include <assert.h> #define ASSERT(X) assert(X) -#endif #else #define ASSERT(X) #endif @@ -327,9 +323,11 @@ static ErlDrvData trace_file_start(ErlDrvPort port, char *buff) | O_BINARY #endif , 0777)) < 0) { + int saved_errno = errno; if (wrap) driver_free(wrap); driver_free(data); + errno = saved_errno; return ERL_DRV_ERROR_ERRNO; } @@ -525,14 +523,19 @@ static void *my_alloc(size_t size) ** A write wrapper that regards it as an error if not all data was written. */ static int do_write(FILETYPE fd, unsigned char *buff, int siz) { - int w = write(fd, buff, siz); - if (w != siz) { - if (w >= 0) { - errno = ENOSPC; + int w; + while (1) { + w = write(fd, buff, siz); + if (w < 0 && errno == EINTR) + continue; + else if (w != siz) { + if (w >= 0) { + errno = ENOSPC; + } + return -1; } - return -1; + return siz; } - return siz; } /* @@ -627,8 +630,10 @@ static void close_unlink_port(TraceFileData *data) */ static int wrap_file(TraceFileData *data) { if (my_flush(data) < 0) { + int saved_errno = errno; close(data->fd); data->fd = -1; + errno = saved_errno; return -1; } close(data->fd); @@ -644,12 +649,15 @@ static int wrap_file(TraceFileData *data) { next_name(&data->wrap->del); } next_name(&data->wrap->cur); +try_open: data->fd = open(data->wrap->cur.name, O_WRONLY | O_TRUNC | O_CREAT #ifdef O_BINARY | O_BINARY #endif , 0777); if (data->fd < 0) { + if (errno == EINTR) + goto try_open; data->fd = -1; return -1; } diff --git a/lib/runtime_tools/c_src/trace_ip_drv.c b/lib/runtime_tools/c_src/trace_ip_drv.c index f7b5ea65cb..5b43f8179e 100644 --- a/lib/runtime_tools/c_src/trace_ip_drv.c +++ b/lib/runtime_tools/c_src/trace_ip_drv.c @@ -44,19 +44,8 @@ #endif #ifdef DEBUG -# ifndef __WIN32__ - /* erl_exit is not available to dll_drivers on windows. */ - void erl_exit(int, char *, ...); -# define ASSERT(X) \ - do { \ - if (!(X)) { \ - erl_exit(1,"%s",#X); \ - } \ - } while(0) -# else -# include <assert.h> -# define ASSERT(X) assert(X) -# endif +# include <assert.h> +# define ASSERT(X) assert(X) #else # define ASSERT(X) #endif diff --git a/lib/runtime_tools/doc/src/dbg.xml b/lib/runtime_tools/doc/src/dbg.xml index 1a11806211..2065627026 100644 --- a/lib/runtime_tools/doc/src/dbg.xml +++ b/lib/runtime_tools/doc/src/dbg.xml @@ -1030,9 +1030,9 @@ hello</pre> <fsummary>Stop the <c>dbg</c>server and the tracing of all processes.</fsummary> <desc> <p>Stops the <c>dbg</c> server and clears all trace flags for - all processes and all trace patterns for all functions. Also + all processes and all local trace patterns for all functions. Also shuts down all trace clients and closes all trace ports.</p> - <p>Note that no trace patterns are affected by this + <p>Note that no global trace patterns are affected by this function.</p> </desc> </func> @@ -1040,8 +1040,7 @@ hello</pre> <name>stop_clear() -> ok</name> <fsummary>Stop the <c>dbg</c>server and the tracing of all processes, and clears trace patterns.</fsummary> <desc> - <p>Same as stop/0, but also clears all trace patterns on local - and global functions calls.</p> + <p>Same as stop/0, but also clears all trace patterns on global functions calls.</p> </desc> </func> </funcs> diff --git a/lib/runtime_tools/doc/src/notes.xml b/lib/runtime_tools/doc/src/notes.xml index 71b244ec6b..24b589b928 100644 --- a/lib/runtime_tools/doc/src/notes.xml +++ b/lib/runtime_tools/doc/src/notes.xml @@ -32,6 +32,53 @@ <p>This document describes the changes made to the Runtime_Tools application.</p> +<section><title>Runtime_Tools 1.9.3</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p><c>dbg:trace_client()</c> now uses a read buffer to + speed up reading of trace files.</p> + <p> + Own Id: OTP-13279</p> + </item> + </list> + </section> + +</section> + +<section><title>Runtime_Tools 1.9.2</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Clarified dbg:stop documentation</p> + <p> + Own Id: OTP-13078</p> + </item> + </list> + </section> + +</section> + +<section><title>Runtime_Tools 1.9.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The <c>trace_file_drv</c> did not handle <c>EINTR</c> + correct which caused it to fail when the runtime system + received a signal.</p> + <p> + Own Id: OTP-12890 Aux Id: seq12885 </p> + </item> + </list> + </section> + +</section> + <section><title>Runtime_Tools 1.9</title> <section><title>Improvements and New Features</title> diff --git a/lib/runtime_tools/src/dbg.erl b/lib/runtime_tools/src/dbg.erl index d2a7d734c1..6eea1a0917 100644 --- a/lib/runtime_tools/src/dbg.erl +++ b/lib/runtime_tools/src/dbg.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -1269,13 +1269,15 @@ gen_reader(follow_file, Filename) -> %% Opens a file and returns a reader (lazy list). gen_reader_file(ReadFun, Filename) -> - case file:open(Filename, [read, raw, binary]) of + case file:open(Filename, [read, raw, binary, read_ahead]) of {ok, File} -> mk_reader(ReadFun, File); Error -> exit({client_cannot_open, Error}) end. +-dialyzer({no_improper_lists, mk_reader/2}). + %% Creates and returns a reader (lazy list). mk_reader(ReadFun, Source) -> fun() -> @@ -1294,13 +1296,15 @@ mk_reader(ReadFun, Source) -> mk_reader_wrap([]) -> []; mk_reader_wrap([Hd | _] = WrapFiles) -> - case file:open(wrap_name(Hd), [read, raw, binary]) of + case file:open(wrap_name(Hd), [read, raw, binary, read_ahead]) of {ok, File} -> mk_reader_wrap(WrapFiles, File); Error -> exit({client_cannot_open, Error}) end. +-dialyzer({no_improper_lists, mk_reader_wrap/2}). + mk_reader_wrap([_Hd | Tail] = WrapFiles, File) -> fun() -> case read_term(fun file_read/2, File) of diff --git a/lib/runtime_tools/vsn.mk b/lib/runtime_tools/vsn.mk index 3aadc46ab6..bfc8b84b91 100644 --- a/lib/runtime_tools/vsn.mk +++ b/lib/runtime_tools/vsn.mk @@ -1 +1 @@ -RUNTIME_TOOLS_VSN = 1.9 +RUNTIME_TOOLS_VSN = 1.9.3 diff --git a/lib/sasl/doc/src/alarm_handler.xml b/lib/sasl/doc/src/alarm_handler.xml index b98f22d2a1..68076ba28d 100644 --- a/lib/sasl/doc/src/alarm_handler.xml +++ b/lib/sasl/doc/src/alarm_handler.xml @@ -37,94 +37,92 @@ <module>alarm_handler</module> <modulesummary>An Alarm Handling Process</modulesummary> <description> - <p>The alarm handler process is a <c>gen_event</c> event manager - process which receives alarms in the system. This process is not - intended to be a complete alarm handler. It defines a - place to which alarms can be sent. One simple event handler is - installed in the alarm handler at start-up, but users are - encouraged to write and install their own handlers. - </p> + <p>The alarm handler process is a + <seealso marker="stdlib:gen_event"><c>gen_event</c></seealso> + event manager process that receives alarms in the system. + This process is not intended to be a complete alarm handler. + It defines a place to which alarms can be sent. One simple event + handler is installed in the alarm handler at startup, but users + are encouraged to write and install their own handlers.</p> <p>The simple event handler sends all alarms as info reports to - the error logger, and saves all of them in a list which can be - passed to a user defined event handler, which may be installed at - a later stage. The list can grow large if many alarms are - generated. So it is a good reason to install a better user defined - handler. - </p> - <p>There are functions to set and clear alarms. The format of - alarms are defined by the user. For example, an event handler - for SNMP could be defined, together with an alarm MIB. - </p> - <p>The alarm handler is part of the SASL application. - </p> + the error logger, and saves all in a list. This list can be + passed to a user-defined event handler, which can be installed + later. The list can grow large if many alarms are generated. + This is a good reason to install a better user-defined + handler.</p> + <p>Functions are provided to set and clear alarms. The alarm + format is defined by the user. For example, an event handler + for SNMP can be defined, together with an alarm Management + Information Base (MIB).</p> + <p>The alarm handler is part of the <c>SASL</c> application.</p> <p>When writing new event handlers for the alarm handler, the - following events must be handled: - </p> + following events must be handled:</p> <taglist> <tag><c>{set_alarm, {AlarmId, AlarmDescr}}</c></tag> <item> <p>This event is generated by - <c>alarm_handler:set_alarm({AlarmId, AlarmDecsr})</c>. - </p> + <c>alarm_handler:set_alarm({AlarmId, AlarmDecsr})</c>.</p> </item> <tag><c>{clear_alarm, AlarmId}</c></tag> <item> <p>This event is - generated by <c>alarm_handler:clear_alarm(AlarmId)</c>. - </p> + generated by <c>alarm_handler:clear_alarm(AlarmId)</c>.</p> </item> </taglist> <p>The default simple handler is called <c>alarm_handler</c> and - it may be exchanged by calling <c>gen_event:swap_handler/3</c> - as <c>gen_event:swap_handler(alarm_handler, {alarm_handler, swap}, {NewHandler, Args})</c>. <c>NewHandler:init({Args, {alarm_handler, Alarms}})</c> is called. Refer to gen_event(3) - for further details. - </p> + it can be exchanged by calling + <seealso marker="stdlib:gen_event#swap_handler/3"><c>gen_event:swap_handler/3</c></seealso> + as <c>gen_event:swap_handler(alarm_handler, {alarm_handler, swap}, + {NewHandler, Args})</c>. <c>NewHandler:init({Args, {alarm_handler, + Alarms}})</c> is called. For more details, see + <seealso marker="stdlib:gen_event"><c>gen_event(3)</c></seealso> + in <c>STDLIB</c>.</p> </description> + <funcs> <func> <name>clear_alarm(AlarmId) -> void()</name> - <fsummary>Clear the specified alarms</fsummary> + <fsummary>Clears the specified alarms.</fsummary> <type> <v>AlarmId = term()</v> </type> <desc> - <p>Sends the <c>clear_alarm</c> event to all event handlers.</p> + <p>Sends event <c>clear_alarm</c> to all event handlers.</p> <p>When receiving this event, the default simple handler - clears the latest received alarm with id <c>AlarmId</c>. - </p> + clears the latest received alarm with id <c>AlarmId</c>.</p> </desc> </func> + <func> <name>get_alarms() -> [alarm()]</name> - <fsummary>Get all active alarms</fsummary> + <fsummary>Gets all active alarms.</fsummary> <desc> <p>Returns a list of all active alarms. This function can only - be used when the simple handler is installed. - </p> + be used when the simple handler is installed.</p> </desc> </func> + <func> <name>set_alarm(alarm())</name> - <fsummary>Set an alarm with an id</fsummary> + <fsummary>Sets an alarm with an id.</fsummary> <type> <v>alarm() = {AlarmId, AlarmDescription}</v> <v>AlarmId = term()</v> <v>AlarmDescription = term()</v> </type> <desc> - <p>Sends the <c>set_alarm</c> event to all event handlers.</p> + <p>Sends event <c>set_alarm</c> to all event handlers.</p> <p>When receiving this event, the default simple handler - stores the alarm. The <c>AlarmId</c> identifies the alarm - and is used when the alarm is cleared. - </p> + stores the alarm. <c>AlarmId</c> identifies the alarm + and is used when the alarm is cleared.</p> </desc> </func> </funcs> <section> <title>See Also</title> - <p>error_logger(3), gen_event(3) - </p> + <p><seealso marker="kernel:error_logger"><c>error_logger(3)</c></seealso>, + <seealso marker="stdlib:gen_event"><c>gen_event(3)</c></seealso></p> </section> </erlref> diff --git a/lib/sasl/doc/src/appup.xml b/lib/sasl/doc/src/appup.xml index 72333960ec..b54d2adb19 100644 --- a/lib/sasl/doc/src/appup.xml +++ b/lib/sasl/doc/src/appup.xml @@ -29,78 +29,85 @@ <rev></rev> </header> <file>appup</file> - <filesummary>Application upgrade file.</filesummary> + <filesummary>Application upgrade file</filesummary> <description> <p>The <em>application upgrade file</em> defines how an application is upgraded or downgraded in a running system.</p> - <p>This file is used by the functions in <c>systools</c> when - generating a release upgrade file <c>relup</c>.</p> + <p>This file is used by the functions in + <seealso marker="systools"><c>systools</c></seealso> + when generating a release upgrade file <c>relup</c>.</p> </description> <section> - <title>FILE SYNTAX</title> - <p>The application upgrade file should be called - <c>Application.appup</c> where <c>Application</c> is the name of - the application. The file should be located in the <c>ebin</c> + <title>File Syntax</title> + <p>The application upgrade file is to be called + <c>Application.appup</c>, where <c>Application</c> is the + application name. The file is to be located in the <c>ebin</c> directory for the application.</p> <p>The <c>.appup</c> file contains one single Erlang term, which defines the instructions used to upgrade or downgrade - the application. The file has the following syntax:</p> + the application. The file has the following syntax:</p> <code type="none"> {Vsn, [{UpFromVsn, Instructions}, ...], - [{DownToVsn, Instructions}, ...]}. - </code> - <list type="bulleted"> - <item> - <p><c>Vsn = string()</c> is the current version of - the application.</p> - </item> - <item> - <p><c>UpFromVsn = string() | binary()</c> is an earlier - version of the application to upgrade from. If it is a - string, it will be interpreted as a specific version - number. If it is a binary, it will be interpreted as a - regular expression which can match multiple version - numbers.</p> - </item> - <item> - <p><c>DownToVsn = string() | binary()</c> is an earlier - version of the application to downgrade to. If it is a - string, it will be interpreted as a specific version - number. If it is a binary, it will be interpreted as a - regular expression which can match multiple version - numbers.</p> - </item> - <item> - <p><c>Instructions</c> is a list of <em>release upgrade instructions</em>, see below. It is recommended to use + [{DownToVsn, Instructions}, ...]}.</code> + <taglist> + <tag><c>Vsn = string()</c></tag> + <item><p>Current application version.</p></item> + <tag><c>UpFromVsn = string() | binary()</c></tag> + <item><p>An earlier + application version to upgrade from. If it is a + string, it is interpreted as a specific version + number. If it is a binary, it is interpreted as a + regular expression that can match multiple version + numbers.</p></item> + <tag><c>DownToVsn = string() | binary()</c></tag> + <item><p>An earlier + application version to downgrade to. If it is a + string, it is interpreted as a specific version + number. If it is a binary, it is interpreted as a + regular expression that can match multiple version + numbers.</p></item> + <tag><c>Instructions</c></tag> + <item><p>A list of <em>release upgrade instructions</em>, see + <seealso marker="#Release Upgrade Instructions">Release + Upgrade Instructions</seealso>. It is recommended to use high-level instructions only. These are automatically translated to low-level instructions by <c>systools</c> when - creating the <c>relup</c> file.</p> - </item> - </list> - <p>In order to avoid duplication of upgrade instructions it is - allowed to use regular expressions to specify the <c>UpFromVsn</c> - and <c>DownToVsn</c>. To be considered a regular expression, the - version identifier must be specified as a binary, e.g.</p> - <code type="none"><<"2\\.1\\.[0-9]+">></code> - <p>will match all versions <c>2.1.x</c>, where x is any number.</p> - <p>Note that the regular expression must match the complete - version string, so the above example will work for for - e.g. <c>2.1.1</c>, but not for <c>2.1.1.1</c></p> + creating the <c>relup</c> file.</p></item> + </taglist> + <p>To avoid duplication of upgrade instructions, it is + allowed to use regular expressions to specify <c>UpFromVsn</c> + and <c>DownToVsn</c>. To be considered a regular expression, the + version identifier must be specified as a binary. For example, + the following match all versions <c>2.1.x</c>, where <c>x</c> is + any number:</p> + <code type="none"> +<<"2\\.1\\.[0-9]+">></code> + <p>Notice that the regular expression must match the complete + version string, so this example works for, for example, + <c>2.1.1</c>, but not for <c>2.1.1.1</c>.</p> </section> <section> - <title>RELEASE UPGRADE INSTRUCTIONS</title> + <marker id="Release Upgrade Instructions"></marker> + <title>Release Upgrade Instructions</title> <p>Release upgrade instructions are interpreted by the release handler when an upgrade or downgrade is made. For more - information about release handling, refer to <em>OTP Design Principles</em>.</p> - <p>A process is said to <em>use</em> a module <c>Mod</c>, if + information about release handling, see + <seealso marker="doc/design_principles:release_handling">OTP + Design Principles</seealso> in <em>System Documentation</em>.</p> + <p>A process is said to <em>use</em> a module <c>Mod</c> if <c>Mod</c> is listed in the <c>Modules</c> part of the child - specification used to start the process, see <c>supervisor(3)</c>. - In the case of gen_event, an event manager process is said to use - <c>Mod</c> if <c>Mod</c> is an installed event handler.</p> - <p><em>High-level instructions</em></p> + specification used to start the process, see + <seealso marker="stdlib:supervisor"><c>supervisor(3)</c></seealso>. + In the case of + <seealso marker="stdlib:gen_event"><c>gen_event</c></seealso>, + an event manager process is said to use <c>Mod</c> if <c>Mod</c> + is an installed event handler.</p> + + <section> + <title>High-Level Instructions</title> <pre> {update, Mod} {update, Mod, supervisor} @@ -116,52 +123,68 @@ Change = soft | {advanced,Extra} Extra = term() PrePurge = PostPurge = soft_purge | brutal_purge - DepMods = [Mod] - </pre> - <p>Synchronized code replacement of processes using the module - <c>Mod</c>. All those processes are suspended using - <c>sys:suspend</c>, the new version of the module is loaded and - then the processes are resumed using <c>sys:resume</c>.</p> - <p><c>Change</c> defaults to <c>soft</c> and defines the type of - code change. If it is set to <c>{advanced,Extra}</c>, processes - implemented using gen_server, gen_fsm or gen_event will transform - their internal state by calling the callback function - <c>code_change</c>. Special processes will call the callback + DepMods = [Mod]</pre> + <p>Synchronized code replacement of processes using module + <c>Mod</c>.</p> + <p>All those processes are suspended using + <seealso marker="stdlib:sys#suspend/1"><c>sys:suspend</c></seealso>, + the new module version is loaded, and + then the processes are resumed using + <seealso marker="stdlib:sys#resume/1"><c>sys:resume</c></seealso>.</p> + <taglist> + <tag><c>Change</c></tag> + <item><p>Defaults to <c>soft</c> and defines the type of + code change. If it is set to <c>{advanced,Extra}</c>, implemented + processes using + <seealso marker="stdlib:gen_server"><c>gen_server</c></seealso>, + <seealso marker="stdlib:gen_fsm"><c>gen_fsm</c></seealso>, or + <seealso marker="stdlib:gen_event"><c>gen_event</c></seealso> + transform their internal state by calling the callback function + <c>code_change</c>. Special processes call the callback function <c>system_code_change/4</c>. In both cases, the term - <c>Extra</c> is passed as an argument to the callback function.</p> - <p><c>PrePurge</c> defaults to <c>brutal_purge</c> and controls - what action to take with processes that are executing old code - before loading the new version of the module. If the value + <c>Extra</c> is passed as an argument to the callback + function.</p></item> + <tag><c>PrePurge</c></tag> + <item><p>Defaults to <c>brutal_purge</c>. It controls + what action to take with processes executing old code + before loading the new module version. If the value is <c>brutal_purge</c>, the processes are killed. If the value is - <c>soft_purge</c>, <c>release_handler:install_release/1</c> - returns <c>{error,{old_processes,Mod}}</c>.</p> - <p><c>PostPurge</c> defaults to <c>brutal_purge</c> and controls + <c>soft_purge</c>, + <seealso marker="release_handler#install_release/1"><c>release_handler:install_release/1</c></seealso> + returns <c>{error,{old_processes,Mod}}</c>.</p></item> + <tag><c>PostPurge</c></tag> + <item><p>Defaults to <c>brutal_purge</c>. It controls what action to take with processes that are executing old code - when the new version of the module has been loaded. If the value + when the new module version has been loaded. If the value is <c>brutal_purge</c>, the code is purged when the release is made permanent and the processes are killed. If the value is - <c>soft_purge</c>, the release handler will purge the old code - when no remaining processes execute the code.</p> - <p><c>DepMods</c> defaults to [] and defines which other modules - <c>Mod</c> is dependent on. In <c>relup</c>, instructions for - suspending processes using <c>Mod</c> will come before + <c>soft_purge</c>, the release handler purges the old code + when no remaining processes execute the code.</p></item> + <tag><c>DepMods</c></tag> + <item><p>Defaults to <c>[]</c> and defines other modules that + <c>Mod</c> is dependent on. In the <c>relup</c> file, instructions + for suspending processes using <c>Mod</c> come before instructions for suspending processes using modules in - <c>DepMods</c> when upgrading, and vice versa when downgrading. + <c>DepMods</c> when upgrading, and conversely when downgrading. In case of circular dependencies, the order of the instructions in - the <c>appup</c> script is kept.</p> - <p><c>Timeout</c> defines the timeout when suspending processes. - If no value or <c>default</c> is given, the default value for - <c>sys:suspend</c> is used.</p> - <p><c>ModType</c> defaults to <c>dynamic</c> and specifies if - the code is "dynamic", that is if a process using the module does - spontaneously switch to new code, or if it is "static". - When doing an advanced update and upgrading, the new version of a + the <c>appup</c> file is kept.</p></item> + <tag><c>Timeout</c></tag> + <item><p>Defines the time-out when suspending processes. + If no value or <c>default</c> is specified, the default value for + <seealso marker="stdlib:sys#suspend/1"><c>sys:suspend</c></seealso> + is used.</p></item> + <tag><c>ModType</c></tag> + <item><p>Defaults to <c>dynamic</c>. It specifies if + the code is "dynamic", that is, if a process using the module + spontaneously switches to new code, or if it is "static". + When doing an advanced update and upgrade, the new version of a dynamic module is loaded before the process is asked to change code. When downgrading, the process is asked to change code before loading the new version. For static modules, the new version is loaded before the process is asked to change code, both in the case of upgrading and downgrading. Callback modules are - dynamic.</p> + dynamic.</p></item> + </taglist> <p><c>update</c> with argument <c>supervisor</c> is used when changing the start specification of a supervisor.</p> <pre> @@ -170,239 +193,229 @@ {load_module, Mod, PrePurge, PostPurge, DepMods} Mod = atom() PrePurge = PostPurge = soft_purge | brutal_purge - DepMods = [Mod] - </pre> + DepMods = [Mod]</pre> <p>Simple code replacement of the module <c>Mod</c>.</p> - <p>See <c>update</c> above for a description of <c>PrePurge</c> and - <c>PostPurge</c>.</p> - <p><c>DepMods</c> defaults to [] and defines which other modules - <c>Mod</c> is dependent on. In <c>relup</c>, instructions for - loading these modules will come before the instruction for loading - <c>Mod</c> when upgrading, and vice versa when downgrading.</p> + <p>For a description of <c>PrePurge</c> and <c>PostPurge</c>, + see <c>update</c> above.</p> + <p><c>DepMods</c> defaults to <c>[]</c> and defines which other modules + <c>Mod</c> is dependent on. In the <c>relup</c> file, instructions for + loading these modules come before the instruction for loading + <c>Mod</c> when upgrading, and conversely when downgrading.</p> <pre> {add_module, Mod} {add_module, Mod, DepMods} Mod = atom() - DepMods = [Mod] - </pre> + DepMods = [Mod]</pre> <p>Loads a new module <c>Mod</c>.</p> - <p><c>DepMods</c> defaults to [] and defines which other modules - <c>Mod</c> is dependent on. In <c>relup</c>, instructions - related to these modules will come before the instruction for - loading <c>Mod</c> when upgrading, and vice versa when + <p><c>DepMods</c> defaults to <c>[]</c> and defines which other modules + <c>Mod</c> is dependent on. In the <c>relup</c> file, instructions + related to these modules come before the instruction for + loading <c>Mod</c> when upgrading, and conversely when downgrading.</p> <pre> {delete_module, Mod} {delete_module, Mod, DepMods} - Mod = atom() - </pre> + Mod = atom()</pre> <p>Deletes a module <c>Mod</c> using the low-level instructions <c>remove</c> and <c>purge</c>.</p> - <p><c>DepMods</c> defaults to [] and defines which other modules - <c>Mod</c> is dependent on. In <c>relup</c>, instructions - related to these modules will come before the instruction for - removing <c>Mod</c> when upgrading, and vice versa when + <p><c>DepMods</c> defaults to <c>[]</c> and defines which other modules + <c>Mod</c> is dependent on. In the <c>relup</c> file, instructions + related to these modules come before the instruction for + removing <c>Mod</c> when upgrading, and conversely when downgrading.</p> <pre> {add_application, Application} {add_application, Application, Type} Application = atom() - Type = permanent | transient | temporary | load | none - </pre> + Type = permanent | transient | temporary | load | none</pre> <p>Adding an application means that the modules defined by the <c>modules</c> key in the <c>.app</c> file are loaded using <c>add_module</c>.</p> <p><c>Type</c> defaults to <c>permanent</c> and specifies the start type of the application. If <c>Type = permanent | transient | temporary</c>, - the application will be loaded and started in the corresponding way, - see <c>application(3)</c>. If <c>Type = load</c>, the application will - only be loaded. If <c>Type = none</c>, the application will be neither - loaded nor started, although the code for its modules will be loaded.</p> + the application is loaded and started in the corresponding way, see + <seealso marker="kernel:application"><c>application(3)</c></seealso>. + If <c>Type = load</c>, the application is only loaded. + If <c>Type = none</c>, the application is not loaded and not + started, although the code for its modules is loaded.</p> <pre> {remove_application, Application} - Application = atom() - </pre> + Application = atom()</pre> <p>Removing an application means that the application is stopped, - the modules are unloaded using <c>delete_module</c> and then + the modules are unloaded using <c>delete_module</c>, and then the application specification is unloaded from the application controller.</p> <pre> {restart_application, Application} - Application = atom() - </pre> + Application = atom()</pre> <p>Restarting an application means that the application is - stopped and then started again similar to using the instructions + stopped and then started again, similar to using the instructions <c>remove_application</c> and <c>add_application</c> in sequence.</p> - <p><em>Low-level instructions</em></p> + </section> + + <section> + <title>Low-Level Instructions</title> <pre> {load_object_code, {App, Vsn, [Mod]}} App = Mod = atom() - Vsn = string() - </pre> - <p>Reads each <c>Mod</c> from the directory <c>App-Vsn/ebin</c> as - a binary. It does not load the modules. The instruction should be - placed first in the script in order to read all new code from file - to make the suspend-load-resume cycle less time consuming. After - this instruction has been executed, the code server with the new - version of <c>App</c>.</p> + Vsn = string()</pre> + <p>Reads each <c>Mod</c> from directory <c>App-Vsn/ebin</c> as + a binary. It does not load the modules. The instruction is to be + placed first in the script to read all new code from the file + to make the suspend-load-resume cycle less time-consuming.</p> <pre> -point_of_no_return - </pre> +point_of_no_return</pre> <p>If a crash occurs after this instruction, the system cannot - recover and is restarted from the old version of the release. - The instruction must only occur once in a script. It should be + recover and is restarted from the old release version. + The instruction must only occur once in a script. It is to be placed after all <c>load_object_code</c> instructions.</p> <pre> {load, {Mod, PrePurge, PostPurge}} Mod = atom() - PrePurge = PostPurge = soft_purge | brutal_purge - </pre> + PrePurge = PostPurge = soft_purge | brutal_purge</pre> <p>Before this instruction occurs, <c>Mod</c> must have been loaded using <c>load_object_code</c>. This instruction loads the module. - <c>PrePurge</c> is ignored. See the high-level instruction - <c>update</c> for a description of <c>PostPurge</c>.</p> + <c>PrePurge</c> is ignored. For a description of <c>PostPurge</c>, + see the high-level instruction <c>update</c> earlier.</p> <pre> {remove, {Mod, PrePurge, PostPurge}} Mod = atom() - PrePurge = PostPurge = soft_purge | brutal_purge - </pre> + PrePurge = PostPurge = soft_purge | brutal_purge</pre> <p>Makes the current version of <c>Mod</c> old. - <c>PrePurge</c> is ignored. See the high-level instruction - <c>update</c> for a description of <c>PostPurge</c>.</p> + <c>PrePurge</c> is ignored. For a description of <c>PostPurge</c>, + see the high-level instruction <c>update</c> earlier.</p> <pre> {purge, [Mod]} - Mod = atom() - </pre> - <p>Purges each module <c>Mod</c>, that is removes the old code. - Note that any process executing purged code is killed.</p> + Mod = atom()</pre> + <p>Purges each module <c>Mod</c>, that is, removes the old code. + Notice that any process executing purged code is killed.</p> <pre> {suspend, [Mod | {Mod, Timeout}]} Mod = atom() - Timeout = int()>0 | default | infinity - </pre> + Timeout = int()>0 | default | infinity</pre> <p>Tries to suspend all processes using a module <c>Mod</c>. If a - process does not respond, it is ignored. This may cause + process does not respond, it is ignored. This can cause the process to die, either because it crashes when it spontaneously switches to new code, or as a result of a purge operation. If no <c>Timeout</c> is specified or <c>default</c> is - given, the default value for <c>sys:suspend</c> is used.</p> + specified, the default value for + <seealso marker="stdlib:sys#suspend/1"><c>sys:suspend</c></seealso> + is used.</p> <pre> {resume, [Mod]} - Mod = atom() - </pre> + Mod = atom()</pre> <p>Resumes all suspended processes using a module <c>Mod</c>.</p> <pre> {code_change, [{Mod, Extra}]} {code_change, Mode, [{Mod, Extra}]} Mod = atom() Mode = up | down - Extra = term() - </pre> + Extra = term()</pre> <p><c>Mode</c> defaults to <c>up</c> and specifies if it is an - upgrade or downgrade.</p> - <p>This instruction sends a <c>code_change</c> system message to - all processes using a module <c>Mod</c> by calling the function - <c>sys:change_code</c>, passing the term <c>Extra</c> as argument.</p> + upgrade or downgrade. This instruction sends a <c>code_change</c> + system message to all processes using a module <c>Mod</c> by + calling function + <seealso marker="stdlib:sys#change_code/4"><c>sys:change_code</c></seealso>, + passing term <c>Extra</c> as argument.</p> <pre> {stop, [Mod]} - Mod = atom() - </pre> + Mod = atom()</pre> <p>Stops all processes using a module <c>Mod</c> by calling - <c>supervisor:terminate_child/2</c>. The instruction is useful + <seealso marker="stdlib:supervisor#terminate_child/2"><c>supervisor:terminate_child/2</c></seealso>. + This instruction is useful when the simplest way to change code is to stop and restart the - processes which run the code.</p> + processes that run the code.</p> <pre> {start, [Mod]} - Mod = atom() - </pre> + Mod = atom()</pre> <p>Starts all stopped processes using a module <c>Mod</c> by calling - <c>supervisor:restart_child/2</c>.</p> + <seealso marker="stdlib:supervisor#restart_child/2"><c>supervisor:restart_child/2</c></seealso>.</p> <pre> {sync_nodes, Id, [Node]} {sync_nodes, Id, {M, F, A}} Id = term() Node = node() M = F = atom() - A = [term()] - </pre> + A = [term()]</pre> <p><c>apply(M, F, A)</c> must return a list of nodes.</p> - <p>The instruction synchronizes the release installation with other - nodes. Each <c>Node</c> must evaluate this command, with the same + <p>This instruction synchronizes the release installation with other + nodes. Each <c>Node</c> must evaluate this command with the same <c>Id</c>. The local node waits for all other nodes to evaluate - the instruction before execution continues. In case a node goes + the instruction before execution continues. If a node goes down, it is considered to be an unrecoverable error, and the local node is restarted from the old release. There is no - timeout for this instruction, which means that it may hang + time-out for this instruction, which means that it can hang forever.</p> <pre> {apply, {M, F, A}} M = F = atom() - A = [term()] - </pre> - <p>Evaluates <c>apply(M, F, A)</c>. If the instruction appears - before the <c>point_of_no_return</c> instruction, a failure is - caught. <c>release_handler:install_release/1</c> then returns - <c>{error,{'EXIT',Reason}}</c>, unless <c>{error,Error}</c> is - thrown or returned. Then it returns <c>{error,Error}</c>.</p> - <p>If the instruction appears after the <c>point_of_no_return</c> - instruction, and the function call fails, the system is - restarted.</p> + A = [term()]</pre> + <p>Evaluates <c>apply(M, F, A)</c>.</p> + <p>If the instruction appears before instruction + <c>point_of_no_return</c>, a failure is caught. + <seealso marker="release_handler#install_release/1"><c>release_handler:install_release/1</c></seealso> + then returns <c>{error,{'EXIT',Reason}}</c>, unless <c>{error,Error}</c> + is thrown or returned. Then it returns <c>{error,Error}</c>.</p> + <p>If the instruction appears after instruction + <c>point_of_no_return</c> and the function call fails, the + system is restarted.</p> <pre> -restart_new_emulator - </pre> - <p>This instruction is used when erts, kernel, stdlib or sasl is +restart_new_emulator</pre> + <p>This instruction is used when the application <c>ERTS</c>, + <c>Kernel</c>, <c>STDLIB</c>, or <c>SASL</c> is upgraded. It shuts down the current emulator and starts a new one. All processes are terminated gracefully, and the new - version of erts, kernel, stdlib and sasl are used when the - emulator restarts. Only one <c>restart_new_emulator</c> - instruction is allowed in the relup, and it shall be placed - first. <seealso marker="systools#make_relup/3">systools:make_relup/3,4</seealso> - will ensure this when the relup is generated. The rest of the - relup script is executed after the restart as a part of the boot - script.</p> - <p>An info report will be written when the upgrade is - completed. To programatically find out if the upgrade is - complete, + version of <c>ERTS</c>, <c>Kernel</c>, <c>STDLIB</c>, and + <c>SASL</c> are used when the emulator restarts. + Only one <c>restart_new_emulator</c> instruction is allowed + in the <c>relup</c> file, and it must be placed first. + <seealso marker="systools#make_relup/3"><c>systools:make_relup/3,4</c></seealso> + ensures this when the <c>relup</c> file is generated. The rest of the + instructions in the <c>relup</c> file is executed after the + restart as a part of the boot script.</p> + <p>An info report is written when the upgrade is completed. + To programmatically determine if the upgrade is complete, call <seealso marker="release_handler#which_releases/0"> - release_handler:which_releases/0,1</seealso> and check if the + <c>release_handler:which_releases/0,1</c></seealso> and check if the expected release has status <c>current</c>.</p> <p>The new release must still be made permanent after the upgrade - is completed. Otherwise, the old emulator is started in case of + is completed, otherwise the old emulator is started if there is an emulator restart.</p> <warning> - <p>As stated above, the <c>restart_new_emulator</c> - instruction causes the emulator to be restarted with new - versions of <c>erts</c>, <c>kernel</c>, <c>stdlib</c> and - <c>sasl</c>. All other applications, however, will at startup - be running their old versions in this new emulator. In most - cases this is no problem, but every now and then there will be - incompatible changes to the core applications which may cause - trouble in this setting. Such incompatible changes (when - functions are removed) are normally preceded by a deprecation - over two major releases. To make sure your application is not - crashed by an incompatible change, always remove any call to - deprecated functions as soon as possible.</p> + <p>As stated earlier, instruction <c>restart_new_emulator</c> + causes the emulator to be restarted with new versions of + <c>ERTS</c>, <c>Kernel</c>, <c>STDLIB</c>, and <c>SASL</c>. + However, all other applications do at startup run their old + versions in this new emulator. This is usually no problem, + but every now and then incompatible changes occur to the + core applications, which can cause + trouble in this setting. Such incompatible changes (when + functions are removed) are normally preceded by a deprecation + over two major releases. To ensure that your application is not + crashed by an incompatible change, always remove any call to + deprecated functions as soon as possible.</p> </warning> <pre> -restart_emulator - </pre> +restart_emulator</pre> <p>This instruction is similar to <c>restart_new_emulator</c>, - except it shall be placed at the end of the relup script. It is - not related to an upgrade of the emulator or the core + except it must be placed at the end of the <c>relup</c> file. + It is not related to an upgrade of the emulator or the core applications, but can be used by any application when a complete - reboot of the system is reqiured. When generating the - relup, <seealso marker="systools#make_relup/3">systools:make_relup/3,4</seealso> + reboot of the system is required.</p> + <p>When generating the <c>relup</c> file, + <seealso marker="systools#make_relup/3"><c>systools:make_relup/3,4</c></seealso> ensures that there is only one <c>restart_emulator</c> - instruction and that it is the last instruction of the - relup.</p> + instruction and that it is the last instruction in the + <c>relup</c> file.</p> + </section> </section> <section> - <title>SEE ALSO</title> - <p><seealso marker="relup">relup(4)</seealso>, - <seealso marker="release_handler">release_handler(3)</seealso>, - supervisor(3), - <seealso marker="systools">systools(3)</seealso></p> + <title>See Also</title> + <p><seealso marker="release_handler"><c>release_handler(3)</c></seealso>, + <seealso marker="relup"><c>relup(4)</c></seealso>, + <seealso marker="stdlib:supervisor"><c>supervisor(3)</c></seealso>, + <seealso marker="systools"><c>systools(3)</c></seealso></p> </section> </fileref> diff --git a/lib/sasl/doc/src/book.xml b/lib/sasl/doc/src/book.xml index 2bb5339d94..624c32a66f 100644 --- a/lib/sasl/doc/src/book.xml +++ b/lib/sasl/doc/src/book.xml @@ -22,7 +22,7 @@ </legalnotice> - <title>System Application Support Libraries (SASL)</title> + <title>System Architecture Support Libraries (SASL)</title> <prepared>OTP Team</prepared> <docno></docno> <date>1999-04-22</date> @@ -31,7 +31,7 @@ </header> <insidecover> </insidecover> - <pagetext>System Application Support Libraries (SASL)</pagetext> + <pagetext>System Architecture Support Libraries (SASL)</pagetext> <preamble> <contents level="2"></contents> </preamble> diff --git a/lib/sasl/doc/src/error_logging.xml b/lib/sasl/doc/src/error_logging.xml index 7c45b1970e..46b12f3872 100644 --- a/lib/sasl/doc/src/error_logging.xml +++ b/lib/sasl/doc/src/error_logging.xml @@ -31,89 +31,93 @@ <date>1999-04-13</date> <rev>B</rev> <file>error_logging.xml</file> - </header> - <p>The SASL application introduces three types of reports:</p> + </header> + <p>The <c>SASL</c> application introduces three types of reports:</p> <list type="bulleted"> - <item>supervisor report</item> - <item>progress report</item> - <item>crash report.</item> + <item>Supervisor report</item> + <item>Progress report</item> + <item>Crash report</item> </list> - <p>When the SASL application is started, it adds a handler that - formats and writes these reports, as specified in the - configuration parameters for sasl, i.e the environment variables - in the SASL application specification, which is found in the - <c>.app</c> file of SASL. See - <seealso marker="sasl_app">sasl(Application)</seealso>, and app(File) - in the Kernel Reference Manual - for the details.</p> + <p>When the <c>SASL</c> application is started, it adds a handler that + formats and writes these reports, as specified in the configuration + parameters for <c>SASL</c>, that is, the environment variables + in the <c>SASL</c> application specification, which is found in the + <c>.app</c> file of <c>SASL</c>. For details, see the + <seealso marker="sasl_app"><c>sasl(6)</c></seealso> application in the + Reference Manual and the <seealso marker="kernel:app"><c>app(4)</c></seealso> + file in the <c>Kernel</c> Reference Manual.</p> <section> <title>Supervisor Report</title> - <p>A supervisor report is issued when a supervised child terminates in - an unexpected way. A supervisor report contains the following + <p>A supervisor report is issued when a supervised child terminates + unexpectedly. A supervisor report contains the following items:</p> <taglist> - <tag>Supervisor.</tag> - <item>The name of the reporting supervisor.</item> - <tag>Context.</tag> - <item>Indicates in which phase the child terminated + <tag><c>Supervisor</c></tag> + <item><p>Name of the reporting supervisor.</p></item> + <tag><c>Context</c></tag> + <item><p>Indicates in which phase the child terminated from the supervisor's point of view. This can be - <c>start_error</c>, <c>child_terminated</c>, or - <c>shutdown_error</c>.</item> - <tag>Reason.</tag> - <item>The termination reason.</item> - <tag>Offender.</tag> - <item>The start specification for the child.</item> + <c>start_error</c>, <c>child_terminated</c>, or + <c>shutdown_error</c>.</p></item> + <tag><c>Reason</c></tag> + <item><p>Termination reason.</p></item> + <tag><c>Offender</c></tag> + <item><p>Start specification for the child.</p></item> </taglist> </section> <section> <title>Progress Report</title> - <p>A progress report is issued whenever a supervisor starts or - restarts. A progress report contains the following items:</p> + <p>A progress report is issued when a supervisor starts or + restarts a child. A progress report contains the following items:</p> <taglist> - <tag>Supervisor.</tag> - <item>The name of the reporting supervisor.</item> - <tag>Started.</tag> - <item>The start specification for the successfully - started child.</item> + <tag><c>Supervisor</c></tag> + <item><p>Name of the reporting supervisor.</p></item> + <tag><c>Started</c></tag> + <item><p>Start specification for the successfully + started child.</p></item> </taglist> <marker id="CRASH"></marker> </section> <section> <title>Crash Report</title> - <p>Processes started with the <c>proc_lib:spawn</c> or - <c>proc_lib:spawn_link</c> functions are wrapped within a - <c>catch</c>. A crash report is issued whenever such a process - terminates with an unexpected reason, which is any reason other - than <c>normal</c> or <c>shutdown</c>. Processes using the - <c>gen_server</c> and <c>gen_fsm</c> behaviours are examples of - such processes. A crash report contains the following items:</p> + <p>Processes started with functions + <seealso marker="stdlib:proc_lib#spawn/1"><c>proc_lib:spawn</c></seealso> or + <seealso marker="stdlib:proc_lib#spawn_link/1"><c>proc_lib:spawn_link</c></seealso> + are wrapped within a <c>catch</c>. A crash report is issued when such + a process terminates with an unexpected reason, which is any reason + other than <c>normal</c>, <c>shutdown</c>, or <c>{shutdown,Term}</c>. + Processes using behaviors + <seealso marker="stdlib:gen_server"><c>gen_server</c></seealso> or + <seealso marker="stdlib:gen_fsm"><c>gen_fsm</c></seealso> + are examples of such processes. A crash report contains the following items:</p> <taglist> - <tag>Crasher.</tag> - <item>Information about the crashing process is reported, such - as initial function call, exit reason, and message queue.</item> - <tag>Neighbours.</tag> - <item>Information about processes which are linked to the crashing + <tag><c>Crasher</c></tag> + <item><p>Information about the crashing process, such + as initial function call, exit reason, and message queue.</p></item> + <tag><c>Neighbours</c></tag> + <item><p>Information about processes that are linked to the crashing process and do not trap exits. These processes are the - neighbours which will terminate because of this process + neighbours that terminate because of this process crash. The information gathered is the same as the information - for Crasher, shown in the previous item.</item> + for Crasher, described in the previous item.</p></item> </taglist> <section> - <title>An Example</title> - <p>The following example shows the reports which are generated - when a process crashes. The example process is an + <title>Example</title> + <p>The following example shows the reports generated + when a process crashes. The example process is a <c>permanent</c> process supervised by the <c>test_sup</c> supervisor. A division by zero is executed and the error is first reported by the faulty process. A crash report is - generated as the process was started using the - <c>proc_lib:spawn/3</c> function. The supervisor generates a - supervisor report showing the process that has crashed, and then a + generated, as the process was started using function + <seealso marker="stdlib:proc_lib#spawn/3"><c>proc_lib:spawn/3</c></seealso>. + The supervisor generates a + supervisor report showing the crashed process. A progress report is generated when the process is finally - re-started.</p> + restarted.</p> <pre> =ERROR REPORT==== 27-May-1996::13:38:56 === <0.63.0>: Divide by zero ! @@ -146,7 +150,6 @@ {shutdown,200}, {child_type,worker}] - =PROGRESS REPORT==== 27-May-1996::13:38:56 === Supervisor: {local,test_sup} Started: [{pid,<0.64.0>}, @@ -154,64 +157,66 @@ {mfa,{test,t,[]}}, {restart_type,permanent}, {shutdown,200}, - {child_type,worker}] - </pre> + {child_type,worker}]</pre> </section> </section> <section> <title>Multi-File Error Report Logging</title> - <p>Multi-file error report logging is used to store error messages, - which are received by the <c>error_logger</c>. The error messages + <p>Multi-file error report logging is used to store error messages + received by <c>error_logger</c>. The error messages are stored in several files and each file is smaller than a - specified amount of kilobytes, and no more than a specified number - of files exist at the same time. The logging is very fast because + specified number of kilobytes. No more than a specified number + of files exist at the same time. The logging is very fast, as each error message is written as a binary term.</p> - <p>Refer to - <c>sasl</c> application in the Reference Manual for more details.</p> + <p>For more details, see the + <seealso marker="sasl_app"><c>sasl(6)</c></seealso> + application in the Reference Manual.</p> </section> <section> <title>Report Browser</title> <p>The report browser is used to browse and format error reports - written by the error logger handler <c>log_mf_h</c> defined in - <c>stdlib</c>.</p> + written by the error logger handler + <seealso marker="stdlib:log_mf_h"><c>log_mf_h</c></seealso> + defined in <c>STDLIB</c>.</p> <p>The <c>log_mf_h</c> handler writes all reports to a - report logging directory. This directory is specified when - configuring the SASL application.</p> + report logging directory, which is specified when + configuring the <c>SASL</c> application.</p> <p>If the report browser is - used off-line, the reports can be copied to another directory - which is specified when starting the browser. If no such directory - is specified, the browser reads reports from the SASL + used offline, the reports can be copied to another directory + specified when starting the browser. If no such directory + is specified, the browser reads reports from the <c>SASL</c> <c>error_logger_mf_dir</c>.</p> <section> - <title>Starting the Report Browser</title> - <p>Start the <c>rb_server</c> with the function - <c>rb:start([Options])</c> as shown in the following - example:</p> + <title>Starting Report Browser</title> + <p>Start the <c>rb_server</c> with function + <seealso marker="rb#start/1"><c>rb:start([Options])</c></seealso> + as shown in the following example:</p> <pre> - - 5><input>rb:start([{max, 20}]).</input> + 5> <input>rb:start([{max, 20}]).</input> rb: reading report...done. rb: reading report...done. rb: reading report...done. rb: reading report...done. - </pre> + {ok,<0.199.0>}</pre> </section> <section> - <title>On-line Help</title> - <p>Enter the command <em>rb:help().</em> to access the report - browser on-line help system.</p> + <title>Online Help</title> + <p>Enter command + <seealso marker="rb#help/0"><c>rb:help()</c></seealso> + to access the report browser online help system.</p> </section> <section> - <title>List Reports in the Server</title> - <p>The function <c>rb:list()</c> lists all loaded reports:</p> + <title>List Reports in Server</title> + <p>Use function + <seealso marker="rb#list/0"><c>rb:list()</c></seealso> + to list all loaded reports:</p> <pre> - - 4><input>rb:list().</input> + 4> <input>rb:list().</input> No Type Process Date Time == ==== ======= ==== ==== 20 progress <0.17.0> 1996-10-16 16:14:54 @@ -234,17 +239,15 @@ 3 progress <0.14.0> 1996-10-16 16:16:36 2 error <0.15.0> 1996-10-16 16:17:04 1 progress <0.14.0> 1996-10-16 16:17:09 - ok - </pre> + ok</pre> </section> <section> <title>Show Reports</title> - <p>To show details of a specific report, use the function - <c>rb:show(Number)</c>:</p> + <p>Use function + <seealso marker="rb#show/1"><c>rb:show(Number)</c></seealso> + to show details of a specific report:</p> <pre> - -10> <input>rb:show(1).</input> 7> <input>rb:show(4).</input> PROGRESS REPORT <0.20.0> 1996-10-16 16:16:36 @@ -259,7 +262,7 @@ started {child_type,worker}] ok -8> rb:show(9). +8> <input>rb:show(9).</input> CRASH REPORT <0.24.0> 1996-10-16 16:16:21 =============================================================================== @@ -287,19 +290,17 @@ heap_size 610 stack_size 142 reductions 54 -ok - </pre> +ok</pre> </section> <section> - <title>Search the Reports</title> - <p>It is possible to show all reports which contain a common - pattern. Suppose a process crashes because it tries to call a - non-existing function <c>release_handler:mbj_func.</c> We could - then show reports as follows:</p> + <title>Search Reports</title> + <p>All reports containing a common pattern can be shown. + Suppose a process crashes because it tries to call a + non-existing function <c>release_handler:mbj_func/1</c>. + The reports can then be shown as follows:</p> <pre> - -12><input>rb:grep("mbj_func").</input> +12> <input>rb:grep("mbj_func").</input> Found match in report number 11 ERROR REPORT <0.24.0> 1996-10-16 16:16:21 @@ -368,19 +369,17 @@ restart_type permanent shutdown 2000 child_type worker -ok - </pre> +ok</pre> </section> <section> - <title>Stop the Server</title> - <p>Stop the <c>rb_server</c> with the function - <c>rb:stop()</c>:</p> + <title>Stop Server</title> + <p>Use function + <seealso marker="rb#stop/0"><c>rb:stop()</c></seealso> + to stop the <c>rb_server</c>:</p> <pre> - -13><input>rb:stop().</input> -ok - </pre> +13> <input>rb:stop().</input> +ok</pre> </section> </section> </chapter> diff --git a/lib/sasl/doc/src/notes.xml b/lib/sasl/doc/src/notes.xml index 36ea42762a..da5bc6be96 100644 --- a/lib/sasl/doc/src/notes.xml +++ b/lib/sasl/doc/src/notes.xml @@ -31,6 +31,89 @@ </header> <p>This document describes the changes made to the SASL application.</p> +<section><title>SASL 2.7</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + During upgrade, the release_handler collects a list of + supervisor pids in order to list all processes in the + supervisor tree. If one of the supervisors (legitimately) + exits before release_handler can examine it, then + <c>sys:get_status/1</c> would earlier be called with a + dead pid, causing a <c>'noproc'</c> error. This has been + corrected.</p> + <p> + Own Id: OTP-13291</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + The module <c>overload</c> is deprecated and will be + removed in OTP 19.</p> + <p> + Own Id: OTP-13057</p> + </item> + <item> + <p> + Improve implementation of supervisor child count, making + it faster and more accurate for dynamic processes of a + <c>simple_one_for_one</c> supervisor.</p> + <p> + Own Id: OTP-13290</p> + </item> + </list> + </section> + +</section> + +<section><title>SASL 2.6.1</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Documentation improvements</p> + <p> + Own Id: OTP-13000</p> + </item> + </list> + </section> + +</section> + +<section><title>SASL 2.6</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>A mechanism for limiting the amount of text that the + built-in error logger events will produce has been + introduced. It is useful for limiting both the size of + log files and the CPU time used to produce them.</p> + <p>This mechanism is experimental in the sense that it + may be changed if it turns out that it does not solve the + problem it is supposed to solve. In that case, there may + be backward incompatible improvements to this + mechanism.</p> + <p>See the documentation for the config parameter + <c>error_logger_format_depth</c> in the Kernel + application for information about how to turn on this + feature.</p> + <p> + Own Id: OTP-12864</p> + </item> + </list> + </section> + +</section> + <section><title>SASL 2.5</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/sasl/doc/src/overload.xml b/lib/sasl/doc/src/overload.xml index 35877220ab..2f19cd9088 100644 --- a/lib/sasl/doc/src/overload.xml +++ b/lib/sasl/doc/src/overload.xml @@ -35,98 +35,94 @@ <module>overload</module> <modulesummary>An Overload Regulation Process</modulesummary> <description> - <p><c>overload</c> is a process which indirectly regulates CPU + <warning> + <p> + All functions in this module are deprecated and will be + removed in a future release. + </p> + </warning> + <p><c>overload</c> is a process that indirectly regulates the CPU usage in the system. The idea is that a main application calls - the <c>request/0</c> function before starting a major job, and + function + <seealso marker="#request/0"><c>request/0</c></seealso> + before starting a major job and proceeds with the job if the return value is positive; otherwise - the job must not be started. - </p> - <p><c>overload</c> is part of the <c>sasl</c> application, and all - configuration parameters are defined there. - </p> - <p>A set of two intensities are maintained, the <c>total intensity</c> and the <c>accept intensity</c>. For that purpose - there are two configuration parameters, the <c>MaxIntensity</c> - and the <c>Weight</c> value (both are measured in 1/second). - </p> + the job must not be started.</p> + <p><c>overload</c> is part of the <c>SASL</c> application and all + configuration parameters are defined there.</p> + <p>A set of two intensities are maintained, the <c>total intensity</c> + and the <c>accept intensity</c>. For that purpose, + there are two configuration parameters, <c>MaxIntensity</c> + and <c>Weight</c>; both are measured in 1/second.</p> <p>Then total and accept intensities are calculated as follows. Assume that the time of the current call to - <c>request/0</c> is <c>T(n)</c>, and that the time of the - previous call was <c>T(n-1)</c>. - </p> + <c>request/0</c> is <c>T(n)</c> and that the time of the + previous call was <c>T(n-1)</c>.</p> <list type="bulleted"> <item> <p>The current <c>total intensity</c>, denoted - <c>TI(n)</c>, is calculated according to the formula, - </p> - <p><c>TI(n) = exp(-Weight*(T(n) - T(n-1)) * TI(n-1) + Weight</c>, - </p> - <p>where <c>TI(n-1)</c> is the previous total intensity. - </p> + <c>TI(n)</c>, is calculated according to the formula</p> + <p><c>TI(n) = exp(-Weight*(T(n) - T(n-1)) * TI(n-1) + Weight</c>,</p> + <p>where <c>TI(n-1)</c> is the previous <c>total intensity</c>.</p> </item> <item> <p>The current <c>accept intensity</c>, denoted - <c>AI(n)</c>, is determined by the formula, - </p> - <p><c>AI(n) = exp(-Weight*(T(n) - T(n-1)) * AI(n-1) + Weight</c>, - </p> - <p>where <c>AI(n-1)</c> is the previous accept intensity, - provided that the value of <c>exp(-Weight*(T(n) - T(n-1)) * AI(n-1)</c> is less than <c>MaxIntensity</c>; otherwise the - value is - </p> - <p><c>AI(n) = exp(-Weight*(T(n) - T(n-1)) * AI(n-1)</c>. - </p> + <c>AI(n)</c>, is determined by the formula</p> + <p><c>AI(n) = exp(-Weight*(T(n) - T(n-1)) * AI(n-1) + Weight</c>,</p> + <p>where <c>AI(n-1)</c> is the previous <c>accept intensity</c>, + if the value of <c>exp(-Weight*(T(n) - T(n-1)) * AI(n-1)</c> + is less than <c>MaxIntensity</c>. Otherwise the value is</p> + <p><c>AI(n) = exp(-Weight*(T(n) - T(n-1)) * AI(n-1)</c></p> </item> </list> <p>The value of configuration parameter <c>Weight</c> controls the - speed with which the calculations of intensities will react to + speed with which the calculations of intensities react to changes in the underlying input intensity. The inverted value of - <c>Weight</c>, - </p> - <p><c>T = 1/Weight</c></p> - <p>can be thought of as the "time constant" - of the intensity calculation formulas. For example, if <c>Weight = 0.1</c>, then a change in the underlying input intensity will be - reflected in the <c>total</c> and <c>accept intensities</c> within - approximately 10 seconds. - </p> + <c>Weight</c>, <c>T = 1/Weight</c>, can be thought of as the + "time constant" of the intensity calculation formulas. For example, + if <c>Weight = 0.1</c>, a change in the underlying input intensity is + reflected in <c>total intensity</c> and <c>accept intensity</c> within + about 10 seconds.</p> <p>The overload process defines one alarm, which it sets using - <c>alarm_handler:set_alarm(Alarm)</c>. <c>Alarm</c> is defined - as: - </p> + <c>alarm_handler:set_alarm(Alarm)</c>. <c>Alarm</c> is defined + as follows:</p> <taglist> <tag><c>{overload, []}</c></tag> <item> - <p>This alarm is set when the current accept intensity exceeds - <c>MaxIntensity</c>. - </p> + <p>This alarm is set when the current <c>accept intensity</c> exceeds + <c>MaxIntensity</c>.</p> </item> </taglist> - <p>A new overload alarm is not set until the current accept - intensity has fallen below <c>MaxIntensity</c>. To prevent the - overload process from generating a lot of set/reset alarms, the - alarm is not reset until the current accept intensity has fallen - below 75% of <c>MaxIntensity</c>, and it is not until then that - the alarm can be set again. - </p> + <p>A new request is not accepted until the current <c>accept + intensity</c> has fallen below <c>MaxIntensity</c>. To prevent the + overload process from generating many set/reset alarms, the + alarm is not reset until the current <c>accept intensity</c> has fallen + below 75% of <c>MaxIntensity</c>; it is not until then that + the alarm can be set again.</p> </description> + <funcs> <func> <name>request() -> accept | reject</name> - <fsummary>Request to proceed with current job</fsummary> + <fsummary>Requests to proceed with current job.</fsummary> <desc> <p>Returns <c>accept</c> or <c>reject</c> depending on the - current value of the accept intensity. </p> + current value of the <c>accept intensity</c>.</p> <p>The application - calling this function should be processed with the job in + calling this function is to proceed with the job in question if the return value is <c>accept</c>; otherwise it - should not continue with that job. - </p> + is not to continue with that job.</p> </desc> </func> + <func> <name>get_overload_info() -> OverloadInfo</name> - <fsummary>Return current overload information data</fsummary> + <fsummary>Returns current overload information data.</fsummary> <type> - <v>OverloadInfo = [{total_intensity, TotalIntensity}, {accept_intensity, AcceptIntensity}, {max_intensity, MaxIntensity}, {weight, Weight}, {total_requests, TotalRequests}, {accepted_requests, AcceptedRequests}].</v> + <v>OverloadInfo = [{total_intensity, TotalIntensity}, + {accept_intensity, AcceptIntensity}, {max_intensity, + MaxIntensity}, {weight, Weight}, {total_requests, + TotalRequests}, {accepted_requests, AcceptedRequests}].</v> <v>TotalIntensity = float() > 0</v> <v>AcceptIntensity = float() > 0</v> <v>MaxIntensity = float() > 0</v> @@ -135,18 +131,22 @@ <v>AcceptedRequests = integer()</v> </type> <desc> - <p>Returns the current total and accept intensities, the - configuration parameters, and absolute counts of the total - number of requests, and accepted number of requests (since - the overload process was started).</p> + <p>Returns:</p> + <list type="bulleted"> + <item>Current total and accept intensities</item> + <item>Configuration parameters</item> + <item>Absolute counts of the total number of requests</item> + <item>Accepted number of requests (since the overload + process was started)</item> + </list> </desc> </func> </funcs> <section> <title>See Also</title> - <p>alarm_handler(3), sasl(3) - </p> + <p><seealso marker="alarm_handler"><c>alarm_handler(3)</c></seealso>, + <seealso marker="sasl_app"><c>sasl(6)</c></seealso></p> </section> </erlref> diff --git a/lib/sasl/doc/src/part.xml b/lib/sasl/doc/src/part.xml index bcd345a7c4..2f47a8ad80 100644 --- a/lib/sasl/doc/src/part.xml +++ b/lib/sasl/doc/src/part.xml @@ -30,8 +30,9 @@ <file>part.xml</file> </header> <description> - <p>The System Architecture Support Libraries, <em>SASL</em>, - provides support for alarm and release handling etc.</p> + <p>The System Architecture Support Libraries <c>SASL</c> application + provides support for alarm handling, release handling, and + related functions.</p> </description> <xi:include href="sasl_intro.xml"/> <xi:include href="error_logging.xml"/> diff --git a/lib/sasl/doc/src/rb.xml b/lib/sasl/doc/src/rb.xml index 85252fc088..e16e9f5a62 100644 --- a/lib/sasl/doc/src/rb.xml +++ b/lib/sasl/doc/src/rb.xml @@ -35,241 +35,252 @@ <module>rb</module> <modulesummary>The Report Browser Tool</modulesummary> <description> - <p>The Report Browser (RB) tool makes it possible to browse and + <p>The Report Browser (RB) tool is used to browse and format error reports written by the error logger handler - <c>log_mf_h</c>. - </p> + <seealso marker="stdlib:log_mf_h"><c>log_mf_h</c></seealso> + in <c>STDLIB</c>.</p> </description> + <funcs> <func> <name>filter(Filters)</name> <name>filter(Filters, Dates)</name> - <fsummary>Filter reports and displays them on the screen</fsummary> + <fsummary>Filters reports and displays them on the screen.</fsummary> <type> <v>Filters = [filter()]</v> - <v>filter() = {Key, Value} | {Key, Value, no} | {Key, RegExp, re} | {Key, RegExp, re, no}</v> + <v>filter() = {Key, Value} | {Key, Value, no} | {Key, RegExp, re} | + {Key, RegExp, re, no}</v> <v>Key = term()</v> <v>Value = term()</v> - <v>RegExp = string() | {string, Options} | mp(), {mp(), Options}</v> + <v>RegExp = string() | {string(), Options} | re:mp() | {re:mp(), Options}</v> <v>Dates = {DateFrom, DateTo} | {DateFrom, from} | {DateTo, to}</v> - <v>DateFrom = DateTo = {date(), time()}</v> - <v>date() and time() are the same type as in the <c>calendar</c> module</v> + <v>DateFrom = DateTo = calendar:datetime()</v> </type> <desc> - <p>This function displays the reports that match the provided filters.</p> - <p> - When a filter includes the <c>no</c> atom it will exclude the reports that match - that filter. - </p> - <p> - The reports are matched using the <c>proplists</c> module. The report must be a proplist - to be matched against any of the <c>filters()</c>. - </p> - <p> - If the filter is of the form <c>{Key, RegExp, re}</c> the report must contain an element with - <c>key = Key</c> and <c>Value</c> must match the RegExp regular expression. - </p> - <p> - If the Dates parameter is provided, then the reports are filtered according to the date - when they occurred. If Dates is of the form <c>{DateFrom, from}</c> then reports that occurred - after DateFrom are displayed. - </p> - <p> - If Dates is of the form <c>{DateTo, to}</c> then reports that occurred before DateTo - are displayed. - </p> - <p> - If two Dates are provided, then reports that occurred between those dates are returned. - </p> - <p> - If you only want to filter only by dates, then you can provide the empty list as the Filters - parameter. - </p> - <p> - See <c>rb:grep/1</c> for more information on the RegExp parameter. - </p> + <p>Displays the reports that match the provided filters.</p> + <p>When a filter includes the <c>no</c> atom, it excludes the + reports that match that filter.</p> + <p>The reports are matched using the + <seealso marker="stdlib:proplists"><c>proplists</c></seealso> + module in <c>STDLIB</c>. The report must be a proplist + to be matched against any of the filters.</p> + <p>If the filter has the form <c>{Key, RegExp, re}</c>, the + report must contain an element with key equal to <c>Key</c> and + the value must match the regular expression <c>RegExp</c>.</p> + <p>If parameter <c>Dates</c> is specified, the reports are filtered + according to the date when they occurred. If <c>Dates</c> has + the form <c>{DateFrom, from}</c>, reports that occurred after + <c>DateFrom</c> are displayed.</p> + <p>If <c>Dates</c> has the form <c>{DateTo, to}</c>, reports that + occurred before <c>DateTo</c> are displayed.</p> + <p>If two <c>Dates</c> are specified, reports that occurred between + those dates are returned.</p> + <p>To filter only by dates, specify the empty list as the <c>Filters</c> + parameter.</p> + <p>For details about parameter <c>RegExp</c>, see <c>rb:grep/1</c>.</p> + <p>For details about data type <c>mp()</c>, see + <seealso marker="stdlib:re#type-mp"><c>re:mp()</c></seealso>.</p> + <p>For details about data type <c>datetime()</c>, see + <seealso marker="stdlib:calendar#type-datetime"><c>calendar:datetime()</c></seealso>.</p> </desc> </func> + <func> <name>grep(RegExp)</name> - <fsummary>Search the reports for a regular expression</fsummary> + <fsummary>Searches the reports for a regular expression.</fsummary> <type> - <v>RegExp = string() | {string, Options} | mp(), {mp(), Options}</v> + <v>RegExp = string() | {string(), Options} | re:mp() | {re:mp(), Options}</v> </type> <desc> - <p>All reports containing the regular expression <c>RegExp</c> - are printed. - </p> - <p><c>RegExp</c> can be a string containing the regular - expression; a tuple with the string and the options for - compilation; a compiled regular expression; a compiled - regular expression and the options for running it. - Refer to the module <c>re</c> and specially the function <c>re:run/3</c> - for a definition of valid regular expressions and options. - </p> + <p>All reports matching the regular expression <c>RegExp</c> + are displayed. <c>RegExp</c> can be any of the following:</p> + <list type="bulleted"> + <item>A string containing the regular expression</item> + <item>A tuple with the string and the options for compilation</item> + <item>A compiled regular expression</item> + <item>A compiled regular expression and the options for running it</item> + </list> + <p>For a definition of valid regular expressions and options, see + the <seealso marker="stdlib:re"><c>re</c></seealso> module in + <c>STDLIB</c> and in particular function <c>re:run/3</c>.</p> + <p>For details about data type <c>mp()</c>, see + <seealso marker="stdlib:re#type-mp"><c>re:mp()</c></seealso>.</p> </desc> </func> + <func> <name>h()</name> <name>help()</name> - <fsummary>Print help information</fsummary> + <fsummary>Displays help information.</fsummary> <desc> - <p>Prints the on-line help information. - </p> + <p>Displays online help information.</p> </desc> </func> + <func> <name>list()</name> <name>list(Type)</name> - <fsummary>List all reports</fsummary> + <fsummary>Lists all reports.</fsummary> <type> <v>Type = type()</v> <v>type() = error | error_report | info_msg | info_report | - warning_msg | warning_report | crash_report | - supervisor_report | progress</v> + warning_msg | warning_report | crash_report | + supervisor_report | progress</v> </type> <desc> - <p>This function lists all reports loaded in the + <p>Lists all reports loaded in <c>rb_server</c>. Each report is given a unique number that - can be used as a reference to the report in the - <c>show/1</c> function. - </p> - <p>If no <c>Type</c> is given, all reports are listed. - </p> + can be used as a reference to the report in function + <seealso marker="#show/1"><c>show/1</c></seealso>.</p> + <p>If no <c>Type</c> is specified, all reports are listed.</p> </desc> </func> + <func> <name>log_list()</name> <name>log_list(Type)</name> - <fsummary>Log reports list</fsummary> + <fsummary>Logs report lists.</fsummary> <type> <v>Type = type()</v> <v>type() = error | error_report | info_msg | info_report | - warning_msg | warning_report | crash_report | - supervisor_report | progress</v> + warning_msg | warning_report | crash_report | + supervisor_report | progress</v> </type> <desc> - <p>Same as <c>list/0</c> or <c>list/1</c> functions - but result is printed to logfile, if set, otherwise to standard_io. - </p> - <p>If no <c>Type</c> is given, all reports are listed. - </p> + <p>Same as functions + <seealso marker="#list/0"><c>list/0</c></seealso> or + <seealso marker="#list/1"><c>list/1</c></seealso>, + but the result is printed to a log file, if set; otherwise + to <c>standard_io</c>.</p> + <p>If no <c>Type</c> is specified, all reports are listed.</p> </desc> </func> + <func> <name>rescan()</name> <name>rescan(Options)</name> - <fsummary>Rescan the report directory</fsummary> + <fsummary>Rescans the report directory.</fsummary> <type> <v>Options = [opt()]</v> </type> <desc> <p>Rescans the report directory. <c>Options</c> is the same as - for <c>start()</c>. - </p> + for function + <seealso marker="#start/1"><c>start/1</c></seealso>.</p> </desc> </func> + <func> <name>show()</name> <name>show(Report)</name> - <fsummary>Show reports</fsummary> + <fsummary>Displays reports.</fsummary> <type> - <v>Report = int() | type()</v> + <v>Report = integer() | type()</v> </type> <desc> - <p>If a type argument is given, all loaded reports of this - type are printed. If an integer argument is given, the - report with this reference number is printed. If no argument - is given, all reports are shown. - </p> + <p>If argument <c>type</c> is specified, all loaded reports of this + type are displayed. If an integer argument is specified, the + report with this reference number is displayed. If no argument + is specified, all reports are displayed.</p> </desc> </func> + <func> <name>start()</name> <name>start(Options)</name> - <fsummary>Start the RB server</fsummary> + <fsummary>Starts the <c>rb_server</c>.</fsummary> <type> <v>Options = [opt()]</v> - <v>opt() = {start_log, FileName} | {max, MaxNoOfReports} | {report_dir, DirString} | {type, ReportType} | {abort_on_error, Bool}</v> + <v>opt() = {start_log, FileName} | {max, MaxNoOfReports} | + {report_dir, DirString} | {type, ReportType} | + {abort_on_error, Bool}</v> <v>FileName = string() | atom() | pid()</v> - <v>MaxNoOfReports = int() | all</v> + <v>MaxNoOfReports = integer() | all</v> <v>DirString = string()</v> <v>ReportType = type() | [type()] | all</v> - <v>Bool = true | false</v> + <v>Bool = boolean()</v> </type> <desc> - <p>The function <c>start/1</c> starts the <c>rb_server</c> - with the specified options, while <c>start/0</c> starts with - default options. The <c>rb_server</c> must be started before - reports can be browsed. When the <c>rb_server</c> is + <p>Function <c>start/1</c> starts <c>rb_server</c> with the + specified options, whereas function <c>start/0</c> starts with + default options. <c>rb_server</c> must be started before + reports can be browsed. When <c>rb_server</c> is started, the files in the specified directory are scanned. The other functions assume that the server has - started. - </p> - <p><c>{start_log, FileName}</c> starts logging to file, - registered name or io_device. All reports will be printed - to the named file. The default is <c>standard_io</c>. - The option {start_log, standard_error} is not allowed and - will be replaced by default standard_io. - </p> - <p><c>{max, MaxNoOfReports}</c>. Controls how many reports the - <c>rb_server</c> should read on start-up. This option is - useful as the directory may contain 20.000 reports. If this - option is given, the <c>MaxNoOfReports</c> latest reports - will be read. The default is 'all'. - </p> - <p><c>{report_dir, DirString}</c>. Defines the directory where - the error log files are located. The default is <c>{sasl, error_logger_mf_dir}</c>. </p> - <p><c>{type, ReportType}</c>. Controls what kind of reports the - <c>rb_server</c> should read on start-up. <c>ReportType</c> - is a supported type, 'all', or a list of supported - types. The default is 'all'. - </p> - <p><c>{abort_on_error, Bool}</c>. This option specifies whether - or not logging should be aborted if rb encounters an unprintable - report. (You may get a report on incorrect form if the - <c>error_logger</c> function <c>error_msg</c> or - <c>info_msg</c> has been called with an invalid format string). - If <c>Bool</c> is <c>true</c>, rb will stop logging (and print an - error message to stdout) if it encounters a badly formatted report. - If logging to file is enabled, an error message will be appended to - the log file as well. - If <c>Bool</c> is <c>false</c> (which is the default value), rb will - print an error message to stdout for every bad report it - encounters, but the logging process is never aborted. All printable - reports will be written. If logging to file is enabled, rb prints - <c>* UNPRINTABLE REPORT *</c> in the log file at the location of an - unprintable report. - </p> + started.</p> + <p><em>Options:</em></p> + <taglist> + <tag><c>{start_log, FileName}</c></tag> + <item><p>Starts logging to file, + registered name, or <c>io_device</c>. All reports are printed + to the specified destination. Default is <c>standard_io</c>. + Option <c>{start_log, standard_error}</c> is not allowed and + will be replaced by default <c>standard_io</c>.</p></item> + <tag><c>{max, MaxNoOfReports}</c></tag> + <item><p>Controls how many reports + <c>rb_server</c> is to read at startup. This option is + useful, as the directory can contain a large amount of reports. If this + option is specified, the <c>MaxNoOfReports</c> latest reports + are read. Default is <c>all</c>.</p></item> + <tag><c>{report_dir, DirString}</c></tag> + <item><p>Defines the directory where + the error log files are located. Default is + the directory specified by application environment + variable <c>error_logger_mf_dir</c>, + see <seealso marker="sasl_app">sasl(6)</seealso>.</p></item> + <tag><c>{type, ReportType}</c></tag> + <item><p>Controls what kind of reports + <c>rb_server</c> is to read at startup. <c>ReportType</c> + is a supported type, <c>all</c>, or a list of supported + types. Default is <c>all</c>.</p></item> + <tag><c>{abort_on_error, Bool}</c></tag> + <item><p>Specifies if + logging is to be ended if <c>rb</c> encounters an unprintable + report. (You can get a report with an incorrect form if function + <c>error_logger</c>, <c>error_msg</c>, or + <c>info_msg</c> has been called with an invalid format string)</p> + <list type="bulleted"> + <item>If <c>Bool</c> is <c>true</c>, <c>rb</c> stops logging + (and prints an error message to <c>stdout</c>) if it encounters + a badly formatted report. If logging to file is enabled, an + error message is appended to the log file as well.</item> + <item>If <c>Bool</c> is <c>false</c> (the default value), <c>rb</c> + prints an error message to <c>stdout</c> for every bad report it + encounters, but the logging process is never ended. All printable + reports are written. If logging to file is enabled, <c>rb</c> prints + <c>* UNPRINTABLE REPORT *</c> in the log file at the location of an + unprintable report.</item> + </list></item> + </taglist> </desc> </func> + <func> <name>start_log(FileName)</name> - <fsummary>Redirect all output to <c>FileName</c></fsummary> + <fsummary>Redirects all output to <c>FileName</c>.</fsummary> <type> <v>FileName = string() | atom() | pid()</v> </type> <desc> <p>Redirects all report output from the RB tool to the - specified file, registered name or io_device. - </p> + specified file, registered name, or <c>io_device</c>.</p> </desc> </func> + <func> <name>stop()</name> - <fsummary>Stop the RB server</fsummary> + <fsummary>Stops the <c>rb_server</c>.</fsummary> <desc> - <p>Stops the <c>rb_server</c>. - </p> + <p>Stops <c>rb_server</c>.</p> </desc> </func> + <func> <name>stop_log()</name> - <fsummary>Stop logging to file</fsummary> + <fsummary>Stops logging to file.</fsummary> <desc> - <p>Closes the log file. The output from the RB tool will be - directed to <c>standard_io</c>. - </p> + <p>Closes the log file. The output from the RB tool is + directed to <c>standard_io</c>.</p> </desc> </func> </funcs> diff --git a/lib/sasl/doc/src/ref_man.xml b/lib/sasl/doc/src/ref_man.xml index 2b608c7c51..a80e5a2a00 100644 --- a/lib/sasl/doc/src/ref_man.xml +++ b/lib/sasl/doc/src/ref_man.xml @@ -30,8 +30,8 @@ <file>application.xml</file> </header> <description> - <p>The System Architecture Support Libraries application, <em>SASL</em>, - provides support for alarm and release handling etc.</p> + <p>The <c>SASL</c> application provides support for alarm handling, + release handling, and related functions.</p> </description> <xi:include href="sasl_app.xml"/> <xi:include href="alarm_handler.xml"/> diff --git a/lib/sasl/doc/src/rel.xml b/lib/sasl/doc/src/rel.xml index a16db24295..d5f3c7310a 100644 --- a/lib/sasl/doc/src/rel.xml +++ b/lib/sasl/doc/src/rel.xml @@ -33,74 +33,65 @@ <file>rel</file> <filesummary>Release resource file</filesummary> <description> - <p>The <em>release resource file</em> specifies which applications are + <p>The <em>release resource file</em> specifies which applications are included in a release (system) based on Erlang/OTP.</p> - <p>This file is used by the functions in <c>systools</c> when generating - start scripts (<c>.script</c>, <c>.boot</c>) and release upgrade - files (<c>relup</c>).</p> + <p>This file is used by the functions in + <seealso marker="systools"><c>systools</c></seealso> + when generating start scripts (<c>.script</c>, <c>.boot</c>) and + release upgrade files (<c>relup</c>).</p> </description> <section> - <title>FILE SYNTAX</title> - <p>The release resource file should be called <c>Name.rel</c>.</p> + <title>File Syntax</title> + <p>The release resource file is to be called <c>Name.rel</c>.</p> <p>The <c>.rel</c> file contains one single Erlang term, which is - called a <em>release specification</em>. The file has the + called a <em>release specification</em>. The file has the following syntax:</p> <code type="none"> {release, {RelName,Vsn}, {erts, EVsn}, [{Application, AppVsn} | {Application, AppVsn, Type} | {Application, AppVsn, IncApps} | - {Application, AppVsn, Type, IncApps}]}. - </code> - <list type="bulleted"> - <item> - <p><c>RelName = string()</c> is the name of the release.</p> - </item> - <item> - <p><c>Vsn = string()</c> is the version of the release.</p> - </item> - <item> - <p><c>EVsn = string()</c> is the version of ERTS the release is - intended for.</p> - </item> - <item> - <p><c>Application = atom()</c> is the name of an application - included in the release.</p> - </item> - <item> - <p><c>AppVsn = string()</c> is the version of an application - included in the release.</p> - </item> - <item> - <p><c>Type = permanent | transient | temporary | load | none</c> - is the start type of an application included in the release.</p> - <p>If <c>Type = permanent | transient | temporary</c>, - the application will be loaded and started in the corresponding - way, see <c>application(3)</c>. If <c>Type = load</c>, - the application will only be loaded. If <c>Type = none</c>, - the application will be neither loaded nor started, although - the code for its modules will be loaded. - Defaults to <c>permanent</c></p> - </item> - <item> - <p><c>IncApps = [atom()]</c> is a list of applications that are - included by an application included in the release.</p> - <p>The list must be a subset of the included applications + {Application, AppVsn, Type, IncApps}]}.</code> + <taglist> + <tag><c>RelName = string()</c></tag> + <item><p>Release name.</p></item> + <tag><c>Vsn = string()</c></tag> + <item><p>Release version.</p></item> + <tag><c>EVsn = string()</c></tag> + <item><p><c>ERTS</c> version the release is intended for.</p></item> + <tag><c>Application = atom()</c></tag> + <item><p>Name of an application included in the release.</p></item> + <tag><c>AppVsn = string()</c></tag> + <item><p>Version of an application included in the release.</p></item> + <tag><c>Type = permanent | transient | temporary | load | none</c></tag> + <item><p>Start type of an application included in the release.</p> + <p>If <c>Type = permanent | transient | temporary</c>, the + application is loaded and started in the corresponding way, see + <seealso marker="kernel:application"><c>application(3)</c></seealso>.</p> + <p>If <c>Type = load</c>, the application is only loaded.</p> + <p>If <c>Type = none</c>, the application is not loaded and not + started, although the code for its modules is loaded.</p> + <p>Defaults to <c>permanent</c></p></item> + <tag><c>IncApps = [atom()]</c></tag> + <item><p>A list of applications that are included by an application + included in the release. The list must be a subset of the + included applications specified in the application resource file (<c>Application.app</c>) and overrides this value. Defaults - to the same value as in the application resource file.</p> - </item> - </list> + to the same value as in the application resource file.</p></item> + </taglist> <note> - <p>The list of applications must contain the <c>kernel</c> and - <c>stdlib</c> applications.</p> + <p>The list of applications must contain the <c>Kernel</c> and + <c>STDLIB</c> applications.</p> </note> </section> <section> - <title>SEE ALSO</title> - <p>application(3), relup(4), systools(3)</p> + <title>See Also</title> + <p><seealso marker="kernel:application"><c>application(3)</c></seealso>, + <seealso marker="relup"><c>relup(4)</c></seealso>, + <seealso marker="systools"><c>systools(3)</c></seealso></p> </section> </fileref> diff --git a/lib/sasl/doc/src/release_handler.xml b/lib/sasl/doc/src/release_handler.xml index 692159d7bf..162707676c 100644 --- a/lib/sasl/doc/src/release_handler.xml +++ b/lib/sasl/doc/src/release_handler.xml @@ -31,109 +31,115 @@ <module>release_handler</module> <modulesummary>Unpacking and Installation of Release Packages</modulesummary> <description> - <p>The <em>release handler</em> is a process belonging to the SASL - application which is responsible for <em>release handling</em>, + <p>The <em>release handler</em> process belongs to the <c>SASL</c> + application, which is responsible for <em>release handling</em>, that is, unpacking, installation, and removal of release packages.</p> - <p>An introduction to release handling and a usage example can be - found in - <seealso marker="doc/design_principles:release_handling">Design Principles</seealso>. - </p> + <p>An introduction to release handling and an example is provided in + <seealso marker="doc/design_principles:release_handling">OTP Design + Principles</seealso> in <em>System Documentation</em>.</p> <p>A <em>release package</em> is a compressed tar file containing code for a certain version of a release, created by calling - <seealso marker="systools#make_tar/1">systools:make_tar/1,2</seealso>. - The release package should be placed in the <c>$ROOT/releases</c> - directory of the previous version of the release where + <seealso marker="systools#make_tar/1"><c>systools:make_tar/1,2</c></seealso>. + The release package is to be located in the <c>$ROOT/releases</c> + directory of the previous version of the release, where <c>$ROOT</c> is the installation root directory, - <c>code:root_dir()</c>. - Another <c>releases</c> directory can be specified using the SASL - configuration parameter <c>releases_dir</c>, or the OS environment + <seealso marker="kernel:code#root_dir/0"><c>code:root_dir()</c></seealso>. + Another <c>releases</c> directory can be specified using the <c>SASL</c> + configuration parameter <c>releases_dir</c> or the OS environment variable <c>RELDIR</c>. The release handler must have write access - to this directory in order to install the new release. + to this directory to install the new release. The persistent state of the release handler is stored there in a file called <c>RELEASES</c>.</p> - <p>A release package should always contain the release resource file - <c>Name.rel</c> and a boot script <c>Name.boot</c>. It may contain - a release upgrade file <c>relup</c> and a system configuration - file <c>sys.config</c>. The <c>.rel</c> file contains information - about the release: its name, version, and which ERTS and - application versions it uses. The <c>relup</c> file contains - scripts for how to upgrade to, or downgrade from, this version of - the release.</p> + <p>A release package is always to contain:</p> + <list type="bulleted"> + <item>A release resource file, <c>Name.rel</c></item> + <item>A boot script, <c>Name.boot</c></item> + </list> + <p>The <c>.rel</c> file contains information about the release: its name, + version, and which <c>ERTS</c> and application versions it uses.</p> + <p>A release package can also contain:</p> + <list type="bulleted"> + <item>A release upgrade file, <c>relup</c></item> + <item>A system configuration file, <c>sys.config</c></item> + </list> + <p>The <c>relup</c> file contains instructions for how to upgrade + to, or downgrade from, this version of the release.</p> <p>The release package can be <em>unpacked</em>, which extracts the files. An unpacked release can be <em>installed</em>. The currently used version of the release is then upgraded or downgraded to the specified version by evaluating the instructions - in <c>relup</c>. An installed release can be made - <em>permanent</em>. There can only be one permanent release in - the system, and this is the release that is used if the system + in the <c>relup</c> file. An installed release can be made + <em>permanent</em>. Only one permanent release can exist in + the system, and this release is used if the system is restarted. An installed release, except the permanent one, can be <em>removed</em>. When a release is removed, all files - that belong to that release only are deleted.</p> - <p>Each version of the release has a status. The status can be + belonging to that release only are deleted.</p> + <p>Each release version has a status, which can be <c>unpacked</c>, <c>current</c>, <c>permanent</c>, or <c>old</c>. - There is always one latest release which either has status - <c>permanent</c> (normal case), or <c>current</c> (installed, but - not yet made permanent). The following table illustrates - the meaning of the status values:</p> + There is always one latest release, which either has status + <c>permanent</c> (normal case) or <c>current</c> (installed, but + not yet made permanent). The meaning of the status values are + illustrated in the following table:</p> <pre> -Status Action NextStatus -------------------------------------------- - - unpack unpacked -unpacked install current - remove - -current make_permanent permanent - install other old - remove - -permanent make other permanent old - install permanent -old reboot_old permanent - install current - remove - - </pre> + Status Action NextStatus + ------------------------------------------- + - unpack unpacked + unpacked install current + remove - + current make_permanent permanent + install other old + remove - + permanent make other permanent old + install permanent + old reboot_old permanent + install current + remove -</pre> <p>The release handler process is a locally registered process on each node. When a release is installed in a distributed system, the release handler on each node must be called. The release - installation may be synchronized between nodes. From an operator - view, it may be unsatisfactory to specify each node. The aim is + installation can be synchronized between nodes. From an operator + view, it can be unsatisfactory to specify each node. The aim is to install one release package in the system, no matter how many - nodes there are. If this is the case, it is recommended that - software management functions are written which take care of - this problem. Such a function may have knowledge of the system + nodes there are. It is recommended that + software management functions are written that take care of + this problem. Such a function can have knowledge of the system architecture, so it can contact each individual release handler to install the package.</p> - <p>For release handling to work properly, the runtime system needs - to have knowledge about which release it is currently running. It - must also be able to change (in run-time) which boot script and - system configuration file should be used if the system is + <p>For release handling to work properly, the runtime system must + know which release it is running. It + must also be able to change (in runtime) which boot script and + system configuration file are to be used if the system is restarted. This is taken care of automatically if Erlang is - started as an embedded system. Read about this in <em>Embedded System</em>. In this case, the system configuration file - <c>sys.config</c> is mandatory.</p> - <p>The installation of a new release may restart the system. Which - program to use is specified by the SASL configuration - parameter <c>start_prg</c> which defaults + started as an embedded system. Read about this in + <seealso marker="doc/embedded:users_guide">Embedded System</seealso> in + <em>System Documentation</em>. In this case, the system + configuration file <c>sys.config</c> is mandatory.</p> + <p>The installation of a new release can restart the system. Which + program to use is specified by the <c>SASL</c> configuration + parameter <c>start_prg</c>, which defaults to <c>$ROOT/bin/start</c>.</p> <p>The emulator restart on Windows NT expects that the system is started using the <c>erlsrv</c> program (as a service). - Furthermore the release handler expects that the service is named - <em>NodeName</em>_<em>Release</em>, where <em>NodeName</em> is - the first part of the Erlang nodename (up to, but not including - the "@") and <em>Release</em> is the current version of - the release. The release handler furthermore expects that a + Furthermore, the release handler expects that the service is named + <c>NodeName</c>_<c>Release</c>, where <c>NodeName</c> is + the first part of the Erlang node name (up to, but not including + the "@") and <c>Release</c> is the current release version. + The release handler furthermore expects that a program like <c>start_erl.exe</c> is specified as "machine" to - <c>erlsrv</c>. During upgrading with restart, a new service will - be registered and started. The new service will be set to - automatic and the old service removed as soon as the new release + <c>erlsrv</c>. During upgrading with restart, a new service + is registered and started. The new service is set to + automatic and the old service is removed when the new release is made permanent.</p> - <p>The release handler at a node which runs on a diskless machine, + <p>The release handler at a node running on a diskless machine, or with a read-only file system, must be configured accordingly - using the following <c>sasl</c> configuration parameters (see - <seealso marker="sasl_app">sasl(6)</seealso> for details):</p> + using the following <c>SASL</c> configuration parameters (for + details, see <seealso marker="sasl_app">sasl(6)</seealso>):</p> <taglist> <tag><c>masters</c></tag> <item> - <p>This node uses a number of master nodes in order to store - and fetch release information. All master nodes must be up - and running whenever release information is written by this + <p>This node uses some master nodes to store + and fetch release information. All master nodes must be + operational whenever release information is written by this node.</p> </item> <tag><c>client_directory</c></tag> @@ -145,24 +151,25 @@ old reboot_old permanent <item> <p>This parameter specifies if the Erlang emulator is statically installed at the client node. A node with a static - emulator cannot dynamically switch to a new emulator because + emulator cannot dynamically switch to a new emulator, as the executable files are statically written into memory.</p> </item> </taglist> - <p>It is also possible to use the release handler to unpack and + <p>The release handler can also be used to unpack and install release packages when not running Erlang as an embedded - system, but in this case the user must somehow make sure that + system. However, in this case the user must somehow ensure that correct boot scripts and configuration files are used if - the system needs to be restarted.</p> - <p>There are additional functions for using another file structure + the system must be restarted.</p> + <p>Functions are provided for using another file structure than the structure defined in OTP. These functions can be used to test a release upgrade locally.</p> </description> + <funcs> <func> <name>check_install_release(Vsn) -> {ok, OtherVsn, Descr} | {error, Reason}</name> <name>check_install_release(Vsn,Opts) -> {ok, OtherVsn, Descr} | {error, Reason}</name> - <fsummary>Check installation of a release in the system.</fsummary> + <fsummary>Checks installation of a release in the system.</fsummary> <type> <v>Vsn = OtherVsn = string()</v> <v>Opts = [Opt]</v> @@ -173,27 +180,29 @@ old reboot_old permanent <desc> <p>Checks if the specified version <c>Vsn</c> of the release can be installed. The release must not have status - <c>current</c>. Issues warnings if <c>relup</c> or - <c>sys.config</c> are not present. If <c>relup</c> is present, + <c>current</c>. Issues warnings if <c>relup</c> file or + <c>sys.config</c> is not present. If <c>relup</c> file is present, its contents are checked and <c>{error,Reason}</c> is returned if an error is found. Also checks that all required - applications are present and that all new code can be loaded, - or <c>{error,Reason}</c> is returned.</p> - <p>This function evaluates all instructions that occur before + applications are present and that all new code can be loaded; + <c>{error,Reason}</c> is returned if an error is found.</p> + <p>Evaluates all instructions that occur before the <c>point_of_no_return</c> instruction in the release upgrade script.</p> - <p>Returns the same as <c>install_release/1</c>. <c>Descr</c> - defaults to "" if no <c>relup</c> file is found.</p> - <p>If the option <c>purge</c> is given, all old code that can - be soft purged will be purged after all other checks are - successfully completed. This can be useful in order to + <p>Returns the same as + <seealso marker="#install_release/1"><c>install_release/1</c></seealso>. + <c>Descr</c> defaults to "" if no <c>relup</c> file is found.</p> + <p>If option <c>purge</c> is specified, all old code that can + be soft-purged is purged after all other checks are + successfully completed. This can be useful to reduce the time needed by <seealso - marker="#install_release/1">install_release</seealso>.</p> + marker="#install_release/1"><c>install_release/1</c></seealso>.</p> </desc> </func> + <func> <name>create_RELEASES(Root, RelDir, RelFile, AppDirs) -> ok | {error, Reason}</name> - <fsummary>Create an initial RELEASES file.</fsummary> + <fsummary>Creates an initial <c>RELEASES</c> file.</fsummary> <type> <v>Root = RelDir = RelFile = string()</v> <v>AppDirs = [{App, Vsn, Dir}]</v> @@ -202,52 +211,55 @@ old reboot_old permanent <v>Reason = term()</v> </type> <desc> - <p>Creates an initial RELEASES file to be used by the release - handler. This file must exist in order to install new + <p>Creates an initial <c>RELEASES</c> file to be used by the + release handler. This file must exist to install new releases.</p> <p><c>Root</c> is the root of the installation (<c>$ROOT</c>) as - described above. <c>RelDir</c> is the the directory where - the <c>RELEASES</c> file should be created (normally + described earlier. <c>RelDir</c> is the directory where + the <c>RELEASES</c> file is to be created (normally <c>$ROOT/releases</c>). <c>RelFile</c> is the name of the <c>.rel</c> file that describes the initial release, including the extension <c>.rel</c>.</p> <p><c>AppDirs</c> can be used to specify from where the modules - for the specified applications should be loaded. <c>App</c> is + for the specified applications are to be loaded. <c>App</c> is the name of an application, <c>Vsn</c> is the version, and <c>Dir</c> is the name of the directory where <c>App-Vsn</c> - is located. The corresponding modules should be located under + is located. The corresponding modules are to be located under <c>Dir/App-Vsn/ebin</c>. The directories for applications not specified in <c>AppDirs</c> are assumed to be located in <c>$ROOT/lib</c>.</p> </desc> </func> + <func> <name>install_file(Vsn, File) -> ok | {error, Reason}</name> - <fsummary>Install a release file in the release structure.</fsummary> + <fsummary>Installs a release file in the release structure.</fsummary> <type> <v>Vsn = File = string()</v> <v>Reason = term()</v> </type> <desc> - <p>Installs a release dependent file in the release structure. - A release dependent file is a file that must be in + <p>Installs a release-dependent file in the release structure. + The release-dependent file must be in the release structure when a new release is installed: - <c>start.boot</c>, <c>relup</c> and <c>sys.config</c>.</p> + <c>start.boot</c>, <c>relup</c>, and <c>sys.config</c>.</p> <p>The function can be called, for example, when these files - are generated at the target. It should be called after - <c>set_unpacked/2</c> has been called.</p> + are generated at the target. The function is to be called after + <seealso marker="#set_unpacked/2"><c>set_unpacked/2</c></seealso> + has been called.</p> </desc> </func> + <func> <name>install_release(Vsn) -> {ok, OtherVsn, Descr} | {error, Reason}</name> <name>install_release(Vsn, [Opt]) -> {ok, OtherVsn, Descr} | {continue_after_restart, OtherVsn, Descr} | {error, Reason}</name> - <fsummary>Install a release in the system.</fsummary> + <fsummary>Installs a release in the system.</fsummary> <type> <v>Vsn = OtherVsn = string()</v> <v>Opt = {error_action, Action} | {code_change_timeout, Timeout}</v> <v> | {suspend_timeout, Timeout} | {update_paths, Bool}</v> <v> Action = restart | reboot</v> - <v> Timeout = default | infinity | int()>0</v> + <v> Timeout = default | infinity | pos_integer()</v> <v> Bool = boolean()</v> <v>Descr = term()</v> <v>Reason = {illegal_option, Opt} | {already_installed, Vsn} | {change_appl_data, term()} | {missing_base_app, OtherVsn, App} | {could_not_create_hybrid_boot, term()} | term()</v> @@ -262,7 +274,7 @@ old reboot_old permanent version and a script <c>{Vsn,Descr2,Instructions2}</c> in this file for downgrading to <c>Vsn</c>.</p> <p>If a script is found, the first thing that happens is that - the applications specifications are updated according to + the application specifications are updated according to the <c>.app</c> files and <c>sys.config</c> belonging to the release version <c>Vsn</c>.</p> <p>After the application specifications have been updated, @@ -271,101 +283,120 @@ old reboot_old permanent <c>OtherVsn</c> and <c>Descr</c> are the version (<c>UpFromVsn</c> or <c>Vsn</c>) and description (<c>Descr1</c> or <c>Descr2</c>) as specified in the script.</p> - <p>If <c>{continue_after_restart,OtherVsn,Descr}</c> is - returned, it means that the emulator will be restarted - before the upgrade instructions are executed. This will - happen if the emulator or any of the applications kernel, - stdlib or sasl are updated. The new version of the emulator - and these core applications will execute after the restart, - but for all other applications the old versions will be - started and the upgrade will be performed as normal by + <p>If <c>{continue_after_restart,OtherVsn,Descr}</c> is + returned, the emulator is restarted + before the upgrade instructions are executed. This + occurs if the emulator or any of the applications + <c>Kernel</c>, <c>STDLIB</c>, or <c>SASL</c> + are updated. The new emulator version + and these core applications execute after the restart. + For all other applications the old versions are + started and the upgrade is performed as normal by executing the upgrade instructions.</p> <p>If a recoverable error occurs, the function returns <c>{error,Reason}</c> and the original application specifications are restored. If a non-recoverable error occurs, the system is restarted.</p> - <p>The option <c>error_action</c> defines if the node should be - restarted (<c>init:restart()</c>) or rebooted - (<c>init:reboot()</c>) in case of an error during - the installation. Default is <c>restart</c>.</p> - <p>The option <c>code_change_timeout</c> defines the timeout - for all calls to <c>sys:change_code</c>. If no value is - specified or <c>default</c> is given, the default value - defined in <c>sys</c> is used.</p> - <p>The option <c>suspend_timeout</c> defines the timeout for - all calls to <c>sys:suspend</c>. If no value is specified, - the values defined by the <c>Timeout</c> parameter of - the <c>upgrade</c> or <c>suspend</c> instructions are used. - If <c>default</c> is specified, the default value defined in - <c>sys</c> is used.</p> - <p>The option <c>{update_paths,Bool}</c> indicates if all - application code paths should be updated (<c>Bool==true</c>), - or if only code paths for modified applications should be - updated (<c>Bool==false</c>, default). This option only has - effect for other application directories than the default - <c>$ROOT/lib/App-Vsn</c>, that is, application directories - provided in the <c>AppDirs</c> argument in a call to - <c>create_RELEASES/4</c> or <c>set_unpacked/2</c>.</p> - <p>Example: In the current version <c>CurVsn</c> of a release, - the application directory of <c>myapp</c> is - <c>$ROOT/lib/myapp-1.0</c>. A new version <c>NewVsn</c> is - unpacked outside the release handler, and the release handler - is informed about this with a call to:</p> - <code type="none"> + <p><em>Options</em>:</p> + <taglist> + <tag><c>error_action</c></tag> + <item><p>Defines if the node is to be + restarted + (<seealso marker="erts:init#restart/0"><c>init:restart()</c></seealso>) + or rebooted + (<seealso marker="erts:init#reboot/0"><c>init:reboot()</c></seealso>) + if there is an error during + the installation. Default is <c>restart</c>.</p></item> + <tag><c>code_change_timeout</c></tag> + <item><p>Defines the time-out + for all calls to + <seealso marker="stdlib:sys#change_code/4"><c>stdlib:sys:change_code</c></seealso>. + If no value is specified or <c>default</c> is specified, the + default value defined in <c>sys</c> is used.</p></item> + <tag><c>suspend_timeout</c></tag> + <item><p>Defines the time-out for + all calls to + <seealso marker="stdlib:sys#suspend/1"><c>stdlib:sys:suspend</c></seealso>. + If no value is specified, the values defined by the <c>Timeout</c> + parameter of the <c>upgrade</c> or <c>suspend</c> instructions are used. + If <c>default</c> is specified, the default value defined in + <c>sys</c> is used.</p></item> + <tag><c>{update_paths,Bool}</c></tag> + <item><p>Indicates if all + application code paths are to be updated (<c>Bool==true</c>) + or if only code paths for modified applications are to be + updated (<c>Bool==false</c>, default). This option has only + effect for other application directories than the default + <c>$ROOT/lib/App-Vsn</c>, that is, application directories + specified in argument <c>AppDirs</c> in a call to + <seealso marker="#create_RELEASES/4"><c>create_RELEASES/4</c></seealso> or + <seealso marker="#set_unpacked/2"><c>set_unpacked/2</c></seealso>.</p> + <p><em>Example:</em></p> + <p>In the current version <c>CurVsn</c> of a release, the + application directory of <c>myapp</c> is + <c>$ROOT/lib/myapp-1.0</c>. A new version <c>NewVsn</c> is + unpacked outside the release handler and the release + handler is informed about this with a call as follows:</p> + <code type="none"> release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). -=> {ok,NewVsn} - </code> - <p>If <c>NewVsn</c> is installed with the option - <c>{update_paths,true}</c>, afterwards - <c>code:lib_dir(myapp)</c> will return - <c>/home/user/myapp-1.0</c>.</p> +=> {ok,NewVsn}</code> + <p>If <c>NewVsn</c> is installed with option + <c>{update_paths,true}</c>, then + <seealso marker="kernel:code#lib_dir/1"><c>kernel:code:lib_dir(myapp)</c></seealso> + returns <c>/home/user/myapp-1.0</c>.</p></item> + </taglist> <note> - <p>Installing a new release might be quite time consuming if + <p>Installing a new release can be time consuming if there are many processes in the system. The reason is that each process must be checked for references to old code - before a module can be purged. This check might lead to + before a module can be purged. This check can lead to garbage collections and copying of data.</p> - <p>If you wish to speed up the execution of - <c>install_release</c>, then you may call <seealso - marker="#check_install_release/1">check_install_release</seealso> - first, using the option <c>purge</c>. This will do the same - check for old code, and then purge all modules that can be - soft purged. The purged modules will then no longer have any - old code, and <c>install_release</c> will not need to do the + <p>To speed up the execution of + <seealso marker="#install_release/1"><c>install_release</c></seealso>, + first call <seealso + marker="#check_install_release/1"><c>check_install_release</c></seealso>, + using option <c>purge</c>. This does the same + check for old code. Then purges all modules that can be + soft-purged. The purged modules do then no longer have any + old code, and + <seealso marker="#install_release/1"><c>install_release</c></seealso> + does not need to do the checks.</p> - <p>Obviously, this will not reduce the overall time for the - upgrade, but it will allow checks and purge to be executed + <p>This does not reduce the overall time for the + upgrade, but it allows checks and purge to be executed in the background before the real upgrade is started.</p> </note> <note> <p>When upgrading the emulator from a version older than OTP - R15, there will be an attempt to load new application beam - code into the old emulator. In some cases, the new beam - format can not be read by the old emulator, and so the code - loading will fail and terminate the complete upgrade. To - overcome this problem, the new application code should be - compiled with the old emulator. See <seealso - marker="doc/design_principles:appup_cookbook">Design - Principles</seealso> for more information about emulator - upgrade from pre OTP R15 versions.</p> + R15, an attempt is made to load new application beam + code into the old emulator. Sometimes the new beam + format cannot be read by the old emulator, so the code + loading fails and the complete upgrade is terminated. To + overcome this problem, the new application code is to be + compiled with the old emulator. For more information about + emulator upgrade from pre OTP R15 versions, see + <seealso marker="doc/design_principles:appup_cookbook">Design + Principles</seealso> in <em>System Documentation</em>.</p> </note> </desc> </func> + <func> <name>make_permanent(Vsn) -> ok | {error, Reason}</name> - <fsummary>Make the specified release version permanent.</fsummary> + <fsummary>Makes the specified release version permanent.</fsummary> <type> <v>Vsn = string()</v> <v>Reason = {bad_status, Status} | term()</v> </type> <desc> - <p>Makes the specified version <c>Vsn</c> of the release + <p>Makes the specified release version <c>Vsn</c> permanent.</p> </desc> </func> + <func> <name>remove_release(Vsn) -> ok | {error, Reason}</name> - <fsummary>Remove a release from the system.</fsummary> + <fsummary>Removes a release from the system.</fsummary> <type> <v>Vsn = string()</v> <v>Reason = {permanent, Vsn} | client_node | term()</v> @@ -375,23 +406,26 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). The release must not be the permanent release. Removes only the files and directories not in use by another release.</p> </desc> + </func> <func> <name>reboot_old_release(Vsn) -> ok | {error, Reason}</name> - <fsummary>Reboot the system from an old release.</fsummary> + <fsummary>Reboots the system from an old release.</fsummary> <type> <v>Vsn = string()</v> <v>Reason = {bad_status, Status} | term()</v> </type> <desc> <p>Reboots the system by making the old release permanent, and - calls <c>init:reboot()</c> directly. The release must have - status <c>old</c>.</p> + calls + <seealso marker="erts:init#reboot/0"><c>init:reboot()</c></seealso> + directly. The release must have status <c>old</c>.</p> </desc> </func> + <func> <name>set_removed(Vsn) -> ok | {error, Reason}</name> - <fsummary>Mark a release as removed.</fsummary> + <fsummary>Marks a release as removed.</fsummary> <type> <v>Vsn = string()</v> <v>Reason = {permanent, Vsn} | term()</v> @@ -403,9 +437,10 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). not delete any files.</p> </desc> </func> + <func> <name>set_unpacked(RelFile, AppDirs) -> {ok, Vsn} | {error, Reason}</name> - <fsummary>Mark a release as unpacked.</fsummary> + <fsummary>Marks a release as unpacked.</fsummary> <type> <v>RelFile = string()</v> <v>AppDirs = [{App, Vsn, Dir}]</v> @@ -419,18 +454,19 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). the release is unpacked. <c>Vsn</c> is extracted from the release resource file <c>RelFile</c>.</p> <p><c>AppDirs</c> can be used to specify from where the modules - for the specified applications should be loaded. <c>App</c> is + for the specified applications are to be loaded. <c>App</c> is the name of an application, <c>Vsn</c> is the version, and <c>Dir</c> is the name of the directory where <c>App-Vsn</c> - is located. The corresponding modules should be located under + is located. The corresponding modules are to be located under <c>Dir/App-Vsn/ebin</c>. The directories for applications not specified in <c>AppDirs</c> are assumed to be located in <c>$ROOT/lib</c>.</p> </desc> </func> + <func> <name>unpack_release(Name) -> {ok, Vsn} | {error, Reason}</name> - <fsummary>Unpack a release package.</fsummary> + <fsummary>Unpacks a release package.</fsummary> <type> <v>Name = Vsn = string()</v> <v>Reason = client_node | term()</v> @@ -438,14 +474,15 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). <desc> <p>Unpacks a release package <c>Name.tar.gz</c> located in the <c>releases</c> directory.</p> - <p>Performs some checks on the package - for example checks - that all mandatory files are present - and extracts its + <p>Performs some checks on the package, for example, checks + that all mandatory files are present, and extracts its contents.</p> </desc> </func> + <func> <name>which_releases() -> [{Name, Vsn, Apps, Status}]</name> - <fsummary>Return all known releases</fsummary> + <fsummary>Returns all known releases.</fsummary> <type> <v>Name = Vsn = string()</v> <v>Apps = ["App-Vsn"]</v> @@ -455,16 +492,18 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). <p>Returns all releases known to the release handler.</p> </desc> </func> + <func> <name>which_releases(Status) -> [{Name, Vsn, Apps, Status}]</name> - <fsummary>Return all known releases of a specific status</fsummary> + <fsummary>Returns all known releases of a specific status.</fsummary> <type> <v>Name = Vsn = string()</v> <v>Apps = ["App-Vsn"]</v> <v>Status = unpacked | current | permanent | old</v> </type> <desc> - <p>Returns all releases known to the release handler of a specific status.</p> + <p>Returns all releases, known to the release handler, of a + specific status.</p> </desc> </func> </funcs> @@ -473,7 +512,8 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). <title>Application Upgrade/Downgrade</title> <p>The following functions can be used to test upgrade and downgrade of single applications (instead of upgrading/downgrading an entire - release). A script corresponding to <c>relup</c> is created + release). A script corresponding to the instructions in the + <c>relup</c> file is created on-the-fly, based on the <c>.appup</c> file for the application, and evaluated exactly in the same way as <c>release_handler</c> does.</p> @@ -482,20 +522,22 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). of <c>.appup</c> files. They are not run within the context of the <c>release_handler</c> process. They must therefore <em>not</em> be used together with calls to - <c>install_release/1,2</c>, as this will cause + <seealso marker="#install_release/1"><c>install_release/1,2</c></seealso>, + as this causes the <c>release_handler</c> to end up in an inconsistent state.</p> - <p>No persistent information is updated, why these functions can + <p>No persistent information is updated, so these functions can be used on any Erlang node, embedded or not. Also, using these - functions does not affect which code will be loaded in case of + functions does not affect which code is loaded if there is a reboot.</p> - <p>If the upgrade or downgrade fails, the application may end up + <p>If the upgrade or downgrade fails, the application can end up in an inconsistent state.</p> </warning> </section> + <funcs> <func> <name>upgrade_app(App, Dir) -> {ok, Unpurged} | restart_emulator | {error, Reason}</name> - <fsummary>Upgrade to a new application version</fsummary> + <fsummary>Upgrades to a new application version.</fsummary> <type> <v>App = atom()</v> <v>Dir = string()</v> @@ -506,39 +548,46 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). <desc> <p>Upgrades an application <c>App</c> from the current version to a new version located in <c>Dir</c> according to - the <c>.appup</c> script.</p> + the <c>.appup</c> file.</p> <p><c>App</c> is the name of the application, which must be started. <c>Dir</c> is the new library directory of - <c>App</c>, the corresponding modules as well as - the <c>.app</c> and <c>.appup</c> files should be located + <c>App</c>. The corresponding modules as well as + the <c>.app</c> and <c>.appup</c> files are to be located under <c>Dir/ebin</c>.</p> <p>The function looks in the <c>.appup</c> file and tries to find an upgrade script from the current version of the application using - <seealso marker="#upgrade_script/2">upgrade_script/2</seealso>. + <seealso marker="#upgrade_script/2"><c>upgrade_script/2</c></seealso>. This script is evaluated using - <seealso marker="#eval_appup_script/4">eval_appup_script/4</seealso>, + <seealso marker="#eval_appup_script/4"><c>eval_appup_script/4</c></seealso>, exactly in the same way as - <seealso marker="#install_release/1">install_release/1,2</seealso> + <seealso marker="#install_release/1"><c>install_release/1,2</c></seealso> does.</p> - <p>Returns <c>{ok, Unpurged}</c> if evaluating the script is - successful, where <c>Unpurged</c> is a list of unpurged - modules, or <c>restart_emulator</c> if this instruction is - encountered in the script, or <c>{error, Reason}</c> if - an error occurred when finding or evaluating the script.</p> + <p>Returns one of the following:</p> + <list type="bulleted"> + <item><c>{ok, Unpurged}</c> if evaluating the script is + successful, where <c>Unpurged</c> is a list of unpurged + modules</item> + <item><c>restart_emulator</c> if this instruction is + encountered in the script</item> + <item><c>{error, Reason}</c> if an error occurred when + finding or evaluating the script</item> + </list> <p>If the <c>restart_new_emulator</c> instruction is found in - the script, <c>upgrade_app/2</c> will return - <c>{error,restart_new_emulator}</c>. The reason for this is - that this instruction requires that a new version of the - emulator is started before the rest of the upgrade - instructions can be executed, and this can only be done by - <c>install_release/1,2</c>.</p> + the script, + <seealso marker="#upgrade_app/2"><c>upgrade_app/2</c></seealso> + returns <c>{error,restart_new_emulator}</c>. This because + <c>restart_new_emulator</c> requires a new version of the + emulator to be started before the rest of the upgrade + instructions can be executed, and this can only be done by + <seealso marker="#install_release/1"><c>install_release/1,2</c></seealso>.</p> </desc> </func> + <func> <name>downgrade_app(App, Dir) -></name> <name>downgrade_app(App, OldVsn, Dir) -> {ok, Unpurged} | restart_emulator | {error, Reason}</name> - <fsummary>Downgrade to a previous application version</fsummary> + <fsummary>Downgrades to a previous application version.</fsummary> <type> <v>App = atom()</v> <v>Dir = OldVsn = string()</v> @@ -549,110 +598,124 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). <desc> <p>Downgrades an application <c>App</c> from the current version to a previous version <c>OldVsn</c> located in - <c>Dir</c> according to the <c>.appup</c> script.</p> + <c>Dir</c> according to the <c>.appup</c> file.</p> <p><c>App</c> is the name of the application, which must be - started. <c>OldVsn</c> is the previous version of - the application and can be omitted if <c>Dir</c> is of + started. <c>OldVsn</c> is the previous application version + and can be omitted if <c>Dir</c> is of the format <c>"App-OldVsn"</c>. <c>Dir</c> is the library - directory of this previous version of <c>App</c>, - the corresponding modules as well as the old <c>.app</c> file - should be located under <c>Dir/ebin</c>. The <c>.appup</c> - file should be located in the <c>ebin</c> directory of + directory of the previous version of <c>App</c>. + The corresponding modules and the old <c>.app</c> file + are to be located under <c>Dir/ebin</c>. The <c>.appup</c> + file is to be located in the <c>ebin</c> directory of the <em>current</em> library directory of the application - (<c>code:lib_dir(App)</c>).</p> + (<seealso marker="kernel:code#lib_dir/1"><c>code:lib_dir(App)</c></seealso>).</p> <p>The function looks in the <c>.appup</c> file and tries to - find an downgrade script to the previous version of + find a downgrade script to the previous version of the application using - <seealso marker="#downgrade_script/3">downgrade_script/3</seealso>. + <seealso marker="#downgrade_script/3"><c>downgrade_script/3</c></seealso>. This script is evaluated using - <seealso marker="#eval_appup_script/4">eval_appup_script/4</seealso>, + <seealso marker="#eval_appup_script/4"><c>eval_appup_script/4</c></seealso>, exactly in the same way as - <seealso marker="#install_release/1">install_release/1,2</seealso> + <seealso marker="#install_release/1"><c>install_release/1,2</c></seealso> does.</p> - <p>Returns <c>{ok, Unpurged}</c> if evaluating the script is - successful, where <c>Unpurged</c> is a list of unpurged - modules, or <c>restart_emulator</c> if this instruction is - encountered in the script, or <c>{error, Reason}</c> if - an error occurred when finding or evaluating the script.</p> + <p>Returns one of the following:</p> + <list type="bulleted"> + <item><c>{ok, Unpurged}</c> if evaluating the script is + successful, where <c>Unpurged</c> is a list of unpurged + modules</item> + <item><c>restart_emulator</c> if this instruction is + encountered in the script</item> + <item><c>{error, Reason}</c> if an error occurred when + finding or evaluating the script</item> + </list> </desc> </func> + <func> <name>upgrade_script(App, Dir) -> {ok, NewVsn, Script}</name> - <fsummary>Find an application upgrade script</fsummary> + <fsummary>Finds an application upgrade script.</fsummary> <type> <v>App = atom()</v> <v>Dir = string()</v> <v>NewVsn = string()</v> - <v>Script = Instructions -- see appup(4)</v> + <v>Script = Instructions</v> </type> <desc> <p>Tries to find an application upgrade script for <c>App</c> from the current version to a new version located in <c>Dir</c>.</p> <p>The upgrade script can then be evaluated using - <seealso marker="#eval_appup_script/4">eval_appup_script/4</seealso>. + <seealso marker="#eval_appup_script/4"><c>eval_appup_script/4</c></seealso>. It is recommended to use - <seealso marker="#upgrade_app/2">upgrade_app/2</seealso> - instead, but this function is useful in order to inspect - the contents of the script.</p> + <seealso marker="#upgrade_app/2"><c>upgrade_app/2</c></seealso> + instead, but this function (<c>upgrade_script</c>) is useful + to inspect the contents of the script.</p> <p><c>App</c> is the name of the application, which must be started. <c>Dir</c> is the new library directory of - <c>App</c>, the corresponding modules as well as - the <c>.app</c> and <c>.appup</c> files should be located + <c>App</c>. The corresponding modules as well as + the <c>.app</c> and <c>.appup</c> files are to be located under <c>Dir/ebin</c>.</p> <p>The function looks in the <c>.appup</c> file and tries to - find an upgrade script from the current version of - the application. High-level instructions are translated to - low-level instructions and the instructions are sorted in - the same manner as when generating a <c>relup</c> script.</p> + find an upgrade script from the current application version. + High-level instructions are translated to + low-level instructions. The instructions are sorted in + the same manner as when generating a <c>relup</c> file.</p> <p>Returns <c>{ok, NewVsn, Script}</c> if successful, where - <c>NewVsn</c> is the new application version.</p> + <c>NewVsn</c> is the new application version. + For details about <c>Script</c>, see + <seealso marker="appup"><c>appup(4)</c></seealso>.</p> <p>Failure: If a script cannot be found, the function fails with an appropriate error reason.</p> </desc> </func> + <func> <name>downgrade_script(App, OldVsn, Dir) -> {ok, Script}</name> - <fsummary>Find an application downgrade script</fsummary> + <fsummary>Finds an application downgrade script.</fsummary> <type> <v>App = atom()</v> <v>OldVsn = Dir = string()</v> - <v>Script = Instructions -- see appup(4)</v> + <v>Script = Instructions</v> </type> <desc> <p>Tries to find an application downgrade script for <c>App</c> from the current version to a previous version <c>OldVsn</c> located in <c>Dir</c>.</p> <p>The downgrade script can then be evaluated using - <seealso marker="#eval_appup_script/4">eval_appup_script/4</seealso>. + <seealso marker="#eval_appup_script/4"><c>eval_appup_script/4</c></seealso>. It is recommended to use - <seealso marker="#downgrade_app/2">downgrade_app/2,3</seealso> - instead, but this function is useful in order to inspect - the contents of the script.</p> + <seealso marker="#downgrade_app/2"><c>downgrade_app/2,3</c></seealso> + instead, but this function (<c>downgrade_script</c>) is useful + to inspect the contents of the script.</p> <p><c>App</c> is the name of the application, which must be started. <c>Dir</c> is the previous library directory of - <c>App</c>, the corresponding modules as well as - the old <c>.app</c> file should be located under - <c>Dir/ebin</c>. The <c>.appup</c> file should be located in + <c>App</c>. The corresponding modules and + the old <c>.app</c> file are to be located under + <c>Dir/ebin</c>. The <c>.appup</c> file is to be located in the <c>ebin</c> directory of the <em>current</em> library - directory of the application (<c>code:lib_dir(App)</c>).</p> + directory of the application + (<seealso marker="kernel:code#lib_dir/1"><c>code:lib_dir(App)</c>)</seealso>.</p> <p>The function looks in the <c>.appup</c> file and tries to - find an downgrade script from the current version of - the application. High-level instructions are translated to - low-level instructions and the instructions are sorted in - the same manner as when generating a <c>relup</c> script.</p> - <p>Returns <c>{ok, Script}</c> if successful.</p> + find a downgrade script from the current application version. + High-level instructions are translated to + low-level instructions. The instructions are sorted in + the same manner as when generating a <c>relup</c> file.</p> + <p>Returns <c>{ok, Script}</c> if successful. + For details about <c>Script</c>, see + <seealso marker="appup"><c>appup(4)</c></seealso>.</p> <p>Failure: If a script cannot be found, the function fails with an appropriate error reason.</p> </desc> </func> + <func> <name>eval_appup_script(App, ToVsn, ToDir, Script) -> {ok, Unpurged} | restart_emulator | {error, Reason}</name> - <fsummary>Evaluate an application upgrade or downgrade script</fsummary> + <fsummary>Evaluates an application upgrade or downgrade script.</fsummary> <type> <v>App = atom()</v> <v>ToVsn = ToDir = string()</v> - <v>Script -- see upgrade_script/2, downgrade_script/3</v> + <v>Script</v> + <d>See <seealso marker="#upgrade_script/2"><c>upgrade_script/2</c></seealso>, <seealso marker="#downgrade_script/3"><c>downgrade_script/3</c></seealso></d> <v>Unpurged = [Module]</v> <v> Module = atom()</v> <v>Reason = term()</v> @@ -660,114 +723,100 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). <desc> <p>Evaluates an application upgrade or downgrade script <c>Script</c>, the result from calling - <seealso marker="#upgrade_app/2">upgrade_script/2</seealso> or - <seealso marker="#downgrade_app/3">downgrade_script/3</seealso>, + <seealso marker="#upgrade_script/2"><c>upgrade_script/2</c></seealso> or + <seealso marker="#downgrade_script/3"><c>downgrade_script/3</c></seealso>, exactly in the same way as - <seealso marker="#install_release/1">install_release/1,2</seealso> + <seealso marker="#install_release/1"><c>install_release/1,2</c></seealso> does.</p> <p><c>App</c> is the name of the application, which must be started. <c>ToVsn</c> is the version to be upgraded/downgraded to, and <c>ToDir</c> is the library directory of this version. The corresponding modules as well as the <c>.app</c> and - <c>.appup</c> files should be located under <c>Dir/ebin</c>.</p> - <p>Returns <c>{ok, Unpurged}</c> if evaluating the script is - successful, where <c>Unpurged</c> is a list of unpurged - modules, or <c>restart_emulator</c> if this instruction is - encountered in the script, or <c>{error, Reason}</c> if - an error occurred when evaluating the script.</p> - <p>If the <c>restart_new_emulator</c> instruction is found in - the script, <c>eval_appup_script/4</c> will return - <c>{error,restart_new_emulator}</c>. The reason for this is - that this instruction requires that a new version of the - emulator is started before the rest of the upgrade - instructions can be executed, and this can only be done by - <c>install_release/1,2</c>.</p> + <c>.appup</c> files are to be located under <c>Dir/ebin</c>.</p> + <p>Returns one of the following:</p> + <list type="bulleted"> + <item><c>{ok, Unpurged}</c> if evaluating the script is + successful, where <c>Unpurged</c> is a list of unpurged + modules</item> + <item><c>restart_emulator</c> if this instruction is + encountered in the script</item> + <item><c>{error, Reason}</c> if an error occurred when + finding or evaluating the script</item> + </list> + <p>If the <c>restart_new_emulator</c> instruction is found in + the script, + <seealso marker="#eval_appup_script/4"><c>eval_appup_script/4</c></seealso> + returns <c>{error,restart_new_emulator}</c>. This because + <c>restart_new_emulator</c> requires a new version of the + emulator to be started before the rest of the upgrade + instructions can be executed, and this can only be done by + <seealso marker="#install_release/1"><c>install_release/1,2</c></seealso>.</p> </desc> </func> </funcs> <section> <title>Typical Error Reasons</title> - <list type="bulleted"> - <item> - <p><c>{bad_masters, Masters}</c> - The master nodes - <c>Masters</c> are not alive.</p> - </item> - <item> - <p><c>{bad_rel_file, File}</c> - Specified <c>.rel</c> file - <c>File</c> can not be read, or does not contain a single - term.</p> - </item> - <item> - <p><c>{bad_rel_data, Data}</c> - Specified <c>.rel</c> file - does not contain a recognized release specification, but - another term <c>Data</c>.</p> - </item> - <item> - <p><c>{bad_relup_file, File}</c> - Specified <c>relup</c> file - <c>Relup</c> contains bad data.</p> - </item> - <item> - <p><c>{cannot_extract_file, Name, Reason}</c> - Problems when - extracting from a tar file, <c>erl_tar:extract/2</c> returned - <c>{error, {Name, Reason}}</c>.</p> - </item> - <item> - <p><c>{existing_release, Vsn}</c> - Specified release version - <c>Vsn</c> is already in use.</p> - </item> - <item> - <p><c>{Master, Reason, When}</c> - Some operation, indicated by - the term <c>When</c>, failed on the master node <c>Master</c> - with the specified error reason <c>Reason</c>.</p> - </item> - <item> - <p><c>{no_matching_relup, Vsn, CurrentVsn}</c> - Cannot find a - script for up/downgrading between <c>CurrentVsn</c> and - <c>Vsn</c>.</p> - </item> - <item> - <p><c>{no_such_directory, Path}</c> - The directory <c>Path</c> - does not exist.</p> - </item> - <item> - <p><c>{no_such_file, Path}</c> - The path <c>Path</c> (file or - directory) does not exist.</p> - </item> - <item> - <p><c>{no_such_file, {Master, Path}}</c> - The path <c>Path</c> - (file or directory) does not exist at the master node - <c>Master</c>.</p> - </item> - <item> - <p><c>{no_such_release, Vsn}</c> - The specified version - <c>Vsn</c> of the release does not exist.</p> - </item> - <item> - <p><c>{not_a_directory, Path}</c> - <c>Path</c> exists, but is - not a directory.</p> - </item> - <item> - <p><c>{Posix, File}</c> - Some file operation failed for - <c>File</c>. <c>Posix</c> is an atom named from the Posix - error codes, such as <c>enoent</c>, <c>eacces</c> or - <c>eisdir</c>. See <c>file(3)</c>.</p> - </item> - <item> - <p><c>Posix</c> - Some file operation failed, as above.</p> - </item> - </list> + <taglist> + <tag><c>{bad_masters, Masters}</c></tag> + <item><p>The master nodes <c>Masters</c> are not alive.</p></item> + <tag><c>{bad_rel_file, File}</c></tag> + <item><p>Specified <c>.rel</c> file <c>File</c> cannot be read or + does not contain a single term.</p></item> + <tag><c>{bad_rel_data, Data}</c></tag> + <item><p>Specified <c>.rel</c> file does not contain a recognized + release specification, but another term <c>Data</c>.</p></item> + <tag><c>{bad_relup_file, File}</c></tag> + <item><p>Specified <c>relup</c> file <c>Relup</c> contains bad + data.</p></item> + <tag><c>{cannot_extract_file, Name, Reason}</c></tag> + <item><p>Problems when extracting from a tar file, + <seealso marker="stdlib:erl_tar#extract/2"><c>erl_tar:extract/2</c></seealso> + returned <c>{error, {Name, Reason}}</c>.</p></item> + <tag><c>{existing_release, Vsn}</c></tag> + <item><p>Specified release version <c>Vsn</c> is already + in use.</p></item> + <tag><c>{Master, Reason, When}</c></tag> + <item><p>Some operation, indicated by the term <c>When</c>, failed + on the master node <c>Master</c> with the specified error + reason <c>Reason</c>.</p></item> + <tag><c>{no_matching_relup, Vsn, CurrentVsn}</c></tag> + <item><p>Cannot find a script for upgrading/downgrading between + <c>CurrentVsn</c> and <c>Vsn</c>.</p></item> + <tag><c>{no_such_directory, Path}</c></tag> + <item><p>The directory <c>Path</c>does not exist.</p></item> + <tag><c>{no_such_file, Path}</c></tag> + <item><p>The path <c>Path</c> (file or directory) does not + exist.</p></item> + <tag><c>{no_such_file, {Master, Path}}</c></tag> + <item><p>The path <c>Path</c> (file or directory) does not exist at + the master node <c>Master</c>.</p></item> + <tag><c>{no_such_release, Vsn}</c></tag> + <item><p>The specified release version <c>Vsn</c> does not + exist.</p></item> + <tag><c>{not_a_directory, Path}</c></tag> + <item><p><c>Path</c> exists but is not a directory.</p></item> + <tag><c>{Posix, File}</c></tag> + <item><p>Some file operation failed for <c>File</c>. <c>Posix</c> + is an atom named from the Posix error codes, such as + <c>enoent</c>, <c>eacces</c>, or <c>eisdir</c>. See + <seealso marker="kernel:file"><c>file(3)</c></seealso> + in <c>Kernel</c>.</p></item> + <tag><c>Posix</c></tag> + <item><p>Some file operation failed, as for the previous item in + the list.</p></item> + </taglist> </section> <section> - <title>SEE ALSO</title> - <p><seealso marker="doc/design_principles:release_handling">OTP Design Principles</seealso>, - <seealso marker="kernel:config">config(4)</seealso>, - <seealso marker="relup">relup(4)</seealso>, - <seealso marker="rel">rel(4)</seealso>, - <seealso marker="script">script(4)</seealso>, - <seealso marker="stdlib:sys">sys(3)</seealso>, - <seealso marker="systools">systools(3)</seealso></p> + <title>See Also</title> + <p><seealso marker="doc/design_principles:users_guide">OTP Design Principles</seealso>, + <seealso marker="kernel:config"><c>config(4)</c></seealso>, + <seealso marker="rel"><c>rel(4)</c></seealso>, + <seealso marker="relup"><c>relup(4)</c></seealso>, + <seealso marker="script"><c>script(4)</c></seealso>, + <seealso marker="stdlib:sys"><c>sys(3)</c></seealso>, + <seealso marker="systools"><c>systools(3)</c></seealso></p> </section> </erlref> diff --git a/lib/sasl/doc/src/relup.xml b/lib/sasl/doc/src/relup.xml index 8eecf3fce2..58918fc8e8 100644 --- a/lib/sasl/doc/src/relup.xml +++ b/lib/sasl/doc/src/relup.xml @@ -36,59 +36,53 @@ <p>The <em>release upgrade file</em> describes how a release is upgraded in a running system.</p> <p>This file is automatically generated by - <c>systools:make_relup/3,4</c>, using a release resource file - (<c>.rel</c>), application resource files (<c>.app</c>) and + <seealso marker="systools#make_relup/3"><c>systools:make_relup/3,4</c></seealso>, + using a release resource file + (<c>.rel</c>), application resource files (<c>.app</c>), and application upgrade files (<c>.appup</c>) as input.</p> </description> <section> - <title>FILE SYNTAX</title> - <p>In a target system, the release upgrade file should be located in - the <c>OTP_ROOT/erts-EVsn/Vsn</c> directory.</p> + <title>File Syntax</title> + <p>In a target system, the release upgrade file is to be located in + directory <c>$ROOT/releases/Vsn</c>.</p> <p>The <c>relup</c> file contains one single Erlang term, which defines the instructions used to upgrade the release. The file has the following syntax:</p> <code type="none"> {Vsn, [{UpFromVsn, Descr, Instructions}, ...], - [{DownToVsn, Descr, Instructions}, ...]}. - </code> - <list type="bulleted"> - <item> - <p><c>Vsn = string()</c> is the current version of the release.</p> - </item> - <item> - <p><c>UpFromVsn = string()</c> is an earlier version of the release - to upgrade from.</p> - </item> - <item> - <p><c>Descr = term()</c> is a user defined parameter passed - from the <c>systools:make_relup/3,4</c> function. It will - be used in the return value of - <c>release_handler:install_release/1,2</c>.</p> - </item> - <item> - <p><c>Instructions</c> is a list of low-level release upgrade - instructions, see <c>appup(4)</c>.</p> - <p>It consists of the release upgrade instructions from + [{DownToVsn, Descr, Instructions}, ...]}.</code> + <taglist> + <tag><c>Vsn = string()</c></tag> + <item><p>Current release version.</p></item> + <tag><c>UpFromVsn = string()</c></tag> + <item><p>Earlier version of the release to upgrade from.</p></item> + <tag><c>Descr = term()</c></tag> + <item><p>A user-defined parameter passed + from the function + <seealso marker="systools#make_relup/3"><c>systools:make_relup/3,4</c></seealso>. + It is used in the return value of + <seealso marker="release_handler#install_release/1"><c>release_handler:install_release/1,2</c></seealso>.</p></item> + <tag><c>Instructions</c></tag> + <item><p>A list of low-level release upgrade instructions, see + <seealso marker="appup"><c>appup(4)</c></seealso>. + It consists of the release upgrade instructions from the respective application upgrade files (high-level instructions are translated to low-level instructions), in the same order - as in the start script.</p> - </item> - <item> - <p><c>DownToVsn = string()</c> is an earlier version of the release - to downgrade to.</p> - </item> - </list> - <p>When upgrading from <c>UpFromVsn</c> with - <c>release_handler:install_release/1,2</c>, there does not have to be - an exact match of versions, but <c>UpFromVsn</c> can be a sub-string - of the current release version.</p> + as in the start script.</p></item> + <tag><c>DownToVsn = string()</c></tag> + <item><p>Earlier version of the release to downgrade to.</p></item> + </taglist> </section> <section> - <title>SEE ALSO</title> - <p>app(4), appup(4), rel(4), release_handler(3), systools(3)</p> + <title>See Also</title> + <p><seealso marker="kernel:app"><c>app(4)</c></seealso>, + <seealso marker="appup"><c>appup(4)</c></seealso>, + <seealso marker="rel"><c>rel(4)</c></seealso>, + <seealso marker="release_handler"><c>release_handler(3)</c></seealso>, + <seealso marker="systools"><c>systools(3)</c></seealso></p> </section> </fileref> diff --git a/lib/sasl/doc/src/sasl_app.xml b/lib/sasl/doc/src/sasl_app.xml index 7cdb3e2ca7..bcd446a868 100644 --- a/lib/sasl/doc/src/sasl_app.xml +++ b/lib/sasl/doc/src/sasl_app.xml @@ -27,143 +27,163 @@ <docno></docno> <date></date> <rev></rev> - </header> - <app>sasl</app> - <appsummary>The SASL Application</appsummary> - <description> - <p>This section describes the SASL (System Architecture Support Libraries) - application which provides the following services:</p> + </header> + <app>sasl</app> + <appsummary>The SASL application</appsummary> + <description> + <p>The <c>SASL</c> application provides the following services:</p> <list type="bulleted"> <item><c>alarm_handler</c></item> - <item><c>overload</c></item> + <item><c>overload</c> (deprecated)</item> <item><c>rb</c></item> <item><c>release_handler</c></item> <item><c>systools</c></item> </list> - <p>The SASL application also includes <c>error_logger</c> event - handlers for formatting SASL error and crash reports.</p> - + <p>The <c>SASL</c> application also includes <c>error_logger</c> event + handlers for formatting <c>SASL</c> error and crash reports.</p> <note> - <p>The SASL application in OTP has nothing to do with + <p>The <c>SASL</c> application in OTP has nothing to do with "Simple Authentication and Security Layer" (RFC 4422).</p> </note> - </description> <section> <title>Error Logger Event Handlers</title> <p>The following error logger event handlers are used by - the SASL application.</p> + the <c>SASL</c> application.</p> <taglist> <tag><c>sasl_report_tty_h</c></tag> <item> - <p>Formats and writes <em>supervisor reports</em>, <em>crash reports</em> and <em>progress reports</em> to <c>stdio</c>.</p> + <p>Formats and writes <em>supervisor reports</em>, <em>crash + reports</em>, and <em>progress reports</em> to <c>stdio</c>. + This error logger event handler uses + <seealso marker="kernel:kernel_app#error_logger_format_depth">error_logger_format_depth</seealso> + in the <c>Kernel</c> application to limit how much detail is + printed in crash and supervisor reports.</p> </item> <tag><c>sasl_report_file_h</c></tag> <item> - <p>Formats and writes <em>supervisor reports</em>, <em>crash report</em> and <em>progress report</em> to a single file.</p> + <p>Formats and writes <em>supervisor reports</em>, <em>crash + report</em>, and <em>progress report</em> to a single file. + This error logger event handler uses + <seealso marker="kernel:kernel_app#error_logger_format_depth">error_logger_format_depth</seealso> + in the <c>Kernel</c> application to limit the details + printed in crash and supervisor reports.</p> </item> <tag><c>log_mf_h</c></tag> <item> - <p>This error logger writes <em>all</em> events sent to - the error logger to disk.</p> - <p>To activate this event handler, the following three sasl - configuration parameters must be set: - <c>error_logger_mf_dir</c>, <c>error_logger_mf_maxbytes</c> - and <c>error_logger_mf_maxfiles</c>. See below for more - information about the configuration parameters.</p> + <p>This error logger writes <em>all</em> events sent to the + error logger to disk. Multiple files and log rotation are + used. For efficiency reasons, each event is written as a + binary. For more information about this handler, + see <seealso marker="stdlib:log_mf_h">the <c>STDLIB</c> Reference + Manual</seealso>.</p> + <p>To activate this event handler, three <c>SASL</c> + configuration parameters must be set, + <c>error_logger_mf_dir</c>, <c>error_logger_mf_maxbytes</c>, + and <c>error_logger_mf_maxfiles</c>. The next section provides + more information about the configuration parameters.</p> </item> </taglist> </section> <section> <title>Configuration</title> - <p>The following configuration parameters are defined for the SASL - application. See <c>app(4)</c> for more information about - configuration parameters:</p> + <p>The following configuration parameters are defined for the <c>SASL</c> + application. For more information about configuration parameters, see + <seealso marker="kernel:app"><c>app(4)</c></seealso> in <c>Kernel</c>.</p> + <p>All configuration parameters are optional.</p> <taglist> - <tag><c><![CDATA[sasl_error_logger = Value <optional>]]></c></tag> + <tag><c><![CDATA[sasl_error_logger = Value ]]></c></tag> <item> - <p><c>Value</c> is one of:</p> + <p><c>Value</c> is one of the following:</p> <taglist> <tag><c>tty</c></tag> - <item>Installs <c>sasl_report_tty_h</c> in the error logger. - This is the default option.</item> + <item><p>Installs <c>sasl_report_tty_h</c> in the error logger. + This is the default option.</p></item> <tag><c>{file,FileName}</c></tag> - <item>Installs <c>sasl_report_file_h</c> in the error logger. - This makes all reports go to the file <c>FileName</c>. - <c>FileName</c> is a string.</item> + <item><p>Installs <c>sasl_report_file_h</c> in the error logger. + All reports go to file <c>FileName</c>, which is a + string.</p></item> <tag><c>{file,FileName,Modes}</c></tag> - <item>Same as <c>{file,FileName}</c> except that the <c>Modes</c> - allows to specify the modes used for opening the <c>FileName</c> - given to the <seealso marker="kernel:file#open/2">file:open/2</seealso> - call. When not specified, the <c>Modes</c> defaults to <c>[write]</c>. - Use <c>[append]</c> for having the <c>FileName</c> open in append mode. - <c>FileName</c> is a string.</item> + <item><p>Same as <c>{file,FileName}</c>, except that <c>Modes</c> + allows you to specify the modes used for opening the <c>FileName</c> + given to the <seealso marker="kernel:file#open/2">file:open/2</seealso> + call. When not specified, <c>Modes</c> defaults to <c>[write]</c>. + Use <c>[append]</c> to have the <c>FileName</c> open in append mode. + <c>FileName</c> is a string.</p></item> <tag><c>false</c></tag> - <item> - <p>No SASL error logger handler is installed.</p> - </item> + <item><p>No <c>SASL</c> error logger handler is installed.</p></item> </taglist> </item> - <tag><c><![CDATA[errlog_type = error | progress | all <optional>]]></c></tag> + <tag><c><![CDATA[errlog_type = error | progress | all ]]></c></tag> <item> <p>Restricts the error logging performed by the specified - <c>sasl_error_logger</c> to error reports, progress reports, + <c>sasl_error_logger</c> to error reports or progress reports, or both. Default is <c>all</c>.</p> </item> - <tag><c><![CDATA[error_logger_mf_dir = string() | false<optional>]]></c></tag> + <tag><c><![CDATA[error_logger_mf_dir = string() | false ]]></c></tag> <item> - <p>Specifies in which directory the files are stored. If this - parameter is undefined or <c>false</c>, + <p>Specifies in which directory <c>log_mf_h</c> is to store + its files. If this parameter is undefined or <c>false</c>, the <c>log_mf_h</c> handler is not installed.</p> </item> - <tag><c><![CDATA[error_logger_mf_maxbytes = integer() <optional>]]></c></tag> + <tag><c><![CDATA[error_logger_mf_maxbytes = integer() ]]></c></tag> <item> - <p>Specifies how large each individual file can be. If this - parameter is undefined, the <c>log_mf_h</c> handler is not - installed.</p> + <p>Specifies the maximum size of each individual file written + by <c>log_mf_h</c>. If this parameter is undefined, + the <c>log_mf_h</c> handler is not installed.</p> </item> - <tag><c><![CDATA[error_logger_mf_maxfiles = 0<integer()<256 <optional>]]></c></tag> + <tag><c><![CDATA[error_logger_mf_maxfiles = 0<integer()<256 ]]></c></tag> <item> - <p>Specifies how many files are used. If this parameter is - undefined, the <c>log_mf_h</c> handler is not installed.</p> + <p>Specifies the number of files used by <c>log_mf_h</c>. If + this parameter is undefined, the <c>log_mf_h</c> handler is + not installed.</p> </item> - <tag><c><![CDATA[overload_max_intensity = float() > 0 <optional>]]></c></tag> + <tag><c><![CDATA[overload_max_intensity = float() > 0 ]]></c></tag> <item> - <p>Specifies the maximum intensity for <c>overload</c>. Default + <p>Specifies the maximum intensity + for <seealso marker="overload"><c>overload</c></seealso>. Default is <c>0.8</c>.</p> + <p>Note that the <c>overload</c> module is deprected and + will be removed in a future release.</p> </item> - <tag><c><![CDATA[overload_weight = float() > 0 <optional>]]></c></tag> + <tag><c><![CDATA[overload_weight = float() > 0 ]]></c></tag> <item> - <p>Specifies the <c>overload</c> weight. Default is <c>0.1</c>.</p> + <p>Specifies the <seealso marker="overload"><c>overload</c></seealso> + weight. Default is <c>0.1</c>.</p> + <p>Note that the <c>overload</c> module is deprected and + will be removed in a future release.</p> </item> - <tag><c><![CDATA[start_prg = string() <optional>]]></c></tag> + <tag><c><![CDATA[start_prg = string() ]]></c></tag> <item> - <p>Specifies which program should be used when restarting - the system. Default is <c>$OTP_ROOT/bin/start</c>.</p> + <p>Specifies the program to be used when restarting the system + during release installation. Default is + <c>$OTP_ROOT/bin/start</c>.</p> </item> - <tag><c><![CDATA[masters = [atom()] <optional>]]></c></tag> + <tag><c><![CDATA[masters = [atom()] ]]></c></tag> <item> - <p>Specifies which nodes this node uses to read/write release - information. This parameter is ignored if - the <c>client_directory</c> parameter is not set.</p> + <p>Specifies the nodes used by this node to read/write release + information. This parameter is ignored if parameter + <c>client_directory</c> is not set.</p> </item> - <tag><c><![CDATA[client_directory = string() <optional>]]></c></tag> + <tag><c><![CDATA[client_directory = string() ]]></c></tag> <item> <p>This parameter specifies the client directory at the master - nodes. Refer to Release Handling in <em>OTP Design Principles</em> for more information. This parameter is - ignored if the <c>masters</c> parameter is not set.</p> + nodes. For details, see + <seealso marker="doc/design_principles:release_handling">Release Handling</seealso> + in <em>OTP Design Principles</em>. This parameter is + ignored if parameter <c>masters</c> is not set.</p> </item> - <tag><c><![CDATA[static_emulator = true | false <optional>]]></c></tag> + <tag><c><![CDATA[static_emulator = true | false ]]></c></tag> <item> <p>Indicates if the Erlang emulator is statically installed. A node with a static emulator cannot switch dynamically to a - new emulator as the executable files are written into memory - statically. This parameter is ignored if the <c>masters</c> - and <c>client_directory</c> parameters are not set.</p> + new emulator, as the executable files are written into memory + statically. This parameter is ignored if parameters <c>masters</c> + and <c>client_directory</c> are not set.</p> </item> - <tag><c><![CDATA[releases_dir = string() <optional>]]></c></tag> + <tag><c><![CDATA[releases_dir = string() ]]></c></tag> <item> <p>Indicates where the <c>releases</c> directory is located. The release handler writes all its files to this directory. @@ -171,7 +191,7 @@ <c>RELDIR</c> is used. By default, this is <c>$OTP_ROOT/releases</c>.</p> </item> - <tag><c><![CDATA[utc_log = true | false <optional>]]></c></tag> + <tag><c><![CDATA[utc_log = true | false ]]></c></tag> <item> <p>If set to <c>true</c>, all dates in textual log outputs are displayed in Universal Coordinated Time with the string @@ -182,13 +202,13 @@ <section> <title>See Also</title> - <p><seealso marker="alarm_handler">alarm_handler(3)</seealso>, - error_logger(3), - log_mf_h(3), - <seealso marker="overload">overload(3)</seealso>, - <seealso marker="rb">rb(3)</seealso>, - <seealso marker="release_handler">release_handler(3)</seealso>, - <seealso marker="systools">systools(3)</seealso></p> + <p><seealso marker="alarm_handler"><c>alarm_handler(3)</c></seealso>, + <seealso marker="kernel:error_logger"><c>error_logger(3)</c></seealso>, + <seealso marker="stdlib:log_mf_h"><c>log_mf_h(3)</c></seealso>, + <seealso marker="overload"><c>overload(3)</c></seealso>, + <seealso marker="rb"><c>rb(3)</c></seealso>, + <seealso marker="release_handler"><c>release_handler(3)</c></seealso>, + <seealso marker="systools"><c>systools(3)</c></seealso></p> </section> </appref> diff --git a/lib/sasl/doc/src/sasl_intro.xml b/lib/sasl/doc/src/sasl_intro.xml index 2dc3efebc1..bbc9457103 100644 --- a/lib/sasl/doc/src/sasl_intro.xml +++ b/lib/sasl/doc/src/sasl_intro.xml @@ -31,22 +31,32 @@ </header> <section> - <title>About This Document</title> - <p>The SASL (System Architecture Support Libraries) - application provides support for:</p> + <title>Scope</title> + <p>The <c>SASL</c> application provides support for:</p> <list type="bulleted"> - <item>error logging</item> - <item>alarm handling</item> - <item>overload regulation</item> - <item>release handling</item> - <item>report browsing.</item> + <item>Error logging</item> + <item>Alarm handling</item> + <item>Overload regulation</item> + <item>Release handling</item> + <item>Report browsing</item> </list> - <p>In this document, "SASL Error Logging" describes the error - handler which produces the supervisor, progress, and crash - reports which can be written to screen, or to a specified file. - It also describes the report browser <c>rb</c>.</p> - <p>The chapters about release structure and release handling have - been moved to <em>OTP Design Principles</em>.</p> + <p>Section + <seealso marker="error_logging">SASL Error Logging</seealso> + describes the error + handler that produces the supervisor, progress, and crash + reports, which can be written to screen or to a specified file. + It also describes the Report Browser (RB).</p> + <p>The sections about release structure and release handling have + been moved to section + <seealso marker="doc/design_principles:users_guide">OTP Design Principles</seealso> + in <em>System Documentation</em>.</p> </section> + + <section> + <title>Prerequisites</title> + <p>It is assumed that the reader is familiar with the Erlang + programming language.</p> + </section> + </chapter> diff --git a/lib/sasl/doc/src/script.xml b/lib/sasl/doc/src/script.xml index 838efe69bb..db3ea0f487 100644 --- a/lib/sasl/doc/src/script.xml +++ b/lib/sasl/doc/src/script.xml @@ -37,25 +37,21 @@ <file>script</file> <filesummary>Boot script</filesummary> <description> - <p>The <em>boot script</em> describes how the Erlang runtime system is - started. It contains instructions on which code to load and - which processes and applications to start. - </p> - <p>The command <c>erl -boot Name</c> starts the system with a boot + <p>The <em>boot script</em> describes how the Erlang runtime system + is started. It contains instructions on which code to load and + which processes and applications to start.</p> + <p>Command <c>erl -boot Name</c> starts the system with a boot file called <c>Name.boot</c>, which is generated from the - <c>Name.script</c> file, using <c>systools:script2boot/1</c>. - </p> + <c>Name.script</c> file, using + <seealso marker="systools#script2boot/1"><c>systools:script2boot/1</c></seealso>.</p> <p>The <c>.script</c> file is generated by <c>systools</c> from a - <c>.rel</c> file and <c>.app</c> files. - </p> + <c>.rel</c> file and from <c>.app</c> files.</p> </description> <section> - <title>FILE SYNTAX</title> - <p>The boot script is stored in a file with the extension - <c>.script</c></p> - <p>The file has the following syntax: - </p> + <title>File Syntax</title> + <p>The boot script is stored in a file with extension + <c>.script</c>. The file has the following syntax:</p> <code type="none"> {script, {Name, Vsn}, [ @@ -70,100 +66,97 @@ ... {apply, {Mod, Func, Args}}, ... - {progress, started}]}. </code> - <list type="bulleted"> - <item><c>Name = string()</c> defines the name of the system. - </item> - <item><c>Vsn = string()</c> defines the version of the system. - </item> - <item><c>{progress, Term}</c> sets the "progress" of the - initialization program. The function <c>init:get_status()</c> - returns the current value of the progress, which is - <c>{InternalStatus,Term}</c>. - </item> - <item> - <p><c>{path, [Dir]}</c> where <c>Dir</c> is a string. This + {progress, started}]}.</code> + <taglist> + <tag><c>Name = string()</c></tag> + <item><p>Defines the system name.</p></item> + <tag><c>Vsn = string()</c></tag> + <item><p>Defines the system version.</p></item> + <tag><c>{progress, Term}</c></tag> + <item><p>Sets the "progress" of the initialization + program. The + <seealso marker="erts:init#get_status/0"><c>init:get_status/0</c></seealso> + function returns the current value of the progress, which is + <c>{InternalStatus,Term}</c>.</p></item> + <tag><c>{path, [Dir]}</c></tag> + <item><p><c>Dir</c> is a string. This argument sets the load path of the system to <c>[Dir]</c>. The load path used to load modules is obtained from the initial load path, which is given in the script file, together with - any path flags which were supplied in the command line - arguments. The command line arguments modify the path as + any path flags that were supplied in the command-line + arguments. The command-line arguments modify the path as follows:</p> <list type="bulleted"> <item><c>-pa Dir1 Dir2 ... DirN</c> adds the directories <c>Dir1, Dir2, ..., DirN</c> to the front of the initial - load path. - </item> + load path.</item> <item><c>-pz Dir1 Dir2 ... DirN</c> adds the directories <c>Dir1, Dir2, ..., DirN</c> to the end of the initial - load path. - </item> + load path.</item> <item> <p><c>-path Dir1 Dir2 ... DirN</c> defines a set of - directories <c>Dir1, Dir2, ..., DirN</c> which replaces + directories <c>Dir1, Dir2, ..., DirN</c>, which replace the search path given in the script file. Directory names in the path are interpreted as follows:</p> <list type="bulleted"> <item>Directory names starting with <c>/</c> are assumed - to be absolute path names. - </item> + to be absolute path names.</item> <item>Directory names not starting with <c>/</c> are - assumed to be relative the current working directory. - </item> + assumed to be relative the current working directory.</item> <item>The special <c>$ROOT</c> variable can only be used - in the script, not as a command line argument. The + in the script, not as a command-line argument. The given directory is relative the Erlang installation - directory. - </item> + directory.</item> </list> </item> </list> - </item> - <item><c>{primLoad, [Mod]}</c> loads the modules <c>[Mod]</c> - from the directories specified in <c>Path</c>. The script - interpreter fetches the appropriate module by calling the - function <c>erl_prim_loader:get_file(Mod)</c>. A fatal error - which terminates the system will occur if the module cannot be - located. - </item> - <item><c>{kernel_load_completed}</c> indicates that all modules - which <em>must</em> be loaded <em>before</em> any processes - are started are loaded. In interactive mode, all - <c>{primLoad,[Mod]}</c> commands interpreted after this - command are ignored, and these modules are loaded on demand. - In embedded mode, <c>kernel_load_completed</c> is ignored, and - all modules are loaded during system start. - </item> - <item><c>{kernelProcess, Name, {Mod, Func, Args}}</c> starts a - "kernel process". The kernel process <c>Name</c> is started - by evaluating <c>apply(Mod, Func, Args)</c> which is expected - to return <c>{ok, Pid}</c> or <c>ignore</c>. The <c>init</c> - process monitors the behaviour of <c>Pid</c> and terminates - the system if <c>Pid</c> dies. Kernel processes are key - components of the runtime system. Users do not normally add - new kernel processes. - </item> - <item><c>{apply, {Mod, Func, Args}}</c>. The init process simply - evaluates <c>apply(Mod, Func, Args)</c>. The system - terminates if this results in an error. The boot procedure - hangs if this function never returns. - </item> - </list> + </item> + <tag><c>{primLoad, [Mod]}</c></tag> + <item><p>Loads the modules <c>[Mod]</c> + from the directories specified in <c>Path</c>. The script + interpreter fetches the appropriate module by calling + <seealso marker="erts:erl_prim_loader#get_file/1"> + <c>erl_prim_loader:get_file(Mod)</c></seealso>. A fatal error + that terminates the system occurs if the module cannot be + located.</p></item> + <tag><c>{kernel_load_completed}</c></tag> + <item><p>Indicates that all modules + that <em>must</em> be loaded <em>before</em> any processes + are started are loaded. In interactive mode, all + <c>{primLoad,[Mod]}</c> commands interpreted after this + command are ignored, and these modules are loaded on demand. + In embedded mode, <c>kernel_load_completed</c> is ignored, and + all modules are loaded during system start.</p></item> + <tag><c>{kernelProcess, Name, {Mod, Func, Args}}</c></tag> + <item><p>Starts the + "kernel process" <c>Name</c> + by evaluating <c>apply(Mod, Func, Args)</c>. The start function is + to return <c>{ok, Pid}</c> or <c>ignore</c>. The <c>init</c> + process monitors the behavior of <c>Pid</c> and terminates + the system if <c>Pid</c> dies. Kernel processes are key + components of the runtime system. Users do not normally add + new kernel processes.</p></item> + <tag><c>{apply, {Mod, Func, Args}}</c>.</tag> + <item><p>The init process + evaluates <c>apply(Mod, Func, Args)</c>. The system + terminates if this results in an error. The boot procedure + hangs if this function never returns.</p></item> + </taglist> <note> - <p>In the <c>interactive</c> system the code loader provides - demand driven code loading, but in the <c>embedded</c> system - the code loader loads all the code immediately. The same - version of <c>code</c> is used in both cases. The code server - calls <c>init:get_argument(mode)</c> to find out if it should - run in demand mode, or non-demand driven mode. - </p> + <p>In an interactive system, the code loader provides + demand-driven code loading, but in an embedded system + the code loader loads all code immediately. The same + version of <seealso marker="kernel:code"><c>code</c></seealso> + is used in both cases. The code server calls + <seealso marker="erts:init#get_argument/1"><c>init:get_argument(mode)</c></seealso> + to determine if it is to run in demand mode or non-demand + driven mode.</p> </note> </section> <section> - <title>SEE ALSO</title> - <p>systools(3) - </p> + <title>See Also</title> + <p><seealso marker="systools"><c>systools(3)</c></seealso></p> </section> </fileref> diff --git a/lib/sasl/doc/src/systools.xml b/lib/sasl/doc/src/systools.xml index 11d99fa595..1a5119a5cf 100644 --- a/lib/sasl/doc/src/systools.xml +++ b/lib/sasl/doc/src/systools.xml @@ -31,17 +31,18 @@ <rev></rev> </header> <module>systools</module> - <modulesummary>A Set of Release Handling Tools.</modulesummary> + <modulesummary>A Set of Release Handling Tools</modulesummary> <description> <p>This module contains functions to generate boot scripts - (<c>.boot</c>, <c>.script</c>), release upgrade scripts + (<c>.boot</c>, <c>.script</c>), a release upgrade file (<c>relup</c>), and release packages.</p> </description> + <funcs> <func> <name>make_relup(Name, UpFrom, DownTo) -> Result</name> <name>make_relup(Name, UpFrom, DownTo, [Opt]) -> Result</name> - <fsummary>Generate a release upgrade file <c>relup</c>.</fsummary> + <fsummary>Generates a release upgrade file <c>relup</c>.</fsummary> <type> <v>Name = string()</v> <v>UpFrom = DownTo = [Name | {Name,Descr}]</v> @@ -50,93 +51,94 @@ | warnings_as_errors</v> <v> Dir = string()</v> <v>Result = ok | error | {ok,Relup,Module,Warnings} | {error,Module,Error}</v> - <v> Relup - see relup(4)</v> + <v> Relup, see relup(4)</v> <v> Module = atom()</v> <v> Warnings = Error = term()</v> </type> <desc> - <p>Generates a release upgrade file <c>relup</c> containing a - script which describes how to upgrade the system from a number - of previous releases, and how to downgrade to a number of - previous releases. The script is used by - <c>release_handler</c> when installing a new version of a - release in run-time.</p> - <p>By default, <c>relup</c> is placed in the current working - directory. If the option <c>{outdir,Dir}</c> is provided, - <c>relup</c> is placed in <c>Dir</c> instead.</p> + <p>Generates a release upgrade file <c>relup</c> containing instructions + for upgrading from or downgrading to one or more previous releases. + The instructions are used by + <seealso marker="release_handler"><c>release_handler</c></seealso> + when installing a new version of a release in runtime.</p> + <p>By default, <c>relup</c> file is located in the current working + directory. If option <c>{outdir,Dir}</c> is specified, + the <c>relup</c> file is located in <c>Dir</c> instead.</p> <p>The release resource file <c>Name.rel</c> is compared with - all release resource files <c>Name2.rel</c> specified in - <c>UpFrom</c> and <c>DownTo</c>. For each such pair, it is - deducted:</p> + all release resource files <c>Name2.rel</c>, specified in + <c>UpFrom</c> and <c>DownTo</c>. For each such pair, the + following is deducted:</p> <list type="bulleted"> <item> - <p>Which applications should be deleted, that is - applications which are listed in <c>Name.rel</c> but not - in <c>Name2.rel</c>.</p> + <p>Which applications to be deleted, that is, + applications listed in <c>Name.rel</c> but not + in <c>Name2.rel</c></p> </item> <item> - <p>Which applications should be added, that is applications - which are listed in <c>Name2.rel</c> but not in - <c>Name.rel</c>.</p> + <p>Which applications to be added, that is, applications + listed in <c>Name2.rel</c> but not in <c>Name.rel</c></p> </item> <item> - <p>Which applications should be upgraded/downgraded, that - is applications listed in both <c>Name.rel</c> and - <c>Name2.rel</c>, but with different versions.</p> + <p>Which applications to be upgraded/downgraded, that + is, applications listed in both <c>Name.rel</c> and + <c>Name2.rel</c> but with different versions</p> </item> <item> <p>If the emulator needs to be restarted after upgrading or - downgrading, that is if the ERTS version differs between - <c>Name.rel</c> and <c>Name2.rel</c>.</p> + downgrading, that is, if the <c>ERTS</c> version differs + between <c>Name.rel</c> and <c>Name2.rel</c></p> </item> </list> - <p>Instructions for this are added to the <c>relup</c> script in + <p>Instructions for this are added to the <c>relup</c> file in the above order. Instructions for upgrading or downgrading between application versions are fetched from the relevant application upgrade files <c>App.appup</c>, sorted in the same order as when generating a boot script, see - <c>make_script/1,2</c>. High-level instructions are translated - into low-level instructions and the result is printed to - <c>relup</c>.</p> - <p>The optional <c>Descr</c> parameter is included as-is in - the <c>relup</c> script, see <c>relup(4)</c>. Defaults to + <seealso marker="#make_script/1"><c>make_script/1,2</c></seealso>. + High-level instructions are translated + into low-level instructions and the result is printed to the + <c>relup</c> file.</p> + <p>The optional <c>Descr</c> parameter is included "as is" in + the <c>relup</c> file, see + <seealso marker="relup"><c>relup(4)</c></seealso>. Defaults to the empty list.</p> <p>All the files are searched for in the code path. It is - assumed that the <c>.app</c> and <c>.appup</c> file for an - application is located in the same directory.</p> - <p>If the option <c>{path,[Dir]}</c> is provided, this path is - appended to the current path. The wildcard <c>*</c> is - expanded to all matching directories. - Example: <c>lib/*/ebin</c>.</p> - <p>If the <c>restart_emulator</c> option is supplied, a + assumed that the <c>.app</c> and <c>.appup</c> files for an + application are located in the same directory.</p> + <p>If option <c>{path,[Dir]}</c> is specified, this path is + appended to the current path. Wildcard <c>*</c> is + expanded to all matching directories, for example, + <c>lib/*/ebin</c>.</p> + <p>If option <c>restart_emulator</c> is specified, a low-level instruction to restart the emulator is appended to - the relup scripts. This ensures that a complete reboot of + the <c>relup</c> file. This ensures that a complete reboot of the system is done when the system is upgraded or downgraded.</p> - <p>If an upgrade includes a change from an emulator earlier - than OTP R15 to OTP R15 or later, the warning - <c>pre_R15_emulator_upgrade</c> is issued. See <seealso - marker="doc/design_principles:appup_cookbook">Design - Principles</seealso> for more information about this.</p> + <p>If an upgrade includes a change from an emulator earlier + than OTP R15 to OTP R15 or later, the warning + <c>pre_R15_emulator_upgrade</c> is issued. For more information + about this, see + <seealso marker="doc/design_principles:appup_cookbook">Design + Principles</seealso> in <em>System Documentation</em>.</p> <p>By default, errors and warnings are printed to tty and - the function returns <c>ok</c> or <c>error</c>. If the option - <c>silent</c> is provided, the function instead returns - <c>{ok,Relup,Module,Warnings}</c> where <c>Relup</c> is - the release upgrade script, or it returns - <c>{error,Module,Error}</c>. Warnings and errors can be - converted to strings by calling + the function returns <c>ok</c> or <c>error</c>. If option + <c>silent</c> is specified, the function instead either returns + <c>{ok,Relup,Module,Warnings}</c>, where <c>Relup</c> is + the release upgrade file, or <c>{error,Module,Error}</c>. + Warnings and errors can be converted to strings by calling <c>Module:format_warning(Warnings)</c> or <c>Module:format_error(Error)</c>.</p> - <p>If the option <c>noexec</c> is provided, the function returns + <p>If option <c>noexec</c> is specified, the function returns the same values as for <c>silent</c> but no <c>relup</c> file is created.</p> - <p>If the option <c>warnings_as_errors</c> is provided, warnings - are treated as errors.</p> + <p>If option <c>warnings_as_errors</c> is specified, warnings + are treated as errors.</p> </desc> </func> + <func> <name>make_script(Name) -> Result</name> <name>make_script(Name, [Opt]) -> Result</name> - <fsummary>Generate a boot script <c>.script/.boot</c>.</fsummary> + <fsummary>Generates a boot script <c>.script/.boot</c>.</fsummary> <type> <v>Name = string()</v> <v>Opt = src_tests | {path,[Dir]} | local | {variables,[Var]} | exref | @@ -153,114 +155,117 @@ <desc> <p>Generates a boot script <c>Name.script</c> and its binary version, the boot file <c>Name.boot</c>. The boot file - specifies which code should be loaded and which applications - should be started when the Erlang runtime system is started. - See <c>script(4)</c>.</p> - <p>The release resource file <c>Name.rel</c> is read to find - out which applications are included in the release. Then - the relevant application resource files <c>App.app</c> are - read to find out which modules should be loaded and if and - how the application should be started. (Keys <c>modules</c> - and <c>mod</c>, see <c>app(4)</c>).</p> - <p>By default, the boot script and boot file are placed in + specifies which code to be loaded and which applications + to be started when the Erlang runtime system is started. + See <seealso marker="script"><c>script(4)</c></seealso>.</p> + <p>The release resource file <c>Name.rel</c> is read to determine + which applications are included in the release. Then + the relevant application resource files <c>App.app</c> are read + to determine which modules to be loaded, and if and + how the applications are to be started. (Keys <c>modules</c> + and <c>mod</c>, see + <seealso marker="kernel:app"><c>app(4)</c></seealso>.</p> + <p>By default, the boot script and boot file are located in the same directory as <c>Name.rel</c>. That is, in the current working directory unless <c>Name</c> contains a path. If - the option <c>{outdir,Dir}</c> is provided, they are placed + option <c>{outdir,Dir}</c> is specified, they are located in <c>Dir</c> instead.</p> - <p>The correctness of each application is checked:</p> + <p>The correctness of each application is checked as follows:</p> <list type="bulleted"> <item> <p>The version of an application specified in - the <c>.rel</c> file should be the same as the version + the <c>.rel</c> file is to be the same as the version specified in the <c>.app</c> file.</p> </item> <item> - <p>There should be no undefined applications, that is, - dependencies to applications which are not included in - the release. (Key <c>applications</c> in <c>.app</c> + <p>There are to be no undefined applications, that is, + dependencies to applications that are not included in + the release. (Key <c>applications</c> in the <c>.app</c> file).</p> </item> <item> - <p>There should be no circular dependencies among + <p>There are to be no circular dependencies among the applications.</p> </item> <item> - <p>There should be no duplicated modules, that is, modules with + <p>There are to be no duplicated modules, that is, modules with the same name but belonging to different applications.</p> </item> <item> - <p>If the <c>src_tests</c> option is specified, a + <p>If option <c>src_tests</c> is specified, a warning is issued if the source code for a module is - missing or newer than the object code.</p> + missing or is newer than the object code.</p> </item> </list> <p>The applications are sorted according to the dependencies between the applications. Where there are no dependencies, the order in the <c>.rel</c> file is kept.</p> - <p>The function will fail if the mandatory - applications <c>kernel</c> and <c>stdlib</c> are not - included in the <c>.rel</c> file and have start - type <c>permanent</c> (default).</p> - <p>If <c>sasl</c> is not included as an application in - the <c>.rel</c> file, a warning is emitted because such a - release can not be used in an upgrade. To turn off this - warning, add the option <c>no_warn_sasl</c>.</p> + <p>The function fails if the mandatory + applications <c>Kernel</c> and <c>STDLIB</c> are not + included in the <c>.rel</c> file and have start + type <c>permanent</c> (which is default).</p> + <p>If <c>SASL</c> is not included as an application in + the <c>.rel</c> file, a warning is issued because such a + release cannot be used in an upgrade. To turn off this + warning, add option <c>no_warn_sasl</c>.</p> <p>All files are searched for in the current path. It is assumed that the <c>.app</c> and <c>.beam</c> files for an - application is located in the same directory. The <c>.erl</c> + application are located in the same directory. The <c>.erl</c> files are also assumed to be located in this directory, unless - it is an <c>ebin</c> directory in which case they may be + it is an <c>ebin</c> directory in which case they can be located in the corresponding <c>src</c> directory.</p> - <p>If the option <c>{path,[Dir]}</c> is provided, this path is + <p>If option <c>{path,[Dir]}</c> is specified, this path is appended to the current path. A directory in the path can be - given with a wildcard <c>*</c>, this is expanded to all + specified with a wildcard <c>*</c>, this is expanded to all matching directories. Example: <c>"lib/*/ebin"</c>.</p> <p>In the generated boot script all application directories are - structured as <c>App-Vsn/ebin</c> and assumed to be located + structured as <c>App-Vsn/ebin</c>. They are assumed to be located in <c>$ROOT/lib</c>, where <c>$ROOT</c> is the root directory - of the installed release. If the <c>local</c> option is - supplied, the actual directories where the applications were + of the installed release. If option <c>local</c> is + specified, the actual directories where the applications were found are used instead. This is a useful way to test a generated boot script locally.</p> - <p>The <c>variables</c> option can be used to specify an + <p>Option <c>variables</c> can be used to specify an installation directory other than <c>$ROOT/lib</c> for some of the applications. If a variable <c>{VarName,Prefix}</c> is specified and an application is found in a directory - <c>Prefix/Rest/App[-Vsn]/ebin</c>, this application will get + <c>Prefix/Rest/App[-Vsn]/ebin</c>, this application gets the path <c>VarName/Rest/App-Vsn/ebin</c> in the boot script. If an application is found in a directory <c>Prefix/Rest</c>, - the path will be <c>VarName/Rest/App-Vsn/ebin</c>. When + the path is <c>VarName/Rest/App-Vsn/ebin</c>. When starting Erlang, all variables <c>VarName</c> are given - values using the <c>boot_var</c> command line flag.</p> - <p>Example: If the option <c>{variables,[{"TEST","lib"}]}</c> is - supplied, and <c>myapp.app</c> is found in - <c>lib/myapp/ebin</c>, then the path to this application in - the boot script will be <c>"$TEST/myapp-1/ebin"</c>. If - <c>myapp.app</c> is found in <c>lib/test</c>, then the path - will be <c>$TEST/test/myapp-1/ebin</c>.</p> + values using command-line flag <c>boot_var</c>.</p> + <p><em>Example:</em> If option <c>{variables,[{"TEST","lib"}]}</c> + is specified and <c>myapp.app</c> is found in + <c>lib/myapp/ebin</c>, the path to this application in + the boot script is <c>"$TEST/myapp-1/ebin"</c>. If + <c>myapp.app</c> is found in <c>lib/test</c>, the path + is <c>$TEST/test/myapp-1/ebin</c>.</p> <p>The checks performed before the boot script is generated can be extended with some cross reference checks by specifying - the <c>exref</c> option. These checks are performed with + option <c>exref</c>. These checks are performed with the Xref tool. All applications, or the applications specified with <c>{exref,[App]}</c>, are checked by Xref and - warnings are generated for calls to undefined functions.</p> + warnings are issued for calls to undefined functions.</p> <p>By default, errors and warnings are printed to tty and - the function returns <c>ok</c> or <c>error</c>. If the option - <c>silent</c> is provided, the function instead returns + the function returns <c>ok</c> or <c>error</c>. If option + <c>silent</c> is specified, the function instead returns <c>{ok,Module,Warnings}</c> or <c>{error,Module,Error}</c>. Warnings and errors can be converted to strings by calling <c>Module:format_warning(Warnings)</c> or <c>Module:format_error(Error)</c>.</p> - <p>If the option <c>warnings_as_errors</c> is provided, warnings - are treated as errors.</p> - <p>If the option <c>no_dot_erlang</c> is provided, the instruction to - load the <c>.erlang</c> file during boot is <em>NOT</em> included.</p> + <p>If option <c>warnings_as_errors</c> is specified, warnings + are treated as errors.</p> + <p>If option <c>no_dot_erlang</c> is specified, the instruction to + load the <c>.erlang</c> file during boot is <em>not</em> + included.</p> </desc> </func> + <func> <name>make_tar(Name) -> Result</name> <name>make_tar(Name, [Opt]) -> Result</name> - <fsummary>Create a release package.</fsummary> + <fsummary>Creates a release package.</fsummary> <type> <v>Name = string()</v> <v>Opt = {dirs,[IncDir]} | {path,[Dir]} | {variables,[Var]} | {var_tar,VarTar} | {erts,Dir} | src_tests | exref | {exref,[App]} | silent | {outdir,Dir}</v> @@ -276,90 +281,91 @@ <v> Warning = Error = term()</v> </type> <desc> - <p>Creates a release package file <c>Name.tar.gz</c>. file. + <p>Creates a release package file <c>Name.tar.gz</c>. This file must be uncompressed and unpacked on the target - system using the <c>release_handler</c>, before the new - release can be installed.</p> - <p>The release resource file <c>Name.rel</c> is read to find out + system using + <seealso marker="release_handler"><c>release_handler</c></seealso> + before the new release can be installed.</p> + <p>The release resource file <c>Name.rel</c> is read to determine which applications are included in the release. Then the relevant application resource files <c>App.app</c> are - read to find out the version and modules of each application. - (Keys <c>vsn</c> and <c>modules</c>, see <c>app(4)</c>).</p> - <p>By default, the release package file is placed in the same + read to determine the version and modules of each application + (keys <c>vsn</c> and <c>modules</c>, see + <seealso marker="kernel:app"><c>app(4)</c></seealso>).</p> + <p>By default, the release package file is located in the same directory as <c>Name.rel</c>. That is, in the current working - directory unless <c>Name</c> contains a path. If the option - <c>{outdir,Dir}</c> is provided, it is placed in <c>Dir</c> + directory unless <c>Name</c> contains a path. If option + <c>{outdir,Dir}</c> is specified, it is located in <c>Dir</c> instead.</p> <p>By default, the release package contains the directories <c>lib/App-Vsn/ebin</c> and <c>lib/App-Vsn/priv</c> for each - included application. If more directories, the option - <c>dirs</c> is supplied. Example: + included application. If more directories are to be included, + option <c>dirs</c> is specified, for example, <c>{dirs,[src,examples]}</c>.</p> <p>All these files are searched for in the current path. If - the option <c>{path,[Dir]}</c> is provided, this path is - appended to the current path. The wildcard <c>*</c> is + option <c>{path,[Dir]}</c> is specified, this path is + appended to the current path. Wildcard <c>*</c> is expanded to all matching directories. Example: <c>"lib/*/ebin"</c>.</p> - <p>The <c>variables</c> option can be used to specify an + <p>Option <c>variables</c> can be used to specify an installation directory other than <c>lib</c> for some of - the applications. If a variable <c>{VarName,Prefix}</c> is - specified and an application is found in a directory - <c>Prefix/Rest/App[-Vsn]/ebin</c>, this application will be + the applications. If variable <c>{VarName,Prefix}</c> is + specified and an application is found in directory + <c>Prefix/Rest/App[-Vsn]/ebin</c>, this application is packed into a separate <c>VarName.tar.gz</c> file as <c>Rest/App-Vsn/ebin</c>.</p> - <p>Example: If the option <c>{variables,[{"TEST","lib"}]}</c> is - supplied, and <c>myapp.app</c> is found in - <c>lib/myapp-1/ebin</c>, the the application <c>myapp</c> is + <p><em>Example:</em> If option <c>{variables,[{"TEST","lib"}]}</c> + is specified and <c>myapp.app</c> is located in + <c>lib/myapp-1/ebin</c>, application <c>myapp</c> is included in <c>TEST.tar.gz</c>:</p> <pre> % <input>tar tf TEST.tar</input> myapp-1/ebin/myapp.app -... - </pre> - <p>The <c>{var_tar,VarTar}</c> option can be used to specify if - and where a separate package should be stored. In this option, - <c>VarTar</c> is:</p> - <list type="bulleted"> - <item> - <p><c>include</c>. Each separate (variable) package is - included in the main <c>ReleaseName.tar.gz</c> file. This - is the default.</p> - </item> - <item> - <p><c>ownfile</c>. Each separate (variable) package is - generated as separate files in the same directory as - the <c>ReleaseName.tar.gz</c> file.</p> - </item> - <item> - <p><c>omit</c>. No separate (variable) packages are - generated and applications which are found underneath a - variable directory are ignored.</p> - </item> - </list> - <p>A directory called <c>releases</c> is also included in +...</pre> + <p>Option <c>{var_tar,VarTar}</c> can be used to specify if + and where a separate package is to be stored. In this option + <c>VarTar</c> is one of the following:</p> + <taglist> + <tag><c>include</c></tag> + <item><p>Each separate (variable) package is included in the + main <c>ReleaseName.tar.gz</c> file. This is the + default.</p></item> + <tag><c>ownfile</c></tag> + <item><p>Each separate (variable) package is + generated as a separate file in the same directory as + the <c>ReleaseName.tar.gz</c> file.</p></item> + <tag><c>omit</c></tag> + <item><p>No separate (variable) packages are + generated. Applications that are found underneath a + variable directory are ignored.</p></item> + </taglist> + <p>A directory <c>releases</c> is also included in the release package, containing <c>Name.rel</c> and a - subdirectory called <c>RelVsn</c>. <c>RelVsn</c> is + subdirectory <c>RelVsn</c>. <c>RelVsn</c> is the release version as specified in <c>Name.rel</c>.</p> <p><c>releases/RelVsn</c> contains the boot script <c>Name.boot</c> renamed to <c>start.boot</c> and, if found, the files <c>relup</c> and <c>sys.config</c>. These files are searched for in the same directory as <c>Name.rel</c>, in the current working directory, and in any directories - specified using the <c>path</c> option.</p> - <p>If the release package should contain a new Erlang runtime + specified using option <c>path</c>.</p> + <p>If the release package is to contain a new Erlang runtime system, the <c>bin</c> directory of the specified runtime system <c>{erts,Dir}</c> is copied to <c>erts-ErtsVsn/bin</c>.</p> - <p>All checks performed with the <c>make_script</c> function - are performed before the release package is created. The - <c>src_tests</c> and <c>exref</c> options are also + <p>All checks with function + <seealso marker="#make_script/1"><c>make_script</c></seealso> + are performed before the release package is created. + Options <c>src_tests</c> and <c>exref</c> are also valid here.</p> <p>The return value and the handling of errors and warnings - are the same as described for <c>make_script</c> above.</p> + are the same as described for + <seealso marker="#make_script/1"><c>make_script</c></seealso>.</p> </desc> </func> + <func> <name>script2boot(File) -> ok | error</name> - <fsummary>Generate a binary version of a boot script.</fsummary> + <fsummary>Generates a binary version of a boot script.</fsummary> <type> <v>File = string()</v> </type> @@ -367,17 +373,24 @@ myapp-1/ebin/myapp.app <p>The Erlang runtime system requires that the contents of the script used to boot the system is a binary Erlang term. This function transforms the <c>File.script</c> boot script - to a binary term which is stored in the file <c>File.boot</c>.</p> - <p>A boot script generated using the <c>make_script</c> - function is already transformed to the binary form.</p> + to a binary term, which is stored in the <c>File.boot</c> + file.</p> + <p>A boot script generated using + <seealso marker="#make_script/1"><c>make_script</c></seealso> + is already transformed to the binary form.</p> </desc> </func> </funcs> <section> - <title>SEE ALSO</title> - <p>app(4), appup(4), erl(1), rel(4), release_handler(3), relup(4), - script(4)</p> + <title>See Also</title> + <p><seealso marker="kernel:app"><c>app(4)</c></seealso>, + <seealso marker="appup"><c>appup(4)</c></seealso>, + <seealso marker="erts:erl"><c>erl(1)</c></seealso>, + <seealso marker="rel"><c>rel(4)</c></seealso>, + <seealso marker="release_handler"><c>release_handler(3)</c></seealso>, + <seealso marker="relup"><c>relup(4)</c></seealso>, + <seealso marker="script"><c>script(4)</c></seealso></p> </section> </erlref> diff --git a/lib/sasl/src/overload.erl b/lib/sasl/src/overload.erl index 61b925d219..bc8ab7d5e4 100644 --- a/lib/sasl/src/overload.erl +++ b/lib/sasl/src/overload.erl @@ -19,6 +19,8 @@ %% -module(overload). +-deprecated(module). + -export([start_link/0, request/0, set_config_data/2, get_overload_info/0]). diff --git a/lib/sasl/src/release_handler_1.erl b/lib/sasl/src/release_handler_1.erl index 536ac924d4..a6325270a5 100644 --- a/lib/sasl/src/release_handler_1.erl +++ b/lib/sasl/src/release_handler_1.erl @@ -587,12 +587,12 @@ get_supervised_procs() -> get_application_names()). get_supervised_procs(_, Root, Procs, {ok, SupMod}) -> - get_procs(maybe_supervisor_which_children(get_proc_state(Root), SupMod, Root), Root) ++ + get_procs(maybe_supervisor_which_children(Root, SupMod, Root), Root) ++ [{undefined, undefined, Root, [SupMod]} | Procs]; get_supervised_procs(Application, Root, Procs, {error, _}) -> error_logger:error_msg("release_handler: cannot find top supervisor for " "application ~w~n", [Application]), - get_procs(maybe_supervisor_which_children(get_proc_state(Root), Application, Root), Root) ++ Procs. + get_procs(maybe_supervisor_which_children(Root, Application, Root), Root) ++ Procs. get_application_names() -> lists:map(fun({Application, _Name, _Vsn}) -> @@ -613,33 +613,54 @@ get_procs([{Name, Pid, worker, Mods} | T], Sup) when is_pid(Pid), is_list(Mods) [{Sup, Name, Pid, Mods} | get_procs(T, Sup)]; get_procs([{Name, Pid, supervisor, Mods} | T], Sup) when is_pid(Pid) -> [{Sup, Name, Pid, Mods} | get_procs(T, Sup)] ++ - get_procs(maybe_supervisor_which_children(get_proc_state(Pid), Name, Pid), Pid); + get_procs(maybe_supervisor_which_children(Pid, Name, Pid), Pid); get_procs([_H | T], Sup) -> get_procs(T, Sup); get_procs(_, _Sup) -> []. +maybe_supervisor_which_children(Proc, Name, Pid) -> + case get_proc_state(Proc) of + noproc -> + %% process exited before we could interrogate it. + %% not necessarily a bug, but reporting a warning as a curiosity. + error_logger:warning_msg("release_handler: a process (~p) exited" + " during supervision tree interrogation." + " Continuing ...~n", [Proc]), + []; + + suspended -> + error_logger:error_msg("release_handler: a which_children call" + " to ~p (~w) was avoided. This supervisor" + " is suspended and should likely be upgraded" + " differently. Exiting ...~n", [Name, Pid]), + error(suspended_supervisor); + + running -> + case catch supervisor:which_children(Pid) of + Res when is_list(Res) -> + Res; + Other -> + error_logger:error_msg("release_handler: ~p~nerror during" + " a which_children call to ~p (~w)." + " [State: running] Exiting ... ~n", + [Other, Name, Pid]), + error(which_children_failed) + end + end. + get_proc_state(Proc) -> - {status, _, {module, _}, [_, State, _, _, _]} = sys:get_status(Proc), - State. - -maybe_supervisor_which_children(suspended, Name, Pid) -> - error_logger:error_msg("release_handler: a which_children call" - " to ~p (~w) was avoided. This supervisor" - " is suspended and should likely be upgraded" - " differently. Exiting ...~n", [Name, Pid]), - error(suspended_supervisor); - -maybe_supervisor_which_children(State, Name, Pid) -> - case catch supervisor:which_children(Pid) of - Res when is_list(Res) -> - Res; - Other -> - error_logger:error_msg("release_handler: ~p~nerror during" - " a which_children call to ~p (~w)." - " [State: ~p] Exiting ... ~n", - [Other, Name, Pid, State]), - error(which_children_failed) + %% sys:send_system_msg can exit with {noproc, {m,f,a}}. + %% This happens if a supervisor exits after which_children has provided + %% its pid for interrogation. + %% ie. Proc may no longer be running at this point. + try sys:get_status(Proc) of + %% as per sys:get_status/1, SysState can only be running | suspended. + {status, _, {module, _}, [_, State, _, _, _]} when State == running ; + State == suspended -> + State + catch exit:{noproc, {sys, get_status, [Proc]}} -> + noproc end. maybe_get_dynamic_mods(Name, Pid) -> @@ -655,48 +676,19 @@ maybe_get_dynamic_mods(Name, Pid) -> error(get_modules_failed) end. -%% XXXX -%% Note: The following is a terrible hack done in order to resolve the -%% problem stated in ticket OTP-3452. - -%% XXXX NOTE WELL: This record is from supervisor.erl. Also the record -%% name is really `state'. --record(supervisor_state, {name, - strategy, - children = [], - dynamics = [], - intensity, - period, - restarts = [], - module, - args}). - %% Return the name of the call-back module that implements the %% (top) supervisor SupPid. %% Returns: {ok, Module} | {error,undefined} %% get_supervisor_module(SupPid) -> - case catch get_supervisor_module1(SupPid) of - {ok, Module} when is_atom(Module) -> + case catch supervisor:get_callback_module(SupPid) of + Module when is_atom(Module) -> {ok, Module}; _Other -> io:format("~w: reason: ~w~n", [SupPid, _Other]), {error, undefined} end. -get_supervisor_module1(SupPid) -> - {status, _Pid, {module, _Mod}, - [_PDict, _SysState, _Parent, _Dbg, Misc]} = sys:get_status(SupPid), - %% supervisor Misc field changed at R13B04, handle old and new variants here - State = case Misc of - [_Name, State1, _Type, _Time] -> - State1; - [_Header, _Data, {data, [{"State", State2}]}] -> - State2 - end, - %% Cannot use #supervisor_state{module = Module} = State. - {ok, element(#supervisor_state.module, State)}. - %%----------------------------------------------------------------- %% Func: do_soft_purge/3 %% Args: Mod = atom() diff --git a/lib/sasl/src/sasl.app.src b/lib/sasl/src/sasl.app.src index 7864e84773..507e2dc229 100644 --- a/lib/sasl/src/sasl.app.src +++ b/lib/sasl/src/sasl.app.src @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2015. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -46,6 +46,6 @@ {env, [{sasl_error_logger, tty}, {errlog_type, all}]}, {mod, {sasl, []}}, - {runtime_dependencies, ["tools-2.6.14","stdlib-2.0","kernel-3.0", + {runtime_dependencies, ["tools-2.6.14","stdlib-2.8","kernel-4.1", "erts-6.0"]}]}. diff --git a/lib/sasl/src/sasl.appup.src b/lib/sasl/src/sasl.appup.src index eddb5a3fd0..e08ae369b8 100644 --- a/lib/sasl/src/sasl.appup.src +++ b/lib/sasl/src/sasl.appup.src @@ -18,7 +18,9 @@ %% %CopyrightEnd% {"%VSN%", %% Up from - max one major revision back - [{<<"2\\.4(\\.[0-9]+)*">>,[restart_new_emulator]}], % OTP-17 + [{<<"2\\.[5-7](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.* + {<<"2\\.4(\\.[0-9]+)*">>,[restart_new_emulator]}], % OTP-17 %% Down to - max one major revision back - [{<<"2\\.4(\\.[0-9]+)*">>,[restart_new_emulator]}] % OTP-17 + [{<<"2\\.[5-7](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.* + {<<"2\\.4(\\.[0-9]+)*">>,[restart_new_emulator]}] % OTP-17 }. diff --git a/lib/sasl/src/sasl_report.erl b/lib/sasl/src/sasl_report.erl index 1b1d432352..0b8c4212d2 100644 --- a/lib/sasl/src/sasl_report.erl +++ b/lib/sasl/src/sasl_report.erl @@ -62,27 +62,53 @@ write_report2(IO, Fd, Head, supervisor_report, Report) -> Context = sup_get(errorContext, Report), Reason = sup_get(reason, Report), Offender = sup_get(offender, Report), - FmtString = " Supervisor: ~p~n Context: ~p~n Reason: " - "~80.18p~n Offender: ~80.18p~n~n", - write_report_action(IO, Fd, Head ++ FmtString, - [Name,Context,Reason,Offender]); + {FmtString,Args} = supervisor_format([Name,Context,Reason,Offender]), + write_report_action(IO, Fd, Head, FmtString, Args); write_report2(IO, Fd, Head, progress, Report) -> Format = format_key_val(Report), - write_report_action(IO, Fd, Head ++ "~s", [Format]); + write_report_action(IO, Fd, Head, "~s", [Format]); write_report2(IO, Fd, Head, crash_report, Report) -> - Format = proc_lib:format(Report), - write_report_action(IO, Fd, Head ++ "~s", [Format]). + Depth = get_depth(), + Format = proc_lib:format(Report, latin1, Depth), + write_report_action(IO, Fd, Head, "~s", [Format]). + +supervisor_format(Args0) -> + case get_depth() of + unlimited -> + {" Supervisor: ~p~n" + " Context: ~p~n" + " Reason: ~80.18p~n" + " Offender: ~80.18p~n~n", + Args0}; + Depth -> + [A,B,C,D] = Args0, + Args = [A,Depth,B,Depth,C,Depth,D,Depth], + {" Supervisor: ~P~n" + " Context: ~P~n" + " Reason: ~80.18P~n" + " Offender: ~80.18P~n~n", + Args} + end. -write_report_action(io, Fd, Format, Args) -> - io:format(Fd, Format, Args); -write_report_action(io_lib, _Fd, Format, Args) -> - io_lib:format(Format, Args). +write_report_action(IO, Fd, Head, Format, Args) -> + S = [Head|io_lib:format(Format, Args)], + case IO of + io -> io:put_chars(Fd, S); + io_lib -> S + end. format_key_val([{Tag,Data}|Rep]) -> io_lib:format(" ~16w: ~p~n",[Tag,Data]) ++ format_key_val(Rep); format_key_val(_) -> []. +get_depth() -> + case application:get_env(kernel, error_logger_format_depth) of + {ok, Depth} when is_integer(Depth) -> + max(10, Depth); + undefined -> + unlimited + end. sup_get(Tag, Report) -> case lists:keysearch(Tag, 1, Report) of diff --git a/lib/sasl/test/Makefile b/lib/sasl/test/Makefile index 86fc57abfc..86976def6a 100644 --- a/lib/sasl/test/Makefile +++ b/lib/sasl/test/Makefile @@ -29,11 +29,13 @@ MODULES= \ alarm_handler_SUITE \ installer \ release_handler_SUITE \ + sasl_report_SUITE \ + sasl_report_suite_supervisor \ systools_SUITE \ systools_rc_SUITE \ overload_SUITE \ rb_SUITE \ - rh_test_lib + rh_test_lib \ ERL_FILES= $(MODULES:%=%.erl) diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl index d57de2593a..ee620dcdb4 100644 --- a/lib/sasl/test/release_handler_SUITE.erl +++ b/lib/sasl/test/release_handler_SUITE.erl @@ -1363,7 +1363,7 @@ upgrade_supervisor(Conf) when is_list(Conf) -> %% Check that the restart strategy and child spec is updated {status, _, {module, _}, [_, _, _, _, [_,_,{data,[{"State",State}]}]]} = rpc:call(Node,sys,get_status,[a_sup]), - {state,_,RestartStrategy,[Child],_,_,_,_,_,_} = State, + {state,_,RestartStrategy,[Child],_,_,_,_,_,_,_} = State, one_for_all = RestartStrategy, % changed from one_for_one {child,_,_,_,_,brutal_kill,_,_} = Child, % changed from timeout 2000 diff --git a/lib/sasl/test/sasl_SUITE.erl b/lib/sasl/test/sasl_SUITE.erl index 1d76cdee6e..cd8316b451 100644 --- a/lib/sasl/test/sasl_SUITE.erl +++ b/lib/sasl/test/sasl_SUITE.erl @@ -28,10 +28,11 @@ -export([app_test/1, appup_test/1, log_mf_h_env/1, - log_file/1]). + log_file/1, + utc_log/1]). all() -> - [log_mf_h_env, log_file, app_test, appup_test]. + [log_mf_h_env, log_file, app_test, appup_test, utc_log]. groups() -> []. @@ -182,20 +183,104 @@ log_mf_h_env(Config) -> log_file(Config) -> PrivDir = ?config(priv_dir,Config), LogDir = filename:join(PrivDir,sasl_SUITE_log_dir), - ok = filelib:ensure_dir(LogDir), File = filename:join(LogDir, "file.log"), + ok = filelib:ensure_dir(File), application:stop(sasl), clear_env(sasl), - ok = application:set_env(sasl,sasl_error_logger,{file, File}, [{persistent, true}]), + _ = test_log_file(File, {file,File}), + _ = test_log_file(File, {file,File,[write]}), + + ok = file:write_file(File, <<"=PROGRESS preserve me\n">>), + <<"=PROGRESS preserve me\n",_/binary>> = + test_log_file(File, {file,File,[append]}), + + ok = application:set_env(sasl,sasl_error_logger, tty, + [{persistent, false}]), + ok = application:start(sasl). + +test_log_file(File, Arg) -> + ok = application:set_env(sasl, sasl_error_logger, Arg, + [{persistent, true}]), + ok = application:start(sasl), + application:stop(sasl), + {ok,Bin} = file:read_file(File), + ok = file:delete(File), + Lines0 = binary:split(Bin, <<"\n">>, [trim_all,global]), + Lines = [L || L <- Lines0, + binary:match(L, <<"=PROGRESS">>) =:= {0,9}], + io:format("~p:\n~p\n", [Arg,Lines]), + + %% There must be at least four PROGRESS lines. + if + length(Lines) >= 4 -> ok; + true -> ?t:fail() + end, + Bin. + +%% Make a basic test of utc_log. +utc_log(Config) -> + PrivDir = ?config(priv_dir, Config), + LogDir = filename:join(PrivDir, sasl_SUITE_log_dir), + Log = filename:join(LogDir, "utc.log"), + ok = filelib:ensure_dir(Log), + + application:stop(sasl), + clear_env(sasl), + + %% Test that the UTC marker gets added to PROGRESS lines + %% when the utc_log configuration variable is set to true. + ok = application:set_env(sasl, sasl_error_logger, {file,Log}, + [{persistent,true}]), + ok = application:set_env(sasl, utc_log, true, [{persistent,true}]), ok = application:start(sasl), application:stop(sasl), - ok = application:set_env(sasl,sasl_error_logger,{file, File, [append]}, [{persistent, true}]), + + verify_utc_log(Log, true), + + %% Test that no UTC markers gets added to PROGRESS lines + %% when the utc_log configuration variable is set to false. + ok = application:set_env(sasl, utc_log, false, [{persistent,true}]), + ok = application:start(sasl), + application:stop(sasl), + + verify_utc_log(Log, false), + + %% Test that no UTC markers gets added to PROGRESS lines + %% when the utc_log configuration variable is unset. + ok = application:unset_env(sasl, utc_log, [{persistent,true}]), ok = application:start(sasl), application:stop(sasl), - ok = application:set_env(sasl,sasl_error_logger, tty, [{persistent, false}]), + + verify_utc_log(Log, false), + + %% Change back to the standard TTY error logger. + ok = application:set_env(sasl,sasl_error_logger, tty, + [{persistent, false}]), ok = application:start(sasl). +verify_utc_log(Log, UTC) -> + {ok,Bin} = file:read_file(Log), + ok = file:delete(Log), + + Lines0 = binary:split(Bin, <<"\n">>, [trim_all,global]), + Lines = [L || L <- Lines0, + binary:match(L, <<"=PROGRESS">>) =:= {0,9}], + Setting = application:get_env(sasl, utc_log), + io:format("utc_log ~p:\n~p\n", [Setting,Lines]), + Filtered = [L || L <- Lines, + binary:match(L, <<" UTC ===">>) =:= nomatch], + %% Filtered now contains all lines WITHOUT any UTC markers. + case UTC of + false -> + %% No UTC marker on the PROGRESS line. + Filtered = Lines; + true -> + %% Each PROGRESS line must have an UTC marker. + [] = Filtered + end, + ok. + %%----------------------------------------------------------------- %% Internal diff --git a/lib/sasl/test/sasl_report_SUITE.erl b/lib/sasl/test/sasl_report_SUITE.erl new file mode 100644 index 0000000000..940234f152 --- /dev/null +++ b/lib/sasl/test/sasl_report_SUITE.erl @@ -0,0 +1,141 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2015. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% +-module(sasl_report_SUITE). +-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, + init_per_group/2,end_per_group/2]). +-export([gen_server_crash/1]). + +-export([crash_me/0,start_link/0,init/1,handle_cast/2,terminate/2]). + +-include_lib("test_server/include/test_server.hrl"). + +suite() -> [{ct_hooks,[ts_install_cth]}]. + +all() -> + [gen_server_crash]. + +groups() -> + []. + +init_per_suite(Config) -> + Config. + +end_per_suite(_Config) -> + ok. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + +gen_server_crash(Config) -> + try + do_gen_server_crash(Config) + after + error_logger:tty(true), + ok = application:unset_env(sasl, sasl_error_logger), + ok = application:unset_env(kernel, error_logger_format_depth), + error_logger:add_report_handler(cth_log_redirect) + end, + ok. + +do_gen_server_crash(Config) -> + PrivDir = ?config(priv_dir, Config), + LogDir = filename:join(PrivDir, ?MODULE), + KernelLog = filename:join(LogDir, "kernel.log"), + SaslLog = filename:join(LogDir, "sasl.log"), + ok = filelib:ensure_dir(SaslLog), + + error_logger:delete_report_handler(cth_log_redirect), + error_logger:tty(false), + application:stop(sasl), + ok = application:set_env(sasl, sasl_error_logger, {file,SaslLog}, + [{persistent,true}]), + application:set_env(kernel, error_logger_format_depth, 30), + error_logger:logfile({open,KernelLog}), + application:start(sasl), + io:format("~p\n", [gen_event:which_handlers(error_logger)]), + + crash_me(), + + error_logger:logfile(close), + + check_file(KernelLog, 70000, 150000), + check_file(SaslLog, 50000, 100000), + + ok. + +check_file(File, Min, Max) -> + {ok,Bin} = file:read_file(File), + Base = filename:basename(File), + io:format("*** Contents of ~s ***\n", [Base]), + io:put_chars([Bin,"\n"]), + Sz = byte_size(Bin), + io:format("Size: ~p (allowed range is ~p..~p)\n", + [Sz,Min,Max]), + if + Sz < Min -> + %% Truncated? Other problem? + ?t:fail({too_short,Base}); + Sz > Max -> + %% Truncation doesn't work? + ?t:fail({too_big,Base}); + true -> + ok + end. + +%%% +%%% gen_server that crashes. +%%% + +crash_me() -> + {ok,SuperPid} = supervisor:start_link(sasl_report_suite_supervisor, []), + [{Id,Pid,_,_}] = supervisor:which_children(SuperPid), + HugeData = gb_sets:from_list(lists:seq(1, 100000)), + gen_server:cast(Pid, HugeData), + Ref = monitor(process, Pid), + receive + {'DOWN',Ref,process,Pid,_} -> + supervisor:terminate_child(SuperPid, Id), + unlink(SuperPid), + exit(SuperPid, kill), + ok + end. + +start_link() -> + gen_server:start_link(?MODULE, [], []). + +init(_) -> + St = <<0:100000/unit:8>>, + {ok,St}. + +handle_cast(Big, St) -> + Seq = lists:seq(1, 10000), + self() ! Seq, + self() ! Seq, + self() ! Seq, + self() ! Seq, + self() ! Seq, + x = Big, + {noreply,St}. + +terminate(_, _) -> + ok. diff --git a/lib/sasl/test/sasl_report_suite_supervisor.erl b/lib/sasl/test/sasl_report_suite_supervisor.erl new file mode 100644 index 0000000000..bc92a40af2 --- /dev/null +++ b/lib/sasl/test/sasl_report_suite_supervisor.erl @@ -0,0 +1,77 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2015. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +-module(sasl_report_suite_supervisor). + +-behaviour(supervisor). + +%% API +-export([start_link/0]). + +%% Supervisor callbacks +-export([init/1]). + +-define(SERVER, ?MODULE). + +%%%=================================================================== +%%% API functions +%%%=================================================================== + +%%-------------------------------------------------------------------- +%% @doc +%% Starts the supervisor +%% +%% @spec start_link() -> {ok, Pid} | ignore | {error, Error} +%% @end +%%-------------------------------------------------------------------- +start_link() -> + supervisor:start_link({local, ?SERVER}, ?MODULE, []). + +%%%=================================================================== +%%% Supervisor callbacks +%%%=================================================================== + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Whenever a supervisor is started using supervisor:start_link/[2,3], +%% this function is called by the new process to find out about +%% restart strategy, maximum restart intensity, and child +%% specifications. +%% +%% @spec init(Args) -> {ok, {SupFlags, [ChildSpec]}} | +%% ignore | +%% {error, Reason} +%% @end +%%-------------------------------------------------------------------- +init([]) -> + + SupFlags = #{strategy => one_for_one, + intensity => 1, + period => 5}, + + AChild = #{id => 'sasl_report_suit_supervisor', + start => {sasl_report_SUITE, start_link, []}, + restart => permanent, + shutdown => 5000, + type => worker, + modules => [sasl_report_SUITE]}, + + {ok, {SupFlags, [AChild]}}. diff --git a/lib/sasl/vsn.mk b/lib/sasl/vsn.mk index e07b36f4ba..accb58a199 100644 --- a/lib/sasl/vsn.mk +++ b/lib/sasl/vsn.mk @@ -1 +1 @@ -SASL_VSN = 2.5 +SASL_VSN = 2.7 diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml index 94e73ddfca..4693a744f5 100644 --- a/lib/snmp/doc/src/notes.xml +++ b/lib/snmp/doc/src/notes.xml @@ -34,7 +34,51 @@ </header> - <section><title>SNMP 5.2</title> + <section><title>SNMP 5.2.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Snmp agent now properly handles <c>vacmViewTreeFamily</c> + masks.</p> + <p> + Own Id: OTP-13264</p> + </item> + </list> + </section> + +</section> + +<section><title>SNMP 5.2.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Small documentation fixes</p> + <p> + Own Id: OTP-13017</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Update configuration check of imask ( list of ones and + zeros) to allow the empty list.</p> + <p> + Own Id: OTP-13101</p> + </item> + </list> + </section> + +</section> + +<section><title>SNMP 5.2</title> <section><title>Improvements and New Features</title> <list> diff --git a/lib/snmp/doc/src/snmp_advanced_agent.xml b/lib/snmp/doc/src/snmp_advanced_agent.xml index 717f7426c6..b17246438d 100644 --- a/lib/snmp/doc/src/snmp_advanced_agent.xml +++ b/lib/snmp/doc/src/snmp_advanced_agent.xml @@ -340,7 +340,7 @@ SEQUENCE { empDepNo INTEGER, empName DisplayString, - empTelNo DisplayString + empTelNo DisplayString, empStatus RowStatus } </code> diff --git a/lib/snmp/doc/src/snmp_agent_netif.xml b/lib/snmp/doc/src/snmp_agent_netif.xml index 769fd23115..9583f1f521 100644 --- a/lib/snmp/doc/src/snmp_agent_netif.xml +++ b/lib/snmp/doc/src/snmp_agent_netif.xml @@ -76,8 +76,7 @@ <c>{Domain, Addr}</c> tuple where <c>Domain</c> is <c>transportDomainUdpIpv4</c> or <c>transportDomainUdpIpv4</c>, and <c>Addr</c> is an - <c>{<seealso marker="kernel:inet#type-ip_address">IpAddr</seealso>, - IpPort}</c> tuple.</p> + <c>{</c><seealso marker="kernel:inet#type-ip_address"><c>IpAddr</c></seealso><c>,IpPort}</c> tuple.</p> <section> <marker id="outgoing_messages"></marker> diff --git a/lib/snmp/doc/src/snmp_app.xml b/lib/snmp/doc/src/snmp_app.xml index 234a076eda..39aac8e7d7 100644 --- a/lib/snmp/doc/src/snmp_app.xml +++ b/lib/snmp/doc/src/snmp_app.xml @@ -135,16 +135,16 @@ <marker id="agent_opts_and_types"></marker> <p>Agent specific config options and types:</p> <taglist> - <marker id="agent_type"></marker> - <tag><c><![CDATA[agent_type() = master | sub <optional>]]></c></tag> + <tag><marker id="agent_type"></marker> + <c><![CDATA[agent_type() = master | sub <optional>]]></c></tag> <item> <p>If <c>master</c>, one master agent is started. Otherwise, no agents are started. </p> <p>Default is <c>master</c>.</p> </item> - <marker id="agent_disco"></marker> - <tag><c><![CDATA[agent_discovery() = [agent_discovery_opt()] <optional>]]></c></tag> + <tag><marker id="agent_disco"></marker> + <c><![CDATA[agent_discovery() = [agent_discovery_opt()] <optional>]]></c></tag> <item> <p><c>agent_discovery_opt() = {terminating, agent_terminating_discovery_opts()} | @@ -156,8 +156,8 @@ <p>For defaults see the options in <c>agent_discovery_opt()</c>.</p> </item> - <marker id="agent_term_disco_opts"></marker> - <tag><c><![CDATA[agent_terminating_discovery_opts() = [agent_terminating_discovery_opt()] <optional>]]></c></tag> + <tag><marker id="agent_term_disco_opts"></marker> + <c><![CDATA[agent_terminating_discovery_opts() = [agent_terminating_discovery_opt()] <optional>]]></c></tag> <item> <p><c>agent_terminating_discovery_opt() = {enable, boolean()} | @@ -174,8 +174,8 @@ </list> </item> - <marker id="agent_orig_disco_opts"></marker> - <tag><c><![CDATA[agent_originating_discovery_opts() = [agent_originating_discovery_opt()] <optional>]]></c></tag> + <tag><marker id="agent_orig_disco_opts"></marker> + <c><![CDATA[agent_originating_discovery_opts() = [agent_originating_discovery_opt()] <optional>]]></c></tag> <item> <p><c>agent_originating_discovery_opt() = {enable, boolean()}</c></p> @@ -188,38 +188,39 @@ </list> </item> - <marker id="agent_mt"></marker> - <tag><c><![CDATA[multi_threaded() = bool() <optional>]]></c></tag> + <tag><marker id="agent_mt"></marker> + <c><![CDATA[multi_threaded() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c>, the agent is multi-threaded, with one thread for each get request. </p> <p>Default is <c>false</c>.</p> </item> - <marker id="agent_data_dir"></marker> - <tag><c><![CDATA[db_dir() = string() <mandatory>]]></c></tag> + <tag><marker id="agent_data_dir"></marker> + <c><![CDATA[db_dir() = string() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP agent internal db files are stored.</p> </item> - <marker id="agent_gb_max_vbs"></marker> - <tag><c><![CDATA[gb_max_vbs() = pos_integer() | infinity <optional>]]></c></tag> + + <tag><marker id="agent_gb_max_vbs"></marker> + <c><![CDATA[gb_max_vbs() = pos_integer() | infinity <optional>]]></c></tag> <item> <p>Defines the maximum number of varbinds allowed in a Get-BULK response.</p> <p>Default is <c>1000</c>.</p> </item> - <marker id="agent_local_db"></marker> - <tag><c><![CDATA[local_db() = [local_db_opt()] <optional>]]></c></tag> + <tag><marker id="agent_local_db"></marker> + <c><![CDATA[local_db() = [local_db_opt()] <optional>]]></c></tag> <item> <p><c>local_db_opt() = {repair, agent_repair()} | {auto_save, agent_auto_save()} | {verbosity, verbosity()}</c></p> <p>Defines options specific for the SNMP agent local database.</p> <p>For defaults see the options in <c>local_db_opt()</c>.</p> </item> - <marker id="agent_ldb_repair"></marker> - <tag><c><![CDATA[agent_repair() = false | true | force <optional>]]></c></tag> + <tag><marker id="agent_ldb_repair"></marker> + <c><![CDATA[agent_repair() = false | true | force <optional>]]></c></tag> <item> <p>When starting snmpa_local_db it always tries to open an existing database. If <c>false</c>, and some errors occur, a new @@ -229,16 +230,16 @@ <p>Default is <c>true</c>.</p> </item> - <marker id="agent_ldb_auto_save"></marker> - <tag><c><![CDATA[agent_auto_save() = integer() | infinity <optional>]]></c></tag> + <tag><marker id="agent_ldb_auto_save"></marker> + <c><![CDATA[agent_auto_save() = integer() | infinity <optional>]]></c></tag> <item> <p>The auto save interval. The table is flushed to disk whenever not accessed for this amount of time.</p> <p>Default is <c>5000</c>.</p> </item> - <marker id="agent_net_if"></marker> - <tag><c><![CDATA[agent_net_if() = [agent_net_if_opt()] <optional>]]></c></tag> + <tag><marker id="agent_net_if"></marker> + <c><![CDATA[agent_net_if() = [agent_net_if_opt()] <optional>]]></c></tag> <item> <p><c>agent_net_if_opt() = {module, agent_net_if_module()} | {verbosity, verbosity()} | {options, agent_net_if_options()}</c></p> <p>Defines options specific for the SNMP agent network interface @@ -246,8 +247,8 @@ <p>For defaults see the options in <c>agent_net_if_opt()</c>.</p> </item> - <marker id="agent_ni_module"></marker> - <tag><c><![CDATA[agent_net_if_module() = atom() <optional>]]></c></tag> + <tag><marker id="agent_ni_module"></marker> + <c><![CDATA[agent_net_if_module() = atom() <optional>]]></c></tag> <item> <p>Module which handles the network interface part for the SNMP agent. Must implement the @@ -255,8 +256,8 @@ <p>Default is <c>snmpa_net_if</c>.</p> </item> - <marker id="agent_ni_opts"></marker> - <tag><c><![CDATA[agent_net_if_options() = [agent_net_if_option()] <optional>]]></c></tag> + <tag><marker id="agent_ni_opts"></marker> + <c><![CDATA[agent_net_if_options() = [agent_net_if_option()] <optional>]]></c></tag> <item> <p><c>agent_net_if_option() = {bind_to, bind_to()} | {sndbuf, sndbuf()} | @@ -270,15 +271,15 @@ <p>For defaults see the options in <c>agent_net_if_option()</c>.</p> </item> - <marker id="agent_ni_req_limit"></marker> - <tag><c><![CDATA[req_limit() = integer() | infinity <optional>]]></c></tag> + <tag><marker id="agent_ni_req_limit"></marker> + <c><![CDATA[req_limit() = integer() | infinity <optional>]]></c></tag> <item> <p>Max number of simultaneous requests handled by the agent.</p> <p>Default is <c>infinity</c>.</p> </item> - <marker id="agent_ni_filter_opts"></marker> - <tag><c><![CDATA[agent_net_if_filter_options() = [agent_net_if_filter_option()] <optional>]]></c></tag> + <tag><marker id="agent_ni_filter_opts"></marker> + <c><![CDATA[agent_net_if_filter_options() = [agent_net_if_filter_option()] <optional>]]></c></tag> <item> <p><c>agent_net_if_filter_option() = {module, agent_net_if_filter_module()}</c></p> <p>These options are actually specific to the used module. @@ -288,8 +289,8 @@ <c>agent_net_if_filter_option()</c>.</p> </item> - <marker id="agent_ni_filter_module"></marker> - <tag><c><![CDATA[agent_net_if_filter_module() = atom() <optional>]]></c></tag> + <tag><marker id="agent_ni_filter_module"></marker> + <c><![CDATA[agent_net_if_filter_module() = atom() <optional>]]></c></tag> <item> <p>Module which handles the network interface filter part for the SNMP agent. Must implement the @@ -297,8 +298,8 @@ <p>Default is <c>snmpa_net_if_filter</c>.</p> </item> - <marker id="agent_mibs"></marker> - <tag><c><![CDATA[agent_mibs() = [string()] <optional>]]></c></tag> + <tag><marker id="agent_mibs"></marker> + <c><![CDATA[agent_mibs() = [string()] <optional>]]></c></tag> <item> <p>Specifies a list of MIBs (including path) that defines which MIBs are initially loaded into the SNMP master agent. </p> @@ -312,8 +313,8 @@ <p>Default is <c>[]</c>.</p> </item> - <marker id="agent_mib_storage"></marker> - <tag><c><![CDATA[mib_storage() = [mib_storage_opt()] <optional>]]></c></tag> + <tag><marker id="agent_mib_storage"></marker> + <c><![CDATA[mib_storage() = [mib_storage_opt()] <optional>]]></c></tag> <item> <p><c>mib_storage_opt() = {module, mib_storage_module()} | {options, mib_storage_options()}</c></p> <p>This option specifies how basic mib data is stored. @@ -322,8 +323,8 @@ <p>Default is <c>[{module, snmpa_mib_storage_ets}]</c>. </p> </item> - <marker id="agent_mst_module"></marker> - <tag><c><![CDATA[mib_storage_module() = snmpa_mib_data_ets | snmpa_mib_data_dets | snmpa_mib_data_mnesia | module()]]></c></tag> + <tag><marker id="agent_mst_module"></marker> + <c><![CDATA[mib_storage_module() = snmpa_mib_data_ets | snmpa_mib_data_dets | snmpa_mib_data_mnesia | module()]]></c></tag> <item> <p>Defines the mib storage module of the SNMP agent as defined by the <seealso marker="snmpa_mib_storage">snmpa_mib_storage</seealso> @@ -337,8 +338,8 @@ <p>Default module is <c>snmpa_mib_storage_ets</c>. </p> </item> - <marker id="agent_mst_options"></marker> - <tag><c><![CDATA[mib_storage_options() = list() <optional>]]></c></tag> + <tag><marker id="agent_mst_options"></marker> + <c><![CDATA[mib_storage_options() = list() <optional>]]></c></tag> <item> <p>This is implementattion depended. That is, it depends on the module. For each module a specific set of options are valid. @@ -427,16 +428,16 @@ </list> </item> - <marker id="agent_mib_server"></marker> - <tag><c><![CDATA[mib_server() = [mib_server_opt()] <optional>]]></c></tag> + <tag><marker id="agent_mib_server"></marker> + <c><![CDATA[mib_server() = [mib_server_opt()] <optional>]]></c></tag> <item> <p><c>mib_server_opt() = {mibentry_override, mibentry_override()} | {trapentry_override, trapentry_override()} | {verbosity, verbosity()} | {cache, mibs_cache()} | {data_module, mib_server_data_module()}</c></p> <p>Defines options specific for the SNMP agent mib server. </p> <p>For defaults see the options in <c>mib_server_opt()</c>.</p> </item> - <marker id="agent_ms_meo"></marker> - <tag><c><![CDATA[mibentry_override() = bool() <optional>]]></c></tag> + <tag><marker id="agent_ms_meo"></marker> + <c><![CDATA[mibentry_override() = bool() <optional>]]></c></tag> <item> <p>If this value is false, then when loading a mib each mib- entry is checked prior to installation of the mib. @@ -445,8 +446,8 @@ <p>Default is <c>false</c>.</p> </item> - <marker id="agent_ms_teo"></marker> - <tag><c><![CDATA[trapentry_override() = bool() <optional>]]></c></tag> + <tag><marker id="agent_ms_teo"></marker> + <c><![CDATA[trapentry_override() = bool() <optional>]]></c></tag> <item> <p>If this value is false, then when loading a mib each trap is checked prior to installation of the mib. @@ -455,11 +456,12 @@ <p>Default is <c>false</c>.</p> </item> - <marker id="agent_ms_data_module"></marker> <!-- - <tag><c><![CDATA[mib_server_data_module() = snmpa_mib_data_tttn | snmpa_mib_data_ttln | module() <optional>]]></c></tag> + <tag><marker id="agent_ms_data_module"></marker> + <c><![CDATA[mib_server_data_module() = snmpa_mib_data_tttn | snmpa_mib_data_ttln | module() <optional>]]></c></tag> --> - <tag><c><![CDATA[mib_server_data_module() = snmpa_mib_data_tttn | module() <optional>]]></c></tag> + <tag><marker id="agent_ms_data_module"></marker> + <c><![CDATA[mib_server_data_module() = snmpa_mib_data_tttn | module() <optional>]]></c></tag> <item> <p>Defines the backend data module of the SNMP agent mib-server as defined by the @@ -476,24 +478,24 @@ <p>Default module is <c>snmpa_mib_data_tttn</c>. </p> </item> - <marker id="agent_ms_cache"></marker> - <tag><c><![CDATA[mibs_cache() = bool() | mibs_cache_opts() <optional>]]></c></tag> + <tag><marker id="agent_ms_cache"></marker> + <c><![CDATA[mibs_cache() = bool() | mibs_cache_opts() <optional>]]></c></tag> <item> <p>Shall the agent utilize the mib server lookup cache or not.</p> <p>Default is <c>true</c> (in which case the <c>mibs_cache_opts()</c> default values apply).</p> </item> - <marker id="agent_ms_cache_opts"></marker> - <tag><c><![CDATA[mibs_cache_opts() = [mibs_cache_opt()] <optional>]]></c></tag> + <tag><marker id="agent_ms_cache_opts"></marker> + <c><![CDATA[mibs_cache_opts() = [mibs_cache_opt()] <optional>]]></c></tag> <item> <p><c>mibs_cache_opt() = {autogc, mibs_cache_autogc()} | {gclimit, mibs_cache_gclimit()} | {age, mibs_cache_age()}</c></p> <p>Defines options specific for the SNMP agent mib server cache. </p> <p>For defaults see the options in <c>mibs_cache_opt()</c>.</p> </item> - <marker id="agent_ms_cache_autogc"></marker> - <tag><c><![CDATA[mibs_cache_autogc() = bool() <optional>]]></c></tag> + <tag><marker id="agent_ms_cache_autogc"></marker> + <c><![CDATA[mibs_cache_autogc() = bool() <optional>]]></c></tag> <item> <p>Defines if the mib server shall perform cache gc automatically or leave it to the user (see @@ -501,8 +503,8 @@ <p>Default is <c>true</c>.</p> </item> - <marker id="agent_ms_cache_age"></marker> - <tag><c><![CDATA[mibs_cache_age() = integer() > 0 <optional>]]></c></tag> + <tag><marker id="agent_ms_cache_age"></marker> + <c><![CDATA[mibs_cache_age() = integer() > 0 <optional>]]></c></tag> <item> <p>Defines how old the entries in the cache will be allowed to become before they are GC'ed (assuming GC is performed). @@ -511,8 +513,8 @@ <p>Default is <c>10 timutes</c>.</p> </item> - <marker id="agent_ms_cache_gclimit"></marker> - <tag><c><![CDATA[mibs_cache_gclimit() = integer() > 0 | infinity <optional>]]></c></tag> + <tag><marker id="agent_ms_cache_gclimit"></marker> + <c><![CDATA[mibs_cache_gclimit() = integer() > 0 | infinity <optional>]]></c></tag> <item> <p>When performing a GC, this is the max number of cache entries that will be deleted from the cache. </p> @@ -522,8 +524,8 @@ <p>Default is <c>100</c>.</p> </item> - <marker id="agent_error_report_mod"></marker> - <tag><c><![CDATA[error_report_mod() = atom() <optional>]]></c></tag> + <tag><marker id="agent_error_report_mod"></marker> + <c><![CDATA[error_report_mod() = atom() <optional>]]></c></tag> <item> <p>Defines an error report module, implementing the <seealso marker="snmpa_error_report">snmpa_error_report</seealso> @@ -532,38 +534,38 @@ <p>Default is <c>snmpa_error_logger</c>.</p> </item> - <marker id="agent_symbolic_store"></marker> - <tag><c>symbolic_store() = [symbolic_store_opt()]</c></tag> + <tag><marker id="agent_symbolic_store"></marker> + <c>symbolic_store() = [symbolic_store_opt()]</c></tag> <item> <p><c>symbolic_store_opt() = {verbosity, verbosity()}</c></p> <p>Defines options specific for the SNMP agent symbolic store. </p> <p>For defaults see the options in <c>symbolic_store_opt()</c>.</p> </item> - <marker id="agent_target_cache"></marker> - <tag><c>target_cache() = [target_cache_opt()]</c></tag> + <tag><marker id="agent_target_cache"></marker> + <c>target_cache() = [target_cache_opt()]</c></tag> <item> <p><c>target_cache_opt() = {verbosity, verbosity()}</c></p> <p>Defines options specific for the SNMP agent target cache. </p> <p>For defaults see the options in <c>target_cache_opt()</c>.</p> </item> - <marker id="agent_config"></marker> - <tag><c><![CDATA[agent_config() = [agent_config_opt()] <mandatory>]]></c></tag> + <tag><marker id="agent_config"></marker> + <c><![CDATA[agent_config() = [agent_config_opt()] <mandatory>]]></c></tag> <item> <p><c>agent_config_opt() = {dir, agent_config_dir()} | {force_load, force_load()} | {verbosity, verbosity()}</c></p> <p>Defines specific config related options for the SNMP agent. </p> <p>For defaults see the options in <c>agent_config_opt()</c>.</p> </item> - <marker id="agent_config_dir"></marker> - <tag><c><![CDATA[agent_config_dir = dir() <mandatory>]]></c></tag> + <tag><marker id="agent_config_dir"></marker> + <c><![CDATA[agent_config_dir = dir() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP agent configuration files are stored.</p> </item> - <marker id="agent_force_load"></marker> - <tag><c><![CDATA[force_load() = bool() <optional>]]></c></tag> + <tag><marker id="agent_force_load"></marker> + <c><![CDATA[force_load() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c> the configuration files are re-read during start-up, and the contents of the configuration @@ -577,16 +579,16 @@ <marker id="manager_opts_and_types"></marker> <p>Manager specific config options and types:</p> <taglist> - <marker id="manager_server"></marker> - <tag><c><![CDATA[server() = [server_opt()] <optional>]]></c></tag> + <tag><marker id="manager_server"></marker> + <c><![CDATA[server() = [server_opt()] <optional>]]></c></tag> <item> <p><c>server_opt() = {timeout, server_timeout()} | {verbosity, verbosity()}</c></p> <p>Specifies the options for the manager server process.</p> <p>Default is <c>silence</c>.</p> </item> - <marker id="manager_server_timeout"></marker> - <tag><c><![CDATA[server_timeout() = integer() <optional>]]></c></tag> + <tag><marker id="manager_server_timeout"></marker> + <c><![CDATA[server_timeout() = integer() <optional>]]></c></tag> <item> <p>Asynchronous request cleanup time. For every requests, some info is stored internally, in order to be able to @@ -606,44 +608,44 @@ <p>Default is <c>30000</c>.</p> </item> - <marker id="manager_config"></marker> - <tag><c><![CDATA[manager_config() = [manager_config_opt()] <mandatory>]]></c></tag> + <tag><marker id="manager_config"></marker> + <c><![CDATA[manager_config() = [manager_config_opt()] <mandatory>]]></c></tag> <item> <p><c>manager_config_opt() = {dir, manager_config_dir()} | {db_dir, manager_db_dir()} | {db_init_error, db_init_error()} | {repair, manager_repair()} | {auto_save, manager_auto_save()} | {verbosity, verbosity()}</c></p> <p>Defines specific config related options for the SNMP manager. </p> <p>For defaults see the options in <c>manager_config_opt()</c>.</p> </item> - <marker id="manager_config_dir"></marker> - <tag><c><![CDATA[manager_config_dir = dir() <mandatory>]]></c></tag> + <tag><marker id="manager_config_dir"></marker> + <c><![CDATA[manager_config_dir = dir() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP manager configuration files are stored.</p> </item> - <marker id="manager_config_db_dir"></marker> - <tag><c><![CDATA[manager_db_dir = dir() <mandatory>]]></c></tag> + <tag><marker id="manager_config_db_dir"></marker> + <c><![CDATA[manager_db_dir = dir() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP manager store persistent data.</p> </item> - <marker id="manager_config_repair"></marker> - <tag><c><![CDATA[manager_repair() = false | true | force <optional>]]></c></tag> + <tag><marker id="manager_config_repair"></marker> + <c><![CDATA[manager_repair() = false | true | force <optional>]]></c></tag> <item> <p>Defines the repair option for the persistent database (if and how the table is repaired when opened). </p> <p>Default is <c>true</c>.</p> </item> - <marker id="manager_config_auto_save"></marker> - <tag><c><![CDATA[manager_auto_save() = integer() | infinity <optional>]]></c></tag> + <tag><marker id="manager_config_auto_save"></marker> + <c><![CDATA[manager_auto_save() = integer() | infinity <optional>]]></c></tag> <item> <p>The auto save interval. The table is flushed to disk whenever not accessed for this amount of time.</p> <p>Default is <c>5000</c>.</p> </item> - <marker id="manager_irb"></marker> - <tag><c><![CDATA[manager_irb() = auto | user | {user, integer()} <optional>]]></c></tag> + <tag><marker id="manager_irb"></marker> + <c><![CDATA[manager_irb() = auto | user | {user, integer()} <optional>]]></c></tag> <item> <p>This option defines how the manager will handle the sending of response (acknowledgment) to received inform-requests. </p> @@ -672,16 +674,16 @@ <p>Default is <c>auto</c>.</p> </item> - <marker id="manager_mibs"></marker> - <tag><c><![CDATA[manager_mibs() = [string()] <optional>]]></c></tag> + <tag><marker id="manager_mibs"></marker> + <c><![CDATA[manager_mibs() = [string()] <optional>]]></c></tag> <item> <p>Specifies a list of MIBs (including path) and defines which MIBs are initially loaded into the SNMP manager. </p> <p>Default is <c>[]</c>.</p> </item> - <marker id="manager_net_if"></marker> - <tag><c><![CDATA[manager_net_if() = [manager_net_if_opt()] <optional>]]></c></tag> + <tag><marker id="manager_net_if"></marker> + <c><![CDATA[manager_net_if() = [manager_net_if_opt()] <optional>]]></c></tag> <item> <p><c>manager_net_if_opt() = {module, manager_net_if_module()} | {verbosity, verbosity()} | @@ -691,8 +693,8 @@ <p>For defaults see the options in <c>manager_net_if_opt()</c>.</p> </item> - <marker id="manager_ni_opts"></marker> - <tag><c><![CDATA[manager_net_if_options() = [manager_net_if_option()] <optional>]]></c></tag> + <tag><marker id="manager_ni_opts"></marker> + <c><![CDATA[manager_net_if_options() = [manager_net_if_option()] <optional>]]></c></tag> <item> <p><c>manager_net_if_option() = {bind_to, bind_to()} | {sndbuf, sndbuf()} | @@ -705,8 +707,8 @@ <p>For defaults see the options in <c>manager_net_if_option()</c>.</p> </item> - <marker id="manager_ni_module"></marker> - <tag><c><![CDATA[manager_net_if_module() = atom() <optional>]]></c></tag> + <tag><marker id="manager_ni_module"></marker> + <c><![CDATA[manager_net_if_module() = atom() <optional>]]></c></tag> <item> <p>The module which handles the network interface part for the SNMP manager. It must implement the @@ -714,8 +716,8 @@ <p>Default is <c>snmpm_net_if</c>.</p> </item> - <marker id="manager_ni_filter_opts"></marker> - <tag><c><![CDATA[manager_net_if_filter_options() = [manager_net_if_filter_option()] <optional>]]></c></tag> + <tag><marker id="manager_ni_filter_opts"></marker> + <c><![CDATA[manager_net_if_filter_options() = [manager_net_if_filter_option()] <optional>]]></c></tag> <item> <p><c>manager_net_if_filter_option() = {module, manager_net_if_filter_module()}</c></p> <p>These options are actually specific to the used module. @@ -725,8 +727,8 @@ <c>manager_net_if_filter_option()</c>.</p> </item> - <marker id="manager_ni_filter_module"></marker> - <tag><c><![CDATA[manager_net_if_filter_module() = atom() <optional>]]></c></tag> + <tag><marker id="manager_ni_filter_module"></marker> + <c><![CDATA[manager_net_if_filter_module() = atom() <optional>]]></c></tag> <item> <p>Module which handles the network interface filter part for the SNMP manager. Must implement the @@ -734,16 +736,16 @@ <p>Default is <c>snmpm_net_if_filter</c>.</p> </item> - <marker id="manager_def_user_module"></marker> - <tag><c><![CDATA[def_user_module() = atom() <optional>]]></c></tag> + <tag><marker id="manager_def_user_module"></marker> + <c><![CDATA[def_user_module() = atom() <optional>]]></c></tag> <item> <p>The module implementing the default user. See the <seealso marker="snmpm_user">snmpm_user</seealso> behaviour.</p> <p>Default is <c>snmpm_user_default</c>.</p> </item> - <marker id="manager_def_user_data"></marker> - <tag><c><![CDATA[def_user_data() = term() <optional>]]></c></tag> + <tag><marker id="manager_def_user_data"></marker> + <c><![CDATA[def_user_data() = term() <optional>]]></c></tag> <item> <p>Data for the default user. Passed to the user module when calling the callback functions.</p> @@ -754,8 +756,8 @@ <marker id="common_types"></marker> <p>Common config types:</p> <taglist> - <marker id="restart_type"></marker> - <tag><c>restart_type() = permanent | transient | temporary</c></tag> + <tag><marker id="restart_type"></marker> + <c>restart_type() = permanent | transient | temporary</c></tag> <item> <p>See <seealso marker="stdlib:supervisor#child_spec">supervisor</seealso> documentation for more info.</p> @@ -763,8 +765,8 @@ for the manager.</p> </item> - <marker id="db_init_error"></marker> - <tag><c>db_init_error() = terminate | create | create_db_and_dir</c></tag> + <tag><marker id="db_init_error"></marker> + <c>db_init_error() = terminate | create | create_db_and_dir</c></tag> <item> <p>Defines what to do if the agent or manager is unable to open an existing database file. <c>terminate</c> means that the @@ -776,31 +778,31 @@ <p>Default is <c>terminate</c>.</p> </item> - <marker id="prio"></marker> - <tag><c><![CDATA[priority() = atom() <optional>]]></c></tag> + <tag><marker id="prio"></marker> + <c><![CDATA[priority() = atom() <optional>]]></c></tag> <item> <p>Defines the Erlang priority for all SNMP processes.</p> <p>Default is <c>normal</c>.</p> </item> - <marker id="versions"></marker> - <tag><c><![CDATA[versions() = [version()] <optional>]]></c></tag> + <tag><marker id="versions"></marker> + <c><![CDATA[versions() = [version()] <optional>]]></c></tag> <item> <p><c>version() = v1 | v2 | v3</c></p> <p>Which SNMP versions shall be accepted/used.</p> <p>Default is <c>[v1,v2,v3]</c>.</p> </item> - <marker id="verbosity"></marker> - <tag><c><![CDATA[verbosity() = silence | info | log | debug | trace <optional>]]></c></tag> + <tag><marker id="verbosity"></marker> + <c><![CDATA[verbosity() = silence | info | log | debug | trace <optional>]]></c></tag> <item> <p>Verbosity for a SNMP process. This specifies now much debug info is printed.</p> <p>Default is <c>silence</c>.</p> </item> - <marker id="bind_to"></marker> - <tag><c><![CDATA[bind_to() = bool() <optional>]]></c></tag> + <tag><marker id="bind_to"></marker> + <c><![CDATA[bind_to() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c>, net_if binds to the IP address. If <c>false</c>, net_if listens on any IP address on the host @@ -808,8 +810,8 @@ <p>Default is <c>false</c>.</p> </item> - <marker id="no_reuse"></marker> - <tag><c><![CDATA[no_reuse() = bool() <optional>]]></c></tag> + <tag><marker id="no_reuse"></marker> + <c><![CDATA[no_reuse() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c>, net_if does not specify that the IP and port address should be reusable. If <c>false</c>, @@ -817,30 +819,30 @@ <p>Default is <c>false</c>.</p> </item> - <marker id="recbuf"></marker> - <tag><c><![CDATA[recbuf() = integer() <optional>]]></c></tag> + <tag><marker id="recbuf"></marker> + <c><![CDATA[recbuf() = integer() <optional>]]></c></tag> <item> <p>Receive buffer size. </p> <p>Default value is defined by <c>gen_udp</c>.</p> </item> - <marker id="sndbuf"></marker> - <tag><c><![CDATA[sndbuf() = integer() <optional>]]></c></tag> + <tag><marker id="sndbuf"></marker> + <c><![CDATA[sndbuf() = integer() <optional>]]></c></tag> <item> <p>Send buffer size. </p> <p>Default value is defined by <c>gen_udp</c>.</p> </item> - <marker id="note_store"></marker> - <tag><c><![CDATA[note_store() = [note_store_opt()] <optional>]]></c></tag> + <tag><marker id="note_store"></marker> + <c><![CDATA[note_store() = [note_store_opt()] <optional>]]></c></tag> <item> <p><c>note_store_opt() = {timeout, note_store_timeout()} | {verbosity, verbosity()}</c></p> <p>Specifies the start-up verbosity for the SNMP note store.</p> <p>For defaults see the options in <c>note_store_opt()</c>.</p> </item> - <marker id="ns_timeout"></marker> - <tag><c><![CDATA[note_store_timeout() = integer() <optional>]]></c></tag> + <tag><marker id="ns_timeout"></marker> + <c><![CDATA[note_store_timeout() = integer() <optional>]]></c></tag> <item> <p>Note cleanup time. When storing a note in the note store, each note is given lifetime. Every <c>timeout</c> the note_store @@ -850,8 +852,8 @@ </item> - <marker id="audit_trail_log"></marker> - <tag><c><![CDATA[audit_trail_log() = [audit_trail_log_opt()] <optional>]]></c></tag> + <tag><marker id="audit_trail_log"></marker> + <c><![CDATA[audit_trail_log() = [audit_trail_log_opt()] <optional>]]></c></tag> <item> <p><c>audit_trail_log_opt() = {type, atl_type()} | {dir, atl_dir()} | {size, atl_size()} | {repair, atl_repair()} | {seqno, atl_seqno()}</c></p> <p>If present, this option specifies the options for the @@ -861,8 +863,8 @@ <p>If not present, audit trail logging is not used.</p> </item> - <marker id="atl_type"></marker> - <tag><c><![CDATA[atl_type() = read | write | read_write <optional>]]></c></tag> + <tag><marker id="atl_type"></marker> + <c><![CDATA[atl_type() = read | write | read_write <optional>]]></c></tag> <item> <p>Specifies what type of an audit trail log should be used. The effect of the type is actually different for the the agent @@ -883,16 +885,16 @@ <p>Default is <c>read_write</c>.</p> </item> - <marker id="atl_dir"></marker> - <tag><c><![CDATA[atl_dir = dir() <mandatory>]]></c></tag> + <tag><marker id="atl_dir"></marker> + <c><![CDATA[atl_dir = dir() <mandatory>]]></c></tag> <item> <p>Specifies where the audit trail log should be stored.</p> <p>If <c>audit_trail_log</c> specifies that logging should take place, this parameter <em>must</em> be defined.</p> </item> - <marker id="atl_size"></marker> - <tag><c><![CDATA[atl_size() = {integer(), integer()} <mandatory>]]></c></tag> + <tag><marker id="atl_size"></marker> + <c><![CDATA[atl_size() = {integer(), integer()} <mandatory>]]></c></tag> <item> <p>Specifies the size of the audit trail log. This parameter is sent to <c>disk_log</c>. </p> @@ -900,8 +902,8 @@ take place, this parameter <em>must</em> be defined.</p> </item> - <marker id="atl_repair"></marker> - <tag><c><![CDATA[atl_repair() = true | false | truncate | snmp_repair <optional>]]></c></tag> + <tag><marker id="atl_repair"></marker> + <c><![CDATA[atl_repair() = true | false | truncate | snmp_repair <optional>]]></c></tag> <item> <p>Specifies if and how the audit trail log shall be repaired when opened. Unless this parameter has the value <c>snmp_repair</c> @@ -913,8 +915,8 @@ <p>Default is <c>true</c>.</p> </item> - <marker id="atl_seqno"></marker> - <tag><c><![CDATA[atl_seqno() = true | false <optional>]]></c></tag> + <tag><marker id="atl_seqno"></marker> + <c><![CDATA[atl_seqno() = true | false <optional>]]></c></tag> <item> <p>Specifies if the audit trail log entries will be (sequence) numbered or not. The range of the sequence numbers are according diff --git a/lib/snmp/doc/src/snmp_config.xml b/lib/snmp/doc/src/snmp_config.xml index f10574a2a9..a085252d90 100644 --- a/lib/snmp/doc/src/snmp_config.xml +++ b/lib/snmp/doc/src/snmp_config.xml @@ -130,16 +130,16 @@ <marker id="agent_opts_and_types"></marker> <p>Agent specific config options and types:</p> <taglist> - <marker id="agent_type"></marker> - <tag><c><![CDATA[agent_type() = master | sub <optional>]]></c></tag> + <tag><marker id="agent_type"></marker> + <c><![CDATA[agent_type() = master | sub <optional>]]></c></tag> <item> <p>If <c>master</c>, one master agent is started. Otherwise, no agents are started. </p> <p>Default is <c>master</c>.</p> </item> - <marker id="agent_disco"></marker> - <tag><c><![CDATA[agent_discovery() = [agent_discovery_opt()] <optional>]]></c></tag> + <tag><marker id="agent_disco"></marker> + <c><![CDATA[agent_discovery() = [agent_discovery_opt()] <optional>]]></c></tag> <item> <p><c>agent_discovery_opt() = {terminating, agent_terminating_discovery_opts()} | @@ -151,8 +151,8 @@ <p>For defaults see the options in <c>agent_discovery_opt()</c>.</p> </item> - <marker id="agent_term_disco_opts"></marker> - <tag><c><![CDATA[agent_terminating_discovery_opts() = [agent_terminating_discovery_opt()] <optional>]]></c></tag> + <tag><marker id="agent_term_disco_opts"></marker> + <c><![CDATA[agent_terminating_discovery_opts() = [agent_terminating_discovery_opt()] <optional>]]></c></tag> <item> <p><c>agent_terminating_discovery_opt() = {enable, boolean()} | @@ -169,8 +169,8 @@ </list> </item> - <marker id="agent_orig_disco_opts"></marker> - <tag><c><![CDATA[agent_originating_discovery_opts() = [agent_originating_discovery_opt()] <optional>]]></c></tag> + <tag><marker id="agent_orig_disco_opts"></marker> + <c><![CDATA[agent_originating_discovery_opts() = [agent_originating_discovery_opt()] <optional>]]></c></tag> <item> <p><c>agent_originating_discovery_opt() = {enable, boolean()}</c></p> @@ -183,38 +183,38 @@ </list> </item> - <marker id="agent_mt"></marker> - <tag><c><![CDATA[multi_threaded() = bool() <optional>]]></c></tag> + <tag><marker id="agent_mt"></marker> + <c><![CDATA[multi_threaded() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c>, the agent is multi-threaded, with one thread for each get request. </p> <p>Default is <c>false</c>.</p> </item> - <marker id="agent_data_dir"></marker> - <tag><c><![CDATA[db_dir() = string() <mandatory>]]></c></tag> + <tag><marker id="agent_data_dir"></marker> + <c><![CDATA[db_dir() = string() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP agent internal db files are stored.</p> </item> - <marker id="agent_gb_max_vbs"></marker> - <tag><c><![CDATA[gb_max_vbs() = pos_integer() | infinity <optional>]]></c></tag> + <tag><marker id="agent_gb_max_vbs"></marker> + <c><![CDATA[gb_max_vbs() = pos_integer() | infinity <optional>]]></c></tag> <item> <p>Defines the maximum number of varbinds allowed in a Get-BULK response.</p> <p>Default is <c>1000</c>.</p> </item> - <marker id="agent_local_db"></marker> - <tag><c><![CDATA[local_db() = [local_db_opt()] <optional>]]></c></tag> + <tag><marker id="agent_local_db"></marker> + <c><![CDATA[local_db() = [local_db_opt()] <optional>]]></c></tag> <item> <p><c>local_db_opt() = {repair, agent_repair()} | {auto_save, agent_auto_save()} | {verbosity, verbosity()}</c></p> <p>Defines options specific for the SNMP agent local database.</p> <p>For defaults see the options in <c>local_db_opt()</c>.</p> </item> - <marker id="agent_ldb_repair"></marker> - <tag><c><![CDATA[agent_repair() = false | true | force <optional>]]></c></tag> + <tag><marker id="agent_ldb_repair"></marker> + <c><![CDATA[agent_repair() = false | true | force <optional>]]></c></tag> <item> <p>When starting snmpa_local_db it always tries to open an existing database. If <c>false</c>, and some errors occur, a new @@ -224,16 +224,16 @@ <p>Default is <c>true</c>.</p> </item> - <marker id="agent_ldb_auto_save"></marker> - <tag><c><![CDATA[agent_auto_save() = integer() | infinity <optional>]]></c></tag> + <tag><marker id="agent_ldb_auto_save"></marker> + <c><![CDATA[agent_auto_save() = integer() | infinity <optional>]]></c></tag> <item> <p>The auto save interval. The table is flushed to disk whenever not accessed for this amount of time.</p> <p>Default is <c>5000</c>.</p> </item> - <marker id="agent_net_if"></marker> - <tag><c><![CDATA[agent_net_if() = [agent_net_if_opt()] <optional>]]></c></tag> + <tag><marker id="agent_net_if"></marker> + <c><![CDATA[agent_net_if() = [agent_net_if_opt()] <optional>]]></c></tag> <item> <p><c>agent_net_if_option() = {module, agent_net_if_module()} | {verbosity, verbosity()} | @@ -243,8 +243,8 @@ <p>For defaults see the options in <c>agent_net_if_opt()</c>.</p> </item> - <marker id="agent_ni_module"></marker> - <tag><c><![CDATA[agent_net_if_module() = atom() <optional>]]></c></tag> + <tag><marker id="agent_ni_module"></marker> + <c><![CDATA[agent_net_if_module() = atom() <optional>]]></c></tag> <item> <p>Module which handles the network interface part for the SNMP agent. Must implement the @@ -252,8 +252,8 @@ <p>Default is <c>snmpa_net_if</c>.</p> </item> - <marker id="agent_ni_opts"></marker> - <tag><c><![CDATA[agent_net_if_options() = [agent_net_if_option()] <optional>]]></c></tag> + <tag><marker id="agent_ni_opts"></marker> + <c><![CDATA[agent_net_if_options() = [agent_net_if_option()] <optional>]]></c></tag> <item> <p><c>agent_net_if_option() = {bind_to, bind_to()} | {sndbuf, sndbuf()} | @@ -267,15 +267,15 @@ <p>For defaults see the options in <c>agent_net_if_option()</c>.</p> </item> - <marker id="agent_ni_req_limit"></marker> - <tag><c><![CDATA[req_limit() = integer() | infinity <optional>]]></c></tag> + <tag><marker id="agent_ni_req_limit"></marker> + <c><![CDATA[req_limit() = integer() | infinity <optional>]]></c></tag> <item> <p>Max number of simultaneous requests handled by the agent.</p> <p>Default is <c>infinity</c>.</p> </item> - <marker id="agent_ni_filter_opts"></marker> - <tag><c><![CDATA[agent_net_if_filter_options() = [agent_net_if_filter_option()] <optional>]]></c></tag> + <tag><marker id="agent_ni_filter_opts"></marker> + <c><![CDATA[agent_net_if_filter_options() = [agent_net_if_filter_option()] <optional>]]></c></tag> <item> <p><c><![CDATA[agent_net_if_filter_option() = {module, agent_net_if_filter_module()}]]></c></p> <p>These options are actually specific to the used module. @@ -284,8 +284,8 @@ <p>For defaults see the options in <c>agent_net_if_filter_option()</c>.</p> </item> - <marker id="agent_ni_filter_module"></marker> - <tag><c><![CDATA[agent_net_if_filter_module() = atom() <optional>]]></c></tag> + <tag><marker id="agent_ni_filter_module"></marker> + <c><![CDATA[agent_net_if_filter_module() = atom() <optional>]]></c></tag> <item> <p>Module which handles the network interface filter part for the SNMP agent. Must implement the @@ -294,8 +294,8 @@ <p>Default is <c>snmpa_net_if_filter</c>.</p> </item> - <marker id="agent_mibs"></marker> - <tag><c><![CDATA[agent_mibs() = [string()] <optional>]]></c></tag> + <tag><marker id="agent_mibs"></marker> + <c><![CDATA[agent_mibs() = [string()] <optional>]]></c></tag> <item> <p>Specifies a list of MIBs (including path) that defines which MIBs are initially loaded into the SNMP master agent. </p> @@ -309,8 +309,8 @@ <p>Default is <c>[]</c>.</p> </item> - <marker id="agent_mib_storage"></marker> - <tag><c><![CDATA[mib_storage() = [mib_storage_opt()] <optional>]]></c></tag> + <tag><marker id="agent_mib_storage"></marker> + <c><![CDATA[mib_storage() = [mib_storage_opt()] <optional>]]></c></tag> <item> <p><c>mib_storage_opt() = {module, mib_storage_module()} | {options, mib_storage_options()}</c></p> <p>This option specifies how basic mib data is stored. @@ -319,8 +319,8 @@ <p>Default is <c>[{module, snmpa_mib_storage_ets}]</c>. </p> </item> - <marker id="agent_mst_module"></marker> - <tag><c><![CDATA[mib_storage_module() = snmpa_mib_data_ets | snmpa_mib_data_dets | snmpa_mib_data_mnesia | module()]]></c></tag> + <tag><marker id="agent_mst_module"></marker> + <c><![CDATA[mib_storage_module() = snmpa_mib_data_ets | snmpa_mib_data_dets | snmpa_mib_data_mnesia | module()]]></c></tag> <item> <p>Defines the mib storage module of the SNMP agent as defined by the <seealso marker="snmpa_mib_storage">snmpa_mib_storage</seealso> @@ -334,8 +334,8 @@ <p>Default module is <c>snmpa_mib_storage_ets</c>. </p> </item> - <marker id="agent_mst_options"></marker> - <tag><c><![CDATA[mib_storage_options() = list() <optional>]]></c></tag> + <tag><marker id="agent_mst_options"></marker> + <c><![CDATA[mib_storage_options() = list() <optional>]]></c></tag> <item> <p>This is implementattion depended. That is, it depends on the module. For each module a specific set of options are valid. @@ -429,8 +429,8 @@ This is the old format which is "supported", but not documented, in so far as it will be converted to the new format if found. - <marker id="agent_mib_storage"></marker> - <tag><c><![CDATA[mib_storage() = ets | {ets, Dir} | {ets, Dir, Action} | dets | {dets, Dir} | {dets, Dir, Action} | mnesia | {mnesia, Nodes} | {mnesia, Nodes, Action} <optional>]]></c></tag> + <tag><marker id="agent_mib_storage"></marker> + <c><![CDATA[mib_storage() = ets | {ets, Dir} | {ets, Dir, Action} | dets | {dets, Dir} | {dets, Dir, Action} | mnesia | {mnesia, Nodes} | {mnesia, Nodes, Action} <optional>]]></c></tag> <item> <p>Specifies how info retrieved from the mibs will be stored.</p> <p>If <c>mib_storage</c> is <c>{ets, Dir}</c>, the table will also be @@ -456,16 +456,16 @@ in so far as it will be converted to the new format if found. </item> --> - <marker id="agent_mib_server"></marker> - <tag><c><![CDATA[mib_server() = [mib_server_opt()] <optional>]]></c></tag> + <tag><marker id="agent_mib_server"></marker> + <c><![CDATA[mib_server() = [mib_server_opt()] <optional>]]></c></tag> <item> <p><c>mib_server_opt() = {mibentry_override, mibentry_override()} | {trapentry_override, trapentry_override()} | {verbosity, verbosity()} | {cache, mibs_cache()} | {data_module, mib_server_data_module()}</c></p> <p>Defines options specific for the SNMP agent mib server. </p> <p>For defaults see the options in <c>mib_server_opt()</c>.</p> </item> - <marker id="agent_ms_meo"></marker> - <tag><c><![CDATA[mibentry_override() = bool() <optional>]]></c></tag> + <tag><marker id="agent_ms_meo"></marker> + <c><![CDATA[mibentry_override() = bool() <optional>]]></c></tag> <item> <p>If this value is false, then when loading a mib each mib- entry is checked prior to installation of the mib. @@ -474,8 +474,8 @@ in so far as it will be converted to the new format if found. <p>Default is <c>false</c>.</p> </item> - <marker id="agent_ms_teo"></marker> - <tag><c><![CDATA[trapentry_override() = bool() <optional>]]></c></tag> + <tag><marker id="agent_ms_teo"></marker> + <c><![CDATA[trapentry_override() = bool() <optional>]]></c></tag> <item> <p>If this value is false, then when loading a mib each trap is checked prior to installation of the mib. @@ -484,11 +484,13 @@ in so far as it will be converted to the new format if found. <p>Default is <c>false</c>.</p> </item> - <marker id="agent_ms_data_module"></marker> + <!-- - <tag><c><![CDATA[mib_server_data_module() = snmpa_mib_data_tttn | snmpa_mib_data_ttln | module() <optional>]]></c></tag> + <tag><marker id="agent_ms_data_module"></marker> + <c><![CDATA[mib_server_data_module() = snmpa_mib_data_tttn | snmpa_mib_data_ttln | module() <optional>]]></c></tag> --> - <tag><c><![CDATA[mib_server_data_module() = snmpa_mib_data_tttn | module() <optional>]]></c></tag> + <tag><marker id="agent_ms_data_module"></marker> + <c><![CDATA[mib_server_data_module() = snmpa_mib_data_tttn | module() <optional>]]></c></tag> <item> <p>Defines the backend data module of the SNMP agent mib-server as defined by the @@ -505,24 +507,24 @@ in so far as it will be converted to the new format if found. <p>Default module is <c>snmpa_mib_data_tttn</c>. </p> </item> - <marker id="agent_ms_cache"></marker> - <tag><c><![CDATA[mibs_cache() = bool() | mibs_cache_opts() <optional>]]></c></tag> + <tag><marker id="agent_ms_cache"></marker> + <c><![CDATA[mibs_cache() = bool() | mibs_cache_opts() <optional>]]></c></tag> <item> <p>Shall the agent utilize the mib server lookup cache or not.</p> <p>Default is <c>true</c> (in which case the <c>mibs_cache_opts()</c> default values apply).</p> </item> - <marker id="agent_ms_cache_opts"></marker> - <tag><c><![CDATA[mibs_cache_opts() = [mibs_cache_opt()] <optional>]]></c></tag> + <tag><marker id="agent_ms_cache_opts"></marker> + <c><![CDATA[mibs_cache_opts() = [mibs_cache_opt()] <optional>]]></c></tag> <item> <p><c>mibs_cache_opt() = {autogc, mibs_cache_autogc()} | {gclimit, mibs_cache_gclimit()} | {age, mibs_cache_age()}</c></p> <p>Defines options specific for the SNMP agent mib server cache. </p> <p>For defaults see the options in <c>mibs_cache_opt()</c>.</p> </item> - <marker id="agent_ms_cache_autogc"></marker> - <tag><c><![CDATA[mibs_cache_autogc() = bool() <optional>]]></c></tag> + <tag><marker id="agent_ms_cache_autogc"></marker> + <c><![CDATA[mibs_cache_autogc() = bool() <optional>]]></c></tag> <item> <p>Defines if the mib server shall perform cache gc automatically or leave it to the user (see @@ -530,8 +532,8 @@ in so far as it will be converted to the new format if found. <p>Default is <c>true</c>.</p> </item> - <marker id="agent_ms_cache_age"></marker> - <tag><c><![CDATA[mibs_cache_age() = integer() > 0 <optional>]]></c></tag> + <tag><marker id="agent_ms_cache_age"></marker> + <c><![CDATA[mibs_cache_age() = integer() > 0 <optional>]]></c></tag> <item> <p>Defines how old the entries in the cache will be allowed to become before they are GC'ed (assuming GC is performed). @@ -540,8 +542,8 @@ in so far as it will be converted to the new format if found. <p>Default is <c>10 timutes</c>.</p> </item> - <marker id="agent_ms_cache_gclimit"></marker> - <tag><c><![CDATA[mibs_cache_gclimit() = integer() > 0 | infinity <optional>]]></c></tag> + <tag><marker id="agent_ms_cache_gclimit"></marker> + <c><![CDATA[mibs_cache_gclimit() = integer() > 0 | infinity <optional>]]></c></tag> <item> <p>When performing a GC, this is the max number of cache entries that will be deleted from the cache. </p> @@ -551,8 +553,8 @@ in so far as it will be converted to the new format if found. <p>Default is <c>100</c>.</p> </item> - <marker id="agent_error_report_mod"></marker> - <tag><c><![CDATA[error_report_mod() = atom() <optional>]]></c></tag> + <tag><marker id="agent_error_report_mod"></marker> + <c><![CDATA[error_report_mod() = atom() <optional>]]></c></tag> <item> <p>Defines an error report module, implementing the <seealso marker="snmpa_error_report">snmpa_error_report</seealso> @@ -561,38 +563,38 @@ in so far as it will be converted to the new format if found. <p>Default is <c>snmpa_error_logger</c>.</p> </item> - <marker id="agent_symbolic_store"></marker> - <tag><c>symbolic_store() = [symbolic_store_opt()]</c></tag> + <tag><marker id="agent_symbolic_store"></marker> + <c>symbolic_store() = [symbolic_store_opt()]</c></tag> <item> <p><c>symbolic_store_opt() = {verbosity, verbosity()}</c></p> <p>Defines options specific for the SNMP agent symbolic store. </p> <p>For defaults see the options in <c>symbolic_store_opt()</c>.</p> </item> - <marker id="agent_target_cache"></marker> - <tag><c>target_cache() = [target_cache_opt()]</c></tag> + <tag><marker id="agent_target_cache"></marker> + <c>target_cache() = [target_cache_opt()]</c></tag> <item> <p><c>target_cache_opt() = {verbosity, verbosity()}</c></p> <p>Defines options specific for the SNMP agent target cache. </p> <p>For defaults see the options in <c>target_cache_opt()</c>.</p> </item> - <marker id="agent_config"></marker> - <tag><c><![CDATA[agent_config() = [agent_config_opt()] <mandatory>]]></c></tag> + <tag><marker id="agent_config"></marker> + <c><![CDATA[agent_config() = [agent_config_opt()] <mandatory>]]></c></tag> <item> <p><c>agent_config_opt() = {dir, agent_config_dir()} | {force_load, force_load()} | {verbosity, verbosity()}</c></p> <p>Defines specific config related options for the SNMP agent. </p> <p>For defaults see the options in <c>agent_config_opt()</c>.</p> </item> - <marker id="agent_config_dir"></marker> - <tag><c><![CDATA[agent_config_dir = dir() <mandatory>]]></c></tag> + <tag><marker id="agent_config_dir"></marker> + <c><![CDATA[agent_config_dir = dir() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP agent configuration files are stored.</p> </item> - <marker id="agent_force_load"></marker> - <tag><c><![CDATA[force_load() = bool() <optional>]]></c></tag> + <tag><marker id="agent_force_load"></marker> + <c><![CDATA[force_load() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c> the configuration files are re-read during start-up, and the contents of the configuration @@ -606,16 +608,16 @@ in so far as it will be converted to the new format if found. <marker id="manager_opts_and_types"></marker> <p>Manager specific config options and types:</p> <taglist> - <marker id="manager_server"></marker> - <tag><c><![CDATA[server() = [server_opt()] <optional>]]></c></tag> + <tag><marker id="manager_server"></marker> + <c><![CDATA[server() = [server_opt()] <optional>]]></c></tag> <item> <p><c>server_opt() = {timeout, server_timeout()} | {verbosity, verbosity()}</c></p> <p>Specifies the options for the manager server process.</p> <p>Default is <c>silence</c>.</p> </item> - <marker id="manager_server_timeout"></marker> - <tag><c><![CDATA[server_timeout() = integer() <optional>]]></c></tag> + <tag><marker id="manager_server_timeout"></marker> + <c><![CDATA[server_timeout() = integer() <optional>]]></c></tag> <item> <p>Asynchronous request cleanup time. For every requests, some info is stored internally, in order to be able to @@ -635,44 +637,44 @@ in so far as it will be converted to the new format if found. <p>Default is <c>30000</c>.</p> </item> - <marker id="manager_config"></marker> - <tag><c><![CDATA[manager_config() = [manager_config_opt()] <mandatory>]]></c></tag> + <tag><marker id="manager_config"></marker> + <c><![CDATA[manager_config() = [manager_config_opt()] <mandatory>]]></c></tag> <item> <p><c>manager_config_opt() = {dir, manager_config_dir()} | {db_dir, manager_db_dir()} | {db_init_error, db_init_error()} | {repair, manager_repair()} | {auto_save, manager_auto_save()} | {verbosity, verbosity()}</c></p> <p>Defines specific config related options for the SNMP manager. </p> <p>For defaults see the options in <c>manager_config_opt()</c>.</p> </item> - <marker id="manager_config_dir"></marker> - <tag><c><![CDATA[manager_config_dir = dir() <mandatory>]]></c></tag> + <tag><marker id="manager_config_dir"></marker> + <c><![CDATA[manager_config_dir = dir() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP manager configuration files are stored.</p> </item> - <marker id="manager_config_db_dir"></marker> - <tag><c><![CDATA[manager_db_dir = dir() <mandatory>]]></c></tag> + <tag><marker id="manager_config_db_dir"></marker> + <c><![CDATA[manager_db_dir = dir() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP manager store persistent data.</p> </item> - <marker id="manager_config_repair"></marker> - <tag><c><![CDATA[manager_repair() = false | true | force <optional>]]></c></tag> + <tag><marker id="manager_config_repair"></marker> + <c><![CDATA[manager_repair() = false | true | force <optional>]]></c></tag> <item> <p>Defines the repair option for the persistent database (if and how the table is repaired when opened). </p> <p>Default is <c>true</c>.</p> </item> - <marker id="manager_config_auto_save"></marker> - <tag><c><![CDATA[manager_auto_save() = integer() | infinity <optional>]]></c></tag> + <tag><marker id="manager_config_auto_save"></marker> + <c><![CDATA[manager_auto_save() = integer() | infinity <optional>]]></c></tag> <item> <p>The auto save interval. The table is flushed to disk whenever not accessed for this amount of time.</p> <p>Default is <c>5000</c>.</p> </item> - <marker id="manager_irb"></marker> - <tag><c><![CDATA[manager_irb() = auto | user | {user, integer()} <optional>]]></c></tag> + <tag><marker id="manager_irb"></marker> + <c><![CDATA[manager_irb() = auto | user | {user, integer()} <optional>]]></c></tag> <item> <p>This option defines how the manager will handle the sending of response (acknowledgment) to received inform-requests. </p> @@ -701,16 +703,16 @@ in so far as it will be converted to the new format if found. <p>Default is <c>auto</c>.</p> </item> - <marker id="manager_mibs"></marker> - <tag><c><![CDATA[manager_mibs() = [string()] <optional>]]></c></tag> + <tag><marker id="manager_mibs"></marker> + <c><![CDATA[manager_mibs() = [string()] <optional>]]></c></tag> <item> <p>Specifies a list of MIBs (including path) and defines which MIBs are initially loaded into the SNMP manager. </p> <p>Default is <c>[]</c>.</p> </item> - <marker id="manager_net_if"></marker> - <tag><c><![CDATA[manager_net_if() = [manager_net_if_opt()] <optional>]]></c></tag> + <tag><marker id="manager_net_if"></marker> + <c><![CDATA[manager_net_if() = [manager_net_if_opt()] <optional>]]></c></tag> <item> <p><c>manager_net_if_opt() = {module, manager_net_if_module()} | {verbosity, verbosity()} | @@ -720,8 +722,8 @@ in so far as it will be converted to the new format if found. <p>For defaults see the options in <c>manager_net_if_opt()</c>.</p> </item> - <marker id="manager_ni_opts"></marker> - <tag><c><![CDATA[manager_net_if_options() = [manager_net_if_option()] <optional>]]></c></tag> + <tag><marker id="manager_ni_opts"></marker> + <c><![CDATA[manager_net_if_options() = [manager_net_if_option()] <optional>]]></c></tag> <item> <p><c>manager_net_if_option() = {bind_to, bind_to()} | {sndbuf, sndbuf()} | @@ -734,8 +736,8 @@ in so far as it will be converted to the new format if found. <p>For defaults see the options in <c>manager_net_if_option()</c>.</p> </item> - <marker id="manager_ni_module"></marker> - <tag><c><![CDATA[manager_net_if_module() = atom() <optional>]]></c></tag> + <tag><marker id="manager_ni_module"></marker> + <c><![CDATA[manager_net_if_module() = atom() <optional>]]></c></tag> <item> <p>The module which handles the network interface part for the SNMP manager. It must implement the @@ -743,8 +745,8 @@ in so far as it will be converted to the new format if found. <p>Default is <c>snmpm_net_if</c>. </p> </item> - <marker id="manager_ni_filter_opts"></marker> - <tag><c><![CDATA[manager_net_if_filter_options() = [manager_net_if_filter_option()] <optional>]]></c></tag> + <tag><marker id="manager_ni_filter_opts"></marker> + <c><![CDATA[manager_net_if_filter_options() = [manager_net_if_filter_option()] <optional>]]></c></tag> <item> <p><c>manager_net_if_filter_option() = {module, manager_net_if_filter_module()}</c></p> <p>These options are actually specific to the used module. @@ -754,8 +756,8 @@ in so far as it will be converted to the new format if found. <c>manager_net_if_filter_option()</c>.</p> </item> - <marker id="manager_ni_filter_module"></marker> - <tag><c><![CDATA[manager_net_if_filter_module() = atom() <optional>]]></c></tag> + <tag><marker id="manager_ni_filter_module"></marker> + <c><![CDATA[manager_net_if_filter_module() = atom() <optional>]]></c></tag> <item> <p>Module which handles the network interface filter part for the SNMP manager. Must implement the @@ -763,16 +765,16 @@ in so far as it will be converted to the new format if found. <p>Default is <c>snmpm_net_if_filter</c>.</p> </item> - <marker id="manager_def_user_module"></marker> - <tag><c><![CDATA[def_user_module() = atom() <optional>]]></c></tag> + <tag><marker id="manager_def_user_module"></marker> + <c><![CDATA[def_user_module() = atom() <optional>]]></c></tag> <item> <p>The module implementing the default user. See the <seealso marker="snmpm_user">snmpm_user</seealso> behaviour.</p> <p>Default is <c>snmpm_user_default</c>.</p> </item> - <marker id="manager_def_user_data"></marker> - <tag><c><![CDATA[def_user_data() = term() <optional>]]></c></tag> + <tag><marker id="manager_def_user_data"></marker> + <c><![CDATA[def_user_data() = term() <optional>]]></c></tag> <item> <p>Data for the default user. Passed to the user when calling the callback functions.</p> @@ -783,8 +785,8 @@ in so far as it will be converted to the new format if found. <marker id="common_types"></marker> <p>Common config types:</p> <taglist> - <marker id="restart_type"></marker> - <tag><c>restart_type() = permanent | transient | temporary</c></tag> + <tag><marker id="restart_type"></marker> + <c>restart_type() = permanent | transient | temporary</c></tag> <item> <p>See <seealso marker="stdlib:supervisor#child_spec">supervisor</seealso> documentation for more info.</p> @@ -792,8 +794,8 @@ in so far as it will be converted to the new format if found. for the manager.</p> </item> - <marker id="db_init_error"></marker> - <tag><c>db_init_error() = terminate | create | create_db_and_dir</c></tag> + <tag><marker id="db_init_error"></marker> + <c>db_init_error() = terminate | create | create_db_and_dir</c></tag> <item> <p>Defines what to do if the agent is unable to open an existing database file. <c>terminate</c> means that the @@ -805,31 +807,31 @@ in so far as it will be converted to the new format if found. <p>Default is <c>terminate</c>.</p> </item> - <marker id="prio"></marker> - <tag><c><![CDATA[priority() = atom() <optional>]]></c></tag> + <tag><marker id="prio"></marker> + <c><![CDATA[priority() = atom() <optional>]]></c></tag> <item> <p>Defines the Erlang priority for all SNMP processes.</p> <p>Default is <c>normal</c>.</p> </item> - <marker id="versions"></marker> - <tag><c><![CDATA[versions() = [version()] <optional>]]></c></tag> + <tag><marker id="versions"></marker> + <c><![CDATA[versions() = [version()] <optional>]]></c></tag> <item> <p><c>version() = v1 | v2 | v3</c></p> <p>Which SNMP versions shall be accepted/used.</p> <p>Default is <c>[v1,v2,v3]</c>.</p> </item> - <marker id="verbosity"></marker> - <tag><c><![CDATA[verbosity() = silence | info | log | debug | trace <optional>]]></c></tag> + <tag><marker id="verbosity"></marker> + <c><![CDATA[verbosity() = silence | info | log | debug | trace <optional>]]></c></tag> <item> <p>Verbosity for a SNMP process. This specifies now much debug info is printed.</p> <p>Default is <c>silence</c>.</p> </item> - <marker id="bind_to"></marker> - <tag><c><![CDATA[bind_to() = bool() <optional>]]></c></tag> + <tag><marker id="bind_to"></marker> + <c><![CDATA[bind_to() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c>, net_if binds to the IP address. If <c>false</c>, net_if listens on any IP address on the host @@ -837,8 +839,8 @@ in so far as it will be converted to the new format if found. <p>Default is <c>false</c>.</p> </item> - <marker id="no_reuse"></marker> - <tag><c><![CDATA[no_reuse() = bool() <optional>]]></c></tag> + <tag><marker id="no_reuse"></marker> + <c><![CDATA[no_reuse() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c>, net_if does not specify that the IP and port address should be reusable. If <c>false</c>, @@ -846,30 +848,30 @@ in so far as it will be converted to the new format if found. <p>Default is <c>false</c>.</p> </item> - <marker id="recbuf"></marker> - <tag><c><![CDATA[recbuf() = integer() <optional>]]></c></tag> + <tag><marker id="recbuf"></marker> + <c><![CDATA[recbuf() = integer() <optional>]]></c></tag> <item> <p>Receive buffer size. </p> <p>Default value is defined by <c>gen_udp</c>.</p> </item> - <marker id="sndbuf"></marker> - <tag><c><![CDATA[sndbuf() = integer() <optional>]]></c></tag> + <tag><marker id="sndbuf"></marker> + <c><![CDATA[sndbuf() = integer() <optional>]]></c></tag> <item> <p>Send buffer size. </p> <p>Default value is defined by <c>gen_udp</c>.</p> </item> - <marker id="note_store"></marker> - <tag><c><![CDATA[note_store() = [note_store_opt()] <optional>]]></c></tag> + <tag><marker id="note_store"></marker> + <c><![CDATA[note_store() = [note_store_opt()] <optional>]]></c></tag> <item> <p><c>note_store_opt() = {timeout, note_store_timeout()} | {verbosity, verbosity()}</c></p> <p>Specifies the options for the SNMP note store.</p> <p>For defaults see the options in <c>note_store_opt()</c>.</p> </item> - <marker id="ns_timeout"></marker> - <tag><c><![CDATA[note_store_timeout() = integer() <optional>]]></c></tag> + <tag><marker id="ns_timeout"></marker> + <c><![CDATA[note_store_timeout() = integer() <optional>]]></c></tag> <item> <p>Note cleanup time. When storing a note in the note store, each note is given lifetime. Every <c>timeout</c> the note_store @@ -878,8 +880,8 @@ in so far as it will be converted to the new format if found. <p>Default is <c>30000</c>.</p> </item> - <marker id="audit_trail_log"></marker> - <tag><c><![CDATA[audit_trail_log() [audit_trail_log_opt()] <optional>]]></c></tag> + <tag><marker id="audit_trail_log"></marker> + <c><![CDATA[audit_trail_log() [audit_trail_log_opt()] <optional>]]></c></tag> <item> <p><c>audit_trail_log_opt() = {type, atl_type()} | {dir, atl_dir()} | {size, atl_size()} | {repair, atl_repair()} | {seqno, atl_seqno()}</c></p> <p>If present, this option specifies the options for the @@ -889,8 +891,8 @@ in so far as it will be converted to the new format if found. <p>If not present, audit trail logging is not used.</p> </item> - <marker id="atl_type"></marker> - <tag><c><![CDATA[atl_type() = read | write | read_write <optional>]]></c></tag> + <tag><marker id="atl_type"></marker> + <c><![CDATA[atl_type() = read | write | read_write <optional>]]></c></tag> <item> <p>Specifies what type of an audit trail log should be used. The effect of the type is actually different for the the agent @@ -911,16 +913,16 @@ in so far as it will be converted to the new format if found. <p>Default is <c>read_write</c>.</p> </item> - <marker id="atl_dir"></marker> - <tag><c><![CDATA[atl_dir = dir() <mandatory>]]></c></tag> + <tag><marker id="atl_dir"></marker> + <c><![CDATA[atl_dir = dir() <mandatory>]]></c></tag> <item> <p>Specifies where the audit trail log should be stored.</p> <p>If <c>audit_trail_log</c> specifies that logging should take place, this parameter <em>must</em> be defined.</p> </item> - <marker id="atl_size"></marker> - <tag><c><![CDATA[atl_size() = {integer(), integer()} <mandatory>]]></c></tag> + <tag><marker id="atl_size"></marker> + <c><![CDATA[atl_size() = {integer(), integer()} <mandatory>]]></c></tag> <item> <p>Specifies the size of the audit trail log. This parameter is sent to <c>disk_log</c>. </p> @@ -928,8 +930,8 @@ in so far as it will be converted to the new format if found. take place, this parameter <em>must</em> be defined.</p> </item> - <marker id="atl_repair"></marker> - <tag><c><![CDATA[atl_repair() = true | false | truncate | snmp_repair <optional>]]></c></tag> + <tag><marker id="atl_repair"></marker> + <c><![CDATA[atl_repair() = true | false | truncate | snmp_repair <optional>]]></c></tag> <item> <p>Specifies if and how the audit trail log shall be repaired when opened. Unless this parameter has the value <c>snmp_repair</c> @@ -941,8 +943,8 @@ in so far as it will be converted to the new format if found. <p>Default is <c>true</c>.</p> </item> - <marker id="atl_seqno"></marker> - <tag><c><![CDATA[atl_seqno() = true | false <optional>]]></c></tag> + <tag><marker id="atl_seqno"></marker> + <c><![CDATA[atl_seqno() = true | false <optional>]]></c></tag> <item> <p>Specifies if the audit trail log entries will be (sequence) numbered or not. The range of the sequence numbers are according diff --git a/lib/snmp/doc/src/snmp_manager_netif.xml b/lib/snmp/doc/src/snmp_manager_netif.xml index 8454d03b17..98d4e7fd96 100644 --- a/lib/snmp/doc/src/snmp_manager_netif.xml +++ b/lib/snmp/doc/src/snmp_manager_netif.xml @@ -75,8 +75,7 @@ <p>In this section a <c>Domain</c> field is the transport domain i.e one of <c>transportDomainUdpIpv4</c> or <c>transportDomainUdpIpv6</c>, and an <c>Addr</c> field is an - <c>{<seealso marker="kernel:inet#type-ip_address">IpAddr</seealso>, - IpPort}</c> tuple.</p> + <c>{</c><seealso marker="kernel:inet#type-ip_address"><c>IpAddr</c></seealso><c>,IpPort}</c> tuple.</p> <p>Net if must send the following message when it receives an SNMP PDU from the network that is aimed for the MasterAgent: diff --git a/lib/snmp/doc/src/snmpa.xml b/lib/snmp/doc/src/snmpa.xml index f205af6e88..c84eeec524 100644 --- a/lib/snmp/doc/src/snmpa.xml +++ b/lib/snmp/doc/src/snmpa.xml @@ -622,12 +622,12 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} <p>Converts an Audit Trail Log to a readable format and prints it on stdio. <c>LogName</c> defaults to "snmpa_log". - <c>LogFile</c> defaults to "snmpa.log". + <c>LogFile</c> defaults to "snmpa.log".</p> <p>The <c>Block</c> option indicates if the log should be blocked during conversion. This could be usefull when converting large logs (when otherwise the log could wrap during conversion). Defaults to <c>true</c>. </p> - See <seealso marker="snmp#log_to_io">snmp:log_to_io</seealso> + <p>See <seealso marker="snmp#log_to_io">snmp:log_to_io</seealso> for more info.</p> <marker id="change_log_size"></marker> diff --git a/lib/snmp/doc/src/snmpm.xml b/lib/snmp/doc/src/snmpm.xml index b14c0e6afd..ab288fd020 100644 --- a/lib/snmp/doc/src/snmpm.xml +++ b/lib/snmp/doc/src/snmpm.xml @@ -1241,12 +1241,12 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 <p>Converts an Audit Trail Log to a readable text file. <c>OutFile</c> defaults to "./snmpm_log.txt". <c>LogName</c> defaults to "snmpm_log". - <c>LogFile</c> defaults to "snmpm.log". + <c>LogFile</c> defaults to "snmpm.log".</p> <p>The <c>Block</c> argument indicates if the log should be blocked during conversion. This could be usefull when converting large logs (when otherwise the log could wrap during conversion). Defaults to <c>true</c>. </p> - See <seealso marker="snmp#log_to_txt">snmp:log_to_txt</seealso> + <p>See <seealso marker="snmp#log_to_txt">snmp:log_to_txt</seealso> for more info.</p> <marker id="log_to_io"></marker> @@ -1280,12 +1280,12 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 <p>Converts an Audit Trail Log to a readable format and prints it on stdio. <c>LogName</c> defaults to "snmpm_log". - <c>LogFile</c> defaults to "snmpm.log". + <c>LogFile</c> defaults to "snmpm.log".</p> <p>The <c>Block</c> argument indicates if the log should be blocked during conversion. This could be usefull when converting large logs (when otherwise the log could wrap during conversion). Defaults to <c>true</c>. </p> - See <seealso marker="snmp#log_to_io">snmp:log_to_io</seealso> + <p>See <seealso marker="snmp#log_to_io">snmp:log_to_io</seealso> for more info.</p> <marker id="change_log_size"></marker> diff --git a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl index 586b7c7171..9e6aa74d45 100644 --- a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl +++ b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl @@ -34,6 +34,8 @@ %% Internal exports -export([check_vacm/1]). +%% +-export([emask2imask/1]). -include("snmp_types.hrl"). diff --git a/lib/snmp/src/agent/snmpa_acm.erl b/lib/snmp/src/agent/snmpa_acm.erl index 7327575846..0264c6a992 100644 --- a/lib/snmp/src/agent/snmpa_acm.erl +++ b/lib/snmp/src/agent/snmpa_acm.erl @@ -280,7 +280,7 @@ validate_mib_view(Oid, MibView) -> end. get_largest_family([{SubTree, Mask, Type} | T], Oid, Res) -> - case check_mask(Oid, SubTree, Mask) of + case check_mask(Oid, SubTree, snmp_view_based_acm_mib:emask2imask(Mask)) of true -> get_largest_family(T, Oid, add_res(length(SubTree), SubTree, Type, Res)); false -> get_largest_family(T, Oid, Res) @@ -345,7 +345,7 @@ validate_all_mib_view([], _MibView) -> %% intelligent. %%----------------------------------------------------------------- is_definitely_not_in_mib_view(Oid, [{SubTree, Mask,?view_included}|T]) -> - case check_maybe_mask(Oid, SubTree, Mask) of + case check_maybe_mask(Oid, SubTree, snmp_view_based_acm_mib:emask2imask(Mask)) of true -> false; false -> is_definitely_not_in_mib_view(Oid, T) end; diff --git a/lib/snmp/src/app/snmp.appup.src b/lib/snmp/src/app/snmp.appup.src index 6632d29457..ca61782639 100644 --- a/lib/snmp/src/app/snmp.appup.src +++ b/lib/snmp/src/app/snmp.appup.src @@ -1,69 +1,24 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1999-2015. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%% -%% %CopyrightEnd% -%% - - +%% -*- erlang -*- {"%VSN%", %% ----- U p g r a d e ------------------------------------------------------- - %% Instruction examples: %% {restart_application, snmp} %% {load_module, snmp_pdus, soft_purge, soft_purge, []} %% {update, snmpa_local_db, soft, soft_purge, soft_purge, []} %% {add_module, snmpm_net_if_mt} [ - {"5.1.2", [ % Only runtime dependencies change - ]}, - {"5.1.1", [{restart_application, snmp}]}, - {"5.1", [ % Only compiler changes - ]}, - {"5.0", [{restart_application, snmp}]}, - {"4.25.1", [{restart_application, snmp}]}, - {"4.25.0.1", [{restart_application, snmp}]}, - {"4.25.0.0.1", [{restart_application, snmp}]}, - {"4.25", [{restart_application, snmp}]}, - {"4.24.2", [{restart_application, snmp}]}, - {"4.24.1", [{restart_application, snmp}]}, - {"4.24", [{restart_application, snmp}]} - ], - + {<<"5\\..*">>, [{restart_application, snmp}]}, + {<<"4\\..*">>, [{restart_application, snmp}]} + ], + %% ------D o w n g r a d e --------------------------------------------------- - %% Instruction examples: %% {remove, {snmpm_net_if_mt, soft_purge, soft_purge}} - + [ - {"5.1.2", [ % Only runtime dependencies change - ]}, - {"5.1.1", [{restart_application, snmp}]}, - {"5.1", [ % Only compiler changes - ]}, - {"5.0", [{restart_application, snmp}]}, - {"4.25.1", [{restart_application, snmp}]}, - {"4.25.0.1", [{restart_application, snmp}]}, - {"4.25.0.0.1", [{restart_application, snmp}]}, - {"4.25", [{restart_application, snmp}]}, - {"4.24.2", [{restart_application, snmp}]}, - {"4.24.1", [{restart_application, snmp}]}, - {"4.24", [{restart_application, snmp}]} - ] - -}. + {<<"5\\..*">>, [{restart_application, snmp}]}, + {<<"4\\..*">>, [{restart_application, snmp}]} + ] +}. diff --git a/lib/snmp/src/misc/snmp_conf.erl b/lib/snmp/src/misc/snmp_conf.erl index 0364613f8e..6264d79cec 100644 --- a/lib/snmp/src/misc/snmp_conf.erl +++ b/lib/snmp/src/misc/snmp_conf.erl @@ -1005,6 +1005,8 @@ check_imask(IMask) when is_list(IMask) -> do_check_imask(IMask), {ok, IMask}. +do_check_imask([]) -> + ok; do_check_imask([0|IMask]) -> do_check_imask(IMask); do_check_imask([1|IMask]) -> diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk index bf8e87fa0c..f60cbbfaa7 100644 --- a/lib/snmp/vsn.mk +++ b/lib/snmp/vsn.mk @@ -19,6 +19,6 @@ # %CopyrightEnd% APPLICATION = snmp -SNMP_VSN = 5.2 +SNMP_VSN = 5.2.2 PRE_VSN = APP_VSN = "$(APPLICATION)-$(SNMP_VSN)$(PRE_VSN)" diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml index 9d498c0fdc..4764d9ffe6 100644 --- a/lib/ssh/doc/src/notes.xml +++ b/lib/ssh/doc/src/notes.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2004</year><year>2014</year> + <year>2004</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -30,6 +30,409 @@ <file>notes.xml</file> </header> +<section><title>Ssh 4.2.2.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Upgrade of an established client connection could crash + because the ssh client supervisors children had wrong + type. This is fixed now.</p> + <p> + Own Id: OTP-13782 Aux Id: seq13158 </p> + </item> + </list> + </section> + +</section> + +<section><title>Ssh 4.2.2.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + SSH client does not any longer retry a bad password given + as option to ssh:connect et al.</p> + <p> + Own Id: OTP-13674 Aux Id: TR-HU92273 </p> + </item> + </list> + </section> + +</section> + +<section><title>Ssh 4.2.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Documentation correction of <c>ssh_sftp:position/4</c></p> + <p> + Thanks to Rabbe Fogelholm.</p> + <p> + Own Id: OTP-13305 Aux Id: ERL-87 </p> + </item> + </list> + </section> + +</section> + +<section><title>Ssh 4.2.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The authentication method 'keyboard-interactive' failed + in the Erlang client when the server after successful + authentication continued by asking for zero more + passwords.</p> + <p> + Own Id: OTP-13225</p> + </item> + </list> + </section> + +</section> + +<section><title>Ssh 4.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Better error handling in ssh_file. There was some rare + errors when a NFS-mounted file was opened by ssh_file and + then remotely deleted during reading. That caused an + endless loop. </p> + <p> + That bug is now fixed.</p> + <p> + Own Id: OTP-12699 Aux Id: OTP-11688 </p> + </item> + <item> + <p> + Fixed a bug in the compression algorithm + [email protected].</p> + <p> + Own Id: OTP-12759</p> + </item> + <item> + <p> + It is now possible to start more than one daemon with a + file descriptor given in option fd. Each daemon must of + course have a unique file descriptor.</p> + <p> + Own Id: OTP-12966 Aux Id: seq12945 </p> + </item> + <item> + <p> + Fixed a bug that caused the option <c>dh_gex_limit</c> to + be ignored.</p> + <p> + Own Id: OTP-13029</p> + </item> + <item> + <p> + A problem is fixed with the <c>ssh:connect</c> option + <c>pref_public_key_algs</c> specifying user keys.</p> + <p> + Own Id: OTP-13158</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Document updates in the ssh reference manual: app doc + file and ssh_connection.</p> + <p> + Own Id: OTP-12003</p> + </item> + <item> + <p> + The authorization phase is made stateful to prevent ssh + acting on messages sent in wrong order.</p> + <p> + Own Id: OTP-12787</p> + </item> + <item> + <p> + Testcases for bad message lengths and for bad subfield + lengths added.</p> + <p> + Own Id: OTP-12792 Aux Id: Codenomicon #5214, 6166 </p> + </item> + <item> + <p> + The 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384' and + 'ecdsa-sha2-nistp521' signature algorithms for ssh are + implemented. See RFC 5656.</p> + <p> + Own Id: OTP-12936</p> + </item> + <item> + <p> + The crypto algorithms 'aes192-ctr' and 'aes256-ctr' are + implemented. See RFC 4344.</p> + <p> + Own Id: OTP-12939</p> + </item> + <item> + <p> + The ciphers and macs AEAD_AES_128_GCM and + AEAD_AES_256_GCM are implemented but not enabled per + default. See the SSH App Reference Manual and RFC5647 for + details.</p> + <p> + The ciphers [email protected] and + [email protected] are also implemented and available + in the default configuration.</p> + <p> + Own Id: OTP-13018</p> + </item> + <item> + <p> + The ssh:daemon option dh_gex_groups is extended to read a + user provided ssh moduli file with generator-modulus + pairs. The file is in openssh format.</p> + <p> + Own Id: OTP-13052 Aux Id: OTP-13054 </p> + </item> + <item> + <p> + There is now a file (public_key/priv/moduli) which lists + size-generator-modulus triples. The purpose is to give + servers the possibility to select the crypto primes + randomly among a list of pregenerated triples. This + reduces the risk for some attacks on diffie-hellman + negotiation.</p> + <p> + See the reference manual for public_key:dh_gex_group/4 + where the handling of this is described.</p> + <p> + The ssh server (ssh:daemon) uses this.</p> + <p> + Own Id: OTP-13054 Aux Id: OTP-13052 </p> + </item> + <item> + <p> + The ssh:daemon option pwdfun now also takes a fun/4. This + enables the user to 1) check userid-password in another + way than the builtin algorithm, 2) implement rate + limiting per user or source IP or IP+Port, and 3) + implement blocking of missbehaving peers.</p> + <p> + The old fun/2 still works as previously.</p> + <p> + Own Id: OTP-13055 Aux Id: OTP-13053 </p> + </item> + <item> + <p> + There is now a new option to make the server limit the + size range of moduli available for the diffie-hellman + group exchange negotiation. See option <c> + {dh_gex_limits,{Min,Max}}</c> in ssh:daemon/3.</p> + <p> + Own Id: OTP-13066</p> + </item> + <item> + <p> + Ecdh key exchange now validates compressed and + uncompressed keys as defined in rfc5656</p> + <p> + Own Id: OTP-13067</p> + </item> + <item> + <p> + Search order for the .ssh directory are changed so + <c>$HOME</c> is tried before + <c>init:get_argument(home)</c>.</p> + <p> + Own Id: OTP-13109</p> + </item> + <item> + <p> + The sftp receive window handling is optimized so it will + not update the remote end too often. This makes "sftp + mget" considerable faster.</p> + <p> + Own Id: OTP-13130</p> + </item> + <item> + <p> + The option <c>key_cb</c> is extended to take an optional + list that is passed to the callback module as an option. + With this it is possible to have different keys depending + on which host that is connected. Another possibility is + to write a callback module that fetches keys etc from a + database.</p> + <p> + Thanks to Vipin Nair.</p> + <p> + Own Id: OTP-13156</p> + </item> + </list> + </section> + +</section> + +<section><title>Ssh 4.1.3</title> + + <section><title>Known Bugs and Problems</title> + <list> + <item> + <p> + SSH_MSG_KEX_DH_GEX_REQUEST_OLD implemented to make PuTTY + work with erl server.</p> + <p> + Own Id: OTP-13140</p> + </item> + </list> + </section> + +</section> + +<section><title>Ssh 4.1.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Add a 1024 group to the list of key group-exchange groups</p> + <p> + Own Id: OTP-13046</p> + </item> + </list> + </section> + +</section> + +<section><title>Ssh 4.1.1</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + A new option <c>max_channels</c> limits the number of + channels with active server-side subsystems that are + accepted.</p> + <p> + Own Id: OTP-13036</p> + </item> + </list> + </section> + +</section> + +<section><title>Ssh 4.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Send an understandable disconnect message when the key + exchange phase can't find a common algorithm. There are + also some test cases added.</p> + <p> + Own Id: OTP-11531</p> + </item> + <item> + <p> + The third parameter in <c>ssh_sftp:write_file</c> is now + accepting iolists again. Unicode handling adjusted.</p> + <p> + Own Id: OTP-12853 Aux Id: seq12891 </p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + First part of ssh test suite re-organization and + extension.</p> + <p> + Own Id: OTP-12230</p> + </item> + <item> + <p> + The key exchange algorithms 'ecdh-sha2-nistp256', + 'ecdh-sha2-nistp384' and 'ecdh-sha2-nistp521' are + implemented. See RFC 5656.</p> + <p> + This raises the security level considerably.</p> + <p> + Own Id: OTP-12622 Aux Id: OTP-12671, OTP-12672 </p> + </item> + <item> + <p> + The key exchange algorithm 'diffie-hellman-group14-sha1' + is implemented. See RFC 4253.</p> + <p> + This raises the security level.</p> + <p> + Own Id: OTP-12671 Aux Id: OTP-12672, OTP-12622 </p> + </item> + <item> + <p> + The key exchange algorithms + 'diffie-hellman-group-exchange-sha1' and + 'diffie-hellman-group-exchange-sha256' are implemented. + See RFC 4419.</p> + <p> + This raises the security level.</p> + <p> + Own Id: OTP-12672 Aux Id: OTP-12671, OTP-12622 </p> + </item> + <item> + <p> + Adding random length extra padding as recommended in RFC + 4253 section 6.</p> + <p> + Own Id: OTP-12831</p> + </item> + <item> + <p> + New test library for low-level protocol testing. There is + also a test suite using it for some preliminary tests. + The intention is to build on that for more testing of + individual ssh messages. See + <c>lib/ssh/test/ssh_trpt_test_lib.erl</c> and + <c>ssh_protocol_SUITE.erl</c> in the same directory.</p> + <p> + Own Id: OTP-12858</p> + </item> + <item> + <p> + Increased default values for + diffie-hellman-group-exchange-sha* to Min = 1024, N = + 6144, Max = 8192.</p> + <p> + Added 6144 and 8192 bit default gex groups.</p> + <p> + Own Id: OTP-12937</p> + </item> + <item> + <p> + The mac algorithm 'hmac-sha2-512' is implemented. See RFC + 6668.</p> + <p> + Own Id: OTP-12938</p> + </item> + </list> + </section> + +</section> + <section><title>Ssh 4.0</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -82,9 +485,9 @@ <p> Thanks to Simon Cornish</p> <p> - Own Id: OTP-12760 Aux Id: <a + Own Id: OTP-12760 Aux Id: <url href="https://github.com/erlang/otp/pull/715">pull req - 715</a> </p> + 715</url> </p> </item> <item> <p> @@ -250,13 +653,13 @@ </item> <item> <p> - Made Codenomicon Defensics test suite pass: <list> + Made Codenomicon Defensics test suite pass:</p> <list> <item>limit number of algorithms in kexinit message</item> <item>check 'e' and 'f' parameters in kexdh</item> <item>implement 'keyboard-interactive' user authentication on server side</item> <item> return plain text message to bad version exchange message</item> - </list></p> + </list> <p> Own Id: OTP-12784</p> </item> diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml index d24025ca4d..850557444d 100644 --- a/lib/ssh/doc/src/ssh.xml +++ b/lib/ssh/doc/src/ssh.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2004</year><year>2014</year> + <year>2004</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -32,28 +32,33 @@ <modulesummary>Main API of the ssh application</modulesummary> <description> <p>Interface module for the <c>ssh</c> application.</p> + <p>See <seealso marker="ssh:SSH_app#supported">ssh(6)</seealso> for details of supported version, + algorithms and unicode support.</p> </description> - <section> - <title>SSH</title> - <marker id="supported"/> - <list type="bulleted"> - <item>For application dependencies see <seealso marker="SSH_app"> ssh(6)</seealso> </item> - <item>Supported SSH version is 2.0.</item> - <item>Supported public key algorithms: ssh-rsa and ssh-dss.</item> - <item>Supported MAC algorithms: hmac-sha2-256 and hmac-sha1.</item> - <item>Supported encryption algorithms: aes128-ctr, aes128-cb and 3des-cbc.</item> - <item>Supported key exchange algorithms: diffie-hellman-group1-sha1.</item> - <item>Supported compression algorithms: none, zlib, [email protected],</item> - <item>Supports unicode filenames if the emulator and the underlaying OS support it. - See section DESCRIPTION in the - <seealso marker="kernel:file">file</seealso> manual page in <c>kernel</c> - for information about this subject.</item> - <item>Supports unicode in shell and CLI.</item> - </list> - + <section> + <title>OPTIONS</title> + <p>The exact behaviour of some functions can be adjusted with the use of options which are documented together + with the functions. Generally could each option be used at most one time in each function call. If given two or more + times, the effect is not predictable unless explicitly documented.</p> + <p>The options are of different kinds:</p> + <taglist> + <tag>Limits</tag> + <item><p>which alters limits in the system, for example number of simultaneous login attempts.</p></item> + + <tag>Timeouts</tag> + <item><p>which give some defined behaviour if too long time elapses before a given event or action, + for example time to wait for an answer.</p></item> + + <tag>Callbacks</tag> + <item><p>which gives the caller of the function the possibility to execute own code on some events, + for example calling an own logging function or to perform an own login function</p></item> + + <tag>Behaviour</tag> + <item><p>which changes the systems behaviour.</p></item> + </taglist> </section> - + <section> <title>DATA TYPES</title> <p>Type definitions that are used more than once in @@ -80,6 +85,15 @@ <item><p><c>atom()</c> - Name of the Erlang module implementing the subsystem using the <c>ssh_channel</c> behavior, see <seealso marker="ssh_channel">ssh_channel(3)</seealso></p></item> + <tag><c>key_cb() =</c></tag> + <item> + <p><c>atom() | {atom(), list()}</c></p> + <p><c>atom()</c> - Name of the erlang module implementing the behaviours + <seealso marker="ssh_client_key_api">ssh_client_key_api</seealso> or + <seealso marker="ssh_client_key_api">ssh_client_key_api</seealso> as the + case maybe.</p> + <p><c>list()</c> - List of options that can be passed to the callback module.</p> + </item> <tag><c>channel_init_args() =</c></tag> <item><p><c>list()</c></p></item> @@ -192,26 +206,25 @@ <tag><c><![CDATA[{public_key_alg, 'ssh-rsa' | 'ssh-dss'}]]></c></tag> <item> <note> - <p>This option is kept for compatibility. It is ignored if the <c>preferred_algorithms</c> - option is used. The equivalence of <c>{public_key_alg,'ssh-dss'}</c> is - <c>{preferred_algorithms, [{public_key,['ssh-dss','ssh-rsa']}]}</c>.</p> + <p>This option will be removed in OTP 20, but is kept for compatibility. It is ignored if + the preferred <c>pref_public_key_algs</c> option is used.</p> </note> <p>Sets the preferred public key algorithm to use for user authentication. If the preferred algorithm fails, - the other algorithm is tried. The default is - to try <c><![CDATA['ssh-rsa']]></c> first.</p> + the other algorithm is tried. If <c>{public_key_alg, 'ssh-rsa'}</c> is set, it is translated + to <c>{pref_public_key_algs, ['ssh-rsa','ssh-dss']}</c>. If it is + <c>{public_key_alg, 'ssh-dss'}</c>, it is translated + to <c>{pref_public_key_algs, ['ssh-dss','ssh-rsa']}</c>. + </p> </item> <tag><c><![CDATA[{pref_public_key_algs, list()}]]></c></tag> <item> - <note> - <p>This option is kept for compatibility. It is ignored if the <c>preferred_algorithms</c> - option is used. The equivalence of <c>{pref_public_key_algs,['ssh-dss']}</c> is - <c>{preferred_algorithms, [{public_key,['ssh-dss']}]}</c>.</p> - </note> - <p>List of public key algorithms to try to use. - <c>'ssh-rsa'</c> and <c>'ssh-dss'</c> are available. - Overrides <c><![CDATA[{public_key_alg, 'ssh-rsa' | 'ssh-dss'}]]></c></p> + <p>List of user (client) public key algorithms to try to use.</p> + <p>The default value is + <c><![CDATA[['ssh-rsa','ssh-dss','ecdsa-sha2-nistp256','ecdsa-sha2-nistp384','ecdsa-sha2-nistp521'] ]]></c> + </p> + <p>If there is no public key of a specified type available, the corresponding entry is ignored.</p> </item> <tag><c><![CDATA[{preferred_algorithms, algs_list()}]]></c></tag> @@ -219,6 +232,7 @@ <p>List of algorithms to use in the algorithm negotiation. The default <c>algs_list()</c> can be obtained from <seealso marker="#default_algorithms/0">default_algorithms/0</seealso>. </p> + <p>If an alg_entry() is missing in the algs_list(), the default value is used for that entry.</p> <p>Here is an example of this option:</p> <code> {preferred_algorithms, @@ -229,9 +243,9 @@ {compression,[none,zlib]} } </code> - <p>The example specifies different algorithms in the two directions (client2server and server2client), for cipher but specifies the same -algorithms for mac and compression in both directions. The kex (key exchange) and public key algorithms are set to their default values, -kex is implicit but public_key is set explicitly.</p> + <p>The example specifies different algorithms in the two directions (client2server and server2client), + for cipher but specifies the same algorithms for mac and compression in both directions. + The kex (key exchange) is implicit but public_key is set explicitly.</p> <warning> <p>Changing the values can make a connection less secure. Do not change unless you @@ -240,6 +254,13 @@ kex is implicit but public_key is set explicitly.</p> </warning> </item> + <tag><c><![CDATA[{dh_gex_limits,{Min=integer(),I=integer(),Max=integer()}}]]></c></tag> + <item> + <p>Sets the three diffie-hellman-group-exchange parameters that guides the connected server in choosing a group. + See RFC 4419 for the function of thoose. The default value is <c>{1024, 6144, 8192}</c>. + </p> + </item> + <tag><c><![CDATA[{connect_timeout, timeout()}]]></c></tag> <item> <p>Sets a time-out on the transport layer @@ -260,11 +281,13 @@ kex is implicit but public_key is set explicitly.</p> password, if the password authentication method is attempted.</p> </item> - <tag><c><![CDATA[{key_cb, atom()}]]></c></tag> + <tag><c><![CDATA[{key_cb, key_cb()}]]></c></tag> <item> - <p>Module implementing the behaviour - <seealso marker="ssh_client_key_api">ssh_client_key_api</seealso>. - Can be used to customize the handling of public keys. + <p>Module implementing the behaviour <seealso + marker="ssh_client_key_api">ssh_client_key_api</seealso>. Can be used to + customize the handling of public keys. If callback options are provided + along with the module name, they are made available to the callback + module via the options passed to it under the key 'key_cb_private'. </p> </item> <tag><c><![CDATA[{quiet_mode, atom() = boolean()}]]></c></tag> @@ -395,10 +418,10 @@ kex is implicit but public_key is set explicitly.</p> <c><![CDATA["publickey,keyboard-interactive,password"]]></c></p> </item> - <tag><c><![CDATA[{auth_method_kb_interactive_data, PromptTexts}]]> - <br/>where: - <br/>PromptTexts = kb_int_tuple() | fun(Peer::{IP::tuple(),Port::integer()}, User::string(), Service::string()) -> kb_int_tuple() - <br/>kb_int_tuple() = {Name::string(), Instruction::string(), Prompt::string(), Echo::boolean()}</c> + <tag><c><![CDATA[{auth_method_kb_interactive_data, PromptTexts}]]></c> + <br/><c>where:</c> + <br/><c>PromptTexts = kb_int_tuple() | fun(Peer::{IP::tuple(),Port::integer()}, User::string(), Service::string()) -> kb_int_tuple()</c> + <br/><c>kb_int_tuple() = {Name::string(), Instruction::string(), Prompt::string(), Echo::boolean()}</c> </tag> <item> <p>Sets the text strings that the daemon sends to the client for presentation to the user when using <c>keyboar-interactive</c> authentication. If the fun/3 is used, it is called when the actual authentication occurs and may therefore return dynamic data like time, remote ip etc.</p> @@ -428,6 +451,7 @@ kex is implicit but public_key is set explicitly.</p> <p>List of algorithms to use in the algorithm negotiation. The default <c>algs_list()</c> can be obtained from <seealso marker="#default_algorithms/0">default_algorithms/0</seealso>. </p> + <p>If an alg_entry() is missing in the algs_list(), the default value is used for that entry.</p> <p>Here is an example of this option:</p> <code> {preferred_algorithms, @@ -438,9 +462,9 @@ kex is implicit but public_key is set explicitly.</p> {compression,[none,zlib]} } </code> - <p>The example specifies different algorithms in the two directions (client2server and server2client), for cipher but specifies the same -algorithms for mac and compression in both directions. The kex (key exchange) and public key algorithms are set to their default values, -kex is implicit but public_key is set explicitly.</p> + <p>The example specifies different algorithms in the two directions (client2server and server2client), + for cipher but specifies the same algorithms for mac and compression in both directions. + The kex (key exchange) is implicit but public_key is set explicitly.</p> <warning> <p>Changing the values can make a connection less secure. Do not change unless you @@ -449,12 +473,82 @@ kex is implicit but public_key is set explicitly.</p> </warning> </item> - <tag><c><![CDATA[{pwdfun, fun(User::string(), password::string()) -> boolean()}]]></c></tag> + <tag><c><![CDATA[{dh_gex_groups, [{Size=integer(),G=integer(),P=integer()}] | {file,filename()} {ssh_moduli_file,filename()} }]]></c></tag> + <item> + <p>Defines the groups the server may choose among when diffie-hellman-group-exchange is negotiated. + See RFC 4419 for details. The three variants of this option are: + </p> + <taglist> + <tag><c>{Size=integer(),G=integer(),P=integer()}</c></tag> + <item>The groups are given explicitly in this list. There may be several elements with the same <c>Size</c>. + In such a case, the server will choose one randomly in the negotiated Size. + </item> + <tag><c>{file,filename()}</c></tag> + <item>The file must have one or more three-tuples <c>{Size=integer(),G=integer(),P=integer()}</c> + terminated by a dot. The file is read when the daemon starts. + </item> + <tag><c>{ssh_moduli_file,filename()}</c></tag> + <item>The file must be in + <seealso marker="public_key:public_key#dh_gex_group/4">ssh-keygen moduli file format</seealso>. + The file is read when the daemon starts. + </item> + </taglist> + <p>The default list is fetched from the + <seealso marker="public_key:public_key#dh_gex_group/4">public_key</seealso> application. + </p> + </item> + + <tag><c><![CDATA[{dh_gex_limits,{Min=integer(),Max=integer()}}]]></c></tag> + <item> + <p>Limits what a client can ask for in diffie-hellman-group-exchange. + The limits will be + <c>{MaxUsed = min(MaxClient,Max), MinUsed = max(MinClient,Min)}</c> where <c>MaxClient</c> and + <c>MinClient</c> are the values proposed by a connecting client. + </p> + <p>The default value is <c>{0,infinity}</c>. + </p> + <p>If <c>MaxUsed < MinUsed</c> in a key exchange, it will fail with a disconnect. + </p> + <p>See RFC 4419 for the function of the Max and Min values.</p> + </item> + + <tag><c><![CDATA[{pwdfun, fun(User::string(), Password::string(), PeerAddress::{ip_adress(),port_number()}, State::any()) -> boolean() | disconnect | {boolean(),any()} }]]></c></tag> + <item> + <p>Provides a function for password validation. This could used for calling an external system or if + passwords should be stored as a hash. The fun returns: + </p> + <list type="bulleted"> + <item><c>true</c> if the user and password is valid and</item> + <item><c>false</c> otherwise.</item> + </list> + <p>This fun can also be used to make delays in authentication tries for example by calling + <seealso marker="stdlib:timer#sleep/1">timer:sleep/1</seealso>. To facilitate counting of failed tries + the <c>State</c> variable could be used. This state is per connection only. The first time the pwdfun + is called for a connection, the <c>State</c> variable has the value <c>undefined</c>. + The pwdfun can return - in addition to the values above - a new state + as: + </p> + <list type="bulleted"> + <item><c>{true, NewState:any()}</c> if the user and password is valid or</item> + <item><c>{false, NewState:any()}</c> if the user or password is invalid</item> + </list> + <p>A third usage is to block login attempts from a missbehaving peer. The <c>State</c> described above + can be used for this. In addition to the responses above, the following return value is introduced: + </p> + <list type="bulleted"> + <item><c>disconnect</c> if the connection should be closed immediately after sending a SSH_MSG_DISCONNECT + message.</item> + </list> + </item> + + <tag><c><![CDATA[{pwdfun, fun(User::string(), Password::string()) -> boolean()}]]></c></tag> <item> <p>Provides a function for password validation. This function is called with user and password as strings, and returns <c><![CDATA[true]]></c> if the password is valid and <c><![CDATA[false]]></c> otherwise.</p> + <p>This option (<c>{pwdfun,fun/2}</c>) is the same as a subset of the previous + (<c>{pwdfun,fun/4}</c>). It is kept for compatibility.</p> </item> <tag><c><![CDATA[{negotiation_timeout, integer()}]]></c></tag> @@ -485,6 +579,15 @@ kex is implicit but public_key is set explicitly.</p> </p> </item> + <tag><c><![CDATA[{max_channels, pos_integer()}]]></c></tag> + <item> + <p>The maximum number of channels with active remote subsystem that are accepted for + each connection to this daemon</p> + <p>By default, this option is not set. This means that the number is not limited. + </p> + </item> + + <tag><c><![CDATA[{parallel_login, boolean()}]]></c></tag> <item> <p>If set to false (the default value), only one login is handled at a time. @@ -516,11 +619,13 @@ kex is implicit but public_key is set explicitly.</p> </p> </item> - <tag><c><![CDATA[{key_cb, atom()}]]></c></tag> + <tag><c><![CDATA[{key_cb, key_cb()}]]></c></tag> <item> - <p>Module implementing the behaviour - <seealso marker="ssh_server_key_api">ssh_server_key_api</seealso>. - Can be used to customize the handling of public keys. + <p>Module implementing the behaviour <seealso + marker="ssh_server_key_api">ssh_server_key_api</seealso>. Can be used to + customize the handling of public keys. If callback options are provided + along with the module name, they are made available to the callback + module via the options passed to it under the key 'key_cb_private'. </p> </item> diff --git a/lib/ssh/doc/src/ssh_app.xml b/lib/ssh/doc/src/ssh_app.xml index 4c85585820..f6ce44c015 100644 --- a/lib/ssh/doc/src/ssh_app.xml +++ b/lib/ssh/doc/src/ssh_app.xml @@ -4,7 +4,7 @@ <appref> <header> <copyright> - <year>2012</year><year>2013</year> + <year>2012</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -41,15 +41,18 @@ <section> <title>DEPENDENCIES</title> - <p>The <c>ssh</c> application uses the applications <c>public_key</c> and - <c>crypto</c> to handle public keys and encryption. Hence, these + <p>The <c>ssh</c> application uses the applications + <seealso marker="public_key:public_key">public_key</seealso> and + <seealso marker="crypto:crypto">crypto</seealso> + to handle public keys and encryption. Hence, these applications must be loaded for the <c>ssh</c> application to work. In an embedded environment this means that they must be started with - <c>application:start/[1,2]</c> before the <c>ssh</c> application is started. + <seealso marker="kernel:application#start/1">application:start/1,2</seealso> before the + <c>ssh</c> application is started. </p> </section> - <section> + <section> <title>CONFIGURATION</title> <p>The <c>ssh</c> application does not have an application- @@ -62,10 +65,13 @@ <item><c>authorized_keys2</c></item> <item><c>id_dsa</c></item> <item><c>id_rsa</c></item> + <item><c>id_ecdsa</c></item> <item><c>ssh_host_dsa_key</c></item> <item><c>ssh_host_rsa_key</c></item> + <item><c>ssh_host_ecdsa_key</c></item> </list> <p>By default, <c>ssh</c> looks for <c>id_dsa</c>, <c>id_rsa</c>, + <c>id_ecdsa_key</c>, <c>known_hosts</c>, and <c>authorized_keys</c> in ~/.ssh, and for the host key files in <c>/etc/ssh</c>. These locations can be changed by the options <c>user_dir</c> and <c>system_dir</c>. @@ -79,7 +85,7 @@ </section> <section> <title>Public Keys</title> - <p><c>id_dsa</c> and <c>id_rsa</c> are the users private key files. + <p><c>id_dsa</c>, <c>id_rsa</c> and <c>id_ecdsa</c> are the users private key files. Notice that the public key is part of the private key so the <c>ssh</c> application does not use the <c>id_<*>.pub</c> files. These are for the user's convenience when it is needed to convey the user's @@ -104,8 +110,8 @@ <section> <title>Host Keys</title> <p>RSA and DSA host keys are supported and are - expected to be found in files named <c>ssh_host_rsa_key</c> and - <c>ssh_host_dsa_key</c>. + expected to be found in files named <c>ssh_host_rsa_key</c>, + <c>ssh_host_dsa_key</c> and <c>ssh_host_ecdsa_key</c>. </p> </section> <section> @@ -114,6 +120,198 @@ </section> <section> + <marker id="supported"/> + <title>SUPPORTED SPECIFICATIONS AND STANDARDS</title> + <p>The supported SSH version is 2.0.</p> + </section> + <section> + <title>Algorithms</title> + <p>The actual set of algorithms may vary depending on which OpenSSL crypto library that is installed on the machine. + For the list on a particular installation, use the command + <seealso marker="ssh:ssh#default_algorithms/0">ssh:default_algorithms/0</seealso>. + The user may override the default algorithm configuration both on the server side and the client side. + See the option <c>preferred_algorithms</c> in the <seealso marker="ssh:ssh#daemon/1">ssh:daemon/1,2,3</seealso> and + <seealso marker="ssh:ssh#connect/3">ssh:connect/3,4</seealso> functions. + </p> + + <p>Supported algorithms are:</p> + + <taglist> + <tag>Key exchange algorithms</tag> + <item> + <list type="bulleted"> + <item>ecdh-sha2-nistp256</item> + <item>ecdh-sha2-nistp384</item> + <item>ecdh-sha2-nistp521</item> + <item>diffie-hellman-group-exchange-sha1</item> + <item>diffie-hellman-group-exchange-sha256</item> + <item>diffie-hellman-group14-sha1</item> + <item>diffie-hellman-group1-sha1</item> + </list> + </item> + + <tag>Public key algorithms</tag> + <item> + <list type="bulleted"> + <item>ecdsa-sha2-nistp256</item> + <item>ecdsa-sha2-nistp384</item> + <item>ecdsa-sha2-nistp521</item> + <item>ssh-rsa</item> + <item>ssh-dss</item> + </list> + </item> + + <tag>MAC algorithms</tag> + <item> + <list type="bulleted"> + <item>hmac-sha2-256</item> + <item>hmac-sha2-512</item> + <item>hmac-sha1</item> + </list> + </item> + + <tag>Encryption algorithms (ciphers)</tag> + <item> + <list type="bulleted"> + <item>[email protected] (AEAD_AES_128_GCM)</item> + <item>[email protected] (AEAD_AES_256_GCM)</item> + <item>aes128-ctr</item> + <item>aes192-ctr</item> + <item>aes256-ctr</item> + <item>aes128-cbc</item> + <item>3des-cbc</item> + </list> + <p>Following the internet de-facto standard, the cipher and mac algorithm AEAD_AES_128_GCM is selected when the + cipher [email protected] is negotiated. The cipher and mac algorithm AEAD_AES_256_GCM is selected when the + cipher [email protected] is negotiated. + </p> + <p>See the text at the description of <seealso marker="#rfc5647_note">the rfc 5647 further down</seealso> + for more information. + </p> + </item> + + <tag>Compression algorithms</tag> + <item> + <list type="bulleted"> + <item>none</item> + <item>[email protected]</item> + <item>zlib</item> + </list> + </item> + </taglist> + </section> + <section> + <title>Unicode support</title> + <p>Unicode filenames are supported if the emulator and the underlaying OS support it. See section DESCRIPTION in the + <seealso marker="kernel:file">file</seealso> manual page in <c>kernel</c> for information about this subject. + </p> + <p>The shell and the cli both support unicode. + </p> + </section> + + <section> + <title>Rfcs</title> + <p>The following rfc:s are supported:</p> + <list type="bulleted"> + <item><url href="https://tools.ietf.org/html/rfc4251">RFC 4251</url>, The Secure Shell (SSH) Protocol Architecture. + <p>Except</p> + <list type="bulleted"> + <item>9.4.6 Host-Based Authentication</item> + <item>9.5.2 Proxy Forwarding</item> + <item>9.5.3 X11 Forwarding</item> + </list> + <p/> + </item> + + <item><url href="https://tools.ietf.org/html/rfc4252">RFC 4252</url>, The Secure Shell (SSH) Authentication Protocol. + <p>Except</p> + <list type="bulleted"> + <item>9. Host-Based Authentication: "hostbased"</item> + </list> + <p/> + </item> + + <item><url href="https://tools.ietf.org/html/rfc4253">RFC 4253</url>, The Secure Shell (SSH) Transport Layer Protocol. + <p></p> + </item> + + <item><url href="https://tools.ietf.org/html/rfc4254">RFC 4254</url>, The Secure Shell (SSH) Connection Protocol. + <p>Except</p> + <list type="bulleted"> + <item>6.3. X11 Forwarding</item> + <item>7. TCP/IP Port Forwarding</item> + </list> + <p/> + </item> + + <item><url href="https://tools.ietf.org/html/rfc4256">RFC 4256</url>, Generic Message Exchange Authentication for + the Secure Shell Protocol (SSH). + <p>Except</p> + <list type="bulleted"> + <item><c>num-prompts > 1</c></item> + <item>password changing</item> + <item>other identification methods than userid-password</item> + </list> + <p/> + </item> + + <item><url href="https://tools.ietf.org/html/rfc4419">RFC 4419</url>, Diffie-Hellman Group Exchange for + the Secure Shell (SSH) Transport Layer Protocol. + <p/> + </item> + + <item><url href="https://tools.ietf.org/html/rfc4716">RFC 4716</url>, The Secure Shell (SSH) Public Key File Format. + <p/> + </item> + + <item><url href="https://tools.ietf.org/html/rfc5647">RFC 5647</url>, AES Galois Counter Mode for + the Secure Shell Transport Layer Protocol. + <p><marker id="rfc5647_note"/>There is an ambiguity in the synchronized selection of cipher and mac algorithm. + This is resolved by OpenSSH in the ciphers [email protected] and [email protected] which are implemented. + If the explicit ciphers and macs AEAD_AES_128_GCM or AEAD_AES_256_GCM are needed, + they could be enabled with the option preferred_algorithms. + </p> + <warning> + <p> + If the client or the server is not Erlang/OTP, it is the users responsibility to check that + other implementation has the same interpretation of AEAD_AES_*_GCM as the Erlang/OTP SSH before + enabling them. The aes*[email protected] variants are always safe to use since they lack the + ambiguity. + </p> + </warning> + <p>The second paragraph in section 5.1 is resolved as:</p> + <list type="ordered"> + <item>If the negotiated cipher is AEAD_AES_128_GCM, the mac algorithm is set to AEAD_AES_128_GCM.</item> + <item>If the negotiated cipher is AEAD_AES_256_GCM, the mac algorithm is set to AEAD_AES_256_GCM.</item> + <item>If the mac algorithm is AEAD_AES_128_GCM, the cipher is set to AEAD_AES_128_GCM.</item> + <item>If the mac algorithm is AEAD_AES_256_GCM, the cipher is set to AEAD_AES_256_GCM.</item> + </list> + <p>The first rule that matches when read in order from the top is applied</p> + </item> + + <item><url href="https://tools.ietf.org/html/rfc5656">RFC 5656</url>, Elliptic Curve Algorithm Integration in + the Secure Shell Transport Layer. + <p>Except</p> + <list type="bulleted"> + <item>5. ECMQV Key Exchange</item> + <item>6.4. ECMQV Key Exchange and Verification Method Name</item> + <item>7.2. ECMQV Message Numbers</item> + <item>10.2. Recommended Curves</item> + </list> + <p/> + </item> + + <item><url href="https://tools.ietf.org/html/rfc6668">RFC 6668</url>, SHA-2 Data Integrity Verification for + the Secure Shell (SSH) Transport Layer Protocol + <p>Comment: Defines hmac-sha2-256 and hmac-sha2-512 + </p> + </item> + + </list> + + </section> + + <section> <title>SEE ALSO</title> <p><seealso marker="kernel:application">application(3)</seealso></p> </section> diff --git a/lib/ssh/doc/src/ssh_connection.xml b/lib/ssh/doc/src/ssh_connection.xml index 9a7bb09b12..150d46a9a2 100644 --- a/lib/ssh/doc/src/ssh_connection.xml +++ b/lib/ssh/doc/src/ssh_connection.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>2008</year> - <year>2014</year> + <year>2015</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> @@ -31,15 +31,15 @@ <rev></rev> </header> <module>ssh_connection</module> - <modulesummary>This module provides API functions to send - <url href="http://www.ietf.org/rfc/rfc4254.txt"> SSH Connection Protocol </url> - events to the other side of an SSH channel. + <modulesummary> + This module provides API functions to send SSH Connection Protocol + events to the other side of an SSH channel. </modulesummary> <description> - <p>The SSH Connection Protocol is used by clients and servers, - that is, SSH channels, to communicate over the SSH connection. The - API functions in this module send SSH Connection Protocol events, + <p>The <url href="http://www.ietf.org/rfc/rfc4254.txt">SSH Connection Protocol</url> + is used by clients and servers, that is, SSH channels, to communicate over the + SSH connection. The API functions in this module send SSH Connection Protocol events, which are received as messages by the remote channel. If the receiving channel is an Erlang process, the messages have the format @@ -373,6 +373,9 @@ <desc> <p>Is to be called by client- and server-channel processes to send data to each other. </p> + <p>The function <seealso marker="ssh:ssh_connection#subsystem/4">subsystem/4</seealso> and subsequent + calls of <c>send/3,4,5</c> must be executed in the same process. + </p> </desc> </func> @@ -454,6 +457,9 @@ <p>Is to be called by a client-channel process for requesting to execute a predefined subsystem on the server. </p> + <p>The function <c>subsystem/4</c> and subsequent calls of + <seealso marker="ssh:ssh_connection#send/3">send/3,4,5</seealso> must be executed in the same process. + </p> </desc> </func> diff --git a/lib/ssh/doc/src/ssh_server_key_api.xml b/lib/ssh/doc/src/ssh_server_key_api.xml index efb2c436e8..a0694ca8d9 100644 --- a/lib/ssh/doc/src/ssh_server_key_api.xml +++ b/lib/ssh/doc/src/ssh_server_key_api.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>2012</year> - <year>2013</year> + <year>2015</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> @@ -75,7 +75,7 @@ <d>Host key algorithm. Is to support <c>'ssh-rsa' | 'ssh-dss'</c>, but more algorithms can be handled.</d> <v>DaemonOptions = proplists:proplist()</v> - <d>Options provided to <seealso marker="ssh#daemon-2">ssh:daemon/[2,3]</seealso>.</d> + <d>Options provided to <seealso marker="ssh#daemon-2">ssh:daemon/[2,3]</seealso>.</d> <v>Key = private_key()</v> <d>Private key of the host matching the <c>Algorithm</c>.</d> <v>Reason = term()</v> diff --git a/lib/ssh/doc/src/ssh_sftp.xml b/lib/ssh/doc/src/ssh_sftp.xml index 17800fac5d..f4b41b74f3 100644 --- a/lib/ssh/doc/src/ssh_sftp.xml +++ b/lib/ssh/doc/src/ssh_sftp.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2005</year><year>2014</year> + <year>2005</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -61,20 +61,23 @@ <funcs> <func> - <name>apread(ChannelPid, Handle, Position, Len) -> {async, N} | {error, Error}</name> - <v>ChannelPid = pid()</v> - <v>Handle = term()</v> - <v>Position = integer()</v> - <v>Len = integer()</v> - <v>N = term()</v> - <v>Reason = term()</v> - - <desc><p>The <c><![CDATA[apread]]></c> function reads from a specified position, - combining the <c><![CDATA[position]]></c> and <c><![CDATA[aread]]></c> functions.</p> + <name>apread(ChannelPid, Handle, Position, Len) -> {async, N} | {error, Reason}</name> + <fsummary>Reads asynchronously from an open file.</fsummary> + <type> + <v>ChannelPid = pid()</v> + <v>Handle = term()</v> + <v>Position = integer()</v> + <v>Len = integer()</v> + <v>N = term()</v> + <v>Reason = term()</v> + </type> + + <desc><p>The <c><![CDATA[apread]]></c> function reads from a specified position, + combining the <c><![CDATA[position]]></c> and <c><![CDATA[aread]]></c> functions.</p> <p><seealso marker="#apread-4">ssh_sftp:apread/4</seealso></p> </desc> - </func> - - <func> + </func> + + <func> <name>apwrite(ChannelPid, Handle, Position, Data) -> ok | {error, Reason}</name> <fsummary>Writes asynchronously to an open file.</fsummary> <type> @@ -330,7 +333,7 @@ <func> <name>position(ChannelPid, Handle, Location) -></name> - <name>position(ChannelPid, Handle, Location, Timeout) -> {ok, NewPosition | {error, Error}</name> + <name>position(ChannelPid, Handle, Location, Timeout) -> {ok, NewPosition} | {error, Reason}</name> <fsummary>Sets the file position of a file.</fsummary> <type> <v>ChannelPid = pid()</v> @@ -396,7 +399,7 @@ <func> <name>pwrite(ChannelPid, Handle, Position, Data) -> ok</name> - <name>pwrite(ChannelPid, Handle, Position, Data, Timeout) -> ok | {error, Error}</name> + <name>pwrite(ChannelPid, Handle, Position, Data, Timeout) -> ok | {error, Reason}</name> <fsummary>Writes to an open file.</fsummary> <type> <v>ChannelPid = pid()</v> @@ -589,7 +592,7 @@ <func> <name>write(ChannelPid, Handle, Data) -></name> - <name>write(ChannelPid, Handle, Data, Timeout) -> ok | {error, Error}</name> + <name>write(ChannelPid, Handle, Data, Timeout) -> ok | {error, Reason}</name> <fsummary>Writes to an open file.</fsummary> <type> <v>ChannelPid = pid()</v> diff --git a/lib/ssh/doc/src/using_ssh.xml b/lib/ssh/doc/src/using_ssh.xml index 91185a0f6e..6826f20fb3 100644 --- a/lib/ssh/doc/src/using_ssh.xml +++ b/lib/ssh/doc/src/using_ssh.xml @@ -234,7 +234,7 @@ <title>SFTP Client with TAR Compression and Encryption</title> <p>Example of writing and then reading a tar file follows:</p> - <code type="erlang"> + <code type="erl"> {ok,HandleWrite} = ssh_sftp:open_tar(ChannelPid, ?tar_file_name, [write]), ok = erl_tar:add(HandleWrite, .... ), ok = erl_tar:add(HandleWrite, .... ), @@ -249,10 +249,10 @@ </code> <p>The previous write and read example can be extended with encryption and decryption as follows:</p> - <code type="erlang"> + <code type="erl"> %% First three parameters depending on which crypto type we select: Key = <<"This is a 256 bit key. abcdefghi">>, -Ivec0 = crypto:rand_bytes(16), +Ivec0 = crypto:strong_rand_bytes(16), DataSize = 1024, % DataSize rem 16 = 0 for aes_cbc %% Initialization of the CryptoState, in this case it is the Ivector. diff --git a/lib/ssh/doc/standard/draft-ietf-secsh-architecture-15.2.ps b/lib/ssh/doc/standard/draft-ietf-secsh-architecture-15.2.ps deleted file mode 100644 index d766a933b4..0000000000 --- a/lib/ssh/doc/standard/draft-ietf-secsh-architecture-15.2.ps +++ /dev/null @@ -1,3315 +0,0 @@ -%!PS-Adobe-3.0 -%%BoundingBox: 75 0 595 747 -%%Title: Enscript Output -%%For: Magnus Thoang -%%Creator: GNU enscript 1.6.1 -%%CreationDate: Fri Oct 31 13:31:26 2003 -%%Orientation: Portrait -%%Pages: 15 0 -%%DocumentMedia: A4 595 842 0 () () -%%DocumentNeededResources: (atend) -%%EndComments -%%BeginProlog -%%BeginProcSet: PStoPS 1 15 -userdict begin -[/showpage/erasepage/copypage]{dup where{pop dup load - type/operatortype eq{1 array cvx dup 0 3 index cvx put - bind def}{pop}ifelse}{pop}ifelse}forall -[/letter/legal/executivepage/a4/a4small/b5/com10envelope - /monarchenvelope/c5envelope/dlenvelope/lettersmall/note - /folio/quarto/a5]{dup where{dup wcheck{exch{}put} - {pop{}def}ifelse}{pop}ifelse}forall -/setpagedevice {pop}bind 1 index where{dup wcheck{3 1 roll put} - {pop def}ifelse}{def}ifelse -/PStoPSmatrix matrix currentmatrix def -/PStoPSxform matrix def/PStoPSclip{clippath}def -/defaultmatrix{PStoPSmatrix exch PStoPSxform exch concatmatrix}bind def -/initmatrix{matrix defaultmatrix setmatrix}bind def -/initclip[{matrix currentmatrix PStoPSmatrix setmatrix - [{currentpoint}stopped{$error/newerror false put{newpath}} - {/newpath cvx 3 1 roll/moveto cvx 4 array astore cvx}ifelse] - {[/newpath cvx{/moveto cvx}{/lineto cvx} - {/curveto cvx}{/closepath cvx}pathforall]cvx exch pop} - stopped{$error/errorname get/invalidaccess eq{cleartomark - $error/newerror false put cvx exec}{stop}ifelse}if}bind aload pop - /initclip dup load dup type dup/operatortype eq{pop exch pop} - {dup/arraytype eq exch/packedarraytype eq or - {dup xcheck{exch pop aload pop}{pop cvx}ifelse} - {pop cvx}ifelse}ifelse - {newpath PStoPSclip clip newpath exec setmatrix} bind aload pop]cvx def -/initgraphics{initmatrix newpath initclip 1 setlinewidth - 0 setlinecap 0 setlinejoin []0 setdash 0 setgray - 10 setmiterlimit}bind def -end -%%EndProcSet -%%BeginResource: procset Enscript-Prolog 1.6 1 -% -% Procedures. -% - -/_S { % save current state - /_s save def -} def -/_R { % restore from saved state - _s restore -} def - -/S { % showpage protecting gstate - gsave - showpage - grestore -} bind def - -/MF { % fontname newfontname -> - make a new encoded font - /newfontname exch def - /fontname exch def - - /fontdict fontname findfont def - /newfont fontdict maxlength dict def - - fontdict { - exch - dup /FID eq { - % skip FID pair - pop pop - } { - % copy to the new font dictionary - exch newfont 3 1 roll put - } ifelse - } forall - - newfont /FontName newfontname put - - % insert only valid encoding vectors - encoding_vector length 256 eq { - newfont /Encoding encoding_vector put - } if - - newfontname newfont definefont pop -} def - -/SF { % fontname width height -> - set a new font - /height exch def - /width exch def - - findfont - [width 0 0 height 0 0] makefont setfont -} def - -/SUF { % fontname width height -> - set a new user font - /height exch def - /width exch def - - /F-gs-user-font MF - /F-gs-user-font width height SF -} def - -/M {moveto} bind def -/s {show} bind def - -/Box { % x y w h -> - define box path - /d_h exch def /d_w exch def /d_y exch def /d_x exch def - d_x d_y moveto - d_w 0 rlineto - 0 d_h rlineto - d_w neg 0 rlineto - closepath -} def - -/bgs { % x y height blskip gray str -> - show string with bg color - /str exch def - /gray exch def - /blskip exch def - /height exch def - /y exch def - /x exch def - - gsave - x y blskip sub str stringwidth pop height Box - gray setgray - fill - grestore - x y M str s -} def - -% Highlight bars. -/highlight_bars { % nlines lineheight output_y_margin gray -> - - gsave - setgray - /ymarg exch def - /lineheight exch def - /nlines exch def - - % This 2 is just a magic number to sync highlight lines to text. - 0 d_header_y ymarg sub 2 sub translate - - /cw d_output_w cols div def - /nrows d_output_h ymarg 2 mul sub lineheight div cvi def - - % for each column - 0 1 cols 1 sub { - cw mul /xp exch def - - % for each rows - 0 1 nrows 1 sub { - /rn exch def - rn lineheight mul neg /yp exch def - rn nlines idiv 2 mod 0 eq { - % Draw highlight bar. 4 is just a magic indentation. - xp 4 add yp cw 8 sub lineheight neg Box fill - } if - } for - } for - - grestore -} def - -% Line highlight bar. -/line_highlight { % x y width height gray -> - - gsave - /gray exch def - Box gray setgray fill - grestore -} def - -% Column separator lines. -/column_lines { - gsave - .1 setlinewidth - 0 d_footer_h translate - /cw d_output_w cols div def - 1 1 cols 1 sub { - cw mul 0 moveto - 0 d_output_h rlineto stroke - } for - grestore -} def - -% Column borders. -/column_borders { - gsave - .1 setlinewidth - 0 d_footer_h moveto - 0 d_output_h rlineto - d_output_w 0 rlineto - 0 d_output_h neg rlineto - closepath stroke - grestore -} def - -% Do the actual underlay drawing -/draw_underlay { - ul_style 0 eq { - ul_str true charpath stroke - } { - ul_str show - } ifelse -} def - -% Underlay -/underlay { % - -> - - gsave - 0 d_page_h translate - d_page_h neg d_page_w atan rotate - - ul_gray setgray - ul_font setfont - /dw d_page_h dup mul d_page_w dup mul add sqrt def - ul_str stringwidth pop dw exch sub 2 div ul_h_ptsize -2 div moveto - draw_underlay - grestore -} def - -/user_underlay { % - -> - - gsave - ul_x ul_y translate - ul_angle rotate - ul_gray setgray - ul_font setfont - 0 0 ul_h_ptsize 2 div sub moveto - draw_underlay - grestore -} def - -% Page prefeed -/page_prefeed { % bool -> - - statusdict /prefeed known { - statusdict exch /prefeed exch put - } { - pop - } ifelse -} def - -% Wrapped line markers -/wrapped_line_mark { % x y charwith charheight type -> - - /type exch def - /h exch def - /w exch def - /y exch def - /x exch def - - type 2 eq { - % Black boxes (like TeX does) - gsave - 0 setlinewidth - x w 4 div add y M - 0 h rlineto w 2 div 0 rlineto 0 h neg rlineto - closepath fill - grestore - } { - type 3 eq { - % Small arrows - gsave - .2 setlinewidth - x w 2 div add y h 2 div add M - w 4 div 0 rlineto - x w 4 div add y lineto stroke - - x w 4 div add w 8 div add y h 4 div add M - x w 4 div add y lineto - w 4 div h 8 div rlineto stroke - grestore - } { - % do nothing - } ifelse - } ifelse -} def - -% EPSF import. - -/BeginEPSF { - /b4_Inc_state save def % Save state for cleanup - /dict_count countdictstack def % Count objects on dict stack - /op_count count 1 sub def % Count objects on operand stack - userdict begin - /showpage { } def - 0 setgray 0 setlinecap - 1 setlinewidth 0 setlinejoin - 10 setmiterlimit [ ] 0 setdash newpath - /languagelevel where { - pop languagelevel - 1 ne { - false setstrokeadjust false setoverprint - } if - } if -} bind def - -/EndEPSF { - count op_count sub { pos } repeat % Clean up stacks - countdictstack dict_count sub { end } repeat - b4_Inc_state restore -} bind def - -% Check PostScript language level. -/languagelevel where { - pop /gs_languagelevel languagelevel def -} { - /gs_languagelevel 1 def -} ifelse -%%EndResource -%%BeginResource: procset Enscript-Encoding-88591 1.6 1 -/encoding_vector [ -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/space /exclam /quotedbl /numbersign -/dollar /percent /ampersand /quoteright -/parenleft /parenright /asterisk /plus -/comma /hyphen /period /slash -/zero /one /two /three -/four /five /six /seven -/eight /nine /colon /semicolon -/less /equal /greater /question -/at /A /B /C -/D /E /F /G -/H /I /J /K -/L /M /N /O -/P /Q /R /S -/T /U /V /W -/X /Y /Z /bracketleft -/backslash /bracketright /asciicircum /underscore -/quoteleft /a /b /c -/d /e /f /g -/h /i /j /k -/l /m /n /o -/p /q /r /s -/t /u /v /w -/x /y /z /braceleft -/bar /braceright /tilde /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/space /exclamdown /cent /sterling -/currency /yen /brokenbar /section -/dieresis /copyright /ordfeminine /guillemotleft -/logicalnot /hyphen /registered /macron -/degree /plusminus /twosuperior /threesuperior -/acute /mu /paragraph /bullet -/cedilla /onesuperior /ordmasculine /guillemotright -/onequarter /onehalf /threequarters /questiondown -/Agrave /Aacute /Acircumflex /Atilde -/Adieresis /Aring /AE /Ccedilla -/Egrave /Eacute /Ecircumflex /Edieresis -/Igrave /Iacute /Icircumflex /Idieresis -/Eth /Ntilde /Ograve /Oacute -/Ocircumflex /Otilde /Odieresis /multiply -/Oslash /Ugrave /Uacute /Ucircumflex -/Udieresis /Yacute /Thorn /germandbls -/agrave /aacute /acircumflex /atilde -/adieresis /aring /ae /ccedilla -/egrave /eacute /ecircumflex /edieresis -/igrave /iacute /icircumflex /idieresis -/eth /ntilde /ograve /oacute -/ocircumflex /otilde /odieresis /divide -/oslash /ugrave /uacute /ucircumflex -/udieresis /yacute /thorn /ydieresis -] def -%%EndResource -%%EndProlog -%%BeginSetup -%%IncludeResource: font Courier-Bold -%%IncludeResource: font Courier -/HFpt_w 10 def -/HFpt_h 10 def -/Courier-Bold /HF-gs-font MF -/HF /HF-gs-font findfont [HFpt_w 0 0 HFpt_h 0 0] makefont def -/Courier /F-gs-font MF -/F-gs-font 10 10 SF -/#copies 1 def -/d_page_w 520 def -/d_page_h 747 def -/d_header_x 0 def -/d_header_y 747 def -/d_header_w 520 def -/d_header_h 0 def -/d_footer_x 0 def -/d_footer_y 0 def -/d_footer_w 520 def -/d_footer_h 0 def -/d_output_w 520 def -/d_output_h 747 def -/cols 1 def -userdict/PStoPSxform PStoPSmatrix matrix currentmatrix - matrix invertmatrix matrix concatmatrix - matrix invertmatrix put -%%EndSetup -%%Page: (0,1) 1 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 1 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 701 M -(Network Working Group T. Ylonen) s -5 690 M -(Internet-Draft SSH Communications Security Corp) s -5 679 M -(Expires: March 31, 2004 D. Moffat, Ed.) s -5 668 M -( Sun Microsystems, Inc) s -5 657 M -( Oct 2003) s -5 624 M -( SSH Protocol Architecture) s -5 613 M -( draft-ietf-secsh-architecture-15.txt) s -5 591 M -(Status of this Memo) s -5 569 M -( This document is an Internet-Draft and is in full conformance with) s -5 558 M -( all provisions of Section 10 of RFC2026.) s -5 536 M -( Internet-Drafts are working documents of the Internet Engineering) s -5 525 M -( Task Force \(IETF\), its areas, and its working groups. Note that other) s -5 514 M -( groups may also distribute working documents as Internet-Drafts.) s -5 492 M -( Internet-Drafts are draft documents valid for a maximum of six months) s -5 481 M -( and may be updated, replaced, or obsoleted by other documents at any) s -5 470 M -( time. It is inappropriate to use Internet-Drafts as reference) s -5 459 M -( material or to cite them other than as "work in progress.") s -5 437 M -( The list of current Internet-Drafts can be accessed at http://) s -5 426 M -( www.ietf.org/ietf/1id-abstracts.txt.) s -5 404 M -( The list of Internet-Draft Shadow Directories can be accessed at) s -5 393 M -( http://www.ietf.org/shadow.html.) s -5 371 M -( This Internet-Draft will expire on March 31, 2004.) s -5 349 M -(Copyright Notice) s -5 327 M -( Copyright \(C\) The Internet Society \(2003\). All Rights Reserved.) s -5 305 M -(Abstract) s -5 283 M -( SSH is a protocol for secure remote login and other secure network) s -5 272 M -( services over an insecure network. This document describes the) s -5 261 M -( architecture of the SSH protocol, as well as the notation and) s -5 250 M -( terminology used in SSH protocol documents. It also discusses the SSH) s -5 239 M -( algorithm naming system that allows local extensions. The SSH) s -5 228 M -( protocol consists of three major components: The Transport Layer) s -5 217 M -( Protocol provides server authentication, confidentiality, and) s -5 206 M -( integrity with perfect forward secrecy. The User Authentication) s -5 195 M -( Protocol authenticates the client to the server. The Connection) s -5 184 M -( Protocol multiplexes the encrypted tunnel into several logical) s -5 173 M -( channels. Details of these protocols are described in separate) s -5 129 M -(Ylonen & Moffat Expires March 31, 2004 [Page 1]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 2 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Protocol Architecture Oct 2003) s -5 690 M -( documents.) s -5 668 M -(Table of Contents) s -5 646 M -( 1. Contributors . . . . . . . . . . . . . . . . . . . . . . . . 3) s -5 635 M -( 2. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3) s -5 624 M -( 3. Specification of Requirements . . . . . . . . . . . . . . . 3) s -5 613 M -( 4. Architecture . . . . . . . . . . . . . . . . . . . . . . . . 3) s -5 602 M -( 4.1 Host Keys . . . . . . . . . . . . . . . . . . . . . . . . . 4) s -5 591 M -( 4.2 Extensibility . . . . . . . . . . . . . . . . . . . . . . . 5) s -5 580 M -( 4.3 Policy Issues . . . . . . . . . . . . . . . . . . . . . . . 5) s -5 569 M -( 4.4 Security Properties . . . . . . . . . . . . . . . . . . . . 6) s -5 558 M -( 4.5 Packet Size and Overhead . . . . . . . . . . . . . . . . . . 6) s -5 547 M -( 4.6 Localization and Character Set Support . . . . . . . . . . . 7) s -5 536 M -( 5. Data Type Representations Used in the SSH Protocols . . . . 8) s -5 525 M -( 6. Algorithm Naming . . . . . . . . . . . . . . . . . . . . . . 10) s -5 514 M -( 7. Message Numbers . . . . . . . . . . . . . . . . . . . . . . 11) s -5 503 M -( 8. IANA Considerations . . . . . . . . . . . . . . . . . . . . 11) s -5 492 M -( 9. Security Considerations . . . . . . . . . . . . . . . . . . 12) s -5 481 M -( 9.1 Pseudo-Random Number Generation . . . . . . . . . . . . . . 12) s -5 470 M -( 9.2 Transport . . . . . . . . . . . . . . . . . . . . . . . . . 13) s -5 459 M -( 9.2.1 Confidentiality . . . . . . . . . . . . . . . . . . . . . . 13) s -5 448 M -( 9.2.2 Data Integrity . . . . . . . . . . . . . . . . . . . . . . . 16) s -5 437 M -( 9.2.3 Replay . . . . . . . . . . . . . . . . . . . . . . . . . . . 16) s -5 426 M -( 9.2.4 Man-in-the-middle . . . . . . . . . . . . . . . . . . . . . 17) s -5 415 M -( 9.2.5 Denial-of-service . . . . . . . . . . . . . . . . . . . . . 19) s -5 404 M -( 9.2.6 Covert Channels . . . . . . . . . . . . . . . . . . . . . . 19) s -5 393 M -( 9.2.7 Forward Secrecy . . . . . . . . . . . . . . . . . . . . . . 20) s -5 382 M -( 9.3 Authentication Protocol . . . . . . . . . . . . . . . . . . 20) s -5 371 M -( 9.3.1 Weak Transport . . . . . . . . . . . . . . . . . . . . . . . 21) s -5 360 M -( 9.3.2 Debug messages . . . . . . . . . . . . . . . . . . . . . . . 21) s -5 349 M -( 9.3.3 Local security policy . . . . . . . . . . . . . . . . . . . 21) s -5 338 M -( 9.3.4 Public key authentication . . . . . . . . . . . . . . . . . 22) s -5 327 M -( 9.3.5 Password authentication . . . . . . . . . . . . . . . . . . 22) s -5 316 M -( 9.3.6 Host based authentication . . . . . . . . . . . . . . . . . 23) s -5 305 M -( 9.4 Connection protocol . . . . . . . . . . . . . . . . . . . . 23) s -5 294 M -( 9.4.1 End point security . . . . . . . . . . . . . . . . . . . . . 23) s -5 283 M -( 9.4.2 Proxy forwarding . . . . . . . . . . . . . . . . . . . . . . 23) s -5 272 M -( 9.4.3 X11 forwarding . . . . . . . . . . . . . . . . . . . . . . . 24) s -5 261 M -( Normative References . . . . . . . . . . . . . . . . . . . . 24) s -5 250 M -( Informative References . . . . . . . . . . . . . . . . . . . 25) s -5 239 M -( Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 27) s -5 228 M -( Intellectual Property and Copyright Statements . . . . . . . 28) s -5 129 M -(Ylonen & Moffat Expires March 31, 2004 [Page 2]) s -_R -S -PStoPSsaved restore -%%Page: (2,3) 2 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 3 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Protocol Architecture Oct 2003) s -5 690 M -(1. Contributors) s -5 668 M -( The major original contributors of this document were: Tatu Ylonen,) s -5 657 M -( Tero Kivinen, Timo J. Rinne, Sami Lehtinen \(all of SSH Communications) s -5 646 M -( Security Corp\), and Markku-Juhani O. Saarinen \(University of) s -5 635 M -( Jyvaskyla\)) s -5 613 M -( The document editor is: [email protected]. Comments on this) s -5 602 M -( internet draft should be sent to the IETF SECSH working group,) s -5 591 M -( details at: http://ietf.org/html.charters/secsh-charter.html) s -5 569 M -(2. Introduction) s -5 547 M -( SSH is a protocol for secure remote login and other secure network) s -5 536 M -( services over an insecure network. It consists of three major) s -5 525 M -( components:) s -5 514 M -( o The Transport Layer Protocol [SSH-TRANS] provides server) s -5 503 M -( authentication, confidentiality, and integrity. It may optionally) s -5 492 M -( also provide compression. The transport layer will typically be) s -5 481 M -( run over a TCP/IP connection, but might also be used on top of any) s -5 470 M -( other reliable data stream.) s -5 459 M -( o The User Authentication Protocol [SSH-USERAUTH] authenticates the) s -5 448 M -( client-side user to the server. It runs over the transport layer) s -5 437 M -( protocol.) s -5 426 M -( o The Connection Protocol [SSH-CONNECT] multiplexes the encrypted) s -5 415 M -( tunnel into several logical channels. It runs over the user) s -5 404 M -( authentication protocol.) s -5 382 M -( The client sends a service request once a secure transport layer) s -5 371 M -( connection has been established. A second service request is sent) s -5 360 M -( after user authentication is complete. This allows new protocols to) s -5 349 M -( be defined and coexist with the protocols listed above.) s -5 327 M -( The connection protocol provides channels that can be used for a wide) s -5 316 M -( range of purposes. Standard methods are provided for setting up) s -5 305 M -( secure interactive shell sessions and for forwarding \("tunneling"\)) s -5 294 M -( arbitrary TCP/IP ports and X11 connections.) s -5 272 M -(3. Specification of Requirements) s -5 250 M -( All documents related to the SSH protocols shall use the keywords) s -5 239 M -( "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",) s -5 228 M -( "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" to describe) s -5 217 M -( requirements. They are to be interpreted as described in [RFC2119].) s -5 195 M -(4. Architecture) s -5 129 M -(Ylonen & Moffat Expires March 31, 2004 [Page 3]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 4 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Protocol Architecture Oct 2003) s -5 690 M -(4.1 Host Keys) s -5 668 M -( Each server host SHOULD have a host key. Hosts MAY have multiple) s -5 657 M -( host keys using multiple different algorithms. Multiple hosts MAY) s -5 646 M -( share the same host key. If a host has keys at all, it MUST have at) s -5 635 M -( least one key using each REQUIRED public key algorithm \(DSS) s -5 624 M -( [FIPS-186]\).) s -5 602 M -( The server host key is used during key exchange to verify that the) s -5 591 M -( client is really talking to the correct server. For this to be) s -5 580 M -( possible, the client must have a priori knowledge of the server's) s -5 569 M -( public host key.) s -5 547 M -( Two different trust models can be used:) s -5 536 M -( o The client has a local database that associates each host name \(as) s -5 525 M -( typed by the user\) with the corresponding public host key. This) s -5 514 M -( method requires no centrally administered infrastructure, and no) s -5 503 M -( third-party coordination. The downside is that the database of) s -5 492 M -( name-to-key associations may become burdensome to maintain.) s -5 481 M -( o The host name-to-key association is certified by some trusted) s -5 470 M -( certification authority. The client only knows the CA root key,) s -5 459 M -( and can verify the validity of all host keys certified by accepted) s -5 448 M -( CAs.) s -5 426 M -( The second alternative eases the maintenance problem, since) s -5 415 M -( ideally only a single CA key needs to be securely stored on the) s -5 404 M -( client. On the other hand, each host key must be appropriately) s -5 393 M -( certified by a central authority before authorization is possible.) s -5 382 M -( Also, a lot of trust is placed on the central infrastructure.) s -5 360 M -( The protocol provides the option that the server name - host key) s -5 349 M -( association is not checked when connecting to the host for the first) s -5 338 M -( time. This allows communication without prior communication of host) s -5 327 M -( keys or certification. The connection still provides protection) s -5 316 M -( against passive listening; however, it becomes vulnerable to active) s -5 305 M -( man-in-the-middle attacks. Implementations SHOULD NOT normally allow) s -5 294 M -( such connections by default, as they pose a potential security) s -5 283 M -( problem. However, as there is no widely deployed key infrastructure) s -5 272 M -( available on the Internet yet, this option makes the protocol much) s -5 261 M -( more usable during the transition time until such an infrastructure) s -5 250 M -( emerges, while still providing a much higher level of security than) s -5 239 M -( that offered by older solutions \(e.g. telnet [RFC-854] and rlogin) s -5 228 M -( [RFC-1282]\).) s -5 206 M -( Implementations SHOULD try to make the best effort to check host) s -5 195 M -( keys. An example of a possible strategy is to only accept a host key) s -5 184 M -( without checking the first time a host is connected, save the key in) s -5 173 M -( a local database, and compare against that key on all future) s -5 129 M -(Ylonen & Moffat Expires March 31, 2004 [Page 4]) s -_R -S -PStoPSsaved restore -%%Page: (4,5) 3 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 5 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Protocol Architecture Oct 2003) s -5 690 M -( connections to that host.) s -5 668 M -( Implementations MAY provide additional methods for verifying the) s -5 657 M -( correctness of host keys, e.g. a hexadecimal fingerprint derived from) s -5 646 M -( the SHA-1 hash of the public key. Such fingerprints can easily be) s -5 635 M -( verified by using telephone or other external communication channels.) s -5 613 M -( All implementations SHOULD provide an option to not accept host keys) s -5 602 M -( that cannot be verified.) s -5 580 M -( We believe that ease of use is critical to end-user acceptance of) s -5 569 M -( security solutions, and no improvement in security is gained if the) s -5 558 M -( new solutions are not used. Thus, providing the option not to check) s -5 547 M -( the server host key is believed to improve the overall security of) s -5 536 M -( the Internet, even though it reduces the security of the protocol in) s -5 525 M -( configurations where it is allowed.) s -5 503 M -(4.2 Extensibility) s -5 481 M -( We believe that the protocol will evolve over time, and some) s -5 470 M -( organizations will want to use their own encryption, authentication) s -5 459 M -( and/or key exchange methods. Central registration of all extensions) s -5 448 M -( is cumbersome, especially for experimental or classified features.) s -5 437 M -( On the other hand, having no central registration leads to conflicts) s -5 426 M -( in method identifiers, making interoperability difficult.) s -5 404 M -( We have chosen to identify algorithms, methods, formats, and) s -5 393 M -( extension protocols with textual names that are of a specific format.) s -5 382 M -( DNS names are used to create local namespaces where experimental or) s -5 371 M -( classified extensions can be defined without fear of conflicts with) s -5 360 M -( other implementations.) s -5 338 M -( One design goal has been to keep the base protocol as simple as) s -5 327 M -( possible, and to require as few algorithms as possible. However, all) s -5 316 M -( implementations MUST support a minimal set of algorithms to ensure) s -5 305 M -( interoperability \(this does not imply that the local policy on all) s -5 294 M -( hosts would necessary allow these algorithms\). The mandatory) s -5 283 M -( algorithms are specified in the relevant protocol documents.) s -5 261 M -( Additional algorithms, methods, formats, and extension protocols can) s -5 250 M -( be defined in separate drafts. See Section Algorithm Naming \(Section) s -5 239 M -( 6\) for more information.) s -5 217 M -(4.3 Policy Issues) s -5 195 M -( The protocol allows full negotiation of encryption, integrity, key) s -5 184 M -( exchange, compression, and public key algorithms and formats.) s -5 173 M -( Encryption, integrity, public key, and compression algorithms can be) s -5 129 M -(Ylonen & Moffat Expires March 31, 2004 [Page 5]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 6 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Protocol Architecture Oct 2003) s -5 690 M -( different for each direction.) s -5 668 M -( The following policy issues SHOULD be addressed in the configuration) s -5 657 M -( mechanisms of each implementation:) s -5 646 M -( o Encryption, integrity, and compression algorithms, separately for) s -5 635 M -( each direction. The policy MUST specify which is the preferred) s -5 624 M -( algorithm \(e.g. the first algorithm listed in each category\).) s -5 613 M -( o Public key algorithms and key exchange method to be used for host) s -5 602 M -( authentication. The existence of trusted host keys for different) s -5 591 M -( public key algorithms also affects this choice.) s -5 580 M -( o The authentication methods that are to be required by the server) s -5 569 M -( for each user. The server's policy MAY require multiple) s -5 558 M -( authentication for some or all users. The required algorithms MAY) s -5 547 M -( depend on the location where the user is trying to log in from.) s -5 536 M -( o The operations that the user is allowed to perform using the) s -5 525 M -( connection protocol. Some issues are related to security; for) s -5 514 M -( example, the policy SHOULD NOT allow the server to start sessions) s -5 503 M -( or run commands on the client machine, and MUST NOT allow) s -5 492 M -( connections to the authentication agent unless forwarding such) s -5 481 M -( connections has been requested. Other issues, such as which TCP/) s -5 470 M -( IP ports can be forwarded and by whom, are clearly issues of local) s -5 459 M -( policy. Many of these issues may involve traversing or bypassing) s -5 448 M -( firewalls, and are interrelated with the local security policy.) s -5 426 M -(4.4 Security Properties) s -5 404 M -( The primary goal of the SSH protocol is improved security on the) s -5 393 M -( Internet. It attempts to do this in a way that is easy to deploy,) s -5 382 M -( even at the cost of absolute security.) s -5 371 M -( o All encryption, integrity, and public key algorithms used are) s -5 360 M -( well-known, well-established algorithms.) s -5 349 M -( o All algorithms are used with cryptographically sound key sizes) s -5 338 M -( that are believed to provide protection against even the strongest) s -5 327 M -( cryptanalytic attacks for decades.) s -5 316 M -( o All algorithms are negotiated, and in case some algorithm is) s -5 305 M -( broken, it is easy to switch to some other algorithm without) s -5 294 M -( modifying the base protocol.) s -5 272 M -( Specific concessions were made to make wide-spread fast deployment) s -5 261 M -( easier. The particular case where this comes up is verifying that) s -5 250 M -( the server host key really belongs to the desired host; the protocol) s -5 239 M -( allows the verification to be left out \(but this is NOT RECOMMENDED\).) s -5 228 M -( This is believed to significantly improve usability in the short) s -5 217 M -( term, until widespread Internet public key infrastructures emerge.) s -5 195 M -(4.5 Packet Size and Overhead) s -5 173 M -( Some readers will worry about the increase in packet size due to new) s -5 129 M -(Ylonen & Moffat Expires March 31, 2004 [Page 6]) s -_R -S -PStoPSsaved restore -%%Page: (6,7) 4 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 7 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Protocol Architecture Oct 2003) s -5 690 M -( headers, padding, and MAC. The minimum packet size is in the order) s -5 679 M -( of 28 bytes \(depending on negotiated algorithms\). The increase is) s -5 668 M -( negligible for large packets, but very significant for one-byte) s -5 657 M -( packets \(telnet-type sessions\). There are, however, several factors) s -5 646 M -( that make this a non-issue in almost all cases:) s -5 635 M -( o The minimum size of a TCP/IP header is 32 bytes. Thus, the) s -5 624 M -( increase is actually from 33 to 51 bytes \(roughly\).) s -5 613 M -( o The minimum size of the data field of an Ethernet packet is 46) s -5 602 M -( bytes [RFC-894]. Thus, the increase is no more than 5 bytes. When) s -5 591 M -( Ethernet headers are considered, the increase is less than 10) s -5 580 M -( percent.) s -5 569 M -( o The total fraction of telnet-type data in the Internet is) s -5 558 M -( negligible, even with increased packet sizes.) s -5 536 M -( The only environment where the packet size increase is likely to have) s -5 525 M -( a significant effect is PPP [RFC-1134] over slow modem lines \(PPP) s -5 514 M -( compresses the TCP/IP headers, emphasizing the increase in packet) s -5 503 M -( size\). However, with modern modems, the time needed to transfer is in) s -5 492 M -( the order of 2 milliseconds, which is a lot faster than people can) s -5 481 M -( type.) s -5 459 M -( There are also issues related to the maximum packet size. To) s -5 448 M -( minimize delays in screen updates, one does not want excessively) s -5 437 M -( large packets for interactive sessions. The maximum packet size is) s -5 426 M -( negotiated separately for each channel.) s -5 404 M -(4.6 Localization and Character Set Support) s -5 382 M -( For the most part, the SSH protocols do not directly pass text that) s -5 371 M -( would be displayed to the user. However, there are some places where) s -5 360 M -( such data might be passed. When applicable, the character set for the) s -5 349 M -( data MUST be explicitly specified. In most places, ISO 10646 with) s -5 338 M -( UTF-8 encoding is used [RFC-2279]. When applicable, a field is also) s -5 327 M -( provided for a language tag [RFC-3066].) s -5 305 M -( One big issue is the character set of the interactive session. There) s -5 294 M -( is no clear solution, as different applications may display data in) s -5 283 M -( different formats. Different types of terminal emulation may also be) s -5 272 M -( employed in the client, and the character set to be used is) s -5 261 M -( effectively determined by the terminal emulation. Thus, no place is) s -5 250 M -( provided for directly specifying the character set or encoding for) s -5 239 M -( terminal session data. However, the terminal emulation type \(e.g.) s -5 228 M -( "vt100"\) is transmitted to the remote site, and it implicitly) s -5 217 M -( specifies the character set and encoding. Applications typically use) s -5 206 M -( the terminal type to determine what character set they use, or the) s -5 195 M -( character set is determined using some external means. The terminal) s -5 184 M -( emulation may also allow configuring the default character set. In) s -5 173 M -( any case, the character set for the terminal session is considered) s -5 129 M -(Ylonen & Moffat Expires March 31, 2004 [Page 7]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 8 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Protocol Architecture Oct 2003) s -5 690 M -( primarily a client local issue.) s -5 668 M -( Internal names used to identify algorithms or protocols are normally) s -5 657 M -( never displayed to users, and must be in US-ASCII.) s -5 635 M -( The client and server user names are inherently constrained by what) s -5 624 M -( the server is prepared to accept. They might, however, occasionally) s -5 613 M -( be displayed in logs, reports, etc. They MUST be encoded using ISO) s -5 602 M -( 10646 UTF-8, but other encodings may be required in some cases. It) s -5 591 M -( is up to the server to decide how to map user names to accepted user) s -5 580 M -( names. Straight bit-wise binary comparison is RECOMMENDED.) s -5 558 M -( For localization purposes, the protocol attempts to minimize the) s -5 547 M -( number of textual messages transmitted. When present, such messages) s -5 536 M -( typically relate to errors, debugging information, or some externally) s -5 525 M -( configured data. For data that is normally displayed, it SHOULD be) s -5 514 M -( possible to fetch a localized message instead of the transmitted) s -5 503 M -( message by using a numerical code. The remaining messages SHOULD be) s -5 492 M -( configurable.) s -5 470 M -(5. Data Type Representations Used in the SSH Protocols) s -5 459 M -( byte) s -5 437 M -( A byte represents an arbitrary 8-bit value \(octet\) [RFC-1700].) s -5 426 M -( Fixed length data is sometimes represented as an array of bytes,) s -5 415 M -( written byte[n], where n is the number of bytes in the array.) s -5 393 M -( boolean) s -5 371 M -( A boolean value is stored as a single byte. The value 0) s -5 360 M -( represents FALSE, and the value 1 represents TRUE. All non-zero) s -5 349 M -( values MUST be interpreted as TRUE; however, applications MUST NOT) s -5 338 M -( store values other than 0 and 1.) s -5 316 M -( uint32) s -5 294 M -( Represents a 32-bit unsigned integer. Stored as four bytes in the) s -5 283 M -( order of decreasing significance \(network byte order\). For) s -5 272 M -( example, the value 699921578 \(0x29b7f4aa\) is stored as 29 b7 f4) s -5 261 M -( aa.) s -5 239 M -( uint64) s -5 217 M -( Represents a 64-bit unsigned integer. Stored as eight bytes in) s -5 206 M -( the order of decreasing significance \(network byte order\).) s -5 129 M -(Ylonen & Moffat Expires March 31, 2004 [Page 8]) s -_R -S -PStoPSsaved restore -%%Page: (8,9) 5 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 9 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Protocol Architecture Oct 2003) s -5 690 M -( string) s -5 668 M -( Arbitrary length binary string. Strings are allowed to contain) s -5 657 M -( arbitrary binary data, including null characters and 8-bit) s -5 646 M -( characters. They are stored as a uint32 containing its length) s -5 635 M -( \(number of bytes that follow\) and zero \(= empty string\) or more) s -5 624 M -( bytes that are the value of the string. Terminating null) s -5 613 M -( characters are not used.) s -5 591 M -( Strings are also used to store text. In that case, US-ASCII is) s -5 580 M -( used for internal names, and ISO-10646 UTF-8 for text that might) s -5 569 M -( be displayed to the user. The terminating null character SHOULD) s -5 558 M -( NOT normally be stored in the string.) s -5 536 M -( For example, the US-ASCII string "testing" is represented as 00 00) s -5 525 M -( 00 07 t e s t i n g. The UTF8 mapping does not alter the encoding) s -5 514 M -( of US-ASCII characters.) s -5 492 M -( mpint) s -5 470 M -( Represents multiple precision integers in two's complement format,) s -5 459 M -( stored as a string, 8 bits per byte, MSB first. Negative numbers) s -5 448 M -( have the value 1 as the most significant bit of the first byte of) s -5 437 M -( the data partition. If the most significant bit would be set for a) s -5 426 M -( positive number, the number MUST be preceded by a zero byte.) s -5 415 M -( Unnecessary leading bytes with the value 0 or 255 MUST NOT be) s -5 404 M -( included. The value zero MUST be stored as a string with zero) s -5 393 M -( bytes of data.) s -5 371 M -( By convention, a number that is used in modular computations in) s -5 360 M -( Z_n SHOULD be represented in the range 0 <= x < n.) s -5 338 M -( Examples:) s -5 327 M -( value \(hex\) representation \(hex\)) s -5 316 M -( ---------------------------------------------------------------) s -5 305 M -( 0 00 00 00 00) s -5 294 M -( 9a378f9b2e332a7 00 00 00 08 09 a3 78 f9 b2 e3 32 a7) s -5 283 M -( 80 00 00 00 02 00 80) s -5 272 M -( -1234 00 00 00 02 ed cc) s -5 261 M -( -deadbeef 00 00 00 05 ff 21 52 41 11) s -5 217 M -( name-list) s -5 195 M -( A string containing a comma separated list of names. A name list) s -5 184 M -( is represented as a uint32 containing its length \(number of bytes) s -5 173 M -( that follow\) followed by a comma-separated list of zero or more) s -5 129 M -(Ylonen & Moffat Expires March 31, 2004 [Page 9]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 10 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Protocol Architecture Oct 2003) s -5 690 M -( names. A name MUST be non-zero length, and it MUST NOT contain a) s -5 679 M -( comma \(','\). Context may impose additional restrictions on the) s -5 668 M -( names; for example, the names in a list may have to be valid) s -5 657 M -( algorithm identifier \(see Algorithm Naming below\), or [RFC-3066]) s -5 646 M -( language tags. The order of the names in a list may or may not be) s -5 635 M -( significant, also depending on the context where the list is is) s -5 624 M -( used. Terminating NUL characters are not used, neither for the) s -5 613 M -( individual names, nor for the list as a whole.) s -5 591 M -( Examples:) s -5 580 M -( value representation \(hex\)) s -5 569 M -( ---------------------------------------) s -5 558 M -( \(\), the empty list 00 00 00 00) s -5 547 M -( \("zlib"\) 00 00 00 04 7a 6c 69 62) s -5 536 M -( \("zlib", "none"\) 00 00 00 09 7a 6c 69 62 2c 6e 6f 6e 65) s -5 481 M -(6. Algorithm Naming) s -5 459 M -( The SSH protocols refer to particular hash, encryption, integrity,) s -5 448 M -( compression, and key exchange algorithms or protocols by names.) s -5 437 M -( There are some standard algorithms that all implementations MUST) s -5 426 M -( support. There are also algorithms that are defined in the protocol) s -5 415 M -( specification but are OPTIONAL. Furthermore, it is expected that) s -5 404 M -( some organizations will want to use their own algorithms.) s -5 382 M -( In this protocol, all algorithm identifiers MUST be printable) s -5 371 M -( US-ASCII non-empty strings no longer than 64 characters. Names MUST) s -5 360 M -( be case-sensitive.) s -5 338 M -( There are two formats for algorithm names:) s -5 327 M -( o Names that do not contain an at-sign \(@\) are reserved to be) s -5 316 M -( assigned by IETF consensus \(RFCs\). Examples include `3des-cbc',) s -5 305 M -( `sha-1', `hmac-sha1', and `zlib' \(the quotes are not part of the) s -5 294 M -( name\). Names of this format MUST NOT be used without first) s -5 283 M -( registering them. Registered names MUST NOT contain an at-sign) s -5 272 M -( \(@\) or a comma \(,\).) s -5 261 M -( o Anyone can define additional algorithms by using names in the) s -5 250 M -( format name@domainname, e.g. "[email protected]". The) s -5 239 M -( format of the part preceding the at sign is not specified; it MUST) s -5 228 M -( consist of US-ASCII characters except at-sign and comma. The part) s -5 217 M -( following the at-sign MUST be a valid fully qualified internet) s -5 206 M -( domain name [RFC-1034] controlled by the person or organization) s -5 195 M -( defining the name. It is up to each domain how it manages its) s -5 184 M -( local namespace.) s -5 129 M -(Ylonen & Moffat Expires March 31, 2004 [Page 10]) s -_R -S -PStoPSsaved restore -%%Page: (10,11) 6 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 11 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Protocol Architecture Oct 2003) s -5 690 M -(7. Message Numbers) s -5 668 M -( SSH packets have message numbers in the range 1 to 255. These numbers) s -5 657 M -( have been allocated as follows:) s -5 624 M -( Transport layer protocol:) s -5 602 M -( 1 to 19 Transport layer generic \(e.g. disconnect, ignore, debug,) s -5 591 M -( etc.\)) s -5 580 M -( 20 to 29 Algorithm negotiation) s -5 569 M -( 30 to 49 Key exchange method specific \(numbers can be reused for) s -5 558 M -( different authentication methods\)) s -5 536 M -( User authentication protocol:) s -5 514 M -( 50 to 59 User authentication generic) s -5 503 M -( 60 to 79 User authentication method specific \(numbers can be) s -5 492 M -( reused for different authentication methods\)) s -5 470 M -( Connection protocol:) s -5 448 M -( 80 to 89 Connection protocol generic) s -5 437 M -( 90 to 127 Channel related messages) s -5 415 M -( Reserved for client protocols:) s -5 393 M -( 128 to 191 Reserved) s -5 371 M -( Local extensions:) s -5 349 M -( 192 to 255 Local extensions) s -5 305 M -(8. IANA Considerations) s -5 283 M -( The initial state of the IANA registry is detailed in [SSH-NUMBERS].) s -5 261 M -( Allocation of the following types of names in the SSH protocols is) s -5 250 M -( assigned by IETF consensus:) s -5 239 M -( o SSH encryption algorithm names,) s -5 228 M -( o SSH MAC algorithm names,) s -5 217 M -( o SSH public key algorithm names \(public key algorithm also implies) s -5 206 M -( encoding and signature/encryption capability\),) s -5 195 M -( o SSH key exchange method names, and) s -5 184 M -( o SSH protocol \(service\) names.) s -5 129 M -(Ylonen & Moffat Expires March 31, 2004 [Page 11]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 12 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Protocol Architecture Oct 2003) s -5 690 M -( These names MUST be printable US-ASCII strings, and MUST NOT contain) s -5 679 M -( the characters at-sign \('@'\), comma \(','\), or whitespace or control) s -5 668 M -( characters \(ASCII codes 32 or less\). Names are case-sensitive, and) s -5 657 M -( MUST NOT be longer than 64 characters.) s -5 635 M -( Names with the at-sign \('@'\) in them are allocated by the owner of) s -5 624 M -( DNS name after the at-sign \(hierarchical allocation in [RFC-2343]\),) s -5 613 M -( otherwise the same restrictions as above.) s -5 591 M -( Each category of names listed above has a separate namespace.) s -5 580 M -( However, using the same name in multiple categories SHOULD be avoided) s -5 569 M -( to minimize confusion.) s -5 547 M -( Message numbers \(see Section Message Numbers \(Section 7\)\) in the) s -5 536 M -( range of 0..191 are allocated via IETF consensus; message numbers in) s -5 525 M -( the 192..255 range \(the "Local extensions" set\) are reserved for) s -5 514 M -( private use.) s -5 492 M -(9. Security Considerations) s -5 470 M -( In order to make the entire body of Security Considerations more) s -5 459 M -( accessible, Security Considerations for the transport,) s -5 448 M -( authentication, and connection documents have been gathered here.) s -5 426 M -( The transport protocol [1] provides a confidential channel over an) s -5 415 M -( insecure network. It performs server host authentication, key) s -5 404 M -( exchange, encryption, and integrity protection. It also derives a) s -5 393 M -( unique session id that may be used by higher-level protocols.) s -5 371 M -( The authentication protocol [2] provides a suite of mechanisms which) s -5 360 M -( can be used to authenticate the client user to the server.) s -5 349 M -( Individual mechanisms specified in the in authentication protocol use) s -5 338 M -( the session id provided by the transport protocol and/or depend on) s -5 327 M -( the security and integrity guarantees of the transport protocol.) s -5 305 M -( The connection protocol [3] specifies a mechanism to multiplex) s -5 294 M -( multiple streams [channels] of data over the confidential and) s -5 283 M -( authenticated transport. It also specifies channels for accessing an) s -5 272 M -( interactive shell, for 'proxy-forwarding' various external protocols) s -5 261 M -( over the secure transport \(including arbitrary TCP/IP protocols\), and) s -5 250 M -( for accessing secure 'subsystems' on the server host.) s -5 228 M -(9.1 Pseudo-Random Number Generation) s -5 206 M -( This protocol binds each session key to the session by including) s -5 195 M -( random, session specific data in the hash used to produce session) s -5 184 M -( keys. Special care should be taken to ensure that all of the random) s -5 173 M -( numbers are of good quality. If the random data here \(e.g., DH) s -5 129 M -(Ylonen & Moffat Expires March 31, 2004 [Page 12]) s -_R -S -PStoPSsaved restore -%%Page: (12,13) 7 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 13 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Protocol Architecture Oct 2003) s -5 690 M -( parameters\) are pseudo-random then the pseudo-random number generator) s -5 679 M -( should be cryptographically secure \(i.e., its next output not easily) s -5 668 M -( guessed even when knowing all previous outputs\) and, furthermore,) s -5 657 M -( proper entropy needs to be added to the pseudo-random number) s -5 646 M -( generator. RFC 1750 [1750] offers suggestions for sources of random) s -5 635 M -( numbers and entropy. Implementors should note the importance of) s -5 624 M -( entropy and the well-meant, anecdotal warning about the difficulty in) s -5 613 M -( properly implementing pseudo-random number generating functions.) s -5 591 M -( The amount of entropy available to a given client or server may) s -5 580 M -( sometimes be less than what is required. In this case one must) s -5 569 M -( either resort to pseudo-random number generation regardless of) s -5 558 M -( insufficient entropy or refuse to run the protocol. The latter is) s -5 547 M -( preferable.) s -5 525 M -(9.2 Transport) s -5 503 M -(9.2.1 Confidentiality) s -5 481 M -( It is beyond the scope of this document and the Secure Shell Working) s -5 470 M -( Group to analyze or recommend specific ciphers other than the ones) s -5 459 M -( which have been established and accepted within the industry. At the) s -5 448 M -( time of this writing, ciphers commonly in use include 3DES, ARCFOUR,) s -5 437 M -( twofish, serpent and blowfish. AES has been accepted by The) s -5 426 M -( published as a US Federal Information Processing Standards [FIPS-197]) s -5 415 M -( and the cryptographic community as being acceptable for this purpose) s -5 404 M -( as well has accepted AES. As always, implementors and users should) s -5 393 M -( check current literature to ensure that no recent vulnerabilities) s -5 382 M -( have been found in ciphers used within products. Implementors should) s -5 371 M -( also check to see which ciphers are considered to be relatively) s -5 360 M -( stronger than others and should recommend their use to users over) s -5 349 M -( relatively weaker ciphers. It would be considered good form for an) s -5 338 M -( implementation to politely and unobtrusively notify a user that a) s -5 327 M -( stronger cipher is available and should be used when a weaker one is) s -5 316 M -( actively chosen.) s -5 294 M -( The "none" cipher is provided for debugging and SHOULD NOT be used) s -5 283 M -( except for that purpose. It's cryptographic properties are) s -5 272 M -( sufficiently described in RFC 2410, which will show that its use does) s -5 261 M -( not meet the intent of this protocol.) s -5 239 M -( The relative merits of these and other ciphers may also be found in) s -5 228 M -( current literature. Two references that may provide information on) s -5 217 M -( the subject are [SCHNEIER] and [KAUFMAN,PERLMAN,SPECINER]. Both of) s -5 206 M -( these describe the CBC mode of operation of certain ciphers and the) s -5 195 M -( weakness of this scheme. Essentially, this mode is theoretically) s -5 184 M -( vulnerable to chosen cipher-text attacks because of the high) s -5 173 M -( predictability of the start of packet sequence. However, this attack) s -5 129 M -(Ylonen & Moffat Expires March 31, 2004 [Page 13]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 14 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Protocol Architecture Oct 2003) s -5 690 M -( is still deemed difficult and not considered fully practicable) s -5 679 M -( especially if relatively longer block sizes are used.) s -5 657 M -( Additionally, another CBC mode attack may be mitigated through the) s -5 646 M -( insertion of packets containing SSH_MSG_IGNORE. Without this) s -5 635 M -( technique, a specific attack may be successful. For this attack) s -5 624 M -( \(commonly known as the Rogaway attack) s -5 613 M -( [ROGAWAY],[DAI],[BELLARE,KOHNO,NAMPREMPRE]\) to work, the attacker) s -5 602 M -( would need to know the IV of the next block that is going to be) s -5 591 M -( encrypted. In CBC mode that is the output of the encryption of the) s -5 580 M -( previous block. If the attacker does not have any way to see the) s -5 569 M -( packet yet \(i.e it is in the internal buffers of the ssh) s -5 558 M -( implementation or even in the kernel\) then this attack will not work.) s -5 547 M -( If the last packet has been sent out to the network \(i.e the attacker) s -5 536 M -( has access to it\) then he can use the attack.) s -5 514 M -( In the optimal case an implementor would need to add an extra packet) s -5 503 M -( only if the packet has been sent out onto the network and there are) s -5 492 M -( no other packets waiting for transmission. Implementors may wish to) s -5 481 M -( check to see if there are any unsent packets awaiting transmission,) s -5 470 M -( but unfortunately it is not normally easy to obtain this information) s -5 459 M -( from the kernel or buffers. If there are not, then a packet) s -5 448 M -( containing SSH_MSG_IGNORE SHOULD be sent. If a new packet is added) s -5 437 M -( to the stream every time the attacker knows the IV that is supposed) s -5 426 M -( to be used for the next packet, then the attacker will not be able to) s -5 415 M -( guess the correct IV, thus the attack will never be successfull.) s -5 393 M -( As an example, consider the following case:) s -5 360 M -( Client Server) s -5 349 M -( ------ ------) s -5 338 M -( TCP\(seq=x, len=500\) ->) s -5 327 M -( contains Record 1) s -5 305 M -( [500 ms passes, no ACK]) s -5 283 M -( TCP\(seq=x, len=1000\) ->) s -5 272 M -( contains Records 1,2) s -5 250 M -( ACK) s -5 217 M -( 1. The Nagle algorithm + TCP retransmits mean that the two records) s -5 206 M -( get coalesced into a single TCP segment) s -5 195 M -( 2. Record 2 is *not* at the beginning of the TCP segment and never) s -5 184 M -( will be, since it gets ACKed.) s -5 129 M -(Ylonen & Moffat Expires March 31, 2004 [Page 14]) s -_R -S -PStoPSsaved restore -%%Page: (14,15) 8 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 15 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Protocol Architecture Oct 2003) s -5 690 M -( 3. Yet, the attack is possible because Record 1 has already been) s -5 679 M -( seen.) s -5 657 M -( As this example indicates, it's totally unsafe to use the existence) s -5 646 M -( of unflushed data in the TCP buffers proper as a guide to whether you) s -5 635 M -( need an empty packet, since when you do the second write\(\), the) s -5 624 M -( buffers will contain the un-ACKed Record 1.) s -5 129 M -(Ylonen & Moffat Expires March 31, 2004 [Page 15]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 16 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Protocol Architecture Oct 2003) s -5 690 M -( On the other hand, it's perfectly safe to have the following) s -5 679 M -( situation:) s -5 646 M -( Client Server) s -5 635 M -( ------ ------) s -5 624 M -( TCP\(seq=x, len=500\) ->) s -5 613 M -( contains SSH_MSG_IGNORE) s -5 591 M -( TCP\(seq=y, len=500\) ->) s -5 580 M -( contains Data) s -5 558 M -( Provided that the IV for second SSH Record is fixed after the data for) s -5 547 M -( the Data packet is determined -i.e. you do:) s -5 536 M -( read from user) s -5 525 M -( encrypt null packet) s -5 514 M -( encrypt data packet) s -5 481 M -(9.2.2 Data Integrity) s -5 459 M -( This protocol does allow the Data Integrity mechanism to be disabled.) s -5 448 M -( Implementors SHOULD be wary of exposing this feature for any purpose) s -5 437 M -( other than debugging. Users and administrators SHOULD be explicitly) s -5 426 M -( warned anytime the "none" MAC is enabled.) s -5 404 M -( So long as the "none" MAC is not used, this protocol provides data) s -5 393 M -( integrity.) s -5 371 M -( Because MACs use a 32 bit sequence number, they might start to leak) s -5 360 M -( information after 2**32 packets have been sent. However, following) s -5 349 M -( the rekeying recommendations should prevent this attack. The) s -5 338 M -( transport protocol [1] recommends rekeying after one gigabyte of) s -5 327 M -( data, and the smallest possible packet is 16 bytes. Therefore,) s -5 316 M -( rekeying SHOULD happen after 2**28 packets at the very most.) s -5 294 M -(9.2.3 Replay) s -5 272 M -( The use of a MAC other than 'none' provides integrity and) s -5 261 M -( authentication. In addition, the transport protocol provides a) s -5 250 M -( unique session identifier \(bound in part to pseudo-random data that) s -5 239 M -( is part of the algorithm and key exchange process\) that can be used) s -5 228 M -( by higher level protocols to bind data to a given session and prevent) s -5 217 M -( replay of data from prior sessions. For example, the authentication) s -5 206 M -( protocol uses this to prevent replay of signatures from previous) s -5 195 M -( sessions. Because public key authentication exchanges are) s -5 184 M -( cryptographically bound to the session \(i.e., to the initial key) s -5 173 M -( exchange\) they cannot be successfully replayed in other sessions.) s -5 129 M -(Ylonen & Moffat Expires March 31, 2004 [Page 16]) s -_R -S -PStoPSsaved restore -%%Page: (16,17) 9 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 17 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Protocol Architecture Oct 2003) s -5 690 M -( Note that the session ID can be made public without harming the) s -5 679 M -( security of the protocol.) s -5 657 M -( If two session happen to have the same session ID [hash of key) s -5 646 M -( exchanges] then packets from one can be replayed against the other.) s -5 635 M -( It must be stressed that the chances of such an occurrence are,) s -5 624 M -( needless to say, minimal when using modern cryptographic methods.) s -5 613 M -( This is all the more so true when specifying larger hash function) s -5 602 M -( outputs and DH parameters.) s -5 580 M -( Replay detection using monotonically increasing sequence numbers as) s -5 569 M -( input to the MAC, or HMAC in some cases, is described in [RFC2085] />) s -5 558 M -( [RFC2246], [RFC2743], [RFC1964], [RFC2025], and [RFC1510]. The) s -5 547 M -( underlying construct is discussed in [RFC2104]. Essentially a) s -5 536 M -( different sequence number in each packet ensures that at least this) s -5 525 M -( one input to the MAC function will be unique and will provide a) s -5 514 M -( nonrecurring MAC output that is not predictable to an attacker. If) s -5 503 M -( the session stays active long enough, however, this sequence number) s -5 492 M -( will wrap. This event may provide an attacker an opportunity to) s -5 481 M -( replay a previously recorded packet with an identical sequence number) s -5 470 M -( but only if the peers have not rekeyed since the transmission of the) s -5 459 M -( first packet with that sequence number. If the peers have rekeyed,) s -5 448 M -( then the replay will be detected as the MAC check will fail. For) s -5 437 M -( this reason, it must be emphasized that peers MUST rekey before a) s -5 426 M -( wrap of the sequence numbers. Naturally, if an attacker does attempt) s -5 415 M -( to replay a captured packet before the peers have rekeyed, then the) s -5 404 M -( receiver of the duplicate packet will not be able to validate the MAC) s -5 393 M -( and it will be discarded. The reason that the MAC will fail is) s -5 382 M -( because the receiver will formulate a MAC based upon the packet) s -5 371 M -( contents, the shared secret, and the expected sequence number. Since) s -5 360 M -( the replayed packet will not be using that expected sequence number) s -5 349 M -( \(the sequence number of the replayed packet will have already been) s -5 338 M -( passed by the receiver\) then the calculated MAC will not match the) s -5 327 M -( MAC received with the packet.) s -5 305 M -(9.2.4 Man-in-the-middle) s -5 283 M -( This protocol makes no assumptions nor provisions for an) s -5 272 M -( infrastructure or means for distributing the public keys of hosts. It) s -5 261 M -( is expected that this protocol will sometimes be used without first) s -5 250 M -( verifying the association between the server host key and the server) s -5 239 M -( host name. Such usage is vulnerable to man-in-the-middle attacks.) s -5 228 M -( This section describes this and encourages administrators and users) s -5 217 M -( to understand the importance of verifying this association before any) s -5 206 M -( session is initiated.) s -5 184 M -( There are three cases of man-in-the-middle attacks to consider. The) s -5 173 M -( first is where an attacker places a device between the client and the) s -5 129 M -(Ylonen & Moffat Expires March 31, 2004 [Page 17]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 18 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Protocol Architecture Oct 2003) s -5 690 M -( server before the session is initiated. In this case, the attack) s -5 679 M -( device is trying to mimic the legitimate server and will offer its) s -5 668 M -( public key to the client when the client initiates a session. If it) s -5 657 M -( were to offer the public key of the server, then it would not be able) s -5 646 M -( to decrypt or sign the transmissions between the legitimate server) s -5 635 M -( and the client unless it also had access to the private-key of the) s -5 624 M -( host. The attack device will also, simultaneously to this, initiate) s -5 613 M -( a session to the legitimate server masquerading itself as the client.) s -5 602 M -( If the public key of the server had been securely distributed to the) s -5 591 M -( client prior to that session initiation, the key offered to the) s -5 580 M -( client by the attack device will not match the key stored on the) s -5 569 M -( client. In that case, the user SHOULD be given a warning that the) s -5 558 M -( offered host key does not match the host key cached on the client.) s -5 547 M -( As described in Section 3.1 of [ARCH], the user may be free to accept) s -5 536 M -( the new key and continue the session. It is RECOMMENDED that the) s -5 525 M -( warning provide sufficient information to the user of the client) s -5 514 M -( device so they may make an informed decision. If the user chooses to) s -5 503 M -( continue the session with the stored public-key of the server \(not) s -5 492 M -( the public-key offered at the start of the session\), then the session) s -5 481 M -( specific data between the attacker and server will be different) s -5 470 M -( between the client-to-attacker session and the attacker-to-server) s -5 459 M -( sessions due to the randomness discussed above. From this, the) s -5 448 M -( attacker will not be able to make this attack work since the attacker) s -5 437 M -( will not be able to correctly sign packets containing this session) s -5 426 M -( specific data from the server since he does not have the private key) s -5 415 M -( of that server.) s -5 393 M -( The second case that should be considered is similar to the first) s -5 382 M -( case in that it also happens at the time of connection but this case) s -5 371 M -( points out the need for the secure distribution of server public) s -5 360 M -( keys. If the server public keys are not securely distributed then) s -5 349 M -( the client cannot know if it is talking to the intended server. An) s -5 338 M -( attacker may use social engineering techniques to pass off server) s -5 327 M -( keys to unsuspecting users and may then place a man-in-the-middle) s -5 316 M -( attack device between the legitimate server and the clients. If this) s -5 305 M -( is allowed to happen then the clients will form client-to-attacker) s -5 294 M -( sessions and the attacker will form attacker-to-server sessions and) s -5 283 M -( will be able to monitor and manipulate all of the traffic between the) s -5 272 M -( clients and the legitimate servers. Server administrators are) s -5 261 M -( encouraged to make host key fingerprints available for checking by) s -5 250 M -( some means whose security does not rely on the integrity of the) s -5 239 M -( actual host keys. Possible mechanisms are discussed in Section 3.1) s -5 228 M -( of [SSH-ARCH] and may also include secured Web pages, physical pieces) s -5 217 M -( of paper, etc. Implementors SHOULD provide recommendations on how) s -5 206 M -( best to do this with their implementation. Because the protocol is) s -5 195 M -( extensible, future extensions to the protocol may provide better) s -5 184 M -( mechanisms for dealing with the need to know the server's host key) s -5 173 M -( before connecting. For example, making the host key fingerprint) s -5 129 M -(Ylonen & Moffat Expires March 31, 2004 [Page 18]) s -_R -S -PStoPSsaved restore -%%Page: (18,19) 10 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 19 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Protocol Architecture Oct 2003) s -5 690 M -( available through a secure DNS lookup, or using kerberos over gssapi) s -5 679 M -( during key exchange to authenticate the server are possibilities.) s -5 657 M -( In the third man-in-the-middle case, attackers may attempt to) s -5 646 M -( manipulate packets in transit between peers after the session has) s -5 635 M -( been established. As described in the Replay part of this section, a) s -5 624 M -( successful attack of this nature is very improbable. As in the) s -5 613 M -( Replay section, this reasoning does assume that the MAC is secure and) s -5 602 M -( that it is infeasible to construct inputs to a MAC algorithm to give) s -5 591 M -( a known output. This is discussed in much greater detail in Section) s -5 580 M -( 6 of RFC 2104. If the MAC algorithm has a vulnerability or is weak) s -5 569 M -( enough, then the attacker may be able to specify certain inputs to) s -5 558 M -( yield a known MAC. With that they may be able to alter the contents) s -5 547 M -( of a packet in transit. Alternatively the attacker may be able to) s -5 536 M -( exploit the algorithm vulnerability or weakness to find the shared) s -5 525 M -( secret by reviewing the MACs from captured packets. In either of) s -5 514 M -( those cases, an attacker could construct a packet or packets that) s -5 503 M -( could be inserted into an SSH stream. To prevent that, implementors) s -5 492 M -( are encouraged to utilize commonly accepted MAC algorithms and) s -5 481 M -( administrators are encouraged to watch current literature and) s -5 470 M -( discussions of cryptography to ensure that they are not using a MAC) s -5 459 M -( algorithm that has a recently found vulnerability or weakness.) s -5 437 M -( In summary, the use of this protocol without a reliable association) s -5 426 M -( of the binding between a host and its host keys is inherently) s -5 415 M -( insecure and is NOT RECOMMENDED. It may however be necessary in) s -5 404 M -( non-security critical environments, and will still provide protection) s -5 393 M -( against passive attacks. Implementors of protocols and applications) s -5 382 M -( running on top of this protocol should keep this possibility in mind.) s -5 360 M -(9.2.5 Denial-of-service) s -5 338 M -( This protocol is designed to be used over a reliable transport. If) s -5 327 M -( transmission errors or message manipulation occur, the connection is) s -5 316 M -( closed. The connection SHOULD be re-established if this occurs.) s -5 305 M -( Denial of service attacks of this type \("wire cutter"\) are almost) s -5 294 M -( impossible to avoid.) s -5 272 M -( In addition, this protocol is vulnerable to Denial of Service attacks) s -5 261 M -( because an attacker can force the server to go through the CPU and) s -5 250 M -( memory intensive tasks of connection setup and key exchange without) s -5 239 M -( authenticating. Implementors SHOULD provide features that make this) s -5 228 M -( more difficult. For example, only allowing connections from a subset) s -5 217 M -( of IPs known to have valid users.) s -5 195 M -(9.2.6 Covert Channels) s -5 173 M -( The protocol was not designed to eliminate covert channels. For) s -5 129 M -(Ylonen & Moffat Expires March 31, 2004 [Page 19]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 20 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Protocol Architecture Oct 2003) s -5 690 M -( example, the padding, SSH_MSG_IGNORE messages, and several other) s -5 679 M -( places in the protocol can be used to pass covert information, and) s -5 668 M -( the recipient has no reliable way to verify whether such information) s -5 657 M -( is being sent.) s -5 635 M -(9.2.7 Forward Secrecy) s -5 613 M -( It should be noted that the Diffie-Hellman key exchanges may provide) s -5 602 M -( perfect forward secrecy \(PFS\). PFS is essentially defined as the) s -5 591 M -( cryptographic property of a key-establishment protocol in which the) s -5 580 M -( compromise of a session key or long-term private key after a given) s -5 569 M -( session does not cause the compromise of any earlier session. [ANSI) s -5 558 M -( T1.523-2001] SSHv2 sessions resulting from a key exchange using) s -5 547 M -( diffie-hellman-group1-sha1 are secure even if private keying/) s -5 536 M -( authentication material is later revealed, but not if the session) s -5 525 M -( keys are revealed. So, given this definition of PFS, SSHv2 does have) s -5 514 M -( PFS. It is hoped that all other key exchange mechanisms proposed and) s -5 503 M -( used in the future will also provide PFS. This property is not) s -5 492 M -( commuted to any of the applications or protocols using SSH as a) s -5 481 M -( transport however. The transport layer of SSH provides) s -5 470 M -( confidentiality for password authentication and other methods that) s -5 459 M -( rely on secret data.) s -5 437 M -( Of course, if the DH private parameters for the client and server are) s -5 426 M -( revealed then the session key is revealed, but these items can be) s -5 415 M -( thrown away after the key exchange completes. It's worth pointing) s -5 404 M -( out that these items should not be allowed to end up on swap space) s -5 393 M -( and that they should be erased from memory as soon as the key) s -5 382 M -( exchange completes.) s -5 360 M -(9.3 Authentication Protocol) s -5 338 M -( The purpose of this protocol is to perform client user) s -5 327 M -( authentication. It assumes that this run over a secure transport) s -5 316 M -( layer protocol, which has already authenticated the server machine,) s -5 305 M -( established an encrypted communications channel, and computed a) s -5 294 M -( unique session identifier for this session.) s -5 272 M -( Several authentication methods with different security) s -5 261 M -( characteristics are allowed. It is up to the server's local policy) s -5 250 M -( to decide which methods \(or combinations of methods\) it is willing to) s -5 239 M -( accept for each user. Authentication is no stronger than the weakest) s -5 228 M -( combination allowed.) s -5 206 M -( The server may go into a "sleep" period after repeated unsuccessful) s -5 195 M -( authentication attempts to make key search more difficult for) s -5 184 M -( attackers. Care should be taken so that this doesn't become a) s -5 173 M -( self-denial of service vector.) s -5 129 M -(Ylonen & Moffat Expires March 31, 2004 [Page 20]) s -_R -S -PStoPSsaved restore -%%Page: (20,21) 11 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 21 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Protocol Architecture Oct 2003) s -5 690 M -(9.3.1 Weak Transport) s -5 668 M -( If the transport layer does not provide confidentiality,) s -5 657 M -( authentication methods that rely on secret data SHOULD be disabled.) s -5 646 M -( If it does not provide strong integrity protection, requests to) s -5 635 M -( change authentication data \(e.g. a password change\) SHOULD be) s -5 624 M -( disabled to prevent an attacker from modifying the ciphertext) s -5 613 M -( without being noticed, or rendering the new authentication data) s -5 602 M -( unusable \(denial of service\).) s -5 580 M -( The assumption as stated above that the Authentication Protocol only) s -5 569 M -( run over a secure transport that has previously authenticated the) s -5 558 M -( server is very important to note. People deploying SSH are reminded) s -5 547 M -( of the consequences of man-in-the-middle attacks if the client does) s -5 536 M -( not have a very strong a priori association of the server with the) s -5 525 M -( host key of that server. Specifically for the case of the) s -5 514 M -( Authentication Protocol the client may form a session to a) s -5 503 M -( man-in-the-middle attack device and divulge user credentials such as) s -5 492 M -( their username and password. Even in the cases of authentication) s -5 481 M -( where no user credentials are divulged, an attacker may still gain) s -5 470 M -( information they shouldn't have by capturing key-strokes in much the) s -5 459 M -( same way that a honeypot works.) s -5 437 M -(9.3.2 Debug messages) s -5 415 M -( Special care should be taken when designing debug messages. These) s -5 404 M -( messages may reveal surprising amounts of information about the host) s -5 393 M -( if not properly designed. Debug messages can be disabled \(during) s -5 382 M -( user authentication phase\) if high security is required.) s -5 371 M -( Administrators of host machines should make all attempts to) s -5 360 M -( compartmentalize all event notification messages and protect them) s -5 349 M -( from unwarranted observation. Developers should be aware of the) s -5 338 M -( sensitive nature of some of the normal event messages and debug) s -5 327 M -( messages and may want to provide guidance to administrators on ways) s -5 316 M -( to keep this information away from unauthorized people. Developers) s -5 305 M -( should consider minimizing the amount of sensitive information) s -5 294 M -( obtainable by users during the authentication phase in accordance) s -5 283 M -( with the local policies. For this reason, it is RECOMMENDED that) s -5 272 M -( debug messages be initially disabled at the time of deployment and) s -5 261 M -( require an active decision by an administrator to allow them to be) s -5 250 M -( enabled. It is also RECOMMENDED that a message expressing this) s -5 239 M -( concern be presented to the administrator of a system when the action) s -5 228 M -( is taken to enable debugging messages.) s -5 206 M -(9.3.3 Local security policy) s -5 184 M -( Implementer MUST ensure that the credentials provided validate the) s -5 173 M -( professed user and also MUST ensure that the local policy of the) s -5 129 M -(Ylonen & Moffat Expires March 31, 2004 [Page 21]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 22 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Protocol Architecture Oct 2003) s -5 690 M -( server permits the user the access requested. In particular, because) s -5 679 M -( of the flexible nature of the SSH connection protocol, it may not be) s -5 668 M -( possible to determine the local security policy, if any, that should) s -5 657 M -( apply at the time of authentication because the kind of service being) s -5 646 M -( requested is not clear at that instant. For example, local policy) s -5 635 M -( might allow a user to access files on the server, but not start an) s -5 624 M -( interactive shell. However, during the authentication protocol, it is) s -5 613 M -( not known whether the user will be accessing files or attempting to) s -5 602 M -( use an interactive shell, or even both. In any event, where local) s -5 591 M -( security policy for the server host exists, it MUST be applied and) s -5 580 M -( enforced correctly.) s -5 558 M -( Implementors are encouraged to provide a default local policy and) s -5 547 M -( make its parameters known to administrators and users. At the) s -5 536 M -( discretion of the implementors, this default policy may be along the) s -5 525 M -( lines of 'anything goes' where there are no restrictions placed upon) s -5 514 M -( users, or it may be along the lines of 'excessively restrictive' in) s -5 503 M -( which case the administrators will have to actively make changes to) s -5 492 M -( this policy to meet their needs. Alternatively, it may be some) s -5 481 M -( attempt at providing something practical and immediately useful to) s -5 470 M -( the administrators of the system so they don't have to put in much) s -5 459 M -( effort to get SSH working. Whatever choice is made MUST be applied) s -5 448 M -( and enforced as required above.) s -5 426 M -(9.3.4 Public key authentication) s -5 404 M -( The use of public-key authentication assumes that the client host has) s -5 393 M -( not been compromised. It also assumes that the private-key of the) s -5 382 M -( server host has not been compromised.) s -5 360 M -( This risk can be mitigated by the use of passphrases on private keys;) s -5 349 M -( however, this is not an enforceable policy. The use of smartcards,) s -5 338 M -( or other technology to make passphrases an enforceable policy is) s -5 327 M -( suggested.) s -5 305 M -( The server could require both password and public-key authentication,) s -5 294 M -( however, this requires the client to expose its password to the) s -5 283 M -( server \(see section on password authentication below.\)) s -5 261 M -(9.3.5 Password authentication) s -5 239 M -( The password mechanism as specified in the authentication protocol) s -5 228 M -( assumes that the server has not been compromised. If the server has) s -5 217 M -( been compromised, using password authentication will reveal a valid) s -5 206 M -( username / password combination to the attacker, which may lead to) s -5 195 M -( further compromises.) s -5 173 M -( This vulnerability can be mitigated by using an alternative form of) s -5 129 M -(Ylonen & Moffat Expires March 31, 2004 [Page 22]) s -_R -S -PStoPSsaved restore -%%Page: (22,23) 12 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 23 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Protocol Architecture Oct 2003) s -5 690 M -( authentication. For example, public-key authentication makes no) s -5 679 M -( assumptions about security on the server.) s -5 657 M -(9.3.6 Host based authentication) s -5 635 M -( Host based authentication assumes that the client has not been) s -5 624 M -( compromised. There are no mitigating strategies, other than to use) s -5 613 M -( host based authentication in combination with another authentication) s -5 602 M -( method.) s -5 580 M -(9.4 Connection protocol) s -5 558 M -(9.4.1 End point security) s -5 536 M -( End point security is assumed by the connection protocol. If the) s -5 525 M -( server has been compromised, any terminal sessions, port forwarding,) s -5 514 M -( or systems accessed on the host are compromised. There are no) s -5 503 M -( mitigating factors for this.) s -5 481 M -( If the client end point has been compromised, and the server fails to) s -5 470 M -( stop the attacker at the authentication protocol, all services) s -5 459 M -( exposed \(either as subsystems or through forwarding\) will be) s -5 448 M -( vulnerable to attack. Implementors SHOULD provide mechanisms for) s -5 437 M -( administrators to control which services are exposed to limit the) s -5 426 M -( vulnerability of other services.) s -5 404 M -( These controls might include controlling which machines and ports can) s -5 393 M -( be target in 'port-forwarding' operations, which users are allowed to) s -5 382 M -( use interactive shell facilities, or which users are allowed to use) s -5 371 M -( exposed subsystems.) s -5 349 M -(9.4.2 Proxy forwarding) s -5 327 M -( The SSH connection protocol allows for proxy forwarding of other) s -5 316 M -( protocols such as SNMP, POP3, and HTTP. This may be a concern for) s -5 305 M -( network administrators who wish to control the access of certain) s -5 294 M -( applications by users located outside of their physical location.) s -5 283 M -( Essentially, the forwarding of these protocols may violate site) s -5 272 M -( specific security policies as they may be undetectably tunneled) s -5 261 M -( through a firewall. Implementors SHOULD provide an administrative) s -5 250 M -( mechanism to control the proxy forwarding functionality so that site) s -5 239 M -( specific security policies may be upheld.) s -5 217 M -( In addition, a reverse proxy forwarding functionality is available,) s -5 206 M -( which again can be used to bypass firewall controls.) s -5 184 M -( As indicated above, end-point security is assumed during proxy) s -5 173 M -( forwarding operations. Failure of end-point security will compromise) s -5 129 M -(Ylonen & Moffat Expires March 31, 2004 [Page 23]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 24 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Protocol Architecture Oct 2003) s -5 690 M -( all data passed over proxy forwarding.) s -5 668 M -(9.4.3 X11 forwarding) s -5 646 M -( Another form of proxy forwarding provided by the ssh connection) s -5 635 M -( protocol is the forwarding of the X11 protocol. If end-point) s -5 624 M -( security has been compromised, X11 forwarding may allow attacks) s -5 613 M -( against the X11 server. Users and administrators should, as a matter) s -5 602 M -( of course, use appropriate X11 security mechanisms to prevent) s -5 591 M -( unauthorized use of the X11 server. Implementors, administrators and) s -5 580 M -( users who wish to further explore the security mechanisms of X11 are) s -5 569 M -( invited to read [SCHEIFLER] and analyze previously reported problems) s -5 558 M -( with the interactions between SSH forwarding and X11 in CERT) s -5 547 M -( vulnerabilities VU#363181 and VU#118892 [CERT].) s -5 525 M -( X11 display forwarding with SSH, by itself, is not sufficient to) s -5 514 M -( correct well known problems with X11 security [VENEMA]. However, X11) s -5 503 M -( display forwarding in SSHv2 \(or other, secure protocols\), combined) s -5 492 M -( with actual and pseudo-displays which accept connections only over) s -5 481 M -( local IPC mechanisms authorized by permissions or ACLs, does correct) s -5 470 M -( many X11 security problems as long as the "none" MAC is not used. It) s -5 459 M -( is RECOMMENDED that X11 display implementations default to allowing) s -5 448 M -( display opens only over local IPC. It is RECOMMENDED that SSHv2) s -5 437 M -( server implementations that support X11 forwarding default to) s -5 426 M -( allowing display opens only over local IPC. On single-user systems) s -5 415 M -( it might be reasonable to default to allowing local display opens) s -5 404 M -( over TCP/IP.) s -5 382 M -( Implementors of the X11 forwarding protocol SHOULD implement the) s -5 371 M -( magic cookie access checking spoofing mechanism as described in) s -5 360 M -( [ssh-connect] as an additional mechanism to prevent unauthorized use) s -5 349 M -( of the proxy.) s -5 327 M -(Normative References) s -5 305 M -( [SSH-ARCH]) s -5 294 M -( Ylonen, T., "SSH Protocol Architecture", I-D) s -5 283 M -( draft-ietf-architecture-15.txt, Oct 2003.) s -5 261 M -( [SSH-TRANS]) s -5 250 M -( Ylonen, T., "SSH Transport Layer Protocol", I-D) s -5 239 M -( draft-ietf-transport-17.txt, Oct 2003.) s -5 217 M -( [SSH-USERAUTH]) s -5 206 M -( Ylonen, T., "SSH Authentication Protocol", I-D) s -5 195 M -( draft-ietf-userauth-18.txt, Oct 2003.) s -5 173 M -( [SSH-CONNECT]) s -5 129 M -(Ylonen & Moffat Expires March 31, 2004 [Page 24]) s -_R -S -PStoPSsaved restore -%%Page: (24,25) 13 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 25 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Protocol Architecture Oct 2003) s -5 690 M -( Ylonen, T., "SSH Connection Protocol", I-D) s -5 679 M -( draft-ietf-connect-18.txt, Oct 2003.) s -5 657 M -( [SSH-NUMBERS]) s -5 646 M -( Lehtinen, S. and D. Moffat, "SSH Protocol Assigned) s -5 635 M -( Numbers", I-D draft-ietf-secsh-assignednumbers-05.txt, Oct) s -5 624 M -( 2003.) s -5 602 M -( [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate) s -5 591 M -( Requirement Levels", BCP 14, RFC 2119, March 1997.) s -5 569 M -(Informative References) s -5 547 M -( [FIPS-186]) s -5 536 M -( Federal Information Processing Standards Publication,) s -5 525 M -( "FIPS PUB 186, Digital Signature Standard", May 1994.) s -5 503 M -( [FIPS-197]) s -5 492 M -( National Institue of Standards and Technology, "FIPS 197,) s -5 481 M -( Specification for the Advanced Encryption Standard",) s -5 470 M -( November 2001.) s -5 448 M -( [ANSI T1.523-2001]) s -5 437 M -( American National Standards Insitute, Inc., "Telecom) s -5 426 M -( Glossary 2000", February 2001.) s -5 404 M -( [SCHEIFLER]) s -5 393 M -( Scheifler, R., "X Window System : The Complete Reference) s -5 382 M -( to Xlib, X Protocol, Icccm, Xlfd, 3rd edition.", Digital) s -5 371 M -( Press ISBN 1555580882, Feburary 1992.) s -5 349 M -( [RFC0854] Postel, J. and J. Reynolds, "Telnet Protocol) s -5 338 M -( Specification", STD 8, RFC 854, May 1983.) s -5 316 M -( [RFC0894] Hornig, C., "Standard for the transmission of IP datagrams) s -5 305 M -( over Ethernet networks", STD 41, RFC 894, April 1984.) s -5 283 M -( [RFC1034] Mockapetris, P., "Domain names - concepts and facilities",) s -5 272 M -( STD 13, RFC 1034, November 1987.) s -5 250 M -( [RFC1134] Perkins, D., "Point-to-Point Protocol: A proposal for) s -5 239 M -( multi-protocol transmission of datagrams over) s -5 228 M -( Point-to-Point links", RFC 1134, November 1989.) s -5 206 M -( [RFC1282] Kantor, B., "BSD Rlogin", RFC 1282, December 1991.) s -5 184 M -( [RFC1510] Kohl, J. and B. Neuman, "The Kerberos Network) s -5 173 M -( Authentication Service \(V5\)", RFC 1510, September 1993.) s -5 129 M -(Ylonen & Moffat Expires March 31, 2004 [Page 25]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 26 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Protocol Architecture Oct 2003) s -5 690 M -( [RFC1700] Reynolds, J. and J. Postel, "Assigned Numbers", RFC 1700,) s -5 679 M -( October 1994.) s -5 657 M -( [RFC1750] Eastlake, D., Crocker, S. and J. Schiller, "Randomness) s -5 646 M -( Recommendations for Security", RFC 1750, December 1994.) s -5 624 M -( [RFC3066] Alvestrand, H., "Tags for the Identification of) s -5 613 M -( Languages", BCP 47, RFC 3066, January 2001.) s -5 591 M -( [RFC1964] Linn, J., "The Kerberos Version 5 GSS-API Mechanism", RFC) s -5 580 M -( 1964, June 1996.) s -5 558 M -( [RFC2025] Adams, C., "The Simple Public-Key GSS-API Mechanism) s -5 547 M -( \(SPKM\)", RFC 2025, October 1996.) s -5 525 M -( [RFC2085] Oehler, M. and R. Glenn, "HMAC-MD5 IP Authentication with) s -5 514 M -( Replay Prevention", RFC 2085, February 1997.) s -5 492 M -( [RFC2104] Krawczyk, H., Bellare, M. and R. Canetti, "HMAC:) s -5 481 M -( Keyed-Hashing for Message Authentication", RFC 2104,) s -5 470 M -( February 1997.) s -5 448 M -( [RFC2246] Dierks, T., Allen, C., Treese, W., Karlton, P., Freier, A.) s -5 437 M -( and P. Kocher, "The TLS Protocol Version 1.0", RFC 2246,) s -5 426 M -( January 1999.) s -5 404 M -( [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO) s -5 393 M -( 10646", RFC 2279, January 1998.) s -5 371 M -( [RFC2410] Glenn, R. and S. Kent, "The NULL Encryption Algorithm and) s -5 360 M -( Its Use With IPsec", RFC 2410, November 1998.) s -5 338 M -( [RFC2434] Narten, T. and H. Alvestrand, "Guidelines for Writing an) s -5 327 M -( IANA Considerations Section in RFCs", BCP 26, RFC 2434,) s -5 316 M -( October 1998.) s -5 294 M -( [RFC2743] Linn, J., "Generic Security Service Application Program) s -5 283 M -( Interface Version 2, Update 1", RFC 2743, January 2000.) s -5 261 M -( [SCHNEIER]) s -5 250 M -( Schneier, B., "Applied Cryptography Second Edition:) s -5 239 M -( protocols algorithms and source in code in C", 1996.) s -5 217 M -( [KAUFMAN,PERLMAN,SPECINER]) s -5 206 M -( Kaufman, C., Perlman, R. and M. Speciner, "Network) s -5 195 M -( Security: PRIVATE Communication in a PUBLIC World", 1995.) s -5 173 M -( [CERT] CERT Coordination Center, The., "http://www.cert.org/nav/) s -5 129 M -(Ylonen & Moffat Expires March 31, 2004 [Page 26]) s -_R -S -PStoPSsaved restore -%%Page: (26,27) 14 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 27 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Protocol Architecture Oct 2003) s -5 690 M -( index_red.html".) s -5 668 M -( [VENEMA] Venema, W., "Murphy's Law and Computer Security",) s -5 657 M -( Proceedings of 6th USENIX Security Symposium, San Jose CA) s -5 646 M -( http://www.usenix.org/publications/library/proceedings/) s -5 635 M -( sec96/venema.html, July 1996.) s -5 613 M -( [ROGAWAY] Rogaway, P., "Problems with Proposed IP Cryptography",) s -5 602 M -( Unpublished paper http://www.cs.ucdavis.edu/~rogaway/) s -5 591 M -( papers/draft-rogaway-ipsec-comments-00.txt, 1996.) s -5 569 M -( [DAI] Dai, W., "An attack against SSH2 protocol", Email to the) s -5 558 M -( SECSH Working Group [email protected] ftp://) s -5 547 M -( ftp.ietf.org/ietf-mail-archive/secsh/2002-02.mail, Feb) s -5 536 M -( 2002.) s -5 514 M -( [BELLARE,KOHNO,NAMPREMPRE]) s -5 503 M -( Bellaire, M., Kohno, T. and C. Namprempre, "Authenticated) s -5 492 M -( Encryption in SSH: Fixing the SSH Binary Packet Protocol",) s -5 481 M -( , Sept 2002.) s -5 448 M -(Authors' Addresses) s -5 426 M -( Tatu Ylonen) s -5 415 M -( SSH Communications Security Corp) s -5 404 M -( Fredrikinkatu 42) s -5 393 M -( HELSINKI FIN-00100) s -5 382 M -( Finland) s -5 360 M -( EMail: [email protected]) s -5 327 M -( Darren J. Moffat \(editor\)) s -5 316 M -( Sun Microsystems, Inc) s -5 305 M -( 17 Network Circle) s -5 294 M -( Menlo Park CA 94025) s -5 283 M -( USA) s -5 261 M -( EMail: [email protected]) s -5 129 M -(Ylonen & Moffat Expires March 31, 2004 [Page 27]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 28 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Protocol Architecture Oct 2003) s -5 690 M -(Intellectual Property Statement) s -5 668 M -( The IETF takes no position regarding the validity or scope of any) s -5 657 M -( intellectual property or other rights that might be claimed to) s -5 646 M -( pertain to the implementation or use of the technology described in) s -5 635 M -( this document or the extent to which any license under such rights) s -5 624 M -( might or might not be available; neither does it represent that it) s -5 613 M -( has made any effort to identify any such rights. Information on the) s -5 602 M -( IETF's procedures with respect to rights in standards-track and) s -5 591 M -( standards-related documentation can be found in BCP-11. Copies of) s -5 580 M -( claims of rights made available for publication and any assurances of) s -5 569 M -( licenses to be made available, or the result of an attempt made to) s -5 558 M -( obtain a general license or permission for the use of such) s -5 547 M -( proprietary rights by implementors or users of this specification can) s -5 536 M -( be obtained from the IETF Secretariat.) s -5 514 M -( The IETF invites any interested party to bring to its attention any) s -5 503 M -( copyrights, patents or patent applications, or other proprietary) s -5 492 M -( rights which may cover technology that may be required to practice) s -5 481 M -( this standard. Please address the information to the IETF Executive) s -5 470 M -( Director.) s -5 448 M -( The IETF has been notified of intellectual property rights claimed in) s -5 437 M -( regard to some or all of the specification contained in this) s -5 426 M -( document. For more information consult the online list of claimed) s -5 415 M -( rights.) s -5 382 M -(Full Copyright Statement) s -5 360 M -( Copyright \(C\) The Internet Society \(2003\). All Rights Reserved.) s -5 338 M -( This document and translations of it may be copied and furnished to) s -5 327 M -( others, and derivative works that comment on or otherwise explain it) s -5 316 M -( or assist in its implementation may be prepared, copied, published) s -5 305 M -( and distributed, in whole or in part, without restriction of any) s -5 294 M -( kind, provided that the above copyright notice and this paragraph are) s -5 283 M -( included on all such copies and derivative works. However, this) s -5 272 M -( document itself may not be modified in any way, such as by removing) s -5 261 M -( the copyright notice or references to the Internet Society or other) s -5 250 M -( Internet organizations, except as needed for the purpose of) s -5 239 M -( developing Internet standards in which case the procedures for) s -5 228 M -( copyrights defined in the Internet Standards process must be) s -5 217 M -( followed, or as required to translate it into languages other than) s -5 206 M -( English.) s -5 184 M -( The limited permissions granted above are perpetual and will not be) s -5 173 M -( revoked by the Internet Society or its successors or assignees.) s -5 129 M -(Ylonen & Moffat Expires March 31, 2004 [Page 28]) s -_R -S -PStoPSsaved restore -%%Page: (28,29) 15 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 29 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Protocol Architecture Oct 2003) s -5 690 M -( This document and the information contained herein is provided on an) s -5 679 M -( "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING) s -5 668 M -( TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING) s -5 657 M -( BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION) s -5 646 M -( HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF) s -5 635 M -( MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.) s -5 602 M -(Acknowledgment) s -5 580 M -( Funding for the RFC Editor function is currently provided by the) s -5 569 M -( Internet Society.) s -5 129 M -(Ylonen & Moffat Expires March 31, 2004 [Page 29]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -showpage -PStoPSsaved restore -%%Trailer -%%Pages: 29 -%%DocumentNeededResources: font Courier-Bold Courier -%%EOF diff --git a/lib/ssh/doc/standard/draft-ietf-secsh-architecture-15.txt b/lib/ssh/doc/standard/draft-ietf-secsh-architecture-15.txt deleted file mode 100644 index 18070e8485..0000000000 --- a/lib/ssh/doc/standard/draft-ietf-secsh-architecture-15.txt +++ /dev/null @@ -1,1624 +0,0 @@ - - - -Network Working Group T. Ylonen -Internet-Draft SSH Communications Security Corp -Expires: March 31, 2004 D. Moffat, Ed. - Sun Microsystems, Inc - Oct 2003 - - - SSH Protocol Architecture - draft-ietf-secsh-architecture-15.txt - -Status of this Memo - - This document is an Internet-Draft and is in full conformance with - all provisions of Section 10 of RFC2026. - - Internet-Drafts are working documents of the Internet Engineering - Task Force (IETF), its areas, and its working groups. Note that other - groups may also distribute working documents as Internet-Drafts. - - Internet-Drafts are draft documents valid for a maximum of six months - and may be updated, replaced, or obsoleted by other documents at any - time. It is inappropriate to use Internet-Drafts as reference - material or to cite them other than as "work in progress." - - The list of current Internet-Drafts can be accessed at http:// - www.ietf.org/ietf/1id-abstracts.txt. - - The list of Internet-Draft Shadow Directories can be accessed at - http://www.ietf.org/shadow.html. - - This Internet-Draft will expire on March 31, 2004. - -Copyright Notice - - Copyright (C) The Internet Society (2003). All Rights Reserved. - -Abstract - - SSH is a protocol for secure remote login and other secure network - services over an insecure network. This document describes the - architecture of the SSH protocol, as well as the notation and - terminology used in SSH protocol documents. It also discusses the SSH - algorithm naming system that allows local extensions. The SSH - protocol consists of three major components: The Transport Layer - Protocol provides server authentication, confidentiality, and - integrity with perfect forward secrecy. The User Authentication - Protocol authenticates the client to the server. The Connection - Protocol multiplexes the encrypted tunnel into several logical - channels. Details of these protocols are described in separate - - - -Ylonen & Moffat Expires March 31, 2004 [Page 1] - -Internet-Draft SSH Protocol Architecture Oct 2003 - - - documents. - -Table of Contents - - 1. Contributors . . . . . . . . . . . . . . . . . . . . . . . . 3 - 2. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 - 3. Specification of Requirements . . . . . . . . . . . . . . . 3 - 4. Architecture . . . . . . . . . . . . . . . . . . . . . . . . 3 - 4.1 Host Keys . . . . . . . . . . . . . . . . . . . . . . . . . 4 - 4.2 Extensibility . . . . . . . . . . . . . . . . . . . . . . . 5 - 4.3 Policy Issues . . . . . . . . . . . . . . . . . . . . . . . 5 - 4.4 Security Properties . . . . . . . . . . . . . . . . . . . . 6 - 4.5 Packet Size and Overhead . . . . . . . . . . . . . . . . . . 6 - 4.6 Localization and Character Set Support . . . . . . . . . . . 7 - 5. Data Type Representations Used in the SSH Protocols . . . . 8 - 6. Algorithm Naming . . . . . . . . . . . . . . . . . . . . . . 10 - 7. Message Numbers . . . . . . . . . . . . . . . . . . . . . . 11 - 8. IANA Considerations . . . . . . . . . . . . . . . . . . . . 11 - 9. Security Considerations . . . . . . . . . . . . . . . . . . 12 - 9.1 Pseudo-Random Number Generation . . . . . . . . . . . . . . 12 - 9.2 Transport . . . . . . . . . . . . . . . . . . . . . . . . . 13 - 9.2.1 Confidentiality . . . . . . . . . . . . . . . . . . . . . . 13 - 9.2.2 Data Integrity . . . . . . . . . . . . . . . . . . . . . . . 16 - 9.2.3 Replay . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 - 9.2.4 Man-in-the-middle . . . . . . . . . . . . . . . . . . . . . 17 - 9.2.5 Denial-of-service . . . . . . . . . . . . . . . . . . . . . 19 - 9.2.6 Covert Channels . . . . . . . . . . . . . . . . . . . . . . 19 - 9.2.7 Forward Secrecy . . . . . . . . . . . . . . . . . . . . . . 20 - 9.3 Authentication Protocol . . . . . . . . . . . . . . . . . . 20 - 9.3.1 Weak Transport . . . . . . . . . . . . . . . . . . . . . . . 21 - 9.3.2 Debug messages . . . . . . . . . . . . . . . . . . . . . . . 21 - 9.3.3 Local security policy . . . . . . . . . . . . . . . . . . . 21 - 9.3.4 Public key authentication . . . . . . . . . . . . . . . . . 22 - 9.3.5 Password authentication . . . . . . . . . . . . . . . . . . 22 - 9.3.6 Host based authentication . . . . . . . . . . . . . . . . . 23 - 9.4 Connection protocol . . . . . . . . . . . . . . . . . . . . 23 - 9.4.1 End point security . . . . . . . . . . . . . . . . . . . . . 23 - 9.4.2 Proxy forwarding . . . . . . . . . . . . . . . . . . . . . . 23 - 9.4.3 X11 forwarding . . . . . . . . . . . . . . . . . . . . . . . 24 - Normative References . . . . . . . . . . . . . . . . . . . . 24 - Informative References . . . . . . . . . . . . . . . . . . . 25 - Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 27 - Intellectual Property and Copyright Statements . . . . . . . 28 - - - - - - - - -Ylonen & Moffat Expires March 31, 2004 [Page 2] - -Internet-Draft SSH Protocol Architecture Oct 2003 - - -1. Contributors - - The major original contributors of this document were: Tatu Ylonen, - Tero Kivinen, Timo J. Rinne, Sami Lehtinen (all of SSH Communications - Security Corp), and Markku-Juhani O. Saarinen (University of - Jyvaskyla) - - The document editor is: [email protected]. Comments on this - internet draft should be sent to the IETF SECSH working group, - details at: http://ietf.org/html.charters/secsh-charter.html - -2. Introduction - - SSH is a protocol for secure remote login and other secure network - services over an insecure network. It consists of three major - components: - o The Transport Layer Protocol [SSH-TRANS] provides server - authentication, confidentiality, and integrity. It may optionally - also provide compression. The transport layer will typically be - run over a TCP/IP connection, but might also be used on top of any - other reliable data stream. - o The User Authentication Protocol [SSH-USERAUTH] authenticates the - client-side user to the server. It runs over the transport layer - protocol. - o The Connection Protocol [SSH-CONNECT] multiplexes the encrypted - tunnel into several logical channels. It runs over the user - authentication protocol. - - The client sends a service request once a secure transport layer - connection has been established. A second service request is sent - after user authentication is complete. This allows new protocols to - be defined and coexist with the protocols listed above. - - The connection protocol provides channels that can be used for a wide - range of purposes. Standard methods are provided for setting up - secure interactive shell sessions and for forwarding ("tunneling") - arbitrary TCP/IP ports and X11 connections. - -3. Specification of Requirements - - All documents related to the SSH protocols shall use the keywords - "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", - "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" to describe - requirements. They are to be interpreted as described in [RFC2119]. - -4. Architecture - - - - - -Ylonen & Moffat Expires March 31, 2004 [Page 3] - -Internet-Draft SSH Protocol Architecture Oct 2003 - - -4.1 Host Keys - - Each server host SHOULD have a host key. Hosts MAY have multiple - host keys using multiple different algorithms. Multiple hosts MAY - share the same host key. If a host has keys at all, it MUST have at - least one key using each REQUIRED public key algorithm (DSS - [FIPS-186]). - - The server host key is used during key exchange to verify that the - client is really talking to the correct server. For this to be - possible, the client must have a priori knowledge of the server's - public host key. - - Two different trust models can be used: - o The client has a local database that associates each host name (as - typed by the user) with the corresponding public host key. This - method requires no centrally administered infrastructure, and no - third-party coordination. The downside is that the database of - name-to-key associations may become burdensome to maintain. - o The host name-to-key association is certified by some trusted - certification authority. The client only knows the CA root key, - and can verify the validity of all host keys certified by accepted - CAs. - - The second alternative eases the maintenance problem, since - ideally only a single CA key needs to be securely stored on the - client. On the other hand, each host key must be appropriately - certified by a central authority before authorization is possible. - Also, a lot of trust is placed on the central infrastructure. - - The protocol provides the option that the server name - host key - association is not checked when connecting to the host for the first - time. This allows communication without prior communication of host - keys or certification. The connection still provides protection - against passive listening; however, it becomes vulnerable to active - man-in-the-middle attacks. Implementations SHOULD NOT normally allow - such connections by default, as they pose a potential security - problem. However, as there is no widely deployed key infrastructure - available on the Internet yet, this option makes the protocol much - more usable during the transition time until such an infrastructure - emerges, while still providing a much higher level of security than - that offered by older solutions (e.g. telnet [RFC-854] and rlogin - [RFC-1282]). - - Implementations SHOULD try to make the best effort to check host - keys. An example of a possible strategy is to only accept a host key - without checking the first time a host is connected, save the key in - a local database, and compare against that key on all future - - - -Ylonen & Moffat Expires March 31, 2004 [Page 4] - -Internet-Draft SSH Protocol Architecture Oct 2003 - - - connections to that host. - - Implementations MAY provide additional methods for verifying the - correctness of host keys, e.g. a hexadecimal fingerprint derived from - the SHA-1 hash of the public key. Such fingerprints can easily be - verified by using telephone or other external communication channels. - - All implementations SHOULD provide an option to not accept host keys - that cannot be verified. - - We believe that ease of use is critical to end-user acceptance of - security solutions, and no improvement in security is gained if the - new solutions are not used. Thus, providing the option not to check - the server host key is believed to improve the overall security of - the Internet, even though it reduces the security of the protocol in - configurations where it is allowed. - -4.2 Extensibility - - We believe that the protocol will evolve over time, and some - organizations will want to use their own encryption, authentication - and/or key exchange methods. Central registration of all extensions - is cumbersome, especially for experimental or classified features. - On the other hand, having no central registration leads to conflicts - in method identifiers, making interoperability difficult. - - We have chosen to identify algorithms, methods, formats, and - extension protocols with textual names that are of a specific format. - DNS names are used to create local namespaces where experimental or - classified extensions can be defined without fear of conflicts with - other implementations. - - One design goal has been to keep the base protocol as simple as - possible, and to require as few algorithms as possible. However, all - implementations MUST support a minimal set of algorithms to ensure - interoperability (this does not imply that the local policy on all - hosts would necessary allow these algorithms). The mandatory - algorithms are specified in the relevant protocol documents. - - Additional algorithms, methods, formats, and extension protocols can - be defined in separate drafts. See Section Algorithm Naming (Section - 6) for more information. - -4.3 Policy Issues - - The protocol allows full negotiation of encryption, integrity, key - exchange, compression, and public key algorithms and formats. - Encryption, integrity, public key, and compression algorithms can be - - - -Ylonen & Moffat Expires March 31, 2004 [Page 5] - -Internet-Draft SSH Protocol Architecture Oct 2003 - - - different for each direction. - - The following policy issues SHOULD be addressed in the configuration - mechanisms of each implementation: - o Encryption, integrity, and compression algorithms, separately for - each direction. The policy MUST specify which is the preferred - algorithm (e.g. the first algorithm listed in each category). - o Public key algorithms and key exchange method to be used for host - authentication. The existence of trusted host keys for different - public key algorithms also affects this choice. - o The authentication methods that are to be required by the server - for each user. The server's policy MAY require multiple - authentication for some or all users. The required algorithms MAY - depend on the location where the user is trying to log in from. - o The operations that the user is allowed to perform using the - connection protocol. Some issues are related to security; for - example, the policy SHOULD NOT allow the server to start sessions - or run commands on the client machine, and MUST NOT allow - connections to the authentication agent unless forwarding such - connections has been requested. Other issues, such as which TCP/ - IP ports can be forwarded and by whom, are clearly issues of local - policy. Many of these issues may involve traversing or bypassing - firewalls, and are interrelated with the local security policy. - -4.4 Security Properties - - The primary goal of the SSH protocol is improved security on the - Internet. It attempts to do this in a way that is easy to deploy, - even at the cost of absolute security. - o All encryption, integrity, and public key algorithms used are - well-known, well-established algorithms. - o All algorithms are used with cryptographically sound key sizes - that are believed to provide protection against even the strongest - cryptanalytic attacks for decades. - o All algorithms are negotiated, and in case some algorithm is - broken, it is easy to switch to some other algorithm without - modifying the base protocol. - - Specific concessions were made to make wide-spread fast deployment - easier. The particular case where this comes up is verifying that - the server host key really belongs to the desired host; the protocol - allows the verification to be left out (but this is NOT RECOMMENDED). - This is believed to significantly improve usability in the short - term, until widespread Internet public key infrastructures emerge. - -4.5 Packet Size and Overhead - - Some readers will worry about the increase in packet size due to new - - - -Ylonen & Moffat Expires March 31, 2004 [Page 6] - -Internet-Draft SSH Protocol Architecture Oct 2003 - - - headers, padding, and MAC. The minimum packet size is in the order - of 28 bytes (depending on negotiated algorithms). The increase is - negligible for large packets, but very significant for one-byte - packets (telnet-type sessions). There are, however, several factors - that make this a non-issue in almost all cases: - o The minimum size of a TCP/IP header is 32 bytes. Thus, the - increase is actually from 33 to 51 bytes (roughly). - o The minimum size of the data field of an Ethernet packet is 46 - bytes [RFC-894]. Thus, the increase is no more than 5 bytes. When - Ethernet headers are considered, the increase is less than 10 - percent. - o The total fraction of telnet-type data in the Internet is - negligible, even with increased packet sizes. - - The only environment where the packet size increase is likely to have - a significant effect is PPP [RFC-1134] over slow modem lines (PPP - compresses the TCP/IP headers, emphasizing the increase in packet - size). However, with modern modems, the time needed to transfer is in - the order of 2 milliseconds, which is a lot faster than people can - type. - - There are also issues related to the maximum packet size. To - minimize delays in screen updates, one does not want excessively - large packets for interactive sessions. The maximum packet size is - negotiated separately for each channel. - -4.6 Localization and Character Set Support - - For the most part, the SSH protocols do not directly pass text that - would be displayed to the user. However, there are some places where - such data might be passed. When applicable, the character set for the - data MUST be explicitly specified. In most places, ISO 10646 with - UTF-8 encoding is used [RFC-2279]. When applicable, a field is also - provided for a language tag [RFC-3066]. - - One big issue is the character set of the interactive session. There - is no clear solution, as different applications may display data in - different formats. Different types of terminal emulation may also be - employed in the client, and the character set to be used is - effectively determined by the terminal emulation. Thus, no place is - provided for directly specifying the character set or encoding for - terminal session data. However, the terminal emulation type (e.g. - "vt100") is transmitted to the remote site, and it implicitly - specifies the character set and encoding. Applications typically use - the terminal type to determine what character set they use, or the - character set is determined using some external means. The terminal - emulation may also allow configuring the default character set. In - any case, the character set for the terminal session is considered - - - -Ylonen & Moffat Expires March 31, 2004 [Page 7] - -Internet-Draft SSH Protocol Architecture Oct 2003 - - - primarily a client local issue. - - Internal names used to identify algorithms or protocols are normally - never displayed to users, and must be in US-ASCII. - - The client and server user names are inherently constrained by what - the server is prepared to accept. They might, however, occasionally - be displayed in logs, reports, etc. They MUST be encoded using ISO - 10646 UTF-8, but other encodings may be required in some cases. It - is up to the server to decide how to map user names to accepted user - names. Straight bit-wise binary comparison is RECOMMENDED. - - For localization purposes, the protocol attempts to minimize the - number of textual messages transmitted. When present, such messages - typically relate to errors, debugging information, or some externally - configured data. For data that is normally displayed, it SHOULD be - possible to fetch a localized message instead of the transmitted - message by using a numerical code. The remaining messages SHOULD be - configurable. - -5. Data Type Representations Used in the SSH Protocols - byte - - A byte represents an arbitrary 8-bit value (octet) [RFC-1700]. - Fixed length data is sometimes represented as an array of bytes, - written byte[n], where n is the number of bytes in the array. - - boolean - - A boolean value is stored as a single byte. The value 0 - represents FALSE, and the value 1 represents TRUE. All non-zero - values MUST be interpreted as TRUE; however, applications MUST NOT - store values other than 0 and 1. - - uint32 - - Represents a 32-bit unsigned integer. Stored as four bytes in the - order of decreasing significance (network byte order). For - example, the value 699921578 (0x29b7f4aa) is stored as 29 b7 f4 - aa. - - uint64 - - Represents a 64-bit unsigned integer. Stored as eight bytes in - the order of decreasing significance (network byte order). - - - - - - -Ylonen & Moffat Expires March 31, 2004 [Page 8] - -Internet-Draft SSH Protocol Architecture Oct 2003 - - - string - - Arbitrary length binary string. Strings are allowed to contain - arbitrary binary data, including null characters and 8-bit - characters. They are stored as a uint32 containing its length - (number of bytes that follow) and zero (= empty string) or more - bytes that are the value of the string. Terminating null - characters are not used. - - Strings are also used to store text. In that case, US-ASCII is - used for internal names, and ISO-10646 UTF-8 for text that might - be displayed to the user. The terminating null character SHOULD - NOT normally be stored in the string. - - For example, the US-ASCII string "testing" is represented as 00 00 - 00 07 t e s t i n g. The UTF8 mapping does not alter the encoding - of US-ASCII characters. - - mpint - - Represents multiple precision integers in two's complement format, - stored as a string, 8 bits per byte, MSB first. Negative numbers - have the value 1 as the most significant bit of the first byte of - the data partition. If the most significant bit would be set for a - positive number, the number MUST be preceded by a zero byte. - Unnecessary leading bytes with the value 0 or 255 MUST NOT be - included. The value zero MUST be stored as a string with zero - bytes of data. - - By convention, a number that is used in modular computations in - Z_n SHOULD be represented in the range 0 <= x < n. - - Examples: - value (hex) representation (hex) - --------------------------------------------------------------- - 0 00 00 00 00 - 9a378f9b2e332a7 00 00 00 08 09 a3 78 f9 b2 e3 32 a7 - 80 00 00 00 02 00 80 - -1234 00 00 00 02 ed cc - -deadbeef 00 00 00 05 ff 21 52 41 11 - - - - name-list - - A string containing a comma separated list of names. A name list - is represented as a uint32 containing its length (number of bytes - that follow) followed by a comma-separated list of zero or more - - - -Ylonen & Moffat Expires March 31, 2004 [Page 9] - -Internet-Draft SSH Protocol Architecture Oct 2003 - - - names. A name MUST be non-zero length, and it MUST NOT contain a - comma (','). Context may impose additional restrictions on the - names; for example, the names in a list may have to be valid - algorithm identifier (see Algorithm Naming below), or [RFC-3066] - language tags. The order of the names in a list may or may not be - significant, also depending on the context where the list is is - used. Terminating NUL characters are not used, neither for the - individual names, nor for the list as a whole. - - Examples: - value representation (hex) - --------------------------------------- - (), the empty list 00 00 00 00 - ("zlib") 00 00 00 04 7a 6c 69 62 - ("zlib", "none") 00 00 00 09 7a 6c 69 62 2c 6e 6f 6e 65 - - - - -6. Algorithm Naming - - The SSH protocols refer to particular hash, encryption, integrity, - compression, and key exchange algorithms or protocols by names. - There are some standard algorithms that all implementations MUST - support. There are also algorithms that are defined in the protocol - specification but are OPTIONAL. Furthermore, it is expected that - some organizations will want to use their own algorithms. - - In this protocol, all algorithm identifiers MUST be printable - US-ASCII non-empty strings no longer than 64 characters. Names MUST - be case-sensitive. - - There are two formats for algorithm names: - o Names that do not contain an at-sign (@) are reserved to be - assigned by IETF consensus (RFCs). Examples include `3des-cbc', - `sha-1', `hmac-sha1', and `zlib' (the quotes are not part of the - name). Names of this format MUST NOT be used without first - registering them. Registered names MUST NOT contain an at-sign - (@) or a comma (,). - o Anyone can define additional algorithms by using names in the - format name@domainname, e.g. "[email protected]". The - format of the part preceding the at sign is not specified; it MUST - consist of US-ASCII characters except at-sign and comma. The part - following the at-sign MUST be a valid fully qualified internet - domain name [RFC-1034] controlled by the person or organization - defining the name. It is up to each domain how it manages its - local namespace. - - - - -Ylonen & Moffat Expires March 31, 2004 [Page 10] - -Internet-Draft SSH Protocol Architecture Oct 2003 - - -7. Message Numbers - - SSH packets have message numbers in the range 1 to 255. These numbers - have been allocated as follows: - - - Transport layer protocol: - - 1 to 19 Transport layer generic (e.g. disconnect, ignore, debug, - etc.) - 20 to 29 Algorithm negotiation - 30 to 49 Key exchange method specific (numbers can be reused for - different authentication methods) - - User authentication protocol: - - 50 to 59 User authentication generic - 60 to 79 User authentication method specific (numbers can be - reused for different authentication methods) - - Connection protocol: - - 80 to 89 Connection protocol generic - 90 to 127 Channel related messages - - Reserved for client protocols: - - 128 to 191 Reserved - - Local extensions: - - 192 to 255 Local extensions - - - -8. IANA Considerations - - The initial state of the IANA registry is detailed in [SSH-NUMBERS]. - - Allocation of the following types of names in the SSH protocols is - assigned by IETF consensus: - o SSH encryption algorithm names, - o SSH MAC algorithm names, - o SSH public key algorithm names (public key algorithm also implies - encoding and signature/encryption capability), - o SSH key exchange method names, and - o SSH protocol (service) names. - - - - -Ylonen & Moffat Expires March 31, 2004 [Page 11] - -Internet-Draft SSH Protocol Architecture Oct 2003 - - - These names MUST be printable US-ASCII strings, and MUST NOT contain - the characters at-sign ('@'), comma (','), or whitespace or control - characters (ASCII codes 32 or less). Names are case-sensitive, and - MUST NOT be longer than 64 characters. - - Names with the at-sign ('@') in them are allocated by the owner of - DNS name after the at-sign (hierarchical allocation in [RFC-2343]), - otherwise the same restrictions as above. - - Each category of names listed above has a separate namespace. - However, using the same name in multiple categories SHOULD be avoided - to minimize confusion. - - Message numbers (see Section Message Numbers (Section 7)) in the - range of 0..191 are allocated via IETF consensus; message numbers in - the 192..255 range (the "Local extensions" set) are reserved for - private use. - -9. Security Considerations - - In order to make the entire body of Security Considerations more - accessible, Security Considerations for the transport, - authentication, and connection documents have been gathered here. - - The transport protocol [1] provides a confidential channel over an - insecure network. It performs server host authentication, key - exchange, encryption, and integrity protection. It also derives a - unique session id that may be used by higher-level protocols. - - The authentication protocol [2] provides a suite of mechanisms which - can be used to authenticate the client user to the server. - Individual mechanisms specified in the in authentication protocol use - the session id provided by the transport protocol and/or depend on - the security and integrity guarantees of the transport protocol. - - The connection protocol [3] specifies a mechanism to multiplex - multiple streams [channels] of data over the confidential and - authenticated transport. It also specifies channels for accessing an - interactive shell, for 'proxy-forwarding' various external protocols - over the secure transport (including arbitrary TCP/IP protocols), and - for accessing secure 'subsystems' on the server host. - -9.1 Pseudo-Random Number Generation - - This protocol binds each session key to the session by including - random, session specific data in the hash used to produce session - keys. Special care should be taken to ensure that all of the random - numbers are of good quality. If the random data here (e.g., DH - - - -Ylonen & Moffat Expires March 31, 2004 [Page 12] - -Internet-Draft SSH Protocol Architecture Oct 2003 - - - parameters) are pseudo-random then the pseudo-random number generator - should be cryptographically secure (i.e., its next output not easily - guessed even when knowing all previous outputs) and, furthermore, - proper entropy needs to be added to the pseudo-random number - generator. RFC 1750 [1750] offers suggestions for sources of random - numbers and entropy. Implementors should note the importance of - entropy and the well-meant, anecdotal warning about the difficulty in - properly implementing pseudo-random number generating functions. - - The amount of entropy available to a given client or server may - sometimes be less than what is required. In this case one must - either resort to pseudo-random number generation regardless of - insufficient entropy or refuse to run the protocol. The latter is - preferable. - -9.2 Transport - -9.2.1 Confidentiality - - It is beyond the scope of this document and the Secure Shell Working - Group to analyze or recommend specific ciphers other than the ones - which have been established and accepted within the industry. At the - time of this writing, ciphers commonly in use include 3DES, ARCFOUR, - twofish, serpent and blowfish. AES has been accepted by The - published as a US Federal Information Processing Standards [FIPS-197] - and the cryptographic community as being acceptable for this purpose - as well has accepted AES. As always, implementors and users should - check current literature to ensure that no recent vulnerabilities - have been found in ciphers used within products. Implementors should - also check to see which ciphers are considered to be relatively - stronger than others and should recommend their use to users over - relatively weaker ciphers. It would be considered good form for an - implementation to politely and unobtrusively notify a user that a - stronger cipher is available and should be used when a weaker one is - actively chosen. - - The "none" cipher is provided for debugging and SHOULD NOT be used - except for that purpose. It's cryptographic properties are - sufficiently described in RFC 2410, which will show that its use does - not meet the intent of this protocol. - - The relative merits of these and other ciphers may also be found in - current literature. Two references that may provide information on - the subject are [SCHNEIER] and [KAUFMAN,PERLMAN,SPECINER]. Both of - these describe the CBC mode of operation of certain ciphers and the - weakness of this scheme. Essentially, this mode is theoretically - vulnerable to chosen cipher-text attacks because of the high - predictability of the start of packet sequence. However, this attack - - - -Ylonen & Moffat Expires March 31, 2004 [Page 13] - -Internet-Draft SSH Protocol Architecture Oct 2003 - - - is still deemed difficult and not considered fully practicable - especially if relatively longer block sizes are used. - - Additionally, another CBC mode attack may be mitigated through the - insertion of packets containing SSH_MSG_IGNORE. Without this - technique, a specific attack may be successful. For this attack - (commonly known as the Rogaway attack - [ROGAWAY],[DAI],[BELLARE,KOHNO,NAMPREMPRE]) to work, the attacker - would need to know the IV of the next block that is going to be - encrypted. In CBC mode that is the output of the encryption of the - previous block. If the attacker does not have any way to see the - packet yet (i.e it is in the internal buffers of the ssh - implementation or even in the kernel) then this attack will not work. - If the last packet has been sent out to the network (i.e the attacker - has access to it) then he can use the attack. - - In the optimal case an implementor would need to add an extra packet - only if the packet has been sent out onto the network and there are - no other packets waiting for transmission. Implementors may wish to - check to see if there are any unsent packets awaiting transmission, - but unfortunately it is not normally easy to obtain this information - from the kernel or buffers. If there are not, then a packet - containing SSH_MSG_IGNORE SHOULD be sent. If a new packet is added - to the stream every time the attacker knows the IV that is supposed - to be used for the next packet, then the attacker will not be able to - guess the correct IV, thus the attack will never be successfull. - - As an example, consider the following case: - - - Client Server - ------ ------ - TCP(seq=x, len=500) -> - contains Record 1 - - [500 ms passes, no ACK] - - TCP(seq=x, len=1000) -> - contains Records 1,2 - - ACK - - - 1. The Nagle algorithm + TCP retransmits mean that the two records - get coalesced into a single TCP segment - 2. Record 2 is *not* at the beginning of the TCP segment and never - will be, since it gets ACKed. - - - - -Ylonen & Moffat Expires March 31, 2004 [Page 14] - -Internet-Draft SSH Protocol Architecture Oct 2003 - - - 3. Yet, the attack is possible because Record 1 has already been - seen. - - As this example indicates, it's totally unsafe to use the existence - of unflushed data in the TCP buffers proper as a guide to whether you - need an empty packet, since when you do the second write(), the - buffers will contain the un-ACKed Record 1. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Ylonen & Moffat Expires March 31, 2004 [Page 15] - -Internet-Draft SSH Protocol Architecture Oct 2003 - - - On the other hand, it's perfectly safe to have the following - situation: - - - Client Server - ------ ------ - TCP(seq=x, len=500) -> - contains SSH_MSG_IGNORE - - TCP(seq=y, len=500) -> - contains Data - - Provided that the IV for second SSH Record is fixed after the data for - the Data packet is determined -i.e. you do: - read from user - encrypt null packet - encrypt data packet - - -9.2.2 Data Integrity - - This protocol does allow the Data Integrity mechanism to be disabled. - Implementors SHOULD be wary of exposing this feature for any purpose - other than debugging. Users and administrators SHOULD be explicitly - warned anytime the "none" MAC is enabled. - - So long as the "none" MAC is not used, this protocol provides data - integrity. - - Because MACs use a 32 bit sequence number, they might start to leak - information after 2**32 packets have been sent. However, following - the rekeying recommendations should prevent this attack. The - transport protocol [1] recommends rekeying after one gigabyte of - data, and the smallest possible packet is 16 bytes. Therefore, - rekeying SHOULD happen after 2**28 packets at the very most. - -9.2.3 Replay - - The use of a MAC other than 'none' provides integrity and - authentication. In addition, the transport protocol provides a - unique session identifier (bound in part to pseudo-random data that - is part of the algorithm and key exchange process) that can be used - by higher level protocols to bind data to a given session and prevent - replay of data from prior sessions. For example, the authentication - protocol uses this to prevent replay of signatures from previous - sessions. Because public key authentication exchanges are - cryptographically bound to the session (i.e., to the initial key - exchange) they cannot be successfully replayed in other sessions. - - - -Ylonen & Moffat Expires March 31, 2004 [Page 16] - -Internet-Draft SSH Protocol Architecture Oct 2003 - - - Note that the session ID can be made public without harming the - security of the protocol. - - If two session happen to have the same session ID [hash of key - exchanges] then packets from one can be replayed against the other. - It must be stressed that the chances of such an occurrence are, - needless to say, minimal when using modern cryptographic methods. - This is all the more so true when specifying larger hash function - outputs and DH parameters. - - Replay detection using monotonically increasing sequence numbers as - input to the MAC, or HMAC in some cases, is described in [RFC2085] /> - [RFC2246], [RFC2743], [RFC1964], [RFC2025], and [RFC1510]. The - underlying construct is discussed in [RFC2104]. Essentially a - different sequence number in each packet ensures that at least this - one input to the MAC function will be unique and will provide a - nonrecurring MAC output that is not predictable to an attacker. If - the session stays active long enough, however, this sequence number - will wrap. This event may provide an attacker an opportunity to - replay a previously recorded packet with an identical sequence number - but only if the peers have not rekeyed since the transmission of the - first packet with that sequence number. If the peers have rekeyed, - then the replay will be detected as the MAC check will fail. For - this reason, it must be emphasized that peers MUST rekey before a - wrap of the sequence numbers. Naturally, if an attacker does attempt - to replay a captured packet before the peers have rekeyed, then the - receiver of the duplicate packet will not be able to validate the MAC - and it will be discarded. The reason that the MAC will fail is - because the receiver will formulate a MAC based upon the packet - contents, the shared secret, and the expected sequence number. Since - the replayed packet will not be using that expected sequence number - (the sequence number of the replayed packet will have already been - passed by the receiver) then the calculated MAC will not match the - MAC received with the packet. - -9.2.4 Man-in-the-middle - - This protocol makes no assumptions nor provisions for an - infrastructure or means for distributing the public keys of hosts. It - is expected that this protocol will sometimes be used without first - verifying the association between the server host key and the server - host name. Such usage is vulnerable to man-in-the-middle attacks. - This section describes this and encourages administrators and users - to understand the importance of verifying this association before any - session is initiated. - - There are three cases of man-in-the-middle attacks to consider. The - first is where an attacker places a device between the client and the - - - -Ylonen & Moffat Expires March 31, 2004 [Page 17] - -Internet-Draft SSH Protocol Architecture Oct 2003 - - - server before the session is initiated. In this case, the attack - device is trying to mimic the legitimate server and will offer its - public key to the client when the client initiates a session. If it - were to offer the public key of the server, then it would not be able - to decrypt or sign the transmissions between the legitimate server - and the client unless it also had access to the private-key of the - host. The attack device will also, simultaneously to this, initiate - a session to the legitimate server masquerading itself as the client. - If the public key of the server had been securely distributed to the - client prior to that session initiation, the key offered to the - client by the attack device will not match the key stored on the - client. In that case, the user SHOULD be given a warning that the - offered host key does not match the host key cached on the client. - As described in Section 3.1 of [ARCH], the user may be free to accept - the new key and continue the session. It is RECOMMENDED that the - warning provide sufficient information to the user of the client - device so they may make an informed decision. If the user chooses to - continue the session with the stored public-key of the server (not - the public-key offered at the start of the session), then the session - specific data between the attacker and server will be different - between the client-to-attacker session and the attacker-to-server - sessions due to the randomness discussed above. From this, the - attacker will not be able to make this attack work since the attacker - will not be able to correctly sign packets containing this session - specific data from the server since he does not have the private key - of that server. - - The second case that should be considered is similar to the first - case in that it also happens at the time of connection but this case - points out the need for the secure distribution of server public - keys. If the server public keys are not securely distributed then - the client cannot know if it is talking to the intended server. An - attacker may use social engineering techniques to pass off server - keys to unsuspecting users and may then place a man-in-the-middle - attack device between the legitimate server and the clients. If this - is allowed to happen then the clients will form client-to-attacker - sessions and the attacker will form attacker-to-server sessions and - will be able to monitor and manipulate all of the traffic between the - clients and the legitimate servers. Server administrators are - encouraged to make host key fingerprints available for checking by - some means whose security does not rely on the integrity of the - actual host keys. Possible mechanisms are discussed in Section 3.1 - of [SSH-ARCH] and may also include secured Web pages, physical pieces - of paper, etc. Implementors SHOULD provide recommendations on how - best to do this with their implementation. Because the protocol is - extensible, future extensions to the protocol may provide better - mechanisms for dealing with the need to know the server's host key - before connecting. For example, making the host key fingerprint - - - -Ylonen & Moffat Expires March 31, 2004 [Page 18] - -Internet-Draft SSH Protocol Architecture Oct 2003 - - - available through a secure DNS lookup, or using kerberos over gssapi - during key exchange to authenticate the server are possibilities. - - In the third man-in-the-middle case, attackers may attempt to - manipulate packets in transit between peers after the session has - been established. As described in the Replay part of this section, a - successful attack of this nature is very improbable. As in the - Replay section, this reasoning does assume that the MAC is secure and - that it is infeasible to construct inputs to a MAC algorithm to give - a known output. This is discussed in much greater detail in Section - 6 of RFC 2104. If the MAC algorithm has a vulnerability or is weak - enough, then the attacker may be able to specify certain inputs to - yield a known MAC. With that they may be able to alter the contents - of a packet in transit. Alternatively the attacker may be able to - exploit the algorithm vulnerability or weakness to find the shared - secret by reviewing the MACs from captured packets. In either of - those cases, an attacker could construct a packet or packets that - could be inserted into an SSH stream. To prevent that, implementors - are encouraged to utilize commonly accepted MAC algorithms and - administrators are encouraged to watch current literature and - discussions of cryptography to ensure that they are not using a MAC - algorithm that has a recently found vulnerability or weakness. - - In summary, the use of this protocol without a reliable association - of the binding between a host and its host keys is inherently - insecure and is NOT RECOMMENDED. It may however be necessary in - non-security critical environments, and will still provide protection - against passive attacks. Implementors of protocols and applications - running on top of this protocol should keep this possibility in mind. - -9.2.5 Denial-of-service - - This protocol is designed to be used over a reliable transport. If - transmission errors or message manipulation occur, the connection is - closed. The connection SHOULD be re-established if this occurs. - Denial of service attacks of this type ("wire cutter") are almost - impossible to avoid. - - In addition, this protocol is vulnerable to Denial of Service attacks - because an attacker can force the server to go through the CPU and - memory intensive tasks of connection setup and key exchange without - authenticating. Implementors SHOULD provide features that make this - more difficult. For example, only allowing connections from a subset - of IPs known to have valid users. - -9.2.6 Covert Channels - - The protocol was not designed to eliminate covert channels. For - - - -Ylonen & Moffat Expires March 31, 2004 [Page 19] - -Internet-Draft SSH Protocol Architecture Oct 2003 - - - example, the padding, SSH_MSG_IGNORE messages, and several other - places in the protocol can be used to pass covert information, and - the recipient has no reliable way to verify whether such information - is being sent. - -9.2.7 Forward Secrecy - - It should be noted that the Diffie-Hellman key exchanges may provide - perfect forward secrecy (PFS). PFS is essentially defined as the - cryptographic property of a key-establishment protocol in which the - compromise of a session key or long-term private key after a given - session does not cause the compromise of any earlier session. [ANSI - T1.523-2001] SSHv2 sessions resulting from a key exchange using - diffie-hellman-group1-sha1 are secure even if private keying/ - authentication material is later revealed, but not if the session - keys are revealed. So, given this definition of PFS, SSHv2 does have - PFS. It is hoped that all other key exchange mechanisms proposed and - used in the future will also provide PFS. This property is not - commuted to any of the applications or protocols using SSH as a - transport however. The transport layer of SSH provides - confidentiality for password authentication and other methods that - rely on secret data. - - Of course, if the DH private parameters for the client and server are - revealed then the session key is revealed, but these items can be - thrown away after the key exchange completes. It's worth pointing - out that these items should not be allowed to end up on swap space - and that they should be erased from memory as soon as the key - exchange completes. - -9.3 Authentication Protocol - - The purpose of this protocol is to perform client user - authentication. It assumes that this run over a secure transport - layer protocol, which has already authenticated the server machine, - established an encrypted communications channel, and computed a - unique session identifier for this session. - - Several authentication methods with different security - characteristics are allowed. It is up to the server's local policy - to decide which methods (or combinations of methods) it is willing to - accept for each user. Authentication is no stronger than the weakest - combination allowed. - - The server may go into a "sleep" period after repeated unsuccessful - authentication attempts to make key search more difficult for - attackers. Care should be taken so that this doesn't become a - self-denial of service vector. - - - -Ylonen & Moffat Expires March 31, 2004 [Page 20] - -Internet-Draft SSH Protocol Architecture Oct 2003 - - -9.3.1 Weak Transport - - If the transport layer does not provide confidentiality, - authentication methods that rely on secret data SHOULD be disabled. - If it does not provide strong integrity protection, requests to - change authentication data (e.g. a password change) SHOULD be - disabled to prevent an attacker from modifying the ciphertext - without being noticed, or rendering the new authentication data - unusable (denial of service). - - The assumption as stated above that the Authentication Protocol only - run over a secure transport that has previously authenticated the - server is very important to note. People deploying SSH are reminded - of the consequences of man-in-the-middle attacks if the client does - not have a very strong a priori association of the server with the - host key of that server. Specifically for the case of the - Authentication Protocol the client may form a session to a - man-in-the-middle attack device and divulge user credentials such as - their username and password. Even in the cases of authentication - where no user credentials are divulged, an attacker may still gain - information they shouldn't have by capturing key-strokes in much the - same way that a honeypot works. - -9.3.2 Debug messages - - Special care should be taken when designing debug messages. These - messages may reveal surprising amounts of information about the host - if not properly designed. Debug messages can be disabled (during - user authentication phase) if high security is required. - Administrators of host machines should make all attempts to - compartmentalize all event notification messages and protect them - from unwarranted observation. Developers should be aware of the - sensitive nature of some of the normal event messages and debug - messages and may want to provide guidance to administrators on ways - to keep this information away from unauthorized people. Developers - should consider minimizing the amount of sensitive information - obtainable by users during the authentication phase in accordance - with the local policies. For this reason, it is RECOMMENDED that - debug messages be initially disabled at the time of deployment and - require an active decision by an administrator to allow them to be - enabled. It is also RECOMMENDED that a message expressing this - concern be presented to the administrator of a system when the action - is taken to enable debugging messages. - -9.3.3 Local security policy - - Implementer MUST ensure that the credentials provided validate the - professed user and also MUST ensure that the local policy of the - - - -Ylonen & Moffat Expires March 31, 2004 [Page 21] - -Internet-Draft SSH Protocol Architecture Oct 2003 - - - server permits the user the access requested. In particular, because - of the flexible nature of the SSH connection protocol, it may not be - possible to determine the local security policy, if any, that should - apply at the time of authentication because the kind of service being - requested is not clear at that instant. For example, local policy - might allow a user to access files on the server, but not start an - interactive shell. However, during the authentication protocol, it is - not known whether the user will be accessing files or attempting to - use an interactive shell, or even both. In any event, where local - security policy for the server host exists, it MUST be applied and - enforced correctly. - - Implementors are encouraged to provide a default local policy and - make its parameters known to administrators and users. At the - discretion of the implementors, this default policy may be along the - lines of 'anything goes' where there are no restrictions placed upon - users, or it may be along the lines of 'excessively restrictive' in - which case the administrators will have to actively make changes to - this policy to meet their needs. Alternatively, it may be some - attempt at providing something practical and immediately useful to - the administrators of the system so they don't have to put in much - effort to get SSH working. Whatever choice is made MUST be applied - and enforced as required above. - -9.3.4 Public key authentication - - The use of public-key authentication assumes that the client host has - not been compromised. It also assumes that the private-key of the - server host has not been compromised. - - This risk can be mitigated by the use of passphrases on private keys; - however, this is not an enforceable policy. The use of smartcards, - or other technology to make passphrases an enforceable policy is - suggested. - - The server could require both password and public-key authentication, - however, this requires the client to expose its password to the - server (see section on password authentication below.) - -9.3.5 Password authentication - - The password mechanism as specified in the authentication protocol - assumes that the server has not been compromised. If the server has - been compromised, using password authentication will reveal a valid - username / password combination to the attacker, which may lead to - further compromises. - - This vulnerability can be mitigated by using an alternative form of - - - -Ylonen & Moffat Expires March 31, 2004 [Page 22] - -Internet-Draft SSH Protocol Architecture Oct 2003 - - - authentication. For example, public-key authentication makes no - assumptions about security on the server. - -9.3.6 Host based authentication - - Host based authentication assumes that the client has not been - compromised. There are no mitigating strategies, other than to use - host based authentication in combination with another authentication - method. - -9.4 Connection protocol - -9.4.1 End point security - - End point security is assumed by the connection protocol. If the - server has been compromised, any terminal sessions, port forwarding, - or systems accessed on the host are compromised. There are no - mitigating factors for this. - - If the client end point has been compromised, and the server fails to - stop the attacker at the authentication protocol, all services - exposed (either as subsystems or through forwarding) will be - vulnerable to attack. Implementors SHOULD provide mechanisms for - administrators to control which services are exposed to limit the - vulnerability of other services. - - These controls might include controlling which machines and ports can - be target in 'port-forwarding' operations, which users are allowed to - use interactive shell facilities, or which users are allowed to use - exposed subsystems. - -9.4.2 Proxy forwarding - - The SSH connection protocol allows for proxy forwarding of other - protocols such as SNMP, POP3, and HTTP. This may be a concern for - network administrators who wish to control the access of certain - applications by users located outside of their physical location. - Essentially, the forwarding of these protocols may violate site - specific security policies as they may be undetectably tunneled - through a firewall. Implementors SHOULD provide an administrative - mechanism to control the proxy forwarding functionality so that site - specific security policies may be upheld. - - In addition, a reverse proxy forwarding functionality is available, - which again can be used to bypass firewall controls. - - As indicated above, end-point security is assumed during proxy - forwarding operations. Failure of end-point security will compromise - - - -Ylonen & Moffat Expires March 31, 2004 [Page 23] - -Internet-Draft SSH Protocol Architecture Oct 2003 - - - all data passed over proxy forwarding. - -9.4.3 X11 forwarding - - Another form of proxy forwarding provided by the ssh connection - protocol is the forwarding of the X11 protocol. If end-point - security has been compromised, X11 forwarding may allow attacks - against the X11 server. Users and administrators should, as a matter - of course, use appropriate X11 security mechanisms to prevent - unauthorized use of the X11 server. Implementors, administrators and - users who wish to further explore the security mechanisms of X11 are - invited to read [SCHEIFLER] and analyze previously reported problems - with the interactions between SSH forwarding and X11 in CERT - vulnerabilities VU#363181 and VU#118892 [CERT]. - - X11 display forwarding with SSH, by itself, is not sufficient to - correct well known problems with X11 security [VENEMA]. However, X11 - display forwarding in SSHv2 (or other, secure protocols), combined - with actual and pseudo-displays which accept connections only over - local IPC mechanisms authorized by permissions or ACLs, does correct - many X11 security problems as long as the "none" MAC is not used. It - is RECOMMENDED that X11 display implementations default to allowing - display opens only over local IPC. It is RECOMMENDED that SSHv2 - server implementations that support X11 forwarding default to - allowing display opens only over local IPC. On single-user systems - it might be reasonable to default to allowing local display opens - over TCP/IP. - - Implementors of the X11 forwarding protocol SHOULD implement the - magic cookie access checking spoofing mechanism as described in - [ssh-connect] as an additional mechanism to prevent unauthorized use - of the proxy. - -Normative References - - [SSH-ARCH] - Ylonen, T., "SSH Protocol Architecture", I-D - draft-ietf-architecture-15.txt, Oct 2003. - - [SSH-TRANS] - Ylonen, T., "SSH Transport Layer Protocol", I-D - draft-ietf-transport-17.txt, Oct 2003. - - [SSH-USERAUTH] - Ylonen, T., "SSH Authentication Protocol", I-D - draft-ietf-userauth-18.txt, Oct 2003. - - [SSH-CONNECT] - - - -Ylonen & Moffat Expires March 31, 2004 [Page 24] - -Internet-Draft SSH Protocol Architecture Oct 2003 - - - Ylonen, T., "SSH Connection Protocol", I-D - draft-ietf-connect-18.txt, Oct 2003. - - [SSH-NUMBERS] - Lehtinen, S. and D. Moffat, "SSH Protocol Assigned - Numbers", I-D draft-ietf-secsh-assignednumbers-05.txt, Oct - 2003. - - [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate - Requirement Levels", BCP 14, RFC 2119, March 1997. - -Informative References - - [FIPS-186] - Federal Information Processing Standards Publication, - "FIPS PUB 186, Digital Signature Standard", May 1994. - - [FIPS-197] - National Institue of Standards and Technology, "FIPS 197, - Specification for the Advanced Encryption Standard", - November 2001. - - [ANSI T1.523-2001] - American National Standards Insitute, Inc., "Telecom - Glossary 2000", February 2001. - - [SCHEIFLER] - Scheifler, R., "X Window System : The Complete Reference - to Xlib, X Protocol, Icccm, Xlfd, 3rd edition.", Digital - Press ISBN 1555580882, Feburary 1992. - - [RFC0854] Postel, J. and J. Reynolds, "Telnet Protocol - Specification", STD 8, RFC 854, May 1983. - - [RFC0894] Hornig, C., "Standard for the transmission of IP datagrams - over Ethernet networks", STD 41, RFC 894, April 1984. - - [RFC1034] Mockapetris, P., "Domain names - concepts and facilities", - STD 13, RFC 1034, November 1987. - - [RFC1134] Perkins, D., "Point-to-Point Protocol: A proposal for - multi-protocol transmission of datagrams over - Point-to-Point links", RFC 1134, November 1989. - - [RFC1282] Kantor, B., "BSD Rlogin", RFC 1282, December 1991. - - [RFC1510] Kohl, J. and B. Neuman, "The Kerberos Network - Authentication Service (V5)", RFC 1510, September 1993. - - - -Ylonen & Moffat Expires March 31, 2004 [Page 25] - -Internet-Draft SSH Protocol Architecture Oct 2003 - - - [RFC1700] Reynolds, J. and J. Postel, "Assigned Numbers", RFC 1700, - October 1994. - - [RFC1750] Eastlake, D., Crocker, S. and J. Schiller, "Randomness - Recommendations for Security", RFC 1750, December 1994. - - [RFC3066] Alvestrand, H., "Tags for the Identification of - Languages", BCP 47, RFC 3066, January 2001. - - [RFC1964] Linn, J., "The Kerberos Version 5 GSS-API Mechanism", RFC - 1964, June 1996. - - [RFC2025] Adams, C., "The Simple Public-Key GSS-API Mechanism - (SPKM)", RFC 2025, October 1996. - - [RFC2085] Oehler, M. and R. Glenn, "HMAC-MD5 IP Authentication with - Replay Prevention", RFC 2085, February 1997. - - [RFC2104] Krawczyk, H., Bellare, M. and R. Canetti, "HMAC: - Keyed-Hashing for Message Authentication", RFC 2104, - February 1997. - - [RFC2246] Dierks, T., Allen, C., Treese, W., Karlton, P., Freier, A. - and P. Kocher, "The TLS Protocol Version 1.0", RFC 2246, - January 1999. - - [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO - 10646", RFC 2279, January 1998. - - [RFC2410] Glenn, R. and S. Kent, "The NULL Encryption Algorithm and - Its Use With IPsec", RFC 2410, November 1998. - - [RFC2434] Narten, T. and H. Alvestrand, "Guidelines for Writing an - IANA Considerations Section in RFCs", BCP 26, RFC 2434, - October 1998. - - [RFC2743] Linn, J., "Generic Security Service Application Program - Interface Version 2, Update 1", RFC 2743, January 2000. - - [SCHNEIER] - Schneier, B., "Applied Cryptography Second Edition: - protocols algorithms and source in code in C", 1996. - - [KAUFMAN,PERLMAN,SPECINER] - Kaufman, C., Perlman, R. and M. Speciner, "Network - Security: PRIVATE Communication in a PUBLIC World", 1995. - - [CERT] CERT Coordination Center, The., "http://www.cert.org/nav/ - - - -Ylonen & Moffat Expires March 31, 2004 [Page 26] - -Internet-Draft SSH Protocol Architecture Oct 2003 - - - index_red.html". - - [VENEMA] Venema, W., "Murphy's Law and Computer Security", - Proceedings of 6th USENIX Security Symposium, San Jose CA - http://www.usenix.org/publications/library/proceedings/ - sec96/venema.html, July 1996. - - [ROGAWAY] Rogaway, P., "Problems with Proposed IP Cryptography", - Unpublished paper http://www.cs.ucdavis.edu/~rogaway/ - papers/draft-rogaway-ipsec-comments-00.txt, 1996. - - [DAI] Dai, W., "An attack against SSH2 protocol", Email to the - SECSH Working Group [email protected] ftp:// - ftp.ietf.org/ietf-mail-archive/secsh/2002-02.mail, Feb - 2002. - - [BELLARE,KOHNO,NAMPREMPRE] - Bellaire, M., Kohno, T. and C. Namprempre, "Authenticated - Encryption in SSH: Fixing the SSH Binary Packet Protocol", - , Sept 2002. - - -Authors' Addresses - - Tatu Ylonen - SSH Communications Security Corp - Fredrikinkatu 42 - HELSINKI FIN-00100 - Finland - - EMail: [email protected] - - - Darren J. Moffat (editor) - Sun Microsystems, Inc - 17 Network Circle - Menlo Park CA 94025 - USA - - EMail: [email protected] - - - - - - - - - - - -Ylonen & Moffat Expires March 31, 2004 [Page 27] - -Internet-Draft SSH Protocol Architecture Oct 2003 - - -Intellectual Property Statement - - The IETF takes no position regarding the validity or scope of any - intellectual property or other rights that might be claimed to - pertain to the implementation or use of the technology described in - this document or the extent to which any license under such rights - might or might not be available; neither does it represent that it - has made any effort to identify any such rights. Information on the - IETF's procedures with respect to rights in standards-track and - standards-related documentation can be found in BCP-11. Copies of - claims of rights made available for publication and any assurances of - licenses to be made available, or the result of an attempt made to - obtain a general license or permission for the use of such - proprietary rights by implementors or users of this specification can - be obtained from the IETF Secretariat. - - The IETF invites any interested party to bring to its attention any - copyrights, patents or patent applications, or other proprietary - rights which may cover technology that may be required to practice - this standard. Please address the information to the IETF Executive - Director. - - The IETF has been notified of intellectual property rights claimed in - regard to some or all of the specification contained in this - document. For more information consult the online list of claimed - rights. - - -Full Copyright Statement - - Copyright (C) The Internet Society (2003). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assignees. - - - -Ylonen & Moffat Expires March 31, 2004 [Page 28] - -Internet-Draft SSH Protocol Architecture Oct 2003 - - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - - -Acknowledgment - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Ylonen & Moffat Expires March 31, 2004 [Page 29]
\ No newline at end of file diff --git a/lib/ssh/doc/standard/draft-ietf-secsh-connect-18.2.ps b/lib/ssh/doc/standard/draft-ietf-secsh-connect-18.2.ps deleted file mode 100644 index 7a386724c2..0000000000 --- a/lib/ssh/doc/standard/draft-ietf-secsh-connect-18.2.ps +++ /dev/null @@ -1,2557 +0,0 @@ -%!PS-Adobe-3.0 -%%BoundingBox: 75 0 595 747 -%%Title: Enscript Output -%%For: Magnus Thoang -%%Creator: GNU enscript 1.6.1 -%%CreationDate: Fri Oct 31 13:33:02 2003 -%%Orientation: Portrait -%%Pages: 11 0 -%%DocumentMedia: A4 595 842 0 () () -%%DocumentNeededResources: (atend) -%%EndComments -%%BeginProlog -%%BeginProcSet: PStoPS 1 15 -userdict begin -[/showpage/erasepage/copypage]{dup where{pop dup load - type/operatortype eq{1 array cvx dup 0 3 index cvx put - bind def}{pop}ifelse}{pop}ifelse}forall -[/letter/legal/executivepage/a4/a4small/b5/com10envelope - /monarchenvelope/c5envelope/dlenvelope/lettersmall/note - /folio/quarto/a5]{dup where{dup wcheck{exch{}put} - {pop{}def}ifelse}{pop}ifelse}forall -/setpagedevice {pop}bind 1 index where{dup wcheck{3 1 roll put} - {pop def}ifelse}{def}ifelse -/PStoPSmatrix matrix currentmatrix def -/PStoPSxform matrix def/PStoPSclip{clippath}def -/defaultmatrix{PStoPSmatrix exch PStoPSxform exch concatmatrix}bind def -/initmatrix{matrix defaultmatrix setmatrix}bind def -/initclip[{matrix currentmatrix PStoPSmatrix setmatrix - [{currentpoint}stopped{$error/newerror false put{newpath}} - {/newpath cvx 3 1 roll/moveto cvx 4 array astore cvx}ifelse] - {[/newpath cvx{/moveto cvx}{/lineto cvx} - {/curveto cvx}{/closepath cvx}pathforall]cvx exch pop} - stopped{$error/errorname get/invalidaccess eq{cleartomark - $error/newerror false put cvx exec}{stop}ifelse}if}bind aload pop - /initclip dup load dup type dup/operatortype eq{pop exch pop} - {dup/arraytype eq exch/packedarraytype eq or - {dup xcheck{exch pop aload pop}{pop cvx}ifelse} - {pop cvx}ifelse}ifelse - {newpath PStoPSclip clip newpath exec setmatrix} bind aload pop]cvx def -/initgraphics{initmatrix newpath initclip 1 setlinewidth - 0 setlinecap 0 setlinejoin []0 setdash 0 setgray - 10 setmiterlimit}bind def -end -%%EndProcSet -%%BeginResource: procset Enscript-Prolog 1.6 1 -% -% Procedures. -% - -/_S { % save current state - /_s save def -} def -/_R { % restore from saved state - _s restore -} def - -/S { % showpage protecting gstate - gsave - showpage - grestore -} bind def - -/MF { % fontname newfontname -> - make a new encoded font - /newfontname exch def - /fontname exch def - - /fontdict fontname findfont def - /newfont fontdict maxlength dict def - - fontdict { - exch - dup /FID eq { - % skip FID pair - pop pop - } { - % copy to the new font dictionary - exch newfont 3 1 roll put - } ifelse - } forall - - newfont /FontName newfontname put - - % insert only valid encoding vectors - encoding_vector length 256 eq { - newfont /Encoding encoding_vector put - } if - - newfontname newfont definefont pop -} def - -/SF { % fontname width height -> - set a new font - /height exch def - /width exch def - - findfont - [width 0 0 height 0 0] makefont setfont -} def - -/SUF { % fontname width height -> - set a new user font - /height exch def - /width exch def - - /F-gs-user-font MF - /F-gs-user-font width height SF -} def - -/M {moveto} bind def -/s {show} bind def - -/Box { % x y w h -> - define box path - /d_h exch def /d_w exch def /d_y exch def /d_x exch def - d_x d_y moveto - d_w 0 rlineto - 0 d_h rlineto - d_w neg 0 rlineto - closepath -} def - -/bgs { % x y height blskip gray str -> - show string with bg color - /str exch def - /gray exch def - /blskip exch def - /height exch def - /y exch def - /x exch def - - gsave - x y blskip sub str stringwidth pop height Box - gray setgray - fill - grestore - x y M str s -} def - -% Highlight bars. -/highlight_bars { % nlines lineheight output_y_margin gray -> - - gsave - setgray - /ymarg exch def - /lineheight exch def - /nlines exch def - - % This 2 is just a magic number to sync highlight lines to text. - 0 d_header_y ymarg sub 2 sub translate - - /cw d_output_w cols div def - /nrows d_output_h ymarg 2 mul sub lineheight div cvi def - - % for each column - 0 1 cols 1 sub { - cw mul /xp exch def - - % for each rows - 0 1 nrows 1 sub { - /rn exch def - rn lineheight mul neg /yp exch def - rn nlines idiv 2 mod 0 eq { - % Draw highlight bar. 4 is just a magic indentation. - xp 4 add yp cw 8 sub lineheight neg Box fill - } if - } for - } for - - grestore -} def - -% Line highlight bar. -/line_highlight { % x y width height gray -> - - gsave - /gray exch def - Box gray setgray fill - grestore -} def - -% Column separator lines. -/column_lines { - gsave - .1 setlinewidth - 0 d_footer_h translate - /cw d_output_w cols div def - 1 1 cols 1 sub { - cw mul 0 moveto - 0 d_output_h rlineto stroke - } for - grestore -} def - -% Column borders. -/column_borders { - gsave - .1 setlinewidth - 0 d_footer_h moveto - 0 d_output_h rlineto - d_output_w 0 rlineto - 0 d_output_h neg rlineto - closepath stroke - grestore -} def - -% Do the actual underlay drawing -/draw_underlay { - ul_style 0 eq { - ul_str true charpath stroke - } { - ul_str show - } ifelse -} def - -% Underlay -/underlay { % - -> - - gsave - 0 d_page_h translate - d_page_h neg d_page_w atan rotate - - ul_gray setgray - ul_font setfont - /dw d_page_h dup mul d_page_w dup mul add sqrt def - ul_str stringwidth pop dw exch sub 2 div ul_h_ptsize -2 div moveto - draw_underlay - grestore -} def - -/user_underlay { % - -> - - gsave - ul_x ul_y translate - ul_angle rotate - ul_gray setgray - ul_font setfont - 0 0 ul_h_ptsize 2 div sub moveto - draw_underlay - grestore -} def - -% Page prefeed -/page_prefeed { % bool -> - - statusdict /prefeed known { - statusdict exch /prefeed exch put - } { - pop - } ifelse -} def - -% Wrapped line markers -/wrapped_line_mark { % x y charwith charheight type -> - - /type exch def - /h exch def - /w exch def - /y exch def - /x exch def - - type 2 eq { - % Black boxes (like TeX does) - gsave - 0 setlinewidth - x w 4 div add y M - 0 h rlineto w 2 div 0 rlineto 0 h neg rlineto - closepath fill - grestore - } { - type 3 eq { - % Small arrows - gsave - .2 setlinewidth - x w 2 div add y h 2 div add M - w 4 div 0 rlineto - x w 4 div add y lineto stroke - - x w 4 div add w 8 div add y h 4 div add M - x w 4 div add y lineto - w 4 div h 8 div rlineto stroke - grestore - } { - % do nothing - } ifelse - } ifelse -} def - -% EPSF import. - -/BeginEPSF { - /b4_Inc_state save def % Save state for cleanup - /dict_count countdictstack def % Count objects on dict stack - /op_count count 1 sub def % Count objects on operand stack - userdict begin - /showpage { } def - 0 setgray 0 setlinecap - 1 setlinewidth 0 setlinejoin - 10 setmiterlimit [ ] 0 setdash newpath - /languagelevel where { - pop languagelevel - 1 ne { - false setstrokeadjust false setoverprint - } if - } if -} bind def - -/EndEPSF { - count op_count sub { pos } repeat % Clean up stacks - countdictstack dict_count sub { end } repeat - b4_Inc_state restore -} bind def - -% Check PostScript language level. -/languagelevel where { - pop /gs_languagelevel languagelevel def -} { - /gs_languagelevel 1 def -} ifelse -%%EndResource -%%BeginResource: procset Enscript-Encoding-88591 1.6 1 -/encoding_vector [ -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/space /exclam /quotedbl /numbersign -/dollar /percent /ampersand /quoteright -/parenleft /parenright /asterisk /plus -/comma /hyphen /period /slash -/zero /one /two /three -/four /five /six /seven -/eight /nine /colon /semicolon -/less /equal /greater /question -/at /A /B /C -/D /E /F /G -/H /I /J /K -/L /M /N /O -/P /Q /R /S -/T /U /V /W -/X /Y /Z /bracketleft -/backslash /bracketright /asciicircum /underscore -/quoteleft /a /b /c -/d /e /f /g -/h /i /j /k -/l /m /n /o -/p /q /r /s -/t /u /v /w -/x /y /z /braceleft -/bar /braceright /tilde /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/space /exclamdown /cent /sterling -/currency /yen /brokenbar /section -/dieresis /copyright /ordfeminine /guillemotleft -/logicalnot /hyphen /registered /macron -/degree /plusminus /twosuperior /threesuperior -/acute /mu /paragraph /bullet -/cedilla /onesuperior /ordmasculine /guillemotright -/onequarter /onehalf /threequarters /questiondown -/Agrave /Aacute /Acircumflex /Atilde -/Adieresis /Aring /AE /Ccedilla -/Egrave /Eacute /Ecircumflex /Edieresis -/Igrave /Iacute /Icircumflex /Idieresis -/Eth /Ntilde /Ograve /Oacute -/Ocircumflex /Otilde /Odieresis /multiply -/Oslash /Ugrave /Uacute /Ucircumflex -/Udieresis /Yacute /Thorn /germandbls -/agrave /aacute /acircumflex /atilde -/adieresis /aring /ae /ccedilla -/egrave /eacute /ecircumflex /edieresis -/igrave /iacute /icircumflex /idieresis -/eth /ntilde /ograve /oacute -/ocircumflex /otilde /odieresis /divide -/oslash /ugrave /uacute /ucircumflex -/udieresis /yacute /thorn /ydieresis -] def -%%EndResource -%%EndProlog -%%BeginSetup -%%IncludeResource: font Courier-Bold -%%IncludeResource: font Courier -/HFpt_w 10 def -/HFpt_h 10 def -/Courier-Bold /HF-gs-font MF -/HF /HF-gs-font findfont [HFpt_w 0 0 HFpt_h 0 0] makefont def -/Courier /F-gs-font MF -/F-gs-font 10 10 SF -/#copies 1 def -/d_page_w 520 def -/d_page_h 747 def -/d_header_x 0 def -/d_header_y 747 def -/d_header_w 520 def -/d_header_h 0 def -/d_footer_x 0 def -/d_footer_y 0 def -/d_footer_w 520 def -/d_footer_h 0 def -/d_output_w 520 def -/d_output_h 747 def -/cols 1 def -userdict/PStoPSxform PStoPSmatrix matrix currentmatrix - matrix invertmatrix matrix concatmatrix - matrix invertmatrix put -%%EndSetup -%%Page: (0,1) 1 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 1 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 701 M -(Network Working Group T. Ylonen) s -5 690 M -(Internet-Draft SSH Communications Security Corp) s -5 679 M -(Expires: March 31, 2004 D. Moffat, Editor, Ed.) s -5 668 M -( Sun Microsystems, Inc) s -5 657 M -( Oct 2003) s -5 624 M -( SSH Connection Protocol) s -5 613 M -( draft-ietf-secsh-connect-18.txt) s -5 591 M -(Status of this Memo) s -5 569 M -( This document is an Internet-Draft and is in full conformance with) s -5 558 M -( all provisions of Section 10 of RFC2026.) s -5 536 M -( Internet-Drafts are working documents of the Internet Engineering) s -5 525 M -( Task Force \(IETF\), its areas, and its working groups. Note that other) s -5 514 M -( groups may also distribute working documents as Internet-Drafts.) s -5 492 M -( Internet-Drafts are draft documents valid for a maximum of six months) s -5 481 M -( and may be updated, replaced, or obsoleted by other documents at any) s -5 470 M -( time. It is inappropriate to use Internet-Drafts as reference) s -5 459 M -( material or to cite them other than as "work in progress.") s -5 437 M -( The list of current Internet-Drafts can be accessed at http://) s -5 426 M -( www.ietf.org/ietf/1id-abstracts.txt.) s -5 404 M -( The list of Internet-Draft Shadow Directories can be accessed at) s -5 393 M -( http://www.ietf.org/shadow.html.) s -5 371 M -( This Internet-Draft will expire on March 31, 2004.) s -5 349 M -(Copyright Notice) s -5 327 M -( Copyright \(C\) The Internet Society \(2003\). All Rights Reserved.) s -5 305 M -(Abstract) s -5 283 M -( SSH is a protocol for secure remote login and other secure network) s -5 272 M -( services over an insecure network.) s -5 250 M -( This document describes the SSH Connection Protocol. It provides) s -5 239 M -( interactive login sessions, remote execution of commands, forwarded) s -5 228 M -( TCP/IP connections, and forwarded X11 connections. All of these) s -5 217 M -( channels are multiplexed into a single encrypted tunnel.) s -5 195 M -( The SSH Connection Protocol has been designed to run on top of the) s -5 184 M -( SSH transport layer and user authentication protocols.) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 1]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 2 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Connection Protocol Oct 2003) s -5 690 M -(Table of Contents) s -5 668 M -( 1. Contributors . . . . . . . . . . . . . . . . . . . . . . . . 3) s -5 657 M -( 2. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3) s -5 646 M -( 3. Conventions Used in This Document . . . . . . . . . . . . . 3) s -5 635 M -( 4. Global Requests . . . . . . . . . . . . . . . . . . . . . . 3) s -5 624 M -( 5. Channel Mechanism . . . . . . . . . . . . . . . . . . . . . 4) s -5 613 M -( 5.1 Opening a Channel . . . . . . . . . . . . . . . . . . . . . 4) s -5 602 M -( 5.2 Data Transfer . . . . . . . . . . . . . . . . . . . . . . . 5) s -5 591 M -( 5.3 Closing a Channel . . . . . . . . . . . . . . . . . . . . . 6) s -5 580 M -( 5.4 Channel-Specific Requests . . . . . . . . . . . . . . . . . 7) s -5 569 M -( 6. Interactive Sessions . . . . . . . . . . . . . . . . . . . . 8) s -5 558 M -( 6.1 Opening a Session . . . . . . . . . . . . . . . . . . . . . 8) s -5 547 M -( 6.2 Requesting a Pseudo-Terminal . . . . . . . . . . . . . . . . 8) s -5 536 M -( 6.3 X11 Forwarding . . . . . . . . . . . . . . . . . . . . . . . 9) s -5 525 M -( 6.3.1 Requesting X11 Forwarding . . . . . . . . . . . . . . . . . 9) s -5 514 M -( 6.3.2 X11 Channels . . . . . . . . . . . . . . . . . . . . . . . . 10) s -5 503 M -( 6.4 Environment Variable Passing . . . . . . . . . . . . . . . . 10) s -5 492 M -( 6.5 Starting a Shell or a Command . . . . . . . . . . . . . . . 10) s -5 481 M -( 6.6 Session Data Transfer . . . . . . . . . . . . . . . . . . . 11) s -5 470 M -( 6.7 Window Dimension Change Message . . . . . . . . . . . . . . 12) s -5 459 M -( 6.8 Local Flow Control . . . . . . . . . . . . . . . . . . . . . 12) s -5 448 M -( 6.9 Signals . . . . . . . . . . . . . . . . . . . . . . . . . . 12) s -5 437 M -( 6.10 Returning Exit Status . . . . . . . . . . . . . . . . . . . 13) s -5 426 M -( 7. TCP/IP Port Forwarding . . . . . . . . . . . . . . . . . . . 14) s -5 415 M -( 7.1 Requesting Port Forwarding . . . . . . . . . . . . . . . . . 14) s -5 404 M -( 7.2 TCP/IP Forwarding Channels . . . . . . . . . . . . . . . . . 15) s -5 393 M -( 8. Encoding of Terminal Modes . . . . . . . . . . . . . . . . . 16) s -5 382 M -( 9. Summary of Message Numbers . . . . . . . . . . . . . . . . . 18) s -5 371 M -( 10. Security Considerations . . . . . . . . . . . . . . . . . . 18) s -5 360 M -( 11. iana cONSiderations . . . . . . . . . . . . . . . . . . . . 19) s -5 349 M -( 12. Intellectual Property . . . . . . . . . . . . . . . . . . . 19) s -5 338 M -( Normative References . . . . . . . . . . . . . . . . . . . . 19) s -5 327 M -( Informative References . . . . . . . . . . . . . . . . . . . 20) s -5 316 M -( Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 20) s -5 305 M -( Intellectual Property and Copyright Statements . . . . . . . 21) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 2]) s -_R -S -PStoPSsaved restore -%%Page: (2,3) 2 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 3 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Connection Protocol Oct 2003) s -5 690 M -(1. Contributors) s -5 668 M -( The major original contributors of this document were: Tatu Ylonen,) s -5 657 M -( Tero Kivinen, Timo J. Rinne, Sami Lehtinen \(all of SSH Communications) s -5 646 M -( Security Corp\), and Markku-Juhani O. Saarinen \(University of) s -5 635 M -( Jyvaskyla\)) s -5 613 M -( The document editor is: [email protected]. Comments on this) s -5 602 M -( internet draft should be sent to the IETF SECSH working group,) s -5 591 M -( details at: http://ietf.org/html.charters/secsh-charter.html) s -5 569 M -(2. Introduction) s -5 547 M -( The SSH Connection Protocol has been designed to run on top of the) s -5 536 M -( SSH transport layer and user authentication protocols. It provides) s -5 525 M -( interactive login sessions, remote execution of commands, forwarded) s -5 514 M -( TCP/IP connections, and forwarded X11 connections. The service name) s -5 503 M -( for this protocol is "ssh-connection".) s -5 481 M -( This document should be read only after reading the SSH architecture) s -5 470 M -( document [SSH-ARCH]. This document freely uses terminology and) s -5 459 M -( notation from the architecture document without reference or further) s -5 448 M -( explanation.) s -5 426 M -(3. Conventions Used in This Document) s -5 404 M -( The keywords "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT",) s -5 393 M -( and "MAY" that appear in this document are to be interpreted as) s -5 382 M -( described in [RFC2119].) s -5 360 M -( The used data types and terminology are specified in the architecture) s -5 349 M -( document [SSH-ARCH].) s -5 327 M -( The architecture document also discusses the algorithm naming) s -5 316 M -( conventions that MUST be used with the SSH protocols.) s -5 294 M -(4. Global Requests) s -5 272 M -( There are several kinds of requests that affect the state of the) s -5 261 M -( remote end "globally", independent of any channels. An example is a) s -5 250 M -( request to start TCP/IP forwarding for a specific port. All such) s -5 239 M -( requests use the following format.) s -5 217 M -( byte SSH_MSG_GLOBAL_REQUEST) s -5 206 M -( string request name \(restricted to US-ASCII\)) s -5 195 M -( boolean want reply) s -5 184 M -( ... request-specific data follows) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 3]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 4 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Connection Protocol Oct 2003) s -5 690 M -( Request names follow the DNS extensibility naming convention outlined) s -5 679 M -( in [SSH-ARCH].) s -5 657 M -( The recipient will respond to this message with) s -5 646 M -( SSH_MSG_REQUEST_SUCCESS or SSH_MSG_REQUEST_FAILURE if `want reply' is) s -5 635 M -( TRUE.) s -5 613 M -( byte SSH_MSG_REQUEST_SUCCESS) s -5 602 M -( ..... response specific data) s -5 580 M -( Usually the response specific data is non-existent.) s -5 558 M -( If the recipient does not recognize or support the request, it simply) s -5 547 M -( responds with SSH_MSG_REQUEST_FAILURE.) s -5 525 M -( byte SSH_MSG_REQUEST_FAILURE) s -5 492 M -(5. Channel Mechanism) s -5 470 M -( All terminal sessions, forwarded connections, etc. are channels.) s -5 459 M -( Either side may open a channel. Multiple channels are multiplexed) s -5 448 M -( into a single connection.) s -5 426 M -( Channels are identified by numbers at each end. The number referring) s -5 415 M -( to a channel may be different on each side. Requests to open a) s -5 404 M -( channel contain the sender's channel number. Any other) s -5 393 M -( channel-related messages contain the recipient's channel number for) s -5 382 M -( the channel.) s -5 360 M -( Channels are flow-controlled. No data may be sent to a channel until) s -5 349 M -( a message is received to indicate that window space is available.) s -5 327 M -(5.1 Opening a Channel) s -5 305 M -( When either side wishes to open a new channel, it allocates a local) s -5 294 M -( number for the channel. It then sends the following message to the) s -5 283 M -( other side, and includes the local channel number and initial window) s -5 272 M -( size in the message.) s -5 250 M -( byte SSH_MSG_CHANNEL_OPEN) s -5 239 M -( string channel type \(restricted to US-ASCII\)) s -5 228 M -( uint32 sender channel) s -5 217 M -( uint32 initial window size) s -5 206 M -( uint32 maximum packet size) s -5 195 M -( ... channel type specific data follows) s -5 173 M -( The channel type is a name as described in the SSH architecture) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 4]) s -_R -S -PStoPSsaved restore -%%Page: (4,5) 3 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 5 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Connection Protocol Oct 2003) s -5 690 M -( document, with similar extension mechanisms. `sender channel' is a) s -5 679 M -( local identifier for the channel used by the sender of this message.) s -5 668 M -( `initial window size' specifies how many bytes of channel data can be) s -5 657 M -( sent to the sender of this message without adjusting the window.) s -5 646 M -( `Maximum packet size' specifies the maximum size of an individual) s -5 635 M -( data packet that can be sent to the sender \(for example, one might) s -5 624 M -( want to use smaller packets for interactive connections to get better) s -5 613 M -( interactive response on slow links\).) s -5 591 M -( The remote side then decides whether it can open the channel, and) s -5 580 M -( responds with either) s -5 558 M -( byte SSH_MSG_CHANNEL_OPEN_CONFIRMATION) s -5 547 M -( uint32 recipient channel) s -5 536 M -( uint32 sender channel) s -5 525 M -( uint32 initial window size) s -5 514 M -( uint32 maximum packet size) s -5 503 M -( ... channel type specific data follows) s -5 481 M -( where `recipient channel' is the channel number given in the original) s -5 470 M -( open request, and `sender channel' is the channel number allocated by) s -5 459 M -( the other side, or) s -5 437 M -( byte SSH_MSG_CHANNEL_OPEN_FAILURE) s -5 426 M -( uint32 recipient channel) s -5 415 M -( uint32 reason code) s -5 404 M -( string additional textual information \(ISO-10646 UTF-8 [RFC2279]\)) s -5 393 M -( string language tag \(as defined in [RFC3066]\)) s -5 371 M -( If the recipient of the SSH_MSG_CHANNEL_OPEN message does not support) s -5 360 M -( the specified channel type, it simply responds with) s -5 349 M -( SSH_MSG_CHANNEL_OPEN_FAILURE. The client MAY show the additional) s -5 338 M -( information to the user. If this is done, the client software should) s -5 327 M -( take the precautions discussed in [SSH-ARCH].) s -5 305 M -( The following reason codes are defined:) s -5 283 M -( #define SSH_OPEN_ADMINISTRATIVELY_PROHIBITED 1) s -5 272 M -( #define SSH_OPEN_CONNECT_FAILED 2) s -5 261 M -( #define SSH_OPEN_UNKNOWN_CHANNEL_TYPE 3) s -5 250 M -( #define SSH_OPEN_RESOURCE_SHORTAGE 4) s -5 217 M -(5.2 Data Transfer) s -5 195 M -( The window size specifies how many bytes the other party can send) s -5 184 M -( before it must wait for the window to be adjusted. Both parties use) s -5 173 M -( the following message to adjust the window.) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 5]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 6 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Connection Protocol Oct 2003) s -5 690 M -( byte SSH_MSG_CHANNEL_WINDOW_ADJUST) s -5 679 M -( uint32 recipient channel) s -5 668 M -( uint32 bytes to add) s -5 646 M -( After receiving this message, the recipient MAY send the given number) s -5 635 M -( of bytes more than it was previously allowed to send; the window size) s -5 624 M -( is incremented.) s -5 602 M -( Data transfer is done with messages of the following type.) s -5 580 M -( byte SSH_MSG_CHANNEL_DATA) s -5 569 M -( uint32 recipient channel) s -5 558 M -( string data) s -5 536 M -( The maximum amount of data allowed is the current window size. The) s -5 525 M -( window size is decremented by the amount of data sent. Both parties) s -5 514 M -( MAY ignore all extra data sent after the allowed window is empty.) s -5 492 M -( Additionally, some channels can transfer several types of data. An) s -5 481 M -( example of this is stderr data from interactive sessions. Such data) s -5 470 M -( can be passed with SSH_MSG_CHANNEL_EXTENDED_DATA messages, where a) s -5 459 M -( separate integer specifies the type of the data. The available types) s -5 448 M -( and their interpretation depend on the type of the channel.) s -5 426 M -( byte SSH_MSG_CHANNEL_EXTENDED_DATA) s -5 415 M -( uint32 recipient_channel) s -5 404 M -( uint32 data_type_code) s -5 393 M -( string data) s -5 371 M -( Data sent with these messages consumes the same window as ordinary) s -5 360 M -( data.) s -5 338 M -( Currently, only the following type is defined.) s -5 316 M -( #define SSH_EXTENDED_DATA_STDERR 1) s -5 283 M -(5.3 Closing a Channel) s -5 261 M -( When a party will no longer send more data to a channel, it SHOULD) s -5 250 M -( send SSH_MSG_CHANNEL_EOF.) s -5 228 M -( byte SSH_MSG_CHANNEL_EOF) s -5 217 M -( uint32 recipient_channel) s -5 195 M -( No explicit response is sent to this message; however, the) s -5 184 M -( application may send EOF to whatever is at the other end of the) s -5 173 M -( channel. Note that the channel remains open after this message, and) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 6]) s -_R -S -PStoPSsaved restore -%%Page: (6,7) 4 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 7 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Connection Protocol Oct 2003) s -5 690 M -( more data may still be sent in the other direction. This message) s -5 679 M -( does not consume window space and can be sent even if no window space) s -5 668 M -( is available.) s -5 646 M -( When either party wishes to terminate the channel, it sends) s -5 635 M -( SSH_MSG_CHANNEL_CLOSE. Upon receiving this message, a party MUST) s -5 624 M -( send back a SSH_MSG_CHANNEL_CLOSE unless it has already sent this) s -5 613 M -( message for the channel. The channel is considered closed for a) s -5 602 M -( party when it has both sent and received SSH_MSG_CHANNEL_CLOSE, and) s -5 591 M -( the party may then reuse the channel number. A party MAY send) s -5 580 M -( SSH_MSG_CHANNEL_CLOSE without having sent or received) s -5 569 M -( SSH_MSG_CHANNEL_EOF.) s -5 547 M -( byte SSH_MSG_CHANNEL_CLOSE) s -5 536 M -( uint32 recipient_channel) s -5 514 M -( This message does not consume window space and can be sent even if no) s -5 503 M -( window space is available.) s -5 481 M -( It is recommended that any data sent before this message is delivered) s -5 470 M -( to the actual destination, if possible.) s -5 448 M -(5.4 Channel-Specific Requests) s -5 426 M -( Many channel types have extensions that are specific to that) s -5 415 M -( particular channel type. An example is requesting a pty \(pseudo) s -5 404 M -( terminal\) for an interactive session.) s -5 382 M -( All channel-specific requests use the following format.) s -5 360 M -( byte SSH_MSG_CHANNEL_REQUEST) s -5 349 M -( uint32 recipient channel) s -5 338 M -( string request type \(restricted to US-ASCII\)) s -5 327 M -( boolean want reply) s -5 316 M -( ... type-specific data) s -5 294 M -( If want reply is FALSE, no response will be sent to the request.) s -5 283 M -( Otherwise, the recipient responds with either SSH_MSG_CHANNEL_SUCCESS) s -5 272 M -( or SSH_MSG_CHANNEL_FAILURE, or request-specific continuation) s -5 261 M -( messages. If the request is not recognized or is not supported for) s -5 250 M -( the channel, SSH_MSG_CHANNEL_FAILURE is returned.) s -5 228 M -( This message does not consume window space and can be sent even if no) s -5 217 M -( window space is available. Request types are local to each channel) s -5 206 M -( type.) s -5 184 M -( The client is allowed to send further messages without waiting for) s -5 173 M -( the response to the request.) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 7]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 8 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Connection Protocol Oct 2003) s -5 690 M -( request type names follow the DNS extensibility naming convention) s -5 679 M -( outlined in [SSH-ARCH]) s -5 657 M -( byte SSH_MSG_CHANNEL_SUCCESS) s -5 646 M -( uint32 recipient_channel) s -5 613 M -( byte SSH_MSG_CHANNEL_FAILURE) s -5 602 M -( uint32 recipient_channel) s -5 580 M -( These messages do not consume window space and can be sent even if no) s -5 569 M -( window space is available.) s -5 547 M -(6. Interactive Sessions) s -5 525 M -( A session is a remote execution of a program. The program may be a) s -5 514 M -( shell, an application, a system command, or some built-in subsystem.) s -5 503 M -( It may or may not have a tty, and may or may not involve X11) s -5 492 M -( forwarding. Multiple sessions can be active simultaneously.) s -5 470 M -(6.1 Opening a Session) s -5 448 M -( A session is started by sending the following message.) s -5 426 M -( byte SSH_MSG_CHANNEL_OPEN) s -5 415 M -( string "session") s -5 404 M -( uint32 sender channel) s -5 393 M -( uint32 initial window size) s -5 382 M -( uint32 maximum packet size) s -5 360 M -( Client implementations SHOULD reject any session channel open) s -5 349 M -( requests to make it more difficult for a corrupt server to attack the) s -5 338 M -( client.) s -5 316 M -(6.2 Requesting a Pseudo-Terminal) s -5 294 M -( A pseudo-terminal can be allocated for the session by sending the) s -5 283 M -( following message.) s -5 261 M -( byte SSH_MSG_CHANNEL_REQUEST) s -5 250 M -( uint32 recipient_channel) s -5 239 M -( string "pty-req") s -5 228 M -( boolean want_reply) s -5 217 M -( string TERM environment variable value \(e.g., vt100\)) s -5 206 M -( uint32 terminal width, characters \(e.g., 80\)) s -5 195 M -( uint32 terminal height, rows \(e.g., 24\)) s -5 184 M -( uint32 terminal width, pixels \(e.g., 640\)) s -5 173 M -( uint32 terminal height, pixels \(e.g., 480\)) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 8]) s -_R -S -PStoPSsaved restore -%%Page: (8,9) 5 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 9 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Connection Protocol Oct 2003) s -5 690 M -( string encoded terminal modes) s -5 668 M -( The encoding of terminal modes is described in Section Encoding of) s -5 657 M -( Terminal Modes \(Section 8\). Zero dimension parameters MUST be) s -5 646 M -( ignored. The character/row dimensions override the pixel dimensions) s -5 635 M -( \(when nonzero\). Pixel dimensions refer to the drawable area of the) s -5 624 M -( window.) s -5 602 M -( The dimension parameters are only informational.) s -5 580 M -( The client SHOULD ignore pty requests.) s -5 558 M -(6.3 X11 Forwarding) s -5 536 M -(6.3.1 Requesting X11 Forwarding) s -5 514 M -( X11 forwarding may be requested for a session by sending) s -5 492 M -( byte SSH_MSG_CHANNEL_REQUEST) s -5 481 M -( uint32 recipient channel) s -5 470 M -( string "x11-req") s -5 459 M -( boolean want reply) s -5 448 M -( boolean single connection) s -5 437 M -( string x11 authentication protocol) s -5 426 M -( string x11 authentication cookie) s -5 415 M -( uint32 x11 screen number) s -5 393 M -( It is recommended that the authentication cookie that is sent be a) s -5 382 M -( fake, random cookie, and that the cookie is checked and replaced by) s -5 371 M -( the real cookie when a connection request is received.) s -5 349 M -( X11 connection forwarding should stop when the session channel is) s -5 338 M -( closed; however, already opened forwardings should not be) s -5 327 M -( automatically closed when the session channel is closed.) s -5 305 M -( If `single connection' is TRUE, only a single connection should be) s -5 294 M -( forwarded. No more connections will be forwarded after the first, or) s -5 283 M -( after the session channel has been closed.) s -5 261 M -( The "x11 authentication protocol" is the name of the X11) s -5 250 M -( authentication method used, e.g. "MIT-MAGIC-COOKIE-1".) s -5 228 M -( The x11 authentication cookie MUST be hexadecimal encoded.) s -5 206 M -( X Protocol is documented in [SCHEIFLER].) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 9]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 10 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Connection Protocol Oct 2003) s -5 690 M -(6.3.2 X11 Channels) s -5 668 M -( X11 channels are opened with a channel open request. The resulting) s -5 657 M -( channels are independent of the session, and closing the session) s -5 646 M -( channel does not close the forwarded X11 channels.) s -5 624 M -( byte SSH_MSG_CHANNEL_OPEN) s -5 613 M -( string "x11") s -5 602 M -( uint32 sender channel) s -5 591 M -( uint32 initial window size) s -5 580 M -( uint32 maximum packet size) s -5 569 M -( string originator address \(e.g. "192.168.7.38"\)) s -5 558 M -( uint32 originator port) s -5 536 M -( The recipient should respond with SSH_MSG_CHANNEL_OPEN_CONFIRMATION) s -5 525 M -( or SSH_MSG_CHANNEL_OPEN_FAILURE.) s -5 503 M -( Implementations MUST reject any X11 channel open requests if they) s -5 492 M -( have not requested X11 forwarding.) s -5 470 M -(6.4 Environment Variable Passing) s -5 448 M -( Environment variables may be passed to the shell/command to be) s -5 437 M -( started later. Uncontrolled setting of environment variables in a) s -5 426 M -( privileged process can be a security hazard. It is recommended that) s -5 415 M -( implementations either maintain a list of allowable variable names or) s -5 404 M -( only set environment variables after the server process has dropped) s -5 393 M -( sufficient privileges.) s -5 371 M -( byte SSH_MSG_CHANNEL_REQUEST) s -5 360 M -( uint32 recipient channel) s -5 349 M -( string "env") s -5 338 M -( boolean want reply) s -5 327 M -( string variable name) s -5 316 M -( string variable value) s -5 283 M -(6.5 Starting a Shell or a Command) s -5 261 M -( Once the session has been set up, a program is started at the remote) s -5 250 M -( end. The program can be a shell, an application program or a) s -5 239 M -( subsystem with a host-independent name. Only one of these requests) s -5 228 M -( can succeed per channel.) s -5 206 M -( byte SSH_MSG_CHANNEL_REQUEST) s -5 195 M -( uint32 recipient channel) s -5 184 M -( string "shell") s -5 173 M -( boolean want reply) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 10]) s -_R -S -PStoPSsaved restore -%%Page: (10,11) 6 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 11 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Connection Protocol Oct 2003) s -5 690 M -( This message will request the user's default shell \(typically defined) s -5 679 M -( in /etc/passwd in UNIX systems\) to be started at the other end.) s -5 657 M -( byte SSH_MSG_CHANNEL_REQUEST) s -5 646 M -( uint32 recipient channel) s -5 635 M -( string "exec") s -5 624 M -( boolean want reply) s -5 613 M -( string command) s -5 591 M -( This message will request the server to start the execution of the) s -5 580 M -( given command. The command string may contain a path. Normal) s -5 569 M -( precautions MUST be taken to prevent the execution of unauthorized) s -5 558 M -( commands.) s -5 536 M -( byte SSH_MSG_CHANNEL_REQUEST) s -5 525 M -( uint32 recipient channel) s -5 514 M -( string "subsystem") s -5 503 M -( boolean want reply) s -5 492 M -( string subsystem name) s -5 470 M -( This last form executes a predefined subsystem. It is expected that) s -5 459 M -( these will include a general file transfer mechanism, and possibly) s -5 448 M -( other features. Implementations may also allow configuring more such) s -5 437 M -( mechanisms. As the user's shell is usually used to execute the) s -5 426 M -( subsystem, it is advisable for the subsystem protocol to have a) s -5 415 M -( "magic cookie" at the beginning of the protocol transaction to) s -5 404 M -( distinguish it from arbitrary output generated by shell) s -5 393 M -( initialization scripts etc. This spurious output from the shell may) s -5 382 M -( be filtered out either at the server or at the client.) s -5 360 M -( The server SHOULD not halt the execution of the protocol stack when) s -5 349 M -( starting a shell or a program. All input and output from these SHOULD) s -5 338 M -( be redirected to the channel or to the encrypted tunnel.) s -5 316 M -( It is RECOMMENDED to request and check the reply for these messages.) s -5 305 M -( The client SHOULD ignore these messages.) s -5 283 M -( Subsystem names follow the DNS extensibility naming convention) s -5 272 M -( outlined in [SSH-ARCH].) s -5 250 M -(6.6 Session Data Transfer) s -5 228 M -( Data transfer for a session is done using SSH_MSG_CHANNEL_DATA and) s -5 217 M -( SSH_MSG_CHANNEL_EXTENDED_DATA packets and the window mechanism. The) s -5 206 M -( extended data type SSH_EXTENDED_DATA_STDERR has been defined for) s -5 195 M -( stderr data.) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 11]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 12 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Connection Protocol Oct 2003) s -5 690 M -(6.7 Window Dimension Change Message) s -5 668 M -( When the window \(terminal\) size changes on the client side, it MAY) s -5 657 M -( send a message to the other side to inform it of the new dimensions.) s -5 635 M -( byte SSH_MSG_CHANNEL_REQUEST) s -5 624 M -( uint32 recipient_channel) s -5 613 M -( string "window-change") s -5 602 M -( boolean FALSE) s -5 591 M -( uint32 terminal width, columns) s -5 580 M -( uint32 terminal height, rows) s -5 569 M -( uint32 terminal width, pixels) s -5 558 M -( uint32 terminal height, pixels) s -5 536 M -( No response SHOULD be sent to this message.) s -5 514 M -(6.8 Local Flow Control) s -5 492 M -( On many systems, it is possible to determine if a pseudo-terminal is) s -5 481 M -( using control-S/control-Q flow control. When flow control is) s -5 470 M -( allowed, it is often desirable to do the flow control at the client) s -5 459 M -( end to speed up responses to user requests. This is facilitated by) s -5 448 M -( the following notification. Initially, the server is responsible for) s -5 437 M -( flow control. \(Here, again, client means the side originating the) s -5 426 M -( session, and server means the other side.\)) s -5 404 M -( The message below is used by the server to inform the client when it) s -5 393 M -( can or cannot perform flow control \(control-S/control-Q processing\).) s -5 382 M -( If `client can do' is TRUE, the client is allowed to do flow control) s -5 371 M -( using control-S and control-Q. The client MAY ignore this message.) s -5 349 M -( byte SSH_MSG_CHANNEL_REQUEST) s -5 338 M -( uint32 recipient channel) s -5 327 M -( string "xon-xoff") s -5 316 M -( boolean FALSE) s -5 305 M -( boolean client can do) s -5 283 M -( No response is sent to this message.) s -5 261 M -(6.9 Signals) s -5 239 M -( A signal can be delivered to the remote process/service using the) s -5 228 M -( following message. Some systems may not implement signals, in which) s -5 217 M -( case they SHOULD ignore this message.) s -5 195 M -( byte SSH_MSG_CHANNEL_REQUEST) s -5 184 M -( uint32 recipient channel) s -5 173 M -( string "signal") s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 12]) s -_R -S -PStoPSsaved restore -%%Page: (12,13) 7 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 13 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Connection Protocol Oct 2003) s -5 690 M -( boolean FALSE) s -5 679 M -( string signal name without the "SIG" prefix.) s -5 657 M -( Signal names will be encoded as discussed in the "exit-signal") s -5 646 M -( SSH_MSG_CHANNEL_REQUEST.) s -5 624 M -(6.10 Returning Exit Status) s -5 602 M -( When the command running at the other end terminates, the following) s -5 591 M -( message can be sent to return the exit status of the command.) s -5 580 M -( Returning the status is RECOMMENDED. No acknowledgment is sent for) s -5 569 M -( this message. The channel needs to be closed with) s -5 558 M -( SSH_MSG_CHANNEL_CLOSE after this message.) s -5 536 M -( The client MAY ignore these messages.) s -5 514 M -( byte SSH_MSG_CHANNEL_REQUEST) s -5 503 M -( uint32 recipient_channel) s -5 492 M -( string "exit-status") s -5 481 M -( boolean FALSE) s -5 470 M -( uint32 exit_status) s -5 448 M -( The remote command may also terminate violently due to a signal.) s -5 437 M -( Such a condition can be indicated by the following message. A zero) s -5 426 M -( exit_status usually means that the command terminated successfully.) s -5 404 M -( byte SSH_MSG_CHANNEL_REQUEST) s -5 393 M -( uint32 recipient channel) s -5 382 M -( string "exit-signal") s -5 371 M -( boolean FALSE) s -5 360 M -( string signal name without the "SIG" prefix.) s -5 349 M -( boolean core dumped) s -5 338 M -( string error message \(ISO-10646 UTF-8\)) s -5 327 M -( string language tag \(as defined in [RFC3066]\)) s -5 305 M -( The signal name is one of the following \(these are from [POSIX]\)) s -5 283 M -( ABRT) s -5 272 M -( ALRM) s -5 261 M -( FPE) s -5 250 M -( HUP) s -5 239 M -( ILL) s -5 228 M -( INT) s -5 217 M -( KILL) s -5 206 M -( PIPE) s -5 195 M -( QUIT) s -5 184 M -( SEGV) s -5 173 M -( TERM) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 13]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 14 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Connection Protocol Oct 2003) s -5 690 M -( USR1) s -5 679 M -( USR2) s -5 657 M -( Additional signal names MAY be sent in the format "sig-name@xyz",) s -5 646 M -( where `sig-name' and `xyz' may be anything a particular implementor) s -5 635 M -( wants \(except the `@' sign\). However, it is suggested that if a) s -5 624 M -( `configure' script is used, the non-standard signal names it finds be) s -5 613 M -( encoded as "[email protected]", where `SIG' is the signal name) s -5 602 M -( without the "SIG" prefix, and `xyz' be the host type, as determined) s -5 591 M -( by `config.guess'.) s -5 569 M -( The `error message' contains an additional explanation of the error) s -5 558 M -( message. The message may consist of multiple lines. The client) s -5 547 M -( software MAY display this message to the user. If this is done, the) s -5 536 M -( client software should take the precautions discussed in [SSH-ARCH].) s -5 514 M -(7. TCP/IP Port Forwarding) s -5 492 M -(7.1 Requesting Port Forwarding) s -5 470 M -( A party need not explicitly request forwardings from its own end to) s -5 459 M -( the other direction. However, if it wishes that connections to a) s -5 448 M -( port on the other side be forwarded to the local side, it must) s -5 437 M -( explicitly request this.) s -5 404 M -( byte SSH_MSG_GLOBAL_REQUEST) s -5 393 M -( string "tcpip-forward") s -5 382 M -( boolean want reply) s -5 371 M -( string address to bind \(e.g. "0.0.0.0"\)) s -5 360 M -( uint32 port number to bind) s -5 338 M -( `Address to bind' and `port number to bind' specify the IP address) s -5 327 M -( and port to which the socket to be listened is bound. The address) s -5 316 M -( should be "0.0.0.0" if connections are allowed from anywhere. \(Note) s -5 305 M -( that the client can still filter connections based on information) s -5 294 M -( passed in the open request.\)) s -5 272 M -( Implementations should only allow forwarding privileged ports if the) s -5 261 M -( user has been authenticated as a privileged user.) s -5 239 M -( Client implementations SHOULD reject these messages; they are) s -5 228 M -( normally only sent by the client.) s -5 195 M -( If a client passes 0 as port number to bind and has want reply TRUE) s -5 184 M -( then the server allocates the next available unprivileged port number) s -5 173 M -( and replies with the following message, otherwise there is no) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 14]) s -_R -S -PStoPSsaved restore -%%Page: (14,15) 8 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 15 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Connection Protocol Oct 2003) s -5 690 M -( response specific data.) s -5 657 M -( byte SSH_MSG_GLOBAL_REQUEST_SUCCESS) s -5 646 M -( uint32 port that was bound on the server) s -5 624 M -( A port forwarding can be cancelled with the following message. Note) s -5 613 M -( that channel open requests may be received until a reply to this) s -5 602 M -( message is received.) s -5 580 M -( byte SSH_MSG_GLOBAL_REQUEST) s -5 569 M -( string "cancel-tcpip-forward") s -5 558 M -( boolean want reply) s -5 547 M -( string address_to_bind \(e.g. "127.0.0.1"\)) s -5 536 M -( uint32 port number to bind) s -5 514 M -( Client implementations SHOULD reject these messages; they are) s -5 503 M -( normally only sent by the client.) s -5 481 M -(7.2 TCP/IP Forwarding Channels) s -5 459 M -( When a connection comes to a port for which remote forwarding has) s -5 448 M -( been requested, a channel is opened to forward the port to the other) s -5 437 M -( side.) s -5 415 M -( byte SSH_MSG_CHANNEL_OPEN) s -5 404 M -( string "forwarded-tcpip") s -5 393 M -( uint32 sender channel) s -5 382 M -( uint32 initial window size) s -5 371 M -( uint32 maximum packet size) s -5 360 M -( string address that was connected) s -5 349 M -( uint32 port that was connected) s -5 338 M -( string originator IP address) s -5 327 M -( uint32 originator port) s -5 305 M -( Implementations MUST reject these messages unless they have) s -5 294 M -( previously requested a remote TCP/IP port forwarding with the given) s -5 283 M -( port number.) s -5 261 M -( When a connection comes to a locally forwarded TCP/IP port, the) s -5 250 M -( following packet is sent to the other side. Note that these messages) s -5 239 M -( MAY be sent also for ports for which no forwarding has been) s -5 228 M -( explicitly requested. The receiving side must decide whether to) s -5 217 M -( allow the forwarding.) s -5 195 M -( byte SSH_MSG_CHANNEL_OPEN) s -5 184 M -( string "direct-tcpip") s -5 173 M -( uint32 sender channel) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 15]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 16 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Connection Protocol Oct 2003) s -5 690 M -( uint32 initial window size) s -5 679 M -( uint32 maximum packet size) s -5 668 M -( string host to connect) s -5 657 M -( uint32 port to connect) s -5 646 M -( string originator IP address) s -5 635 M -( uint32 originator port) s -5 613 M -( `Host to connect' and `port to connect' specify the TCP/IP host and) s -5 602 M -( port where the recipient should connect the channel. `Host to) s -5 591 M -( connect' may be either a domain name or a numeric IP address.) s -5 569 M -( `Originator IP address' is the numeric IP address of the machine) s -5 558 M -( where the connection request comes from, and `originator port' is the) s -5 547 M -( port on the originator host from where the connection came from.) s -5 525 M -( Forwarded TCP/IP channels are independent of any sessions, and) s -5 514 M -( closing a session channel does not in any way imply that forwarded) s -5 503 M -( connections should be closed.) s -5 481 M -( Client implementations SHOULD reject direct TCP/IP open requests for) s -5 470 M -( security reasons.) s -5 448 M -(8. Encoding of Terminal Modes) s -5 426 M -( Terminal modes \(as passed in a pty request\) are encoded into a byte) s -5 415 M -( stream. It is intended that the coding be portable across different) s -5 404 M -( environments.) s -5 382 M -( The tty mode description is a stream of bytes. The stream consists) s -5 371 M -( of opcode-argument pairs. It is terminated by opcode TTY_OP_END \(0\).) s -5 360 M -( Opcodes 1 to 159 have a single uint32 argument. Opcodes 160 to 255) s -5 349 M -( are not yet defined, and cause parsing to stop \(they should only be) s -5 338 M -( used after any other data\).) s -5 316 M -( The client SHOULD put in the stream any modes it knows about, and the) s -5 305 M -( server MAY ignore any modes it does not know about. This allows some) s -5 294 M -( degree of machine-independence, at least between systems that use a) s -5 283 M -( POSIX-like tty interface. The protocol can support other systems as) s -5 272 M -( well, but the client may need to fill reasonable values for a number) s -5 261 M -( of parameters so the server pty gets set to a reasonable mode \(the) s -5 250 M -( server leaves all unspecified mode bits in their default values, and) s -5 239 M -( only some combinations make sense\).) s -5 217 M -( The following opcodes have been defined. The naming of opcodes) s -5 206 M -( mostly follows the POSIX terminal mode flags.) s -5 184 M -( 0 TTY_OP_END Indicates end of options.) s -5 173 M -( 1 VINTR Interrupt character; 255 if none. Similarly for the) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 16]) s -_R -S -PStoPSsaved restore -%%Page: (16,17) 9 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 17 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Connection Protocol Oct 2003) s -5 690 M -( other characters. Not all of these characters are) s -5 679 M -( supported on all systems.) s -5 668 M -( 2 VQUIT The quit character \(sends SIGQUIT signal on POSIX) s -5 657 M -( systems\).) s -5 646 M -( 3 VERASE Erase the character to left of the cursor.) s -5 635 M -( 4 VKILL Kill the current input line.) s -5 624 M -( 5 VEOF End-of-file character \(sends EOF from the terminal\).) s -5 613 M -( 6 VEOL End-of-line character in addition to carriage return) s -5 602 M -( and/or linefeed.) s -5 591 M -( 7 VEOL2 Additional end-of-line character.) s -5 580 M -( 8 VSTART Continues paused output \(normally control-Q\).) s -5 569 M -( 9 VSTOP Pauses output \(normally control-S\).) s -5 558 M -( 10 VSUSP Suspends the current program.) s -5 547 M -( 11 VDSUSP Another suspend character.) s -5 536 M -( 12 VREPRINT Reprints the current input line.) s -5 525 M -( 13 VWERASE Erases a word left of cursor.) s -5 514 M -( 14 VLNEXT Enter the next character typed literally, even if it) s -5 503 M -( is a special character) s -5 492 M -( 15 VFLUSH Character to flush output.) s -5 481 M -( 16 VSWTCH Switch to a different shell layer.) s -5 470 M -( 17 VSTATUS Prints system status line \(load, command, pid etc\).) s -5 459 M -( 18 VDISCARD Toggles the flushing of terminal output.) s -5 448 M -( 30 IGNPAR The ignore parity flag. The parameter SHOULD be 0 if) s -5 437 M -( this flag is FALSE set, and 1 if it is TRUE.) s -5 426 M -( 31 PARMRK Mark parity and framing errors.) s -5 415 M -( 32 INPCK Enable checking of parity errors.) s -5 404 M -( 33 ISTRIP Strip 8th bit off characters.) s -5 393 M -( 34 INLCR Map NL into CR on input.) s -5 382 M -( 35 IGNCR Ignore CR on input.) s -5 371 M -( 36 ICRNL Map CR to NL on input.) s -5 360 M -( 37 IUCLC Translate uppercase characters to lowercase.) s -5 349 M -( 38 IXON Enable output flow control.) s -5 338 M -( 39 IXANY Any char will restart after stop.) s -5 327 M -( 40 IXOFF Enable input flow control.) s -5 316 M -( 41 IMAXBEL Ring bell on input queue full.) s -5 305 M -( 50 ISIG Enable signals INTR, QUIT, [D]SUSP.) s -5 294 M -( 51 ICANON Canonicalize input lines.) s -5 283 M -( 52 XCASE Enable input and output of uppercase characters by) s -5 272 M -( preceding their lowercase equivalents with `\\'.) s -5 261 M -( 53 ECHO Enable echoing.) s -5 250 M -( 54 ECHOE Visually erase chars.) s -5 239 M -( 55 ECHOK Kill character discards current line.) s -5 228 M -( 56 ECHONL Echo NL even if ECHO is off.) s -5 217 M -( 57 NOFLSH Don't flush after interrupt.) s -5 206 M -( 58 TOSTOP Stop background jobs from output.) s -5 195 M -( 59 IEXTEN Enable extensions.) s -5 184 M -( 60 ECHOCTL Echo control characters as ^\(Char\).) s -5 173 M -( 61 ECHOKE Visual erase for line kill.) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 17]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 18 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Connection Protocol Oct 2003) s -5 690 M -( 62 PENDIN Retype pending input.) s -5 679 M -( 70 OPOST Enable output processing.) s -5 668 M -( 71 OLCUC Convert lowercase to uppercase.) s -5 657 M -( 72 ONLCR Map NL to CR-NL.) s -5 646 M -( 73 OCRNL Translate carriage return to newline \(output\).) s -5 635 M -( 74 ONOCR Translate newline to carriage return-newline) s -5 624 M -( \(output\).) s -5 613 M -( 75 ONLRET Newline performs a carriage return \(output\).) s -5 602 M -( 90 CS7 7 bit mode.) s -5 591 M -( 91 CS8 8 bit mode.) s -5 580 M -( 92 PARENB Parity enable.) s -5 569 M -( 93 PARODD Odd parity, else even.) s -5 547 M -( 128 TTY_OP_ISPEED Specifies the input baud rate in bits per second.) s -5 536 M -( 129 TTY_OP_OSPEED Specifies the output baud rate in bits per second.) s -5 503 M -(9. Summary of Message Numbers) s -5 481 M -( #define SSH_MSG_GLOBAL_REQUEST 80) s -5 470 M -( #define SSH_MSG_REQUEST_SUCCESS 81) s -5 459 M -( #define SSH_MSG_REQUEST_FAILURE 82) s -5 448 M -( #define SSH_MSG_CHANNEL_OPEN 90) s -5 437 M -( #define SSH_MSG_CHANNEL_OPEN_CONFIRMATION 91) s -5 426 M -( #define SSH_MSG_CHANNEL_OPEN_FAILURE 92) s -5 415 M -( #define SSH_MSG_CHANNEL_WINDOW_ADJUST 93) s -5 404 M -( #define SSH_MSG_CHANNEL_DATA 94) s -5 393 M -( #define SSH_MSG_CHANNEL_EXTENDED_DATA 95) s -5 382 M -( #define SSH_MSG_CHANNEL_EOF 96) s -5 371 M -( #define SSH_MSG_CHANNEL_CLOSE 97) s -5 360 M -( #define SSH_MSG_CHANNEL_REQUEST 98) s -5 349 M -( #define SSH_MSG_CHANNEL_SUCCESS 99) s -5 338 M -( #define SSH_MSG_CHANNEL_FAILURE 100) s -5 305 M -(10. Security Considerations) s -5 283 M -( This protocol is assumed to run on top of a secure, authenticated) s -5 272 M -( transport. User authentication and protection against network-level) s -5 261 M -( attacks are assumed to be provided by the underlying protocols.) s -5 239 M -( It is RECOMMENDED that implementations disable all the potentially) s -5 228 M -( dangerous features \(e.g. agent forwarding, X11 forwarding, and TCP/IP) s -5 217 M -( forwarding\) if the host key has changed.) s -5 195 M -( Full security considerations for this protocol are provided in) s -5 184 M -( Section 8 of [SSH-ARCH]) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 18]) s -_R -S -PStoPSsaved restore -%%Page: (18,19) 10 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 19 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Connection Protocol Oct 2003) s -5 690 M -(11. iana cONSiderations) s -5 668 M -( This document is part of a set, the IANA considerations for the SSH) s -5 657 M -( protocol as defined in [SSH-ARCH], [SSH-TRANS], [SSH-USERAUTH],) s -5 646 M -( [SSH-CONNECT] are detailed in [SSH-NUMBERS].) s -5 624 M -(12. Intellectual Property) s -5 602 M -( The IETF takes no position regarding the validity or scope of any) s -5 591 M -( intellectual property or other rights that might be claimed to) s -5 580 M -( pertain to the implementation or use of the technology described in) s -5 569 M -( this document or the extent to which any license under such rights) s -5 558 M -( might or might not be available; neither does it represent that it) s -5 547 M -( has made any effort to identify any such rights. Information on the) s -5 536 M -( IETF's procedures with respect to rights in standards-track and) s -5 525 M -( standards-related documentation can be found in BCP-11. Copies of) s -5 514 M -( claims of rights made available for publication and any assurances of) s -5 503 M -( licenses to be made available, or the result of an attempt made to) s -5 492 M -( obtain a general license or permission for the use of such) s -5 481 M -( proprietary rights by implementers or users of this specification can) s -5 470 M -( be obtained from the IETF Secretariat.) s -5 448 M -( The IETF has been notified of intellectual property rights claimed in) s -5 437 M -( regard to some or all of the specification contained in this) s -5 426 M -( document. For more information consult the online list of claimed) s -5 415 M -( rights.) s -5 393 M -(Normative References) s -5 371 M -( [SSH-ARCH]) s -5 360 M -( Ylonen, T., "SSH Protocol Architecture", I-D) s -5 349 M -( draft-ietf-architecture-15.txt, Oct 2003.) s -5 327 M -( [SSH-TRANS]) s -5 316 M -( Ylonen, T., "SSH Transport Layer Protocol", I-D) s -5 305 M -( draft-ietf-transport-17.txt, Oct 2003.) s -5 283 M -( [SSH-USERAUTH]) s -5 272 M -( Ylonen, T., "SSH Authentication Protocol", I-D) s -5 261 M -( draft-ietf-userauth-18.txt, Oct 2003.) s -5 239 M -( [SSH-CONNECT]) s -5 228 M -( Ylonen, T., "SSH Connection Protocol", I-D) s -5 217 M -( draft-ietf-connect-18.txt, Oct 2003.) s -5 195 M -( [SSH-NUMBERS]) s -5 184 M -( Lehtinen, S. and D. Moffat, "SSH Protocol Assigned) s -5 173 M -( Numbers", I-D draft-ietf-secsh-assignednumbers-05.txt, Oct) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 19]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 20 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Connection Protocol Oct 2003) s -5 690 M -( 2003.) s -5 668 M -( [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate) s -5 657 M -( Requirement Levels", BCP 14, RFC 2119, March 1997.) s -5 635 M -(Informative References) s -5 613 M -( [RFC3066] Alvestrand, H., "Tags for the Identification of) s -5 602 M -( Languages", BCP 47, RFC 3066, January 2001.) s -5 580 M -( [RFC1884] Hinden, R. and S. Deering, "IP Version 6 Addressing) s -5 569 M -( Architecture", RFC 1884, December 1995.) s -5 547 M -( [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO) s -5 536 M -( 10646", RFC 2279, January 1998.) s -5 514 M -( [SCHEIFLER]) s -5 503 M -( Scheifler, R., "X Window System : The Complete Reference) s -5 492 M -( to Xlib, X Protocol, Icccm, Xlfd, 3rd edition.", Digital) s -5 481 M -( Press ISBN 1555580882, Feburary 1992.) s -5 459 M -( [POSIX] ISO/IEC, 9945-1., "Information technology -- Portable) s -5 448 M -( Operating System Interface \(POSIX\)-Part 1: System) s -5 437 M -( Application Program Interface \(API\) C Language", ANSI/IEE) s -5 426 M -( Std 1003.1, July 1996.) s -5 393 M -(Authors' Addresses) s -5 371 M -( Tatu Ylonen) s -5 360 M -( SSH Communications Security Corp) s -5 349 M -( Fredrikinkatu 42) s -5 338 M -( HELSINKI FIN-00100) s -5 327 M -( Finland) s -5 305 M -( EMail: [email protected]) s -5 272 M -( Darren J. Moffat \(editor\)) s -5 261 M -( Sun Microsystems, Inc) s -5 250 M -( 17 Network Circle) s -5 239 M -( Menlo Park CA 94025) s -5 228 M -( USA) s -5 206 M -( EMail: [email protected]) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 20]) s -_R -S -PStoPSsaved restore -%%Page: (20,21) 11 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 21 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Connection Protocol Oct 2003) s -5 690 M -(Intellectual Property Statement) s -5 668 M -( The IETF takes no position regarding the validity or scope of any) s -5 657 M -( intellectual property or other rights that might be claimed to) s -5 646 M -( pertain to the implementation or use of the technology described in) s -5 635 M -( this document or the extent to which any license under such rights) s -5 624 M -( might or might not be available; neither does it represent that it) s -5 613 M -( has made any effort to identify any such rights. Information on the) s -5 602 M -( IETF's procedures with respect to rights in standards-track and) s -5 591 M -( standards-related documentation can be found in BCP-11. Copies of) s -5 580 M -( claims of rights made available for publication and any assurances of) s -5 569 M -( licenses to be made available, or the result of an attempt made to) s -5 558 M -( obtain a general license or permission for the use of such) s -5 547 M -( proprietary rights by implementors or users of this specification can) s -5 536 M -( be obtained from the IETF Secretariat.) s -5 514 M -( The IETF invites any interested party to bring to its attention any) s -5 503 M -( copyrights, patents or patent applications, or other proprietary) s -5 492 M -( rights which may cover technology that may be required to practice) s -5 481 M -( this standard. Please address the information to the IETF Executive) s -5 470 M -( Director.) s -5 448 M -( The IETF has been notified of intellectual property rights claimed in) s -5 437 M -( regard to some or all of the specification contained in this) s -5 426 M -( document. For more information consult the online list of claimed) s -5 415 M -( rights.) s -5 382 M -(Full Copyright Statement) s -5 360 M -( Copyright \(C\) The Internet Society \(2003\). All Rights Reserved.) s -5 338 M -( This document and translations of it may be copied and furnished to) s -5 327 M -( others, and derivative works that comment on or otherwise explain it) s -5 316 M -( or assist in its implementation may be prepared, copied, published) s -5 305 M -( and distributed, in whole or in part, without restriction of any) s -5 294 M -( kind, provided that the above copyright notice and this paragraph are) s -5 283 M -( included on all such copies and derivative works. However, this) s -5 272 M -( document itself may not be modified in any way, such as by removing) s -5 261 M -( the copyright notice or references to the Internet Society or other) s -5 250 M -( Internet organizations, except as needed for the purpose of) s -5 239 M -( developing Internet standards in which case the procedures for) s -5 228 M -( copyrights defined in the Internet Standards process must be) s -5 217 M -( followed, or as required to translate it into languages other than) s -5 206 M -( English.) s -5 184 M -( The limited permissions granted above are perpetual and will not be) s -5 173 M -( revoked by the Internet Society or its successors or assignees.) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 21]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 22 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Connection Protocol Oct 2003) s -5 690 M -( This document and the information contained herein is provided on an) s -5 679 M -( "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING) s -5 668 M -( TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING) s -5 657 M -( BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION) s -5 646 M -( HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF) s -5 635 M -( MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.) s -5 602 M -(Acknowledgment) s -5 580 M -( Funding for the RFC Editor function is currently provided by the) s -5 569 M -( Internet Society.) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 22]) s -_R -S -PStoPSsaved restore -%%Trailer -%%Pages: 22 -%%DocumentNeededResources: font Courier-Bold Courier -%%EOF diff --git a/lib/ssh/doc/standard/draft-ietf-secsh-connect-18.txt b/lib/ssh/doc/standard/draft-ietf-secsh-connect-18.txt deleted file mode 100644 index 1cb8ad6409..0000000000 --- a/lib/ssh/doc/standard/draft-ietf-secsh-connect-18.txt +++ /dev/null @@ -1,1232 +0,0 @@ - - - -Network Working Group T. Ylonen -Internet-Draft SSH Communications Security Corp -Expires: March 31, 2004 D. Moffat, Editor, Ed. - Sun Microsystems, Inc - Oct 2003 - - - SSH Connection Protocol - draft-ietf-secsh-connect-18.txt - -Status of this Memo - - This document is an Internet-Draft and is in full conformance with - all provisions of Section 10 of RFC2026. - - Internet-Drafts are working documents of the Internet Engineering - Task Force (IETF), its areas, and its working groups. Note that other - groups may also distribute working documents as Internet-Drafts. - - Internet-Drafts are draft documents valid for a maximum of six months - and may be updated, replaced, or obsoleted by other documents at any - time. It is inappropriate to use Internet-Drafts as reference - material or to cite them other than as "work in progress." - - The list of current Internet-Drafts can be accessed at http:// - www.ietf.org/ietf/1id-abstracts.txt. - - The list of Internet-Draft Shadow Directories can be accessed at - http://www.ietf.org/shadow.html. - - This Internet-Draft will expire on March 31, 2004. - -Copyright Notice - - Copyright (C) The Internet Society (2003). All Rights Reserved. - -Abstract - - SSH is a protocol for secure remote login and other secure network - services over an insecure network. - - This document describes the SSH Connection Protocol. It provides - interactive login sessions, remote execution of commands, forwarded - TCP/IP connections, and forwarded X11 connections. All of these - channels are multiplexed into a single encrypted tunnel. - - The SSH Connection Protocol has been designed to run on top of the - SSH transport layer and user authentication protocols. - - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 1] - -Internet-Draft SSH Connection Protocol Oct 2003 - - -Table of Contents - - 1. Contributors . . . . . . . . . . . . . . . . . . . . . . . . 3 - 2. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 - 3. Conventions Used in This Document . . . . . . . . . . . . . 3 - 4. Global Requests . . . . . . . . . . . . . . . . . . . . . . 3 - 5. Channel Mechanism . . . . . . . . . . . . . . . . . . . . . 4 - 5.1 Opening a Channel . . . . . . . . . . . . . . . . . . . . . 4 - 5.2 Data Transfer . . . . . . . . . . . . . . . . . . . . . . . 5 - 5.3 Closing a Channel . . . . . . . . . . . . . . . . . . . . . 6 - 5.4 Channel-Specific Requests . . . . . . . . . . . . . . . . . 7 - 6. Interactive Sessions . . . . . . . . . . . . . . . . . . . . 8 - 6.1 Opening a Session . . . . . . . . . . . . . . . . . . . . . 8 - 6.2 Requesting a Pseudo-Terminal . . . . . . . . . . . . . . . . 8 - 6.3 X11 Forwarding . . . . . . . . . . . . . . . . . . . . . . . 9 - 6.3.1 Requesting X11 Forwarding . . . . . . . . . . . . . . . . . 9 - 6.3.2 X11 Channels . . . . . . . . . . . . . . . . . . . . . . . . 10 - 6.4 Environment Variable Passing . . . . . . . . . . . . . . . . 10 - 6.5 Starting a Shell or a Command . . . . . . . . . . . . . . . 10 - 6.6 Session Data Transfer . . . . . . . . . . . . . . . . . . . 11 - 6.7 Window Dimension Change Message . . . . . . . . . . . . . . 12 - 6.8 Local Flow Control . . . . . . . . . . . . . . . . . . . . . 12 - 6.9 Signals . . . . . . . . . . . . . . . . . . . . . . . . . . 12 - 6.10 Returning Exit Status . . . . . . . . . . . . . . . . . . . 13 - 7. TCP/IP Port Forwarding . . . . . . . . . . . . . . . . . . . 14 - 7.1 Requesting Port Forwarding . . . . . . . . . . . . . . . . . 14 - 7.2 TCP/IP Forwarding Channels . . . . . . . . . . . . . . . . . 15 - 8. Encoding of Terminal Modes . . . . . . . . . . . . . . . . . 16 - 9. Summary of Message Numbers . . . . . . . . . . . . . . . . . 18 - 10. Security Considerations . . . . . . . . . . . . . . . . . . 18 - 11. iana cONSiderations . . . . . . . . . . . . . . . . . . . . 19 - 12. Intellectual Property . . . . . . . . . . . . . . . . . . . 19 - Normative References . . . . . . . . . . . . . . . . . . . . 19 - Informative References . . . . . . . . . . . . . . . . . . . 20 - Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 20 - Intellectual Property and Copyright Statements . . . . . . . 21 - - - - - - - - - - - - - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 2] - -Internet-Draft SSH Connection Protocol Oct 2003 - - -1. Contributors - - The major original contributors of this document were: Tatu Ylonen, - Tero Kivinen, Timo J. Rinne, Sami Lehtinen (all of SSH Communications - Security Corp), and Markku-Juhani O. Saarinen (University of - Jyvaskyla) - - The document editor is: [email protected]. Comments on this - internet draft should be sent to the IETF SECSH working group, - details at: http://ietf.org/html.charters/secsh-charter.html - -2. Introduction - - The SSH Connection Protocol has been designed to run on top of the - SSH transport layer and user authentication protocols. It provides - interactive login sessions, remote execution of commands, forwarded - TCP/IP connections, and forwarded X11 connections. The service name - for this protocol is "ssh-connection". - - This document should be read only after reading the SSH architecture - document [SSH-ARCH]. This document freely uses terminology and - notation from the architecture document without reference or further - explanation. - -3. Conventions Used in This Document - - The keywords "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT", - and "MAY" that appear in this document are to be interpreted as - described in [RFC2119]. - - The used data types and terminology are specified in the architecture - document [SSH-ARCH]. - - The architecture document also discusses the algorithm naming - conventions that MUST be used with the SSH protocols. - -4. Global Requests - - There are several kinds of requests that affect the state of the - remote end "globally", independent of any channels. An example is a - request to start TCP/IP forwarding for a specific port. All such - requests use the following format. - - byte SSH_MSG_GLOBAL_REQUEST - string request name (restricted to US-ASCII) - boolean want reply - ... request-specific data follows - - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 3] - -Internet-Draft SSH Connection Protocol Oct 2003 - - - Request names follow the DNS extensibility naming convention outlined - in [SSH-ARCH]. - - The recipient will respond to this message with - SSH_MSG_REQUEST_SUCCESS or SSH_MSG_REQUEST_FAILURE if `want reply' is - TRUE. - - byte SSH_MSG_REQUEST_SUCCESS - ..... response specific data - - Usually the response specific data is non-existent. - - If the recipient does not recognize or support the request, it simply - responds with SSH_MSG_REQUEST_FAILURE. - - byte SSH_MSG_REQUEST_FAILURE - - -5. Channel Mechanism - - All terminal sessions, forwarded connections, etc. are channels. - Either side may open a channel. Multiple channels are multiplexed - into a single connection. - - Channels are identified by numbers at each end. The number referring - to a channel may be different on each side. Requests to open a - channel contain the sender's channel number. Any other - channel-related messages contain the recipient's channel number for - the channel. - - Channels are flow-controlled. No data may be sent to a channel until - a message is received to indicate that window space is available. - -5.1 Opening a Channel - - When either side wishes to open a new channel, it allocates a local - number for the channel. It then sends the following message to the - other side, and includes the local channel number and initial window - size in the message. - - byte SSH_MSG_CHANNEL_OPEN - string channel type (restricted to US-ASCII) - uint32 sender channel - uint32 initial window size - uint32 maximum packet size - ... channel type specific data follows - - The channel type is a name as described in the SSH architecture - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 4] - -Internet-Draft SSH Connection Protocol Oct 2003 - - - document, with similar extension mechanisms. `sender channel' is a - local identifier for the channel used by the sender of this message. - `initial window size' specifies how many bytes of channel data can be - sent to the sender of this message without adjusting the window. - `Maximum packet size' specifies the maximum size of an individual - data packet that can be sent to the sender (for example, one might - want to use smaller packets for interactive connections to get better - interactive response on slow links). - - The remote side then decides whether it can open the channel, and - responds with either - - byte SSH_MSG_CHANNEL_OPEN_CONFIRMATION - uint32 recipient channel - uint32 sender channel - uint32 initial window size - uint32 maximum packet size - ... channel type specific data follows - - where `recipient channel' is the channel number given in the original - open request, and `sender channel' is the channel number allocated by - the other side, or - - byte SSH_MSG_CHANNEL_OPEN_FAILURE - uint32 recipient channel - uint32 reason code - string additional textual information (ISO-10646 UTF-8 [RFC2279]) - string language tag (as defined in [RFC3066]) - - If the recipient of the SSH_MSG_CHANNEL_OPEN message does not support - the specified channel type, it simply responds with - SSH_MSG_CHANNEL_OPEN_FAILURE. The client MAY show the additional - information to the user. If this is done, the client software should - take the precautions discussed in [SSH-ARCH]. - - The following reason codes are defined: - - #define SSH_OPEN_ADMINISTRATIVELY_PROHIBITED 1 - #define SSH_OPEN_CONNECT_FAILED 2 - #define SSH_OPEN_UNKNOWN_CHANNEL_TYPE 3 - #define SSH_OPEN_RESOURCE_SHORTAGE 4 - - -5.2 Data Transfer - - The window size specifies how many bytes the other party can send - before it must wait for the window to be adjusted. Both parties use - the following message to adjust the window. - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 5] - -Internet-Draft SSH Connection Protocol Oct 2003 - - - byte SSH_MSG_CHANNEL_WINDOW_ADJUST - uint32 recipient channel - uint32 bytes to add - - After receiving this message, the recipient MAY send the given number - of bytes more than it was previously allowed to send; the window size - is incremented. - - Data transfer is done with messages of the following type. - - byte SSH_MSG_CHANNEL_DATA - uint32 recipient channel - string data - - The maximum amount of data allowed is the current window size. The - window size is decremented by the amount of data sent. Both parties - MAY ignore all extra data sent after the allowed window is empty. - - Additionally, some channels can transfer several types of data. An - example of this is stderr data from interactive sessions. Such data - can be passed with SSH_MSG_CHANNEL_EXTENDED_DATA messages, where a - separate integer specifies the type of the data. The available types - and their interpretation depend on the type of the channel. - - byte SSH_MSG_CHANNEL_EXTENDED_DATA - uint32 recipient_channel - uint32 data_type_code - string data - - Data sent with these messages consumes the same window as ordinary - data. - - Currently, only the following type is defined. - - #define SSH_EXTENDED_DATA_STDERR 1 - - -5.3 Closing a Channel - - When a party will no longer send more data to a channel, it SHOULD - send SSH_MSG_CHANNEL_EOF. - - byte SSH_MSG_CHANNEL_EOF - uint32 recipient_channel - - No explicit response is sent to this message; however, the - application may send EOF to whatever is at the other end of the - channel. Note that the channel remains open after this message, and - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 6] - -Internet-Draft SSH Connection Protocol Oct 2003 - - - more data may still be sent in the other direction. This message - does not consume window space and can be sent even if no window space - is available. - - When either party wishes to terminate the channel, it sends - SSH_MSG_CHANNEL_CLOSE. Upon receiving this message, a party MUST - send back a SSH_MSG_CHANNEL_CLOSE unless it has already sent this - message for the channel. The channel is considered closed for a - party when it has both sent and received SSH_MSG_CHANNEL_CLOSE, and - the party may then reuse the channel number. A party MAY send - SSH_MSG_CHANNEL_CLOSE without having sent or received - SSH_MSG_CHANNEL_EOF. - - byte SSH_MSG_CHANNEL_CLOSE - uint32 recipient_channel - - This message does not consume window space and can be sent even if no - window space is available. - - It is recommended that any data sent before this message is delivered - to the actual destination, if possible. - -5.4 Channel-Specific Requests - - Many channel types have extensions that are specific to that - particular channel type. An example is requesting a pty (pseudo - terminal) for an interactive session. - - All channel-specific requests use the following format. - - byte SSH_MSG_CHANNEL_REQUEST - uint32 recipient channel - string request type (restricted to US-ASCII) - boolean want reply - ... type-specific data - - If want reply is FALSE, no response will be sent to the request. - Otherwise, the recipient responds with either SSH_MSG_CHANNEL_SUCCESS - or SSH_MSG_CHANNEL_FAILURE, or request-specific continuation - messages. If the request is not recognized or is not supported for - the channel, SSH_MSG_CHANNEL_FAILURE is returned. - - This message does not consume window space and can be sent even if no - window space is available. Request types are local to each channel - type. - - The client is allowed to send further messages without waiting for - the response to the request. - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 7] - -Internet-Draft SSH Connection Protocol Oct 2003 - - - request type names follow the DNS extensibility naming convention - outlined in [SSH-ARCH] - - byte SSH_MSG_CHANNEL_SUCCESS - uint32 recipient_channel - - - byte SSH_MSG_CHANNEL_FAILURE - uint32 recipient_channel - - These messages do not consume window space and can be sent even if no - window space is available. - -6. Interactive Sessions - - A session is a remote execution of a program. The program may be a - shell, an application, a system command, or some built-in subsystem. - It may or may not have a tty, and may or may not involve X11 - forwarding. Multiple sessions can be active simultaneously. - -6.1 Opening a Session - - A session is started by sending the following message. - - byte SSH_MSG_CHANNEL_OPEN - string "session" - uint32 sender channel - uint32 initial window size - uint32 maximum packet size - - Client implementations SHOULD reject any session channel open - requests to make it more difficult for a corrupt server to attack the - client. - -6.2 Requesting a Pseudo-Terminal - - A pseudo-terminal can be allocated for the session by sending the - following message. - - byte SSH_MSG_CHANNEL_REQUEST - uint32 recipient_channel - string "pty-req" - boolean want_reply - string TERM environment variable value (e.g., vt100) - uint32 terminal width, characters (e.g., 80) - uint32 terminal height, rows (e.g., 24) - uint32 terminal width, pixels (e.g., 640) - uint32 terminal height, pixels (e.g., 480) - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 8] - -Internet-Draft SSH Connection Protocol Oct 2003 - - - string encoded terminal modes - - The encoding of terminal modes is described in Section Encoding of - Terminal Modes (Section 8). Zero dimension parameters MUST be - ignored. The character/row dimensions override the pixel dimensions - (when nonzero). Pixel dimensions refer to the drawable area of the - window. - - The dimension parameters are only informational. - - The client SHOULD ignore pty requests. - -6.3 X11 Forwarding - -6.3.1 Requesting X11 Forwarding - - X11 forwarding may be requested for a session by sending - - byte SSH_MSG_CHANNEL_REQUEST - uint32 recipient channel - string "x11-req" - boolean want reply - boolean single connection - string x11 authentication protocol - string x11 authentication cookie - uint32 x11 screen number - - It is recommended that the authentication cookie that is sent be a - fake, random cookie, and that the cookie is checked and replaced by - the real cookie when a connection request is received. - - X11 connection forwarding should stop when the session channel is - closed; however, already opened forwardings should not be - automatically closed when the session channel is closed. - - If `single connection' is TRUE, only a single connection should be - forwarded. No more connections will be forwarded after the first, or - after the session channel has been closed. - - The "x11 authentication protocol" is the name of the X11 - authentication method used, e.g. "MIT-MAGIC-COOKIE-1". - - The x11 authentication cookie MUST be hexadecimal encoded. - - X Protocol is documented in [SCHEIFLER]. - - - - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 9] - -Internet-Draft SSH Connection Protocol Oct 2003 - - -6.3.2 X11 Channels - - X11 channels are opened with a channel open request. The resulting - channels are independent of the session, and closing the session - channel does not close the forwarded X11 channels. - - byte SSH_MSG_CHANNEL_OPEN - string "x11" - uint32 sender channel - uint32 initial window size - uint32 maximum packet size - string originator address (e.g. "192.168.7.38") - uint32 originator port - - The recipient should respond with SSH_MSG_CHANNEL_OPEN_CONFIRMATION - or SSH_MSG_CHANNEL_OPEN_FAILURE. - - Implementations MUST reject any X11 channel open requests if they - have not requested X11 forwarding. - -6.4 Environment Variable Passing - - Environment variables may be passed to the shell/command to be - started later. Uncontrolled setting of environment variables in a - privileged process can be a security hazard. It is recommended that - implementations either maintain a list of allowable variable names or - only set environment variables after the server process has dropped - sufficient privileges. - - byte SSH_MSG_CHANNEL_REQUEST - uint32 recipient channel - string "env" - boolean want reply - string variable name - string variable value - - -6.5 Starting a Shell or a Command - - Once the session has been set up, a program is started at the remote - end. The program can be a shell, an application program or a - subsystem with a host-independent name. Only one of these requests - can succeed per channel. - - byte SSH_MSG_CHANNEL_REQUEST - uint32 recipient channel - string "shell" - boolean want reply - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 10] - -Internet-Draft SSH Connection Protocol Oct 2003 - - - This message will request the user's default shell (typically defined - in /etc/passwd in UNIX systems) to be started at the other end. - - byte SSH_MSG_CHANNEL_REQUEST - uint32 recipient channel - string "exec" - boolean want reply - string command - - This message will request the server to start the execution of the - given command. The command string may contain a path. Normal - precautions MUST be taken to prevent the execution of unauthorized - commands. - - byte SSH_MSG_CHANNEL_REQUEST - uint32 recipient channel - string "subsystem" - boolean want reply - string subsystem name - - This last form executes a predefined subsystem. It is expected that - these will include a general file transfer mechanism, and possibly - other features. Implementations may also allow configuring more such - mechanisms. As the user's shell is usually used to execute the - subsystem, it is advisable for the subsystem protocol to have a - "magic cookie" at the beginning of the protocol transaction to - distinguish it from arbitrary output generated by shell - initialization scripts etc. This spurious output from the shell may - be filtered out either at the server or at the client. - - The server SHOULD not halt the execution of the protocol stack when - starting a shell or a program. All input and output from these SHOULD - be redirected to the channel or to the encrypted tunnel. - - It is RECOMMENDED to request and check the reply for these messages. - The client SHOULD ignore these messages. - - Subsystem names follow the DNS extensibility naming convention - outlined in [SSH-ARCH]. - -6.6 Session Data Transfer - - Data transfer for a session is done using SSH_MSG_CHANNEL_DATA and - SSH_MSG_CHANNEL_EXTENDED_DATA packets and the window mechanism. The - extended data type SSH_EXTENDED_DATA_STDERR has been defined for - stderr data. - - - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 11] - -Internet-Draft SSH Connection Protocol Oct 2003 - - -6.7 Window Dimension Change Message - - When the window (terminal) size changes on the client side, it MAY - send a message to the other side to inform it of the new dimensions. - - byte SSH_MSG_CHANNEL_REQUEST - uint32 recipient_channel - string "window-change" - boolean FALSE - uint32 terminal width, columns - uint32 terminal height, rows - uint32 terminal width, pixels - uint32 terminal height, pixels - - No response SHOULD be sent to this message. - -6.8 Local Flow Control - - On many systems, it is possible to determine if a pseudo-terminal is - using control-S/control-Q flow control. When flow control is - allowed, it is often desirable to do the flow control at the client - end to speed up responses to user requests. This is facilitated by - the following notification. Initially, the server is responsible for - flow control. (Here, again, client means the side originating the - session, and server means the other side.) - - The message below is used by the server to inform the client when it - can or cannot perform flow control (control-S/control-Q processing). - If `client can do' is TRUE, the client is allowed to do flow control - using control-S and control-Q. The client MAY ignore this message. - - byte SSH_MSG_CHANNEL_REQUEST - uint32 recipient channel - string "xon-xoff" - boolean FALSE - boolean client can do - - No response is sent to this message. - -6.9 Signals - - A signal can be delivered to the remote process/service using the - following message. Some systems may not implement signals, in which - case they SHOULD ignore this message. - - byte SSH_MSG_CHANNEL_REQUEST - uint32 recipient channel - string "signal" - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 12] - -Internet-Draft SSH Connection Protocol Oct 2003 - - - boolean FALSE - string signal name without the "SIG" prefix. - - Signal names will be encoded as discussed in the "exit-signal" - SSH_MSG_CHANNEL_REQUEST. - -6.10 Returning Exit Status - - When the command running at the other end terminates, the following - message can be sent to return the exit status of the command. - Returning the status is RECOMMENDED. No acknowledgment is sent for - this message. The channel needs to be closed with - SSH_MSG_CHANNEL_CLOSE after this message. - - The client MAY ignore these messages. - - byte SSH_MSG_CHANNEL_REQUEST - uint32 recipient_channel - string "exit-status" - boolean FALSE - uint32 exit_status - - The remote command may also terminate violently due to a signal. - Such a condition can be indicated by the following message. A zero - exit_status usually means that the command terminated successfully. - - byte SSH_MSG_CHANNEL_REQUEST - uint32 recipient channel - string "exit-signal" - boolean FALSE - string signal name without the "SIG" prefix. - boolean core dumped - string error message (ISO-10646 UTF-8) - string language tag (as defined in [RFC3066]) - - The signal name is one of the following (these are from [POSIX]) - - ABRT - ALRM - FPE - HUP - ILL - INT - KILL - PIPE - QUIT - SEGV - TERM - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 13] - -Internet-Draft SSH Connection Protocol Oct 2003 - - - USR1 - USR2 - - Additional signal names MAY be sent in the format "sig-name@xyz", - where `sig-name' and `xyz' may be anything a particular implementor - wants (except the `@' sign). However, it is suggested that if a - `configure' script is used, the non-standard signal names it finds be - encoded as "[email protected]", where `SIG' is the signal name - without the "SIG" prefix, and `xyz' be the host type, as determined - by `config.guess'. - - The `error message' contains an additional explanation of the error - message. The message may consist of multiple lines. The client - software MAY display this message to the user. If this is done, the - client software should take the precautions discussed in [SSH-ARCH]. - -7. TCP/IP Port Forwarding - -7.1 Requesting Port Forwarding - - A party need not explicitly request forwardings from its own end to - the other direction. However, if it wishes that connections to a - port on the other side be forwarded to the local side, it must - explicitly request this. - - - byte SSH_MSG_GLOBAL_REQUEST - string "tcpip-forward" - boolean want reply - string address to bind (e.g. "0.0.0.0") - uint32 port number to bind - - `Address to bind' and `port number to bind' specify the IP address - and port to which the socket to be listened is bound. The address - should be "0.0.0.0" if connections are allowed from anywhere. (Note - that the client can still filter connections based on information - passed in the open request.) - - Implementations should only allow forwarding privileged ports if the - user has been authenticated as a privileged user. - - Client implementations SHOULD reject these messages; they are - normally only sent by the client. - - - If a client passes 0 as port number to bind and has want reply TRUE - then the server allocates the next available unprivileged port number - and replies with the following message, otherwise there is no - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 14] - -Internet-Draft SSH Connection Protocol Oct 2003 - - - response specific data. - - - byte SSH_MSG_GLOBAL_REQUEST_SUCCESS - uint32 port that was bound on the server - - A port forwarding can be cancelled with the following message. Note - that channel open requests may be received until a reply to this - message is received. - - byte SSH_MSG_GLOBAL_REQUEST - string "cancel-tcpip-forward" - boolean want reply - string address_to_bind (e.g. "127.0.0.1") - uint32 port number to bind - - Client implementations SHOULD reject these messages; they are - normally only sent by the client. - -7.2 TCP/IP Forwarding Channels - - When a connection comes to a port for which remote forwarding has - been requested, a channel is opened to forward the port to the other - side. - - byte SSH_MSG_CHANNEL_OPEN - string "forwarded-tcpip" - uint32 sender channel - uint32 initial window size - uint32 maximum packet size - string address that was connected - uint32 port that was connected - string originator IP address - uint32 originator port - - Implementations MUST reject these messages unless they have - previously requested a remote TCP/IP port forwarding with the given - port number. - - When a connection comes to a locally forwarded TCP/IP port, the - following packet is sent to the other side. Note that these messages - MAY be sent also for ports for which no forwarding has been - explicitly requested. The receiving side must decide whether to - allow the forwarding. - - byte SSH_MSG_CHANNEL_OPEN - string "direct-tcpip" - uint32 sender channel - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 15] - -Internet-Draft SSH Connection Protocol Oct 2003 - - - uint32 initial window size - uint32 maximum packet size - string host to connect - uint32 port to connect - string originator IP address - uint32 originator port - - `Host to connect' and `port to connect' specify the TCP/IP host and - port where the recipient should connect the channel. `Host to - connect' may be either a domain name or a numeric IP address. - - `Originator IP address' is the numeric IP address of the machine - where the connection request comes from, and `originator port' is the - port on the originator host from where the connection came from. - - Forwarded TCP/IP channels are independent of any sessions, and - closing a session channel does not in any way imply that forwarded - connections should be closed. - - Client implementations SHOULD reject direct TCP/IP open requests for - security reasons. - -8. Encoding of Terminal Modes - - Terminal modes (as passed in a pty request) are encoded into a byte - stream. It is intended that the coding be portable across different - environments. - - The tty mode description is a stream of bytes. The stream consists - of opcode-argument pairs. It is terminated by opcode TTY_OP_END (0). - Opcodes 1 to 159 have a single uint32 argument. Opcodes 160 to 255 - are not yet defined, and cause parsing to stop (they should only be - used after any other data). - - The client SHOULD put in the stream any modes it knows about, and the - server MAY ignore any modes it does not know about. This allows some - degree of machine-independence, at least between systems that use a - POSIX-like tty interface. The protocol can support other systems as - well, but the client may need to fill reasonable values for a number - of parameters so the server pty gets set to a reasonable mode (the - server leaves all unspecified mode bits in their default values, and - only some combinations make sense). - - The following opcodes have been defined. The naming of opcodes - mostly follows the POSIX terminal mode flags. - - 0 TTY_OP_END Indicates end of options. - 1 VINTR Interrupt character; 255 if none. Similarly for the - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 16] - -Internet-Draft SSH Connection Protocol Oct 2003 - - - other characters. Not all of these characters are - supported on all systems. - 2 VQUIT The quit character (sends SIGQUIT signal on POSIX - systems). - 3 VERASE Erase the character to left of the cursor. - 4 VKILL Kill the current input line. - 5 VEOF End-of-file character (sends EOF from the terminal). - 6 VEOL End-of-line character in addition to carriage return - and/or linefeed. - 7 VEOL2 Additional end-of-line character. - 8 VSTART Continues paused output (normally control-Q). - 9 VSTOP Pauses output (normally control-S). - 10 VSUSP Suspends the current program. - 11 VDSUSP Another suspend character. - 12 VREPRINT Reprints the current input line. - 13 VWERASE Erases a word left of cursor. - 14 VLNEXT Enter the next character typed literally, even if it - is a special character - 15 VFLUSH Character to flush output. - 16 VSWTCH Switch to a different shell layer. - 17 VSTATUS Prints system status line (load, command, pid etc). - 18 VDISCARD Toggles the flushing of terminal output. - 30 IGNPAR The ignore parity flag. The parameter SHOULD be 0 if - this flag is FALSE set, and 1 if it is TRUE. - 31 PARMRK Mark parity and framing errors. - 32 INPCK Enable checking of parity errors. - 33 ISTRIP Strip 8th bit off characters. - 34 INLCR Map NL into CR on input. - 35 IGNCR Ignore CR on input. - 36 ICRNL Map CR to NL on input. - 37 IUCLC Translate uppercase characters to lowercase. - 38 IXON Enable output flow control. - 39 IXANY Any char will restart after stop. - 40 IXOFF Enable input flow control. - 41 IMAXBEL Ring bell on input queue full. - 50 ISIG Enable signals INTR, QUIT, [D]SUSP. - 51 ICANON Canonicalize input lines. - 52 XCASE Enable input and output of uppercase characters by - preceding their lowercase equivalents with `\'. - 53 ECHO Enable echoing. - 54 ECHOE Visually erase chars. - 55 ECHOK Kill character discards current line. - 56 ECHONL Echo NL even if ECHO is off. - 57 NOFLSH Don't flush after interrupt. - 58 TOSTOP Stop background jobs from output. - 59 IEXTEN Enable extensions. - 60 ECHOCTL Echo control characters as ^(Char). - 61 ECHOKE Visual erase for line kill. - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 17] - -Internet-Draft SSH Connection Protocol Oct 2003 - - - 62 PENDIN Retype pending input. - 70 OPOST Enable output processing. - 71 OLCUC Convert lowercase to uppercase. - 72 ONLCR Map NL to CR-NL. - 73 OCRNL Translate carriage return to newline (output). - 74 ONOCR Translate newline to carriage return-newline - (output). - 75 ONLRET Newline performs a carriage return (output). - 90 CS7 7 bit mode. - 91 CS8 8 bit mode. - 92 PARENB Parity enable. - 93 PARODD Odd parity, else even. - - 128 TTY_OP_ISPEED Specifies the input baud rate in bits per second. - 129 TTY_OP_OSPEED Specifies the output baud rate in bits per second. - - -9. Summary of Message Numbers - - #define SSH_MSG_GLOBAL_REQUEST 80 - #define SSH_MSG_REQUEST_SUCCESS 81 - #define SSH_MSG_REQUEST_FAILURE 82 - #define SSH_MSG_CHANNEL_OPEN 90 - #define SSH_MSG_CHANNEL_OPEN_CONFIRMATION 91 - #define SSH_MSG_CHANNEL_OPEN_FAILURE 92 - #define SSH_MSG_CHANNEL_WINDOW_ADJUST 93 - #define SSH_MSG_CHANNEL_DATA 94 - #define SSH_MSG_CHANNEL_EXTENDED_DATA 95 - #define SSH_MSG_CHANNEL_EOF 96 - #define SSH_MSG_CHANNEL_CLOSE 97 - #define SSH_MSG_CHANNEL_REQUEST 98 - #define SSH_MSG_CHANNEL_SUCCESS 99 - #define SSH_MSG_CHANNEL_FAILURE 100 - - -10. Security Considerations - - This protocol is assumed to run on top of a secure, authenticated - transport. User authentication and protection against network-level - attacks are assumed to be provided by the underlying protocols. - - It is RECOMMENDED that implementations disable all the potentially - dangerous features (e.g. agent forwarding, X11 forwarding, and TCP/IP - forwarding) if the host key has changed. - - Full security considerations for this protocol are provided in - Section 8 of [SSH-ARCH] - - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 18] - -Internet-Draft SSH Connection Protocol Oct 2003 - - -11. iana cONSiderations - - This document is part of a set, the IANA considerations for the SSH - protocol as defined in [SSH-ARCH], [SSH-TRANS], [SSH-USERAUTH], - [SSH-CONNECT] are detailed in [SSH-NUMBERS]. - -12. Intellectual Property - - The IETF takes no position regarding the validity or scope of any - intellectual property or other rights that might be claimed to - pertain to the implementation or use of the technology described in - this document or the extent to which any license under such rights - might or might not be available; neither does it represent that it - has made any effort to identify any such rights. Information on the - IETF's procedures with respect to rights in standards-track and - standards-related documentation can be found in BCP-11. Copies of - claims of rights made available for publication and any assurances of - licenses to be made available, or the result of an attempt made to - obtain a general license or permission for the use of such - proprietary rights by implementers or users of this specification can - be obtained from the IETF Secretariat. - - The IETF has been notified of intellectual property rights claimed in - regard to some or all of the specification contained in this - document. For more information consult the online list of claimed - rights. - -Normative References - - [SSH-ARCH] - Ylonen, T., "SSH Protocol Architecture", I-D - draft-ietf-architecture-15.txt, Oct 2003. - - [SSH-TRANS] - Ylonen, T., "SSH Transport Layer Protocol", I-D - draft-ietf-transport-17.txt, Oct 2003. - - [SSH-USERAUTH] - Ylonen, T., "SSH Authentication Protocol", I-D - draft-ietf-userauth-18.txt, Oct 2003. - - [SSH-CONNECT] - Ylonen, T., "SSH Connection Protocol", I-D - draft-ietf-connect-18.txt, Oct 2003. - - [SSH-NUMBERS] - Lehtinen, S. and D. Moffat, "SSH Protocol Assigned - Numbers", I-D draft-ietf-secsh-assignednumbers-05.txt, Oct - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 19] - -Internet-Draft SSH Connection Protocol Oct 2003 - - - 2003. - - [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate - Requirement Levels", BCP 14, RFC 2119, March 1997. - -Informative References - - [RFC3066] Alvestrand, H., "Tags for the Identification of - Languages", BCP 47, RFC 3066, January 2001. - - [RFC1884] Hinden, R. and S. Deering, "IP Version 6 Addressing - Architecture", RFC 1884, December 1995. - - [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO - 10646", RFC 2279, January 1998. - - [SCHEIFLER] - Scheifler, R., "X Window System : The Complete Reference - to Xlib, X Protocol, Icccm, Xlfd, 3rd edition.", Digital - Press ISBN 1555580882, Feburary 1992. - - [POSIX] ISO/IEC, 9945-1., "Information technology -- Portable - Operating System Interface (POSIX)-Part 1: System - Application Program Interface (API) C Language", ANSI/IEE - Std 1003.1, July 1996. - - -Authors' Addresses - - Tatu Ylonen - SSH Communications Security Corp - Fredrikinkatu 42 - HELSINKI FIN-00100 - Finland - - EMail: [email protected] - - - Darren J. Moffat (editor) - Sun Microsystems, Inc - 17 Network Circle - Menlo Park CA 94025 - USA - - EMail: [email protected] - - - - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 20] - -Internet-Draft SSH Connection Protocol Oct 2003 - - -Intellectual Property Statement - - The IETF takes no position regarding the validity or scope of any - intellectual property or other rights that might be claimed to - pertain to the implementation or use of the technology described in - this document or the extent to which any license under such rights - might or might not be available; neither does it represent that it - has made any effort to identify any such rights. Information on the - IETF's procedures with respect to rights in standards-track and - standards-related documentation can be found in BCP-11. Copies of - claims of rights made available for publication and any assurances of - licenses to be made available, or the result of an attempt made to - obtain a general license or permission for the use of such - proprietary rights by implementors or users of this specification can - be obtained from the IETF Secretariat. - - The IETF invites any interested party to bring to its attention any - copyrights, patents or patent applications, or other proprietary - rights which may cover technology that may be required to practice - this standard. Please address the information to the IETF Executive - Director. - - The IETF has been notified of intellectual property rights claimed in - regard to some or all of the specification contained in this - document. For more information consult the online list of claimed - rights. - - -Full Copyright Statement - - Copyright (C) The Internet Society (2003). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assignees. - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 21] - -Internet-Draft SSH Connection Protocol Oct 2003 - - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - - -Acknowledgment - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 22]
\ No newline at end of file diff --git a/lib/ssh/doc/standard/draft-ietf-secsh-filexfer-02.2.ps b/lib/ssh/doc/standard/draft-ietf-secsh-filexfer-02.2.ps deleted file mode 100644 index 06c91bf8cd..0000000000 --- a/lib/ssh/doc/standard/draft-ietf-secsh-filexfer-02.2.ps +++ /dev/null @@ -1,2853 +0,0 @@ -%!PS-Adobe-3.0 -%%BoundingBox: 75 0 595 747 -%%Title: Enscript Output -%%For: Magnus Thoang -%%Creator: GNU enscript 1.6.1 -%%CreationDate: Wed Nov 12 12:26:07 2003 -%%Orientation: Portrait -%%Pages: 15 0 -%%DocumentMedia: A4 595 842 0 () () -%%DocumentNeededResources: (atend) -%%EndComments -%%BeginProlog -%%BeginProcSet: PStoPS 1 15 -userdict begin -[/showpage/erasepage/copypage]{dup where{pop dup load - type/operatortype eq{1 array cvx dup 0 3 index cvx put - bind def}{pop}ifelse}{pop}ifelse}forall -[/letter/legal/executivepage/a4/a4small/b5/com10envelope - /monarchenvelope/c5envelope/dlenvelope/lettersmall/note - /folio/quarto/a5]{dup where{dup wcheck{exch{}put} - {pop{}def}ifelse}{pop}ifelse}forall -/setpagedevice {pop}bind 1 index where{dup wcheck{3 1 roll put} - {pop def}ifelse}{def}ifelse -/PStoPSmatrix matrix currentmatrix def -/PStoPSxform matrix def/PStoPSclip{clippath}def -/defaultmatrix{PStoPSmatrix exch PStoPSxform exch concatmatrix}bind def -/initmatrix{matrix defaultmatrix setmatrix}bind def -/initclip[{matrix currentmatrix PStoPSmatrix setmatrix - [{currentpoint}stopped{$error/newerror false put{newpath}} - {/newpath cvx 3 1 roll/moveto cvx 4 array astore cvx}ifelse] - {[/newpath cvx{/moveto cvx}{/lineto cvx} - {/curveto cvx}{/closepath cvx}pathforall]cvx exch pop} - stopped{$error/errorname get/invalidaccess eq{cleartomark - $error/newerror false put cvx exec}{stop}ifelse}if}bind aload pop - /initclip dup load dup type dup/operatortype eq{pop exch pop} - {dup/arraytype eq exch/packedarraytype eq or - {dup xcheck{exch pop aload pop}{pop cvx}ifelse} - {pop cvx}ifelse}ifelse - {newpath PStoPSclip clip newpath exec setmatrix} bind aload pop]cvx def -/initgraphics{initmatrix newpath initclip 1 setlinewidth - 0 setlinecap 0 setlinejoin []0 setdash 0 setgray - 10 setmiterlimit}bind def -end -%%EndProcSet -%%BeginResource: procset Enscript-Prolog 1.6 1 -% -% Procedures. -% - -/_S { % save current state - /_s save def -} def -/_R { % restore from saved state - _s restore -} def - -/S { % showpage protecting gstate - gsave - showpage - grestore -} bind def - -/MF { % fontname newfontname -> - make a new encoded font - /newfontname exch def - /fontname exch def - - /fontdict fontname findfont def - /newfont fontdict maxlength dict def - - fontdict { - exch - dup /FID eq { - % skip FID pair - pop pop - } { - % copy to the new font dictionary - exch newfont 3 1 roll put - } ifelse - } forall - - newfont /FontName newfontname put - - % insert only valid encoding vectors - encoding_vector length 256 eq { - newfont /Encoding encoding_vector put - } if - - newfontname newfont definefont pop -} def - -/SF { % fontname width height -> - set a new font - /height exch def - /width exch def - - findfont - [width 0 0 height 0 0] makefont setfont -} def - -/SUF { % fontname width height -> - set a new user font - /height exch def - /width exch def - - /F-gs-user-font MF - /F-gs-user-font width height SF -} def - -/M {moveto} bind def -/s {show} bind def - -/Box { % x y w h -> - define box path - /d_h exch def /d_w exch def /d_y exch def /d_x exch def - d_x d_y moveto - d_w 0 rlineto - 0 d_h rlineto - d_w neg 0 rlineto - closepath -} def - -/bgs { % x y height blskip gray str -> - show string with bg color - /str exch def - /gray exch def - /blskip exch def - /height exch def - /y exch def - /x exch def - - gsave - x y blskip sub str stringwidth pop height Box - gray setgray - fill - grestore - x y M str s -} def - -% Highlight bars. -/highlight_bars { % nlines lineheight output_y_margin gray -> - - gsave - setgray - /ymarg exch def - /lineheight exch def - /nlines exch def - - % This 2 is just a magic number to sync highlight lines to text. - 0 d_header_y ymarg sub 2 sub translate - - /cw d_output_w cols div def - /nrows d_output_h ymarg 2 mul sub lineheight div cvi def - - % for each column - 0 1 cols 1 sub { - cw mul /xp exch def - - % for each rows - 0 1 nrows 1 sub { - /rn exch def - rn lineheight mul neg /yp exch def - rn nlines idiv 2 mod 0 eq { - % Draw highlight bar. 4 is just a magic indentation. - xp 4 add yp cw 8 sub lineheight neg Box fill - } if - } for - } for - - grestore -} def - -% Line highlight bar. -/line_highlight { % x y width height gray -> - - gsave - /gray exch def - Box gray setgray fill - grestore -} def - -% Column separator lines. -/column_lines { - gsave - .1 setlinewidth - 0 d_footer_h translate - /cw d_output_w cols div def - 1 1 cols 1 sub { - cw mul 0 moveto - 0 d_output_h rlineto stroke - } for - grestore -} def - -% Column borders. -/column_borders { - gsave - .1 setlinewidth - 0 d_footer_h moveto - 0 d_output_h rlineto - d_output_w 0 rlineto - 0 d_output_h neg rlineto - closepath stroke - grestore -} def - -% Do the actual underlay drawing -/draw_underlay { - ul_style 0 eq { - ul_str true charpath stroke - } { - ul_str show - } ifelse -} def - -% Underlay -/underlay { % - -> - - gsave - 0 d_page_h translate - d_page_h neg d_page_w atan rotate - - ul_gray setgray - ul_font setfont - /dw d_page_h dup mul d_page_w dup mul add sqrt def - ul_str stringwidth pop dw exch sub 2 div ul_h_ptsize -2 div moveto - draw_underlay - grestore -} def - -/user_underlay { % - -> - - gsave - ul_x ul_y translate - ul_angle rotate - ul_gray setgray - ul_font setfont - 0 0 ul_h_ptsize 2 div sub moveto - draw_underlay - grestore -} def - -% Page prefeed -/page_prefeed { % bool -> - - statusdict /prefeed known { - statusdict exch /prefeed exch put - } { - pop - } ifelse -} def - -% Wrapped line markers -/wrapped_line_mark { % x y charwith charheight type -> - - /type exch def - /h exch def - /w exch def - /y exch def - /x exch def - - type 2 eq { - % Black boxes (like TeX does) - gsave - 0 setlinewidth - x w 4 div add y M - 0 h rlineto w 2 div 0 rlineto 0 h neg rlineto - closepath fill - grestore - } { - type 3 eq { - % Small arrows - gsave - .2 setlinewidth - x w 2 div add y h 2 div add M - w 4 div 0 rlineto - x w 4 div add y lineto stroke - - x w 4 div add w 8 div add y h 4 div add M - x w 4 div add y lineto - w 4 div h 8 div rlineto stroke - grestore - } { - % do nothing - } ifelse - } ifelse -} def - -% EPSF import. - -/BeginEPSF { - /b4_Inc_state save def % Save state for cleanup - /dict_count countdictstack def % Count objects on dict stack - /op_count count 1 sub def % Count objects on operand stack - userdict begin - /showpage { } def - 0 setgray 0 setlinecap - 1 setlinewidth 0 setlinejoin - 10 setmiterlimit [ ] 0 setdash newpath - /languagelevel where { - pop languagelevel - 1 ne { - false setstrokeadjust false setoverprint - } if - } if -} bind def - -/EndEPSF { - count op_count sub { pos } repeat % Clean up stacks - countdictstack dict_count sub { end } repeat - b4_Inc_state restore -} bind def - -% Check PostScript language level. -/languagelevel where { - pop /gs_languagelevel languagelevel def -} { - /gs_languagelevel 1 def -} ifelse -%%EndResource -%%BeginResource: procset Enscript-Encoding-88591 1.6 1 -/encoding_vector [ -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/space /exclam /quotedbl /numbersign -/dollar /percent /ampersand /quoteright -/parenleft /parenright /asterisk /plus -/comma /hyphen /period /slash -/zero /one /two /three -/four /five /six /seven -/eight /nine /colon /semicolon -/less /equal /greater /question -/at /A /B /C -/D /E /F /G -/H /I /J /K -/L /M /N /O -/P /Q /R /S -/T /U /V /W -/X /Y /Z /bracketleft -/backslash /bracketright /asciicircum /underscore -/quoteleft /a /b /c -/d /e /f /g -/h /i /j /k -/l /m /n /o -/p /q /r /s -/t /u /v /w -/x /y /z /braceleft -/bar /braceright /tilde /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/space /exclamdown /cent /sterling -/currency /yen /brokenbar /section -/dieresis /copyright /ordfeminine /guillemotleft -/logicalnot /hyphen /registered /macron -/degree /plusminus /twosuperior /threesuperior -/acute /mu /paragraph /bullet -/cedilla /onesuperior /ordmasculine /guillemotright -/onequarter /onehalf /threequarters /questiondown -/Agrave /Aacute /Acircumflex /Atilde -/Adieresis /Aring /AE /Ccedilla -/Egrave /Eacute /Ecircumflex /Edieresis -/Igrave /Iacute /Icircumflex /Idieresis -/Eth /Ntilde /Ograve /Oacute -/Ocircumflex /Otilde /Odieresis /multiply -/Oslash /Ugrave /Uacute /Ucircumflex -/Udieresis /Yacute /Thorn /germandbls -/agrave /aacute /acircumflex /atilde -/adieresis /aring /ae /ccedilla -/egrave /eacute /ecircumflex /edieresis -/igrave /iacute /icircumflex /idieresis -/eth /ntilde /ograve /oacute -/ocircumflex /otilde /odieresis /divide -/oslash /ugrave /uacute /ucircumflex -/udieresis /yacute /thorn /ydieresis -] def -%%EndResource -%%EndProlog -%%BeginSetup -%%IncludeResource: font Courier-Bold -%%IncludeResource: font Courier -/HFpt_w 10 def -/HFpt_h 10 def -/Courier-Bold /HF-gs-font MF -/HF /HF-gs-font findfont [HFpt_w 0 0 HFpt_h 0 0] makefont def -/Courier /F-gs-font MF -/F-gs-font 10 10 SF -/#copies 1 def -/d_page_w 520 def -/d_page_h 747 def -/d_header_x 0 def -/d_header_y 747 def -/d_header_w 520 def -/d_header_h 0 def -/d_footer_x 0 def -/d_footer_y 0 def -/d_footer_w 520 def -/d_footer_h 0 def -/d_output_w 520 def -/d_output_h 747 def -/cols 1 def -userdict/PStoPSxform PStoPSmatrix matrix currentmatrix - matrix invertmatrix matrix concatmatrix - matrix invertmatrix put -%%EndSetup -%%Page: (0,1) 1 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 1 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 701 M -(Network Working Group T. Ylonen) s -5 690 M -(Internet-Draft S. Lehtinen) s -5 679 M -(Expires: April 1, 2002 SSH Communications Security Corp) s -5 668 M -( October 2001) s -5 635 M -( SSH File Transfer Protocol) s -5 624 M -( draft-ietf-secsh-filexfer-02.txt) s -5 602 M -(Status of this Memo) s -5 580 M -( This document is an Internet-Draft and is in full conformance with) s -5 569 M -( all provisions of Section 10 of RFC2026.) s -5 547 M -( Internet-Drafts are working documents of the Internet Engineering) s -5 536 M -( Task Force \(IETF\), its areas, and its working groups. Note that) s -5 525 M -( other groups may also distribute working documents as Internet-) s -5 514 M -( Drafts.) s -5 492 M -( Internet-Drafts are draft documents valid for a maximum of six months) s -5 481 M -( and may be updated, replaced, or obsoleted by other documents at any) s -5 470 M -( time. It is inappropriate to use Internet-Drafts as reference) s -5 459 M -( material or to cite them other than as "work in progress.") s -5 437 M -( The list of current Internet-Drafts can be accessed at http://) s -5 426 M -( www.ietf.org/ietf/1id-abstracts.txt.) s -5 404 M -( The list of Internet-Draft Shadow Directories can be accessed at) s -5 393 M -( http://www.ietf.org/shadow.html.) s -5 371 M -( This Internet-Draft will expire on April 1, 2002.) s -5 349 M -(Copyright Notice) s -5 327 M -( Copyright \(C\) The Internet Society \(2001\). All Rights Reserved.) s -5 305 M -(Abstract) s -5 283 M -( The SSH File Transfer Protocol provides secure file transfer) s -5 272 M -( functionality over any reliable data stream. It is the standard file) s -5 261 M -( transfer protocol for use with the SSH2 protocol. This document) s -5 250 M -( describes the file transfer protocol and its interface to the SSH2) s -5 239 M -( protocol suite.) s -5 129 M -(Ylonen & Lehtinen Expires April 1, 2002 [Page 1]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 2 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2001) s -5 690 M -(Table of Contents) s -5 668 M -( 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3) s -5 657 M -( 2. Use with the SSH Connection Protocol . . . . . . . . . . . . 4) s -5 646 M -( 3. General Packet Format . . . . . . . . . . . . . . . . . . . 5) s -5 635 M -( 4. Protocol Initialization . . . . . . . . . . . . . . . . . . 7) s -5 624 M -( 5. File Attributes . . . . . . . . . . . . . . . . . . . . . . 8) s -5 613 M -( 6. Requests From the Client to the Server . . . . . . . . . . . 10) s -5 602 M -( 6.1 Request Synchronization and Reordering . . . . . . . . . . . 10) s -5 591 M -( 6.2 File Names . . . . . . . . . . . . . . . . . . . . . . . . . 11) s -5 580 M -( 6.3 Opening, Creating, and Closing Files . . . . . . . . . . . . 11) s -5 569 M -( 6.4 Reading and Writing . . . . . . . . . . . . . . . . . . . . 13) s -5 558 M -( 6.5 Removing and Renaming Files . . . . . . . . . . . . . . . . 14) s -5 547 M -( 6.6 Creating and Deleting Directories . . . . . . . . . . . . . 15) s -5 536 M -( 6.7 Scanning Directories . . . . . . . . . . . . . . . . . . . . 15) s -5 525 M -( 6.8 Retrieving File Attributes . . . . . . . . . . . . . . . . . 16) s -5 514 M -( 6.9 Setting File Attributes . . . . . . . . . . . . . . . . . . 17) s -5 503 M -( 6.10 Dealing with Symbolic links . . . . . . . . . . . . . . . . 18) s -5 492 M -( 6.11 Canonicalizing the Server-Side Path Name . . . . . . . . . . 18) s -5 481 M -( 7. Responses from the Server to the Client . . . . . . . . . . 20) s -5 470 M -( 8. Vendor-Specific Extensions . . . . . . . . . . . . . . . . . 24) s -5 459 M -( 9. Security Considerations . . . . . . . . . . . . . . . . . . 25) s -5 448 M -( 10. Changes from previous protocol versions . . . . . . . . . . 26) s -5 437 M -( 10.1 Changes between versions 3 and 2 . . . . . . . . . . . . . . 26) s -5 426 M -( 10.2 Changes between versions 2 and 1 . . . . . . . . . . . . . . 26) s -5 415 M -( 10.3 Changes between versions 1 and 0 . . . . . . . . . . . . . . 26) s -5 404 M -( 11. Trademark Issues . . . . . . . . . . . . . . . . . . . . . . 27) s -5 393 M -( References . . . . . . . . . . . . . . . . . . . . . . . . . 28) s -5 382 M -( Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 28) s -5 371 M -( Full Copyright Statement . . . . . . . . . . . . . . . . . . 29) s -5 129 M -(Ylonen & Lehtinen Expires April 1, 2002 [Page 2]) s -_R -S -PStoPSsaved restore -%%Page: (2,3) 2 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 3 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2001) s -5 690 M -(1. Introduction) s -5 668 M -( This protocol provides secure file transfer \(and more generally file) s -5 657 M -( system access\) functionality over a reliable data stream, such as a) s -5 646 M -( channel in the SSH2 protocol [3].) s -5 624 M -( This protocol is designed so that it could be used to implement a) s -5 613 M -( secure remote file system service, as well as a secure file transfer) s -5 602 M -( service.) s -5 580 M -( This protocol assumes that it runs over a secure channel, and that) s -5 569 M -( the server has already authenticated the user at the client end, and) s -5 558 M -( that the identity of the client user is externally available to the) s -5 547 M -( server implementation.) s -5 525 M -( In general, this protocol follows a simple request-response model.) s -5 514 M -( Each request and response contains a sequence number and multiple) s -5 503 M -( requests may be pending simultaneously. There are a relatively large) s -5 492 M -( number of different request messages, but a small number of possible) s -5 481 M -( response messages. Each request has one or more response messages) s -5 470 M -( that may be returned in result \(e.g., a read either returns data or) s -5 459 M -( reports error status\).) s -5 437 M -( The packet format descriptions in this specification follow the) s -5 426 M -( notation presented in the secsh architecture draft.[3].) s -5 404 M -( Even though this protocol is described in the context of the SSH2) s -5 393 M -( protocol, this protocol is general and independent of the rest of the) s -5 382 M -( SSH2 protocol suite. It could be used in a number of different) s -5 371 M -( applications, such as secure file transfer over TLS RFC 2246 [1] and) s -5 360 M -( transfer of management information in VPN applications.) s -5 129 M -(Ylonen & Lehtinen Expires April 1, 2002 [Page 3]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 4 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2001) s -5 690 M -(2. Use with the SSH Connection Protocol) s -5 668 M -( When used with the SSH2 Protocol suite, this protocol is intended to) s -5 657 M -( be used from the SSH Connection Protocol [5] as a subsystem, as) s -5 646 M -( described in section ``Starting a Shell or a Command''. The) s -5 635 M -( subsystem name used with this protocol is "sftp".) s -5 129 M -(Ylonen & Lehtinen Expires April 1, 2002 [Page 4]) s -_R -S -PStoPSsaved restore -%%Page: (4,5) 3 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 5 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2001) s -5 690 M -(3. General Packet Format) s -5 668 M -( All packets transmitted over the secure connection are of the) s -5 657 M -( following format:) s -5 635 M -( uint32 length) s -5 624 M -( byte type) s -5 613 M -( byte[length - 1] data payload) s -5 591 M -( That is, they are just data preceded by 32-bit length and 8-bit type) s -5 580 M -( fields. The `length' is the length of the data area, and does not) s -5 569 M -( include the `length' field itself. The format and interpretation of) s -5 558 M -( the data area depends on the packet type.) s -5 536 M -( All packet descriptions below only specify the packet type and the) s -5 525 M -( data that goes into the data field. Thus, they should be prefixed by) s -5 514 M -( the `length' and `type' fields.) s -5 492 M -( The maximum size of a packet is in practice determined by the client) s -5 481 M -( \(the maximum size of read or write requests that it sends, plus a few) s -5 470 M -( bytes of packet overhead\). All servers SHOULD support packets of at) s -5 459 M -( least 34000 bytes \(where the packet size refers to the full length,) s -5 448 M -( including the header above\). This should allow for reads and writes) s -5 437 M -( of at most 32768 bytes.) s -5 415 M -( There is no limit on the number of outstanding \(non-acknowledged\)) s -5 404 M -( requests that the client may send to the server. In practice this is) s -5 393 M -( limited by the buffering available on the data stream and the queuing) s -5 382 M -( performed by the server. If the server's queues are full, it should) s -5 371 M -( not read any more data from the stream, and flow control will prevent) s -5 360 M -( the client from sending more requests. Note, however, that while) s -5 349 M -( there is no restriction on the protocol level, the client's API may) s -5 338 M -( provide a limit in order to prevent infinite queuing of outgoing) s -5 327 M -( requests at the client.) s -5 129 M -(Ylonen & Lehtinen Expires April 1, 2002 [Page 5]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 6 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2001) s -5 690 M -( The following values are defined for packet types.) s -5 668 M -( #define SSH_FXP_INIT 1) s -5 657 M -( #define SSH_FXP_VERSION 2) s -5 646 M -( #define SSH_FXP_OPEN 3) s -5 635 M -( #define SSH_FXP_CLOSE 4) s -5 624 M -( #define SSH_FXP_READ 5) s -5 613 M -( #define SSH_FXP_WRITE 6) s -5 602 M -( #define SSH_FXP_LSTAT 7) s -5 591 M -( #define SSH_FXP_FSTAT 8) s -5 580 M -( #define SSH_FXP_SETSTAT 9) s -5 569 M -( #define SSH_FXP_FSETSTAT 10) s -5 558 M -( #define SSH_FXP_OPENDIR 11) s -5 547 M -( #define SSH_FXP_READDIR 12) s -5 536 M -( #define SSH_FXP_REMOVE 13) s -5 525 M -( #define SSH_FXP_MKDIR 14) s -5 514 M -( #define SSH_FXP_RMDIR 15) s -5 503 M -( #define SSH_FXP_REALPATH 16) s -5 492 M -( #define SSH_FXP_STAT 17) s -5 481 M -( #define SSH_FXP_RENAME 18) s -5 470 M -( #define SSH_FXP_READLINK 19) s -5 459 M -( #define SSH_FXP_SYMLINK 20) s -5 448 M -( #define SSH_FXP_STATUS 101) s -5 437 M -( #define SSH_FXP_HANDLE 102) s -5 426 M -( #define SSH_FXP_DATA 103) s -5 415 M -( #define SSH_FXP_NAME 104) s -5 404 M -( #define SSH_FXP_ATTRS 105) s -5 393 M -( #define SSH_FXP_EXTENDED 200) s -5 382 M -( #define SSH_FXP_EXTENDED_REPLY 201) s -5 360 M -( Additional packet types should only be defined if the protocol) s -5 349 M -( version number \(see Section ``Protocol Initialization''\) is) s -5 338 M -( incremented, and their use MUST be negotiated using the version) s -5 327 M -( number. However, the SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY) s -5 316 M -( packets can be used to implement vendor-specific extensions. See) s -5 305 M -( Section ``Vendor-Specific-Extensions'' for more details.) s -5 129 M -(Ylonen & Lehtinen Expires April 1, 2002 [Page 6]) s -_R -S -PStoPSsaved restore -%%Page: (6,7) 4 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 7 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2001) s -5 690 M -(4. Protocol Initialization) s -5 668 M -( When the file transfer protocol starts, it first sends a SSH_FXP_INIT) s -5 657 M -( \(including its version number\) packet to the server. The server) s -5 646 M -( responds with a SSH_FXP_VERSION packet, supplying the lowest of its) s -5 635 M -( own and the client's version number. Both parties should from then) s -5 624 M -( on adhere to particular version of the protocol.) s -5 602 M -( The SSH_FXP_INIT packet \(from client to server\) has the following) s -5 591 M -( data:) s -5 569 M -( uint32 version) s -5 558 M -( <extension data>) s -5 536 M -( The SSH_FXP_VERSION packet \(from server to client\) has the following) s -5 525 M -( data:) s -5 503 M -( uint32 version) s -5 492 M -( <extension data>) s -5 470 M -( The version number of the protocol specified in this document is 3.) s -5 459 M -( The version number should be incremented for each incompatible) s -5 448 M -( revision of this protocol.) s -5 426 M -( The extension data in the above packets may be empty, or may be a) s -5 415 M -( sequence of) s -5 393 M -( string extension_name) s -5 382 M -( string extension_data) s -5 360 M -( pairs \(both strings MUST always be present if one is, but the) s -5 349 M -( `extension_data' string may be of zero length\). If present, these) s -5 338 M -( strings indicate extensions to the baseline protocol. The) s -5 327 M -( `extension_name' field\(s\) identify the name of the extension. The) s -5 316 M -( name should be of the form "name@domain", where the domain is the DNS) s -5 305 M -( domain name of the organization defining the extension. Additional) s -5 294 M -( names that are not of this format may be defined later by the IETF.) s -5 283 M -( Implementations MUST silently ignore any extensions whose name they) s -5 272 M -( do not recognize.) s -5 129 M -(Ylonen & Lehtinen Expires April 1, 2002 [Page 7]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 8 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2001) s -5 690 M -(5. File Attributes) s -5 668 M -( A new compound data type is defined for encoding file attributes. It) s -5 657 M -( is basically just a combination of elementary types, but is defined) s -5 646 M -( once because of the non-trivial description of the fields and to) s -5 635 M -( ensure maintainability.) s -5 613 M -( The same encoding is used both when returning file attributes from) s -5 602 M -( the server and when sending file attributes to the server. When) s -5 591 M -( sending it to the server, the flags field specifies which attributes) s -5 580 M -( are included, and the server will use default values for the) s -5 569 M -( remaining attributes \(or will not modify the values of remaining) s -5 558 M -( attributes\). When receiving attributes from the server, the flags) s -5 547 M -( specify which attributes are included in the returned data. The) s -5 536 M -( server normally returns all attributes it knows about.) s -5 514 M -( uint32 flags) s -5 503 M -( uint64 size present only if flag SSH_FILEXFER_ATTR_SIZE) s -5 492 M -( uint32 uid present only if flag SSH_FILEXFER_ATTR_UIDGID) s -5 481 M -( uint32 gid present only if flag SSH_FILEXFER_ATTR_UIDGID) s -5 470 M -( uint32 permissions present only if flag SSH_FILEXFER_ATTR_PERMISSIONS) s -5 459 M -( uint32 atime present only if flag SSH_FILEXFER_ACMODTIME) s -5 448 M -( uint32 mtime present only if flag SSH_FILEXFER_ACMODTIME) s -5 437 M -( uint32 extended_count present only if flag SSH_FILEXFER_ATTR_EXTENDED) s -5 426 M -( string extended_type) s -5 415 M -( string extended_data) s -5 404 M -( ... more extended data \(extended_type - extended_data pairs\),) s -5 393 M -( so that number of pairs equals extended_count) s -5 371 M -( The `flags' specify which of the fields are present. Those fields) s -5 360 M -( for which the corresponding flag is not set are not present \(not) s -5 349 M -( included in the packet\). New flags can only be added by incrementing) s -5 338 M -( the protocol version number \(or by using the extension mechanism) s -5 327 M -( described below\).) s -5 305 M -( The `size' field specifies the size of the file in bytes.) s -5 283 M -( The `uid' and `gid' fields contain numeric Unix-like user and group) s -5 272 M -( identifiers, respectively.) s -5 250 M -( The `permissions' field contains a bit mask of file permissions as) s -5 239 M -( defined by posix [1].) s -5 217 M -( The `atime' and `mtime' contain the access and modification times of) s -5 206 M -( the files, respectively. They are represented as seconds from Jan 1,) s -5 195 M -( 1970 in UTC.) s -5 173 M -( The SSH_FILEXFER_ATTR_EXTENDED flag provides a general extension) s -5 129 M -(Ylonen & Lehtinen Expires April 1, 2002 [Page 8]) s -_R -S -PStoPSsaved restore -%%Page: (8,9) 5 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 9 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2001) s -5 690 M -( mechanism for vendor-specific extensions. If the flag is specified,) s -5 679 M -( then the `extended_count' field is present. It specifies the number) s -5 668 M -( of extended_type-extended_data pairs that follow. Each of these) s -5 657 M -( pairs specifies an extended attribute. For each of the attributes,) s -5 646 M -( the extended_type field should be a string of the format) s -5 635 M -( "name@domain", where "domain" is a valid, registered domain name and) s -5 624 M -( "name" identifies the method. The IETF may later standardize certain) s -5 613 M -( names that deviate from this format \(e.g., that do not contain the) s -5 602 M -( "@" sign\). The interpretation of `extended_data' depends on the) s -5 591 M -( type. Implementations SHOULD ignore extended data fields that they) s -5 580 M -( do not understand.) s -5 558 M -( Additional fields can be added to the attributes by either defining) s -5 547 M -( additional bits to the flags field to indicate their presence, or by) s -5 536 M -( defining extended attributes for them. The extended attributes) s -5 525 M -( mechanism is recommended for most purposes; additional flags bits) s -5 514 M -( should only be defined by an IETF standards action that also) s -5 503 M -( increments the protocol version number. The use of such new fields) s -5 492 M -( MUST be negotiated by the version number in the protocol exchange.) s -5 481 M -( It is a protocol error if a packet with unsupported protocol bits is) s -5 470 M -( received.) s -5 448 M -( The flags bits are defined to have the following values:) s -5 426 M -( #define SSH_FILEXFER_ATTR_SIZE 0x00000001) s -5 415 M -( #define SSH_FILEXFER_ATTR_UIDGID 0x00000002) s -5 404 M -( #define SSH_FILEXFER_ATTR_PERMISSIONS 0x00000004) s -5 393 M -( #define SSH_FILEXFER_ATTR_ACMODTIME 0x00000008) s -5 382 M -( #define SSH_FILEXFER_ATTR_EXTENDED 0x80000000) s -5 129 M -(Ylonen & Lehtinen Expires April 1, 2002 [Page 9]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 10 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2001) s -5 690 M -(6. Requests From the Client to the Server) s -5 668 M -( Requests from the client to the server represent the various file) s -5 657 M -( system operations. Each request begins with an `id' field, which is) s -5 646 M -( a 32-bit identifier identifying the request \(selected by the client\).) s -5 635 M -( The same identifier will be returned in the response to the request.) s -5 624 M -( One possible implementation of it is a monotonically increasing) s -5 613 M -( request sequence number \(modulo 2^32\).) s -5 591 M -( Many operations in the protocol operate on open files. The) s -5 580 M -( SSH_FXP_OPEN request can return a file handle \(which is an opaque) s -5 569 M -( variable-length string\) which may be used to access the file later) s -5 558 M -( \(e.g. in a read operation\). The client MUST NOT send requests the) s -5 547 M -( server with bogus or closed handles. However, the server MUST) s -5 536 M -( perform adequate checks on the handle in order to avoid security) s -5 525 M -( risks due to fabricated handles.) s -5 503 M -( This design allows either stateful and stateless server) s -5 492 M -( implementation, as well as an implementation which caches state) s -5 481 M -( between requests but may also flush it. The contents of the file) s -5 470 M -( handle string are entirely up to the server and its design. The) s -5 459 M -( client should not modify or attempt to interpret the file handle) s -5 448 M -( strings.) s -5 426 M -( The file handle strings MUST NOT be longer than 256 bytes.) s -5 404 M -(6.1 Request Synchronization and Reordering) s -5 382 M -( The protocol and implementations MUST process requests relating to) s -5 371 M -( the same file in the order in which they are received. In other) s -5 360 M -( words, if an application submits multiple requests to the server, the) s -5 349 M -( results in the responses will be the same as if it had sent the) s -5 338 M -( requests one at a time and waited for the response in each case. For) s -5 327 M -( example, the server may process non-overlapping read/write requests) s -5 316 M -( to the same file in parallel, but overlapping reads and writes cannot) s -5 305 M -( be reordered or parallelized. However, there are no ordering) s -5 294 M -( restrictions on the server for processing requests from two different) s -5 283 M -( file transfer connections. The server may interleave and parallelize) s -5 272 M -( them at will.) s -5 250 M -( There are no restrictions on the order in which responses to) s -5 239 M -( outstanding requests are delivered to the client, except that the) s -5 228 M -( server must ensure fairness in the sense that processing of no) s -5 217 M -( request will be indefinitely delayed even if the client is sending) s -5 206 M -( other requests so that there are multiple outstanding requests all) s -5 195 M -( the time.) s -5 129 M -(Ylonen & Lehtinen Expires April 1, 2002 [Page 10]) s -_R -S -PStoPSsaved restore -%%Page: (10,11) 6 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 11 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2001) s -5 690 M -(6.2 File Names) s -5 668 M -( This protocol represents file names as strings. File names are) s -5 657 M -( assumed to use the slash \('/'\) character as a directory separator.) s -5 635 M -( File names starting with a slash are "absolute", and are relative to) s -5 624 M -( the root of the file system. Names starting with any other character) s -5 613 M -( are relative to the user's default directory \(home directory\). Note) s -5 602 M -( that identifying the user is assumed to take place outside of this) s -5 591 M -( protocol.) s -5 569 M -( Servers SHOULD interpret a path name component ".." as referring to) s -5 558 M -( the parent directory, and "." as referring to the current directory.) s -5 547 M -( If the server implementation limits access to certain parts of the) s -5 536 M -( file system, it must be extra careful in parsing file names when) s -5 525 M -( enforcing such restrictions. There have been numerous reported) s -5 514 M -( security bugs where a ".." in a path name has allowed access outside) s -5 503 M -( the intended area.) s -5 481 M -( An empty path name is valid, and it refers to the user's default) s -5 470 M -( directory \(usually the user's home directory\).) s -5 448 M -( Otherwise, no syntax is defined for file names by this specification.) s -5 437 M -( Clients should not make any other assumptions; however, they can) s -5 426 M -( splice path name components returned by SSH_FXP_READDIR together) s -5 415 M -( using a slash \('/'\) as the separator, and that will work as expected.) s -5 393 M -( It is understood that the lack of well-defined semantics for file) s -5 382 M -( names may cause interoperability problems between clients and servers) s -5 371 M -( using radically different operating systems. However, this approach) s -5 360 M -( is known to work acceptably with most systems, and alternative) s -5 349 M -( approaches that e.g. treat file names as sequences of structured) s -5 338 M -( components are quite complicated.) s -5 316 M -(6.3 Opening, Creating, and Closing Files) s -5 294 M -( Files are opened and created using the SSH_FXP_OPEN message, whose) s -5 283 M -( data part is as follows:) s -5 261 M -( uint32 id) s -5 250 M -( string filename) s -5 239 M -( uint32 pflags) s -5 228 M -( ATTRS attrs) s -5 206 M -( The `id' field is the request identifier as for all requests.) s -5 184 M -( The `filename' field specifies the file name. See Section ``File) s -5 173 M -( Names'' for more information.) s -5 129 M -(Ylonen & Lehtinen Expires April 1, 2002 [Page 11]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 12 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2001) s -5 690 M -( The `pflags' field is a bitmask. The following bits have been) s -5 679 M -( defined.) s -5 657 M -( #define SSH_FXF_READ 0x00000001) s -5 646 M -( #define SSH_FXF_WRITE 0x00000002) s -5 635 M -( #define SSH_FXF_APPEND 0x00000004) s -5 624 M -( #define SSH_FXF_CREAT 0x00000008) s -5 613 M -( #define SSH_FXF_TRUNC 0x00000010) s -5 602 M -( #define SSH_FXF_EXCL 0x00000020) s -5 580 M -( These have the following meanings:) s -5 558 M -( SSH_FXF_READ) s -5 547 M -( Open the file for reading.) s -5 525 M -( SSH_FXF_WRITE) s -5 514 M -( Open the file for writing. If both this and SSH_FXF_READ are) s -5 503 M -( specified, the file is opened for both reading and writing.) s -5 481 M -( SSH_FXF_APPEND) s -5 470 M -( Force all writes to append data at the end of the file.) s -5 448 M -( SSH_FXF_CREAT) s -5 437 M -( If this flag is specified, then a new file will be created if one) s -5 426 M -( does not already exist \(if O_TRUNC is specified, the new file will) s -5 415 M -( be truncated to zero length if it previously exists\).) s -5 393 M -( SSH_FXF_TRUNC) s -5 382 M -( Forces an existing file with the same name to be truncated to zero) s -5 371 M -( length when creating a file by specifying SSH_FXF_CREAT.) s -5 360 M -( SSH_FXF_CREAT MUST also be specified if this flag is used.) s -5 338 M -( SSH_FXF_EXCL) s -5 327 M -( Causes the request to fail if the named file already exists.) s -5 316 M -( SSH_FXF_CREAT MUST also be specified if this flag is used.) s -5 294 M -( The `attrs' field specifies the initial attributes for the file.) s -5 283 M -( Default values will be used for those attributes that are not) s -5 272 M -( specified. See Section ``File Attributes'' for more information.) s -5 250 M -( Regardless the server operating system, the file will always be) s -5 239 M -( opened in "binary" mode \(i.e., no translations between different) s -5 228 M -( character sets and newline encodings\).) s -5 206 M -( The response to this message will be either SSH_FXP_HANDLE \(if the) s -5 195 M -( operation is successful\) or SSH_FXP_STATUS \(if the operation fails\).) s -5 129 M -(Ylonen & Lehtinen Expires April 1, 2002 [Page 12]) s -_R -S -PStoPSsaved restore -%%Page: (12,13) 7 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 13 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2001) s -5 690 M -( A file is closed by using the SSH_FXP_CLOSE request. Its data field) s -5 679 M -( has the following format:) s -5 657 M -( uint32 id) s -5 646 M -( string handle) s -5 624 M -( where `id' is the request identifier, and `handle' is a handle) s -5 613 M -( previously returned in the response to SSH_FXP_OPEN or) s -5 602 M -( SSH_FXP_OPENDIR. The handle becomes invalid immediately after this) s -5 591 M -( request has been sent.) s -5 569 M -( The response to this request will be a SSH_FXP_STATUS message. One) s -5 558 M -( should note that on some server platforms even a close can fail.) s -5 547 M -( This can happen e.g. if the server operating system caches writes,) s -5 536 M -( and an error occurs while flushing cached writes during the close.) s -5 514 M -(6.4 Reading and Writing) s -5 492 M -( Once a file has been opened, it can be read using the SSH_FXP_READ) s -5 481 M -( message, which has the following format:) s -5 459 M -( uint32 id) s -5 448 M -( string handle) s -5 437 M -( uint64 offset) s -5 426 M -( uint32 len) s -5 404 M -( where `id' is the request identifier, `handle' is an open file handle) s -5 393 M -( returned by SSH_FXP_OPEN, `offset' is the offset \(in bytes\) relative) s -5 382 M -( to the beginning of the file from where to start reading, and `len') s -5 371 M -( is the maximum number of bytes to read.) s -5 349 M -( In response to this request, the server will read as many bytes as it) s -5 338 M -( can from the file \(up to `len'\), and return them in a SSH_FXP_DATA) s -5 327 M -( message. If an error occurs or EOF is encountered before reading any) s -5 316 M -( data, the server will respond with SSH_FXP_STATUS. For normal disk) s -5 305 M -( files, it is guaranteed that this will read the specified number of) s -5 294 M -( bytes, or up to end of file. For e.g. device files this may return) s -5 283 M -( fewer bytes than requested.) s -5 261 M -( Writing to a file is achieved using the SSH_FXP_WRITE message, which) s -5 250 M -( has the following format:) s -5 228 M -( uint32 id) s -5 217 M -( string handle) s -5 206 M -( uint64 offset) s -5 195 M -( string data) s -5 173 M -( where `id' is a request identifier, `handle' is a file handle) s -5 129 M -(Ylonen & Lehtinen Expires April 1, 2002 [Page 13]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 14 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2001) s -5 690 M -( returned by SSH_FXP_OPEN, `offset' is the offset \(in bytes\) from the) s -5 679 M -( beginning of the file where to start writing, and `data' is the data) s -5 668 M -( to be written.) s -5 646 M -( The write will extend the file if writing beyond the end of the file.) s -5 635 M -( It is legal to write way beyond the end of the file; the semantics) s -5 624 M -( are to write zeroes from the end of the file to the specified offset) s -5 613 M -( and then the data. On most operating systems, such writes do not) s -5 602 M -( allocate disk space but instead leave "holes" in the file.) s -5 580 M -( The server responds to a write request with a SSH_FXP_STATUS message.) s -5 558 M -(6.5 Removing and Renaming Files) s -5 536 M -( Files can be removed using the SSH_FXP_REMOVE message. It has the) s -5 525 M -( following format:) s -5 503 M -( uint32 id) s -5 492 M -( string filename) s -5 470 M -( where `id' is the request identifier and `filename' is the name of) s -5 459 M -( the file to be removed. See Section ``File Names'' for more) s -5 448 M -( information. This request cannot be used to remove directories.) s -5 426 M -( The server will respond to this request with a SSH_FXP_STATUS) s -5 415 M -( message.) s -5 393 M -( Files \(and directories\) can be renamed using the SSH_FXP_RENAME) s -5 382 M -( message. Its data is as follows:) s -5 360 M -( uint32 id) s -5 349 M -( string oldpath) s -5 338 M -( string newpath) s -5 316 M -( where `id' is the request identifier, `oldpath' is the name of an) s -5 305 M -( existing file or directory, and `newpath' is the new name for the) s -5 294 M -( file or directory. It is an error if there already exists a file) s -5 283 M -( with the name specified by newpath. The server may also fail rename) s -5 272 M -( requests in other situations, for example if `oldpath' and `newpath') s -5 261 M -( point to different file systems on the server.) s -5 239 M -( The server will respond to this request with a SSH_FXP_STATUS) s -5 228 M -( message.) s -5 129 M -(Ylonen & Lehtinen Expires April 1, 2002 [Page 14]) s -_R -S -PStoPSsaved restore -%%Page: (14,15) 8 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 15 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2001) s -5 690 M -(6.6 Creating and Deleting Directories) s -5 668 M -( New directories can be created using the SSH_FXP_MKDIR request. It) s -5 657 M -( has the following format:) s -5 635 M -( uint32 id) s -5 624 M -( string path) s -5 613 M -( ATTRS attrs) s -5 591 M -( where `id' is the request identifier, `path' and `attrs' specifies) s -5 580 M -( the modifications to be made to its attributes. See Section ``File) s -5 569 M -( Names'' for more information on file names. Attributes are discussed) s -5 558 M -( in more detail in Section ``File Attributes''. specifies the) s -5 547 M -( directory to be created. An error will be returned if a file or) s -5 536 M -( directory with the specified path already exists. The server will) s -5 525 M -( respond to this request with a SSH_FXP_STATUS message.) s -5 503 M -( Directories can be removed using the SSH_FXP_RMDIR request, which) s -5 492 M -( has the following format:) s -5 470 M -( uint32 id) s -5 459 M -( string path) s -5 437 M -( where `id' is the request identifier, and `path' specifies the) s -5 426 M -( directory to be removed. See Section ``File Names'' for more) s -5 415 M -( information on file names. An error will be returned if no directory) s -5 404 M -( with the specified path exists, or if the specified directory is not) s -5 393 M -( empty, or if the path specified a file system object other than a) s -5 382 M -( directory. The server responds to this request with a SSH_FXP_STATUS) s -5 371 M -( message.) s -5 349 M -(6.7 Scanning Directories) s -5 327 M -( The files in a directory can be listed using the SSH_FXP_OPENDIR and) s -5 316 M -( SSH_FXP_READDIR requests. Each SSH_FXP_READDIR request returns one) s -5 305 M -( or more file names with full file attributes for each file. The) s -5 294 M -( client should call SSH_FXP_READDIR repeatedly until it has found the) s -5 283 M -( file it is looking for or until the server responds with a) s -5 272 M -( SSH_FXP_STATUS message indicating an error \(normally SSH_FX_EOF if) s -5 261 M -( there are no more files in the directory\). The client should then) s -5 250 M -( close the handle using the SSH_FXP_CLOSE request.) s -5 129 M -(Ylonen & Lehtinen Expires April 1, 2002 [Page 15]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 16 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2001) s -5 690 M -( The SSH_FXP_OPENDIR opens a directory for reading. It has the) s -5 679 M -( following format:) s -5 657 M -( uint32 id) s -5 646 M -( string path) s -5 624 M -( where `id' is the request identifier and `path' is the path name of) s -5 613 M -( the directory to be listed \(without any trailing slash\). See Section) s -5 602 M -( ``File Names'' for more information on file names. This will return) s -5 591 M -( an error if the path does not specify a directory or if the directory) s -5 580 M -( is not readable. The server will respond to this request with either) s -5 569 M -( a SSH_FXP_HANDLE or a SSH_FXP_STATUS message.) s -5 547 M -( Once the directory has been successfully opened, files \(and) s -5 536 M -( directories\) contained in it can be listed using SSH_FXP_READDIR) s -5 525 M -( requests. These are of the format) s -5 503 M -( uint32 id) s -5 492 M -( string handle) s -5 470 M -( where `id' is the request identifier, and `handle' is a handle) s -5 459 M -( returned by SSH_FXP_OPENDIR. \(It is a protocol error to attempt to) s -5 448 M -( use an ordinary file handle returned by SSH_FXP_OPEN.\)) s -5 426 M -( The server responds to this request with either a SSH_FXP_NAME or a) s -5 415 M -( SSH_FXP_STATUS message. One or more names may be returned at a time.) s -5 404 M -( Full status information is returned for each name in order to speed) s -5 393 M -( up typical directory listings.) s -5 371 M -( When the client no longer wishes to read more names from the) s -5 360 M -( directory, it SHOULD call SSH_FXP_CLOSE for the handle. The handle) s -5 349 M -( should be closed regardless of whether an error has occurred or not.) s -5 327 M -(6.8 Retrieving File Attributes) s -5 305 M -( Very often, file attributes are automatically returned by) s -5 294 M -( SSH_FXP_READDIR. However, sometimes there is need to specifically) s -5 283 M -( retrieve the attributes for a named file. This can be done using the) s -5 272 M -( SSH_FXP_STAT, SSH_FXP_LSTAT and SSH_FXP_FSTAT requests.) s -5 250 M -( SSH_FXP_STAT and SSH_FXP_LSTAT only differ in that SSH_FXP_STAT) s -5 239 M -( follows symbolic links on the server, whereas SSH_FXP_LSTAT does not) s -5 228 M -( follow symbolic links. Both have the same format:) s -5 206 M -( uint32 id) s -5 195 M -( string path) s -5 173 M -( where `id' is the request identifier, and `path' specifies the file) s -5 129 M -(Ylonen & Lehtinen Expires April 1, 2002 [Page 16]) s -_R -S -PStoPSsaved restore -%%Page: (16,17) 9 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 17 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2001) s -5 690 M -( system object for which status is to be returned. The server) s -5 679 M -( responds to this request with either SSH_FXP_ATTRS or SSH_FXP_STATUS.) s -5 657 M -( SSH_FXP_FSTAT differs from the others in that it returns status) s -5 646 M -( information for an open file \(identified by the file handle\). Its) s -5 635 M -( format is as follows:) s -5 613 M -( uint32 id) s -5 602 M -( string handle) s -5 580 M -( where `id' is the request identifier and `handle' is a file handle) s -5 569 M -( returned by SSH_FXP_OPEN. The server responds to this request with) s -5 558 M -( SSH_FXP_ATTRS or SSH_FXP_STATUS.) s -5 536 M -(6.9 Setting File Attributes) s -5 514 M -( File attributes may be modified using the SSH_FXP_SETSTAT and) s -5 503 M -( SSH_FXP_FSETSTAT requests. These requests are used for operations) s -5 492 M -( such as changing the ownership, permissions or access times, as well) s -5 481 M -( as for truncating a file.) s -5 459 M -( The SSH_FXP_SETSTAT request is of the following format:) s -5 437 M -( uint32 id) s -5 426 M -( string path) s -5 415 M -( ATTRS attrs) s -5 393 M -( where `id' is the request identifier, `path' specifies the file) s -5 382 M -( system object \(e.g. file or directory\) whose attributes are to be) s -5 371 M -( modified, and `attrs' specifies the modifications to be made to its) s -5 360 M -( attributes. Attributes are discussed in more detail in Section) s -5 349 M -( ``File Attributes''.) s -5 327 M -( An error will be returned if the specified file system object does) s -5 316 M -( not exist or the user does not have sufficient rights to modify the) s -5 305 M -( specified attributes. The server responds to this request with a) s -5 294 M -( SSH_FXP_STATUS message.) s -5 272 M -( The SSH_FXP_FSETSTAT request modifies the attributes of a file which) s -5 261 M -( is already open. It has the following format:) s -5 239 M -( uint32 id) s -5 228 M -( string handle) s -5 217 M -( ATTRS attrs) s -5 195 M -( where `id' is the request identifier, `handle' \(MUST be returned by) s -5 184 M -( SSH_FXP_OPEN\) identifies the file whose attributes are to be) s -5 173 M -( modified, and `attrs' specifies the modifications to be made to its) s -5 129 M -(Ylonen & Lehtinen Expires April 1, 2002 [Page 17]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 18 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2001) s -5 690 M -( attributes. Attributes are discussed in more detail in Section) s -5 679 M -( ``File Attributes''. The server will respond to this request with) s -5 668 M -( SSH_FXP_STATUS.) s -5 646 M -(6.10 Dealing with Symbolic links) s -5 624 M -( The SSH_FXP_READLINK request may be used to read the target of a) s -5 613 M -( symbolic link. It would have a data part as follows:) s -5 591 M -( uint32 id) s -5 580 M -( string path) s -5 558 M -( where `id' is the request identifier and `path' specifies the path) s -5 547 M -( name of the symlink to be read.) s -5 525 M -( The server will respond with a SSH_FXP_NAME packet containing only) s -5 514 M -( one name and a dummy attributes value. The name in the returned) s -5 503 M -( packet contains the target of the link. If an error occurs, the) s -5 492 M -( server may respond with SSH_FXP_STATUS.) s -5 470 M -( The SSH_FXP_SYMLINK request will create a symbolic link on the) s -5 459 M -( server. It is of the following format) s -5 437 M -( uint32 id) s -5 426 M -( string linkpath) s -5 415 M -( string targetpath) s -5 393 M -( where `id' is the request identifier, `linkpath' specifies the path) s -5 382 M -( name of the symlink to be created and `targetpath' specifies the) s -5 371 M -( target of the symlink. The server shall respond with a) s -5 360 M -( SSH_FXP_STATUS indicating either success \(SSH_FX_OK\) or an error) s -5 349 M -( condition.) s -5 327 M -(6.11 Canonicalizing the Server-Side Path Name) s -5 305 M -( The SSH_FXP_REALPATH request can be used to have the server) s -5 294 M -( canonicalize any given path name to an absolute path. This is useful) s -5 283 M -( for converting path names containing ".." components or relative) s -5 272 M -( pathnames without a leading slash into absolute paths. The format of) s -5 261 M -( the request is as follows:) s -5 239 M -( uint32 id) s -5 228 M -( string path) s -5 206 M -( where `id' is the request identifier and `path' specifies the path) s -5 195 M -( name to be canonicalized. The server will respond with a) s -5 184 M -( SSH_FXP_NAME packet containing only one name and a dummy attributes) s -5 173 M -( value. The name is the returned packet will be in canonical form.) s -5 129 M -(Ylonen & Lehtinen Expires April 1, 2002 [Page 18]) s -_R -S -PStoPSsaved restore -%%Page: (18,19) 10 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 19 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2001) s -5 690 M -( If an error occurs, the server may also respond with SSH_FXP_STATUS.) s -5 129 M -(Ylonen & Lehtinen Expires April 1, 2002 [Page 19]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 20 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2001) s -5 690 M -(7. Responses from the Server to the Client) s -5 668 M -( The server responds to the client using one of a few response) s -5 657 M -( packets. All requests can return a SSH_FXP_STATUS response upon) s -5 646 M -( failure. When the operation is successful, any of the responses may) s -5 635 M -( be returned \(depending on the operation\). If no data needs to be) s -5 624 M -( returned to the client, the SSH_FXP_STATUS response with SSH_FX_OK) s -5 613 M -( status is appropriate. Otherwise, the SSH_FXP_HANDLE message is used) s -5 602 M -( to return a file handle \(for SSH_FXP_OPEN and SSH_FXP_OPENDIR) s -5 591 M -( requests\), SSH_FXP_DATA is used to return data from SSH_FXP_READ,) s -5 580 M -( SSH_FXP_NAME is used to return one or more file names from a) s -5 569 M -( SSH_FXP_READDIR or SSH_FXP_REALPATH request, and SSH_FXP_ATTRS is) s -5 558 M -( used to return file attributes from SSH_FXP_STAT, SSH_FXP_LSTAT, and) s -5 547 M -( SSH_FXP_FSTAT requests.) s -5 525 M -( Exactly one response will be returned for each request. Each) s -5 514 M -( response packet contains a request identifier which can be used to) s -5 503 M -( match each response with the corresponding request. Note that it is) s -5 492 M -( legal to have several requests outstanding simultaneously, and the) s -5 481 M -( server is allowed to send responses to them in a different order from) s -5 470 M -( the order in which the requests were sent \(the result of their) s -5 459 M -( execution, however, is guaranteed to be as if they had been processed) s -5 448 M -( one at a time in the order in which the requests were sent\).) s -5 426 M -( Response packets are of the same general format as request packets.) s -5 415 M -( Each response packet begins with the request identifier.) s -5 393 M -( The format of the data portion of the SSH_FXP_STATUS response is as) s -5 382 M -( follows:) s -5 360 M -( uint32 id) s -5 349 M -( uint32 error/status code) s -5 338 M -( string error message \(ISO-10646 UTF-8 [RFC-2279]\)) s -5 327 M -( string language tag \(as defined in [RFC-1766]\)) s -5 305 M -( where `id' is the request identifier, and `error/status code') s -5 294 M -( indicates the result of the requested operation. The value SSH_FX_OK) s -5 283 M -( indicates success, and all other values indicate failure.) s -5 129 M -(Ylonen & Lehtinen Expires April 1, 2002 [Page 20]) s -_R -S -PStoPSsaved restore -%%Page: (20,21) 11 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 21 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2001) s -5 690 M -( Currently, the following values are defined \(other values may be) s -5 679 M -( defined by future versions of this protocol\):) s -5 657 M -( #define SSH_FX_OK 0) s -5 646 M -( #define SSH_FX_EOF 1) s -5 635 M -( #define SSH_FX_NO_SUCH_FILE 2) s -5 624 M -( #define SSH_FX_PERMISSION_DENIED 3) s -5 613 M -( #define SSH_FX_FAILURE 4) s -5 602 M -( #define SSH_FX_BAD_MESSAGE 5) s -5 591 M -( #define SSH_FX_NO_CONNECTION 6) s -5 580 M -( #define SSH_FX_CONNECTION_LOST 7) s -5 569 M -( #define SSH_FX_OP_UNSUPPORTED 8) s -5 547 M -( SSH_FX_OK) s -5 536 M -( Indicates successful completion of the operation.) s -5 514 M -( SSH_FX_EOF) s -5 503 M -( indicates end-of-file condition; for SSH_FX_READ it means that no) s -5 492 M -( more data is available in the file, and for SSH_FX_READDIR it) s -5 481 M -( indicates that no more files are contained in the directory.) s -5 459 M -( SSH_FX_NO_SUCH_FILE) s -5 448 M -( is returned when a reference is made to a file which should exist) s -5 437 M -( but doesn't.) s -5 415 M -( SSH_FX_PERMISSION_DENIED) s -5 404 M -( is returned when the authenticated user does not have sufficient) s -5 393 M -( permissions to perform the operation.) s -5 371 M -( SSH_FX_FAILURE) s -5 360 M -( is a generic catch-all error message; it should be returned if an) s -5 349 M -( error occurs for which there is no more specific error code) s -5 338 M -( defined.) s -5 316 M -( SSH_FX_BAD_MESSAGE) s -5 305 M -( may be returned if a badly formatted packet or protocol) s -5 294 M -( incompatibility is detected.) s -5 272 M -( SSH_FX_NO_CONNECTION) s -5 261 M -( is a pseudo-error which indicates that the client has no) s -5 250 M -( connection to the server \(it can only be generated locally by the) s -5 239 M -( client, and MUST NOT be returned by servers\).) s -5 217 M -( SSH_FX_CONNECTION_LOST) s -5 206 M -( is a pseudo-error which indicates that the connection to the) s -5 195 M -( server has been lost \(it can only be generated locally by the) s -5 184 M -( client, and MUST NOT be returned by servers\).) s -5 129 M -(Ylonen & Lehtinen Expires April 1, 2002 [Page 21]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 22 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2001) s -5 690 M -( SSH_FX_OP_UNSUPPORTED) s -5 679 M -( indicates that an attempt was made to perform an operation which) s -5 668 M -( is not supported for the server \(it may be generated locally by) s -5 657 M -( the client if e.g. the version number exchange indicates that a) s -5 646 M -( required feature is not supported by the server, or it may be) s -5 635 M -( returned by the server if the server does not implement an) s -5 624 M -( operation\).) s -5 602 M -( The SSH_FXP_HANDLE response has the following format:) s -5 580 M -( uint32 id) s -5 569 M -( string handle) s -5 547 M -( where `id' is the request identifier, and `handle' is an arbitrary) s -5 536 M -( string that identifies an open file or directory on the server. The) s -5 525 M -( handle is opaque to the client; the client MUST NOT attempt to) s -5 514 M -( interpret or modify it in any way. The length of the handle string) s -5 503 M -( MUST NOT exceed 256 data bytes.) s -5 481 M -( The SSH_FXP_DATA response has the following format:) s -5 459 M -( uint32 id) s -5 448 M -( string data) s -5 426 M -( where `id' is the request identifier, and `data' is an arbitrary byte) s -5 415 M -( string containing the requested data. The data string may be at most) s -5 404 M -( the number of bytes requested in a SSH_FXP_READ request, but may also) s -5 393 M -( be shorter if end of file is reached or if the read is from something) s -5 382 M -( other than a regular file.) s -5 360 M -( The SSH_FXP_NAME response has the following format:) s -5 338 M -( uint32 id) s -5 327 M -( uint32 count) s -5 316 M -( repeats count times:) s -5 305 M -( string filename) s -5 294 M -( string longname) s -5 283 M -( ATTRS attrs) s -5 261 M -( where `id' is the request identifier, `count' is the number of names) s -5 250 M -( returned in this response, and the remaining fields repeat `count') s -5 239 M -( times \(so that all three fields are first included for the first) s -5 228 M -( file, then for the second file, etc\). In the repeated part,) s -5 217 M -( `filename' is a file name being returned \(for SSH_FXP_READDIR, it) s -5 206 M -( will be a relative name within the directory, without any path) s -5 195 M -( components; for SSH_FXP_REALPATH it will be an absolute path name\),) s -5 184 M -( `longname' is an expanded format for the file name, similar to what) s -5 173 M -( is returned by "ls -l" on Unix systems, and `attrs' is the attributes) s -5 129 M -(Ylonen & Lehtinen Expires April 1, 2002 [Page 22]) s -_R -S -PStoPSsaved restore -%%Page: (22,23) 12 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 23 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2001) s -5 690 M -( of the file as described in Section ``File Attributes''.) s -5 668 M -( The format of the `longname' field is unspecified by this protocol.) s -5 657 M -( It MUST be suitable for use in the output of a directory listing) s -5 646 M -( command \(in fact, the recommended operation for a directory listing) s -5 635 M -( command is to simply display this data\). However, clients SHOULD NOT) s -5 624 M -( attempt to parse the longname field for file attributes; they SHOULD) s -5 613 M -( use the attrs field instead.) s -5 591 M -( The recommended format for the longname field is as follows:) s -5 569 M -( -rwxr-xr-x 1 mjos staff 348911 Mar 25 14:29 t-filexfer) s -5 558 M -( 1234567890 123 12345678 12345678 12345678 123456789012) s -5 536 M -( Here, the first line is sample output, and the second field indicates) s -5 525 M -( widths of the various fields. Fields are separated by spaces. The) s -5 514 M -( first field lists file permissions for user, group, and others; the) s -5 503 M -( second field is link count; the third field is the name of the user) s -5 492 M -( who owns the file; the fourth field is the name of the group that) s -5 481 M -( owns the file; the fifth field is the size of the file in bytes; the) s -5 470 M -( sixth field \(which actually may contain spaces, but is fixed to 12) s -5 459 M -( characters\) is the file modification time, and the seventh field is) s -5 448 M -( the file name. Each field is specified to be a minimum of certain) s -5 437 M -( number of character positions \(indicated by the second line above\),) s -5 426 M -( but may also be longer if the data does not fit in the specified) s -5 415 M -( length.) s -5 393 M -( The SSH_FXP_ATTRS response has the following format:) s -5 371 M -( uint32 id) s -5 360 M -( ATTRS attrs) s -5 338 M -( where `id' is the request identifier, and `attrs' is the returned) s -5 327 M -( file attributes as described in Section ``File Attributes''.) s -5 129 M -(Ylonen & Lehtinen Expires April 1, 2002 [Page 23]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 24 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2001) s -5 690 M -(8. Vendor-Specific Extensions) s -5 668 M -( The SSH_FXP_EXTENDED request provides a generic extension mechanism) s -5 657 M -( for adding vendor-specific commands. The request has the following) s -5 646 M -( format:) s -5 624 M -( uint32 id) s -5 613 M -( string extended-request) s -5 602 M -( ... any request-specific data ...) s -5 580 M -( where `id' is the request identifier, and `extended-request' is a) s -5 569 M -( string of the format "name@domain", where domain is an internet) s -5 558 M -( domain name of the vendor defining the request. The rest of the) s -5 547 M -( request is completely vendor-specific, and servers should only) s -5 536 M -( attempt to interpret it if they recognize the `extended-request') s -5 525 M -( name.) s -5 503 M -( The server may respond to such requests using any of the response) s -5 492 M -( packets defined in Section ``Responses from the Server to the) s -5 481 M -( Client''. Additionally, the server may also respond with a) s -5 470 M -( SSH_FXP_EXTENDED_REPLY packet, as defined below. If the server does) s -5 459 M -( not recognize the `extended-request' name, then the server MUST) s -5 448 M -( respond with SSH_FXP_STATUS with error/status set to) s -5 437 M -( SSH_FX_OP_UNSUPPORTED.) s -5 415 M -( The SSH_FXP_EXTENDED_REPLY packet can be used to carry arbitrary) s -5 404 M -( extension-specific data from the server to the client. It is of the) s -5 393 M -( following format:) s -5 371 M -( uint32 id) s -5 360 M -( ... any request-specific data ...) s -5 129 M -(Ylonen & Lehtinen Expires April 1, 2002 [Page 24]) s -_R -S -PStoPSsaved restore -%%Page: (24,25) 13 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 25 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2001) s -5 690 M -(9. Security Considerations) s -5 668 M -( This protocol assumes that it is run over a secure channel and that) s -5 657 M -( the endpoints of the channel have been authenticated. Thus, this) s -5 646 M -( protocol assumes that it is externally protected from network-level) s -5 635 M -( attacks.) s -5 613 M -( This protocol provides file system access to arbitrary files on the) s -5 602 M -( server \(only constrained by the server implementation\). It is the) s -5 591 M -( responsibility of the server implementation to enforce any access) s -5 580 M -( controls that may be required to limit the access allowed for any) s -5 569 M -( particular user \(the user being authenticated externally to this) s -5 558 M -( protocol, typically using the SSH User Authentication Protocol [6].) s -5 536 M -( Care must be taken in the server implementation to check the validity) s -5 525 M -( of received file handle strings. The server should not rely on them) s -5 514 M -( directly; it MUST check the validity of each handle before relying on) s -5 503 M -( it.) s -5 129 M -(Ylonen & Lehtinen Expires April 1, 2002 [Page 25]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 26 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2001) s -5 690 M -(10. Changes from previous protocol versions) s -5 668 M -( The SSH File Transfer Protocol has changed over time, before it's) s -5 657 M -( standardization. The following is a description of the incompatible) s -5 646 M -( changes between different versions.) s -5 624 M -(10.1 Changes between versions 3 and 2) s -5 602 M -( o The SSH_FXP_READLINK and SSH_FXP_SYMLINK messages were added.) s -5 580 M -( o The SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY messages were) s -5 569 M -( added.) s -5 547 M -( o The SSH_FXP_STATUS message was changed to include fields `error) s -5 536 M -( message' and `language tag'.) s -5 503 M -(10.2 Changes between versions 2 and 1) s -5 481 M -( o The SSH_FXP_RENAME message was added.) s -5 448 M -(10.3 Changes between versions 1 and 0) s -5 426 M -( o Implementation changes, no actual protocol changes.) s -5 129 M -(Ylonen & Lehtinen Expires April 1, 2002 [Page 26]) s -_R -S -PStoPSsaved restore -%%Page: (26,27) 14 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 27 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2001) s -5 690 M -(11. Trademark Issues) s -5 668 M -( "ssh" is a registered trademark of SSH Communications Security Corp) s -5 657 M -( in the United States and/or other countries.) s -5 129 M -(Ylonen & Lehtinen Expires April 1, 2002 [Page 27]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 28 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2001) s -5 690 M -(References) s -5 668 M -( [1] Dierks, T., Allen, C., Treese, W., Karlton, P., Freier, A. and) s -5 657 M -( P. Kocher, "The TLS Protocol Version 1.0", RFC 2246, January) s -5 646 M -( 1999.) s -5 624 M -( [2] Institute of Electrical and Electronics Engineers, "Information) s -5 613 M -( Technology - Portable Operating System Interface \(POSIX\) - Part) s -5 602 M -( 1: System Application Program Interface \(API\) [C Language]",) s -5 591 M -( IEEE Standard 1003.2, 1996.) s -5 569 M -( [3] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S.) s -5 558 M -( Lehtinen, "SSH Protocol Architecture", draft-ietf-secsh-) s -5 547 M -( architecture-09 \(work in progress\), July 2001.) s -5 525 M -( [4] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S.) s -5 514 M -( Lehtinen, "SSH Protocol Transport Protocol", draft-ietf-secsh-) s -5 503 M -( architecture-09 \(work in progress\), July 2001.) s -5 481 M -( [5] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S.) s -5 470 M -( Lehtinen, "SSH Connection Protocol", draft-ietf-secsh-connect-11) s -5 459 M -( \(work in progress\), July 2001.) s -5 437 M -( [6] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S.) s -5 426 M -( Lehtinen, "SSH Authentication Protocol", draft-ietf-secsh-) s -5 415 M -( userauth-11 \(work in progress\), July 2001.) s -5 382 M -(Authors' Addresses) s -5 360 M -( Tatu Ylonen) s -5 349 M -( SSH Communications Security Corp) s -5 338 M -( Fredrikinkatu 42) s -5 327 M -( HELSINKI FIN-00100) s -5 316 M -( Finland) s -5 294 M -( EMail: [email protected]) s -5 261 M -( Sami Lehtinen) s -5 250 M -( SSH Communications Security Corp) s -5 239 M -( Fredrikinkatu 42) s -5 228 M -( HELSINKI FIN-00100) s -5 217 M -( Finland) s -5 195 M -( EMail: [email protected]) s -5 129 M -(Ylonen & Lehtinen Expires April 1, 2002 [Page 28]) s -_R -S -PStoPSsaved restore -%%Page: (28,29) 15 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 29 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2001) s -5 690 M -(Full Copyright Statement) s -5 668 M -( Copyright \(C\) The Internet Society \(2001\). All Rights Reserved.) s -5 646 M -( This document and translations of it may be copied and furnished to) s -5 635 M -( others, and derivative works that comment on or otherwise explain it) s -5 624 M -( or assist in its implementation may be prepared, copied, published) s -5 613 M -( and distributed, in whole or in part, without restriction of any) s -5 602 M -( kind, provided that the above copyright notice and this paragraph are) s -5 591 M -( included on all such copies and derivative works. However, this) s -5 580 M -( document itself may not be modified in any way, such as by removing) s -5 569 M -( the copyright notice or references to the Internet Society or other) s -5 558 M -( Internet organizations, except as needed for the purpose of) s -5 547 M -( developing Internet standards in which case the procedures for) s -5 536 M -( copyrights defined in the Internet Standards process must be) s -5 525 M -( followed, or as required to translate it into languages other than) s -5 514 M -( English.) s -5 492 M -( The limited permissions granted above are perpetual and will not be) s -5 481 M -( revoked by the Internet Society or its successors or assigns.) s -5 459 M -( This document and the information contained herein is provided on an) s -5 448 M -( "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING) s -5 437 M -( TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING) s -5 426 M -( BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION) s -5 415 M -( HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF) s -5 404 M -( MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.) s -5 382 M -(Acknowledgement) s -5 360 M -( Funding for the RFC Editor function is currently provided by the) s -5 349 M -( Internet Society.) s -5 129 M -(Ylonen & Lehtinen Expires April 1, 2002 [Page 29]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 30 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -_R -S -PStoPSsaved restore -%%Trailer -%%Pages: 30 -%%DocumentNeededResources: font Courier-Bold Courier -%%EOF diff --git a/lib/ssh/doc/standard/draft-ietf-secsh-filexfer-02.txt b/lib/ssh/doc/standard/draft-ietf-secsh-filexfer-02.txt deleted file mode 100644 index c4ec8c1125..0000000000 --- a/lib/ssh/doc/standard/draft-ietf-secsh-filexfer-02.txt +++ /dev/null @@ -1,1627 +0,0 @@ - - - -Network Working Group T. Ylonen -Internet-Draft S. Lehtinen -Expires: April 1, 2002 SSH Communications Security Corp - October 2001 - - - SSH File Transfer Protocol - draft-ietf-secsh-filexfer-02.txt - -Status of this Memo - - This document is an Internet-Draft and is in full conformance with - all provisions of Section 10 of RFC2026. - - Internet-Drafts are working documents of the Internet Engineering - Task Force (IETF), its areas, and its working groups. Note that - other groups may also distribute working documents as Internet- - Drafts. - - Internet-Drafts are draft documents valid for a maximum of six months - and may be updated, replaced, or obsoleted by other documents at any - time. It is inappropriate to use Internet-Drafts as reference - material or to cite them other than as "work in progress." - - The list of current Internet-Drafts can be accessed at http:// - www.ietf.org/ietf/1id-abstracts.txt. - - The list of Internet-Draft Shadow Directories can be accessed at - http://www.ietf.org/shadow.html. - - This Internet-Draft will expire on April 1, 2002. - -Copyright Notice - - Copyright (C) The Internet Society (2001). All Rights Reserved. - -Abstract - - The SSH File Transfer Protocol provides secure file transfer - functionality over any reliable data stream. It is the standard file - transfer protocol for use with the SSH2 protocol. This document - describes the file transfer protocol and its interface to the SSH2 - protocol suite. - - - - - - - - - -Ylonen & Lehtinen Expires April 1, 2002 [Page 1] - -Internet-Draft SSH File Transfer Protocol October 2001 - - -Table of Contents - - 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 - 2. Use with the SSH Connection Protocol . . . . . . . . . . . . 4 - 3. General Packet Format . . . . . . . . . . . . . . . . . . . 5 - 4. Protocol Initialization . . . . . . . . . . . . . . . . . . 7 - 5. File Attributes . . . . . . . . . . . . . . . . . . . . . . 8 - 6. Requests From the Client to the Server . . . . . . . . . . . 10 - 6.1 Request Synchronization and Reordering . . . . . . . . . . . 10 - 6.2 File Names . . . . . . . . . . . . . . . . . . . . . . . . . 11 - 6.3 Opening, Creating, and Closing Files . . . . . . . . . . . . 11 - 6.4 Reading and Writing . . . . . . . . . . . . . . . . . . . . 13 - 6.5 Removing and Renaming Files . . . . . . . . . . . . . . . . 14 - 6.6 Creating and Deleting Directories . . . . . . . . . . . . . 15 - 6.7 Scanning Directories . . . . . . . . . . . . . . . . . . . . 15 - 6.8 Retrieving File Attributes . . . . . . . . . . . . . . . . . 16 - 6.9 Setting File Attributes . . . . . . . . . . . . . . . . . . 17 - 6.10 Dealing with Symbolic links . . . . . . . . . . . . . . . . 18 - 6.11 Canonicalizing the Server-Side Path Name . . . . . . . . . . 18 - 7. Responses from the Server to the Client . . . . . . . . . . 20 - 8. Vendor-Specific Extensions . . . . . . . . . . . . . . . . . 24 - 9. Security Considerations . . . . . . . . . . . . . . . . . . 25 - 10. Changes from previous protocol versions . . . . . . . . . . 26 - 10.1 Changes between versions 3 and 2 . . . . . . . . . . . . . . 26 - 10.2 Changes between versions 2 and 1 . . . . . . . . . . . . . . 26 - 10.3 Changes between versions 1 and 0 . . . . . . . . . . . . . . 26 - 11. Trademark Issues . . . . . . . . . . . . . . . . . . . . . . 27 - References . . . . . . . . . . . . . . . . . . . . . . . . . 28 - Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 28 - Full Copyright Statement . . . . . . . . . . . . . . . . . . 29 - - - - - - - - - - - - - - - - - - - - - -Ylonen & Lehtinen Expires April 1, 2002 [Page 2] - -Internet-Draft SSH File Transfer Protocol October 2001 - - -1. Introduction - - This protocol provides secure file transfer (and more generally file - system access) functionality over a reliable data stream, such as a - channel in the SSH2 protocol [3]. - - This protocol is designed so that it could be used to implement a - secure remote file system service, as well as a secure file transfer - service. - - This protocol assumes that it runs over a secure channel, and that - the server has already authenticated the user at the client end, and - that the identity of the client user is externally available to the - server implementation. - - In general, this protocol follows a simple request-response model. - Each request and response contains a sequence number and multiple - requests may be pending simultaneously. There are a relatively large - number of different request messages, but a small number of possible - response messages. Each request has one or more response messages - that may be returned in result (e.g., a read either returns data or - reports error status). - - The packet format descriptions in this specification follow the - notation presented in the secsh architecture draft.[3]. - - Even though this protocol is described in the context of the SSH2 - protocol, this protocol is general and independent of the rest of the - SSH2 protocol suite. It could be used in a number of different - applications, such as secure file transfer over TLS RFC 2246 [1] and - transfer of management information in VPN applications. - - - - - - - - - - - - - - - - - - - - -Ylonen & Lehtinen Expires April 1, 2002 [Page 3] - -Internet-Draft SSH File Transfer Protocol October 2001 - - -2. Use with the SSH Connection Protocol - - When used with the SSH2 Protocol suite, this protocol is intended to - be used from the SSH Connection Protocol [5] as a subsystem, as - described in section ``Starting a Shell or a Command''. The - subsystem name used with this protocol is "sftp". - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Ylonen & Lehtinen Expires April 1, 2002 [Page 4] - -Internet-Draft SSH File Transfer Protocol October 2001 - - -3. General Packet Format - - All packets transmitted over the secure connection are of the - following format: - - uint32 length - byte type - byte[length - 1] data payload - - That is, they are just data preceded by 32-bit length and 8-bit type - fields. The `length' is the length of the data area, and does not - include the `length' field itself. The format and interpretation of - the data area depends on the packet type. - - All packet descriptions below only specify the packet type and the - data that goes into the data field. Thus, they should be prefixed by - the `length' and `type' fields. - - The maximum size of a packet is in practice determined by the client - (the maximum size of read or write requests that it sends, plus a few - bytes of packet overhead). All servers SHOULD support packets of at - least 34000 bytes (where the packet size refers to the full length, - including the header above). This should allow for reads and writes - of at most 32768 bytes. - - There is no limit on the number of outstanding (non-acknowledged) - requests that the client may send to the server. In practice this is - limited by the buffering available on the data stream and the queuing - performed by the server. If the server's queues are full, it should - not read any more data from the stream, and flow control will prevent - the client from sending more requests. Note, however, that while - there is no restriction on the protocol level, the client's API may - provide a limit in order to prevent infinite queuing of outgoing - requests at the client. - - - - - - - - - - - - - - - - - -Ylonen & Lehtinen Expires April 1, 2002 [Page 5] - -Internet-Draft SSH File Transfer Protocol October 2001 - - - The following values are defined for packet types. - - #define SSH_FXP_INIT 1 - #define SSH_FXP_VERSION 2 - #define SSH_FXP_OPEN 3 - #define SSH_FXP_CLOSE 4 - #define SSH_FXP_READ 5 - #define SSH_FXP_WRITE 6 - #define SSH_FXP_LSTAT 7 - #define SSH_FXP_FSTAT 8 - #define SSH_FXP_SETSTAT 9 - #define SSH_FXP_FSETSTAT 10 - #define SSH_FXP_OPENDIR 11 - #define SSH_FXP_READDIR 12 - #define SSH_FXP_REMOVE 13 - #define SSH_FXP_MKDIR 14 - #define SSH_FXP_RMDIR 15 - #define SSH_FXP_REALPATH 16 - #define SSH_FXP_STAT 17 - #define SSH_FXP_RENAME 18 - #define SSH_FXP_READLINK 19 - #define SSH_FXP_SYMLINK 20 - #define SSH_FXP_STATUS 101 - #define SSH_FXP_HANDLE 102 - #define SSH_FXP_DATA 103 - #define SSH_FXP_NAME 104 - #define SSH_FXP_ATTRS 105 - #define SSH_FXP_EXTENDED 200 - #define SSH_FXP_EXTENDED_REPLY 201 - - Additional packet types should only be defined if the protocol - version number (see Section ``Protocol Initialization'') is - incremented, and their use MUST be negotiated using the version - number. However, the SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY - packets can be used to implement vendor-specific extensions. See - Section ``Vendor-Specific-Extensions'' for more details. - - - - - - - - - - - - - - - -Ylonen & Lehtinen Expires April 1, 2002 [Page 6] - -Internet-Draft SSH File Transfer Protocol October 2001 - - -4. Protocol Initialization - - When the file transfer protocol starts, it first sends a SSH_FXP_INIT - (including its version number) packet to the server. The server - responds with a SSH_FXP_VERSION packet, supplying the lowest of its - own and the client's version number. Both parties should from then - on adhere to particular version of the protocol. - - The SSH_FXP_INIT packet (from client to server) has the following - data: - - uint32 version - <extension data> - - The SSH_FXP_VERSION packet (from server to client) has the following - data: - - uint32 version - <extension data> - - The version number of the protocol specified in this document is 3. - The version number should be incremented for each incompatible - revision of this protocol. - - The extension data in the above packets may be empty, or may be a - sequence of - - string extension_name - string extension_data - - pairs (both strings MUST always be present if one is, but the - `extension_data' string may be of zero length). If present, these - strings indicate extensions to the baseline protocol. The - `extension_name' field(s) identify the name of the extension. The - name should be of the form "name@domain", where the domain is the DNS - domain name of the organization defining the extension. Additional - names that are not of this format may be defined later by the IETF. - Implementations MUST silently ignore any extensions whose name they - do not recognize. - - - - - - - - - - - - -Ylonen & Lehtinen Expires April 1, 2002 [Page 7] - -Internet-Draft SSH File Transfer Protocol October 2001 - - -5. File Attributes - - A new compound data type is defined for encoding file attributes. It - is basically just a combination of elementary types, but is defined - once because of the non-trivial description of the fields and to - ensure maintainability. - - The same encoding is used both when returning file attributes from - the server and when sending file attributes to the server. When - sending it to the server, the flags field specifies which attributes - are included, and the server will use default values for the - remaining attributes (or will not modify the values of remaining - attributes). When receiving attributes from the server, the flags - specify which attributes are included in the returned data. The - server normally returns all attributes it knows about. - - uint32 flags - uint64 size present only if flag SSH_FILEXFER_ATTR_SIZE - uint32 uid present only if flag SSH_FILEXFER_ATTR_UIDGID - uint32 gid present only if flag SSH_FILEXFER_ATTR_UIDGID - uint32 permissions present only if flag SSH_FILEXFER_ATTR_PERMISSIONS - uint32 atime present only if flag SSH_FILEXFER_ACMODTIME - uint32 mtime present only if flag SSH_FILEXFER_ACMODTIME - uint32 extended_count present only if flag SSH_FILEXFER_ATTR_EXTENDED - string extended_type - string extended_data - ... more extended data (extended_type - extended_data pairs), - so that number of pairs equals extended_count - - The `flags' specify which of the fields are present. Those fields - for which the corresponding flag is not set are not present (not - included in the packet). New flags can only be added by incrementing - the protocol version number (or by using the extension mechanism - described below). - - The `size' field specifies the size of the file in bytes. - - The `uid' and `gid' fields contain numeric Unix-like user and group - identifiers, respectively. - - The `permissions' field contains a bit mask of file permissions as - defined by posix [1]. - - The `atime' and `mtime' contain the access and modification times of - the files, respectively. They are represented as seconds from Jan 1, - 1970 in UTC. - - The SSH_FILEXFER_ATTR_EXTENDED flag provides a general extension - - - -Ylonen & Lehtinen Expires April 1, 2002 [Page 8] - -Internet-Draft SSH File Transfer Protocol October 2001 - - - mechanism for vendor-specific extensions. If the flag is specified, - then the `extended_count' field is present. It specifies the number - of extended_type-extended_data pairs that follow. Each of these - pairs specifies an extended attribute. For each of the attributes, - the extended_type field should be a string of the format - "name@domain", where "domain" is a valid, registered domain name and - "name" identifies the method. The IETF may later standardize certain - names that deviate from this format (e.g., that do not contain the - "@" sign). The interpretation of `extended_data' depends on the - type. Implementations SHOULD ignore extended data fields that they - do not understand. - - Additional fields can be added to the attributes by either defining - additional bits to the flags field to indicate their presence, or by - defining extended attributes for them. The extended attributes - mechanism is recommended for most purposes; additional flags bits - should only be defined by an IETF standards action that also - increments the protocol version number. The use of such new fields - MUST be negotiated by the version number in the protocol exchange. - It is a protocol error if a packet with unsupported protocol bits is - received. - - The flags bits are defined to have the following values: - - #define SSH_FILEXFER_ATTR_SIZE 0x00000001 - #define SSH_FILEXFER_ATTR_UIDGID 0x00000002 - #define SSH_FILEXFER_ATTR_PERMISSIONS 0x00000004 - #define SSH_FILEXFER_ATTR_ACMODTIME 0x00000008 - #define SSH_FILEXFER_ATTR_EXTENDED 0x80000000 - - - - - - - - - - - - - - - - - - - - - - -Ylonen & Lehtinen Expires April 1, 2002 [Page 9] - -Internet-Draft SSH File Transfer Protocol October 2001 - - -6. Requests From the Client to the Server - - Requests from the client to the server represent the various file - system operations. Each request begins with an `id' field, which is - a 32-bit identifier identifying the request (selected by the client). - The same identifier will be returned in the response to the request. - One possible implementation of it is a monotonically increasing - request sequence number (modulo 2^32). - - Many operations in the protocol operate on open files. The - SSH_FXP_OPEN request can return a file handle (which is an opaque - variable-length string) which may be used to access the file later - (e.g. in a read operation). The client MUST NOT send requests the - server with bogus or closed handles. However, the server MUST - perform adequate checks on the handle in order to avoid security - risks due to fabricated handles. - - This design allows either stateful and stateless server - implementation, as well as an implementation which caches state - between requests but may also flush it. The contents of the file - handle string are entirely up to the server and its design. The - client should not modify or attempt to interpret the file handle - strings. - - The file handle strings MUST NOT be longer than 256 bytes. - -6.1 Request Synchronization and Reordering - - The protocol and implementations MUST process requests relating to - the same file in the order in which they are received. In other - words, if an application submits multiple requests to the server, the - results in the responses will be the same as if it had sent the - requests one at a time and waited for the response in each case. For - example, the server may process non-overlapping read/write requests - to the same file in parallel, but overlapping reads and writes cannot - be reordered or parallelized. However, there are no ordering - restrictions on the server for processing requests from two different - file transfer connections. The server may interleave and parallelize - them at will. - - There are no restrictions on the order in which responses to - outstanding requests are delivered to the client, except that the - server must ensure fairness in the sense that processing of no - request will be indefinitely delayed even if the client is sending - other requests so that there are multiple outstanding requests all - the time. - - - - - -Ylonen & Lehtinen Expires April 1, 2002 [Page 10] - -Internet-Draft SSH File Transfer Protocol October 2001 - - -6.2 File Names - - This protocol represents file names as strings. File names are - assumed to use the slash ('/') character as a directory separator. - - File names starting with a slash are "absolute", and are relative to - the root of the file system. Names starting with any other character - are relative to the user's default directory (home directory). Note - that identifying the user is assumed to take place outside of this - protocol. - - Servers SHOULD interpret a path name component ".." as referring to - the parent directory, and "." as referring to the current directory. - If the server implementation limits access to certain parts of the - file system, it must be extra careful in parsing file names when - enforcing such restrictions. There have been numerous reported - security bugs where a ".." in a path name has allowed access outside - the intended area. - - An empty path name is valid, and it refers to the user's default - directory (usually the user's home directory). - - Otherwise, no syntax is defined for file names by this specification. - Clients should not make any other assumptions; however, they can - splice path name components returned by SSH_FXP_READDIR together - using a slash ('/') as the separator, and that will work as expected. - - It is understood that the lack of well-defined semantics for file - names may cause interoperability problems between clients and servers - using radically different operating systems. However, this approach - is known to work acceptably with most systems, and alternative - approaches that e.g. treat file names as sequences of structured - components are quite complicated. - -6.3 Opening, Creating, and Closing Files - - Files are opened and created using the SSH_FXP_OPEN message, whose - data part is as follows: - - uint32 id - string filename - uint32 pflags - ATTRS attrs - - The `id' field is the request identifier as for all requests. - - The `filename' field specifies the file name. See Section ``File - Names'' for more information. - - - -Ylonen & Lehtinen Expires April 1, 2002 [Page 11] - -Internet-Draft SSH File Transfer Protocol October 2001 - - - The `pflags' field is a bitmask. The following bits have been - defined. - - #define SSH_FXF_READ 0x00000001 - #define SSH_FXF_WRITE 0x00000002 - #define SSH_FXF_APPEND 0x00000004 - #define SSH_FXF_CREAT 0x00000008 - #define SSH_FXF_TRUNC 0x00000010 - #define SSH_FXF_EXCL 0x00000020 - - These have the following meanings: - - SSH_FXF_READ - Open the file for reading. - - SSH_FXF_WRITE - Open the file for writing. If both this and SSH_FXF_READ are - specified, the file is opened for both reading and writing. - - SSH_FXF_APPEND - Force all writes to append data at the end of the file. - - SSH_FXF_CREAT - If this flag is specified, then a new file will be created if one - does not already exist (if O_TRUNC is specified, the new file will - be truncated to zero length if it previously exists). - - SSH_FXF_TRUNC - Forces an existing file with the same name to be truncated to zero - length when creating a file by specifying SSH_FXF_CREAT. - SSH_FXF_CREAT MUST also be specified if this flag is used. - - SSH_FXF_EXCL - Causes the request to fail if the named file already exists. - SSH_FXF_CREAT MUST also be specified if this flag is used. - - The `attrs' field specifies the initial attributes for the file. - Default values will be used for those attributes that are not - specified. See Section ``File Attributes'' for more information. - - Regardless the server operating system, the file will always be - opened in "binary" mode (i.e., no translations between different - character sets and newline encodings). - - The response to this message will be either SSH_FXP_HANDLE (if the - operation is successful) or SSH_FXP_STATUS (if the operation fails). - - - - - -Ylonen & Lehtinen Expires April 1, 2002 [Page 12] - -Internet-Draft SSH File Transfer Protocol October 2001 - - - A file is closed by using the SSH_FXP_CLOSE request. Its data field - has the following format: - - uint32 id - string handle - - where `id' is the request identifier, and `handle' is a handle - previously returned in the response to SSH_FXP_OPEN or - SSH_FXP_OPENDIR. The handle becomes invalid immediately after this - request has been sent. - - The response to this request will be a SSH_FXP_STATUS message. One - should note that on some server platforms even a close can fail. - This can happen e.g. if the server operating system caches writes, - and an error occurs while flushing cached writes during the close. - -6.4 Reading and Writing - - Once a file has been opened, it can be read using the SSH_FXP_READ - message, which has the following format: - - uint32 id - string handle - uint64 offset - uint32 len - - where `id' is the request identifier, `handle' is an open file handle - returned by SSH_FXP_OPEN, `offset' is the offset (in bytes) relative - to the beginning of the file from where to start reading, and `len' - is the maximum number of bytes to read. - - In response to this request, the server will read as many bytes as it - can from the file (up to `len'), and return them in a SSH_FXP_DATA - message. If an error occurs or EOF is encountered before reading any - data, the server will respond with SSH_FXP_STATUS. For normal disk - files, it is guaranteed that this will read the specified number of - bytes, or up to end of file. For e.g. device files this may return - fewer bytes than requested. - - Writing to a file is achieved using the SSH_FXP_WRITE message, which - has the following format: - - uint32 id - string handle - uint64 offset - string data - - where `id' is a request identifier, `handle' is a file handle - - - -Ylonen & Lehtinen Expires April 1, 2002 [Page 13] - -Internet-Draft SSH File Transfer Protocol October 2001 - - - returned by SSH_FXP_OPEN, `offset' is the offset (in bytes) from the - beginning of the file where to start writing, and `data' is the data - to be written. - - The write will extend the file if writing beyond the end of the file. - It is legal to write way beyond the end of the file; the semantics - are to write zeroes from the end of the file to the specified offset - and then the data. On most operating systems, such writes do not - allocate disk space but instead leave "holes" in the file. - - The server responds to a write request with a SSH_FXP_STATUS message. - -6.5 Removing and Renaming Files - - Files can be removed using the SSH_FXP_REMOVE message. It has the - following format: - - uint32 id - string filename - - where `id' is the request identifier and `filename' is the name of - the file to be removed. See Section ``File Names'' for more - information. This request cannot be used to remove directories. - - The server will respond to this request with a SSH_FXP_STATUS - message. - - Files (and directories) can be renamed using the SSH_FXP_RENAME - message. Its data is as follows: - - uint32 id - string oldpath - string newpath - - where `id' is the request identifier, `oldpath' is the name of an - existing file or directory, and `newpath' is the new name for the - file or directory. It is an error if there already exists a file - with the name specified by newpath. The server may also fail rename - requests in other situations, for example if `oldpath' and `newpath' - point to different file systems on the server. - - The server will respond to this request with a SSH_FXP_STATUS - message. - - - - - - - - -Ylonen & Lehtinen Expires April 1, 2002 [Page 14] - -Internet-Draft SSH File Transfer Protocol October 2001 - - -6.6 Creating and Deleting Directories - - New directories can be created using the SSH_FXP_MKDIR request. It - has the following format: - - uint32 id - string path - ATTRS attrs - - where `id' is the request identifier, `path' and `attrs' specifies - the modifications to be made to its attributes. See Section ``File - Names'' for more information on file names. Attributes are discussed - in more detail in Section ``File Attributes''. specifies the - directory to be created. An error will be returned if a file or - directory with the specified path already exists. The server will - respond to this request with a SSH_FXP_STATUS message. - - Directories can be removed using the SSH_FXP_RMDIR request, which - has the following format: - - uint32 id - string path - - where `id' is the request identifier, and `path' specifies the - directory to be removed. See Section ``File Names'' for more - information on file names. An error will be returned if no directory - with the specified path exists, or if the specified directory is not - empty, or if the path specified a file system object other than a - directory. The server responds to this request with a SSH_FXP_STATUS - message. - -6.7 Scanning Directories - - The files in a directory can be listed using the SSH_FXP_OPENDIR and - SSH_FXP_READDIR requests. Each SSH_FXP_READDIR request returns one - or more file names with full file attributes for each file. The - client should call SSH_FXP_READDIR repeatedly until it has found the - file it is looking for or until the server responds with a - SSH_FXP_STATUS message indicating an error (normally SSH_FX_EOF if - there are no more files in the directory). The client should then - close the handle using the SSH_FXP_CLOSE request. - - - - - - - - - - -Ylonen & Lehtinen Expires April 1, 2002 [Page 15] - -Internet-Draft SSH File Transfer Protocol October 2001 - - - The SSH_FXP_OPENDIR opens a directory for reading. It has the - following format: - - uint32 id - string path - - where `id' is the request identifier and `path' is the path name of - the directory to be listed (without any trailing slash). See Section - ``File Names'' for more information on file names. This will return - an error if the path does not specify a directory or if the directory - is not readable. The server will respond to this request with either - a SSH_FXP_HANDLE or a SSH_FXP_STATUS message. - - Once the directory has been successfully opened, files (and - directories) contained in it can be listed using SSH_FXP_READDIR - requests. These are of the format - - uint32 id - string handle - - where `id' is the request identifier, and `handle' is a handle - returned by SSH_FXP_OPENDIR. (It is a protocol error to attempt to - use an ordinary file handle returned by SSH_FXP_OPEN.) - - The server responds to this request with either a SSH_FXP_NAME or a - SSH_FXP_STATUS message. One or more names may be returned at a time. - Full status information is returned for each name in order to speed - up typical directory listings. - - When the client no longer wishes to read more names from the - directory, it SHOULD call SSH_FXP_CLOSE for the handle. The handle - should be closed regardless of whether an error has occurred or not. - -6.8 Retrieving File Attributes - - Very often, file attributes are automatically returned by - SSH_FXP_READDIR. However, sometimes there is need to specifically - retrieve the attributes for a named file. This can be done using the - SSH_FXP_STAT, SSH_FXP_LSTAT and SSH_FXP_FSTAT requests. - - SSH_FXP_STAT and SSH_FXP_LSTAT only differ in that SSH_FXP_STAT - follows symbolic links on the server, whereas SSH_FXP_LSTAT does not - follow symbolic links. Both have the same format: - - uint32 id - string path - - where `id' is the request identifier, and `path' specifies the file - - - -Ylonen & Lehtinen Expires April 1, 2002 [Page 16] - -Internet-Draft SSH File Transfer Protocol October 2001 - - - system object for which status is to be returned. The server - responds to this request with either SSH_FXP_ATTRS or SSH_FXP_STATUS. - - SSH_FXP_FSTAT differs from the others in that it returns status - information for an open file (identified by the file handle). Its - format is as follows: - - uint32 id - string handle - - where `id' is the request identifier and `handle' is a file handle - returned by SSH_FXP_OPEN. The server responds to this request with - SSH_FXP_ATTRS or SSH_FXP_STATUS. - -6.9 Setting File Attributes - - File attributes may be modified using the SSH_FXP_SETSTAT and - SSH_FXP_FSETSTAT requests. These requests are used for operations - such as changing the ownership, permissions or access times, as well - as for truncating a file. - - The SSH_FXP_SETSTAT request is of the following format: - - uint32 id - string path - ATTRS attrs - - where `id' is the request identifier, `path' specifies the file - system object (e.g. file or directory) whose attributes are to be - modified, and `attrs' specifies the modifications to be made to its - attributes. Attributes are discussed in more detail in Section - ``File Attributes''. - - An error will be returned if the specified file system object does - not exist or the user does not have sufficient rights to modify the - specified attributes. The server responds to this request with a - SSH_FXP_STATUS message. - - The SSH_FXP_FSETSTAT request modifies the attributes of a file which - is already open. It has the following format: - - uint32 id - string handle - ATTRS attrs - - where `id' is the request identifier, `handle' (MUST be returned by - SSH_FXP_OPEN) identifies the file whose attributes are to be - modified, and `attrs' specifies the modifications to be made to its - - - -Ylonen & Lehtinen Expires April 1, 2002 [Page 17] - -Internet-Draft SSH File Transfer Protocol October 2001 - - - attributes. Attributes are discussed in more detail in Section - ``File Attributes''. The server will respond to this request with - SSH_FXP_STATUS. - -6.10 Dealing with Symbolic links - - The SSH_FXP_READLINK request may be used to read the target of a - symbolic link. It would have a data part as follows: - - uint32 id - string path - - where `id' is the request identifier and `path' specifies the path - name of the symlink to be read. - - The server will respond with a SSH_FXP_NAME packet containing only - one name and a dummy attributes value. The name in the returned - packet contains the target of the link. If an error occurs, the - server may respond with SSH_FXP_STATUS. - - The SSH_FXP_SYMLINK request will create a symbolic link on the - server. It is of the following format - - uint32 id - string linkpath - string targetpath - - where `id' is the request identifier, `linkpath' specifies the path - name of the symlink to be created and `targetpath' specifies the - target of the symlink. The server shall respond with a - SSH_FXP_STATUS indicating either success (SSH_FX_OK) or an error - condition. - -6.11 Canonicalizing the Server-Side Path Name - - The SSH_FXP_REALPATH request can be used to have the server - canonicalize any given path name to an absolute path. This is useful - for converting path names containing ".." components or relative - pathnames without a leading slash into absolute paths. The format of - the request is as follows: - - uint32 id - string path - - where `id' is the request identifier and `path' specifies the path - name to be canonicalized. The server will respond with a - SSH_FXP_NAME packet containing only one name and a dummy attributes - value. The name is the returned packet will be in canonical form. - - - -Ylonen & Lehtinen Expires April 1, 2002 [Page 18] - -Internet-Draft SSH File Transfer Protocol October 2001 - - - If an error occurs, the server may also respond with SSH_FXP_STATUS. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Ylonen & Lehtinen Expires April 1, 2002 [Page 19] - -Internet-Draft SSH File Transfer Protocol October 2001 - - -7. Responses from the Server to the Client - - The server responds to the client using one of a few response - packets. All requests can return a SSH_FXP_STATUS response upon - failure. When the operation is successful, any of the responses may - be returned (depending on the operation). If no data needs to be - returned to the client, the SSH_FXP_STATUS response with SSH_FX_OK - status is appropriate. Otherwise, the SSH_FXP_HANDLE message is used - to return a file handle (for SSH_FXP_OPEN and SSH_FXP_OPENDIR - requests), SSH_FXP_DATA is used to return data from SSH_FXP_READ, - SSH_FXP_NAME is used to return one or more file names from a - SSH_FXP_READDIR or SSH_FXP_REALPATH request, and SSH_FXP_ATTRS is - used to return file attributes from SSH_FXP_STAT, SSH_FXP_LSTAT, and - SSH_FXP_FSTAT requests. - - Exactly one response will be returned for each request. Each - response packet contains a request identifier which can be used to - match each response with the corresponding request. Note that it is - legal to have several requests outstanding simultaneously, and the - server is allowed to send responses to them in a different order from - the order in which the requests were sent (the result of their - execution, however, is guaranteed to be as if they had been processed - one at a time in the order in which the requests were sent). - - Response packets are of the same general format as request packets. - Each response packet begins with the request identifier. - - The format of the data portion of the SSH_FXP_STATUS response is as - follows: - - uint32 id - uint32 error/status code - string error message (ISO-10646 UTF-8 [RFC-2279]) - string language tag (as defined in [RFC-1766]) - - where `id' is the request identifier, and `error/status code' - indicates the result of the requested operation. The value SSH_FX_OK - indicates success, and all other values indicate failure. - - - - - - - - - - - - - -Ylonen & Lehtinen Expires April 1, 2002 [Page 20] - -Internet-Draft SSH File Transfer Protocol October 2001 - - - Currently, the following values are defined (other values may be - defined by future versions of this protocol): - - #define SSH_FX_OK 0 - #define SSH_FX_EOF 1 - #define SSH_FX_NO_SUCH_FILE 2 - #define SSH_FX_PERMISSION_DENIED 3 - #define SSH_FX_FAILURE 4 - #define SSH_FX_BAD_MESSAGE 5 - #define SSH_FX_NO_CONNECTION 6 - #define SSH_FX_CONNECTION_LOST 7 - #define SSH_FX_OP_UNSUPPORTED 8 - - SSH_FX_OK - Indicates successful completion of the operation. - - SSH_FX_EOF - indicates end-of-file condition; for SSH_FX_READ it means that no - more data is available in the file, and for SSH_FX_READDIR it - indicates that no more files are contained in the directory. - - SSH_FX_NO_SUCH_FILE - is returned when a reference is made to a file which should exist - but doesn't. - - SSH_FX_PERMISSION_DENIED - is returned when the authenticated user does not have sufficient - permissions to perform the operation. - - SSH_FX_FAILURE - is a generic catch-all error message; it should be returned if an - error occurs for which there is no more specific error code - defined. - - SSH_FX_BAD_MESSAGE - may be returned if a badly formatted packet or protocol - incompatibility is detected. - - SSH_FX_NO_CONNECTION - is a pseudo-error which indicates that the client has no - connection to the server (it can only be generated locally by the - client, and MUST NOT be returned by servers). - - SSH_FX_CONNECTION_LOST - is a pseudo-error which indicates that the connection to the - server has been lost (it can only be generated locally by the - client, and MUST NOT be returned by servers). - - - - -Ylonen & Lehtinen Expires April 1, 2002 [Page 21] - -Internet-Draft SSH File Transfer Protocol October 2001 - - - SSH_FX_OP_UNSUPPORTED - indicates that an attempt was made to perform an operation which - is not supported for the server (it may be generated locally by - the client if e.g. the version number exchange indicates that a - required feature is not supported by the server, or it may be - returned by the server if the server does not implement an - operation). - - The SSH_FXP_HANDLE response has the following format: - - uint32 id - string handle - - where `id' is the request identifier, and `handle' is an arbitrary - string that identifies an open file or directory on the server. The - handle is opaque to the client; the client MUST NOT attempt to - interpret or modify it in any way. The length of the handle string - MUST NOT exceed 256 data bytes. - - The SSH_FXP_DATA response has the following format: - - uint32 id - string data - - where `id' is the request identifier, and `data' is an arbitrary byte - string containing the requested data. The data string may be at most - the number of bytes requested in a SSH_FXP_READ request, but may also - be shorter if end of file is reached or if the read is from something - other than a regular file. - - The SSH_FXP_NAME response has the following format: - - uint32 id - uint32 count - repeats count times: - string filename - string longname - ATTRS attrs - - where `id' is the request identifier, `count' is the number of names - returned in this response, and the remaining fields repeat `count' - times (so that all three fields are first included for the first - file, then for the second file, etc). In the repeated part, - `filename' is a file name being returned (for SSH_FXP_READDIR, it - will be a relative name within the directory, without any path - components; for SSH_FXP_REALPATH it will be an absolute path name), - `longname' is an expanded format for the file name, similar to what - is returned by "ls -l" on Unix systems, and `attrs' is the attributes - - - -Ylonen & Lehtinen Expires April 1, 2002 [Page 22] - -Internet-Draft SSH File Transfer Protocol October 2001 - - - of the file as described in Section ``File Attributes''. - - The format of the `longname' field is unspecified by this protocol. - It MUST be suitable for use in the output of a directory listing - command (in fact, the recommended operation for a directory listing - command is to simply display this data). However, clients SHOULD NOT - attempt to parse the longname field for file attributes; they SHOULD - use the attrs field instead. - - The recommended format for the longname field is as follows: - - -rwxr-xr-x 1 mjos staff 348911 Mar 25 14:29 t-filexfer - 1234567890 123 12345678 12345678 12345678 123456789012 - - Here, the first line is sample output, and the second field indicates - widths of the various fields. Fields are separated by spaces. The - first field lists file permissions for user, group, and others; the - second field is link count; the third field is the name of the user - who owns the file; the fourth field is the name of the group that - owns the file; the fifth field is the size of the file in bytes; the - sixth field (which actually may contain spaces, but is fixed to 12 - characters) is the file modification time, and the seventh field is - the file name. Each field is specified to be a minimum of certain - number of character positions (indicated by the second line above), - but may also be longer if the data does not fit in the specified - length. - - The SSH_FXP_ATTRS response has the following format: - - uint32 id - ATTRS attrs - - where `id' is the request identifier, and `attrs' is the returned - file attributes as described in Section ``File Attributes''. - - - - - - - - - - - - - - - - - -Ylonen & Lehtinen Expires April 1, 2002 [Page 23] - -Internet-Draft SSH File Transfer Protocol October 2001 - - -8. Vendor-Specific Extensions - - The SSH_FXP_EXTENDED request provides a generic extension mechanism - for adding vendor-specific commands. The request has the following - format: - - uint32 id - string extended-request - ... any request-specific data ... - - where `id' is the request identifier, and `extended-request' is a - string of the format "name@domain", where domain is an internet - domain name of the vendor defining the request. The rest of the - request is completely vendor-specific, and servers should only - attempt to interpret it if they recognize the `extended-request' - name. - - The server may respond to such requests using any of the response - packets defined in Section ``Responses from the Server to the - Client''. Additionally, the server may also respond with a - SSH_FXP_EXTENDED_REPLY packet, as defined below. If the server does - not recognize the `extended-request' name, then the server MUST - respond with SSH_FXP_STATUS with error/status set to - SSH_FX_OP_UNSUPPORTED. - - The SSH_FXP_EXTENDED_REPLY packet can be used to carry arbitrary - extension-specific data from the server to the client. It is of the - following format: - - uint32 id - ... any request-specific data ... - - - - - - - - - - - - - - - - - - - - -Ylonen & Lehtinen Expires April 1, 2002 [Page 24] - -Internet-Draft SSH File Transfer Protocol October 2001 - - -9. Security Considerations - - This protocol assumes that it is run over a secure channel and that - the endpoints of the channel have been authenticated. Thus, this - protocol assumes that it is externally protected from network-level - attacks. - - This protocol provides file system access to arbitrary files on the - server (only constrained by the server implementation). It is the - responsibility of the server implementation to enforce any access - controls that may be required to limit the access allowed for any - particular user (the user being authenticated externally to this - protocol, typically using the SSH User Authentication Protocol [6]. - - Care must be taken in the server implementation to check the validity - of received file handle strings. The server should not rely on them - directly; it MUST check the validity of each handle before relying on - it. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Ylonen & Lehtinen Expires April 1, 2002 [Page 25] - -Internet-Draft SSH File Transfer Protocol October 2001 - - -10. Changes from previous protocol versions - - The SSH File Transfer Protocol has changed over time, before it's - standardization. The following is a description of the incompatible - changes between different versions. - -10.1 Changes between versions 3 and 2 - - o The SSH_FXP_READLINK and SSH_FXP_SYMLINK messages were added. - - o The SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY messages were - added. - - o The SSH_FXP_STATUS message was changed to include fields `error - message' and `language tag'. - - -10.2 Changes between versions 2 and 1 - - o The SSH_FXP_RENAME message was added. - - -10.3 Changes between versions 1 and 0 - - o Implementation changes, no actual protocol changes. - - - - - - - - - - - - - - - - - - - - - - - - - - -Ylonen & Lehtinen Expires April 1, 2002 [Page 26] - -Internet-Draft SSH File Transfer Protocol October 2001 - - -11. Trademark Issues - - "ssh" is a registered trademark of SSH Communications Security Corp - in the United States and/or other countries. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Ylonen & Lehtinen Expires April 1, 2002 [Page 27] - -Internet-Draft SSH File Transfer Protocol October 2001 - - -References - - [1] Dierks, T., Allen, C., Treese, W., Karlton, P., Freier, A. and - P. Kocher, "The TLS Protocol Version 1.0", RFC 2246, January - 1999. - - [2] Institute of Electrical and Electronics Engineers, "Information - Technology - Portable Operating System Interface (POSIX) - Part - 1: System Application Program Interface (API) [C Language]", - IEEE Standard 1003.2, 1996. - - [3] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. - Lehtinen, "SSH Protocol Architecture", draft-ietf-secsh- - architecture-09 (work in progress), July 2001. - - [4] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. - Lehtinen, "SSH Protocol Transport Protocol", draft-ietf-secsh- - architecture-09 (work in progress), July 2001. - - [5] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. - Lehtinen, "SSH Connection Protocol", draft-ietf-secsh-connect-11 - (work in progress), July 2001. - - [6] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. - Lehtinen, "SSH Authentication Protocol", draft-ietf-secsh- - userauth-11 (work in progress), July 2001. - - -Authors' Addresses - - Tatu Ylonen - SSH Communications Security Corp - Fredrikinkatu 42 - HELSINKI FIN-00100 - Finland - - EMail: [email protected] - - - Sami Lehtinen - SSH Communications Security Corp - Fredrikinkatu 42 - HELSINKI FIN-00100 - Finland - - EMail: [email protected] - - - - - -Ylonen & Lehtinen Expires April 1, 2002 [Page 28] - -Internet-Draft SSH File Transfer Protocol October 2001 - - -Full Copyright Statement - - Copyright (C) The Internet Society (2001). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - -Ylonen & Lehtinen Expires April 1, 2002 [Page 29] - - - diff --git a/lib/ssh/doc/standard/draft-ietf-secsh-filexfer-03.2.ps b/lib/ssh/doc/standard/draft-ietf-secsh-filexfer-03.2.ps deleted file mode 100644 index 6a40cd6067..0000000000 --- a/lib/ssh/doc/standard/draft-ietf-secsh-filexfer-03.2.ps +++ /dev/null @@ -1,3511 +0,0 @@ -%!PS-Adobe-3.0 -%%BoundingBox: 75 0 595 747 -%%Title: Enscript Output -%%For: Magnus Thoang -%%Creator: GNU enscript 1.6.1 -%%CreationDate: Wed Nov 12 12:18:50 2003 -%%Orientation: Portrait -%%Pages: 18 0 -%%DocumentMedia: A4 595 842 0 () () -%%DocumentNeededResources: (atend) -%%EndComments -%%BeginProlog -%%BeginProcSet: PStoPS 1 15 -userdict begin -[/showpage/erasepage/copypage]{dup where{pop dup load - type/operatortype eq{1 array cvx dup 0 3 index cvx put - bind def}{pop}ifelse}{pop}ifelse}forall -[/letter/legal/executivepage/a4/a4small/b5/com10envelope - /monarchenvelope/c5envelope/dlenvelope/lettersmall/note - /folio/quarto/a5]{dup where{dup wcheck{exch{}put} - {pop{}def}ifelse}{pop}ifelse}forall -/setpagedevice {pop}bind 1 index where{dup wcheck{3 1 roll put} - {pop def}ifelse}{def}ifelse -/PStoPSmatrix matrix currentmatrix def -/PStoPSxform matrix def/PStoPSclip{clippath}def -/defaultmatrix{PStoPSmatrix exch PStoPSxform exch concatmatrix}bind def -/initmatrix{matrix defaultmatrix setmatrix}bind def -/initclip[{matrix currentmatrix PStoPSmatrix setmatrix - [{currentpoint}stopped{$error/newerror false put{newpath}} - {/newpath cvx 3 1 roll/moveto cvx 4 array astore cvx}ifelse] - {[/newpath cvx{/moveto cvx}{/lineto cvx} - {/curveto cvx}{/closepath cvx}pathforall]cvx exch pop} - stopped{$error/errorname get/invalidaccess eq{cleartomark - $error/newerror false put cvx exec}{stop}ifelse}if}bind aload pop - /initclip dup load dup type dup/operatortype eq{pop exch pop} - {dup/arraytype eq exch/packedarraytype eq or - {dup xcheck{exch pop aload pop}{pop cvx}ifelse} - {pop cvx}ifelse}ifelse - {newpath PStoPSclip clip newpath exec setmatrix} bind aload pop]cvx def -/initgraphics{initmatrix newpath initclip 1 setlinewidth - 0 setlinecap 0 setlinejoin []0 setdash 0 setgray - 10 setmiterlimit}bind def -end -%%EndProcSet -%%BeginResource: procset Enscript-Prolog 1.6 1 -% -% Procedures. -% - -/_S { % save current state - /_s save def -} def -/_R { % restore from saved state - _s restore -} def - -/S { % showpage protecting gstate - gsave - showpage - grestore -} bind def - -/MF { % fontname newfontname -> - make a new encoded font - /newfontname exch def - /fontname exch def - - /fontdict fontname findfont def - /newfont fontdict maxlength dict def - - fontdict { - exch - dup /FID eq { - % skip FID pair - pop pop - } { - % copy to the new font dictionary - exch newfont 3 1 roll put - } ifelse - } forall - - newfont /FontName newfontname put - - % insert only valid encoding vectors - encoding_vector length 256 eq { - newfont /Encoding encoding_vector put - } if - - newfontname newfont definefont pop -} def - -/SF { % fontname width height -> - set a new font - /height exch def - /width exch def - - findfont - [width 0 0 height 0 0] makefont setfont -} def - -/SUF { % fontname width height -> - set a new user font - /height exch def - /width exch def - - /F-gs-user-font MF - /F-gs-user-font width height SF -} def - -/M {moveto} bind def -/s {show} bind def - -/Box { % x y w h -> - define box path - /d_h exch def /d_w exch def /d_y exch def /d_x exch def - d_x d_y moveto - d_w 0 rlineto - 0 d_h rlineto - d_w neg 0 rlineto - closepath -} def - -/bgs { % x y height blskip gray str -> - show string with bg color - /str exch def - /gray exch def - /blskip exch def - /height exch def - /y exch def - /x exch def - - gsave - x y blskip sub str stringwidth pop height Box - gray setgray - fill - grestore - x y M str s -} def - -% Highlight bars. -/highlight_bars { % nlines lineheight output_y_margin gray -> - - gsave - setgray - /ymarg exch def - /lineheight exch def - /nlines exch def - - % This 2 is just a magic number to sync highlight lines to text. - 0 d_header_y ymarg sub 2 sub translate - - /cw d_output_w cols div def - /nrows d_output_h ymarg 2 mul sub lineheight div cvi def - - % for each column - 0 1 cols 1 sub { - cw mul /xp exch def - - % for each rows - 0 1 nrows 1 sub { - /rn exch def - rn lineheight mul neg /yp exch def - rn nlines idiv 2 mod 0 eq { - % Draw highlight bar. 4 is just a magic indentation. - xp 4 add yp cw 8 sub lineheight neg Box fill - } if - } for - } for - - grestore -} def - -% Line highlight bar. -/line_highlight { % x y width height gray -> - - gsave - /gray exch def - Box gray setgray fill - grestore -} def - -% Column separator lines. -/column_lines { - gsave - .1 setlinewidth - 0 d_footer_h translate - /cw d_output_w cols div def - 1 1 cols 1 sub { - cw mul 0 moveto - 0 d_output_h rlineto stroke - } for - grestore -} def - -% Column borders. -/column_borders { - gsave - .1 setlinewidth - 0 d_footer_h moveto - 0 d_output_h rlineto - d_output_w 0 rlineto - 0 d_output_h neg rlineto - closepath stroke - grestore -} def - -% Do the actual underlay drawing -/draw_underlay { - ul_style 0 eq { - ul_str true charpath stroke - } { - ul_str show - } ifelse -} def - -% Underlay -/underlay { % - -> - - gsave - 0 d_page_h translate - d_page_h neg d_page_w atan rotate - - ul_gray setgray - ul_font setfont - /dw d_page_h dup mul d_page_w dup mul add sqrt def - ul_str stringwidth pop dw exch sub 2 div ul_h_ptsize -2 div moveto - draw_underlay - grestore -} def - -/user_underlay { % - -> - - gsave - ul_x ul_y translate - ul_angle rotate - ul_gray setgray - ul_font setfont - 0 0 ul_h_ptsize 2 div sub moveto - draw_underlay - grestore -} def - -% Page prefeed -/page_prefeed { % bool -> - - statusdict /prefeed known { - statusdict exch /prefeed exch put - } { - pop - } ifelse -} def - -% Wrapped line markers -/wrapped_line_mark { % x y charwith charheight type -> - - /type exch def - /h exch def - /w exch def - /y exch def - /x exch def - - type 2 eq { - % Black boxes (like TeX does) - gsave - 0 setlinewidth - x w 4 div add y M - 0 h rlineto w 2 div 0 rlineto 0 h neg rlineto - closepath fill - grestore - } { - type 3 eq { - % Small arrows - gsave - .2 setlinewidth - x w 2 div add y h 2 div add M - w 4 div 0 rlineto - x w 4 div add y lineto stroke - - x w 4 div add w 8 div add y h 4 div add M - x w 4 div add y lineto - w 4 div h 8 div rlineto stroke - grestore - } { - % do nothing - } ifelse - } ifelse -} def - -% EPSF import. - -/BeginEPSF { - /b4_Inc_state save def % Save state for cleanup - /dict_count countdictstack def % Count objects on dict stack - /op_count count 1 sub def % Count objects on operand stack - userdict begin - /showpage { } def - 0 setgray 0 setlinecap - 1 setlinewidth 0 setlinejoin - 10 setmiterlimit [ ] 0 setdash newpath - /languagelevel where { - pop languagelevel - 1 ne { - false setstrokeadjust false setoverprint - } if - } if -} bind def - -/EndEPSF { - count op_count sub { pos } repeat % Clean up stacks - countdictstack dict_count sub { end } repeat - b4_Inc_state restore -} bind def - -% Check PostScript language level. -/languagelevel where { - pop /gs_languagelevel languagelevel def -} { - /gs_languagelevel 1 def -} ifelse -%%EndResource -%%BeginResource: procset Enscript-Encoding-88591 1.6 1 -/encoding_vector [ -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/space /exclam /quotedbl /numbersign -/dollar /percent /ampersand /quoteright -/parenleft /parenright /asterisk /plus -/comma /hyphen /period /slash -/zero /one /two /three -/four /five /six /seven -/eight /nine /colon /semicolon -/less /equal /greater /question -/at /A /B /C -/D /E /F /G -/H /I /J /K -/L /M /N /O -/P /Q /R /S -/T /U /V /W -/X /Y /Z /bracketleft -/backslash /bracketright /asciicircum /underscore -/quoteleft /a /b /c -/d /e /f /g -/h /i /j /k -/l /m /n /o -/p /q /r /s -/t /u /v /w -/x /y /z /braceleft -/bar /braceright /tilde /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/space /exclamdown /cent /sterling -/currency /yen /brokenbar /section -/dieresis /copyright /ordfeminine /guillemotleft -/logicalnot /hyphen /registered /macron -/degree /plusminus /twosuperior /threesuperior -/acute /mu /paragraph /bullet -/cedilla /onesuperior /ordmasculine /guillemotright -/onequarter /onehalf /threequarters /questiondown -/Agrave /Aacute /Acircumflex /Atilde -/Adieresis /Aring /AE /Ccedilla -/Egrave /Eacute /Ecircumflex /Edieresis -/Igrave /Iacute /Icircumflex /Idieresis -/Eth /Ntilde /Ograve /Oacute -/Ocircumflex /Otilde /Odieresis /multiply -/Oslash /Ugrave /Uacute /Ucircumflex -/Udieresis /Yacute /Thorn /germandbls -/agrave /aacute /acircumflex /atilde -/adieresis /aring /ae /ccedilla -/egrave /eacute /ecircumflex /edieresis -/igrave /iacute /icircumflex /idieresis -/eth /ntilde /ograve /oacute -/ocircumflex /otilde /odieresis /divide -/oslash /ugrave /uacute /ucircumflex -/udieresis /yacute /thorn /ydieresis -] def -%%EndResource -%%EndProlog -%%BeginSetup -%%IncludeResource: font Courier-Bold -%%IncludeResource: font Courier -/HFpt_w 10 def -/HFpt_h 10 def -/Courier-Bold /HF-gs-font MF -/HF /HF-gs-font findfont [HFpt_w 0 0 HFpt_h 0 0] makefont def -/Courier /F-gs-font MF -/F-gs-font 10 10 SF -/#copies 1 def -/d_page_w 520 def -/d_page_h 747 def -/d_header_x 0 def -/d_header_y 747 def -/d_header_w 520 def -/d_header_h 0 def -/d_footer_x 0 def -/d_footer_y 0 def -/d_footer_w 520 def -/d_footer_h 0 def -/d_output_w 520 def -/d_output_h 747 def -/cols 1 def -userdict/PStoPSxform PStoPSmatrix matrix currentmatrix - matrix invertmatrix matrix concatmatrix - matrix invertmatrix put -%%EndSetup -%%Page: (0,1) 1 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 1 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 701 M -(Secure Shell Working Group J. Galbraith) s -5 690 M -(Internet-Draft VanDyke Software) s -5 679 M -(Expires: April 16, 2003 T. Ylonen) s -5 668 M -( S. Lehtinen) s -5 657 M -( SSH Communications Security Corp) s -5 646 M -( October 16, 2002) s -5 613 M -( SSH File Transfer Protocol) s -5 602 M -( draft-ietf-secsh-filexfer-03.txt) s -5 580 M -(Status of this Memo) s -5 558 M -( This document is an Internet-Draft and is in full conformance with) s -5 547 M -( all provisions of Section 10 of RFC2026.) s -5 525 M -( Internet-Drafts are working documents of the Internet Engineering) s -5 514 M -( Task Force \(IETF\), its areas, and its working groups. Note that) s -5 503 M -( other groups may also distribute working documents as Internet-) s -5 492 M -( Drafts.) s -5 470 M -( Internet-Drafts are draft documents valid for a maximum of six months) s -5 459 M -( and may be updated, replaced, or obsoleted by other documents at any) s -5 448 M -( time. It is inappropriate to use Internet-Drafts as reference) s -5 437 M -( material or to cite them other than as "work in progress.") s -5 415 M -( The list of current Internet-Drafts can be accessed at http://) s -5 404 M -( www.ietf.org/ietf/1id-abstracts.txt.) s -5 382 M -( The list of Internet-Draft Shadow Directories can be accessed at) s -5 371 M -( http://www.ietf.org/shadow.html.) s -5 349 M -( This Internet-Draft will expire on April 16, 2003.) s -5 327 M -(Copyright Notice) s -5 305 M -( Copyright \(C\) The Internet Society \(2002\). All Rights Reserved.) s -5 283 M -(Abstract) s -5 261 M -( The SSH File Transfer Protocol provides secure file transfer) s -5 250 M -( functionality over any reliable data stream. It is the standard file) s -5 239 M -( transfer protocol for use with the SSH2 protocol. This document) s -5 228 M -( describes the file transfer protocol and its interface to the SSH2) s -5 217 M -( protocol suite.) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 1]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 2 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -(Table of Contents) s -5 668 M -( 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . 3) s -5 657 M -( 2. Use with the SSH Connection Protocol . . . . . . . . . . . 4) s -5 646 M -( 3. General Packet Format . . . . . . . . . . . . . . . . . . 5) s -5 635 M -( 4. Protocol Initialization . . . . . . . . . . . . . . . . . 7) s -5 624 M -( 4.1 Client Initialization . . . . . . . . . . . . . . . . . . 7) s -5 613 M -( 4.2 Server Initialization . . . . . . . . . . . . . . . . . . 7) s -5 602 M -( 4.3 Determining Server Newline Convention . . . . . . . . . . 8) s -5 591 M -( 5. File Attributes . . . . . . . . . . . . . . . . . . . . . 9) s -5 580 M -( 5.1 Flags . . . . . . . . . . . . . . . . . . . . . . . . . . 9) s -5 569 M -( 5.2 Type . . . . . . . . . . . . . . . . . . . . . . . . . . . 10) s -5 558 M -( 5.3 Size . . . . . . . . . . . . . . . . . . . . . . . . . . . 10) s -5 547 M -( 5.4 Owner and Group . . . . . . . . . . . . . . . . . . . . . 10) s -5 536 M -( 5.5 Permissions . . . . . . . . . . . . . . . . . . . . . . . 11) s -5 525 M -( 5.6 Times . . . . . . . . . . . . . . . . . . . . . . . . . . 11) s -5 514 M -( 5.7 ACL . . . . . . . . . . . . . . . . . . . . . . . . . . . 11) s -5 503 M -( 5.8 Extended attributes . . . . . . . . . . . . . . . . . . . 12) s -5 492 M -( 6. Requests From the Client to the Server . . . . . . . . . . 13) s -5 481 M -( 6.1 Request Synchronization and Reordering . . . . . . . . . . 13) s -5 470 M -( 6.2 File Names . . . . . . . . . . . . . . . . . . . . . . . . 14) s -5 459 M -( 6.3 Opening, Creating, and Closing Files . . . . . . . . . . . 14) s -5 448 M -( 6.4 Reading and Writing . . . . . . . . . . . . . . . . . . . 17) s -5 437 M -( 6.5 Removing and Renaming Files . . . . . . . . . . . . . . . 18) s -5 426 M -( 6.6 Creating and Deleting Directories . . . . . . . . . . . . 19) s -5 415 M -( 6.7 Scanning Directories . . . . . . . . . . . . . . . . . . . 19) s -5 404 M -( 6.8 Retrieving File Attributes . . . . . . . . . . . . . . . . 20) s -5 393 M -( 6.9 Setting File Attributes . . . . . . . . . . . . . . . . . 21) s -5 382 M -( 6.10 Dealing with Symbolic links . . . . . . . . . . . . . . . 22) s -5 371 M -( 6.11 Canonicalizing the Server-Side Path Name . . . . . . . . . 23) s -5 360 M -( 6.11.1 Best practice for dealing with paths . . . . . . . . . . . 23) s -5 349 M -( 7. Responses from the Server to the Client . . . . . . . . . 24) s -5 338 M -( 8. Vendor-Specific Extensions . . . . . . . . . . . . . . . . 28) s -5 327 M -( 9. Security Considerations . . . . . . . . . . . . . . . . . 29) s -5 316 M -( 10. Changes from previous protocol versions . . . . . . . . . 30) s -5 305 M -( 10.1 Changes between versions 4 and 3 . . . . . . . . . . . . . 30) s -5 294 M -( 10.2 Changes between versions 3 and 2 . . . . . . . . . . . . . 31) s -5 283 M -( 10.3 Changes between versions 2 and 1 . . . . . . . . . . . . . 31) s -5 272 M -( 10.4 Changes between versions 1 and 0 . . . . . . . . . . . . . 31) s -5 261 M -( 11. Trademark Issues . . . . . . . . . . . . . . . . . . . . . 32) s -5 250 M -( References . . . . . . . . . . . . . . . . . . . . . . . . 33) s -5 239 M -( Authors' Addresses . . . . . . . . . . . . . . . . . . . . 33) s -5 228 M -( Full Copyright Statement . . . . . . . . . . . . . . . . . 35) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 2]) s -_R -S -PStoPSsaved restore -%%Page: (2,3) 2 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 3 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -(1. Introduction) s -5 668 M -( This protocol provides secure file transfer \(and more generally file) s -5 657 M -( system access\) functionality over a reliable data stream, such as a) s -5 646 M -( channel in the SSH2 protocol [5].) s -5 624 M -( This protocol is designed so that it could be used to implement a) s -5 613 M -( secure remote file system service, as well as a secure file transfer) s -5 602 M -( service.) s -5 580 M -( This protocol assumes that it runs over a secure channel, and that) s -5 569 M -( the server has already authenticated the user at the client end, and) s -5 558 M -( that the identity of the client user is externally available to the) s -5 547 M -( server implementation.) s -5 525 M -( In general, this protocol follows a simple request-response model.) s -5 514 M -( Each request and response contains a sequence number and multiple) s -5 503 M -( requests may be pending simultaneously. There are a relatively large) s -5 492 M -( number of different request messages, but a small number of possible) s -5 481 M -( response messages. Each request has one or more response messages) s -5 470 M -( that may be returned in result \(e.g., a read either returns data or) s -5 459 M -( reports error status\).) s -5 437 M -( The packet format descriptions in this specification follow the) s -5 426 M -( notation presented in the secsh architecture draft. [5]) s -5 404 M -( Even though this protocol is described in the context of the SSH2) s -5 393 M -( protocol, this protocol is general and independent of the rest of the) s -5 382 M -( SSH2 protocol suite. It could be used in a number of different) s -5 371 M -( applications, such as secure file transfer over TLS RFC 2246 [1] and) s -5 360 M -( transfer of management information in VPN applications.) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 3]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 4 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -(2. Use with the SSH Connection Protocol) s -5 668 M -( When used with the SSH2 Protocol suite, this protocol is intended to) s -5 657 M -( be used from the SSH Connection Protocol [7] as a subsystem, as) s -5 646 M -( described in section ``Starting a Shell or a Command''. The) s -5 635 M -( subsystem name used with this protocol is "sftp".) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 4]) s -_R -S -PStoPSsaved restore -%%Page: (4,5) 3 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 5 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -(3. General Packet Format) s -5 668 M -( All packets transmitted over the secure connection are of the) s -5 657 M -( following format:) s -5 635 M -( uint32 length) s -5 624 M -( byte type) s -5 613 M -( byte[length - 1] data payload) s -5 591 M -( That is, they are just data preceded by 32-bit length and 8-bit type) s -5 580 M -( fields. The `length' is the length of the data area, and does not) s -5 569 M -( include the `length' field itself. The format and interpretation of) s -5 558 M -( the data area depends on the packet type.) s -5 536 M -( All packet descriptions below only specify the packet type and the) s -5 525 M -( data that goes into the data field. Thus, they should be prefixed by) s -5 514 M -( the `length' and `type' fields.) s -5 492 M -( The maximum size of a packet is in practice determined by the client) s -5 481 M -( \(the maximum size of read or write requests that it sends, plus a few) s -5 470 M -( bytes of packet overhead\). All servers SHOULD support packets of at) s -5 459 M -( least 34000 bytes \(where the packet size refers to the full length,) s -5 448 M -( including the header above\). This should allow for reads and writes) s -5 437 M -( of at most 32768 bytes.) s -5 415 M -( There is no limit on the number of outstanding \(non-acknowledged\)) s -5 404 M -( requests that the client may send to the server. In practice this is) s -5 393 M -( limited by the buffering available on the data stream and the queuing) s -5 382 M -( performed by the server. If the server's queues are full, it should) s -5 371 M -( not read any more data from the stream, and flow control will prevent) s -5 360 M -( the client from sending more requests. Note, however, that while) s -5 349 M -( there is no restriction on the protocol level, the client's API may) s -5 338 M -( provide a limit in order to prevent infinite queuing of outgoing) s -5 327 M -( requests at the client.) s -5 305 M -( The following values are defined for packet types.) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 5]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 6 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -( #define SSH_FXP_INIT 1) s -5 679 M -( #define SSH_FXP_VERSION 2) s -5 668 M -( #define SSH_FXP_OPEN 3) s -5 657 M -( #define SSH_FXP_CLOSE 4) s -5 646 M -( #define SSH_FXP_READ 5) s -5 635 M -( #define SSH_FXP_WRITE 6) s -5 624 M -( #define SSH_FXP_LSTAT 7) s -5 613 M -( #define SSH_FXP_FSTAT 8) s -5 602 M -( #define SSH_FXP_SETSTAT 9) s -5 591 M -( #define SSH_FXP_FSETSTAT 10) s -5 580 M -( #define SSH_FXP_OPENDIR 11) s -5 569 M -( #define SSH_FXP_READDIR 12) s -5 558 M -( #define SSH_FXP_REMOVE 13) s -5 547 M -( #define SSH_FXP_MKDIR 14) s -5 536 M -( #define SSH_FXP_RMDIR 15) s -5 525 M -( #define SSH_FXP_REALPATH 16) s -5 514 M -( #define SSH_FXP_STAT 17) s -5 503 M -( #define SSH_FXP_RENAME 18) s -5 492 M -( #define SSH_FXP_READLINK 19) s -5 481 M -( #define SSH_FXP_SYMLINK 20) s -5 459 M -( #define SSH_FXP_STATUS 101) s -5 448 M -( #define SSH_FXP_HANDLE 102) s -5 437 M -( #define SSH_FXP_DATA 103) s -5 426 M -( #define SSH_FXP_NAME 104) s -5 415 M -( #define SSH_FXP_ATTRS 105) s -5 393 M -( #define SSH_FXP_EXTENDED 200) s -5 382 M -( #define SSH_FXP_EXTENDED_REPLY 201) s -5 360 M -( RESERVED_FOR_EXTENSIONS 210-255) s -5 338 M -( Additional packet types should only be defined if the protocol) s -5 327 M -( version number \(see Section ``Protocol Initialization''\) is) s -5 316 M -( incremented, and their use MUST be negotiated using the version) s -5 305 M -( number. However, the SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY) s -5 294 M -( packets can be used to implement vendor-specific extensions. See) s -5 283 M -( Section ``Vendor-Specific-Extensions'' for more details.) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 6]) s -_R -S -PStoPSsaved restore -%%Page: (6,7) 4 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 7 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -(4. Protocol Initialization) s -5 668 M -( When the file transfer protocol starts, the client first sends a) s -5 657 M -( SSH_FXP_INIT \(including its version number\) packet to the server.) s -5 646 M -( The server responds with a SSH_FXP_VERSION packet, supplying the) s -5 635 M -( lowest of its own and the client's version number. Both parties) s -5 624 M -( should from then on adhere to particular version of the protocol.) s -5 602 M -( The version number of the protocol specified in this document is 4.) s -5 591 M -( The version number should be incremented for each incompatible) s -5 580 M -( revision of this protocol.) s -5 558 M -(4.1 Client Initialization) s -5 536 M -( The SSH_FXP_INIT packet \(from client to server\) has the following) s -5 525 M -( data:) s -5 503 M -( uint32 version) s -5 481 M -( Version 3 of this protocol allowed clients to include extensions in) s -5 470 M -( the SSH_FXP_INIT packet; however, this can cause interoperability) s -5 459 M -( problems with version 1 and version 2 servers because the client must) s -5 448 M -( send this packet before knowing the servers version.) s -5 426 M -( In this version of the protocol, clients MUST use the) s -5 415 M -( SSH_FXP_EXTENDED packet to send extensions to the server after) s -5 404 M -( version exchange has completed. Clients MUST NOT include extensions) s -5 393 M -( in the version packet. This will prevent interoperability problems) s -5 382 M -( with older servers) s -5 360 M -(4.2 Server Initialization) s -5 338 M -( The SSH_FXP_VERSION packet \(from server to client\) has the following) s -5 327 M -( data:) s -5 305 M -( uint32 version) s -5 294 M -( <extension data>) s -5 272 M -( 'version' is the lower of the protocol version supported by the) s -5 261 M -( server and the version number received from the client.) s -5 239 M -( The extension data may be empty, or may be a sequence of) s -5 217 M -( string extension_name) s -5 206 M -( string extension_data) s -5 184 M -( pairs \(both strings MUST always be present if one is, but the) s -5 173 M -( `extension_data' string may be of zero length\). If present, these) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 7]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 8 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -( strings indicate extensions to the baseline protocol. The) s -5 679 M -( `extension_name' field\(s\) identify the name of the extension. The) s -5 668 M -( name should be of the form "name@domain", where the domain is the DNS) s -5 657 M -( domain name of the organization defining the extension. Additional) s -5 646 M -( names that are not of this format may be defined later by the IETF.) s -5 635 M -( Implementations MUST silently ignore any extensions whose name they) s -5 624 M -( do not recognize.) s -5 602 M -(4.3 Determining Server Newline Convention) s -5 580 M -( In order to correctly process text files in a cross platform) s -5 569 M -( compatible way, the newline convention must be converted from that of) s -5 558 M -( the server to that of the client, or, during an upload, from that of) s -5 547 M -( the client to that of the server.) s -5 525 M -( Versions 3 and prior of this protocol made no provisions for) s -5 514 M -( processing text files. Many clients implemented some sort of) s -5 503 M -( conversion algorithm, but without either a 'canonical' on the wire) s -5 492 M -( format or knowledge of the servers newline convention, correct) s -5 481 M -( conversion was not always possible.) s -5 459 M -( Starting with Version 4, the SSH_FXF_TEXT file open flag \(Section) s -5 448 M -( 6.3\) makes it possible to request that the server translate a file to) s -5 437 M -( a 'canonical' on the wire format. This format uses \\r\\n as the line) s -5 426 M -( separator.) s -5 404 M -( Servers for systems using multiple newline characters \(for example,) s -5 393 M -( Mac OS X or VMS\) or systems using counted records, MUST translate to) s -5 382 M -( the canonical form.) s -5 360 M -( However, to ease the burden of implementation on servers that use a) s -5 349 M -( single, simple separator sequence, the following extension allows the) s -5 338 M -( canonical format to be changed.) s -5 316 M -( string "newline") s -5 305 M -( string new-canonical-separator \(usually "\\r" or "\\n" or "\\r\\n"\)) s -5 283 M -( All clients MUST support this extension.) s -5 261 M -( When processing text files, clients SHOULD NOT translate any) s -5 250 M -( character or sequence that is not an exact match of the servers) s -5 239 M -( newline separator.) s -5 217 M -( In particular, if the newline sequence being used is the canonical) s -5 206 M -( "\\r\\n" sequence, a lone \\r or a lone \\n SHOULD be written through) s -5 195 M -( without change.) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 8]) s -_R -S -PStoPSsaved restore -%%Page: (8,9) 5 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 9 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -(5. File Attributes) s -5 668 M -( A new compound data type is defined for encoding file attributes.) s -5 657 M -( The same encoding is used both when returning file attributes from) s -5 646 M -( the server and when sending file attributes to the server. When) s -5 635 M -( sending it to the server, the flags field specifies which attributes) s -5 624 M -( are included, and the server will use default values for the) s -5 613 M -( remaining attributes \(or will not modify the values of remaining) s -5 602 M -( attributes\). When receiving attributes from the server, the flags) s -5 591 M -( specify which attributes are included in the returned data. The) s -5 580 M -( server normally returns all attributes it knows about.) s -5 558 M -( uint32 flags) s -5 547 M -( byte type always present) s -5 536 M -( uint64 size present only if flag SSH_FILEXFER_ATTR_SIZE) s -5 525 M -( string owner present only if flag SSH_FILEXFER_ATTR_OWNERGROUP) s -5 514 M -( string group present only if flag SSH_FILEXFER_ATTR_OWNERGROUP) s -5 503 M -( uint32 permissions present only if flag SSH_FILEXFER_ATTR_PERMISSIONS) s -5 492 M -( uint32 atime present only if flag SSH_FILEXFER_ATTR_ACCESSTIME) s -5 481 M -( uint32 createtime present only if flag SSH_FILEXFER_ATTR_CREATETIME) s -5 470 M -( uint32 mtime present only if flag SSH_FILEXFER_ATTR_MODIFYTIME) s -5 459 M -( string acl present only if flag SSH_FILEXFER_ATTR_ACL) s -5 448 M -( uint32 extended_count present only if flag SSH_FILEXFER_ATTR_EXTENDED) s -5 437 M -( string extended_type) s -5 426 M -( string extended_data) s -5 415 M -( ... more extended data \(extended_type - extended_data pairs\),) s -5 404 M -( so that number of pairs equals extended_count) s -5 371 M -(5.1 Flags) s -5 349 M -( The `flags' specify which of the fields are present. Those fields) s -5 338 M -( for which the corresponding flag is not set are not present \(not) s -5 327 M -( included in the packet\). New flags can only be added by incrementing) s -5 316 M -( the protocol version number \(or by using the extension mechanism) s -5 305 M -( described below\).) s -5 283 M -( The flags bits are defined to have the following values:) s -5 261 M -( #define SSH_FILEXFER_ATTR_SIZE 0x00000001) s -5 250 M -( #define SSH_FILEXFER_ATTR_PERMISSIONS 0x00000004) s -5 239 M -( #define SSH_FILEXFER_ATTR_ACCESSTIME 0x00000008) s -5 228 M -( #define SSH_FILEXFER_ATTR_CREATETIME 0x00000010) s -5 217 M -( #define SSH_FILEXFER_ATTR_MODIFYTIME 0x00000020) s -5 206 M -( #define SSH_FILEXFER_ATTR_ACL 0x00000040) s -5 195 M -( #define SSH_FILEXFER_ATTR_OWNERGROUP 0x00000080) s -5 184 M -( #define SSH_FILEXFER_ATTR_EXTENDED 0x80000000) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 9]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 10 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -( In previous versions of this protocol flags value 0x00000002 was) s -5 679 M -( SSH_FILEXFER_ATTR_UIDGID. This value is now unused, and OWNERGROUP) s -5 668 M -( was given a new value in order to ease implementation burden.) s -5 657 M -( 0x00000002 MUST NOT appear in the mask. Some future version of this) s -5 646 M -( protocol may reuse flag 0x00000002.) s -5 624 M -(5.2 Type) s -5 602 M -( The type field is always present. The following types are defined:) s -5 580 M -( #define SSH_FILEXFER_TYPE_REGULAR 1) s -5 569 M -( #define SSH_FILEXFER_TYPE_DIRECTORY 2) s -5 558 M -( #define SSH_FILEXFER_TYPE_SYMLINK 3) s -5 547 M -( #define SSH_FILEXFER_TYPE_SPECIAL 4) s -5 536 M -( #define SSH_FILEXFER_TYPE_UNKNOWN 5) s -5 514 M -( On a POSIX system, these values would be derived from the permission) s -5 503 M -( field.) s -5 481 M -(5.3 Size) s -5 459 M -( The `size' field specifies the size of the file on disk, in bytes.) s -5 448 M -( If it is present during file creation, it should be considered a hint) s -5 437 M -( as to the files eventual size.) s -5 415 M -( Files opened with the SSH_FXF_TEXT flag may have a size that is) s -5 404 M -( greater or less than the value of the size field.) s -5 382 M -(5.4 Owner and Group) s -5 360 M -( The `owner' and `group' fields are represented as UTF-8 strings; this) s -5 349 M -( is the form used by NFS v4. See NFS version 4 Protocol. [3] The) s -5 338 M -( following text is selected quotations from section 5.6.) s -5 316 M -( To avoid a representation that is tied to a particular underlying) s -5 305 M -( implementation at the client or server, the use of UTF-8 strings has) s -5 294 M -( been chosen. The string should be of the form user@dns_domain".) s -5 283 M -( This will allow for a client and server that do not use the same) s -5 272 M -( local representation the ability to translate to a common syntax that) s -5 261 M -( can be interpreted by both. In the case where there is no) s -5 250 M -( translation available to the client or server, the attribute value) s -5 239 M -( must be constructed without the "@". Therefore, the absence of the @) s -5 228 M -( from the owner or owner_group attribute signifies that no translation) s -5 217 M -( was available and the receiver of the attribute should not place any) s -5 206 M -( special meaning with the attribute value. Even though the attribute) s -5 195 M -( value can not be translated, it may still be useful. In the case of) s -5 184 M -( a client, the attribute string may be used for local display of) s -5 173 M -( ownership.) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 10]) s -_R -S -PStoPSsaved restore -%%Page: (10,11) 6 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 11 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -(5.5 Permissions) s -5 668 M -( The `permissions' field contains a bit mask of file permissions as) s -5 657 M -( defined by POSIX [1].) s -5 635 M -(5.6 Times) s -5 613 M -( The 'atime', 'createtime', and 'mtime' contain the access, creation,) s -5 602 M -( and modification times of the files, respectively. They are) s -5 591 M -( represented as seconds from Jan 1, 1970 in UTC.) s -5 569 M -(5.7 ACL) s -5 547 M -( The 'ACL' field contains an ACL similar to that defined in section) s -5 536 M -( 5.9 of NFS version 4 Protocol [3].) s -5 514 M -( uint32 ace-count) s -5 492 M -( repeated ace-count time:) s -5 481 M -( uint32 ace-type) s -5 470 M -( uint32 ace-flag) s -5 459 M -( uint32 ace-mask) s -5 448 M -( string who [UTF-8]) s -5 426 M -( ace-type is one of the following four values \(taken from NFS Version) s -5 415 M -( 4 Protocol [3]:) s -5 393 M -( const ACE4_ACCESS_ALLOWED_ACE_TYPE = 0x00000000;) s -5 382 M -( const ACE4_ACCESS_DENIED_ACE_TYPE = 0x00000001;) s -5 371 M -( const ACE4_SYSTEM_AUDIT_ACE_TYPE = 0x00000002;) s -5 360 M -( const ACE4_SYSTEM_ALARM_ACE_TYPE = 0x00000003;) s -5 338 M -( ace-flag is a combination of the following flag values. See NFS) s -5 327 M -( Version 4 Protocol [3] section 5.9.2:) s -5 305 M -( const ACE4_FILE_INHERIT_ACE = 0x00000001;) s -5 294 M -( const ACE4_DIRECTORY_INHERIT_ACE = 0x00000002;) s -5 283 M -( const ACE4_NO_PROPAGATE_INHERIT_ACE = 0x00000004;) s -5 272 M -( const ACE4_INHERIT_ONLY_ACE = 0x00000008;) s -5 261 M -( const ACE4_SUCCESSFUL_ACCESS_ACE_FLAG = 0x00000010;) s -5 250 M -( const ACE4_FAILED_ACCESS_ACE_FLAG = 0x00000020;) s -5 239 M -( const ACE4_IDENTIFIER_GROUP = 0x00000040;) s -5 217 M -( ace-mask is any combination of the following flags \(taken from NFS) s -5 206 M -( Version 4 Protocol [3] section 5.9.3:) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 11]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 12 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -( const ACE4_READ_DATA = 0x00000001;) s -5 679 M -( const ACE4_LIST_DIRECTORY = 0x00000001;) s -5 668 M -( const ACE4_WRITE_DATA = 0x00000002;) s -5 657 M -( const ACE4_ADD_FILE = 0x00000002;) s -5 646 M -( const ACE4_APPEND_DATA = 0x00000004;) s -5 635 M -( const ACE4_ADD_SUBDIRECTORY = 0x00000004;) s -5 624 M -( const ACE4_READ_NAMED_ATTRS = 0x00000008;) s -5 613 M -( const ACE4_WRITE_NAMED_ATTRS = 0x00000010;) s -5 602 M -( const ACE4_EXECUTE = 0x00000020;) s -5 591 M -( const ACE4_DELETE_CHILD = 0x00000040;) s -5 580 M -( const ACE4_READ_ATTRIBUTES = 0x00000080;) s -5 569 M -( const ACE4_WRITE_ATTRIBUTES = 0x00000100;) s -5 558 M -( const ACE4_DELETE = 0x00010000;) s -5 547 M -( const ACE4_READ_ACL = 0x00020000;) s -5 536 M -( const ACE4_WRITE_ACL = 0x00040000;) s -5 525 M -( const ACE4_WRITE_OWNER = 0x00080000;) s -5 514 M -( const ACE4_SYNCHRONIZE = 0x00100000;) s -5 492 M -( who is a UTF-8 string of the form described in 'Owner and Group') s -5 481 M -( \(Section 5.4\)) s -5 459 M -(5.8 Extended attributes) s -5 437 M -( The SSH_FILEXFER_ATTR_EXTENDED flag provides a general extension) s -5 426 M -( mechanism for vendor-specific extensions. If the flag is specified,) s -5 415 M -( then the `extended_count' field is present. It specifies the number) s -5 404 M -( of extended_type-extended_data pairs that follow. Each of these) s -5 393 M -( pairs specifies an extended attribute. For each of the attributes,) s -5 382 M -( the extended_type field should be a string of the format) s -5 371 M -( "name@domain", where "domain" is a valid, registered domain name and) s -5 360 M -( "name" identifies the method. The IETF may later standardize certain) s -5 349 M -( names that deviate from this format \(e.g., that do not contain the) s -5 338 M -( "@" sign\). The interpretation of `extended_data' depends on the) s -5 327 M -( type. Implementations SHOULD ignore extended data fields that they) s -5 316 M -( do not understand.) s -5 294 M -( Additional fields can be added to the attributes by either defining) s -5 283 M -( additional bits to the flags field to indicate their presence, or by) s -5 272 M -( defining extended attributes for them. The extended attributes) s -5 261 M -( mechanism is recommended for most purposes; additional flags bits) s -5 250 M -( should only be defined by an IETF standards action that also) s -5 239 M -( increments the protocol version number. The use of such new fields) s -5 228 M -( MUST be negotiated by the version number in the protocol exchange.) s -5 217 M -( It is a protocol error if a packet with unsupported protocol bits is) s -5 206 M -( received.) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 12]) s -_R -S -PStoPSsaved restore -%%Page: (12,13) 7 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 13 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -(6. Requests From the Client to the Server) s -5 668 M -( Requests from the client to the server represent the various file) s -5 657 M -( system operations. Each request begins with an `id' field, which is) s -5 646 M -( a 32-bit identifier identifying the request \(selected by the client\).) s -5 635 M -( The same identifier will be returned in the response to the request.) s -5 624 M -( One possible implementation is a monotonically increasing request) s -5 613 M -( sequence number \(modulo 2^32\).) s -5 591 M -( Many operations in the protocol operate on open files. The) s -5 580 M -( SSH_FXP_OPEN request can return a file handle \(which is an opaque) s -5 569 M -( variable-length string\) which may be used to access the file later) s -5 558 M -( \(e.g. in a read operation\). The client MUST NOT send requests the) s -5 547 M -( server with bogus or closed handles. However, the server MUST) s -5 536 M -( perform adequate checks on the handle in order to avoid security) s -5 525 M -( risks due to fabricated handles.) s -5 503 M -( This design allows either stateful and stateless server) s -5 492 M -( implementation, as well as an implementation which caches state) s -5 481 M -( between requests but may also flush it. The contents of the file) s -5 470 M -( handle string are entirely up to the server and its design. The) s -5 459 M -( client should not modify or attempt to interpret the file handle) s -5 448 M -( strings.) s -5 426 M -( The file handle strings MUST NOT be longer than 256 bytes.) s -5 404 M -(6.1 Request Synchronization and Reordering) s -5 382 M -( The protocol and implementations MUST process requests relating to) s -5 371 M -( the same file in the order in which they are received. In other) s -5 360 M -( words, if an application submits multiple requests to the server, the) s -5 349 M -( results in the responses will be the same as if it had sent the) s -5 338 M -( requests one at a time and waited for the response in each case. For) s -5 327 M -( example, the server may process non-overlapping read/write requests) s -5 316 M -( to the same file in parallel, but overlapping reads and writes cannot) s -5 305 M -( be reordered or parallelized. However, there are no ordering) s -5 294 M -( restrictions on the server for processing requests from two different) s -5 283 M -( file transfer connections. The server may interleave and parallelize) s -5 272 M -( them at will.) s -5 250 M -( There are no restrictions on the order in which responses to) s -5 239 M -( outstanding requests are delivered to the client, except that the) s -5 228 M -( server must ensure fairness in the sense that processing of no) s -5 217 M -( request will be indefinitely delayed even if the client is sending) s -5 206 M -( other requests so that there are multiple outstanding requests all) s -5 195 M -( the time.) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 13]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 14 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -(6.2 File Names) s -5 668 M -( This protocol represents file names as strings. File names are) s -5 657 M -( assumed to use the slash \('/'\) character as a directory separator.) s -5 635 M -( File names starting with a slash are "absolute", and are relative to) s -5 624 M -( the root of the file system. Names starting with any other character) s -5 613 M -( are relative to the user's default directory \(home directory\). Note) s -5 602 M -( that identifying the user is assumed to take place outside of this) s -5 591 M -( protocol.) s -5 569 M -( Servers SHOULD interpret a path name component ".." as referring to) s -5 558 M -( the parent directory, and "." as referring to the current directory.) s -5 547 M -( If the server implementation limits access to certain parts of the) s -5 536 M -( file system, it must be extra careful in parsing file names when) s -5 525 M -( enforcing such restrictions. There have been numerous reported) s -5 514 M -( security bugs where a ".." in a path name has allowed access outside) s -5 503 M -( the intended area.) s -5 481 M -( An empty path name is valid, and it refers to the user's default) s -5 470 M -( directory \(usually the user's home directory\).) s -5 448 M -( Otherwise, no syntax is defined for file names by this specification.) s -5 437 M -( Clients should not make any other assumptions; however, they can) s -5 426 M -( splice path name components returned by SSH_FXP_READDIR together) s -5 415 M -( using a slash \('/'\) as the separator, and that will work as expected.) s -5 393 M -( In order to comply with IETF Policy on Character Sets and Languages) s -5 382 M -( [2], all filenames are to be encoded in UTF-8. The shortest valid) s -5 371 M -( UTF-8 encoding of the UNICODE data MUST be used. The server is) s -5 360 M -( responsible for converting the UNICODE data to whatever canonical) s -5 349 M -( form it requires.) s -5 327 M -( For example, if the server requires that precomposed characters) s -5 316 M -( always be used, the server MUST NOT assume the filename as sent by) s -5 305 M -( the client has this attribute, but must do this normalization itself.) s -5 283 M -( It is understood that the lack of well-defined semantics for file) s -5 272 M -( names may cause interoperability problems between clients and servers) s -5 261 M -( using radically different operating systems. However, this approach) s -5 250 M -( is known to work acceptably with most systems, and alternative) s -5 239 M -( approaches that e.g. treat file names as sequences of structured) s -5 228 M -( components are quite complicated.) s -5 206 M -(6.3 Opening, Creating, and Closing Files) s -5 184 M -( Files are opened and created using the SSH_FXP_OPEN message, whose) s -5 173 M -( data part is as follows:) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 14]) s -_R -S -PStoPSsaved restore -%%Page: (14,15) 8 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 15 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -( uint32 id) s -5 679 M -( string filename [UTF-8]) s -5 668 M -( uint32 pflags) s -5 657 M -( ATTRS attrs) s -5 635 M -( The `id' field is the request identifier as for all requests.) s -5 613 M -( The `filename' field specifies the file name. See Section ``File) s -5 602 M -( Names'' for more information.) s -5 580 M -( The `pflags' field is a bitmask. The following bits have been) s -5 569 M -( defined.) s -5 547 M -( #define SSH_FXF_READ 0x00000001) s -5 536 M -( #define SSH_FXF_WRITE 0x00000002) s -5 525 M -( #define SSH_FXF_APPEND 0x00000004) s -5 514 M -( #define SSH_FXF_CREAT 0x00000008) s -5 503 M -( #define SSH_FXF_TRUNC 0x00000010) s -5 492 M -( #define SSH_FXF_EXCL 0x00000020) s -5 481 M -( #define SSH_FXF_TEXT 0x00000040) s -5 459 M -( These have the following meanings:) s -5 437 M -( SSH_FXF_READ) s -5 426 M -( Open the file for reading.) s -5 404 M -( SSH_FXF_WRITE) s -5 393 M -( Open the file for writing. If both this and SSH_FXF_READ are) s -5 382 M -( specified, the file is opened for both reading and writing.) s -5 360 M -( SSH_FXF_APPEND) s -5 349 M -( Force all writes to append data at the end of the file. The) s -5 338 M -( offset parameter to write will be ignored.) s -5 316 M -( SSH_FXF_CREAT) s -5 305 M -( If this flag is specified, then a new file will be created if one) s -5 294 M -( does not already exist \(if O_TRUNC is specified, the new file will) s -5 283 M -( be truncated to zero length if it previously exists\).) s -5 261 M -( SSH_FXF_TRUNC) s -5 250 M -( Forces an existing file with the same name to be truncated to zero) s -5 239 M -( length when creating a file by specifying SSH_FXF_CREAT.) s -5 228 M -( SSH_FXF_CREAT MUST also be specified if this flag is used.) s -5 206 M -( SSH_FXF_EXCL) s -5 195 M -( Causes the request to fail if the named file already exists.) s -5 184 M -( SSH_FXF_CREAT MUST also be specified if this flag is used.) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 15]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 16 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -( SSH_FXF_TEXT) s -5 679 M -( Indicates that the server should treat the file as text and) s -5 668 M -( convert it to the canonical newline convention in use. \(See) s -5 657 M -( Determining Server Newline Convention. \(Section 4.3\)) s -5 635 M -( When a file is opened with the FXF_TEXT flag, the offset field in) s -5 624 M -( both the read and write function are ignored.) s -5 602 M -( Servers MUST correctly process multiple parallel reads and writes) s -5 591 M -( correctly in this mode. Naturally, it is permissible for them to) s -5 580 M -( do this by serializing the requests. It would not be possible for) s -5 569 M -( a client to reliably detect a server that does not implement) s -5 558 M -( parallel writes in time to prevent damage.) s -5 536 M -( Clients SHOULD use the SSH_FXF_APPEND flag to append data to a) s -5 525 M -( text file rather then using write with a calculated offset.) s -5 503 M -( To support seeks on text file the following SSH_FXP_EXTENDED) s -5 492 M -( packet is defined.) s -5 448 M -( string "text-seek") s -5 437 M -( string file-handle) s -5 426 M -( uint64 line-number) s -5 404 M -( line-number is the index of the line number to seek to, where byte) s -5 393 M -( 0 in the file is line number 0, and the byte directly following) s -5 382 M -( the first newline sequence in the file is line number 1 and so on.) s -5 360 M -( The response to a "text-seek" request is an SSH_FXP_STATUS) s -5 349 M -( message.) s -5 327 M -( An attempt to seek past the end-of-file should result in a) s -5 316 M -( SSH_FX_EOF status.) s -5 294 M -( Servers SHOULD support at least one "text-seek" in order to) s -5 283 M -( support resume. However, a client MUST be prepared to receive) s -5 272 M -( SSH_FX_OP_UNSUPPORTED when attempting a "text-seek" operation.) s -5 261 M -( The client can then try a fall-back strategy, if it has one.) s -5 239 M -( Clients MUST be prepared to handle SSH_FX_OP_UNSUPPORTED returned) s -5 228 M -( for read or write operations that are not sequential.) s -5 206 M -( The `attrs' field specifies the initial attributes for the file.) s -5 195 M -( Default values will be used for those attributes that are not) s -5 184 M -( specified. See Section ``File Attributes'' for more information.) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 16]) s -_R -S -PStoPSsaved restore -%%Page: (16,17) 9 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 17 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -( The response to this message will be either SSH_FXP_HANDLE \(if the) s -5 679 M -( operation is successful\) or SSH_FXP_STATUS \(if the operation fails\).) s -5 657 M -( A file is closed by using the SSH_FXP_CLOSE request. Its data field) s -5 646 M -( has the following format:) s -5 624 M -( uint32 id) s -5 613 M -( string handle) s -5 591 M -( where `id' is the request identifier, and `handle' is a handle) s -5 580 M -( previously returned in the response to SSH_FXP_OPEN or) s -5 569 M -( SSH_FXP_OPENDIR. The handle becomes invalid immediately after this) s -5 558 M -( request has been sent.) s -5 536 M -( The response to this request will be a SSH_FXP_STATUS message. One) s -5 525 M -( should note that on some server platforms even a close can fail.) s -5 514 M -( This can happen e.g. if the server operating system caches writes,) s -5 503 M -( and an error occurs while flushing cached writes during the close.) s -5 481 M -(6.4 Reading and Writing) s -5 459 M -( Once a file has been opened, it can be read using the SSH_FXP_READ) s -5 448 M -( message, which has the following format:) s -5 426 M -( uint32 id) s -5 415 M -( string handle) s -5 404 M -( uint64 offset) s -5 393 M -( uint32 len) s -5 371 M -( where `id' is the request identifier, `handle' is an open file handle) s -5 360 M -( returned by SSH_FXP_OPEN, `offset' is the offset \(in bytes\) relative) s -5 349 M -( to the beginning of the file from where to start reading, and `len') s -5 338 M -( is the maximum number of bytes to read.) s -5 316 M -( In response to this request, the server will read as many bytes as it) s -5 305 M -( can from the file \(up to `len'\), and return them in a SSH_FXP_DATA) s -5 294 M -( message. If an error occurs or EOF is encountered before reading any) s -5 283 M -( data, the server will respond with SSH_FXP_STATUS. For normal disk) s -5 272 M -( files, it is guaranteed that this will read the specified number of) s -5 261 M -( bytes, or up to end of file. For e.g. device files this may return) s -5 250 M -( fewer bytes than requested.) s -5 228 M -( Writing to a file is achieved using the SSH_FXP_WRITE message, which) s -5 217 M -( has the following format:) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 17]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 18 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -( uint32 id) s -5 679 M -( string handle) s -5 668 M -( uint64 offset) s -5 657 M -( string data) s -5 635 M -( where `id' is a request identifier, `handle' is a file handle) s -5 624 M -( returned by SSH_FXP_OPEN, `offset' is the offset \(in bytes\) from the) s -5 613 M -( beginning of the file where to start writing, and `data' is the data) s -5 602 M -( to be written.) s -5 580 M -( The write will extend the file if writing beyond the end of the file.) s -5 569 M -( It is legal to write way beyond the end of the file; the semantics) s -5 558 M -( are to write zeroes from the end of the file to the specified offset) s -5 547 M -( and then the data. On most operating systems, such writes do not) s -5 536 M -( allocate disk space but instead leave "holes" in the file.) s -5 514 M -( The server responds to a write request with a SSH_FXP_STATUS message.) s -5 492 M -(6.5 Removing and Renaming Files) s -5 470 M -( Files can be removed using the SSH_FXP_REMOVE message. It has the) s -5 459 M -( following format:) s -5 437 M -( uint32 id) s -5 426 M -( string filename [UTF-8]) s -5 404 M -( where `id' is the request identifier and `filename' is the name of) s -5 393 M -( the file to be removed. See Section ``File Names'' for more) s -5 382 M -( information. This request cannot be used to remove directories.) s -5 360 M -( The server will respond to this request with a SSH_FXP_STATUS) s -5 349 M -( message.) s -5 327 M -( Files \(and directories\) can be renamed using the SSH_FXP_RENAME) s -5 316 M -( message. Its data is as follows:) s -5 294 M -( uint32 id) s -5 283 M -( string oldpath [UTF-8]) s -5 272 M -( string newpath [UTF-8]) s -5 250 M -( where `id' is the request identifier, `oldpath' is the name of an) s -5 239 M -( existing file or directory, and `newpath' is the new name for the) s -5 228 M -( file or directory. It is an error if there already exists a file) s -5 217 M -( with the name specified by newpath. The server may also fail rename) s -5 206 M -( requests in other situations, for example if `oldpath' and `newpath') s -5 195 M -( point to different file systems on the server.) s -5 173 M -( The server will respond to this request with a SSH_FXP_STATUS) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 18]) s -_R -S -PStoPSsaved restore -%%Page: (18,19) 10 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 19 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -( message.) s -5 668 M -(6.6 Creating and Deleting Directories) s -5 646 M -( New directories can be created using the SSH_FXP_MKDIR request. It) s -5 635 M -( has the following format:) s -5 613 M -( uint32 id) s -5 602 M -( string path [UTF-8]) s -5 591 M -( ATTRS attrs) s -5 569 M -( where `id' is the request identifier.) s -5 547 M -( `path' specifies the directory to be created. See Section ``File) s -5 536 M -( Names'' for more information on file names.) s -5 514 M -( `attrs' specifies the attributes that should be applied to it upon) s -5 503 M -( creation. Attributes are discussed in more detail in Section ``File) s -5 492 M -( Attributes''.) s -5 470 M -( The server will respond to this request with a SSH_FXP_STATUS) s -5 459 M -( message. If a file or directory with the specified path already) s -5 448 M -( exists, an error will be returned.) s -5 426 M -( Directories can be removed using the SSH_FXP_RMDIR request, which has) s -5 415 M -( the following format:) s -5 393 M -( uint32 id) s -5 382 M -( string path [UTF-8]) s -5 360 M -( where `id' is the request identifier, and `path' specifies the) s -5 349 M -( directory to be removed. See Section ``File Names'' for more) s -5 338 M -( information on file names.) s -5 316 M -( The server responds to this request with a SSH_FXP_STATUS message.) s -5 305 M -( Errors may be returned from this operation for various reasons,) s -5 294 M -( including, but not limited to, the path does not exist, the path does) s -5 283 M -( not refer to a directory object, the directory is not empty, or the) s -5 272 M -( user has insufficient access or permission to perform the requested) s -5 261 M -( operation.) s -5 239 M -(6.7 Scanning Directories) s -5 217 M -( The files in a directory can be listed using the SSH_FXP_OPENDIR and) s -5 206 M -( SSH_FXP_READDIR requests. Each SSH_FXP_READDIR request returns one) s -5 195 M -( or more file names with full file attributes for each file. The) s -5 184 M -( client should call SSH_FXP_READDIR repeatedly until it has found the) s -5 173 M -( file it is looking for or until the server responds with a) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 19]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 20 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -( SSH_FXP_STATUS message indicating an error \(normally SSH_FX_EOF if) s -5 679 M -( there are no more files in the directory\). The client should then) s -5 668 M -( close the handle using the SSH_FXP_CLOSE request.) s -5 646 M -( The SSH_FXP_OPENDIR opens a directory for reading. It has the) s -5 635 M -( following format:) s -5 613 M -( uint32 id) s -5 602 M -( string path [UTF-8]) s -5 580 M -( where `id' is the request identifier and `path' is the path name of) s -5 569 M -( the directory to be listed \(without any trailing slash\). See Section) s -5 558 M -( ``File Names'' for more information on file names. This will return) s -5 547 M -( an error if the path does not specify a directory or if the directory) s -5 536 M -( is not readable. The server will respond to this request with either) s -5 525 M -( a SSH_FXP_HANDLE or a SSH_FXP_STATUS message.) s -5 503 M -( Once the directory has been successfully opened, files \(and) s -5 492 M -( directories\) contained in it can be listed using SSH_FXP_READDIR) s -5 481 M -( requests. These are of the format) s -5 459 M -( uint32 id) s -5 448 M -( string handle) s -5 426 M -( where `id' is the request identifier, and `handle' is a handle) s -5 415 M -( returned by SSH_FXP_OPENDIR. \(It is a protocol error to attempt to) s -5 404 M -( use an ordinary file handle returned by SSH_FXP_OPEN.\)) s -5 382 M -( The server responds to this request with either a SSH_FXP_NAME or a) s -5 371 M -( SSH_FXP_STATUS message. One or more names may be returned at a time.) s -5 360 M -( Full status information is returned for each name in order to speed) s -5 349 M -( up typical directory listings.) s -5 327 M -( If there are no more names available to be read, the server MUST) s -5 316 M -( respond with a SSH_FXP_STATUS message with error code of SSH_FX_EOF.) s -5 294 M -( When the client no longer wishes to read more names from the) s -5 283 M -( directory, it SHOULD call SSH_FXP_CLOSE for the handle. The handle) s -5 272 M -( should be closed regardless of whether an error has occurred or not.) s -5 250 M -(6.8 Retrieving File Attributes) s -5 228 M -( Very often, file attributes are automatically returned by) s -5 217 M -( SSH_FXP_READDIR. However, sometimes there is need to specifically) s -5 206 M -( retrieve the attributes for a named file. This can be done using the) s -5 195 M -( SSH_FXP_STAT, SSH_FXP_LSTAT and SSH_FXP_FSTAT requests.) s -5 173 M -( SSH_FXP_STAT and SSH_FXP_LSTAT only differ in that SSH_FXP_STAT) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 20]) s -_R -S -PStoPSsaved restore -%%Page: (20,21) 11 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 21 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -( follows symbolic links on the server, whereas SSH_FXP_LSTAT does not) s -5 679 M -( follow symbolic links. Both have the same format:) s -5 657 M -( uint32 id) s -5 646 M -( string path [UTF-8]) s -5 635 M -( uint32 flags) s -5 613 M -( where `id' is the request identifier, and `path' specifies the file) s -5 602 M -( system object for which status is to be returned. The server) s -5 591 M -( responds to this request with either SSH_FXP_ATTRS or SSH_FXP_STATUS.) s -5 569 M -( The flags field specify the attribute flags in which the client has) s -5 558 M -( particular interest. This is a hint to the server. For example,) s -5 547 M -( because retrieving owner / group and acl information can be an) s -5 536 M -( expensive operation under some operating systems, the server may) s -5 525 M -( choose not to retrieve this information unless the client expresses a) s -5 514 M -( specific interest in it.) s -5 492 M -( The client has no guarantee the server will provide all the fields) s -5 481 M -( that it has expressed an interest in.) s -5 459 M -( SSH_FXP_FSTAT differs from the others in that it returns status) s -5 448 M -( information for an open file \(identified by the file handle\). Its) s -5 437 M -( format is as follows:) s -5 415 M -( uint32 id) s -5 404 M -( string handle) s -5 393 M -( uint32 flags) s -5 371 M -( where `id' is the request identifier and `handle' is a file handle) s -5 360 M -( returned by SSH_FXP_OPEN. The server responds to this request with) s -5 349 M -( SSH_FXP_ATTRS or SSH_FXP_STATUS.) s -5 327 M -(6.9 Setting File Attributes) s -5 305 M -( File attributes may be modified using the SSH_FXP_SETSTAT and) s -5 294 M -( SSH_FXP_FSETSTAT requests. These requests are used for operations) s -5 283 M -( such as changing the ownership, permissions or access times, as well) s -5 272 M -( as for truncating a file.) s -5 250 M -( The SSH_FXP_SETSTAT request is of the following format:) s -5 228 M -( uint32 id) s -5 217 M -( string path [UTF-8]) s -5 206 M -( ATTRS attrs) s -5 184 M -( where `id' is the request identifier, `path' specifies the file) s -5 173 M -( system object \(e.g. file or directory\) whose attributes are to be) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 21]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 22 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -( modified, and `attrs' specifies the modifications to be made to its) s -5 679 M -( attributes. Attributes are discussed in more detail in Section) s -5 668 M -( ``File Attributes''.) s -5 646 M -( An error will be returned if the specified file system object does) s -5 635 M -( not exist or the user does not have sufficient rights to modify the) s -5 624 M -( specified attributes. The server responds to this request with a) s -5 613 M -( SSH_FXP_STATUS message.) s -5 591 M -( The SSH_FXP_FSETSTAT request modifies the attributes of a file which) s -5 580 M -( is already open. It has the following format:) s -5 558 M -( uint32 id) s -5 547 M -( string handle) s -5 536 M -( ATTRS attrs) s -5 514 M -( where `id' is the request identifier, `handle' \(MUST be returned by) s -5 503 M -( SSH_FXP_OPEN\) identifies the file whose attributes are to be) s -5 492 M -( modified, and `attrs' specifies the modifications to be made to its) s -5 481 M -( attributes. Attributes are discussed in more detail in Section) s -5 470 M -( ``File Attributes''. The server will respond to this request with) s -5 459 M -( SSH_FXP_STATUS.) s -5 437 M -(6.10 Dealing with Symbolic links) s -5 415 M -( The SSH_FXP_READLINK request may be used to read the target of a) s -5 404 M -( symbolic link. It would have a data part as follows:) s -5 382 M -( uint32 id) s -5 371 M -( string path [UTF-8]) s -5 349 M -( where `id' is the request identifier and `path' specifies the path) s -5 338 M -( name of the symlink to be read.) s -5 316 M -( The server will respond with a SSH_FXP_NAME packet containing only) s -5 305 M -( one name and a dummy attributes value. The name in the returned) s -5 294 M -( packet contains the target of the link. If an error occurs, the) s -5 283 M -( server may respond with SSH_FXP_STATUS.) s -5 261 M -( The SSH_FXP_SYMLINK request will create a symbolic link on the) s -5 250 M -( server. It is of the following format) s -5 228 M -( uint32 id) s -5 217 M -( string linkpath [UTF-8]) s -5 206 M -( string targetpath [UTF-8]) s -5 184 M -( where `id' is the request identifier, `linkpath' specifies the path) s -5 173 M -( name of the symlink to be created and `targetpath' specifies the) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 22]) s -_R -S -PStoPSsaved restore -%%Page: (22,23) 12 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 23 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -( target of the symlink. The server shall respond with a) s -5 679 M -( SSH_FXP_STATUS indicating either success \(SSH_FX_OK\) or an error) s -5 668 M -( condition.) s -5 646 M -(6.11 Canonicalizing the Server-Side Path Name) s -5 624 M -( The SSH_FXP_REALPATH request can be used to have the server) s -5 613 M -( canonicalize any given path name to an absolute path. This is useful) s -5 602 M -( for converting path names containing ".." components or relative) s -5 591 M -( pathnames without a leading slash into absolute paths. The format of) s -5 580 M -( the request is as follows:) s -5 558 M -( uint32 id) s -5 547 M -( string path [UTF-8]) s -5 525 M -( where `id' is the request identifier and `path' specifies the path) s -5 514 M -( name to be canonicalized. The server will respond with a) s -5 503 M -( SSH_FXP_NAME packet containing the name in canonical form and a dummy) s -5 492 M -( attributes value. If an error occurs, the server may also respond) s -5 481 M -( with SSH_FXP_STATUS.) s -5 459 M -(6.11.1 Best practice for dealing with paths) s -5 437 M -( The client SHOULD treat the results of SSH_FXP_REALPATH as a) s -5 426 M -( canonical absolute path, even if the path does not appear to be) s -5 415 M -( absolute. A client that use REALPATH\("."\) and treats the result as) s -5 404 M -( absolute, even if there is no leading slash, will continue to) s -5 393 M -( function correctly, even when talking to a Windows NT or VMS style) s -5 382 M -( system, where absolute paths may not begin with a slash.) s -5 360 M -( For example, if the client wishes to change directory up, and the) s -5 349 M -( server has returned "c:/x/y/z" from REALPATH, the client SHOULD use) s -5 338 M -( "c:/x/y/z/..".) s -5 316 M -( As a second example, if the client wishes to open the file "x.txt" in) s -5 305 M -( the current directory, and server has returned "dka100:/x/y/z" as the) s -5 294 M -( canonical path of the directory, the client SHOULD open "dka100:/x/y/) s -5 283 M -( z/x.txt") s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 23]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 24 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -(7. Responses from the Server to the Client) s -5 668 M -( The server responds to the client using one of a few response) s -5 657 M -( packets. All requests can return a SSH_FXP_STATUS response upon) s -5 646 M -( failure. When the operation is successful, any of the responses may) s -5 635 M -( be returned \(depending on the operation\). If no data needs to be) s -5 624 M -( returned to the client, the SSH_FXP_STATUS response with SSH_FX_OK) s -5 613 M -( status is appropriate. Otherwise, the SSH_FXP_HANDLE message is used) s -5 602 M -( to return a file handle \(for SSH_FXP_OPEN and SSH_FXP_OPENDIR) s -5 591 M -( requests\), SSH_FXP_DATA is used to return data from SSH_FXP_READ,) s -5 580 M -( SSH_FXP_NAME is used to return one or more file names from a) s -5 569 M -( SSH_FXP_READDIR or SSH_FXP_REALPATH request, and SSH_FXP_ATTRS is) s -5 558 M -( used to return file attributes from SSH_FXP_STAT, SSH_FXP_LSTAT, and) s -5 547 M -( SSH_FXP_FSTAT requests.) s -5 525 M -( Exactly one response will be returned for each request. Each) s -5 514 M -( response packet contains a request identifier which can be used to) s -5 503 M -( match each response with the corresponding request. Note that it is) s -5 492 M -( legal to have several requests outstanding simultaneously, and the) s -5 481 M -( server is allowed to send responses to them in a different order from) s -5 470 M -( the order in which the requests were sent \(the result of their) s -5 459 M -( execution, however, is guaranteed to be as if they had been processed) s -5 448 M -( one at a time in the order in which the requests were sent\).) s -5 426 M -( Response packets are of the same general format as request packets.) s -5 415 M -( Each response packet begins with the request identifier.) s -5 393 M -( The format of the data portion of the SSH_FXP_STATUS response is as) s -5 382 M -( follows:) s -5 360 M -( uint32 id) s -5 349 M -( uint32 error/status code) s -5 338 M -( string error message \(ISO-10646 UTF-8 [RFC-2279]\)) s -5 327 M -( string language tag \(as defined in [RFC-1766]\)) s -5 305 M -( where `id' is the request identifier, and `error/status code') s -5 294 M -( indicates the result of the requested operation. The value SSH_FX_OK) s -5 283 M -( indicates success, and all other values indicate failure.) s -5 261 M -( Currently, the following values are defined \(other values may be) s -5 250 M -( defined by future versions of this protocol\):) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 24]) s -_R -S -PStoPSsaved restore -%%Page: (24,25) 13 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 25 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -( #define SSH_FX_OK 0) s -5 679 M -( #define SSH_FX_EOF 1) s -5 668 M -( #define SSH_FX_NO_SUCH_FILE 2) s -5 657 M -( #define SSH_FX_PERMISSION_DENIED 3) s -5 646 M -( #define SSH_FX_FAILURE 4) s -5 635 M -( #define SSH_FX_BAD_MESSAGE 5) s -5 624 M -( #define SSH_FX_NO_CONNECTION 6) s -5 613 M -( #define SSH_FX_CONNECTION_LOST 7) s -5 602 M -( #define SSH_FX_OP_UNSUPPORTED 8) s -5 591 M -( #define SSH_FX_INVALID_HANDLE 9) s -5 580 M -( #define SSH_FX_NO_SUCH_PATH 10) s -5 569 M -( #define SSH_FX_FILE_ALREADY_EXISTS 11) s -5 558 M -( #define SSH_FX_WRITE_PROTECT 12) s -5 536 M -( SSH_FX_OK) s -5 525 M -( Indicates successful completion of the operation.) s -5 503 M -( SSH_FX_EOF) s -5 492 M -( indicates end-of-file condition; for SSH_FX_READ it means that no) s -5 481 M -( more data is available in the file, and for SSH_FX_READDIR it) s -5 470 M -( indicates that no more files are contained in the directory.) s -5 448 M -( SSH_FX_NO_SUCH_FILE) s -5 437 M -( is returned when a reference is made to a file which does not) s -5 426 M -( exist.) s -5 404 M -( SSH_FX_PERMISSION_DENIED) s -5 393 M -( is returned when the authenticated user does not have sufficient) s -5 382 M -( permissions to perform the operation.) s -5 360 M -( SSH_FX_FAILURE) s -5 349 M -( is a generic catch-all error message; it should be returned if an) s -5 338 M -( error occurs for which there is no more specific error code) s -5 327 M -( defined.) s -5 305 M -( SSH_FX_BAD_MESSAGE) s -5 294 M -( may be returned if a badly formatted packet or protocol) s -5 283 M -( incompatibility is detected.) s -5 261 M -( SSH_FX_NO_CONNECTION) s -5 250 M -( is a pseudo-error which indicates that the client has no) s -5 239 M -( connection to the server \(it can only be generated locally by the) s -5 228 M -( client, and MUST NOT be returned by servers\).) s -5 206 M -( SSH_FX_CONNECTION_LOST) s -5 195 M -( is a pseudo-error which indicates that the connection to the) s -5 184 M -( server has been lost \(it can only be generated locally by the) s -5 173 M -( client, and MUST NOT be returned by servers\).) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 25]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 26 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -( SSH_FX_OP_UNSUPPORTED) s -5 679 M -( indicates that an attempt was made to perform an operation which) s -5 668 M -( is not supported for the server \(it may be generated locally by) s -5 657 M -( the client if e.g. the version number exchange indicates that a) s -5 646 M -( required feature is not supported by the server, or it may be) s -5 635 M -( returned by the server if the server does not implement an) s -5 624 M -( operation\).) s -5 602 M -( SSH_FX_INVALID_HANDLE) s -5 591 M -( The handle value was invalid.) s -5 569 M -( SSH_FX_NO_SUCH_PATH) s -5 558 M -( The file path does not exist or is invalid.) s -5 536 M -( SSH_FX_FILE_ALREADY_EXISTS) s -5 525 M -( The file already exists.) s -5 503 M -( SSH_FX_WRITE_PROTECT) s -5 492 M -( The file is on read only media, or the media is write protected.) s -5 470 M -( The SSH_FXP_HANDLE response has the following format:) s -5 448 M -( uint32 id) s -5 437 M -( string handle) s -5 415 M -( where `id' is the request identifier, and `handle' is an arbitrary) s -5 404 M -( string that identifies an open file or directory on the server. The) s -5 393 M -( handle is opaque to the client; the client MUST NOT attempt to) s -5 382 M -( interpret or modify it in any way. The length of the handle string) s -5 371 M -( MUST NOT exceed 256 data bytes.) s -5 349 M -( The SSH_FXP_DATA response has the following format:) s -5 327 M -( uint32 id) s -5 316 M -( string data) s -5 294 M -( where `id' is the request identifier, and `data' is an arbitrary byte) s -5 283 M -( string containing the requested data. The data string may be at most) s -5 272 M -( the number of bytes requested in a SSH_FXP_READ request, but may also) s -5 261 M -( be shorter if end of file is reached or if the read is from something) s -5 250 M -( other than a regular file.) s -5 228 M -( The SSH_FXP_NAME response has the following format:) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 26]) s -_R -S -PStoPSsaved restore -%%Page: (26,27) 14 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 27 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -( uint32 id) s -5 679 M -( uint32 count) s -5 668 M -( repeats count times:) s -5 657 M -( string filename [UTF-8]) s -5 646 M -( ATTRS attrs) s -5 624 M -( where `id' is the request identifier, `count' is the number of names) s -5 613 M -( returned in this response, and the remaining fields repeat `count') s -5 602 M -( times \(so that all three fields are first included for the first) s -5 591 M -( file, then for the second file, etc\). In the repeated part,) s -5 580 M -( `filename' is a file name being returned \(for SSH_FXP_READDIR, it) s -5 569 M -( will be a relative name within the directory, without any path) s -5 558 M -( components; for SSH_FXP_REALPATH it will be an absolute path name\),) s -5 547 M -( and `attrs' is the attributes of the file as described in Section) s -5 536 M -( ``File Attributes''.) s -5 514 M -( The SSH_FXP_ATTRS response has the following format:) s -5 492 M -( uint32 id) s -5 481 M -( ATTRS attrs) s -5 459 M -( where `id' is the request identifier, and `attrs' is the returned) s -5 448 M -( file attributes as described in Section ``File Attributes''.) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 27]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 28 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -(8. Vendor-Specific Extensions) s -5 668 M -( The SSH_FXP_EXTENDED request provides a generic extension mechanism) s -5 657 M -( for adding vendor-specific commands. The request has the following) s -5 646 M -( format:) s -5 624 M -( uint32 id) s -5 613 M -( string extended-request) s -5 602 M -( ... any request-specific data ...) s -5 580 M -( where `id' is the request identifier, and `extended-request' is a) s -5 569 M -( string of the format "name@domain", where domain is an internet) s -5 558 M -( domain name of the vendor defining the request. The rest of the) s -5 547 M -( request is completely vendor-specific, and servers should only) s -5 536 M -( attempt to interpret it if they recognize the `extended-request') s -5 525 M -( name.) s -5 503 M -( The server may respond to such requests using any of the response) s -5 492 M -( packets defined in Section ``Responses from the Server to the) s -5 481 M -( Client''. Additionally, the server may also respond with a) s -5 470 M -( SSH_FXP_EXTENDED_REPLY packet, as defined below. If the server does) s -5 459 M -( not recognize the `extended-request' name, then the server MUST) s -5 448 M -( respond with SSH_FXP_STATUS with error/status set to) s -5 437 M -( SSH_FX_OP_UNSUPPORTED.) s -5 415 M -( The SSH_FXP_EXTENDED_REPLY packet can be used to carry arbitrary) s -5 404 M -( extension-specific data from the server to the client. It is of the) s -5 393 M -( following format:) s -5 371 M -( uint32 id) s -5 360 M -( ... any request-specific data ...) s -5 338 M -( There is a range of packet types reserved for use by extensions. In) s -5 327 M -( order to avoid collision, extensions that turn on the use of) s -5 316 M -( additional packet types should determine those numbers dynamically.) s -5 294 M -( The suggested way of doing this is have an extension request from the) s -5 283 M -( client to the server that enables the extension; the extension) s -5 272 M -( response from the server to the client would specify the actual type) s -5 261 M -( values to use, in additional to any other data.) s -5 239 M -( Extension authors should be mindful of the limited range of packet) s -5 228 M -( types available \(there are only 45 values available\) and avoid) s -5 217 M -( requiring a new packet type where possible.) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 28]) s -_R -S -PStoPSsaved restore -%%Page: (28,29) 15 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 29 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -(9. Security Considerations) s -5 668 M -( This protocol assumes that it is run over a secure channel and that) s -5 657 M -( the endpoints of the channel have been authenticated. Thus, this) s -5 646 M -( protocol assumes that it is externally protected from network-level) s -5 635 M -( attacks.) s -5 613 M -( This protocol provides file system access to arbitrary files on the) s -5 602 M -( server \(only constrained by the server implementation\). It is the) s -5 591 M -( responsibility of the server implementation to enforce any access) s -5 580 M -( controls that may be required to limit the access allowed for any) s -5 569 M -( particular user \(the user being authenticated externally to this) s -5 558 M -( protocol, typically using the SSH User Authentication Protocol [8].) s -5 536 M -( Care must be taken in the server implementation to check the validity) s -5 525 M -( of received file handle strings. The server should not rely on them) s -5 514 M -( directly; it MUST check the validity of each handle before relying on) s -5 503 M -( it.) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 29]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 30 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -(10. Changes from previous protocol versions) s -5 668 M -( The SSH File Transfer Protocol has changed over time, before it's) s -5 657 M -( standardization. The following is a description of the incompatible) s -5 646 M -( changes between different versions.) s -5 624 M -(10.1 Changes between versions 4 and 3) s -5 602 M -( Many of the changes between version 4 and version 3 are to the) s -5 591 M -( attribute structure to make it more flexible for non-unix platforms.) s -5 569 M -( o Make all filenames UTF-8.) s -5 547 M -( o Added 'newline' extension.) s -5 525 M -( o Made file attribute owner and group strings so they can actually) s -5 514 M -( be used on disparate systems.) s -5 492 M -( o Added createtime field, and added separate flags for atime,) s -5 481 M -( createtime, and mtime so they can be set separately.) s -5 459 M -( o Split the file type out of the permissions field and into it's own) s -5 448 M -( field \(which is always present.\)) s -5 426 M -( o Added acl attribute.) s -5 404 M -( o Added SSH_FXF_TEXT file open flag.) s -5 382 M -( o Added flags field to the get stat commands so that the client can) s -5 371 M -( specifically request information the server might not normally) s -5 360 M -( included for performance reasons.) s -5 338 M -( o Removed the long filename from the names structure-- it can now be) s -5 327 M -( built from information available in the attrs structure.) s -5 305 M -( o Added reserved range of packet numbers for extensions.) s -5 283 M -( o Added several additional error codes.) s -5 261 M -( o Change the way version negotiate works slightly. Previously, if) s -5 250 M -( the client version were higher than the server version, the server) s -5 239 M -( was supposed to 'echo back' the clients version. The server now) s -5 228 M -( sends it's own version and the lower of the two is considered to) s -5 217 M -( be the one in use.) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 30]) s -_R -S -PStoPSsaved restore -%%Page: (30,31) 16 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 31 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -(10.2 Changes between versions 3 and 2) s -5 668 M -( o The SSH_FXP_READLINK and SSH_FXP_SYMLINK messages were added.) s -5 646 M -( o The SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY messages were) s -5 635 M -( added.) s -5 613 M -( o The SSH_FXP_STATUS message was changed to include fields `error) s -5 602 M -( message' and `language tag'.) s -5 569 M -(10.3 Changes between versions 2 and 1) s -5 547 M -( o The SSH_FXP_RENAME message was added.) s -5 514 M -(10.4 Changes between versions 1 and 0) s -5 492 M -( o Implementation changes, no actual protocol changes.) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 31]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 32 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -(11. Trademark Issues) s -5 668 M -( "ssh" is a registered trademark of SSH Communications Security Corp) s -5 657 M -( in the United States and/or other countries.) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 32]) s -_R -S -PStoPSsaved restore -%%Page: (32,33) 17 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 33 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -(References) s -5 668 M -( [1] Dierks, T., Allen, C., Treese, W., Karlton, P., Freier, A. and) s -5 657 M -( P. Kocher, "The TLS Protocol Version 1.0", RFC 2246, January) s -5 646 M -( 1999.) s -5 624 M -( [2] Alvestrand, H., "IETF Policy on Character Sets and Languages",) s -5 613 M -( BCP 18, RFC 2277, January 1998.) s -5 591 M -( [3] Shepler, S., Callaghan, B., Robinson, D., Thurlow, R., Beame,) s -5 580 M -( C., Eisler, M. and D. Noveck, "NFS version 4 Protocol", RFC) s -5 569 M -( 3010, December 2000.) s -5 547 M -( [4] Institute of Electrical and Electronics Engineers, "Information) s -5 536 M -( Technology - Portable Operating System Interface \(POSIX\) - Part) s -5 525 M -( 1: System Application Program Interface \(API\) [C Language]",) s -5 514 M -( IEEE Standard 1003.2, 1996.) s -5 492 M -( [5] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S.) s -5 481 M -( Lehtinen, "SSH Protocol Architecture", draft-ietf-secsh-) s -5 470 M -( architecture-13 \(work in progress\), September 2002.) s -5 448 M -( [6] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S.) s -5 437 M -( Lehtinen, "SSH Protocol Transport Protocol", draft-ietf-secsh-) s -5 426 M -( transport-15 \(work in progress\), September 2002.) s -5 404 M -( [7] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S.) s -5 393 M -( Lehtinen, "SSH Connection Protocol", draft-ietf-secsh-connect-16) s -5 382 M -( \(work in progress\), September 2002.) s -5 360 M -( [8] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S.) s -5 349 M -( Lehtinen, "SSH Authentication Protocol", draft-ietf-secsh-) s -5 338 M -( userauth-16 \(work in progress\), September 2002.) s -5 305 M -(Authors' Addresses) s -5 283 M -( Joseph Galbraith) s -5 272 M -( VanDyke Software) s -5 261 M -( 4848 Tramway Ridge Blvd) s -5 250 M -( Suite 101) s -5 239 M -( Albuquerque, NM 87111) s -5 228 M -( US) s -5 206 M -( Phone: +1 505 332 5700) s -5 195 M -( EMail: [email protected]) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 33]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 34 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -( Tatu Ylonen) s -5 679 M -( SSH Communications Security Corp) s -5 668 M -( Fredrikinkatu 42) s -5 657 M -( HELSINKI FIN-00100) s -5 646 M -( Finland) s -5 624 M -( EMail: [email protected]) s -5 591 M -( Sami Lehtinen) s -5 580 M -( SSH Communications Security Corp) s -5 569 M -( Fredrikinkatu 42) s -5 558 M -( HELSINKI FIN-00100) s -5 547 M -( Finland) s -5 525 M -( EMail: [email protected]) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 34]) s -_R -S -PStoPSsaved restore -%%Page: (34,35) 18 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 35 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH File Transfer Protocol October 2002) s -5 690 M -(Full Copyright Statement) s -5 668 M -( Copyright \(C\) The Internet Society \(2002\). All Rights Reserved.) s -5 646 M -( This document and translations of it may be copied and furnished to) s -5 635 M -( others, and derivative works that comment on or otherwise explain it) s -5 624 M -( or assist in its implementation may be prepared, copied, published) s -5 613 M -( and distributed, in whole or in part, without restriction of any) s -5 602 M -( kind, provided that the above copyright notice and this paragraph are) s -5 591 M -( included on all such copies and derivative works. However, this) s -5 580 M -( document itself may not be modified in any way, such as by removing) s -5 569 M -( the copyright notice or references to the Internet Society or other) s -5 558 M -( Internet organizations, except as needed for the purpose of) s -5 547 M -( developing Internet standards in which case the procedures for) s -5 536 M -( copyrights defined in the Internet Standards process must be) s -5 525 M -( followed, or as required to translate it into languages other than) s -5 514 M -( English.) s -5 492 M -( The limited permissions granted above are perpetual and will not be) s -5 481 M -( revoked by the Internet Society or its successors or assigns.) s -5 459 M -( This document and the information contained herein is provided on an) s -5 448 M -( "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING) s -5 437 M -( TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING) s -5 426 M -( BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION) s -5 415 M -( HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF) s -5 404 M -( MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.) s -5 382 M -(Acknowledgement) s -5 360 M -( Funding for the RFC Editor function is currently provided by the) s -5 349 M -( Internet Society.) s -5 129 M -(Galbraith, et al. Expires April 16, 2003 [Page 35]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 36 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -_R -S -PStoPSsaved restore -%%Trailer -%%Pages: 36 -%%DocumentNeededResources: font Courier-Bold Courier -%%EOF diff --git a/lib/ssh/doc/standard/draft-ietf-secsh-filexfer-03.txt b/lib/ssh/doc/standard/draft-ietf-secsh-filexfer-03.txt deleted file mode 100644 index 83960ae976..0000000000 --- a/lib/ssh/doc/standard/draft-ietf-secsh-filexfer-03.txt +++ /dev/null @@ -1,1962 +0,0 @@ - - - -Secure Shell Working Group J. Galbraith -Internet-Draft VanDyke Software -Expires: April 16, 2003 T. Ylonen - S. Lehtinen - SSH Communications Security Corp - October 16, 2002 - - - SSH File Transfer Protocol - draft-ietf-secsh-filexfer-03.txt - -Status of this Memo - - This document is an Internet-Draft and is in full conformance with - all provisions of Section 10 of RFC2026. - - Internet-Drafts are working documents of the Internet Engineering - Task Force (IETF), its areas, and its working groups. Note that - other groups may also distribute working documents as Internet- - Drafts. - - Internet-Drafts are draft documents valid for a maximum of six months - and may be updated, replaced, or obsoleted by other documents at any - time. It is inappropriate to use Internet-Drafts as reference - material or to cite them other than as "work in progress." - - The list of current Internet-Drafts can be accessed at http:// - www.ietf.org/ietf/1id-abstracts.txt. - - The list of Internet-Draft Shadow Directories can be accessed at - http://www.ietf.org/shadow.html. - - This Internet-Draft will expire on April 16, 2003. - -Copyright Notice - - Copyright (C) The Internet Society (2002). All Rights Reserved. - -Abstract - - The SSH File Transfer Protocol provides secure file transfer - functionality over any reliable data stream. It is the standard file - transfer protocol for use with the SSH2 protocol. This document - describes the file transfer protocol and its interface to the SSH2 - protocol suite. - - - - - - - -Galbraith, et al. Expires April 16, 2003 [Page 1] - -Internet-Draft SSH File Transfer Protocol October 2002 - - -Table of Contents - - 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . 3 - 2. Use with the SSH Connection Protocol . . . . . . . . . . . 4 - 3. General Packet Format . . . . . . . . . . . . . . . . . . 5 - 4. Protocol Initialization . . . . . . . . . . . . . . . . . 7 - 4.1 Client Initialization . . . . . . . . . . . . . . . . . . 7 - 4.2 Server Initialization . . . . . . . . . . . . . . . . . . 7 - 4.3 Determining Server Newline Convention . . . . . . . . . . 8 - 5. File Attributes . . . . . . . . . . . . . . . . . . . . . 9 - 5.1 Flags . . . . . . . . . . . . . . . . . . . . . . . . . . 9 - 5.2 Type . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 - 5.3 Size . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 - 5.4 Owner and Group . . . . . . . . . . . . . . . . . . . . . 10 - 5.5 Permissions . . . . . . . . . . . . . . . . . . . . . . . 11 - 5.6 Times . . . . . . . . . . . . . . . . . . . . . . . . . . 11 - 5.7 ACL . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 - 5.8 Extended attributes . . . . . . . . . . . . . . . . . . . 12 - 6. Requests From the Client to the Server . . . . . . . . . . 13 - 6.1 Request Synchronization and Reordering . . . . . . . . . . 13 - 6.2 File Names . . . . . . . . . . . . . . . . . . . . . . . . 14 - 6.3 Opening, Creating, and Closing Files . . . . . . . . . . . 14 - 6.4 Reading and Writing . . . . . . . . . . . . . . . . . . . 17 - 6.5 Removing and Renaming Files . . . . . . . . . . . . . . . 18 - 6.6 Creating and Deleting Directories . . . . . . . . . . . . 19 - 6.7 Scanning Directories . . . . . . . . . . . . . . . . . . . 19 - 6.8 Retrieving File Attributes . . . . . . . . . . . . . . . . 20 - 6.9 Setting File Attributes . . . . . . . . . . . . . . . . . 21 - 6.10 Dealing with Symbolic links . . . . . . . . . . . . . . . 22 - 6.11 Canonicalizing the Server-Side Path Name . . . . . . . . . 23 - 6.11.1 Best practice for dealing with paths . . . . . . . . . . . 23 - 7. Responses from the Server to the Client . . . . . . . . . 24 - 8. Vendor-Specific Extensions . . . . . . . . . . . . . . . . 28 - 9. Security Considerations . . . . . . . . . . . . . . . . . 29 - 10. Changes from previous protocol versions . . . . . . . . . 30 - 10.1 Changes between versions 4 and 3 . . . . . . . . . . . . . 30 - 10.2 Changes between versions 3 and 2 . . . . . . . . . . . . . 31 - 10.3 Changes between versions 2 and 1 . . . . . . . . . . . . . 31 - 10.4 Changes between versions 1 and 0 . . . . . . . . . . . . . 31 - 11. Trademark Issues . . . . . . . . . . . . . . . . . . . . . 32 - References . . . . . . . . . . . . . . . . . . . . . . . . 33 - Authors' Addresses . . . . . . . . . . . . . . . . . . . . 33 - Full Copyright Statement . . . . . . . . . . . . . . . . . 35 - - - - - - - - -Galbraith, et al. Expires April 16, 2003 [Page 2] - -Internet-Draft SSH File Transfer Protocol October 2002 - - -1. Introduction - - This protocol provides secure file transfer (and more generally file - system access) functionality over a reliable data stream, such as a - channel in the SSH2 protocol [5]. - - This protocol is designed so that it could be used to implement a - secure remote file system service, as well as a secure file transfer - service. - - This protocol assumes that it runs over a secure channel, and that - the server has already authenticated the user at the client end, and - that the identity of the client user is externally available to the - server implementation. - - In general, this protocol follows a simple request-response model. - Each request and response contains a sequence number and multiple - requests may be pending simultaneously. There are a relatively large - number of different request messages, but a small number of possible - response messages. Each request has one or more response messages - that may be returned in result (e.g., a read either returns data or - reports error status). - - The packet format descriptions in this specification follow the - notation presented in the secsh architecture draft. [5] - - Even though this protocol is described in the context of the SSH2 - protocol, this protocol is general and independent of the rest of the - SSH2 protocol suite. It could be used in a number of different - applications, such as secure file transfer over TLS RFC 2246 [1] and - transfer of management information in VPN applications. - - - - - - - - - - - - - - - - - - - - -Galbraith, et al. Expires April 16, 2003 [Page 3] - -Internet-Draft SSH File Transfer Protocol October 2002 - - -2. Use with the SSH Connection Protocol - - When used with the SSH2 Protocol suite, this protocol is intended to - be used from the SSH Connection Protocol [7] as a subsystem, as - described in section ``Starting a Shell or a Command''. The - subsystem name used with this protocol is "sftp". - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Galbraith, et al. Expires April 16, 2003 [Page 4] - -Internet-Draft SSH File Transfer Protocol October 2002 - - -3. General Packet Format - - All packets transmitted over the secure connection are of the - following format: - - uint32 length - byte type - byte[length - 1] data payload - - That is, they are just data preceded by 32-bit length and 8-bit type - fields. The `length' is the length of the data area, and does not - include the `length' field itself. The format and interpretation of - the data area depends on the packet type. - - All packet descriptions below only specify the packet type and the - data that goes into the data field. Thus, they should be prefixed by - the `length' and `type' fields. - - The maximum size of a packet is in practice determined by the client - (the maximum size of read or write requests that it sends, plus a few - bytes of packet overhead). All servers SHOULD support packets of at - least 34000 bytes (where the packet size refers to the full length, - including the header above). This should allow for reads and writes - of at most 32768 bytes. - - There is no limit on the number of outstanding (non-acknowledged) - requests that the client may send to the server. In practice this is - limited by the buffering available on the data stream and the queuing - performed by the server. If the server's queues are full, it should - not read any more data from the stream, and flow control will prevent - the client from sending more requests. Note, however, that while - there is no restriction on the protocol level, the client's API may - provide a limit in order to prevent infinite queuing of outgoing - requests at the client. - - The following values are defined for packet types. - - - - - - - - - - - - - - - -Galbraith, et al. Expires April 16, 2003 [Page 5] - -Internet-Draft SSH File Transfer Protocol October 2002 - - - #define SSH_FXP_INIT 1 - #define SSH_FXP_VERSION 2 - #define SSH_FXP_OPEN 3 - #define SSH_FXP_CLOSE 4 - #define SSH_FXP_READ 5 - #define SSH_FXP_WRITE 6 - #define SSH_FXP_LSTAT 7 - #define SSH_FXP_FSTAT 8 - #define SSH_FXP_SETSTAT 9 - #define SSH_FXP_FSETSTAT 10 - #define SSH_FXP_OPENDIR 11 - #define SSH_FXP_READDIR 12 - #define SSH_FXP_REMOVE 13 - #define SSH_FXP_MKDIR 14 - #define SSH_FXP_RMDIR 15 - #define SSH_FXP_REALPATH 16 - #define SSH_FXP_STAT 17 - #define SSH_FXP_RENAME 18 - #define SSH_FXP_READLINK 19 - #define SSH_FXP_SYMLINK 20 - - #define SSH_FXP_STATUS 101 - #define SSH_FXP_HANDLE 102 - #define SSH_FXP_DATA 103 - #define SSH_FXP_NAME 104 - #define SSH_FXP_ATTRS 105 - - #define SSH_FXP_EXTENDED 200 - #define SSH_FXP_EXTENDED_REPLY 201 - - RESERVED_FOR_EXTENSIONS 210-255 - - Additional packet types should only be defined if the protocol - version number (see Section ``Protocol Initialization'') is - incremented, and their use MUST be negotiated using the version - number. However, the SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY - packets can be used to implement vendor-specific extensions. See - Section ``Vendor-Specific-Extensions'' for more details. - - - - - - - - - - - - - -Galbraith, et al. Expires April 16, 2003 [Page 6] - -Internet-Draft SSH File Transfer Protocol October 2002 - - -4. Protocol Initialization - - When the file transfer protocol starts, the client first sends a - SSH_FXP_INIT (including its version number) packet to the server. - The server responds with a SSH_FXP_VERSION packet, supplying the - lowest of its own and the client's version number. Both parties - should from then on adhere to particular version of the protocol. - - The version number of the protocol specified in this document is 4. - The version number should be incremented for each incompatible - revision of this protocol. - -4.1 Client Initialization - - The SSH_FXP_INIT packet (from client to server) has the following - data: - - uint32 version - - Version 3 of this protocol allowed clients to include extensions in - the SSH_FXP_INIT packet; however, this can cause interoperability - problems with version 1 and version 2 servers because the client must - send this packet before knowing the servers version. - - In this version of the protocol, clients MUST use the - SSH_FXP_EXTENDED packet to send extensions to the server after - version exchange has completed. Clients MUST NOT include extensions - in the version packet. This will prevent interoperability problems - with older servers - -4.2 Server Initialization - - The SSH_FXP_VERSION packet (from server to client) has the following - data: - - uint32 version - <extension data> - - 'version' is the lower of the protocol version supported by the - server and the version number received from the client. - - The extension data may be empty, or may be a sequence of - - string extension_name - string extension_data - - pairs (both strings MUST always be present if one is, but the - `extension_data' string may be of zero length). If present, these - - - -Galbraith, et al. Expires April 16, 2003 [Page 7] - -Internet-Draft SSH File Transfer Protocol October 2002 - - - strings indicate extensions to the baseline protocol. The - `extension_name' field(s) identify the name of the extension. The - name should be of the form "name@domain", where the domain is the DNS - domain name of the organization defining the extension. Additional - names that are not of this format may be defined later by the IETF. - Implementations MUST silently ignore any extensions whose name they - do not recognize. - -4.3 Determining Server Newline Convention - - In order to correctly process text files in a cross platform - compatible way, the newline convention must be converted from that of - the server to that of the client, or, during an upload, from that of - the client to that of the server. - - Versions 3 and prior of this protocol made no provisions for - processing text files. Many clients implemented some sort of - conversion algorithm, but without either a 'canonical' on the wire - format or knowledge of the servers newline convention, correct - conversion was not always possible. - - Starting with Version 4, the SSH_FXF_TEXT file open flag (Section - 6.3) makes it possible to request that the server translate a file to - a 'canonical' on the wire format. This format uses \r\n as the line - separator. - - Servers for systems using multiple newline characters (for example, - Mac OS X or VMS) or systems using counted records, MUST translate to - the canonical form. - - However, to ease the burden of implementation on servers that use a - single, simple separator sequence, the following extension allows the - canonical format to be changed. - - string "newline" - string new-canonical-separator (usually "\r" or "\n" or "\r\n") - - All clients MUST support this extension. - - When processing text files, clients SHOULD NOT translate any - character or sequence that is not an exact match of the servers - newline separator. - - In particular, if the newline sequence being used is the canonical - "\r\n" sequence, a lone \r or a lone \n SHOULD be written through - without change. - - - - - -Galbraith, et al. Expires April 16, 2003 [Page 8] - -Internet-Draft SSH File Transfer Protocol October 2002 - - -5. File Attributes - - A new compound data type is defined for encoding file attributes. - The same encoding is used both when returning file attributes from - the server and when sending file attributes to the server. When - sending it to the server, the flags field specifies which attributes - are included, and the server will use default values for the - remaining attributes (or will not modify the values of remaining - attributes). When receiving attributes from the server, the flags - specify which attributes are included in the returned data. The - server normally returns all attributes it knows about. - - uint32 flags - byte type always present - uint64 size present only if flag SSH_FILEXFER_ATTR_SIZE - string owner present only if flag SSH_FILEXFER_ATTR_OWNERGROUP - string group present only if flag SSH_FILEXFER_ATTR_OWNERGROUP - uint32 permissions present only if flag SSH_FILEXFER_ATTR_PERMISSIONS - uint32 atime present only if flag SSH_FILEXFER_ATTR_ACCESSTIME - uint32 createtime present only if flag SSH_FILEXFER_ATTR_CREATETIME - uint32 mtime present only if flag SSH_FILEXFER_ATTR_MODIFYTIME - string acl present only if flag SSH_FILEXFER_ATTR_ACL - uint32 extended_count present only if flag SSH_FILEXFER_ATTR_EXTENDED - string extended_type - string extended_data - ... more extended data (extended_type - extended_data pairs), - so that number of pairs equals extended_count - - -5.1 Flags - - The `flags' specify which of the fields are present. Those fields - for which the corresponding flag is not set are not present (not - included in the packet). New flags can only be added by incrementing - the protocol version number (or by using the extension mechanism - described below). - - The flags bits are defined to have the following values: - - #define SSH_FILEXFER_ATTR_SIZE 0x00000001 - #define SSH_FILEXFER_ATTR_PERMISSIONS 0x00000004 - #define SSH_FILEXFER_ATTR_ACCESSTIME 0x00000008 - #define SSH_FILEXFER_ATTR_CREATETIME 0x00000010 - #define SSH_FILEXFER_ATTR_MODIFYTIME 0x00000020 - #define SSH_FILEXFER_ATTR_ACL 0x00000040 - #define SSH_FILEXFER_ATTR_OWNERGROUP 0x00000080 - #define SSH_FILEXFER_ATTR_EXTENDED 0x80000000 - - - - -Galbraith, et al. Expires April 16, 2003 [Page 9] - -Internet-Draft SSH File Transfer Protocol October 2002 - - - In previous versions of this protocol flags value 0x00000002 was - SSH_FILEXFER_ATTR_UIDGID. This value is now unused, and OWNERGROUP - was given a new value in order to ease implementation burden. - 0x00000002 MUST NOT appear in the mask. Some future version of this - protocol may reuse flag 0x00000002. - -5.2 Type - - The type field is always present. The following types are defined: - - #define SSH_FILEXFER_TYPE_REGULAR 1 - #define SSH_FILEXFER_TYPE_DIRECTORY 2 - #define SSH_FILEXFER_TYPE_SYMLINK 3 - #define SSH_FILEXFER_TYPE_SPECIAL 4 - #define SSH_FILEXFER_TYPE_UNKNOWN 5 - - On a POSIX system, these values would be derived from the permission - field. - -5.3 Size - - The `size' field specifies the size of the file on disk, in bytes. - If it is present during file creation, it should be considered a hint - as to the files eventual size. - - Files opened with the SSH_FXF_TEXT flag may have a size that is - greater or less than the value of the size field. - -5.4 Owner and Group - - The `owner' and `group' fields are represented as UTF-8 strings; this - is the form used by NFS v4. See NFS version 4 Protocol. [3] The - following text is selected quotations from section 5.6. - - To avoid a representation that is tied to a particular underlying - implementation at the client or server, the use of UTF-8 strings has - been chosen. The string should be of the form user@dns_domain". - This will allow for a client and server that do not use the same - local representation the ability to translate to a common syntax that - can be interpreted by both. In the case where there is no - translation available to the client or server, the attribute value - must be constructed without the "@". Therefore, the absence of the @ - from the owner or owner_group attribute signifies that no translation - was available and the receiver of the attribute should not place any - special meaning with the attribute value. Even though the attribute - value can not be translated, it may still be useful. In the case of - a client, the attribute string may be used for local display of - ownership. - - - -Galbraith, et al. Expires April 16, 2003 [Page 10] - -Internet-Draft SSH File Transfer Protocol October 2002 - - -5.5 Permissions - - The `permissions' field contains a bit mask of file permissions as - defined by POSIX [1]. - -5.6 Times - - The 'atime', 'createtime', and 'mtime' contain the access, creation, - and modification times of the files, respectively. They are - represented as seconds from Jan 1, 1970 in UTC. - -5.7 ACL - - The 'ACL' field contains an ACL similar to that defined in section - 5.9 of NFS version 4 Protocol [3]. - - uint32 ace-count - - repeated ace-count time: - uint32 ace-type - uint32 ace-flag - uint32 ace-mask - string who [UTF-8] - - ace-type is one of the following four values (taken from NFS Version - 4 Protocol [3]: - - const ACE4_ACCESS_ALLOWED_ACE_TYPE = 0x00000000; - const ACE4_ACCESS_DENIED_ACE_TYPE = 0x00000001; - const ACE4_SYSTEM_AUDIT_ACE_TYPE = 0x00000002; - const ACE4_SYSTEM_ALARM_ACE_TYPE = 0x00000003; - - ace-flag is a combination of the following flag values. See NFS - Version 4 Protocol [3] section 5.9.2: - - const ACE4_FILE_INHERIT_ACE = 0x00000001; - const ACE4_DIRECTORY_INHERIT_ACE = 0x00000002; - const ACE4_NO_PROPAGATE_INHERIT_ACE = 0x00000004; - const ACE4_INHERIT_ONLY_ACE = 0x00000008; - const ACE4_SUCCESSFUL_ACCESS_ACE_FLAG = 0x00000010; - const ACE4_FAILED_ACCESS_ACE_FLAG = 0x00000020; - const ACE4_IDENTIFIER_GROUP = 0x00000040; - - ace-mask is any combination of the following flags (taken from NFS - Version 4 Protocol [3] section 5.9.3: - - - - - - -Galbraith, et al. Expires April 16, 2003 [Page 11] - -Internet-Draft SSH File Transfer Protocol October 2002 - - - const ACE4_READ_DATA = 0x00000001; - const ACE4_LIST_DIRECTORY = 0x00000001; - const ACE4_WRITE_DATA = 0x00000002; - const ACE4_ADD_FILE = 0x00000002; - const ACE4_APPEND_DATA = 0x00000004; - const ACE4_ADD_SUBDIRECTORY = 0x00000004; - const ACE4_READ_NAMED_ATTRS = 0x00000008; - const ACE4_WRITE_NAMED_ATTRS = 0x00000010; - const ACE4_EXECUTE = 0x00000020; - const ACE4_DELETE_CHILD = 0x00000040; - const ACE4_READ_ATTRIBUTES = 0x00000080; - const ACE4_WRITE_ATTRIBUTES = 0x00000100; - const ACE4_DELETE = 0x00010000; - const ACE4_READ_ACL = 0x00020000; - const ACE4_WRITE_ACL = 0x00040000; - const ACE4_WRITE_OWNER = 0x00080000; - const ACE4_SYNCHRONIZE = 0x00100000; - - who is a UTF-8 string of the form described in 'Owner and Group' - (Section 5.4) - -5.8 Extended attributes - - The SSH_FILEXFER_ATTR_EXTENDED flag provides a general extension - mechanism for vendor-specific extensions. If the flag is specified, - then the `extended_count' field is present. It specifies the number - of extended_type-extended_data pairs that follow. Each of these - pairs specifies an extended attribute. For each of the attributes, - the extended_type field should be a string of the format - "name@domain", where "domain" is a valid, registered domain name and - "name" identifies the method. The IETF may later standardize certain - names that deviate from this format (e.g., that do not contain the - "@" sign). The interpretation of `extended_data' depends on the - type. Implementations SHOULD ignore extended data fields that they - do not understand. - - Additional fields can be added to the attributes by either defining - additional bits to the flags field to indicate their presence, or by - defining extended attributes for them. The extended attributes - mechanism is recommended for most purposes; additional flags bits - should only be defined by an IETF standards action that also - increments the protocol version number. The use of such new fields - MUST be negotiated by the version number in the protocol exchange. - It is a protocol error if a packet with unsupported protocol bits is - received. - - - - - - -Galbraith, et al. Expires April 16, 2003 [Page 12] - -Internet-Draft SSH File Transfer Protocol October 2002 - - -6. Requests From the Client to the Server - - Requests from the client to the server represent the various file - system operations. Each request begins with an `id' field, which is - a 32-bit identifier identifying the request (selected by the client). - The same identifier will be returned in the response to the request. - One possible implementation is a monotonically increasing request - sequence number (modulo 2^32). - - Many operations in the protocol operate on open files. The - SSH_FXP_OPEN request can return a file handle (which is an opaque - variable-length string) which may be used to access the file later - (e.g. in a read operation). The client MUST NOT send requests the - server with bogus or closed handles. However, the server MUST - perform adequate checks on the handle in order to avoid security - risks due to fabricated handles. - - This design allows either stateful and stateless server - implementation, as well as an implementation which caches state - between requests but may also flush it. The contents of the file - handle string are entirely up to the server and its design. The - client should not modify or attempt to interpret the file handle - strings. - - The file handle strings MUST NOT be longer than 256 bytes. - -6.1 Request Synchronization and Reordering - - The protocol and implementations MUST process requests relating to - the same file in the order in which they are received. In other - words, if an application submits multiple requests to the server, the - results in the responses will be the same as if it had sent the - requests one at a time and waited for the response in each case. For - example, the server may process non-overlapping read/write requests - to the same file in parallel, but overlapping reads and writes cannot - be reordered or parallelized. However, there are no ordering - restrictions on the server for processing requests from two different - file transfer connections. The server may interleave and parallelize - them at will. - - There are no restrictions on the order in which responses to - outstanding requests are delivered to the client, except that the - server must ensure fairness in the sense that processing of no - request will be indefinitely delayed even if the client is sending - other requests so that there are multiple outstanding requests all - the time. - - - - - -Galbraith, et al. Expires April 16, 2003 [Page 13] - -Internet-Draft SSH File Transfer Protocol October 2002 - - -6.2 File Names - - This protocol represents file names as strings. File names are - assumed to use the slash ('/') character as a directory separator. - - File names starting with a slash are "absolute", and are relative to - the root of the file system. Names starting with any other character - are relative to the user's default directory (home directory). Note - that identifying the user is assumed to take place outside of this - protocol. - - Servers SHOULD interpret a path name component ".." as referring to - the parent directory, and "." as referring to the current directory. - If the server implementation limits access to certain parts of the - file system, it must be extra careful in parsing file names when - enforcing such restrictions. There have been numerous reported - security bugs where a ".." in a path name has allowed access outside - the intended area. - - An empty path name is valid, and it refers to the user's default - directory (usually the user's home directory). - - Otherwise, no syntax is defined for file names by this specification. - Clients should not make any other assumptions; however, they can - splice path name components returned by SSH_FXP_READDIR together - using a slash ('/') as the separator, and that will work as expected. - - In order to comply with IETF Policy on Character Sets and Languages - [2], all filenames are to be encoded in UTF-8. The shortest valid - UTF-8 encoding of the UNICODE data MUST be used. The server is - responsible for converting the UNICODE data to whatever canonical - form it requires. - - For example, if the server requires that precomposed characters - always be used, the server MUST NOT assume the filename as sent by - the client has this attribute, but must do this normalization itself. - - It is understood that the lack of well-defined semantics for file - names may cause interoperability problems between clients and servers - using radically different operating systems. However, this approach - is known to work acceptably with most systems, and alternative - approaches that e.g. treat file names as sequences of structured - components are quite complicated. - -6.3 Opening, Creating, and Closing Files - - Files are opened and created using the SSH_FXP_OPEN message, whose - data part is as follows: - - - -Galbraith, et al. Expires April 16, 2003 [Page 14] - -Internet-Draft SSH File Transfer Protocol October 2002 - - - uint32 id - string filename [UTF-8] - uint32 pflags - ATTRS attrs - - The `id' field is the request identifier as for all requests. - - The `filename' field specifies the file name. See Section ``File - Names'' for more information. - - The `pflags' field is a bitmask. The following bits have been - defined. - - #define SSH_FXF_READ 0x00000001 - #define SSH_FXF_WRITE 0x00000002 - #define SSH_FXF_APPEND 0x00000004 - #define SSH_FXF_CREAT 0x00000008 - #define SSH_FXF_TRUNC 0x00000010 - #define SSH_FXF_EXCL 0x00000020 - #define SSH_FXF_TEXT 0x00000040 - - These have the following meanings: - - SSH_FXF_READ - Open the file for reading. - - SSH_FXF_WRITE - Open the file for writing. If both this and SSH_FXF_READ are - specified, the file is opened for both reading and writing. - - SSH_FXF_APPEND - Force all writes to append data at the end of the file. The - offset parameter to write will be ignored. - - SSH_FXF_CREAT - If this flag is specified, then a new file will be created if one - does not already exist (if O_TRUNC is specified, the new file will - be truncated to zero length if it previously exists). - - SSH_FXF_TRUNC - Forces an existing file with the same name to be truncated to zero - length when creating a file by specifying SSH_FXF_CREAT. - SSH_FXF_CREAT MUST also be specified if this flag is used. - - SSH_FXF_EXCL - Causes the request to fail if the named file already exists. - SSH_FXF_CREAT MUST also be specified if this flag is used. - - - - -Galbraith, et al. Expires April 16, 2003 [Page 15] - -Internet-Draft SSH File Transfer Protocol October 2002 - - - SSH_FXF_TEXT - Indicates that the server should treat the file as text and - convert it to the canonical newline convention in use. (See - Determining Server Newline Convention. (Section 4.3) - - When a file is opened with the FXF_TEXT flag, the offset field in - both the read and write function are ignored. - - Servers MUST correctly process multiple parallel reads and writes - correctly in this mode. Naturally, it is permissible for them to - do this by serializing the requests. It would not be possible for - a client to reliably detect a server that does not implement - parallel writes in time to prevent damage. - - Clients SHOULD use the SSH_FXF_APPEND flag to append data to a - text file rather then using write with a calculated offset. - - To support seeks on text file the following SSH_FXP_EXTENDED - packet is defined. - - - - string "text-seek" - string file-handle - uint64 line-number - - line-number is the index of the line number to seek to, where byte - 0 in the file is line number 0, and the byte directly following - the first newline sequence in the file is line number 1 and so on. - - The response to a "text-seek" request is an SSH_FXP_STATUS - message. - - An attempt to seek past the end-of-file should result in a - SSH_FX_EOF status. - - Servers SHOULD support at least one "text-seek" in order to - support resume. However, a client MUST be prepared to receive - SSH_FX_OP_UNSUPPORTED when attempting a "text-seek" operation. - The client can then try a fall-back strategy, if it has one. - - Clients MUST be prepared to handle SSH_FX_OP_UNSUPPORTED returned - for read or write operations that are not sequential. - - The `attrs' field specifies the initial attributes for the file. - Default values will be used for those attributes that are not - specified. See Section ``File Attributes'' for more information. - - - - -Galbraith, et al. Expires April 16, 2003 [Page 16] - -Internet-Draft SSH File Transfer Protocol October 2002 - - - The response to this message will be either SSH_FXP_HANDLE (if the - operation is successful) or SSH_FXP_STATUS (if the operation fails). - - A file is closed by using the SSH_FXP_CLOSE request. Its data field - has the following format: - - uint32 id - string handle - - where `id' is the request identifier, and `handle' is a handle - previously returned in the response to SSH_FXP_OPEN or - SSH_FXP_OPENDIR. The handle becomes invalid immediately after this - request has been sent. - - The response to this request will be a SSH_FXP_STATUS message. One - should note that on some server platforms even a close can fail. - This can happen e.g. if the server operating system caches writes, - and an error occurs while flushing cached writes during the close. - -6.4 Reading and Writing - - Once a file has been opened, it can be read using the SSH_FXP_READ - message, which has the following format: - - uint32 id - string handle - uint64 offset - uint32 len - - where `id' is the request identifier, `handle' is an open file handle - returned by SSH_FXP_OPEN, `offset' is the offset (in bytes) relative - to the beginning of the file from where to start reading, and `len' - is the maximum number of bytes to read. - - In response to this request, the server will read as many bytes as it - can from the file (up to `len'), and return them in a SSH_FXP_DATA - message. If an error occurs or EOF is encountered before reading any - data, the server will respond with SSH_FXP_STATUS. For normal disk - files, it is guaranteed that this will read the specified number of - bytes, or up to end of file. For e.g. device files this may return - fewer bytes than requested. - - Writing to a file is achieved using the SSH_FXP_WRITE message, which - has the following format: - - - - - - - -Galbraith, et al. Expires April 16, 2003 [Page 17] - -Internet-Draft SSH File Transfer Protocol October 2002 - - - uint32 id - string handle - uint64 offset - string data - - where `id' is a request identifier, `handle' is a file handle - returned by SSH_FXP_OPEN, `offset' is the offset (in bytes) from the - beginning of the file where to start writing, and `data' is the data - to be written. - - The write will extend the file if writing beyond the end of the file. - It is legal to write way beyond the end of the file; the semantics - are to write zeroes from the end of the file to the specified offset - and then the data. On most operating systems, such writes do not - allocate disk space but instead leave "holes" in the file. - - The server responds to a write request with a SSH_FXP_STATUS message. - -6.5 Removing and Renaming Files - - Files can be removed using the SSH_FXP_REMOVE message. It has the - following format: - - uint32 id - string filename [UTF-8] - - where `id' is the request identifier and `filename' is the name of - the file to be removed. See Section ``File Names'' for more - information. This request cannot be used to remove directories. - - The server will respond to this request with a SSH_FXP_STATUS - message. - - Files (and directories) can be renamed using the SSH_FXP_RENAME - message. Its data is as follows: - - uint32 id - string oldpath [UTF-8] - string newpath [UTF-8] - - where `id' is the request identifier, `oldpath' is the name of an - existing file or directory, and `newpath' is the new name for the - file or directory. It is an error if there already exists a file - with the name specified by newpath. The server may also fail rename - requests in other situations, for example if `oldpath' and `newpath' - point to different file systems on the server. - - The server will respond to this request with a SSH_FXP_STATUS - - - -Galbraith, et al. Expires April 16, 2003 [Page 18] - -Internet-Draft SSH File Transfer Protocol October 2002 - - - message. - -6.6 Creating and Deleting Directories - - New directories can be created using the SSH_FXP_MKDIR request. It - has the following format: - - uint32 id - string path [UTF-8] - ATTRS attrs - - where `id' is the request identifier. - - `path' specifies the directory to be created. See Section ``File - Names'' for more information on file names. - - `attrs' specifies the attributes that should be applied to it upon - creation. Attributes are discussed in more detail in Section ``File - Attributes''. - - The server will respond to this request with a SSH_FXP_STATUS - message. If a file or directory with the specified path already - exists, an error will be returned. - - Directories can be removed using the SSH_FXP_RMDIR request, which has - the following format: - - uint32 id - string path [UTF-8] - - where `id' is the request identifier, and `path' specifies the - directory to be removed. See Section ``File Names'' for more - information on file names. - - The server responds to this request with a SSH_FXP_STATUS message. - Errors may be returned from this operation for various reasons, - including, but not limited to, the path does not exist, the path does - not refer to a directory object, the directory is not empty, or the - user has insufficient access or permission to perform the requested - operation. - -6.7 Scanning Directories - - The files in a directory can be listed using the SSH_FXP_OPENDIR and - SSH_FXP_READDIR requests. Each SSH_FXP_READDIR request returns one - or more file names with full file attributes for each file. The - client should call SSH_FXP_READDIR repeatedly until it has found the - file it is looking for or until the server responds with a - - - -Galbraith, et al. Expires April 16, 2003 [Page 19] - -Internet-Draft SSH File Transfer Protocol October 2002 - - - SSH_FXP_STATUS message indicating an error (normally SSH_FX_EOF if - there are no more files in the directory). The client should then - close the handle using the SSH_FXP_CLOSE request. - - The SSH_FXP_OPENDIR opens a directory for reading. It has the - following format: - - uint32 id - string path [UTF-8] - - where `id' is the request identifier and `path' is the path name of - the directory to be listed (without any trailing slash). See Section - ``File Names'' for more information on file names. This will return - an error if the path does not specify a directory or if the directory - is not readable. The server will respond to this request with either - a SSH_FXP_HANDLE or a SSH_FXP_STATUS message. - - Once the directory has been successfully opened, files (and - directories) contained in it can be listed using SSH_FXP_READDIR - requests. These are of the format - - uint32 id - string handle - - where `id' is the request identifier, and `handle' is a handle - returned by SSH_FXP_OPENDIR. (It is a protocol error to attempt to - use an ordinary file handle returned by SSH_FXP_OPEN.) - - The server responds to this request with either a SSH_FXP_NAME or a - SSH_FXP_STATUS message. One or more names may be returned at a time. - Full status information is returned for each name in order to speed - up typical directory listings. - - If there are no more names available to be read, the server MUST - respond with a SSH_FXP_STATUS message with error code of SSH_FX_EOF. - - When the client no longer wishes to read more names from the - directory, it SHOULD call SSH_FXP_CLOSE for the handle. The handle - should be closed regardless of whether an error has occurred or not. - -6.8 Retrieving File Attributes - - Very often, file attributes are automatically returned by - SSH_FXP_READDIR. However, sometimes there is need to specifically - retrieve the attributes for a named file. This can be done using the - SSH_FXP_STAT, SSH_FXP_LSTAT and SSH_FXP_FSTAT requests. - - SSH_FXP_STAT and SSH_FXP_LSTAT only differ in that SSH_FXP_STAT - - - -Galbraith, et al. Expires April 16, 2003 [Page 20] - -Internet-Draft SSH File Transfer Protocol October 2002 - - - follows symbolic links on the server, whereas SSH_FXP_LSTAT does not - follow symbolic links. Both have the same format: - - uint32 id - string path [UTF-8] - uint32 flags - - where `id' is the request identifier, and `path' specifies the file - system object for which status is to be returned. The server - responds to this request with either SSH_FXP_ATTRS or SSH_FXP_STATUS. - - The flags field specify the attribute flags in which the client has - particular interest. This is a hint to the server. For example, - because retrieving owner / group and acl information can be an - expensive operation under some operating systems, the server may - choose not to retrieve this information unless the client expresses a - specific interest in it. - - The client has no guarantee the server will provide all the fields - that it has expressed an interest in. - - SSH_FXP_FSTAT differs from the others in that it returns status - information for an open file (identified by the file handle). Its - format is as follows: - - uint32 id - string handle - uint32 flags - - where `id' is the request identifier and `handle' is a file handle - returned by SSH_FXP_OPEN. The server responds to this request with - SSH_FXP_ATTRS or SSH_FXP_STATUS. - -6.9 Setting File Attributes - - File attributes may be modified using the SSH_FXP_SETSTAT and - SSH_FXP_FSETSTAT requests. These requests are used for operations - such as changing the ownership, permissions or access times, as well - as for truncating a file. - - The SSH_FXP_SETSTAT request is of the following format: - - uint32 id - string path [UTF-8] - ATTRS attrs - - where `id' is the request identifier, `path' specifies the file - system object (e.g. file or directory) whose attributes are to be - - - -Galbraith, et al. Expires April 16, 2003 [Page 21] - -Internet-Draft SSH File Transfer Protocol October 2002 - - - modified, and `attrs' specifies the modifications to be made to its - attributes. Attributes are discussed in more detail in Section - ``File Attributes''. - - An error will be returned if the specified file system object does - not exist or the user does not have sufficient rights to modify the - specified attributes. The server responds to this request with a - SSH_FXP_STATUS message. - - The SSH_FXP_FSETSTAT request modifies the attributes of a file which - is already open. It has the following format: - - uint32 id - string handle - ATTRS attrs - - where `id' is the request identifier, `handle' (MUST be returned by - SSH_FXP_OPEN) identifies the file whose attributes are to be - modified, and `attrs' specifies the modifications to be made to its - attributes. Attributes are discussed in more detail in Section - ``File Attributes''. The server will respond to this request with - SSH_FXP_STATUS. - -6.10 Dealing with Symbolic links - - The SSH_FXP_READLINK request may be used to read the target of a - symbolic link. It would have a data part as follows: - - uint32 id - string path [UTF-8] - - where `id' is the request identifier and `path' specifies the path - name of the symlink to be read. - - The server will respond with a SSH_FXP_NAME packet containing only - one name and a dummy attributes value. The name in the returned - packet contains the target of the link. If an error occurs, the - server may respond with SSH_FXP_STATUS. - - The SSH_FXP_SYMLINK request will create a symbolic link on the - server. It is of the following format - - uint32 id - string linkpath [UTF-8] - string targetpath [UTF-8] - - where `id' is the request identifier, `linkpath' specifies the path - name of the symlink to be created and `targetpath' specifies the - - - -Galbraith, et al. Expires April 16, 2003 [Page 22] - -Internet-Draft SSH File Transfer Protocol October 2002 - - - target of the symlink. The server shall respond with a - SSH_FXP_STATUS indicating either success (SSH_FX_OK) or an error - condition. - -6.11 Canonicalizing the Server-Side Path Name - - The SSH_FXP_REALPATH request can be used to have the server - canonicalize any given path name to an absolute path. This is useful - for converting path names containing ".." components or relative - pathnames without a leading slash into absolute paths. The format of - the request is as follows: - - uint32 id - string path [UTF-8] - - where `id' is the request identifier and `path' specifies the path - name to be canonicalized. The server will respond with a - SSH_FXP_NAME packet containing the name in canonical form and a dummy - attributes value. If an error occurs, the server may also respond - with SSH_FXP_STATUS. - -6.11.1 Best practice for dealing with paths - - The client SHOULD treat the results of SSH_FXP_REALPATH as a - canonical absolute path, even if the path does not appear to be - absolute. A client that use REALPATH(".") and treats the result as - absolute, even if there is no leading slash, will continue to - function correctly, even when talking to a Windows NT or VMS style - system, where absolute paths may not begin with a slash. - - For example, if the client wishes to change directory up, and the - server has returned "c:/x/y/z" from REALPATH, the client SHOULD use - "c:/x/y/z/..". - - As a second example, if the client wishes to open the file "x.txt" in - the current directory, and server has returned "dka100:/x/y/z" as the - canonical path of the directory, the client SHOULD open "dka100:/x/y/ - z/x.txt" - - - - - - - - - - - - - -Galbraith, et al. Expires April 16, 2003 [Page 23] - -Internet-Draft SSH File Transfer Protocol October 2002 - - -7. Responses from the Server to the Client - - The server responds to the client using one of a few response - packets. All requests can return a SSH_FXP_STATUS response upon - failure. When the operation is successful, any of the responses may - be returned (depending on the operation). If no data needs to be - returned to the client, the SSH_FXP_STATUS response with SSH_FX_OK - status is appropriate. Otherwise, the SSH_FXP_HANDLE message is used - to return a file handle (for SSH_FXP_OPEN and SSH_FXP_OPENDIR - requests), SSH_FXP_DATA is used to return data from SSH_FXP_READ, - SSH_FXP_NAME is used to return one or more file names from a - SSH_FXP_READDIR or SSH_FXP_REALPATH request, and SSH_FXP_ATTRS is - used to return file attributes from SSH_FXP_STAT, SSH_FXP_LSTAT, and - SSH_FXP_FSTAT requests. - - Exactly one response will be returned for each request. Each - response packet contains a request identifier which can be used to - match each response with the corresponding request. Note that it is - legal to have several requests outstanding simultaneously, and the - server is allowed to send responses to them in a different order from - the order in which the requests were sent (the result of their - execution, however, is guaranteed to be as if they had been processed - one at a time in the order in which the requests were sent). - - Response packets are of the same general format as request packets. - Each response packet begins with the request identifier. - - The format of the data portion of the SSH_FXP_STATUS response is as - follows: - - uint32 id - uint32 error/status code - string error message (ISO-10646 UTF-8 [RFC-2279]) - string language tag (as defined in [RFC-1766]) - - where `id' is the request identifier, and `error/status code' - indicates the result of the requested operation. The value SSH_FX_OK - indicates success, and all other values indicate failure. - - Currently, the following values are defined (other values may be - defined by future versions of this protocol): - - - - - - - - - - -Galbraith, et al. Expires April 16, 2003 [Page 24] - -Internet-Draft SSH File Transfer Protocol October 2002 - - - #define SSH_FX_OK 0 - #define SSH_FX_EOF 1 - #define SSH_FX_NO_SUCH_FILE 2 - #define SSH_FX_PERMISSION_DENIED 3 - #define SSH_FX_FAILURE 4 - #define SSH_FX_BAD_MESSAGE 5 - #define SSH_FX_NO_CONNECTION 6 - #define SSH_FX_CONNECTION_LOST 7 - #define SSH_FX_OP_UNSUPPORTED 8 - #define SSH_FX_INVALID_HANDLE 9 - #define SSH_FX_NO_SUCH_PATH 10 - #define SSH_FX_FILE_ALREADY_EXISTS 11 - #define SSH_FX_WRITE_PROTECT 12 - - SSH_FX_OK - Indicates successful completion of the operation. - - SSH_FX_EOF - indicates end-of-file condition; for SSH_FX_READ it means that no - more data is available in the file, and for SSH_FX_READDIR it - indicates that no more files are contained in the directory. - - SSH_FX_NO_SUCH_FILE - is returned when a reference is made to a file which does not - exist. - - SSH_FX_PERMISSION_DENIED - is returned when the authenticated user does not have sufficient - permissions to perform the operation. - - SSH_FX_FAILURE - is a generic catch-all error message; it should be returned if an - error occurs for which there is no more specific error code - defined. - - SSH_FX_BAD_MESSAGE - may be returned if a badly formatted packet or protocol - incompatibility is detected. - - SSH_FX_NO_CONNECTION - is a pseudo-error which indicates that the client has no - connection to the server (it can only be generated locally by the - client, and MUST NOT be returned by servers). - - SSH_FX_CONNECTION_LOST - is a pseudo-error which indicates that the connection to the - server has been lost (it can only be generated locally by the - client, and MUST NOT be returned by servers). - - - -Galbraith, et al. Expires April 16, 2003 [Page 25] - -Internet-Draft SSH File Transfer Protocol October 2002 - - - SSH_FX_OP_UNSUPPORTED - indicates that an attempt was made to perform an operation which - is not supported for the server (it may be generated locally by - the client if e.g. the version number exchange indicates that a - required feature is not supported by the server, or it may be - returned by the server if the server does not implement an - operation). - - SSH_FX_INVALID_HANDLE - The handle value was invalid. - - SSH_FX_NO_SUCH_PATH - The file path does not exist or is invalid. - - SSH_FX_FILE_ALREADY_EXISTS - The file already exists. - - SSH_FX_WRITE_PROTECT - The file is on read only media, or the media is write protected. - - The SSH_FXP_HANDLE response has the following format: - - uint32 id - string handle - - where `id' is the request identifier, and `handle' is an arbitrary - string that identifies an open file or directory on the server. The - handle is opaque to the client; the client MUST NOT attempt to - interpret or modify it in any way. The length of the handle string - MUST NOT exceed 256 data bytes. - - The SSH_FXP_DATA response has the following format: - - uint32 id - string data - - where `id' is the request identifier, and `data' is an arbitrary byte - string containing the requested data. The data string may be at most - the number of bytes requested in a SSH_FXP_READ request, but may also - be shorter if end of file is reached or if the read is from something - other than a regular file. - - The SSH_FXP_NAME response has the following format: - - - - - - - - -Galbraith, et al. Expires April 16, 2003 [Page 26] - -Internet-Draft SSH File Transfer Protocol October 2002 - - - uint32 id - uint32 count - repeats count times: - string filename [UTF-8] - ATTRS attrs - - where `id' is the request identifier, `count' is the number of names - returned in this response, and the remaining fields repeat `count' - times (so that all three fields are first included for the first - file, then for the second file, etc). In the repeated part, - `filename' is a file name being returned (for SSH_FXP_READDIR, it - will be a relative name within the directory, without any path - components; for SSH_FXP_REALPATH it will be an absolute path name), - and `attrs' is the attributes of the file as described in Section - ``File Attributes''. - - The SSH_FXP_ATTRS response has the following format: - - uint32 id - ATTRS attrs - - where `id' is the request identifier, and `attrs' is the returned - file attributes as described in Section ``File Attributes''. - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Galbraith, et al. Expires April 16, 2003 [Page 27] - -Internet-Draft SSH File Transfer Protocol October 2002 - - -8. Vendor-Specific Extensions - - The SSH_FXP_EXTENDED request provides a generic extension mechanism - for adding vendor-specific commands. The request has the following - format: - - uint32 id - string extended-request - ... any request-specific data ... - - where `id' is the request identifier, and `extended-request' is a - string of the format "name@domain", where domain is an internet - domain name of the vendor defining the request. The rest of the - request is completely vendor-specific, and servers should only - attempt to interpret it if they recognize the `extended-request' - name. - - The server may respond to such requests using any of the response - packets defined in Section ``Responses from the Server to the - Client''. Additionally, the server may also respond with a - SSH_FXP_EXTENDED_REPLY packet, as defined below. If the server does - not recognize the `extended-request' name, then the server MUST - respond with SSH_FXP_STATUS with error/status set to - SSH_FX_OP_UNSUPPORTED. - - The SSH_FXP_EXTENDED_REPLY packet can be used to carry arbitrary - extension-specific data from the server to the client. It is of the - following format: - - uint32 id - ... any request-specific data ... - - There is a range of packet types reserved for use by extensions. In - order to avoid collision, extensions that turn on the use of - additional packet types should determine those numbers dynamically. - - The suggested way of doing this is have an extension request from the - client to the server that enables the extension; the extension - response from the server to the client would specify the actual type - values to use, in additional to any other data. - - Extension authors should be mindful of the limited range of packet - types available (there are only 45 values available) and avoid - requiring a new packet type where possible. - - - - - - - -Galbraith, et al. Expires April 16, 2003 [Page 28] - -Internet-Draft SSH File Transfer Protocol October 2002 - - -9. Security Considerations - - This protocol assumes that it is run over a secure channel and that - the endpoints of the channel have been authenticated. Thus, this - protocol assumes that it is externally protected from network-level - attacks. - - This protocol provides file system access to arbitrary files on the - server (only constrained by the server implementation). It is the - responsibility of the server implementation to enforce any access - controls that may be required to limit the access allowed for any - particular user (the user being authenticated externally to this - protocol, typically using the SSH User Authentication Protocol [8]. - - Care must be taken in the server implementation to check the validity - of received file handle strings. The server should not rely on them - directly; it MUST check the validity of each handle before relying on - it. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Galbraith, et al. Expires April 16, 2003 [Page 29] - -Internet-Draft SSH File Transfer Protocol October 2002 - - -10. Changes from previous protocol versions - - The SSH File Transfer Protocol has changed over time, before it's - standardization. The following is a description of the incompatible - changes between different versions. - -10.1 Changes between versions 4 and 3 - - Many of the changes between version 4 and version 3 are to the - attribute structure to make it more flexible for non-unix platforms. - - o Make all filenames UTF-8. - - o Added 'newline' extension. - - o Made file attribute owner and group strings so they can actually - be used on disparate systems. - - o Added createtime field, and added separate flags for atime, - createtime, and mtime so they can be set separately. - - o Split the file type out of the permissions field and into it's own - field (which is always present.) - - o Added acl attribute. - - o Added SSH_FXF_TEXT file open flag. - - o Added flags field to the get stat commands so that the client can - specifically request information the server might not normally - included for performance reasons. - - o Removed the long filename from the names structure-- it can now be - built from information available in the attrs structure. - - o Added reserved range of packet numbers for extensions. - - o Added several additional error codes. - - o Change the way version negotiate works slightly. Previously, if - the client version were higher than the server version, the server - was supposed to 'echo back' the clients version. The server now - sends it's own version and the lower of the two is considered to - be the one in use. - - - - - - - -Galbraith, et al. Expires April 16, 2003 [Page 30] - -Internet-Draft SSH File Transfer Protocol October 2002 - - -10.2 Changes between versions 3 and 2 - - o The SSH_FXP_READLINK and SSH_FXP_SYMLINK messages were added. - - o The SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY messages were - added. - - o The SSH_FXP_STATUS message was changed to include fields `error - message' and `language tag'. - - -10.3 Changes between versions 2 and 1 - - o The SSH_FXP_RENAME message was added. - - -10.4 Changes between versions 1 and 0 - - o Implementation changes, no actual protocol changes. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Galbraith, et al. Expires April 16, 2003 [Page 31] - -Internet-Draft SSH File Transfer Protocol October 2002 - - -11. Trademark Issues - - "ssh" is a registered trademark of SSH Communications Security Corp - in the United States and/or other countries. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Galbraith, et al. Expires April 16, 2003 [Page 32] - -Internet-Draft SSH File Transfer Protocol October 2002 - - -References - - [1] Dierks, T., Allen, C., Treese, W., Karlton, P., Freier, A. and - P. Kocher, "The TLS Protocol Version 1.0", RFC 2246, January - 1999. - - [2] Alvestrand, H., "IETF Policy on Character Sets and Languages", - BCP 18, RFC 2277, January 1998. - - [3] Shepler, S., Callaghan, B., Robinson, D., Thurlow, R., Beame, - C., Eisler, M. and D. Noveck, "NFS version 4 Protocol", RFC - 3010, December 2000. - - [4] Institute of Electrical and Electronics Engineers, "Information - Technology - Portable Operating System Interface (POSIX) - Part - 1: System Application Program Interface (API) [C Language]", - IEEE Standard 1003.2, 1996. - - [5] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. - Lehtinen, "SSH Protocol Architecture", draft-ietf-secsh- - architecture-13 (work in progress), September 2002. - - [6] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. - Lehtinen, "SSH Protocol Transport Protocol", draft-ietf-secsh- - transport-15 (work in progress), September 2002. - - [7] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. - Lehtinen, "SSH Connection Protocol", draft-ietf-secsh-connect-16 - (work in progress), September 2002. - - [8] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. - Lehtinen, "SSH Authentication Protocol", draft-ietf-secsh- - userauth-16 (work in progress), September 2002. - - -Authors' Addresses - - Joseph Galbraith - VanDyke Software - 4848 Tramway Ridge Blvd - Suite 101 - Albuquerque, NM 87111 - US - - Phone: +1 505 332 5700 - EMail: [email protected] - - - - - -Galbraith, et al. Expires April 16, 2003 [Page 33] - -Internet-Draft SSH File Transfer Protocol October 2002 - - - Tatu Ylonen - SSH Communications Security Corp - Fredrikinkatu 42 - HELSINKI FIN-00100 - Finland - - EMail: [email protected] - - - Sami Lehtinen - SSH Communications Security Corp - Fredrikinkatu 42 - HELSINKI FIN-00100 - Finland - - EMail: [email protected] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Galbraith, et al. Expires April 16, 2003 [Page 34] - -Internet-Draft SSH File Transfer Protocol October 2002 - - -Full Copyright Statement - - Copyright (C) The Internet Society (2002). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - -Galbraith, et al. Expires April 16, 2003 [Page 35] - - diff --git a/lib/ssh/doc/standard/draft-ietf-secsh-filexfer-04.txt b/lib/ssh/doc/standard/draft-ietf-secsh-filexfer-04.txt deleted file mode 100644 index 9f51883cd2..0000000000 --- a/lib/ssh/doc/standard/draft-ietf-secsh-filexfer-04.txt +++ /dev/null @@ -1,2130 +0,0 @@ - - - -Secure Shell Working Group J. Galbraith -Internet-Draft VanDyke Software -Expires: June 18, 2003 T. Ylonen - S. Lehtinen - SSH Communications Security Corp - December 18, 2002 - - - SSH File Transfer Protocol - draft-ietf-secsh-filexfer-04.txt - -Status of this Memo - - This document is an Internet-Draft and is in full conformance with - all provisions of Section 10 of RFC2026. - - Internet-Drafts are working documents of the Internet Engineering - Task Force (IETF), its areas, and its working groups. Note that - other groups may also distribute working documents as - Internet-Drafts. - - Internet-Drafts are draft documents valid for a maximum of six months - and may be updated, replaced, or obsoleted by other documents at any - time. It is inappropriate to use Internet-Drafts as reference - material or to cite them other than as "work in progress." - - The list of current Internet-Drafts can be accessed at http:// - www.ietf.org/ietf/1id-abstracts.txt. - - The list of Internet-Draft Shadow Directories can be accessed at - http://www.ietf.org/shadow.html. - - This Internet-Draft will expire on June 18, 2003. - -Copyright Notice - - Copyright (C) The Internet Society (2002). All Rights Reserved. - -Abstract - - The SSH File Transfer Protocol provides secure file transfer - functionality over any reliable data stream. It is the standard file - transfer protocol for use with the SSH2 protocol. This document - describes the file transfer protocol and its interface to the SSH2 - protocol suite. - - - - - - - -Galbraith, et al. Expires June 18, 2003 [Page 1] - -Internet-Draft SSH File Transfer Protocol December 2002 - - -Table of Contents - - 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . 3 - 2. Use with the SSH Connection Protocol . . . . . . . . . . . 4 - 3. General Packet Format . . . . . . . . . . . . . . . . . . 5 - 3.1 The use of stderr in the server . . . . . . . . . . . . . 6 - 4. Protocol Initialization . . . . . . . . . . . . . . . . . 8 - 4.1 Client Initialization . . . . . . . . . . . . . . . . . . 8 - 4.2 Server Initialization . . . . . . . . . . . . . . . . . . 8 - 4.3 Determining Server Newline Convention . . . . . . . . . . 9 - 5. File Attributes . . . . . . . . . . . . . . . . . . . . . 10 - 5.1 Flags . . . . . . . . . . . . . . . . . . . . . . . . . . 10 - 5.2 Type . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 - 5.3 Size . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 - 5.4 Owner and Group . . . . . . . . . . . . . . . . . . . . . 11 - 5.5 Permissions . . . . . . . . . . . . . . . . . . . . . . . 12 - 5.6 Times . . . . . . . . . . . . . . . . . . . . . . . . . . 12 - 5.7 ACL . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 - 5.8 Extended attributes . . . . . . . . . . . . . . . . . . . 14 - 6. Requests From the Client to the Server . . . . . . . . . . 15 - 6.1 Request Synchronization and Reordering . . . . . . . . . . 15 - 6.2 File Names . . . . . . . . . . . . . . . . . . . . . . . . 16 - 6.3 Opening, Creating, and Closing Files . . . . . . . . . . . 16 - 6.4 Reading and Writing . . . . . . . . . . . . . . . . . . . 19 - 6.5 Removing and Renaming Files . . . . . . . . . . . . . . . 20 - 6.6 Creating and Deleting Directories . . . . . . . . . . . . 21 - 6.7 Scanning Directories . . . . . . . . . . . . . . . . . . . 21 - 6.8 Retrieving File Attributes . . . . . . . . . . . . . . . . 22 - 6.9 Setting File Attributes . . . . . . . . . . . . . . . . . 23 - 6.10 Dealing with Symbolic links . . . . . . . . . . . . . . . 24 - 6.11 Canonicalizing the Server-Side Path Name . . . . . . . . . 25 - 6.11.1 Best practice for dealing with paths . . . . . . . . . . . 25 - 7. Responses from the Server to the Client . . . . . . . . . 26 - 8. Vendor-Specific Extensions . . . . . . . . . . . . . . . . 30 - 9. Security Considerations . . . . . . . . . . . . . . . . . 31 - 10. Changes from previous protocol versions . . . . . . . . . 32 - 10.1 Changes between versions 4 and 3 . . . . . . . . . . . . . 32 - 10.2 Changes between versions 3 and 2 . . . . . . . . . . . . . 33 - 10.3 Changes between versions 2 and 1 . . . . . . . . . . . . . 33 - 10.4 Changes between versions 1 and 0 . . . . . . . . . . . . . 33 - 11. Trademark Issues . . . . . . . . . . . . . . . . . . . . . 34 - References . . . . . . . . . . . . . . . . . . . . . . . . 35 - Authors' Addresses . . . . . . . . . . . . . . . . . . . . 35 - Intellectual Property and Copyright Statements . . . . . . 37 - - - - - - - -Galbraith, et al. Expires June 18, 2003 [Page 2] - -Internet-Draft SSH File Transfer Protocol December 2002 - - -1. Introduction - - This protocol provides secure file transfer (and more generally file - system access) functionality over a reliable data stream, such as a - channel in the SSH2 protocol [5]. - - This protocol is designed so that it could be used to implement a - secure remote file system service, as well as a secure file transfer - service. - - This protocol assumes that it runs over a secure channel, and that - the server has already authenticated the user at the client end, and - that the identity of the client user is externally available to the - server implementation. - - In general, this protocol follows a simple request-response model. - Each request and response contains a sequence number and multiple - requests may be pending simultaneously. There are a relatively large - number of different request messages, but a small number of possible - response messages. Each request has one or more response messages - that may be returned in result (e.g., a read either returns data or - reports error status). - - The packet format descriptions in this specification follow the - notation presented in the secsh architecture draft. [5] - - Even though this protocol is described in the context of the SSH2 - protocol, this protocol is general and independent of the rest of the - SSH2 protocol suite. It could be used in a number of different - applications, such as secure file transfer over TLS RFC 2246 [1] and - transfer of management information in VPN applications. - - - - - - - - - - - - - - - - - - - - -Galbraith, et al. Expires June 18, 2003 [Page 3] - -Internet-Draft SSH File Transfer Protocol December 2002 - - -2. Use with the SSH Connection Protocol - - When used with the SSH2 Protocol suite, this protocol is intended to - be used from the SSH Connection Protocol [7] as a subsystem, as - described in section ``Starting a Shell or a Command''. The - subsystem name used with this protocol is "sftp". - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Galbraith, et al. Expires June 18, 2003 [Page 4] - -Internet-Draft SSH File Transfer Protocol December 2002 - - -3. General Packet Format - - All packets transmitted over the secure connection are of the - following format: - - uint32 length - byte type - byte[length - 1] data payload - - That is, they are just data preceded by 32-bit length and 8-bit type - fields. The `length' is the length of the data area, and does not - include the `length' field itself. The format and interpretation of - the data area depends on the packet type. - - All packet descriptions below only specify the packet type and the - data that goes into the data field. Thus, they should be prefixed by - the `length' and `type' fields. - - The maximum size of a packet is in practice determined by the client - (the maximum size of read or write requests that it sends, plus a few - bytes of packet overhead). All servers SHOULD support packets of at - least 34000 bytes (where the packet size refers to the full length, - including the header above). This should allow for reads and writes - of at most 32768 bytes. - - There is no limit on the number of outstanding (non-acknowledged) - requests that the client may send to the server. In practice this is - limited by the buffering available on the data stream and the queuing - performed by the server. If the server's queues are full, it should - not read any more data from the stream, and flow control will prevent - the client from sending more requests. Note, however, that while - there is no restriction on the protocol level, the client's API may - provide a limit in order to prevent infinite queuing of outgoing - requests at the client. - - The following values are defined for packet types. - - - - - - - - - - - - - - - -Galbraith, et al. Expires June 18, 2003 [Page 5] - -Internet-Draft SSH File Transfer Protocol December 2002 - - - #define SSH_FXP_INIT 1 - #define SSH_FXP_VERSION 2 - #define SSH_FXP_OPEN 3 - #define SSH_FXP_CLOSE 4 - #define SSH_FXP_READ 5 - #define SSH_FXP_WRITE 6 - #define SSH_FXP_LSTAT 7 - #define SSH_FXP_FSTAT 8 - #define SSH_FXP_SETSTAT 9 - #define SSH_FXP_FSETSTAT 10 - #define SSH_FXP_OPENDIR 11 - #define SSH_FXP_READDIR 12 - #define SSH_FXP_REMOVE 13 - #define SSH_FXP_MKDIR 14 - #define SSH_FXP_RMDIR 15 - #define SSH_FXP_REALPATH 16 - #define SSH_FXP_STAT 17 - #define SSH_FXP_RENAME 18 - #define SSH_FXP_READLINK 19 - #define SSH_FXP_SYMLINK 20 - - #define SSH_FXP_STATUS 101 - #define SSH_FXP_HANDLE 102 - #define SSH_FXP_DATA 103 - #define SSH_FXP_NAME 104 - #define SSH_FXP_ATTRS 105 - - #define SSH_FXP_EXTENDED 200 - #define SSH_FXP_EXTENDED_REPLY 201 - - RESERVED_FOR_EXTENSIONS 210-255 - - Additional packet types should only be defined if the protocol - version number (see Section ``Protocol Initialization'') is - incremented, and their use MUST be negotiated using the version - number. However, the SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY - packets can be used to implement vendor-specific extensions. See - Section ``Vendor-Specific-Extensions'' for more details. - -3.1 The use of stderr in the server - - Packets are sent and received on stdout and stdin. Data sent on - stderr by the server SHOULD be considered debug or supplemental error - information, and MAY be displayed to the user. - - For example, during initialization, there is no client request - active, so errors or warning information cannot be sent to the client - as part of the SFTP protocol at this early stage. However, the - - - -Galbraith, et al. Expires June 18, 2003 [Page 6] - -Internet-Draft SSH File Transfer Protocol December 2002 - - - errors or warnings MAY be sent as stderr text. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Galbraith, et al. Expires June 18, 2003 [Page 7] - -Internet-Draft SSH File Transfer Protocol December 2002 - - -4. Protocol Initialization - - When the file transfer protocol starts, the client first sends a - SSH_FXP_INIT (including its version number) packet to the server. - The server responds with a SSH_FXP_VERSION packet, supplying the - lowest of its own and the client's version number. Both parties - should from then on adhere to particular version of the protocol. - - The version number of the protocol specified in this document is 4. - The version number should be incremented for each incompatible - revision of this protocol. - -4.1 Client Initialization - - The SSH_FXP_INIT packet (from client to server) has the following - data: - - uint32 version - - Version 3 of this protocol allowed clients to include extensions in - the SSH_FXP_INIT packet; however, this can cause interoperability - problems with version 1 and version 2 servers because the client must - send this packet before knowing the servers version. - - In this version of the protocol, clients MUST use the - SSH_FXP_EXTENDED packet to send extensions to the server after - version exchange has completed. Clients MUST NOT include extensions - in the version packet. This will prevent interoperability problems - with older servers - -4.2 Server Initialization - - The SSH_FXP_VERSION packet (from server to client) has the following - data: - - uint32 version - <extension data> - - 'version' is the lower of the protocol version supported by the - server and the version number received from the client. - - The extension data may be empty, or may be a sequence of - - string extension_name - string extension_data - - pairs (both strings MUST always be present if one is, but the - `extension_data' string may be of zero length). If present, these - - - -Galbraith, et al. Expires June 18, 2003 [Page 8] - -Internet-Draft SSH File Transfer Protocol December 2002 - - - strings indicate extensions to the baseline protocol. The - `extension_name' field(s) identify the name of the extension. The - name should be of the form "name@domain", where the domain is the DNS - domain name of the organization defining the extension. Additional - names that are not of this format may be defined later by the IETF. - Implementations MUST silently ignore any extensions whose name they - do not recognize. - -4.3 Determining Server Newline Convention - - In order to correctly process text files in a cross platform - compatible way, the newline convention must be converted from that of - the server to that of the client, or, during an upload, from that of - the client to that of the server. - - Versions 3 and prior of this protocol made no provisions for - processing text files. Many clients implemented some sort of - conversion algorithm, but without either a 'canonical' on the wire - format or knowledge of the servers newline convention, correct - conversion was not always possible. - - Starting with Version 4, the SSH_FXF_TEXT file open flag (Section - 6.3) makes it possible to request that the server translate a file to - a 'canonical' on the wire format. This format uses \r\n as the line - separator. - - Servers for systems using multiple newline characters (for example, - Mac OS X or VMS) or systems using counted records, MUST translate to - the canonical form. - - However, to ease the burden of implementation on servers that use a - single, simple separator sequence, the following extension allows the - canonical format to be changed. - - string "newline" - string new-canonical-separator (usually "\r" or "\n" or "\r\n") - - All clients MUST support this extension. - - When processing text files, clients SHOULD NOT translate any - character or sequence that is not an exact match of the servers - newline separator. - - In particular, if the newline sequence being used is the canonical - "\r\n" sequence, a lone \r or a lone \n SHOULD be written through - without change. - - - - - -Galbraith, et al. Expires June 18, 2003 [Page 9] - -Internet-Draft SSH File Transfer Protocol December 2002 - - -5. File Attributes - - A new compound data type is defined for encoding file attributes. - The same encoding is used both when returning file attributes from - the server and when sending file attributes to the server. When - sending it to the server, the flags field specifies which attributes - are included, and the server will use default values for the - remaining attributes (or will not modify the values of remaining - attributes). When receiving attributes from the server, the flags - specify which attributes are included in the returned data. The - server normally returns all attributes it knows about. - - uint32 flags - byte type always present - uint64 size present only if flag SIZE - string owner present only if flag OWNERGROUP - string group present only if flag OWNERGROUP - uint32 permissions present only if flag PERMISSIONS - uint64 atime present only if flag ACCESSTIME - uint32 atime_nseconds present only if flag SUBSECOND_TIMES - uint64 createtime present only if flag CREATETIME - uint32 createtime_nseconds present only if flag SUBSECOND_TIMES - uint64 mtime present only if flag MODIFYTIME - uint32 mtime_nseconds present only if flag SUBSECOND_TIMES - string acl present only if flag ACL - uint32 extended_count present only if flag EXTENDED - string extended_type - string extended_data - ... more extended data (extended_type - extended_data pairs), - so that number of pairs equals extended_count - - -5.1 Flags - - The `flags' specify which of the fields are present. Those fields - for which the corresponding flag is not set are not present (not - included in the packet). New flags can only be added by incrementing - the protocol version number (or by using the extension mechanism - described below). - - The flags bits are defined to have the following values: - - - - - - - - - - -Galbraith, et al. Expires June 18, 2003 [Page 10] - -Internet-Draft SSH File Transfer Protocol December 2002 - - - #define SSH_FILEXFER_ATTR_SIZE 0x00000001 - #define SSH_FILEXFER_ATTR_PERMISSIONS 0x00000040 - #define SSH_FILEXFER_ATTR_ACCESSTIME 0x00000008 - #define SSH_FILEXFER_ATTR_CREATETIME 0x00000010 - #define SSH_FILEXFER_ATTR_MODIFYTIME 0x00000020 - #define SSH_FILEXFER_ATTR_ACL 0x00000040 - #define SSH_FILEXFER_ATTR_OWNERGROUP 0x00000080 - #define SSH_FILEXFER_ATTR_SUBSECOND_TIMES 0x00000100 - #define SSH_FILEXFER_ATTR_EXTENDED 0x80000000 - - In previous versions of this protocol flags value 0x00000002 was - SSH_FILEXFER_ATTR_UIDGID. This value is now unused, and OWNERGROUP - was given a new value in order to ease implementation burden. - 0x00000002 MUST NOT appear in the mask. Some future version of this - protocol may reuse flag 0x00000002. - -5.2 Type - - The type field is always present. The following types are defined: - - #define SSH_FILEXFER_TYPE_REGULAR 1 - #define SSH_FILEXFER_TYPE_DIRECTORY 2 - #define SSH_FILEXFER_TYPE_SYMLINK 3 - #define SSH_FILEXFER_TYPE_SPECIAL 4 - #define SSH_FILEXFER_TYPE_UNKNOWN 5 - - On a POSIX system, these values would be derived from the permission - field. - -5.3 Size - - The `size' field specifies the size of the file on disk, in bytes. - If it is present during file creation, it should be considered a hint - as to the files eventual size. - - Files opened with the SSH_FXF_TEXT flag may have a size that is - greater or less than the value of the size field. - -5.4 Owner and Group - - The `owner' and `group' fields are represented as UTF-8 strings; this - is the form used by NFS v4. See NFS version 4 Protocol. [3] The - following text is selected quotations from section 5.6. - - To avoid a representation that is tied to a particular underlying - implementation at the client or server, the use of UTF-8 strings has - been chosen. The string should be of the form user@dns_domain". - This will allow for a client and server that do not use the same - - - -Galbraith, et al. Expires June 18, 2003 [Page 11] - -Internet-Draft SSH File Transfer Protocol December 2002 - - - local representation the ability to translate to a common syntax that - can be interpreted by both. In the case where there is no - translation available to the client or server, the attribute value - must be constructed without the "@". Therefore, the absence of the @ - from the owner or owner_group attribute signifies that no translation - was available and the receiver of the attribute should not place any - special meaning with the attribute value. Even though the attribute - value can not be translated, it may still be useful. In the case of - a client, the attribute string may be used for local display of - ownership. - -5.5 Permissions - - The `permissions' field contains a bit mask of file permissions as - defined by POSIX [1]. - -5.6 Times - - The 'atime', 'createtime', and 'mtime' contain the access, creation, - and modification times of the files, respectively. They are - represented as seconds from Jan 1, 1970 in UTC. - - A negative value indicates number of seconds before Jan 1, 1970. In - both cases, if the SSH_FILEXFER_ATTR_SUBSECOND_TIMES flag is set, the - nseconds field is to be added to the seconds field for the final time - representation. For example, if the time to be represented is - one-half second before 0 hour January 1, 1970, the seconds field - would have a value of negative one (-1) and the nseconds fields would - have a value of one-half second (500000000). Values greater than - 999,999,999 for nseconds are considered invalid. - -5.7 ACL - - The 'ACL' field contains an ACL similar to that defined in section - 5.9 of NFS version 4 Protocol [3]. - - uint32 ace-count - - repeated ace-count time: - uint32 ace-type - uint32 ace-flag - uint32 ace-mask - string who [UTF-8] - - ace-type is one of the following four values (taken from NFS Version - 4 Protocol [3]: - - - - - -Galbraith, et al. Expires June 18, 2003 [Page 12] - -Internet-Draft SSH File Transfer Protocol December 2002 - - - const ACE4_ACCESS_ALLOWED_ACE_TYPE = 0x00000000; - const ACE4_ACCESS_DENIED_ACE_TYPE = 0x00000001; - const ACE4_SYSTEM_AUDIT_ACE_TYPE = 0x00000002; - const ACE4_SYSTEM_ALARM_ACE_TYPE = 0x00000003; - - ace-flag is a combination of the following flag values. See NFS - Version 4 Protocol [3] section 5.9.2: - - const ACE4_FILE_INHERIT_ACE = 0x00000001; - const ACE4_DIRECTORY_INHERIT_ACE = 0x00000002; - const ACE4_NO_PROPAGATE_INHERIT_ACE = 0x00000004; - const ACE4_INHERIT_ONLY_ACE = 0x00000008; - const ACE4_SUCCESSFUL_ACCESS_ACE_FLAG = 0x00000010; - const ACE4_FAILED_ACCESS_ACE_FLAG = 0x00000020; - const ACE4_IDENTIFIER_GROUP = 0x00000040; - - ace-mask is any combination of the following flags (taken from NFS - Version 4 Protocol [3] section 5.9.3: - - const ACE4_READ_DATA = 0x00000001; - const ACE4_LIST_DIRECTORY = 0x00000001; - const ACE4_WRITE_DATA = 0x00000002; - const ACE4_ADD_FILE = 0x00000002; - const ACE4_APPEND_DATA = 0x00000004; - const ACE4_ADD_SUBDIRECTORY = 0x00000004; - const ACE4_READ_NAMED_ATTRS = 0x00000008; - const ACE4_WRITE_NAMED_ATTRS = 0x00000010; - const ACE4_EXECUTE = 0x00000020; - const ACE4_DELETE_CHILD = 0x00000040; - const ACE4_READ_ATTRIBUTES = 0x00000080; - const ACE4_WRITE_ATTRIBUTES = 0x00000100; - const ACE4_DELETE = 0x00010000; - const ACE4_READ_ACL = 0x00020000; - const ACE4_WRITE_ACL = 0x00040000; - const ACE4_WRITE_OWNER = 0x00080000; - const ACE4_SYNCHRONIZE = 0x00100000; - - who is a UTF-8 string of the form described in 'Owner and Group' - (Section 5.4) - - Also, as per '5.9.4 ACE who' [3] there are several identifiers that - need to be understood universally. Some of these identifiers cannot - be understood when an client access the server, but have meaning when - a local process accesses the file. The ability to display and modify - these permissions is permitted over SFTP. - - OWNER The owner of the file. - - - - -Galbraith, et al. Expires June 18, 2003 [Page 13] - -Internet-Draft SSH File Transfer Protocol December 2002 - - - GROUP The group associated with the file. - - EVERYONE The world. - - INTERACTIVE Accessed from an interactive terminal. - - NETWORK Accessed via the network. - - DIALUP Accessed as a dialup user to the server. - - BATCH Accessed from a batch job. - - ANONYMOUS Accessed without any authentication. - - AUTHENTICATED Any authenticated user (opposite of ANONYMOUS). - - SERVICE Access from a system service. - - To avoid conflict, these special identifiers are distinguish by an - appended "@" and should appear in the form "xxxx@" (note: no domain - name after the "@"). For example: ANONYMOUS@. - -5.8 Extended attributes - - The SSH_FILEXFER_ATTR_EXTENDED flag provides a general extension - mechanism for vendor-specific extensions. If the flag is specified, - then the `extended_count' field is present. It specifies the number - of extended_type-extended_data pairs that follow. Each of these - pairs specifies an extended attribute. For each of the attributes, - the extended_type field should be a string of the format - "name@domain", where "domain" is a valid, registered domain name and - "name" identifies the method. The IETF may later standardize certain - names that deviate from this format (e.g., that do not contain the - "@" sign). The interpretation of `extended_data' depends on the - type. Implementations SHOULD ignore extended data fields that they - do not understand. - - Additional fields can be added to the attributes by either defining - additional bits to the flags field to indicate their presence, or by - defining extended attributes for them. The extended attributes - mechanism is recommended for most purposes; additional flags bits - should only be defined by an IETF standards action that also - increments the protocol version number. The use of such new fields - MUST be negotiated by the version number in the protocol exchange. - It is a protocol error if a packet with unsupported protocol bits is - received. - - - - - -Galbraith, et al. Expires June 18, 2003 [Page 14] - -Internet-Draft SSH File Transfer Protocol December 2002 - - -6. Requests From the Client to the Server - - Requests from the client to the server represent the various file - system operations. Each request begins with an `id' field, which is - a 32-bit identifier identifying the request (selected by the client). - The same identifier will be returned in the response to the request. - One possible implementation is a monotonically increasing request - sequence number (modulo 2^32). - - Many operations in the protocol operate on open files. The - SSH_FXP_OPEN request can return a file handle (which is an opaque - variable-length string) which may be used to access the file later - (e.g. in a read operation). The client MUST NOT send requests the - server with bogus or closed handles. However, the server MUST - perform adequate checks on the handle in order to avoid security - risks due to fabricated handles. - - This design allows either stateful and stateless server - implementation, as well as an implementation which caches state - between requests but may also flush it. The contents of the file - handle string are entirely up to the server and its design. The - client should not modify or attempt to interpret the file handle - strings. - - The file handle strings MUST NOT be longer than 256 bytes. - -6.1 Request Synchronization and Reordering - - The protocol and implementations MUST process requests relating to - the same file in the order in which they are received. In other - words, if an application submits multiple requests to the server, the - results in the responses will be the same as if it had sent the - requests one at a time and waited for the response in each case. For - example, the server may process non-overlapping read/write requests - to the same file in parallel, but overlapping reads and writes cannot - be reordered or parallelized. However, there are no ordering - restrictions on the server for processing requests from two different - file transfer connections. The server may interleave and parallelize - them at will. - - There are no restrictions on the order in which responses to - outstanding requests are delivered to the client, except that the - server must ensure fairness in the sense that processing of no - request will be indefinitely delayed even if the client is sending - other requests so that there are multiple outstanding requests all - the time. - - - - - -Galbraith, et al. Expires June 18, 2003 [Page 15] - -Internet-Draft SSH File Transfer Protocol December 2002 - - -6.2 File Names - - This protocol represents file names as strings. File names are - assumed to use the slash ('/') character as a directory separator. - - File names starting with a slash are "absolute", and are relative to - the root of the file system. Names starting with any other character - are relative to the user's default directory (home directory). Note - that identifying the user is assumed to take place outside of this - protocol. - - Servers SHOULD interpret a path name component ".." as referring to - the parent directory, and "." as referring to the current directory. - If the server implementation limits access to certain parts of the - file system, it must be extra careful in parsing file names when - enforcing such restrictions. There have been numerous reported - security bugs where a ".." in a path name has allowed access outside - the intended area. - - An empty path name is valid, and it refers to the user's default - directory (usually the user's home directory). - - Otherwise, no syntax is defined for file names by this specification. - Clients should not make any other assumptions; however, they can - splice path name components returned by SSH_FXP_READDIR together - using a slash ('/') as the separator, and that will work as expected. - - In order to comply with IETF Policy on Character Sets and Languages - [2], all filenames are to be encoded in UTF-8. The shortest valid - UTF-8 encoding of the UNICODE data MUST be used. The server is - responsible for converting the UNICODE data to whatever canonical - form it requires. - - For example, if the server requires that precomposed characters - always be used, the server MUST NOT assume the filename as sent by - the client has this attribute, but must do this normalization itself. - - It is understood that the lack of well-defined semantics for file - names may cause interoperability problems between clients and servers - using radically different operating systems. However, this approach - is known to work acceptably with most systems, and alternative - approaches that e.g. treat file names as sequences of structured - components are quite complicated. - -6.3 Opening, Creating, and Closing Files - - Files are opened and created using the SSH_FXP_OPEN message, whose - data part is as follows: - - - -Galbraith, et al. Expires June 18, 2003 [Page 16] - -Internet-Draft SSH File Transfer Protocol December 2002 - - - uint32 id - string filename [UTF-8] - uint32 pflags - ATTRS attrs - - The `id' field is the request identifier as for all requests. - - The `filename' field specifies the file name. See Section ``File - Names'' for more information. - - The `pflags' field is a bitmask. The following bits have been - defined. - - #define SSH_FXF_READ 0x00000001 - #define SSH_FXF_WRITE 0x00000002 - #define SSH_FXF_APPEND 0x00000004 - #define SSH_FXF_CREAT 0x00000008 - #define SSH_FXF_TRUNC 0x00000010 - #define SSH_FXF_EXCL 0x00000020 - #define SSH_FXF_TEXT 0x00000040 - - These have the following meanings: - - SSH_FXF_READ - Open the file for reading. - - SSH_FXF_WRITE - Open the file for writing. If both this and SSH_FXF_READ are - specified, the file is opened for both reading and writing. - - SSH_FXF_APPEND - Force all writes to append data at the end of the file. The - offset parameter to write will be ignored. - - SSH_FXF_CREAT - If this flag is specified, then a new file will be created if one - does not already exist (if O_TRUNC is specified, the new file will - be truncated to zero length if it previously exists). - - SSH_FXF_TRUNC - Forces an existing file with the same name to be truncated to zero - length when creating a file by specifying SSH_FXF_CREAT. - SSH_FXF_CREAT MUST also be specified if this flag is used. - - SSH_FXF_EXCL - Causes the request to fail if the named file already exists. - SSH_FXF_CREAT MUST also be specified if this flag is used. - - - - -Galbraith, et al. Expires June 18, 2003 [Page 17] - -Internet-Draft SSH File Transfer Protocol December 2002 - - - SSH_FXF_TEXT - Indicates that the server should treat the file as text and - convert it to the canonical newline convention in use. (See - Determining Server Newline Convention. (Section 4.3) - - When a file is opened with the FXF_TEXT flag, the offset field in - both the read and write function are ignored. - - Servers MUST correctly process multiple parallel reads and writes - correctly in this mode. Naturally, it is permissible for them to - do this by serializing the requests. It would not be possible for - a client to reliably detect a server that does not implement - parallel writes in time to prevent damage. - - Clients SHOULD use the SSH_FXF_APPEND flag to append data to a - text file rather then using write with a calculated offset. - - To support seeks on text file the following SSH_FXP_EXTENDED - packet is defined. - - - - string "text-seek" - string file-handle - uint64 line-number - - line-number is the index of the line number to seek to, where byte - 0 in the file is line number 0, and the byte directly following - the first newline sequence in the file is line number 1 and so on. - - The response to a "text-seek" request is an SSH_FXP_STATUS - message. - - An attempt to seek past the end-of-file should result in a - SSH_FX_EOF status. - - Servers SHOULD support at least one "text-seek" in order to - support resume. However, a client MUST be prepared to receive - SSH_FX_OP_UNSUPPORTED when attempting a "text-seek" operation. - The client can then try a fall-back strategy, if it has one. - - Clients MUST be prepared to handle SSH_FX_OP_UNSUPPORTED returned - for read or write operations that are not sequential. - - The `attrs' field specifies the initial attributes for the file. - Default values will be used for those attributes that are not - specified. See Section ``File Attributes'' for more information. - - - - -Galbraith, et al. Expires June 18, 2003 [Page 18] - -Internet-Draft SSH File Transfer Protocol December 2002 - - - The response to this message will be either SSH_FXP_HANDLE (if the - operation is successful) or SSH_FXP_STATUS (if the operation fails). - - A file is closed by using the SSH_FXP_CLOSE request. Its data field - has the following format: - - uint32 id - string handle - - where `id' is the request identifier, and `handle' is a handle - previously returned in the response to SSH_FXP_OPEN or - SSH_FXP_OPENDIR. The handle becomes invalid immediately after this - request has been sent. - - The response to this request will be a SSH_FXP_STATUS message. One - should note that on some server platforms even a close can fail. - This can happen e.g. if the server operating system caches writes, - and an error occurs while flushing cached writes during the close. - -6.4 Reading and Writing - - Once a file has been opened, it can be read using the following - message: - - byte SSH_FXP_READ - uint32 id - string handle - uint64 offset - uint32 len - - where `id' is the request identifier, `handle' is an open file handle - returned by SSH_FXP_OPEN, `offset' is the offset (in bytes) relative - to the beginning of the file from where to start reading, and `len' - is the maximum number of bytes to read. - - In response to this request, the server will read as many bytes as it - can from the file (up to `len'), and return them in a SSH_FXP_DATA - message. If an error occurs or EOF is encountered before reading any - data, the server will respond with SSH_FXP_STATUS. - - For normal disk files, it is normally guaranteed that this will read - the specified number of bytes, or up to end of file. However, if the - read length is very long, the server may truncate it if it doesn't - support packets of that length. See General Packet Format (Section - 3). - - For e.g. device files this may return fewer bytes than requested. - - - - -Galbraith, et al. Expires June 18, 2003 [Page 19] - -Internet-Draft SSH File Transfer Protocol December 2002 - - - Writing to a file is achieved using the following message: - - byte SSH_FXP_WRITE - uint32 id - string handle - uint64 offset - string data - - where `id' is a request identifier, `handle' is a file handle - returned by SSH_FXP_OPEN, `offset' is the offset (in bytes) from the - beginning of the file where to start writing, and `data' is the data - to be written. - - The write will extend the file if writing beyond the end of the file. - It is legal to write way beyond the end of the file; the semantics - are to write zeroes from the end of the file to the specified offset - and then the data. On most operating systems, such writes do not - allocate disk space but instead leave "holes" in the file. - - The server responds to a write request with a SSH_FXP_STATUS message. - -6.5 Removing and Renaming Files - - Files can be removed using the SSH_FXP_REMOVE message. It has the - following format: - - uint32 id - string filename [UTF-8] - - where `id' is the request identifier and `filename' is the name of - the file to be removed. See Section ``File Names'' for more - information. This request cannot be used to remove directories. - - The server will respond to this request with a SSH_FXP_STATUS - message. - - Files (and directories) can be renamed using the SSH_FXP_RENAME - message. Its data is as follows: - - uint32 id - string oldpath [UTF-8] - string newpath [UTF-8] - - where `id' is the request identifier, `oldpath' is the name of an - existing file or directory, and `newpath' is the new name for the - file or directory. It is an error if there already exists a file - with the name specified by newpath. The server may also fail rename - requests in other situations, for example if `oldpath' and `newpath' - - - -Galbraith, et al. Expires June 18, 2003 [Page 20] - -Internet-Draft SSH File Transfer Protocol December 2002 - - - point to different file systems on the server. - - The server will respond to this request with a SSH_FXP_STATUS - message. - -6.6 Creating and Deleting Directories - - New directories can be created using the SSH_FXP_MKDIR request. It - has the following format: - - uint32 id - string path [UTF-8] - ATTRS attrs - - where `id' is the request identifier. - - `path' specifies the directory to be created. See Section ``File - Names'' for more information on file names. - - `attrs' specifies the attributes that should be applied to it upon - creation. Attributes are discussed in more detail in Section ``File - Attributes''. - - The server will respond to this request with a SSH_FXP_STATUS - message. If a file or directory with the specified path already - exists, an error will be returned. - - Directories can be removed using the SSH_FXP_RMDIR request, which has - the following format: - - uint32 id - string path [UTF-8] - - where `id' is the request identifier, and `path' specifies the - directory to be removed. See Section ``File Names'' for more - information on file names. - - The server responds to this request with a SSH_FXP_STATUS message. - Errors may be returned from this operation for various reasons, - including, but not limited to, the path does not exist, the path does - not refer to a directory object, the directory is not empty, or the - user has insufficient access or permission to perform the requested - operation. - -6.7 Scanning Directories - - The files in a directory can be listed using the SSH_FXP_OPENDIR and - SSH_FXP_READDIR requests. Each SSH_FXP_READDIR request returns one - - - -Galbraith, et al. Expires June 18, 2003 [Page 21] - -Internet-Draft SSH File Transfer Protocol December 2002 - - - or more file names with full file attributes for each file. The - client should call SSH_FXP_READDIR repeatedly until it has found the - file it is looking for or until the server responds with a - SSH_FXP_STATUS message indicating an error (normally SSH_FX_EOF if - there are no more files in the directory). The client should then - close the handle using the SSH_FXP_CLOSE request. - - The SSH_FXP_OPENDIR opens a directory for reading. It has the - following format: - - uint32 id - string path [UTF-8] - - where `id' is the request identifier and `path' is the path name of - the directory to be listed (without any trailing slash). See Section - ``File Names'' for more information on file names. This will return - an error if the path does not specify a directory or if the directory - is not readable. The server will respond to this request with either - a SSH_FXP_HANDLE or a SSH_FXP_STATUS message. - - Once the directory has been successfully opened, files (and - directories) contained in it can be listed using SSH_FXP_READDIR - requests. These are of the format - - uint32 id - string handle - - where `id' is the request identifier, and `handle' is a handle - returned by SSH_FXP_OPENDIR. (It is a protocol error to attempt to - use an ordinary file handle returned by SSH_FXP_OPEN.) - - The server responds to this request with either a SSH_FXP_NAME or a - SSH_FXP_STATUS message. One or more names may be returned at a time. - Full status information is returned for each name in order to speed - up typical directory listings. - - If there are no more names available to be read, the server MUST - respond with a SSH_FXP_STATUS message with error code of SSH_FX_EOF. - - When the client no longer wishes to read more names from the - directory, it SHOULD call SSH_FXP_CLOSE for the handle. The handle - should be closed regardless of whether an error has occurred or not. - -6.8 Retrieving File Attributes - - Very often, file attributes are automatically returned by - SSH_FXP_READDIR. However, sometimes there is need to specifically - retrieve the attributes for a named file. This can be done using the - - - -Galbraith, et al. Expires June 18, 2003 [Page 22] - -Internet-Draft SSH File Transfer Protocol December 2002 - - - SSH_FXP_STAT, SSH_FXP_LSTAT and SSH_FXP_FSTAT requests. - - SSH_FXP_STAT and SSH_FXP_LSTAT only differ in that SSH_FXP_STAT - follows symbolic links on the server, whereas SSH_FXP_LSTAT does not - follow symbolic links. Both have the same format: - - uint32 id - string path [UTF-8] - uint32 flags - - where `id' is the request identifier, and `path' specifies the file - system object for which status is to be returned. The server - responds to this request with either SSH_FXP_ATTRS or SSH_FXP_STATUS. - - The flags field specify the attribute flags in which the client has - particular interest. This is a hint to the server. For example, - because retrieving owner / group and acl information can be an - expensive operation under some operating systems, the server may - choose not to retrieve this information unless the client expresses a - specific interest in it. - - The client has no guarantee the server will provide all the fields - that it has expressed an interest in. - - SSH_FXP_FSTAT differs from the others in that it returns status - information for an open file (identified by the file handle). Its - format is as follows: - - uint32 id - string handle - uint32 flags - - where `id' is the request identifier and `handle' is a file handle - returned by SSH_FXP_OPEN. The server responds to this request with - SSH_FXP_ATTRS or SSH_FXP_STATUS. - -6.9 Setting File Attributes - - File attributes may be modified using the SSH_FXP_SETSTAT and - SSH_FXP_FSETSTAT requests. These requests are used for operations - such as changing the ownership, permissions or access times, as well - as for truncating a file. - - The SSH_FXP_SETSTAT request is of the following format: - - - - - - - -Galbraith, et al. Expires June 18, 2003 [Page 23] - -Internet-Draft SSH File Transfer Protocol December 2002 - - - uint32 id - string path [UTF-8] - ATTRS attrs - - where `id' is the request identifier, `path' specifies the file - system object (e.g. file or directory) whose attributes are to be - modified, and `attrs' specifies the modifications to be made to its - attributes. Attributes are discussed in more detail in Section - ``File Attributes''. - - An error will be returned if the specified file system object does - not exist or the user does not have sufficient rights to modify the - specified attributes. The server responds to this request with a - SSH_FXP_STATUS message. - - The SSH_FXP_FSETSTAT request modifies the attributes of a file which - is already open. It has the following format: - - uint32 id - string handle - ATTRS attrs - - where `id' is the request identifier, `handle' (MUST be returned by - SSH_FXP_OPEN) identifies the file whose attributes are to be - modified, and `attrs' specifies the modifications to be made to its - attributes. Attributes are discussed in more detail in Section - ``File Attributes''. The server will respond to this request with - SSH_FXP_STATUS. - -6.10 Dealing with Symbolic links - - The SSH_FXP_READLINK request may be used to read the target of a - symbolic link. It would have a data part as follows: - - uint32 id - string path [UTF-8] - - where `id' is the request identifier and `path' specifies the path - name of the symlink to be read. - - The server will respond with a SSH_FXP_NAME packet containing only - one name and a dummy attributes value. The name in the returned - packet contains the target of the link. If an error occurs, the - server may respond with SSH_FXP_STATUS. - - The SSH_FXP_SYMLINK request will create a symbolic link on the - server. It is of the following format - - - - -Galbraith, et al. Expires June 18, 2003 [Page 24] - -Internet-Draft SSH File Transfer Protocol December 2002 - - - uint32 id - string linkpath [UTF-8] - string targetpath [UTF-8] - - where `id' is the request identifier, `linkpath' specifies the path - name of the symlink to be created and `targetpath' specifies the - target of the symlink. The server shall respond with a - SSH_FXP_STATUS indicating either success (SSH_FX_OK) or an error - condition. - -6.11 Canonicalizing the Server-Side Path Name - - The SSH_FXP_REALPATH request can be used to have the server - canonicalize any given path name to an absolute path. This is useful - for converting path names containing ".." components or relative - pathnames without a leading slash into absolute paths. The format of - the request is as follows: - - uint32 id - string path [UTF-8] - - where `id' is the request identifier and `path' specifies the path - name to be canonicalized. The server will respond with a - SSH_FXP_NAME packet containing the name in canonical form and a dummy - attributes value. If an error occurs, the server may also respond - with SSH_FXP_STATUS. - -6.11.1 Best practice for dealing with paths - - The client SHOULD treat the results of SSH_FXP_REALPATH as a - canonical absolute path, even if the path does not appear to be - absolute. A client that use REALPATH(".") and treats the result as - absolute, even if there is no leading slash, will continue to - function correctly, even when talking to a Windows NT or VMS style - system, where absolute paths may not begin with a slash. - - For example, if the client wishes to change directory up, and the - server has returned "c:/x/y/z" from REALPATH, the client SHOULD use - "c:/x/y/z/..". - - As a second example, if the client wishes to open the file "x.txt" in - the current directory, and server has returned "dka100:/x/y/z" as the - canonical path of the directory, the client SHOULD open "dka100:/x/y/ - z/x.txt" - - - - - - - -Galbraith, et al. Expires June 18, 2003 [Page 25] - -Internet-Draft SSH File Transfer Protocol December 2002 - - -7. Responses from the Server to the Client - - The server responds to the client using one of a few response - packets. All requests can return a SSH_FXP_STATUS response upon - failure. When the operation is successful, any of the responses may - be returned (depending on the operation). If no data needs to be - returned to the client, the SSH_FXP_STATUS response with SSH_FX_OK - status is appropriate. Otherwise, the SSH_FXP_HANDLE message is used - to return a file handle (for SSH_FXP_OPEN and SSH_FXP_OPENDIR - requests), SSH_FXP_DATA is used to return data from SSH_FXP_READ, - SSH_FXP_NAME is used to return one or more file names from a - SSH_FXP_READDIR or SSH_FXP_REALPATH request, and SSH_FXP_ATTRS is - used to return file attributes from SSH_FXP_STAT, SSH_FXP_LSTAT, and - SSH_FXP_FSTAT requests. - - Exactly one response will be returned for each request. Each - response packet contains a request identifier which can be used to - match each response with the corresponding request. Note that it is - legal to have several requests outstanding simultaneously, and the - server is allowed to send responses to them in a different order from - the order in which the requests were sent (the result of their - execution, however, is guaranteed to be as if they had been processed - one at a time in the order in which the requests were sent). - - Response packets are of the same general format as request packets. - Each response packet begins with the request identifier. - - The format of the data portion of the SSH_FXP_STATUS response is as - follows: - - uint32 id - uint32 error/status code - string error message (ISO-10646 UTF-8 [RFC-2279]) - string language tag (as defined in [RFC-1766]) - - where `id' is the request identifier, and `error/status code' - indicates the result of the requested operation. The value SSH_FX_OK - indicates success, and all other values indicate failure. - - Currently, the following values are defined (other values may be - defined by future versions of this protocol): - - - - - - - - - - -Galbraith, et al. Expires June 18, 2003 [Page 26] - -Internet-Draft SSH File Transfer Protocol December 2002 - - - #define SSH_FX_OK 0 - #define SSH_FX_EOF 1 - #define SSH_FX_NO_SUCH_FILE 2 - #define SSH_FX_PERMISSION_DENIED 3 - #define SSH_FX_FAILURE 4 - #define SSH_FX_BAD_MESSAGE 5 - #define SSH_FX_NO_CONNECTION 6 - #define SSH_FX_CONNECTION_LOST 7 - #define SSH_FX_OP_UNSUPPORTED 8 - #define SSH_FX_INVALID_HANDLE 9 - #define SSH_FX_NO_SUCH_PATH 10 - #define SSH_FX_FILE_ALREADY_EXISTS 11 - #define SSH_FX_WRITE_PROTECT 12 - #define SSH_FX_NO_MEDIA 13 - - SSH_FX_OK - Indicates successful completion of the operation. - - SSH_FX_EOF - indicates end-of-file condition; for SSH_FX_READ it means that no - more data is available in the file, and for SSH_FX_READDIR it - indicates that no more files are contained in the directory. - - SSH_FX_NO_SUCH_FILE - is returned when a reference is made to a file which does not - exist. - - SSH_FX_PERMISSION_DENIED - is returned when the authenticated user does not have sufficient - permissions to perform the operation. - - SSH_FX_FAILURE - is a generic catch-all error message; it should be returned if an - error occurs for which there is no more specific error code - defined. - - SSH_FX_BAD_MESSAGE - may be returned if a badly formatted packet or protocol - incompatibility is detected. - - SSH_FX_NO_CONNECTION - is a pseudo-error which indicates that the client has no - connection to the server (it can only be generated locally by the - client, and MUST NOT be returned by servers). - - SSH_FX_CONNECTION_LOST - is a pseudo-error which indicates that the connection to the - server has been lost (it can only be generated locally by the - - - -Galbraith, et al. Expires June 18, 2003 [Page 27] - -Internet-Draft SSH File Transfer Protocol December 2002 - - - client, and MUST NOT be returned by servers). - - SSH_FX_OP_UNSUPPORTED - indicates that an attempt was made to perform an operation which - is not supported for the server (it may be generated locally by - the client if e.g. the version number exchange indicates that a - required feature is not supported by the server, or it may be - returned by the server if the server does not implement an - operation). - - SSH_FX_INVALID_HANDLE - The handle value was invalid. - - SSH_FX_NO_SUCH_PATH - The file path does not exist or is invalid. - - SSH_FX_FILE_ALREADY_EXISTS - The file already exists. - - SSH_FX_WRITE_PROTECT - The file is on read only media, or the media is write protected. - - SSH_FX_NO_MEDIA - The requested operation can not be completed because there is no - media available in the drive. - - The SSH_FXP_HANDLE response has the following format: - - uint32 id - string handle - - where `id' is the request identifier, and `handle' is an arbitrary - string that identifies an open file or directory on the server. The - handle is opaque to the client; the client MUST NOT attempt to - interpret or modify it in any way. The length of the handle string - MUST NOT exceed 256 data bytes. - - The SSH_FXP_DATA response has the following format: - - uint32 id - string data - - where `id' is the request identifier, and `data' is an arbitrary byte - string containing the requested data. The data string may be at most - the number of bytes requested in a SSH_FXP_READ request, but may also - be shorter if end of file is reached or if the read is from something - other than a regular file. - - - - -Galbraith, et al. Expires June 18, 2003 [Page 28] - -Internet-Draft SSH File Transfer Protocol December 2002 - - - The SSH_FXP_NAME response has the following format: - - uint32 id - uint32 count - repeats count times: - string filename [UTF-8] - ATTRS attrs - - where `id' is the request identifier, `count' is the number of names - returned in this response, and the remaining fields repeat `count' - times (so that all three fields are first included for the first - file, then for the second file, etc). In the repeated part, - `filename' is a file name being returned (for SSH_FXP_READDIR, it - will be a relative name within the directory, without any path - components; for SSH_FXP_REALPATH it will be an absolute path name), - and `attrs' is the attributes of the file as described in Section - ``File Attributes''. - - The SSH_FXP_ATTRS response has the following format: - - uint32 id - ATTRS attrs - - where `id' is the request identifier, and `attrs' is the returned - file attributes as described in Section ``File Attributes''. - - - - - - - - - - - - - - - - - - - - - - - - - - -Galbraith, et al. Expires June 18, 2003 [Page 29] - -Internet-Draft SSH File Transfer Protocol December 2002 - - -8. Vendor-Specific Extensions - - The SSH_FXP_EXTENDED request provides a generic extension mechanism - for adding vendor-specific commands. The request has the following - format: - - uint32 id - string extended-request - ... any request-specific data ... - - where `id' is the request identifier, and `extended-request' is a - string of the format "name@domain", where domain is an internet - domain name of the vendor defining the request. The rest of the - request is completely vendor-specific, and servers should only - attempt to interpret it if they recognize the `extended-request' - name. - - The server may respond to such requests using any of the response - packets defined in Section ``Responses from the Server to the - Client''. Additionally, the server may also respond with a - SSH_FXP_EXTENDED_REPLY packet, as defined below. If the server does - not recognize the `extended-request' name, then the server MUST - respond with SSH_FXP_STATUS with error/status set to - SSH_FX_OP_UNSUPPORTED. - - The SSH_FXP_EXTENDED_REPLY packet can be used to carry arbitrary - extension-specific data from the server to the client. It is of the - following format: - - uint32 id - ... any request-specific data ... - - There is a range of packet types reserved for use by extensions. In - order to avoid collision, extensions that turn on the use of - additional packet types should determine those numbers dynamically. - - The suggested way of doing this is have an extension request from the - client to the server that enables the extension; the extension - response from the server to the client would specify the actual type - values to use, in additional to any other data. - - Extension authors should be mindful of the limited range of packet - types available (there are only 45 values available) and avoid - requiring a new packet type where possible. - - - - - - - -Galbraith, et al. Expires June 18, 2003 [Page 30] - -Internet-Draft SSH File Transfer Protocol December 2002 - - -9. Security Considerations - - This protocol assumes that it is run over a secure channel and that - the endpoints of the channel have been authenticated. Thus, this - protocol assumes that it is externally protected from network-level - attacks. - - This protocol provides file system access to arbitrary files on the - server (only constrained by the server implementation). It is the - responsibility of the server implementation to enforce any access - controls that may be required to limit the access allowed for any - particular user (the user being authenticated externally to this - protocol, typically using the SSH User Authentication Protocol [8]. - - Care must be taken in the server implementation to check the validity - of received file handle strings. The server should not rely on them - directly; it MUST check the validity of each handle before relying on - it. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Galbraith, et al. Expires June 18, 2003 [Page 31] - -Internet-Draft SSH File Transfer Protocol December 2002 - - -10. Changes from previous protocol versions - - The SSH File Transfer Protocol has changed over time, before it's - standardization. The following is a description of the incompatible - changes between different versions. - -10.1 Changes between versions 4 and 3 - - Many of the changes between version 4 and version 3 are to the - attribute structure to make it more flexible for non-unix platforms. - - o Clarify the use of stderr by the server. - - o Clarify handling of very large read requests by the server. - - o Make all filenames UTF-8. - - o Added 'newline' extension. - - o Made time fields 64 bit, and optionally have nanosecond resultion. - - o Made file attribute owner and group strings so they can actually - be used on disparate systems. - - o Added createtime field, and added separate flags for atime, - createtime, and mtime so they can be set separately. - - o Split the file type out of the permissions field and into it's own - field (which is always present.) - - o Added acl attribute. - - o Added SSH_FXF_TEXT file open flag. - - o Added flags field to the get stat commands so that the client can - specifically request information the server might not normally - included for performance reasons. - - o Removed the long filename from the names structure-- it can now be - built from information available in the attrs structure. - - o Added reserved range of packet numbers for extensions. - - o Added several additional error codes. - - - - - - - -Galbraith, et al. Expires June 18, 2003 [Page 32] - -Internet-Draft SSH File Transfer Protocol December 2002 - - -10.2 Changes between versions 3 and 2 - - o The SSH_FXP_READLINK and SSH_FXP_SYMLINK messages were added. - - o The SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY messages were - added. - - o The SSH_FXP_STATUS message was changed to include fields `error - message' and `language tag'. - - -10.3 Changes between versions 2 and 1 - - o The SSH_FXP_RENAME message was added. - - -10.4 Changes between versions 1 and 0 - - o Implementation changes, no actual protocol changes. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Galbraith, et al. Expires June 18, 2003 [Page 33] - -Internet-Draft SSH File Transfer Protocol December 2002 - - -11. Trademark Issues - - "ssh" is a registered trademark of SSH Communications Security Corp - in the United States and/or other countries. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Galbraith, et al. Expires June 18, 2003 [Page 34] - -Internet-Draft SSH File Transfer Protocol December 2002 - - -References - - [1] Dierks, T., Allen, C., Treese, W., Karlton, P., Freier, A. and - P. Kocher, "The TLS Protocol Version 1.0", RFC 2246, January - 1999. - - [2] Alvestrand, H., "IETF Policy on Character Sets and Languages", - BCP 18, RFC 2277, January 1998. - - [3] Shepler, S., Callaghan, B., Robinson, D., Thurlow, R., Beame, - C., Eisler, M. and D. Noveck, "NFS version 4 Protocol", RFC - 3010, December 2000. - - [4] Institute of Electrical and Electronics Engineers, "Information - Technology - Portable Operating System Interface (POSIX) - Part - 1: System Application Program Interface (API) [C Language]", - IEEE Standard 1003.2, 1996. - - [5] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. - Lehtinen, "SSH Protocol Architecture", - draft-ietf-secsh-architecture-13 (work in progress), September - 2002. - - [6] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. - Lehtinen, "SSH Protocol Transport Protocol", - draft-ietf-secsh-transport-15 (work in progress), September - 2002. - - [7] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. - Lehtinen, "SSH Connection Protocol", draft-ietf-secsh-connect-16 - (work in progress), September 2002. - - [8] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. - Lehtinen, "SSH Authentication Protocol", - draft-ietf-secsh-userauth-16 (work in progress), September 2002. - - -Authors' Addresses - - Joseph Galbraith - VanDyke Software - 4848 Tramway Ridge Blvd - Suite 101 - Albuquerque, NM 87111 - US - - Phone: +1 505 332 5700 - EMail: [email protected] - - - -Galbraith, et al. Expires June 18, 2003 [Page 35] - -Internet-Draft SSH File Transfer Protocol December 2002 - - - Tatu Ylonen - SSH Communications Security Corp - Fredrikinkatu 42 - HELSINKI FIN-00100 - Finland - - EMail: [email protected] - - - Sami Lehtinen - SSH Communications Security Corp - Fredrikinkatu 42 - HELSINKI FIN-00100 - Finland - - EMail: [email protected] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Galbraith, et al. Expires June 18, 2003 [Page 36] - -Internet-Draft SSH File Transfer Protocol December 2002 - - -Intellectual Property Statement - - The IETF takes no position regarding the validity or scope of any - intellectual property or other rights that might be claimed to - pertain to the implementation or use of the technology described in - this document or the extent to which any license under such rights - might or might not be available; neither does it represent that it - has made any effort to identify any such rights. Information on the - IETF's procedures with respect to rights in standards-track and - standards-related documentation can be found in BCP-11. Copies of - claims of rights made available for publication and any assurances of - licenses to be made available, or the result of an attempt made to - obtain a general license or permission for the use of such - proprietary rights by implementors or users of this specification can - be obtained from the IETF Secretariat. - - The IETF invites any interested party to bring to its attention any - copyrights, patents or patent applications, or other proprietary - rights which may cover technology that may be required to practice - this standard. Please address the information to the IETF Executive - Director. - - -Full Copyright Statement - - Copyright (C) The Internet Society (2002). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assignees. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - - - -Galbraith, et al. Expires June 18, 2003 [Page 37] - -Internet-Draft SSH File Transfer Protocol December 2002 - - - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Galbraith, et al. Expires June 18, 2003 [Page 38] - - diff --git a/lib/ssh/doc/standard/draft-ietf-secsh-transport-17.2.ps b/lib/ssh/doc/standard/draft-ietf-secsh-transport-17.2.ps deleted file mode 100644 index d692285b4e..0000000000 --- a/lib/ssh/doc/standard/draft-ietf-secsh-transport-17.2.ps +++ /dev/null @@ -1,3205 +0,0 @@ -%!PS-Adobe-3.0 -%%BoundingBox: 75 0 595 747 -%%Title: Enscript Output -%%For: Magnus Thoang -%%Creator: GNU enscript 1.6.1 -%%CreationDate: Fri Oct 31 13:35:14 2003 -%%Orientation: Portrait -%%Pages: 15 0 -%%DocumentMedia: A4 595 842 0 () () -%%DocumentNeededResources: (atend) -%%EndComments -%%BeginProlog -%%BeginProcSet: PStoPS 1 15 -userdict begin -[/showpage/erasepage/copypage]{dup where{pop dup load - type/operatortype eq{1 array cvx dup 0 3 index cvx put - bind def}{pop}ifelse}{pop}ifelse}forall -[/letter/legal/executivepage/a4/a4small/b5/com10envelope - /monarchenvelope/c5envelope/dlenvelope/lettersmall/note - /folio/quarto/a5]{dup where{dup wcheck{exch{}put} - {pop{}def}ifelse}{pop}ifelse}forall -/setpagedevice {pop}bind 1 index where{dup wcheck{3 1 roll put} - {pop def}ifelse}{def}ifelse -/PStoPSmatrix matrix currentmatrix def -/PStoPSxform matrix def/PStoPSclip{clippath}def -/defaultmatrix{PStoPSmatrix exch PStoPSxform exch concatmatrix}bind def -/initmatrix{matrix defaultmatrix setmatrix}bind def -/initclip[{matrix currentmatrix PStoPSmatrix setmatrix - [{currentpoint}stopped{$error/newerror false put{newpath}} - {/newpath cvx 3 1 roll/moveto cvx 4 array astore cvx}ifelse] - {[/newpath cvx{/moveto cvx}{/lineto cvx} - {/curveto cvx}{/closepath cvx}pathforall]cvx exch pop} - stopped{$error/errorname get/invalidaccess eq{cleartomark - $error/newerror false put cvx exec}{stop}ifelse}if}bind aload pop - /initclip dup load dup type dup/operatortype eq{pop exch pop} - {dup/arraytype eq exch/packedarraytype eq or - {dup xcheck{exch pop aload pop}{pop cvx}ifelse} - {pop cvx}ifelse}ifelse - {newpath PStoPSclip clip newpath exec setmatrix} bind aload pop]cvx def -/initgraphics{initmatrix newpath initclip 1 setlinewidth - 0 setlinecap 0 setlinejoin []0 setdash 0 setgray - 10 setmiterlimit}bind def -end -%%EndProcSet -%%BeginResource: procset Enscript-Prolog 1.6 1 -% -% Procedures. -% - -/_S { % save current state - /_s save def -} def -/_R { % restore from saved state - _s restore -} def - -/S { % showpage protecting gstate - gsave - showpage - grestore -} bind def - -/MF { % fontname newfontname -> - make a new encoded font - /newfontname exch def - /fontname exch def - - /fontdict fontname findfont def - /newfont fontdict maxlength dict def - - fontdict { - exch - dup /FID eq { - % skip FID pair - pop pop - } { - % copy to the new font dictionary - exch newfont 3 1 roll put - } ifelse - } forall - - newfont /FontName newfontname put - - % insert only valid encoding vectors - encoding_vector length 256 eq { - newfont /Encoding encoding_vector put - } if - - newfontname newfont definefont pop -} def - -/SF { % fontname width height -> - set a new font - /height exch def - /width exch def - - findfont - [width 0 0 height 0 0] makefont setfont -} def - -/SUF { % fontname width height -> - set a new user font - /height exch def - /width exch def - - /F-gs-user-font MF - /F-gs-user-font width height SF -} def - -/M {moveto} bind def -/s {show} bind def - -/Box { % x y w h -> - define box path - /d_h exch def /d_w exch def /d_y exch def /d_x exch def - d_x d_y moveto - d_w 0 rlineto - 0 d_h rlineto - d_w neg 0 rlineto - closepath -} def - -/bgs { % x y height blskip gray str -> - show string with bg color - /str exch def - /gray exch def - /blskip exch def - /height exch def - /y exch def - /x exch def - - gsave - x y blskip sub str stringwidth pop height Box - gray setgray - fill - grestore - x y M str s -} def - -% Highlight bars. -/highlight_bars { % nlines lineheight output_y_margin gray -> - - gsave - setgray - /ymarg exch def - /lineheight exch def - /nlines exch def - - % This 2 is just a magic number to sync highlight lines to text. - 0 d_header_y ymarg sub 2 sub translate - - /cw d_output_w cols div def - /nrows d_output_h ymarg 2 mul sub lineheight div cvi def - - % for each column - 0 1 cols 1 sub { - cw mul /xp exch def - - % for each rows - 0 1 nrows 1 sub { - /rn exch def - rn lineheight mul neg /yp exch def - rn nlines idiv 2 mod 0 eq { - % Draw highlight bar. 4 is just a magic indentation. - xp 4 add yp cw 8 sub lineheight neg Box fill - } if - } for - } for - - grestore -} def - -% Line highlight bar. -/line_highlight { % x y width height gray -> - - gsave - /gray exch def - Box gray setgray fill - grestore -} def - -% Column separator lines. -/column_lines { - gsave - .1 setlinewidth - 0 d_footer_h translate - /cw d_output_w cols div def - 1 1 cols 1 sub { - cw mul 0 moveto - 0 d_output_h rlineto stroke - } for - grestore -} def - -% Column borders. -/column_borders { - gsave - .1 setlinewidth - 0 d_footer_h moveto - 0 d_output_h rlineto - d_output_w 0 rlineto - 0 d_output_h neg rlineto - closepath stroke - grestore -} def - -% Do the actual underlay drawing -/draw_underlay { - ul_style 0 eq { - ul_str true charpath stroke - } { - ul_str show - } ifelse -} def - -% Underlay -/underlay { % - -> - - gsave - 0 d_page_h translate - d_page_h neg d_page_w atan rotate - - ul_gray setgray - ul_font setfont - /dw d_page_h dup mul d_page_w dup mul add sqrt def - ul_str stringwidth pop dw exch sub 2 div ul_h_ptsize -2 div moveto - draw_underlay - grestore -} def - -/user_underlay { % - -> - - gsave - ul_x ul_y translate - ul_angle rotate - ul_gray setgray - ul_font setfont - 0 0 ul_h_ptsize 2 div sub moveto - draw_underlay - grestore -} def - -% Page prefeed -/page_prefeed { % bool -> - - statusdict /prefeed known { - statusdict exch /prefeed exch put - } { - pop - } ifelse -} def - -% Wrapped line markers -/wrapped_line_mark { % x y charwith charheight type -> - - /type exch def - /h exch def - /w exch def - /y exch def - /x exch def - - type 2 eq { - % Black boxes (like TeX does) - gsave - 0 setlinewidth - x w 4 div add y M - 0 h rlineto w 2 div 0 rlineto 0 h neg rlineto - closepath fill - grestore - } { - type 3 eq { - % Small arrows - gsave - .2 setlinewidth - x w 2 div add y h 2 div add M - w 4 div 0 rlineto - x w 4 div add y lineto stroke - - x w 4 div add w 8 div add y h 4 div add M - x w 4 div add y lineto - w 4 div h 8 div rlineto stroke - grestore - } { - % do nothing - } ifelse - } ifelse -} def - -% EPSF import. - -/BeginEPSF { - /b4_Inc_state save def % Save state for cleanup - /dict_count countdictstack def % Count objects on dict stack - /op_count count 1 sub def % Count objects on operand stack - userdict begin - /showpage { } def - 0 setgray 0 setlinecap - 1 setlinewidth 0 setlinejoin - 10 setmiterlimit [ ] 0 setdash newpath - /languagelevel where { - pop languagelevel - 1 ne { - false setstrokeadjust false setoverprint - } if - } if -} bind def - -/EndEPSF { - count op_count sub { pos } repeat % Clean up stacks - countdictstack dict_count sub { end } repeat - b4_Inc_state restore -} bind def - -% Check PostScript language level. -/languagelevel where { - pop /gs_languagelevel languagelevel def -} { - /gs_languagelevel 1 def -} ifelse -%%EndResource -%%BeginResource: procset Enscript-Encoding-88591 1.6 1 -/encoding_vector [ -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/space /exclam /quotedbl /numbersign -/dollar /percent /ampersand /quoteright -/parenleft /parenright /asterisk /plus -/comma /hyphen /period /slash -/zero /one /two /three -/four /five /six /seven -/eight /nine /colon /semicolon -/less /equal /greater /question -/at /A /B /C -/D /E /F /G -/H /I /J /K -/L /M /N /O -/P /Q /R /S -/T /U /V /W -/X /Y /Z /bracketleft -/backslash /bracketright /asciicircum /underscore -/quoteleft /a /b /c -/d /e /f /g -/h /i /j /k -/l /m /n /o -/p /q /r /s -/t /u /v /w -/x /y /z /braceleft -/bar /braceright /tilde /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/space /exclamdown /cent /sterling -/currency /yen /brokenbar /section -/dieresis /copyright /ordfeminine /guillemotleft -/logicalnot /hyphen /registered /macron -/degree /plusminus /twosuperior /threesuperior -/acute /mu /paragraph /bullet -/cedilla /onesuperior /ordmasculine /guillemotright -/onequarter /onehalf /threequarters /questiondown -/Agrave /Aacute /Acircumflex /Atilde -/Adieresis /Aring /AE /Ccedilla -/Egrave /Eacute /Ecircumflex /Edieresis -/Igrave /Iacute /Icircumflex /Idieresis -/Eth /Ntilde /Ograve /Oacute -/Ocircumflex /Otilde /Odieresis /multiply -/Oslash /Ugrave /Uacute /Ucircumflex -/Udieresis /Yacute /Thorn /germandbls -/agrave /aacute /acircumflex /atilde -/adieresis /aring /ae /ccedilla -/egrave /eacute /ecircumflex /edieresis -/igrave /iacute /icircumflex /idieresis -/eth /ntilde /ograve /oacute -/ocircumflex /otilde /odieresis /divide -/oslash /ugrave /uacute /ucircumflex -/udieresis /yacute /thorn /ydieresis -] def -%%EndResource -%%EndProlog -%%BeginSetup -%%IncludeResource: font Courier-Bold -%%IncludeResource: font Courier -/HFpt_w 10 def -/HFpt_h 10 def -/Courier-Bold /HF-gs-font MF -/HF /HF-gs-font findfont [HFpt_w 0 0 HFpt_h 0 0] makefont def -/Courier /F-gs-font MF -/F-gs-font 10 10 SF -/#copies 1 def -/d_page_w 520 def -/d_page_h 747 def -/d_header_x 0 def -/d_header_y 747 def -/d_header_w 520 def -/d_header_h 0 def -/d_footer_x 0 def -/d_footer_y 0 def -/d_footer_w 520 def -/d_footer_h 0 def -/d_output_w 520 def -/d_output_h 747 def -/cols 1 def -userdict/PStoPSxform PStoPSmatrix matrix currentmatrix - matrix invertmatrix matrix concatmatrix - matrix invertmatrix put -%%EndSetup -%%Page: (0,1) 1 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 1 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 701 M -(Network Working Group T. Ylonen) s -5 690 M -(Internet-Draft SSH Communications Security Corp) s -5 679 M -(Expires: March 31, 2004 D. Moffat, Editor, Ed.) s -5 668 M -( Sun Microsystems, Inc) s -5 657 M -( Oct 2003) s -5 624 M -( SSH Transport Layer Protocol) s -5 613 M -( draft-ietf-secsh-transport-17.txt) s -5 591 M -(Status of this Memo) s -5 569 M -( This document is an Internet-Draft and is in full conformance with) s -5 558 M -( all provisions of Section 10 of RFC2026.) s -5 536 M -( Internet-Drafts are working documents of the Internet Engineering) s -5 525 M -( Task Force \(IETF\), its areas, and its working groups. Note that other) s -5 514 M -( groups may also distribute working documents as Internet-Drafts.) s -5 492 M -( Internet-Drafts are draft documents valid for a maximum of six months) s -5 481 M -( and may be updated, replaced, or obsoleted by other documents at any) s -5 470 M -( time. It is inappropriate to use Internet-Drafts as reference) s -5 459 M -( material or to cite them other than as "work in progress.") s -5 437 M -( The list of current Internet-Drafts can be accessed at http://) s -5 426 M -( www.ietf.org/ietf/1id-abstracts.txt.) s -5 404 M -( The list of Internet-Draft Shadow Directories can be accessed at) s -5 393 M -( http://www.ietf.org/shadow.html.) s -5 371 M -( This Internet-Draft will expire on March 31, 2004.) s -5 349 M -(Copyright Notice) s -5 327 M -( Copyright \(C\) The Internet Society \(2003\). All Rights Reserved.) s -5 305 M -(Abstract) s -5 283 M -( SSH is a protocol for secure remote login and other secure network) s -5 272 M -( services over an insecure network.) s -5 250 M -( This document describes the SSH transport layer protocol which) s -5 239 M -( typically runs on top of TCP/IP. The protocol can be used as a basis) s -5 228 M -( for a number of secure network services. It provides strong) s -5 217 M -( encryption, server authentication, and integrity protection. It may) s -5 206 M -( also provide compression.) s -5 184 M -( Key exchange method, public key algorithm, symmetric encryption) s -5 173 M -( algorithm, message authentication algorithm, and hash algorithm are) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 1]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 2 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Transport Layer Protocol Oct 2003) s -5 690 M -( all negotiated.) s -5 668 M -( This document also describes the Diffie-Hellman key exchange method) s -5 657 M -( and the minimal set of algorithms that are needed to implement the) s -5 646 M -( SSH transport layer protocol.) s -5 624 M -(Table of Contents) s -5 602 M -( 1. Contributors . . . . . . . . . . . . . . . . . . . . . . . . 3) s -5 591 M -( 2. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3) s -5 580 M -( 3. Conventions Used in This Document . . . . . . . . . . . . . 3) s -5 569 M -( 4. Connection Setup . . . . . . . . . . . . . . . . . . . . . . 3) s -5 558 M -( 4.1 Use over TCP/IP . . . . . . . . . . . . . . . . . . . . . . 4) s -5 547 M -( 4.2 Protocol Version Exchange . . . . . . . . . . . . . . . . . 4) s -5 536 M -( 4.3 Compatibility With Old SSH Versions . . . . . . . . . . . . 4) s -5 525 M -( 4.3.1 Old Client, New Server . . . . . . . . . . . . . . . . . . . 5) s -5 514 M -( 4.3.2 New Client, Old Server . . . . . . . . . . . . . . . . . . . 5) s -5 503 M -( 5. Binary Packet Protocol . . . . . . . . . . . . . . . . . . . 5) s -5 492 M -( 5.1 Maximum Packet Length . . . . . . . . . . . . . . . . . . . 6) s -5 481 M -( 5.2 Compression . . . . . . . . . . . . . . . . . . . . . . . . 7) s -5 470 M -( 5.3 Encryption . . . . . . . . . . . . . . . . . . . . . . . . . 7) s -5 459 M -( 5.4 Data Integrity . . . . . . . . . . . . . . . . . . . . . . . 9) s -5 448 M -( 5.5 Key Exchange Methods . . . . . . . . . . . . . . . . . . . . 10) s -5 437 M -( 5.6 Public Key Algorithms . . . . . . . . . . . . . . . . . . . 11) s -5 426 M -( 6. Key Exchange . . . . . . . . . . . . . . . . . . . . . . . . 13) s -5 415 M -( 6.1 Algorithm Negotiation . . . . . . . . . . . . . . . . . . . 13) s -5 404 M -( 6.2 Output from Key Exchange . . . . . . . . . . . . . . . . . . 16) s -5 393 M -( 6.3 Taking Keys Into Use . . . . . . . . . . . . . . . . . . . . 17) s -5 382 M -( 7. Diffie-Hellman Key Exchange . . . . . . . . . . . . . . . . 18) s -5 371 M -( 7.1 diffie-hellman-group1-sha1 . . . . . . . . . . . . . . . . . 19) s -5 360 M -( 8. Key Re-Exchange . . . . . . . . . . . . . . . . . . . . . . 20) s -5 349 M -( 9. Service Request . . . . . . . . . . . . . . . . . . . . . . 21) s -5 338 M -( 10. Additional Messages . . . . . . . . . . . . . . . . . . . . 21) s -5 327 M -( 10.1 Disconnection Message . . . . . . . . . . . . . . . . . . . 22) s -5 316 M -( 10.2 Ignored Data Message . . . . . . . . . . . . . . . . . . . . 22) s -5 305 M -( 10.3 Debug Message . . . . . . . . . . . . . . . . . . . . . . . 23) s -5 294 M -( 10.4 Reserved Messages . . . . . . . . . . . . . . . . . . . . . 23) s -5 283 M -( 11. Summary of Message Numbers . . . . . . . . . . . . . . . . . 23) s -5 272 M -( 12. IANA Considerations . . . . . . . . . . . . . . . . . . . . 24) s -5 261 M -( 13. Security Considerations . . . . . . . . . . . . . . . . . . 24) s -5 250 M -( 14. Intellectual Property . . . . . . . . . . . . . . . . . . . 24) s -5 239 M -( 15. Additional Information . . . . . . . . . . . . . . . . . . . 24) s -5 228 M -( Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 26) s -5 217 M -( Normative . . . . . . . . . . . . . . . . . . . . . . . . . 25) s -5 206 M -( Informative . . . . . . . . . . . . . . . . . . . . . . . . 25) s -5 195 M -( A. Contibutors . . . . . . . . . . . . . . . . . . . . . . . . 27) s -5 184 M -( Intellectual Property and Copyright Statements . . . . . . . 28) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 2]) s -_R -S -PStoPSsaved restore -%%Page: (2,3) 2 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 3 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Transport Layer Protocol Oct 2003) s -5 690 M -(1. Contributors) s -5 668 M -( The major original contributors of this document were: Tatu Ylonen,) s -5 657 M -( Tero Kivinen, Timo J. Rinne, Sami Lehtinen \(all of SSH Communications) s -5 646 M -( Security Corp\), and Markku-Juhani O. Saarinen \(University of) s -5 635 M -( Jyvaskyla\)) s -5 613 M -( The document editor is: [email protected]. Comments on this) s -5 602 M -( internet draft should be sent to the IETF SECSH working group,) s -5 591 M -( details at: http://ietf.org/html.charters/secsh-charter.html) s -5 569 M -(2. Introduction) s -5 547 M -( The SSH transport layer is a secure low level transport protocol. It) s -5 536 M -( provides strong encryption, cryptographic host authentication, and) s -5 525 M -( integrity protection.) s -5 503 M -( Authentication in this protocol level is host-based; this protocol) s -5 492 M -( does not perform user authentication. A higher level protocol for) s -5 481 M -( user authentication can be designed on top of this protocol.) s -5 459 M -( The protocol has been designed to be simple, flexible, to allow) s -5 448 M -( parameter negotiation, and to minimize the number of round-trips.) s -5 437 M -( Key exchange method, public key algorithm, symmetric encryption) s -5 426 M -( algorithm, message authentication algorithm, and hash algorithm are) s -5 415 M -( all negotiated. It is expected that in most environments, only 2) s -5 404 M -( round-trips will be needed for full key exchange, server) s -5 393 M -( authentication, service request, and acceptance notification of) s -5 382 M -( service request. The worst case is 3 round-trips.) s -5 360 M -(3. Conventions Used in This Document) s -5 338 M -( The keywords "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT",) s -5 327 M -( and "MAY" that appear in this document are to be interpreted as) s -5 316 M -( described in [RFC2119].) s -5 294 M -( The used data types and terminology are specified in the architecture) s -5 283 M -( document [SSH-ARCH].) s -5 261 M -( The architecture document also discusses the algorithm naming) s -5 250 M -( conventions that MUST be used with the SSH protocols.) s -5 228 M -(4. Connection Setup) s -5 206 M -( SSH works over any 8-bit clean, binary-transparent transport. The) s -5 195 M -( underlying transport SHOULD protect against transmission errors as) s -5 184 M -( such errors cause the SSH connection to terminate.) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 3]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 4 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Transport Layer Protocol Oct 2003) s -5 690 M -( The client initiates the connection.) s -5 668 M -(4.1 Use over TCP/IP) s -5 646 M -( When used over TCP/IP, the server normally listens for connections on) s -5 635 M -( port 22. This port number has been registered with the IANA, and has) s -5 624 M -( been officially assigned for SSH.) s -5 602 M -(4.2 Protocol Version Exchange) s -5 580 M -( When the connection has been established, both sides MUST send an) s -5 569 M -( identification string of the form "SSH-protoversion-softwareversion) s -5 558 M -( comments", followed by carriage return and newline characters \(ASCII) s -5 547 M -( 13 and 10, respectively\). Both sides MUST be able to process) s -5 536 M -( identification strings without carriage return character. No null) s -5 525 M -( character is sent. The maximum length of the string is 255) s -5 514 M -( characters, including the carriage return and newline.) s -5 492 M -( The part of the identification string preceding carriage return and) s -5 481 M -( newline is used in the Diffie-Hellman key exchange \(see Section) s -5 470 M -( Section 7\).) s -5 448 M -( The server MAY send other lines of data before sending the version) s -5 437 M -( string. Each line SHOULD be terminated by a carriage return and) s -5 426 M -( newline. Such lines MUST NOT begin with "SSH-", and SHOULD be) s -5 415 M -( encoded in ISO-10646 UTF-8 [RFC2279] \(language is not specified\).) s -5 404 M -( Clients MUST be able to process such lines; they MAY be silently) s -5 393 M -( ignored, or MAY be displayed to the client user; if they are) s -5 382 M -( displayed, control character filtering discussed in [SSH-ARCH] SHOULD) s -5 371 M -( be used. The primary use of this feature is to allow TCP-wrappers to) s -5 360 M -( display an error message before disconnecting.) s -5 338 M -( Version strings MUST consist of printable US-ASCII characters, not) s -5 327 M -( including whitespaces or a minus sign \(-\). The version string is) s -5 316 M -( primarily used to trigger compatibility extensions and to indicate) s -5 305 M -( the capabilities of an implementation. The comment string should) s -5 294 M -( contain additional information that might be useful in solving user) s -5 283 M -( problems.) s -5 261 M -( The protocol version described in this document is 2.0.) s -5 239 M -( Key exchange will begin immediately after sending this identifier.) s -5 228 M -( All packets following the identification string SHALL use the binary) s -5 217 M -( packet protocol, to be described below.) s -5 195 M -(4.3 Compatibility With Old SSH Versions) s -5 173 M -( During the transition period, it is important to be able to work in a) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 4]) s -_R -S -PStoPSsaved restore -%%Page: (4,5) 3 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 5 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Transport Layer Protocol Oct 2003) s -5 690 M -( way that is compatible with the installed SSH clients and servers) s -5 679 M -( that use an older version of the protocol. Information in this) s -5 668 M -( section is only relevant for implementations supporting compatibility) s -5 657 M -( with SSH versions 1.x. There is no standards track or informational) s -5 646 M -( draft available that defines the SSH 1.x protocol. The only known) s -5 635 M -( documentation of the 1.x protocol is contained in README files that) s -5 624 M -( are shipped along with the source code.) s -5 602 M -(4.3.1 Old Client, New Server) s -5 580 M -( Server implementations MAY support a configurable "compatibility") s -5 569 M -( flag that enables compatibility with old versions. When this flag is) s -5 558 M -( on, the server SHOULD identify its protocol version as "1.99".) s -5 547 M -( Clients using protocol 2.0 MUST be able to identify this as identical) s -5 536 M -( to "2.0". In this mode the server SHOULD NOT send the carriage) s -5 525 M -( return character \(ASCII 13\) after the version identification string.) s -5 503 M -( In the compatibility mode the server SHOULD NOT send any further data) s -5 492 M -( after its initialization string until it has received an) s -5 481 M -( identification string from the client. The server can then determine) s -5 470 M -( whether the client is using an old protocol, and can revert to the) s -5 459 M -( old protocol if required. In the compatibility mode, the server MUST) s -5 448 M -( NOT send additional data before the version string.) s -5 426 M -( When compatibility with old clients is not needed, the server MAY) s -5 415 M -( send its initial key exchange data immediately after the) s -5 404 M -( identification string.) s -5 382 M -(4.3.2 New Client, Old Server) s -5 360 M -( Since the new client MAY immediately send additional data after its) s -5 349 M -( identification string \(before receiving server's identification\), the) s -5 338 M -( old protocol may already have been corrupted when the client learns) s -5 327 M -( that the server is old. When this happens, the client SHOULD close) s -5 316 M -( the connection to the server, and reconnect using the old protocol.) s -5 294 M -(5. Binary Packet Protocol) s -5 272 M -( Each packet is in the following format:) s -5 250 M -( uint32 packet_length) s -5 239 M -( byte padding_length) s -5 228 M -( byte[n1] payload; n1 = packet_length - padding_length - 1) s -5 217 M -( byte[n2] random padding; n2 = padding_length) s -5 206 M -( byte[m] mac \(message authentication code\); m = mac_length) s -5 184 M -( packet_length) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 5]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 6 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Transport Layer Protocol Oct 2003) s -5 690 M -( The length of the packet \(bytes\), not including MAC or the) s -5 679 M -( packet_length field itself.) s -5 657 M -( padding_length) s -5 646 M -( Length of padding \(bytes\).) s -5 624 M -( payload) s -5 613 M -( The useful contents of the packet. If compression has been) s -5 602 M -( negotiated, this field is compressed. Initially, compression) s -5 591 M -( MUST be "none".) s -5 569 M -( random padding) s -5 558 M -( Arbitrary-length padding, such that the total length of) s -5 547 M -( \(packet_length || padding_length || payload || padding\) is a) s -5 536 M -( multiple of the cipher block size or 8, whichever is larger.) s -5 525 M -( There MUST be at least four bytes of padding. The padding) s -5 514 M -( SHOULD consist of random bytes. The maximum amount of padding) s -5 503 M -( is 255 bytes.) s -5 481 M -( mac) s -5 470 M -( Message authentication code. If message authentication has) s -5 459 M -( been negotiated, this field contains the MAC bytes. Initially,) s -5 448 M -( the MAC algorithm MUST be "none".) s -5 415 M -( Note that length of the concatenation of packet length, padding) s -5 404 M -( length, payload, and padding MUST be a multiple of the cipher block) s -5 393 M -( size or 8, whichever is larger. This constraint MUST be enforced) s -5 382 M -( even when using stream ciphers. Note that the packet length field is) s -5 371 M -( also encrypted, and processing it requires special care when sending) s -5 360 M -( or receiving packets.) s -5 338 M -( The minimum size of a packet is 16 \(or the cipher block size,) s -5 327 M -( whichever is larger\) bytes \(plus MAC\); implementations SHOULD decrypt) s -5 316 M -( the length after receiving the first 8 \(or cipher block size,) s -5 305 M -( whichever is larger\) bytes of a packet.) s -5 283 M -(5.1 Maximum Packet Length) s -5 261 M -( All implementations MUST be able to process packets with uncompressed) s -5 250 M -( payload length of 32768 bytes or less and total packet size of 35000) s -5 239 M -( bytes or less \(including length, padding length, payload, padding,) s -5 228 M -( and MAC.\). The maximum of 35000 bytes is an arbitrary chosen value) s -5 217 M -( larger than uncompressed size. Implementations SHOULD support longer) s -5 206 M -( packets, where they might be needed, e.g. if an implementation wants) s -5 195 M -( to send a very large number of certificates. Such packets MAY be) s -5 184 M -( sent if the version string indicates that the other party is able to) s -5 173 M -( process them. However, implementations SHOULD check that the packet) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 6]) s -_R -S -PStoPSsaved restore -%%Page: (6,7) 4 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 7 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Transport Layer Protocol Oct 2003) s -5 690 M -( length is reasonable for the implementation to avoid) s -5 679 M -( denial-of-service and/or buffer overflow attacks.) s -5 657 M -(5.2 Compression) s -5 635 M -( If compression has been negotiated, the payload field \(and only it\)) s -5 624 M -( will be compressed using the negotiated algorithm. The length field) s -5 613 M -( and MAC will be computed from the compressed payload. Encryption will) s -5 602 M -( be done after compression.) s -5 580 M -( Compression MAY be stateful, depending on the method. Compression) s -5 569 M -( MUST be independent for each direction, and implementations MUST) s -5 558 M -( allow independently choosing the algorithm for each direction.) s -5 536 M -( The following compression methods are currently defined:) s -5 514 M -( none REQUIRED no compression) s -5 503 M -( zlib OPTIONAL ZLIB \(LZ77\) compression) s -5 481 M -( The "zlib" compression is described in [RFC1950] and in [RFC1951].) s -5 470 M -( The compression context is initialized after each key exchange, and) s -5 459 M -( is passed from one packet to the next with only a partial flush being) s -5 448 M -( performed at the end of each packet. A partial flush means that the) s -5 437 M -( current compressed block is ended and all data will be output. If the) s -5 426 M -( current block is not a stored block, one or more empty blocks are) s -5 415 M -( added after the current block to ensure that there are at least 8) s -5 404 M -( bits counting from the start of the end-of-block code of the current) s -5 393 M -( block to the end of the packet payload.) s -5 371 M -( Additional methods may be defined as specified in [SSH-ARCH].) s -5 349 M -(5.3 Encryption) s -5 327 M -( An encryption algorithm and a key will be negotiated during the key) s -5 316 M -( exchange. When encryption is in effect, the packet length, padding) s -5 305 M -( length, payload and padding fields of each packet MUST be encrypted) s -5 294 M -( with the given algorithm.) s -5 272 M -( The encrypted data in all packets sent in one direction SHOULD be) s -5 261 M -( considered a single data stream. For example, initialization vectors) s -5 250 M -( SHOULD be passed from the end of one packet to the beginning of the) s -5 239 M -( next packet. All ciphers SHOULD use keys with an effective key length) s -5 228 M -( of 128 bits or more.) s -5 206 M -( The ciphers in each direction MUST run independently of each other,) s -5 195 M -( and implementations MUST allow independently choosing the algorithm) s -5 184 M -( for each direction \(if multiple algorithms are allowed by local) s -5 173 M -( policy\).) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 7]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 8 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Transport Layer Protocol Oct 2003) s -5 690 M -( The following ciphers are currently defined:) s -5 668 M -( 3des-cbc REQUIRED three-key 3DES in CBC mode) s -5 657 M -( blowfish-cbc OPTIONALi Blowfish in CBC mode) s -5 646 M -( twofish256-cbc OPTIONAL Twofish in CBC mode,) s -5 635 M -( with 256-bit key) s -5 624 M -( twofish-cbc OPTIONAL alias for "twofish256-cbc" \(this) s -5 613 M -( is being retained for) s -5 602 M -( historical reasons\)) s -5 591 M -( twofish192-cbc OPTIONAL Twofish with 192-bit key) s -5 580 M -( twofish128-cbc OPTIONAL Twofish with 128-bit key) s -5 569 M -( aes256-cbc OPTIONAL AES \(Rijndael\) in CBC mode,) s -5 558 M -( with 256-bit key) s -5 547 M -( aes192-cbc OPTIONAL AES with 192-bit key) s -5 536 M -( aes128-cbc RECOMMENDED AES with 128-bit key) s -5 525 M -( serpent256-cbc OPTIONAL Serpent in CBC mode, with) s -5 514 M -( 256-bit key) s -5 503 M -( serpent192-cbc OPTIONAL Serpent with 192-bit key) s -5 492 M -( serpent128-cbc OPTIONAL Serpent with 128-bit key) s -5 481 M -( arcfour OPTIONAL the ARCFOUR stream cipher) s -5 470 M -( idea-cbc OPTIONAL IDEA in CBC mode) s -5 459 M -( cast128-cbc OPTIONAL CAST-128 in CBC mode) s -5 448 M -( none OPTIONAL no encryption; NOT RECOMMENDED) s -5 426 M -( The "3des-cbc" cipher is three-key triple-DES) s -5 415 M -( \(encrypt-decrypt-encrypt\), where the first 8 bytes of the key are) s -5 404 M -( used for the first encryption, the next 8 bytes for the decryption,) s -5 393 M -( and the following 8 bytes for the final encryption. This requires 24) s -5 382 M -( bytes of key data \(of which 168 bits are actually used\). To) s -5 371 M -( implement CBC mode, outer chaining MUST be used \(i.e., there is only) s -5 360 M -( one initialization vector\). This is a block cipher with 8 byte) s -5 349 M -( blocks. This algorithm is defined in [FIPS-46-3]) s -5 327 M -( The "blowfish-cbc" cipher is Blowfish in CBC mode, with 128 bit keys) s -5 316 M -( [SCHNEIER]. This is a block cipher with 8 byte blocks.) s -5 294 M -( The "twofish-cbc" or "twofish256-cbc" cipher is Twofish in CBC mode,) s -5 283 M -( with 256 bit keys as described [TWOFISH]. This is a block cipher with) s -5 272 M -( 16 byte blocks.) s -5 250 M -( The "twofish192-cbc" cipher. Same as above but with 192-bit key.) s -5 228 M -( The "twofish128-cbc" cipher. Same as above but with 128-bit key.) s -5 206 M -( The "aes256-cbc" cipher is AES \(Advanced Encryption Standard\)) s -5 195 M -( [FIPS-197], formerly Rijndael, in CBC mode. This version uses 256-bit) s -5 184 M -( key.) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 8]) s -_R -S -PStoPSsaved restore -%%Page: (8,9) 5 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 9 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Transport Layer Protocol Oct 2003) s -5 690 M -( The "aes192-cbc" cipher. Same as above but with 192-bit key.) s -5 668 M -( The "aes128-cbc" cipher. Same as above but with 128-bit key.) s -5 646 M -( The "serpent256-cbc" cipher in CBC mode, with 256-bit key as) s -5 635 M -( described in the Serpent AES submission.) s -5 613 M -( The "serpent192-cbc" cipher. Same as above but with 192-bit key.) s -5 591 M -( The "serpent128-cbc" cipher. Same as above but with 128-bit key.) s -5 569 M -( The "arcfour" is the Arcfour stream cipher with 128 bit keys. The) s -5 558 M -( Arcfour cipher is believed to be compatible with the RC4 cipher) s -5 547 M -( [SCHNEIER]. RC4 is a registered trademark of RSA Data Security Inc.) s -5 536 M -( Arcfour \(and RC4\) has problems with weak keys, and should be used) s -5 525 M -( with caution.) s -5 503 M -( The "idea-cbc" cipher is the IDEA cipher in CBC mode [SCHNEIER].) s -5 481 M -( The "cast128-cbc" cipher is the CAST-128 cipher in CBC mode) s -5 470 M -( [RFC2144].) s -5 448 M -( The "none" algorithm specifies that no encryption is to be done.) s -5 437 M -( Note that this method provides no confidentiality protection, and it) s -5 426 M -( is not recommended. Some functionality \(e.g. password) s -5 415 M -( authentication\) may be disabled for security reasons if this cipher) s -5 404 M -( is chosen.) s -5 382 M -( Additional methods may be defined as specified in [SSH-ARCH].) s -5 360 M -(5.4 Data Integrity) s -5 338 M -( Data integrity is protected by including with each packet a message) s -5 327 M -( authentication code \(MAC\) that is computed from a shared secret,) s -5 316 M -( packet sequence number, and the contents of the packet.) s -5 294 M -( The message authentication algorithm and key are negotiated during) s -5 283 M -( key exchange. Initially, no MAC will be in effect, and its length) s -5 272 M -( MUST be zero. After key exchange, the selected MAC will be computed) s -5 261 M -( before encryption from the concatenation of packet data:) s -5 239 M -( mac = MAC\(key, sequence_number || unencrypted_packet\)) s -5 217 M -( where unencrypted_packet is the entire packet without MAC \(the length) s -5 206 M -( fields, payload and padding\), and sequence_number is an implicit) s -5 195 M -( packet sequence number represented as uint32. The sequence number is) s -5 184 M -( initialized to zero for the first packet, and is incremented after) s -5 173 M -( every packet \(regardless of whether encryption or MAC is in use\). It) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 9]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 10 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Transport Layer Protocol Oct 2003) s -5 690 M -( is never reset, even if keys/algorithms are renegotiated later. It) s -5 679 M -( wraps around to zero after every 2^32 packets. The packet sequence) s -5 668 M -( number itself is not included in the packet sent over the wire.) s -5 646 M -( The MAC algorithms for each direction MUST run independently, and) s -5 635 M -( implementations MUST allow choosing the algorithm independently for) s -5 624 M -( both directions.) s -5 602 M -( The MAC bytes resulting from the MAC algorithm MUST be transmitted) s -5 591 M -( without encryption as the last part of the packet. The number of MAC) s -5 580 M -( bytes depends on the algorithm chosen.) s -5 558 M -( The following MAC algorithms are currently defined:) s -5 536 M -( hmac-sha1 REQUIRED HMAC-SHA1 \(digest length = key) s -5 525 M -( length = 20\)) s -5 514 M -( hmac-sha1-96 RECOMMENDED first 96 bits of HMAC-SHA1 \(digest) s -5 503 M -( length = 12, key length = 20\)) s -5 492 M -( hmac-md5 OPTIONAL HMAC-MD5 \(digest length = key) s -5 481 M -( length = 16\)) s -5 470 M -( hmac-md5-96 OPTIONAL first 96 bits of HMAC-MD5 \(digest) s -5 459 M -( length = 12, key length = 16\)) s -5 448 M -( none OPTIONAL no MAC; NOT RECOMMENDED) s -5 426 M -( Figure 1) s -5 404 M -( The "hmac-*" algorithms are described in [RFC2104] The "*-n" MACs use) s -5 393 M -( only the first n bits of the resulting value.) s -5 371 M -( The hash algorithms are described in [SCHNEIER].) s -5 349 M -( Additional methods may be defined as specified in [SSH-ARCH].) s -5 327 M -(5.5 Key Exchange Methods) s -5 305 M -( The key exchange method specifies how one-time session keys are) s -5 294 M -( generated for encryption and for authentication, and how the server) s -5 283 M -( authentication is done.) s -5 261 M -( Only one REQUIRED key exchange method has been defined:) s -5 239 M -( diffie-hellman-group1-sha1 REQUIRED) s -5 217 M -( This method is described later in this document.) s -5 195 M -( Additional methods may be defined as specified in [SSH-ARCH].) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 10]) s -_R -S -PStoPSsaved restore -%%Page: (10,11) 6 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 11 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Transport Layer Protocol Oct 2003) s -5 690 M -(5.6 Public Key Algorithms) s -5 668 M -( This protocol has been designed to be able to operate with almost any) s -5 657 M -( public key format, encoding, and algorithm \(signature and/or) s -5 646 M -( encryption\).) s -5 624 M -( There are several aspects that define a public key type:) s -5 613 M -( o Key format: how is the key encoded and how are certificates) s -5 602 M -( represented. The key blobs in this protocol MAY contain) s -5 591 M -( certificates in addition to keys.) s -5 580 M -( o Signature and/or encryption algorithms. Some key types may not) s -5 569 M -( support both signing and encryption. Key usage may also be) s -5 558 M -( restricted by policy statements in e.g. certificates. In this) s -5 547 M -( case, different key types SHOULD be defined for the different) s -5 536 M -( policy alternatives.) s -5 525 M -( o Encoding of signatures and/or encrypted data. This includes but is) s -5 514 M -( not limited to padding, byte order, and data formats.) s -5 492 M -( The following public key and/or certificate formats are currently defined:) s -5 470 M -( ssh-dss REQUIRED sign Raw DSS Key) s -5 459 M -( ssh-rsa RECOMMENDED sign Raw RSA Key) s -5 448 M -( x509v3-sign-rsa OPTIONAL sign X.509 certificates \(RSA key\)) s -5 437 M -( x509v3-sign-dss OPTIONAL sign X.509 certificates \(DSS key\)) s -5 426 M -( spki-sign-rsa OPTIONAL sign SPKI certificates \(RSA key\)) s -5 415 M -( spki-sign-dss OPTIONAL sign SPKI certificates \(DSS key\)) s -5 404 M -( pgp-sign-rsa OPTIONAL sign OpenPGP certificates \(RSA key\)) s -5 393 M -( pgp-sign-dss OPTIONAL sign OpenPGP certificates \(DSS key\)) s -5 371 M -( Additional key types may be defined as specified in [SSH-ARCH].) s -5 349 M -( The key type MUST always be explicitly known \(from algorithm) s -5 338 M -( negotiation or some other source\). It is not normally included in) s -5 327 M -( the key blob.) s -5 305 M -( Certificates and public keys are encoded as follows:) s -5 283 M -( string certificate or public key format identifier) s -5 272 M -( byte[n] key/certificate data) s -5 250 M -( The certificate part may have be a zero length string, but a public) s -5 239 M -( key is required. This is the public key that will be used for) s -5 228 M -( authentication; the certificate sequence contained in the certificate) s -5 217 M -( blob can be used to provide authorization.) s -5 195 M -( Public key / certifcate formats that do not explicitly specify a) s -5 184 M -( signature format identifier MUST use the public key / certificate) s -5 173 M -( format identifier as the signature identifier.) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 11]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 12 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Transport Layer Protocol Oct 2003) s -5 690 M -( Signatures are encoded as follows:) s -5 679 M -( string signature format identifier \(as specified by the) s -5 668 M -( public key / cert format\)) s -5 657 M -( byte[n] signature blob in format specific encoding.) s -5 624 M -( The "ssh-dss" key format has the following specific encoding:) s -5 602 M -( string "ssh-dss") s -5 591 M -( mpint p) s -5 580 M -( mpint q) s -5 569 M -( mpint g) s -5 558 M -( mpint y) s -5 536 M -( Here the p, q, g, and y parameters form the signature key blob.) s -5 514 M -( Signing and verifying using this key format is done according to the) s -5 503 M -( Digital Signature Standard [FIPS-186] using the SHA-1 hash. A) s -5 492 M -( description can also be found in [SCHNEIER].) s -5 470 M -( The resulting signature is encoded as follows:) s -5 448 M -( string "ssh-dss") s -5 437 M -( string dss_signature_blob) s -5 415 M -( dss_signature_blob is encoded as a string containing r followed by s) s -5 404 M -( \(which are 160 bits long integers, without lengths or padding,) s -5 393 M -( unsigned and in network byte order\).) s -5 371 M -( The "ssh-rsa" key format has the following specific encoding:) s -5 349 M -( string "ssh-rsa") s -5 338 M -( mpint e) s -5 327 M -( mpint n) s -5 305 M -( Here the e and n parameters form the signature key blob.) s -5 283 M -( Signing and verifying using this key format is done according to) s -5 272 M -( [SCHNEIER] and [PKCS1] using the SHA-1 hash.) s -5 250 M -( The resulting signature is encoded as follows:) s -5 228 M -( string "ssh-rsa") s -5 217 M -( string rsa_signature_blob) s -5 195 M -( rsa_signature_blob is encoded as a string containing s \(which is an) s -5 184 M -( integer, without lengths or padding, unsigned and in network byte) s -5 173 M -( order\).) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 12]) s -_R -S -PStoPSsaved restore -%%Page: (12,13) 7 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 13 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Transport Layer Protocol Oct 2003) s -5 690 M -( The "spki-sign-rsa" method indicates that the certificate blob) s -5 679 M -( contains a sequence of SPKI certificates. The format of SPKI) s -5 668 M -( certificates is described in [RFC2693]. This method indicates that) s -5 657 M -( the key \(or one of the keys in the certificate\) is an RSA-key.) s -5 635 M -( The "spki-sign-dss". As above, but indicates that the key \(or one of) s -5 624 M -( the keys in the certificate\) is a DSS-key.) s -5 602 M -( The "pgp-sign-rsa" method indicates the certificates, the public key,) s -5 591 M -( and the signature are in OpenPGP compatible binary format) s -5 580 M -( \([RFC2440]\). This method indicates that the key is an RSA-key.) s -5 558 M -( The "pgp-sign-dss". As above, but indicates that the key is a) s -5 547 M -( DSS-key.) s -5 525 M -(6. Key Exchange) s -5 503 M -( Key exchange begins by each side sending lists of supported) s -5 492 M -( algorithms. Each side has a preferred algorithm in each category, and) s -5 481 M -( it is assumed that most implementations at any given time will use) s -5 470 M -( the same preferred algorithm. Each side MAY guess which algorithm) s -5 459 M -( the other side is using, and MAY send an initial key exchange packet) s -5 448 M -( according to the algorithm if appropriate for the preferred method.) s -5 426 M -( Guess is considered wrong, if:) s -5 415 M -( o the kex algorithm and/or the host key algorithm is guessed wrong) s -5 404 M -( \(server and client have different preferred algorithm\), or) s -5 393 M -( o if any of the other algorithms cannot be agreed upon \(the) s -5 382 M -( procedure is defined below in Section Section 6.1\).) s -5 360 M -( Otherwise, the guess is considered to be right and the optimistically) s -5 349 M -( sent packet MUST be handled as the first key exchange packet.) s -5 327 M -( However, if the guess was wrong, and a packet was optimistically sent) s -5 316 M -( by one or both parties, such packets MUST be ignored \(even if the) s -5 305 M -( error in the guess would not affect the contents of the initial) s -5 294 M -( packet\(s\)\), and the appropriate side MUST send the correct initial) s -5 283 M -( packet.) s -5 261 M -( Server authentication in the key exchange MAY be implicit. After a) s -5 250 M -( key exchange with implicit server authentication, the client MUST) s -5 239 M -( wait for response to its service request message before sending any) s -5 228 M -( further data.) s -5 206 M -(6.1 Algorithm Negotiation) s -5 184 M -( Key exchange begins by each side sending the following packet:) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 13]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 14 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Transport Layer Protocol Oct 2003) s -5 690 M -( byte SSH_MSG_KEXINIT) s -5 679 M -( byte[16] cookie \(random bytes\)) s -5 668 M -( string kex_algorithms) s -5 657 M -( string server_host_key_algorithms) s -5 646 M -( string encryption_algorithms_client_to_server) s -5 635 M -( string encryption_algorithms_server_to_client) s -5 624 M -( string mac_algorithms_client_to_server) s -5 613 M -( string mac_algorithms_server_to_client) s -5 602 M -( string compression_algorithms_client_to_server) s -5 591 M -( string compression_algorithms_server_to_client) s -5 580 M -( string languages_client_to_server) s -5 569 M -( string languages_server_to_client) s -5 558 M -( boolean first_kex_packet_follows) s -5 547 M -( uint32 0 \(reserved for future extension\)) s -5 525 M -( Each of the algorithm strings MUST be a comma-separated list of) s -5 514 M -( algorithm names \(see ''Algorithm Naming'' in [SSH-ARCH]\). Each) s -5 503 M -( supported \(allowed\) algorithm MUST be listed in order of preference.) s -5 481 M -( The first algorithm in each list MUST be the preferred \(guessed\)) s -5 470 M -( algorithm. Each string MUST contain at least one algorithm name.) s -5 437 M -( cookie) s -5 426 M -( The cookie MUST be a random value generated by the sender. Its) s -5 415 M -( purpose is to make it impossible for either side to fully) s -5 404 M -( determine the keys and the session identifier.) s -5 382 M -( kex_algorithms) s -5 371 M -( Key exchange algorithms were defined above. The first) s -5 360 M -( algorithm MUST be the preferred \(and guessed\) algorithm. If) s -5 349 M -( both sides make the same guess, that algorithm MUST be used.) s -5 338 M -( Otherwise, the following algorithm MUST be used to choose a key) s -5 327 M -( exchange method: iterate over client's kex algorithms, one at a) s -5 316 M -( time. Choose the first algorithm that satisfies the following) s -5 305 M -( conditions:) s -5 294 M -( + the server also supports the algorithm,) s -5 283 M -( + if the algorithm requires an encryption-capable host key,) s -5 272 M -( there is an encryption-capable algorithm on the server's) s -5 261 M -( server_host_key_algorithms that is also supported by the) s -5 250 M -( client, and) s -5 239 M -( + if the algorithm requires a signature-capable host key,) s -5 228 M -( there is a signature-capable algorithm on the server's) s -5 217 M -( server_host_key_algorithms that is also supported by the) s -5 206 M -( client.) s -5 195 M -( + If no algorithm satisfying all these conditions can be) s -5 184 M -( found, the connection fails, and both sides MUST disconnect.) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 14]) s -_R -S -PStoPSsaved restore -%%Page: (14,15) 8 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 15 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Transport Layer Protocol Oct 2003) s -5 690 M -( server_host_key_algorithms) s -5 679 M -( List of the algorithms supported for the server host key. The) s -5 668 M -( server lists the algorithms for which it has host keys; the) s -5 657 M -( client lists the algorithms that it is willing to accept.) s -5 646 M -( \(There MAY be multiple host keys for a host, possibly with) s -5 635 M -( different algorithms.\)) s -5 613 M -( Some host keys may not support both signatures and encryption) s -5 602 M -( \(this can be determined from the algorithm\), and thus not all) s -5 591 M -( host keys are valid for all key exchange methods.) s -5 569 M -( Algorithm selection depends on whether the chosen key exchange) s -5 558 M -( algorithm requires a signature or encryption capable host key.) s -5 547 M -( It MUST be possible to determine this from the public key) s -5 536 M -( algorithm name. The first algorithm on the client's list that) s -5 525 M -( satisfies the requirements and is also supported by the server) s -5 514 M -( MUST be chosen. If there is no such algorithm, both sides MUST) s -5 503 M -( disconnect.) s -5 481 M -( encryption_algorithms) s -5 470 M -( Lists the acceptable symmetric encryption algorithms in order) s -5 459 M -( of preference. The chosen encryption algorithm to each) s -5 448 M -( direction MUST be the first algorithm on the client's list) s -5 437 M -( that is also on the server's list. If there is no such) s -5 426 M -( algorithm, both sides MUST disconnect.) s -5 404 M -( Note that "none" must be explicitly listed if it is to be) s -5 393 M -( acceptable. The defined algorithm names are listed in Section) s -5 382 M -( Section 5.3.) s -5 360 M -( mac_algorithms) s -5 349 M -( Lists the acceptable MAC algorithms in order of preference.) s -5 338 M -( The chosen MAC algorithm MUST be the first algorithm on the) s -5 327 M -( client's list that is also on the server's list. If there is) s -5 316 M -( no such algorithm, both sides MUST disconnect.) s -5 294 M -( Note that "none" must be explicitly listed if it is to be) s -5 283 M -( acceptable. The MAC algorithm names are listed in Section) s -5 272 M -( Figure 1.) s -5 250 M -( compression_algorithms) s -5 239 M -( Lists the acceptable compression algorithms in order of) s -5 228 M -( preference. The chosen compression algorithm MUST be the first) s -5 217 M -( algorithm on the client's list that is also on the server's) s -5 206 M -( list. If there is no such algorithm, both sides MUST) s -5 195 M -( disconnect.) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 15]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 16 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Transport Layer Protocol Oct 2003) s -5 690 M -( Note that "none" must be explicitly listed if it is to be) s -5 679 M -( acceptable. The compression algorithm names are listed in) s -5 668 M -( Section Section 5.2.) s -5 646 M -( languages) s -5 635 M -( This is a comma-separated list of language tags in order of) s -5 624 M -( preference [RFC3066]. Both parties MAY ignore this list. If) s -5 613 M -( there are no language preferences, this list SHOULD be empty.) s -5 602 M -( Language tags SHOULD NOT be present unless they are known to be) s -5 591 M -( needed by the sending party.) s -5 569 M -( first_kex_packet_follows) s -5 558 M -( Indicates whether a guessed key exchange packet follows. If a) s -5 547 M -( guessed packet will be sent, this MUST be TRUE. If no guessed) s -5 536 M -( packet will be sent, this MUST be FALSE.) s -5 514 M -( After receiving the SSH_MSG_KEXINIT packet from the other side,) s -5 503 M -( each party will know whether their guess was right. If the) s -5 492 M -( other party's guess was wrong, and this field was TRUE, the) s -5 481 M -( next packet MUST be silently ignored, and both sides MUST then) s -5 470 M -( act as determined by the negotiated key exchange method. If) s -5 459 M -( the guess was right, key exchange MUST continue using the) s -5 448 M -( guessed packet.) s -5 426 M -( After the KEXINIT packet exchange, the key exchange algorithm is run.) s -5 415 M -( It may involve several packet exchanges, as specified by the key) s -5 404 M -( exchange method.) s -5 382 M -(6.2 Output from Key Exchange) s -5 360 M -( The key exchange produces two values: a shared secret K, and an) s -5 349 M -( exchange hash H. Encryption and authentication keys are derived from) s -5 338 M -( these. The exchange hash H from the first key exchange is) s -5 327 M -( additionally used as the session identifier, which is a unique) s -5 316 M -( identifier for this connection. It is used by authentication methods) s -5 305 M -( as a part of the data that is signed as a proof of possession of a) s -5 294 M -( private key. Once computed, the session identifier is not changed,) s -5 283 M -( even if keys are later re-exchanged.) s -5 250 M -( Each key exchange method specifies a hash function that is used in) s -5 239 M -( the key exchange. The same hash algorithm MUST be used in key) s -5 228 M -( derivation. Here, we'll call it HASH.) s -5 195 M -( Encryption keys MUST be computed as HASH of a known value and K as) s -5 184 M -( follows:) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 16]) s -_R -S -PStoPSsaved restore -%%Page: (16,17) 9 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 17 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Transport Layer Protocol Oct 2003) s -5 690 M -( o Initial IV client to server: HASH\(K || H || "A" || session_id\)) s -5 679 M -( \(Here K is encoded as mpint and "A" as byte and session_id as raw) s -5 668 M -( data."A" means the single character A, ASCII 65\).) s -5 657 M -( o Initial IV server to client: HASH\(K || H || "B" || session_id\)) s -5 646 M -( o Encryption key client to server: HASH\(K || H || "C" || session_id\)) s -5 635 M -( o Encryption key server to client: HASH\(K || H || "D" || session_id\)) s -5 624 M -( o Integrity key client to server: HASH\(K || H || "E" || session_id\)) s -5 613 M -( o Integrity key server to client: HASH\(K || H || "F" || session_id\)) s -5 591 M -( Key data MUST be taken from the beginning of the hash output. 128) s -5 580 M -( bits \(16 bytes\) MUST be used for algorithms with variable-length) s -5 569 M -( keys. The only variable key length algorithm defined in this document) s -5 558 M -( is arcfour\). For other algorithms, as many bytes as are needed are) s -5 547 M -( taken from the beginning of the hash value. If the key length needed) s -5 536 M -( is longer than the output of the HASH, the key is extended by) s -5 525 M -( computing HASH of the concatenation of K and H and the entire key so) s -5 514 M -( far, and appending the resulting bytes \(as many as HASH generates\) to) s -5 503 M -( the key. This process is repeated until enough key material is) s -5 492 M -( available; the key is taken from the beginning of this value. In) s -5 481 M -( other words:) s -5 459 M -( K1 = HASH\(K || H || X || session_id\) \(X is e.g. "A"\)) s -5 448 M -( K2 = HASH\(K || H || K1\)) s -5 437 M -( K3 = HASH\(K || H || K1 || K2\)) s -5 426 M -( ...) s -5 415 M -( key = K1 || K2 || K3 || ...) s -5 393 M -( This process will lose entropy if the amount of entropy in K is) s -5 382 M -( larger than the internal state size of HASH.) s -5 360 M -(6.3 Taking Keys Into Use) s -5 338 M -( Key exchange ends by each side sending an SSH_MSG_NEWKEYS message.) s -5 327 M -( This message is sent with the old keys and algorithms. All messages) s -5 316 M -( sent after this message MUST use the new keys and algorithms.) s -5 283 M -( When this message is received, the new keys and algorithms MUST be) s -5 272 M -( taken into use for receiving.) s -5 239 M -( This message is the only valid message after key exchange, in) s -5 228 M -( addition to SSH_MSG_DEBUG, SSH_MSG_DISCONNECT and SSH_MSG_IGNORE) s -5 217 M -( messages. The purpose of this message is to ensure that a party is) s -5 206 M -( able to respond with a disconnect message that the other party can) s -5 195 M -( understand if something goes wrong with the key exchange.) s -5 184 M -( Implementations MUST NOT accept any other messages after key exchange) s -5 173 M -( before receiving SSH_MSG_NEWKEYS.) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 17]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 18 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Transport Layer Protocol Oct 2003) s -5 690 M -( byte SSH_MSG_NEWKEYS) s -5 657 M -(7. Diffie-Hellman Key Exchange) s -5 635 M -( The Diffie-Hellman key exchange provides a shared secret that can not) s -5 624 M -( be determined by either party alone. The key exchange is combined) s -5 613 M -( with a signature with the host key to provide host authentication.) s -5 580 M -( In the following description \(C is the client, S is the server; p is) s -5 569 M -( a large safe prime, g is a generator for a subgroup of GF\(p\), and q) s -5 558 M -( is the order of the subgroup; V_S is S's version string; V_C is C's) s -5 547 M -( version string; K_S is S's public host key; I_C is C's KEXINIT) s -5 536 M -( message and I_S S's KEXINIT message which have been exchanged before) s -5 525 M -( this part begins\):) s -5 492 M -( 1. C generates a random number x \(1 < x < q\) and computes e = g^x) s -5 481 M -( mod p. C sends "e" to S.) s -5 459 M -( 2. S generates a random number y \(0 < y < q\) and computes f = g^y) s -5 448 M -( mod p. S receives "e". It computes K = e^y mod p, H = hash\(V_C) s -5 437 M -( || V_S || I_C || I_S || K_S || e || f || K\) \(these elements are) s -5 426 M -( encoded according to their types; see below\), and signature s on) s -5 415 M -( H with its private host key. S sends "K_S || f || s" to C. The) s -5 404 M -( signing operation may involve a second hashing operation.) s -5 382 M -( 3. C verifies that K_S really is the host key for S \(e.g. using) s -5 371 M -( certificates or a local database\). C is also allowed to accept) s -5 360 M -( the key without verification; however, doing so will render the) s -5 349 M -( protocol insecure against active attacks \(but may be desirable) s -5 338 M -( for practical reasons in the short term in many environments\). C) s -5 327 M -( then computes K = f^x mod p, H = hash\(V_C || V_S || I_C || I_S ||) s -5 316 M -( K_S || e || f || K\), and verifies the signature s on H.) s -5 294 M -( Either side MUST NOT send or accept e or f values that are not in the) s -5 283 M -( range [1, p-1]. If this condition is violated, the key exchange) s -5 272 M -( fails.) s -5 239 M -( This is implemented with the following messages. The hash algorithm) s -5 228 M -( for computing the exchange hash is defined by the method name, and is) s -5 217 M -( called HASH. The public key algorithm for signing is negotiated with) s -5 206 M -( the KEXINIT messages.) s -5 184 M -( First, the client sends the following:) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 18]) s -_R -S -PStoPSsaved restore -%%Page: (18,19) 10 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 19 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Transport Layer Protocol Oct 2003) s -5 690 M -( byte SSH_MSG_KEXDH_INIT) s -5 679 M -( mpint e) s -5 646 M -( The server responds with the following:) s -5 624 M -( byte SSH_MSG_KEXDH_REPLY) s -5 613 M -( string server public host key and certificates \(K_S\)) s -5 602 M -( mpint f) s -5 591 M -( string signature of H) s -5 569 M -( The hash H is computed as the HASH hash of the concatenation of the) s -5 558 M -( following:) s -5 536 M -( string V_C, the client's version string \(CR and NL excluded\)) s -5 525 M -( string V_S, the server's version string \(CR and NL excluded\)) s -5 514 M -( string I_C, the payload of the client's SSH_MSG_KEXINIT) s -5 503 M -( string I_S, the payload of the server's SSH_MSG_KEXINIT) s -5 492 M -( string K_S, the host key) s -5 481 M -( mpint e, exchange value sent by the client) s -5 470 M -( mpint f, exchange value sent by the server) s -5 459 M -( mpint K, the shared secret) s -5 437 M -( This value is called the exchange hash, and it is used to) s -5 426 M -( authenticate the key exchange. The exchange hash SHOULD be kept) s -5 415 M -( secret.) s -5 382 M -( The signature algorithm MUST be applied over H, not the original) s -5 371 M -( data. Most signature algorithms include hashing and additional) s -5 360 M -( padding. For example, "ssh-dss" specifies SHA-1 hashing; in that) s -5 349 M -( case, the data is first hashed with HASH to compute H, and H is then) s -5 338 M -( hashed with SHA-1 as part of the signing operation.) s -5 316 M -(7.1 diffie-hellman-group1-sha1) s -5 294 M -( The "diffie-hellman-group1-sha1" method specifies Diffie-Hellman key) s -5 283 M -( exchange with SHA-1 as HASH, and Oakley group 14 [RFC3526] \(2048-bit) s -5 272 M -( MODP Group\). It is included below in hexadecimal and decimal.) s -5 250 M -( The prime p is equal to 2^1024 - 2^960 - 1 + 2^64 * floor\( 2^894 Pi +) s -5 239 M -( 129093 \). Its hexadecimal value is:) s -5 217 M -( FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1) s -5 206 M -( 29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD) s -5 195 M -( EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245) s -5 184 M -( E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED) s -5 173 M -( EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 19]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 20 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Transport Layer Protocol Oct 2003) s -5 690 M -( FFFFFFFF FFFFFFFF.) s -5 668 M -( In decimal, this value is:) s -5 646 M -( 179769313486231590770839156793787453197860296048756011706444) s -5 635 M -( 423684197180216158519368947833795864925541502180565485980503) s -5 624 M -( 646440548199239100050792877003355816639229553136239076508735) s -5 613 M -( 759914822574862575007425302077447712589550957937778424442426) s -5 602 M -( 617334727629299387668709205606050270810842907692932019128194) s -5 591 M -( 467627007.) s -5 569 M -( The generator used with this prime is g = 2. The group order q is \(p) s -5 558 M -( - 1\) / 2.) s -5 536 M -(8. Key Re-Exchange) s -5 514 M -( Key re-exchange is started by sending an SSH_MSG_KEXINIT packet when) s -5 503 M -( not already doing a key exchange \(as described in Section Section) s -5 492 M -( 6.1\). When this message is received, a party MUST respond with its) s -5 481 M -( own SSH_MSG_KEXINIT message except when the received SSH_MSG_KEXINIT) s -5 470 M -( already was a reply. Either party MAY initiate the re-exchange, but) s -5 459 M -( roles MUST NOT be changed \(i.e., the server remains the server, and) s -5 448 M -( the client remains the client\).) s -5 415 M -( Key re-exchange is performed using whatever encryption was in effect) s -5 404 M -( when the exchange was started. Encryption, compression, and MAC) s -5 393 M -( methods are not changed before a new SSH_MSG_NEWKEYS is sent after) s -5 382 M -( the key exchange \(as in the initial key exchange\). Re-exchange is) s -5 371 M -( processed identically to the initial key exchange, except for the) s -5 360 M -( session identifier that will remain unchanged. It is permissible to) s -5 349 M -( change some or all of the algorithms during the re-exchange. Host) s -5 338 M -( keys can also change. All keys and initialization vectors are) s -5 327 M -( recomputed after the exchange. Compression and encryption contexts) s -5 316 M -( are reset.) s -5 283 M -( It is recommended that the keys are changed after each gigabyte of) s -5 272 M -( transmitted data or after each hour of connection time, whichever) s -5 261 M -( comes sooner. However, since the re-exchange is a public key) s -5 250 M -( operation, it requires a fair amount of processing power and should) s -5 239 M -( not be performed too often.) s -5 206 M -( More application data may be sent after the SSH_MSG_NEWKEYS packet) s -5 195 M -( has been sent; key exchange does not affect the protocols that lie) s -5 184 M -( above the SSH transport layer.) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 20]) s -_R -S -PStoPSsaved restore -%%Page: (20,21) 11 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 21 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Transport Layer Protocol Oct 2003) s -5 690 M -(9. Service Request) s -5 668 M -( After the key exchange, the client requests a service. The service is) s -5 657 M -( identified by a name. The format of names and procedures for defining) s -5 646 M -( new names are defined in [SSH-ARCH].) s -5 613 M -( Currently, the following names have been reserved:) s -5 591 M -( ssh-userauth) s -5 580 M -( ssh-connection) s -5 558 M -( Similar local naming policy is applied to the service names, as is) s -5 547 M -( applied to the algorithm names; a local service should use the) s -5 536 M -( "servicename@domain" syntax.) s -5 514 M -( byte SSH_MSG_SERVICE_REQUEST) s -5 503 M -( string service name) s -5 481 M -( If the server rejects the service request, it SHOULD send an) s -5 470 M -( appropriate SSH_MSG_DISCONNECT message and MUST disconnect.) s -5 437 M -( When the service starts, it may have access to the session identifier) s -5 426 M -( generated during the key exchange.) s -5 393 M -( If the server supports the service \(and permits the client to use) s -5 382 M -( it\), it MUST respond with the following:) s -5 360 M -( byte SSH_MSG_SERVICE_ACCEPT) s -5 349 M -( string service name) s -5 327 M -( Message numbers used by services should be in the area reserved for) s -5 316 M -( them \(see Section 6 in [SSH-ARCH]\). The transport level will) s -5 305 M -( continue to process its own messages.) s -5 272 M -( Note that after a key exchange with implicit server authentication,) s -5 261 M -( the client MUST wait for response to its service request message) s -5 250 M -( before sending any further data.) s -5 228 M -(10. Additional Messages) s -5 206 M -( Either party may send any of the following messages at any time.) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 21]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 22 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Transport Layer Protocol Oct 2003) s -5 690 M -(10.1 Disconnection Message) s -5 668 M -( byte SSH_MSG_DISCONNECT) s -5 657 M -( uint32 reason code) s -5 646 M -( string description [RFC2279]) s -5 635 M -( string language tag [RFC3066]) s -5 613 M -( This message causes immediate termination of the connection. All) s -5 602 M -( implementations MUST be able to process this message; they SHOULD be) s -5 591 M -( able to send this message.) s -5 569 M -( The sender MUST NOT send or receive any data after this message, and) s -5 558 M -( the recipient MUST NOT accept any data after receiving this message.) s -5 547 M -( The description field gives a more specific explanation in a) s -5 536 M -( human-readable form. The error code gives the reason in a more) s -5 525 M -( machine-readable format \(suitable for localization\), and can have the) s -5 514 M -( following values:) s -5 492 M -( #define SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1) s -5 481 M -( #define SSH_DISCONNECT_PROTOCOL_ERROR 2) s -5 470 M -( #define SSH_DISCONNECT_KEY_EXCHANGE_FAILED 3) s -5 459 M -( #define SSH_DISCONNECT_RESERVED 4) s -5 448 M -( #define SSH_DISCONNECT_MAC_ERROR 5) s -5 437 M -( #define SSH_DISCONNECT_COMPRESSION_ERROR 6) s -5 426 M -( #define SSH_DISCONNECT_SERVICE_NOT_AVAILABLE 7) s -5 415 M -( #define SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8) s -5 404 M -( #define SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9) s -5 393 M -( #define SSH_DISCONNECT_CONNECTION_LOST 10) s -5 382 M -( #define SSH_DISCONNECT_BY_APPLICATION 11) s -5 371 M -( #define SSH_DISCONNECT_TOO_MANY_CONNECTIONS 12) s -5 360 M -( #define SSH_DISCONNECT_AUTH_CANCELLED_BY_USER 13) s -5 349 M -( #define SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14) s -5 338 M -( #define SSH_DISCONNECT_ILLEGAL_USER_NAME 15) s -5 316 M -( If the description string is displayed, control character filtering) s -5 305 M -( discussed in [SSH-ARCH] should be used to avoid attacks by sending) s -5 294 M -( terminal control characters.) s -5 272 M -(10.2 Ignored Data Message) s -5 250 M -( byte SSH_MSG_IGNORE) s -5 239 M -( string data) s -5 217 M -( All implementations MUST understand \(and ignore\) this message at any) s -5 206 M -( time \(after receiving the protocol version\). No implementation is) s -5 195 M -( required to send them. This message can be used as an additional) s -5 184 M -( protection measure against advanced traffic analysis techniques.) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 22]) s -_R -S -PStoPSsaved restore -%%Page: (22,23) 12 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 23 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Transport Layer Protocol Oct 2003) s -5 690 M -(10.3 Debug Message) s -5 668 M -( byte SSH_MSG_DEBUG) s -5 657 M -( boolean always_display) s -5 646 M -( string message [RFC2279]) s -5 635 M -( string language tag [RFC3066]) s -5 613 M -( All implementations MUST understand this message, but they are) s -5 602 M -( allowed to ignore it. This message is used to pass the other side) s -5 591 M -( information that may help debugging. If always_display is TRUE, the) s -5 580 M -( message SHOULD be displayed. Otherwise, it SHOULD NOT be displayed) s -5 569 M -( unless debugging information has been explicitly requested by the) s -5 558 M -( user.) s -5 525 M -( The message doesn't need to contain a newline. It is, however,) s -5 514 M -( allowed to consist of multiple lines separated by CRLF \(Carriage) s -5 503 M -( Return - Line Feed\) pairs.) s -5 470 M -( If the message string is displayed, terminal control character) s -5 459 M -( filtering discussed in [SSH-ARCH] should be used to avoid attacks by) s -5 448 M -( sending terminal control characters.) s -5 426 M -(10.4 Reserved Messages) s -5 404 M -( An implementation MUST respond to all unrecognized messages with an) s -5 393 M -( SSH_MSG_UNIMPLEMENTED message in the order in which the messages were) s -5 382 M -( received. Such messages MUST be otherwise ignored. Later protocol) s -5 371 M -( versions may define other meanings for these message types.) s -5 349 M -( byte SSH_MSG_UNIMPLEMENTED) s -5 338 M -( uint32 packet sequence number of rejected message) s -5 305 M -(11. Summary of Message Numbers) s -5 283 M -( The following message numbers have been defined in this protocol:) s -5 261 M -( #define SSH_MSG_DISCONNECT 1) s -5 250 M -( #define SSH_MSG_IGNORE 2) s -5 239 M -( #define SSH_MSG_UNIMPLEMENTED 3) s -5 228 M -( #define SSH_MSG_DEBUG 4) s -5 217 M -( #define SSH_MSG_SERVICE_REQUEST 5) s -5 206 M -( #define SSH_MSG_SERVICE_ACCEPT 6) s -5 184 M -( #define SSH_MSG_KEXINIT 20) s -5 173 M -( #define SSH_MSG_NEWKEYS 21) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 23]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 24 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Transport Layer Protocol Oct 2003) s -5 690 M -( /* Numbers 30-49 used for kex packets.) s -5 679 M -( Different kex methods may reuse message numbers in) s -5 668 M -( this range. */) s -5 646 M -( #define SSH_MSG_KEXDH_INIT 30) s -5 635 M -( #define SSH_MSG_KEXDH_REPLY 31) s -5 602 M -(12. IANA Considerations) s -5 580 M -( This document is part of a set, the IANA considerations for the SSH) s -5 569 M -( protocol as defined in [SSH-ARCH], [SSH-TRANS], [SSH-USERAUTH],) s -5 558 M -( [SSH-CONNECT] are detailed in [SSH-NUMBERS].) s -5 536 M -(13. Security Considerations) s -5 514 M -( This protocol provides a secure encrypted channel over an insecure) s -5 503 M -( network. It performs server host authentication, key exchange,) s -5 492 M -( encryption, and integrity protection. It also derives a unique) s -5 481 M -( session id that may be used by higher-level protocols.) s -5 459 M -( Full security considerations for this protocol are provided in) s -5 448 M -( Section 8 of [SSH-ARCH]) s -5 426 M -(14. Intellectual Property) s -5 404 M -( The IETF takes no position regarding the validity or scope of any) s -5 393 M -( intellectual property or other rights that might be claimed to) s -5 382 M -( pertain to the implementation or use of the technology described in) s -5 371 M -( this document or the extent to which any license under such rights) s -5 360 M -( might or might not be available; neither does it represent that it) s -5 349 M -( has made any effort to identify any such rights. Information on the) s -5 338 M -( IETF's procedures with respect to rights in standards-track and) s -5 327 M -( standards-related documentation can be found in BCP-11. Copies of) s -5 316 M -( claims of rights made available for publication and any assurances of) s -5 305 M -( licenses to be made available, or the result of an attempt made to) s -5 294 M -( obtain a general license or permission for the use of such) s -5 283 M -( proprietary rights by implementers or users of this specification can) s -5 272 M -( be obtained from the IETF Secretariat.) s -5 250 M -( The IETF has been notified of intellectual property rights claimed in) s -5 239 M -( regard to some or all of the specification contained in this) s -5 228 M -( document. For more information consult the online list of claimed) s -5 217 M -( rights.) s -5 195 M -(15. Additional Information) s -5 173 M -( The current document editor is: [email protected]. Comments on) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 24]) s -_R -S -PStoPSsaved restore -%%Page: (24,25) 13 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 25 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Transport Layer Protocol Oct 2003) s -5 690 M -( this internet draft should be sent to the IETF SECSH working group,) s -5 679 M -( details at: http://ietf.org/html.charters/secsh-charter.html) s -5 657 M -(Normative) s -5 635 M -( [SSH-ARCH]) s -5 624 M -( Ylonen, T., "SSH Protocol Architecture", I-D) s -5 613 M -( draft-ietf-architecture-15.txt, Oct 2003.) s -5 591 M -( [SSH-TRANS]) s -5 580 M -( Ylonen, T., "SSH Transport Layer Protocol", I-D) s -5 569 M -( draft-ietf-transport-17.txt, Oct 2003.) s -5 547 M -( [SSH-USERAUTH]) s -5 536 M -( Ylonen, T., "SSH Authentication Protocol", I-D) s -5 525 M -( draft-ietf-userauth-18.txt, Oct 2003.) s -5 503 M -( [SSH-CONNECT]) s -5 492 M -( Ylonen, T., "SSH Connection Protocol", I-D) s -5 481 M -( draft-ietf-connect-18.txt, Oct 2003.) s -5 459 M -( [SSH-NUMBERS]) s -5 448 M -( Lehtinen, S. and D. Moffat, "SSH Protocol Assigned) s -5 437 M -( Numbers", I-D draft-ietf-secsh-assignednumbers-05.txt, Oct) s -5 426 M -( 2003.) s -5 404 M -( [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate) s -5 393 M -( Requirement Levels", BCP 14, RFC 2119, March 1997.) s -5 371 M -(Informative) s -5 349 M -( [FIPS-186]) s -5 338 M -( Federal Information Processing Standards Publication,) s -5 327 M -( "FIPS PUB 186, Digital Signature Standard", May 1994.) s -5 305 M -( [FIPS-197]) s -5 294 M -( NIST, "FIPS PUB 197 Advanced Encryption Standard \(AES\)",) s -5 283 M -( November 2001.) s -5 261 M -( [FIPS-46-3]) s -5 250 M -( U.S. Dept. of Commerce, "FIPS PUB 46-3, Data Encryption) s -5 239 M -( Standard \(DES\)", October 1999.) s -5 217 M -( [RFC2459] Housley, R., Ford, W., Polk, T. and D. Solo, "Internet) s -5 206 M -( X.509 Public Key Infrastructure Certificate and CRL) s -5 195 M -( Profile", RFC 2459, January 1999.) s -5 173 M -( [RFC1034] Mockapetris, P., "Domain names - concepts and facilities",) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 25]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 26 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Transport Layer Protocol Oct 2003) s -5 690 M -( STD 13, RFC 1034, November 1987.) s -5 668 M -( [RFC3066] Alvestrand, H., "Tags for the Identification of) s -5 657 M -( Languages", BCP 47, RFC 3066, January 2001.) s -5 635 M -( [RFC1950] Deutsch, L. and J-L. Gailly, "ZLIB Compressed Data Format) s -5 624 M -( Specification version 3.3", RFC 1950, May 1996.) s -5 602 M -( [RFC1951] Deutsch, P., "DEFLATE Compressed Data Format Specification) s -5 591 M -( version 1.3", RFC 1951, May 1996.) s -5 569 M -( [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO) s -5 558 M -( 10646", RFC 2279, January 1998.) s -5 536 M -( [RFC2104] Krawczyk, H., Bellare, M. and R. Canetti, "HMAC:) s -5 525 M -( Keyed-Hashing for Message Authentication", RFC 2104,) s -5 514 M -( February 1997.) s -5 492 M -( [RFC2144] Adams, C., "The CAST-128 Encryption Algorithm", RFC 2144,) s -5 481 M -( May 1997.) s -5 459 M -( [RFC2440] Callas, J., Donnerhacke, L., Finney, H. and R. Thayer,) s -5 448 M -( "OpenPGP Message Format", RFC 2440, November 1998.) s -5 426 M -( [RFC2693] Ellison, C., Frantz, B., Lampson, B., Rivest, R., Thomas,) s -5 415 M -( B. and T. Ylonen, "SPKI Certificate Theory", RFC 2693,) s -5 404 M -( September 1999.) s -5 382 M -( [RFC3526] Kivinen, T. and M. Kojo, "More Modular Exponential \(MODP\)) s -5 371 M -( Diffie-Hellman groups for Internet Key Exchange \(IKE\)",) s -5 360 M -( RFC 3526, May 2003.) s -5 338 M -( [SCHNEIER]) s -5 327 M -( Schneier, B., "Applied Cryptography Second Edition:) s -5 316 M -( protocols algorithms and source in code in C", 1996.) s -5 294 M -( [TWOFISH] Schneier, B., "The Twofish Encryptions Algorithm: A) s -5 283 M -( 128-Bit Block Cipher, 1st Edition", March 1999.) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 26]) s -_R -S -PStoPSsaved restore -%%Page: (26,27) 14 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 27 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Transport Layer Protocol Oct 2003) s -5 690 M -(Authors' Addresses) s -5 668 M -( Tatu Ylonen) s -5 657 M -( SSH Communications Security Corp) s -5 646 M -( Fredrikinkatu 42) s -5 635 M -( HELSINKI FIN-00100) s -5 624 M -( Finland) s -5 602 M -( EMail: [email protected]) s -5 569 M -( Darren J. Moffat \(editor\)) s -5 558 M -( Sun Microsystems, Inc) s -5 547 M -( 17 Network Circle) s -5 536 M -( Menlo Park 95025) s -5 525 M -( USA) s -5 503 M -( EMail: [email protected]) s -5 481 M -(Appendix A. Contibutors) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 27]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 28 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Transport Layer Protocol Oct 2003) s -5 690 M -(Intellectual Property Statement) s -5 668 M -( The IETF takes no position regarding the validity or scope of any) s -5 657 M -( intellectual property or other rights that might be claimed to) s -5 646 M -( pertain to the implementation or use of the technology described in) s -5 635 M -( this document or the extent to which any license under such rights) s -5 624 M -( might or might not be available; neither does it represent that it) s -5 613 M -( has made any effort to identify any such rights. Information on the) s -5 602 M -( IETF's procedures with respect to rights in standards-track and) s -5 591 M -( standards-related documentation can be found in BCP-11. Copies of) s -5 580 M -( claims of rights made available for publication and any assurances of) s -5 569 M -( licenses to be made available, or the result of an attempt made to) s -5 558 M -( obtain a general license or permission for the use of such) s -5 547 M -( proprietary rights by implementors or users of this specification can) s -5 536 M -( be obtained from the IETF Secretariat.) s -5 514 M -( The IETF invites any interested party to bring to its attention any) s -5 503 M -( copyrights, patents or patent applications, or other proprietary) s -5 492 M -( rights which may cover technology that may be required to practice) s -5 481 M -( this standard. Please address the information to the IETF Executive) s -5 470 M -( Director.) s -5 448 M -( The IETF has been notified of intellectual property rights claimed in) s -5 437 M -( regard to some or all of the specification contained in this) s -5 426 M -( document. For more information consult the online list of claimed) s -5 415 M -( rights.) s -5 382 M -(Full Copyright Statement) s -5 360 M -( Copyright \(C\) The Internet Society \(2003\). All Rights Reserved.) s -5 338 M -( This document and translations of it may be copied and furnished to) s -5 327 M -( others, and derivative works that comment on or otherwise explain it) s -5 316 M -( or assist in its implementation may be prepared, copied, published) s -5 305 M -( and distributed, in whole or in part, without restriction of any) s -5 294 M -( kind, provided that the above copyright notice and this paragraph are) s -5 283 M -( included on all such copies and derivative works. However, this) s -5 272 M -( document itself may not be modified in any way, such as by removing) s -5 261 M -( the copyright notice or references to the Internet Society or other) s -5 250 M -( Internet organizations, except as needed for the purpose of) s -5 239 M -( developing Internet standards in which case the procedures for) s -5 228 M -( copyrights defined in the Internet Standards process must be) s -5 217 M -( followed, or as required to translate it into languages other than) s -5 206 M -( English.) s -5 184 M -( The limited permissions granted above are perpetual and will not be) s -5 173 M -( revoked by the Internet Society or its successors or assignees.) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 28]) s -_R -S -PStoPSsaved restore -%%Page: (28,29) 15 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 29 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Transport Layer Protocol Oct 2003) s -5 690 M -( This document and the information contained herein is provided on an) s -5 679 M -( "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING) s -5 668 M -( TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING) s -5 657 M -( BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION) s -5 646 M -( HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF) s -5 635 M -( MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.) s -5 602 M -(Acknowledgment) s -5 580 M -( Funding for the RFC Editor function is currently provided by the) s -5 569 M -( Internet Society.) s -5 129 M -(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 29]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -showpage -PStoPSsaved restore -%%Trailer -%%Pages: 29 -%%DocumentNeededResources: font Courier-Bold Courier -%%EOF diff --git a/lib/ssh/doc/standard/draft-ietf-secsh-transport-17.txt b/lib/ssh/doc/standard/draft-ietf-secsh-transport-17.txt deleted file mode 100644 index 9073ea52b2..0000000000 --- a/lib/ssh/doc/standard/draft-ietf-secsh-transport-17.txt +++ /dev/null @@ -1,1624 +0,0 @@ - - - -Network Working Group T. Ylonen -Internet-Draft SSH Communications Security Corp -Expires: March 31, 2004 D. Moffat, Editor, Ed. - Sun Microsystems, Inc - Oct 2003 - - - SSH Transport Layer Protocol - draft-ietf-secsh-transport-17.txt - -Status of this Memo - - This document is an Internet-Draft and is in full conformance with - all provisions of Section 10 of RFC2026. - - Internet-Drafts are working documents of the Internet Engineering - Task Force (IETF), its areas, and its working groups. Note that other - groups may also distribute working documents as Internet-Drafts. - - Internet-Drafts are draft documents valid for a maximum of six months - and may be updated, replaced, or obsoleted by other documents at any - time. It is inappropriate to use Internet-Drafts as reference - material or to cite them other than as "work in progress." - - The list of current Internet-Drafts can be accessed at http:// - www.ietf.org/ietf/1id-abstracts.txt. - - The list of Internet-Draft Shadow Directories can be accessed at - http://www.ietf.org/shadow.html. - - This Internet-Draft will expire on March 31, 2004. - -Copyright Notice - - Copyright (C) The Internet Society (2003). All Rights Reserved. - -Abstract - - SSH is a protocol for secure remote login and other secure network - services over an insecure network. - - This document describes the SSH transport layer protocol which - typically runs on top of TCP/IP. The protocol can be used as a basis - for a number of secure network services. It provides strong - encryption, server authentication, and integrity protection. It may - also provide compression. - - Key exchange method, public key algorithm, symmetric encryption - algorithm, message authentication algorithm, and hash algorithm are - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 1] - -Internet-Draft SSH Transport Layer Protocol Oct 2003 - - - all negotiated. - - This document also describes the Diffie-Hellman key exchange method - and the minimal set of algorithms that are needed to implement the - SSH transport layer protocol. - -Table of Contents - - 1. Contributors . . . . . . . . . . . . . . . . . . . . . . . . 3 - 2. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 - 3. Conventions Used in This Document . . . . . . . . . . . . . 3 - 4. Connection Setup . . . . . . . . . . . . . . . . . . . . . . 3 - 4.1 Use over TCP/IP . . . . . . . . . . . . . . . . . . . . . . 4 - 4.2 Protocol Version Exchange . . . . . . . . . . . . . . . . . 4 - 4.3 Compatibility With Old SSH Versions . . . . . . . . . . . . 4 - 4.3.1 Old Client, New Server . . . . . . . . . . . . . . . . . . . 5 - 4.3.2 New Client, Old Server . . . . . . . . . . . . . . . . . . . 5 - 5. Binary Packet Protocol . . . . . . . . . . . . . . . . . . . 5 - 5.1 Maximum Packet Length . . . . . . . . . . . . . . . . . . . 6 - 5.2 Compression . . . . . . . . . . . . . . . . . . . . . . . . 7 - 5.3 Encryption . . . . . . . . . . . . . . . . . . . . . . . . . 7 - 5.4 Data Integrity . . . . . . . . . . . . . . . . . . . . . . . 9 - 5.5 Key Exchange Methods . . . . . . . . . . . . . . . . . . . . 10 - 5.6 Public Key Algorithms . . . . . . . . . . . . . . . . . . . 11 - 6. Key Exchange . . . . . . . . . . . . . . . . . . . . . . . . 13 - 6.1 Algorithm Negotiation . . . . . . . . . . . . . . . . . . . 13 - 6.2 Output from Key Exchange . . . . . . . . . . . . . . . . . . 16 - 6.3 Taking Keys Into Use . . . . . . . . . . . . . . . . . . . . 17 - 7. Diffie-Hellman Key Exchange . . . . . . . . . . . . . . . . 18 - 7.1 diffie-hellman-group1-sha1 . . . . . . . . . . . . . . . . . 19 - 8. Key Re-Exchange . . . . . . . . . . . . . . . . . . . . . . 20 - 9. Service Request . . . . . . . . . . . . . . . . . . . . . . 21 - 10. Additional Messages . . . . . . . . . . . . . . . . . . . . 21 - 10.1 Disconnection Message . . . . . . . . . . . . . . . . . . . 22 - 10.2 Ignored Data Message . . . . . . . . . . . . . . . . . . . . 22 - 10.3 Debug Message . . . . . . . . . . . . . . . . . . . . . . . 23 - 10.4 Reserved Messages . . . . . . . . . . . . . . . . . . . . . 23 - 11. Summary of Message Numbers . . . . . . . . . . . . . . . . . 23 - 12. IANA Considerations . . . . . . . . . . . . . . . . . . . . 24 - 13. Security Considerations . . . . . . . . . . . . . . . . . . 24 - 14. Intellectual Property . . . . . . . . . . . . . . . . . . . 24 - 15. Additional Information . . . . . . . . . . . . . . . . . . . 24 - Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 26 - Normative . . . . . . . . . . . . . . . . . . . . . . . . . 25 - Informative . . . . . . . . . . . . . . . . . . . . . . . . 25 - A. Contibutors . . . . . . . . . . . . . . . . . . . . . . . . 27 - Intellectual Property and Copyright Statements . . . . . . . 28 - - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 2] - -Internet-Draft SSH Transport Layer Protocol Oct 2003 - - -1. Contributors - - The major original contributors of this document were: Tatu Ylonen, - Tero Kivinen, Timo J. Rinne, Sami Lehtinen (all of SSH Communications - Security Corp), and Markku-Juhani O. Saarinen (University of - Jyvaskyla) - - The document editor is: [email protected]. Comments on this - internet draft should be sent to the IETF SECSH working group, - details at: http://ietf.org/html.charters/secsh-charter.html - -2. Introduction - - The SSH transport layer is a secure low level transport protocol. It - provides strong encryption, cryptographic host authentication, and - integrity protection. - - Authentication in this protocol level is host-based; this protocol - does not perform user authentication. A higher level protocol for - user authentication can be designed on top of this protocol. - - The protocol has been designed to be simple, flexible, to allow - parameter negotiation, and to minimize the number of round-trips. - Key exchange method, public key algorithm, symmetric encryption - algorithm, message authentication algorithm, and hash algorithm are - all negotiated. It is expected that in most environments, only 2 - round-trips will be needed for full key exchange, server - authentication, service request, and acceptance notification of - service request. The worst case is 3 round-trips. - -3. Conventions Used in This Document - - The keywords "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT", - and "MAY" that appear in this document are to be interpreted as - described in [RFC2119]. - - The used data types and terminology are specified in the architecture - document [SSH-ARCH]. - - The architecture document also discusses the algorithm naming - conventions that MUST be used with the SSH protocols. - -4. Connection Setup - - SSH works over any 8-bit clean, binary-transparent transport. The - underlying transport SHOULD protect against transmission errors as - such errors cause the SSH connection to terminate. - - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 3] - -Internet-Draft SSH Transport Layer Protocol Oct 2003 - - - The client initiates the connection. - -4.1 Use over TCP/IP - - When used over TCP/IP, the server normally listens for connections on - port 22. This port number has been registered with the IANA, and has - been officially assigned for SSH. - -4.2 Protocol Version Exchange - - When the connection has been established, both sides MUST send an - identification string of the form "SSH-protoversion-softwareversion - comments", followed by carriage return and newline characters (ASCII - 13 and 10, respectively). Both sides MUST be able to process - identification strings without carriage return character. No null - character is sent. The maximum length of the string is 255 - characters, including the carriage return and newline. - - The part of the identification string preceding carriage return and - newline is used in the Diffie-Hellman key exchange (see Section - Section 7). - - The server MAY send other lines of data before sending the version - string. Each line SHOULD be terminated by a carriage return and - newline. Such lines MUST NOT begin with "SSH-", and SHOULD be - encoded in ISO-10646 UTF-8 [RFC2279] (language is not specified). - Clients MUST be able to process such lines; they MAY be silently - ignored, or MAY be displayed to the client user; if they are - displayed, control character filtering discussed in [SSH-ARCH] SHOULD - be used. The primary use of this feature is to allow TCP-wrappers to - display an error message before disconnecting. - - Version strings MUST consist of printable US-ASCII characters, not - including whitespaces or a minus sign (-). The version string is - primarily used to trigger compatibility extensions and to indicate - the capabilities of an implementation. The comment string should - contain additional information that might be useful in solving user - problems. - - The protocol version described in this document is 2.0. - - Key exchange will begin immediately after sending this identifier. - All packets following the identification string SHALL use the binary - packet protocol, to be described below. - -4.3 Compatibility With Old SSH Versions - - During the transition period, it is important to be able to work in a - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 4] - -Internet-Draft SSH Transport Layer Protocol Oct 2003 - - - way that is compatible with the installed SSH clients and servers - that use an older version of the protocol. Information in this - section is only relevant for implementations supporting compatibility - with SSH versions 1.x. There is no standards track or informational - draft available that defines the SSH 1.x protocol. The only known - documentation of the 1.x protocol is contained in README files that - are shipped along with the source code. - -4.3.1 Old Client, New Server - - Server implementations MAY support a configurable "compatibility" - flag that enables compatibility with old versions. When this flag is - on, the server SHOULD identify its protocol version as "1.99". - Clients using protocol 2.0 MUST be able to identify this as identical - to "2.0". In this mode the server SHOULD NOT send the carriage - return character (ASCII 13) after the version identification string. - - In the compatibility mode the server SHOULD NOT send any further data - after its initialization string until it has received an - identification string from the client. The server can then determine - whether the client is using an old protocol, and can revert to the - old protocol if required. In the compatibility mode, the server MUST - NOT send additional data before the version string. - - When compatibility with old clients is not needed, the server MAY - send its initial key exchange data immediately after the - identification string. - -4.3.2 New Client, Old Server - - Since the new client MAY immediately send additional data after its - identification string (before receiving server's identification), the - old protocol may already have been corrupted when the client learns - that the server is old. When this happens, the client SHOULD close - the connection to the server, and reconnect using the old protocol. - -5. Binary Packet Protocol - - Each packet is in the following format: - - uint32 packet_length - byte padding_length - byte[n1] payload; n1 = packet_length - padding_length - 1 - byte[n2] random padding; n2 = padding_length - byte[m] mac (message authentication code); m = mac_length - - packet_length - - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 5] - -Internet-Draft SSH Transport Layer Protocol Oct 2003 - - - The length of the packet (bytes), not including MAC or the - packet_length field itself. - - padding_length - Length of padding (bytes). - - payload - The useful contents of the packet. If compression has been - negotiated, this field is compressed. Initially, compression - MUST be "none". - - random padding - Arbitrary-length padding, such that the total length of - (packet_length || padding_length || payload || padding) is a - multiple of the cipher block size or 8, whichever is larger. - There MUST be at least four bytes of padding. The padding - SHOULD consist of random bytes. The maximum amount of padding - is 255 bytes. - - mac - Message authentication code. If message authentication has - been negotiated, this field contains the MAC bytes. Initially, - the MAC algorithm MUST be "none". - - - Note that length of the concatenation of packet length, padding - length, payload, and padding MUST be a multiple of the cipher block - size or 8, whichever is larger. This constraint MUST be enforced - even when using stream ciphers. Note that the packet length field is - also encrypted, and processing it requires special care when sending - or receiving packets. - - The minimum size of a packet is 16 (or the cipher block size, - whichever is larger) bytes (plus MAC); implementations SHOULD decrypt - the length after receiving the first 8 (or cipher block size, - whichever is larger) bytes of a packet. - -5.1 Maximum Packet Length - - All implementations MUST be able to process packets with uncompressed - payload length of 32768 bytes or less and total packet size of 35000 - bytes or less (including length, padding length, payload, padding, - and MAC.). The maximum of 35000 bytes is an arbitrary chosen value - larger than uncompressed size. Implementations SHOULD support longer - packets, where they might be needed, e.g. if an implementation wants - to send a very large number of certificates. Such packets MAY be - sent if the version string indicates that the other party is able to - process them. However, implementations SHOULD check that the packet - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 6] - -Internet-Draft SSH Transport Layer Protocol Oct 2003 - - - length is reasonable for the implementation to avoid - denial-of-service and/or buffer overflow attacks. - -5.2 Compression - - If compression has been negotiated, the payload field (and only it) - will be compressed using the negotiated algorithm. The length field - and MAC will be computed from the compressed payload. Encryption will - be done after compression. - - Compression MAY be stateful, depending on the method. Compression - MUST be independent for each direction, and implementations MUST - allow independently choosing the algorithm for each direction. - - The following compression methods are currently defined: - - none REQUIRED no compression - zlib OPTIONAL ZLIB (LZ77) compression - - The "zlib" compression is described in [RFC1950] and in [RFC1951]. - The compression context is initialized after each key exchange, and - is passed from one packet to the next with only a partial flush being - performed at the end of each packet. A partial flush means that the - current compressed block is ended and all data will be output. If the - current block is not a stored block, one or more empty blocks are - added after the current block to ensure that there are at least 8 - bits counting from the start of the end-of-block code of the current - block to the end of the packet payload. - - Additional methods may be defined as specified in [SSH-ARCH]. - -5.3 Encryption - - An encryption algorithm and a key will be negotiated during the key - exchange. When encryption is in effect, the packet length, padding - length, payload and padding fields of each packet MUST be encrypted - with the given algorithm. - - The encrypted data in all packets sent in one direction SHOULD be - considered a single data stream. For example, initialization vectors - SHOULD be passed from the end of one packet to the beginning of the - next packet. All ciphers SHOULD use keys with an effective key length - of 128 bits or more. - - The ciphers in each direction MUST run independently of each other, - and implementations MUST allow independently choosing the algorithm - for each direction (if multiple algorithms are allowed by local - policy). - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 7] - -Internet-Draft SSH Transport Layer Protocol Oct 2003 - - - The following ciphers are currently defined: - - 3des-cbc REQUIRED three-key 3DES in CBC mode - blowfish-cbc OPTIONALi Blowfish in CBC mode - twofish256-cbc OPTIONAL Twofish in CBC mode, - with 256-bit key - twofish-cbc OPTIONAL alias for "twofish256-cbc" (this - is being retained for - historical reasons) - twofish192-cbc OPTIONAL Twofish with 192-bit key - twofish128-cbc OPTIONAL Twofish with 128-bit key - aes256-cbc OPTIONAL AES (Rijndael) in CBC mode, - with 256-bit key - aes192-cbc OPTIONAL AES with 192-bit key - aes128-cbc RECOMMENDED AES with 128-bit key - serpent256-cbc OPTIONAL Serpent in CBC mode, with - 256-bit key - serpent192-cbc OPTIONAL Serpent with 192-bit key - serpent128-cbc OPTIONAL Serpent with 128-bit key - arcfour OPTIONAL the ARCFOUR stream cipher - idea-cbc OPTIONAL IDEA in CBC mode - cast128-cbc OPTIONAL CAST-128 in CBC mode - none OPTIONAL no encryption; NOT RECOMMENDED - - The "3des-cbc" cipher is three-key triple-DES - (encrypt-decrypt-encrypt), where the first 8 bytes of the key are - used for the first encryption, the next 8 bytes for the decryption, - and the following 8 bytes for the final encryption. This requires 24 - bytes of key data (of which 168 bits are actually used). To - implement CBC mode, outer chaining MUST be used (i.e., there is only - one initialization vector). This is a block cipher with 8 byte - blocks. This algorithm is defined in [FIPS-46-3] - - The "blowfish-cbc" cipher is Blowfish in CBC mode, with 128 bit keys - [SCHNEIER]. This is a block cipher with 8 byte blocks. - - The "twofish-cbc" or "twofish256-cbc" cipher is Twofish in CBC mode, - with 256 bit keys as described [TWOFISH]. This is a block cipher with - 16 byte blocks. - - The "twofish192-cbc" cipher. Same as above but with 192-bit key. - - The "twofish128-cbc" cipher. Same as above but with 128-bit key. - - The "aes256-cbc" cipher is AES (Advanced Encryption Standard) - [FIPS-197], formerly Rijndael, in CBC mode. This version uses 256-bit - key. - - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 8] - -Internet-Draft SSH Transport Layer Protocol Oct 2003 - - - The "aes192-cbc" cipher. Same as above but with 192-bit key. - - The "aes128-cbc" cipher. Same as above but with 128-bit key. - - The "serpent256-cbc" cipher in CBC mode, with 256-bit key as - described in the Serpent AES submission. - - The "serpent192-cbc" cipher. Same as above but with 192-bit key. - - The "serpent128-cbc" cipher. Same as above but with 128-bit key. - - The "arcfour" is the Arcfour stream cipher with 128 bit keys. The - Arcfour cipher is believed to be compatible with the RC4 cipher - [SCHNEIER]. RC4 is a registered trademark of RSA Data Security Inc. - Arcfour (and RC4) has problems with weak keys, and should be used - with caution. - - The "idea-cbc" cipher is the IDEA cipher in CBC mode [SCHNEIER]. - - The "cast128-cbc" cipher is the CAST-128 cipher in CBC mode - [RFC2144]. - - The "none" algorithm specifies that no encryption is to be done. - Note that this method provides no confidentiality protection, and it - is not recommended. Some functionality (e.g. password - authentication) may be disabled for security reasons if this cipher - is chosen. - - Additional methods may be defined as specified in [SSH-ARCH]. - -5.4 Data Integrity - - Data integrity is protected by including with each packet a message - authentication code (MAC) that is computed from a shared secret, - packet sequence number, and the contents of the packet. - - The message authentication algorithm and key are negotiated during - key exchange. Initially, no MAC will be in effect, and its length - MUST be zero. After key exchange, the selected MAC will be computed - before encryption from the concatenation of packet data: - - mac = MAC(key, sequence_number || unencrypted_packet) - - where unencrypted_packet is the entire packet without MAC (the length - fields, payload and padding), and sequence_number is an implicit - packet sequence number represented as uint32. The sequence number is - initialized to zero for the first packet, and is incremented after - every packet (regardless of whether encryption or MAC is in use). It - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 9] - -Internet-Draft SSH Transport Layer Protocol Oct 2003 - - - is never reset, even if keys/algorithms are renegotiated later. It - wraps around to zero after every 2^32 packets. The packet sequence - number itself is not included in the packet sent over the wire. - - The MAC algorithms for each direction MUST run independently, and - implementations MUST allow choosing the algorithm independently for - both directions. - - The MAC bytes resulting from the MAC algorithm MUST be transmitted - without encryption as the last part of the packet. The number of MAC - bytes depends on the algorithm chosen. - - The following MAC algorithms are currently defined: - - hmac-sha1 REQUIRED HMAC-SHA1 (digest length = key - length = 20) - hmac-sha1-96 RECOMMENDED first 96 bits of HMAC-SHA1 (digest - length = 12, key length = 20) - hmac-md5 OPTIONAL HMAC-MD5 (digest length = key - length = 16) - hmac-md5-96 OPTIONAL first 96 bits of HMAC-MD5 (digest - length = 12, key length = 16) - none OPTIONAL no MAC; NOT RECOMMENDED - - Figure 1 - - The "hmac-*" algorithms are described in [RFC2104] The "*-n" MACs use - only the first n bits of the resulting value. - - The hash algorithms are described in [SCHNEIER]. - - Additional methods may be defined as specified in [SSH-ARCH]. - -5.5 Key Exchange Methods - - The key exchange method specifies how one-time session keys are - generated for encryption and for authentication, and how the server - authentication is done. - - Only one REQUIRED key exchange method has been defined: - - diffie-hellman-group1-sha1 REQUIRED - - This method is described later in this document. - - Additional methods may be defined as specified in [SSH-ARCH]. - - - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 10] - -Internet-Draft SSH Transport Layer Protocol Oct 2003 - - -5.6 Public Key Algorithms - - This protocol has been designed to be able to operate with almost any - public key format, encoding, and algorithm (signature and/or - encryption). - - There are several aspects that define a public key type: - o Key format: how is the key encoded and how are certificates - represented. The key blobs in this protocol MAY contain - certificates in addition to keys. - o Signature and/or encryption algorithms. Some key types may not - support both signing and encryption. Key usage may also be - restricted by policy statements in e.g. certificates. In this - case, different key types SHOULD be defined for the different - policy alternatives. - o Encoding of signatures and/or encrypted data. This includes but is - not limited to padding, byte order, and data formats. - - The following public key and/or certificate formats are currently defined: - - ssh-dss REQUIRED sign Raw DSS Key - ssh-rsa RECOMMENDED sign Raw RSA Key - x509v3-sign-rsa OPTIONAL sign X.509 certificates (RSA key) - x509v3-sign-dss OPTIONAL sign X.509 certificates (DSS key) - spki-sign-rsa OPTIONAL sign SPKI certificates (RSA key) - spki-sign-dss OPTIONAL sign SPKI certificates (DSS key) - pgp-sign-rsa OPTIONAL sign OpenPGP certificates (RSA key) - pgp-sign-dss OPTIONAL sign OpenPGP certificates (DSS key) - - Additional key types may be defined as specified in [SSH-ARCH]. - - The key type MUST always be explicitly known (from algorithm - negotiation or some other source). It is not normally included in - the key blob. - - Certificates and public keys are encoded as follows: - - string certificate or public key format identifier - byte[n] key/certificate data - - The certificate part may have be a zero length string, but a public - key is required. This is the public key that will be used for - authentication; the certificate sequence contained in the certificate - blob can be used to provide authorization. - - Public key / certifcate formats that do not explicitly specify a - signature format identifier MUST use the public key / certificate - format identifier as the signature identifier. - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 11] - -Internet-Draft SSH Transport Layer Protocol Oct 2003 - - - Signatures are encoded as follows: - string signature format identifier (as specified by the - public key / cert format) - byte[n] signature blob in format specific encoding. - - - The "ssh-dss" key format has the following specific encoding: - - string "ssh-dss" - mpint p - mpint q - mpint g - mpint y - - Here the p, q, g, and y parameters form the signature key blob. - - Signing and verifying using this key format is done according to the - Digital Signature Standard [FIPS-186] using the SHA-1 hash. A - description can also be found in [SCHNEIER]. - - The resulting signature is encoded as follows: - - string "ssh-dss" - string dss_signature_blob - - dss_signature_blob is encoded as a string containing r followed by s - (which are 160 bits long integers, without lengths or padding, - unsigned and in network byte order). - - The "ssh-rsa" key format has the following specific encoding: - - string "ssh-rsa" - mpint e - mpint n - - Here the e and n parameters form the signature key blob. - - Signing and verifying using this key format is done according to - [SCHNEIER] and [PKCS1] using the SHA-1 hash. - - The resulting signature is encoded as follows: - - string "ssh-rsa" - string rsa_signature_blob - - rsa_signature_blob is encoded as a string containing s (which is an - integer, without lengths or padding, unsigned and in network byte - order). - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 12] - -Internet-Draft SSH Transport Layer Protocol Oct 2003 - - - The "spki-sign-rsa" method indicates that the certificate blob - contains a sequence of SPKI certificates. The format of SPKI - certificates is described in [RFC2693]. This method indicates that - the key (or one of the keys in the certificate) is an RSA-key. - - The "spki-sign-dss". As above, but indicates that the key (or one of - the keys in the certificate) is a DSS-key. - - The "pgp-sign-rsa" method indicates the certificates, the public key, - and the signature are in OpenPGP compatible binary format - ([RFC2440]). This method indicates that the key is an RSA-key. - - The "pgp-sign-dss". As above, but indicates that the key is a - DSS-key. - -6. Key Exchange - - Key exchange begins by each side sending lists of supported - algorithms. Each side has a preferred algorithm in each category, and - it is assumed that most implementations at any given time will use - the same preferred algorithm. Each side MAY guess which algorithm - the other side is using, and MAY send an initial key exchange packet - according to the algorithm if appropriate for the preferred method. - - Guess is considered wrong, if: - o the kex algorithm and/or the host key algorithm is guessed wrong - (server and client have different preferred algorithm), or - o if any of the other algorithms cannot be agreed upon (the - procedure is defined below in Section Section 6.1). - - Otherwise, the guess is considered to be right and the optimistically - sent packet MUST be handled as the first key exchange packet. - - However, if the guess was wrong, and a packet was optimistically sent - by one or both parties, such packets MUST be ignored (even if the - error in the guess would not affect the contents of the initial - packet(s)), and the appropriate side MUST send the correct initial - packet. - - Server authentication in the key exchange MAY be implicit. After a - key exchange with implicit server authentication, the client MUST - wait for response to its service request message before sending any - further data. - -6.1 Algorithm Negotiation - - Key exchange begins by each side sending the following packet: - - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 13] - -Internet-Draft SSH Transport Layer Protocol Oct 2003 - - - byte SSH_MSG_KEXINIT - byte[16] cookie (random bytes) - string kex_algorithms - string server_host_key_algorithms - string encryption_algorithms_client_to_server - string encryption_algorithms_server_to_client - string mac_algorithms_client_to_server - string mac_algorithms_server_to_client - string compression_algorithms_client_to_server - string compression_algorithms_server_to_client - string languages_client_to_server - string languages_server_to_client - boolean first_kex_packet_follows - uint32 0 (reserved for future extension) - - Each of the algorithm strings MUST be a comma-separated list of - algorithm names (see ''Algorithm Naming'' in [SSH-ARCH]). Each - supported (allowed) algorithm MUST be listed in order of preference. - - The first algorithm in each list MUST be the preferred (guessed) - algorithm. Each string MUST contain at least one algorithm name. - - - cookie - The cookie MUST be a random value generated by the sender. Its - purpose is to make it impossible for either side to fully - determine the keys and the session identifier. - - kex_algorithms - Key exchange algorithms were defined above. The first - algorithm MUST be the preferred (and guessed) algorithm. If - both sides make the same guess, that algorithm MUST be used. - Otherwise, the following algorithm MUST be used to choose a key - exchange method: iterate over client's kex algorithms, one at a - time. Choose the first algorithm that satisfies the following - conditions: - + the server also supports the algorithm, - + if the algorithm requires an encryption-capable host key, - there is an encryption-capable algorithm on the server's - server_host_key_algorithms that is also supported by the - client, and - + if the algorithm requires a signature-capable host key, - there is a signature-capable algorithm on the server's - server_host_key_algorithms that is also supported by the - client. - + If no algorithm satisfying all these conditions can be - found, the connection fails, and both sides MUST disconnect. - - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 14] - -Internet-Draft SSH Transport Layer Protocol Oct 2003 - - - server_host_key_algorithms - List of the algorithms supported for the server host key. The - server lists the algorithms for which it has host keys; the - client lists the algorithms that it is willing to accept. - (There MAY be multiple host keys for a host, possibly with - different algorithms.) - - Some host keys may not support both signatures and encryption - (this can be determined from the algorithm), and thus not all - host keys are valid for all key exchange methods. - - Algorithm selection depends on whether the chosen key exchange - algorithm requires a signature or encryption capable host key. - It MUST be possible to determine this from the public key - algorithm name. The first algorithm on the client's list that - satisfies the requirements and is also supported by the server - MUST be chosen. If there is no such algorithm, both sides MUST - disconnect. - - encryption_algorithms - Lists the acceptable symmetric encryption algorithms in order - of preference. The chosen encryption algorithm to each - direction MUST be the first algorithm on the client's list - that is also on the server's list. If there is no such - algorithm, both sides MUST disconnect. - - Note that "none" must be explicitly listed if it is to be - acceptable. The defined algorithm names are listed in Section - Section 5.3. - - mac_algorithms - Lists the acceptable MAC algorithms in order of preference. - The chosen MAC algorithm MUST be the first algorithm on the - client's list that is also on the server's list. If there is - no such algorithm, both sides MUST disconnect. - - Note that "none" must be explicitly listed if it is to be - acceptable. The MAC algorithm names are listed in Section - Figure 1. - - compression_algorithms - Lists the acceptable compression algorithms in order of - preference. The chosen compression algorithm MUST be the first - algorithm on the client's list that is also on the server's - list. If there is no such algorithm, both sides MUST - disconnect. - - - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 15] - -Internet-Draft SSH Transport Layer Protocol Oct 2003 - - - Note that "none" must be explicitly listed if it is to be - acceptable. The compression algorithm names are listed in - Section Section 5.2. - - languages - This is a comma-separated list of language tags in order of - preference [RFC3066]. Both parties MAY ignore this list. If - there are no language preferences, this list SHOULD be empty. - Language tags SHOULD NOT be present unless they are known to be - needed by the sending party. - - first_kex_packet_follows - Indicates whether a guessed key exchange packet follows. If a - guessed packet will be sent, this MUST be TRUE. If no guessed - packet will be sent, this MUST be FALSE. - - After receiving the SSH_MSG_KEXINIT packet from the other side, - each party will know whether their guess was right. If the - other party's guess was wrong, and this field was TRUE, the - next packet MUST be silently ignored, and both sides MUST then - act as determined by the negotiated key exchange method. If - the guess was right, key exchange MUST continue using the - guessed packet. - - After the KEXINIT packet exchange, the key exchange algorithm is run. - It may involve several packet exchanges, as specified by the key - exchange method. - -6.2 Output from Key Exchange - - The key exchange produces two values: a shared secret K, and an - exchange hash H. Encryption and authentication keys are derived from - these. The exchange hash H from the first key exchange is - additionally used as the session identifier, which is a unique - identifier for this connection. It is used by authentication methods - as a part of the data that is signed as a proof of possession of a - private key. Once computed, the session identifier is not changed, - even if keys are later re-exchanged. - - - Each key exchange method specifies a hash function that is used in - the key exchange. The same hash algorithm MUST be used in key - derivation. Here, we'll call it HASH. - - - Encryption keys MUST be computed as HASH of a known value and K as - follows: - - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 16] - -Internet-Draft SSH Transport Layer Protocol Oct 2003 - - - o Initial IV client to server: HASH(K || H || "A" || session_id) - (Here K is encoded as mpint and "A" as byte and session_id as raw - data."A" means the single character A, ASCII 65). - o Initial IV server to client: HASH(K || H || "B" || session_id) - o Encryption key client to server: HASH(K || H || "C" || session_id) - o Encryption key server to client: HASH(K || H || "D" || session_id) - o Integrity key client to server: HASH(K || H || "E" || session_id) - o Integrity key server to client: HASH(K || H || "F" || session_id) - - Key data MUST be taken from the beginning of the hash output. 128 - bits (16 bytes) MUST be used for algorithms with variable-length - keys. The only variable key length algorithm defined in this document - is arcfour). For other algorithms, as many bytes as are needed are - taken from the beginning of the hash value. If the key length needed - is longer than the output of the HASH, the key is extended by - computing HASH of the concatenation of K and H and the entire key so - far, and appending the resulting bytes (as many as HASH generates) to - the key. This process is repeated until enough key material is - available; the key is taken from the beginning of this value. In - other words: - - K1 = HASH(K || H || X || session_id) (X is e.g. "A") - K2 = HASH(K || H || K1) - K3 = HASH(K || H || K1 || K2) - ... - key = K1 || K2 || K3 || ... - - This process will lose entropy if the amount of entropy in K is - larger than the internal state size of HASH. - -6.3 Taking Keys Into Use - - Key exchange ends by each side sending an SSH_MSG_NEWKEYS message. - This message is sent with the old keys and algorithms. All messages - sent after this message MUST use the new keys and algorithms. - - - When this message is received, the new keys and algorithms MUST be - taken into use for receiving. - - - This message is the only valid message after key exchange, in - addition to SSH_MSG_DEBUG, SSH_MSG_DISCONNECT and SSH_MSG_IGNORE - messages. The purpose of this message is to ensure that a party is - able to respond with a disconnect message that the other party can - understand if something goes wrong with the key exchange. - Implementations MUST NOT accept any other messages after key exchange - before receiving SSH_MSG_NEWKEYS. - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 17] - -Internet-Draft SSH Transport Layer Protocol Oct 2003 - - - byte SSH_MSG_NEWKEYS - - -7. Diffie-Hellman Key Exchange - - The Diffie-Hellman key exchange provides a shared secret that can not - be determined by either party alone. The key exchange is combined - with a signature with the host key to provide host authentication. - - - In the following description (C is the client, S is the server; p is - a large safe prime, g is a generator for a subgroup of GF(p), and q - is the order of the subgroup; V_S is S's version string; V_C is C's - version string; K_S is S's public host key; I_C is C's KEXINIT - message and I_S S's KEXINIT message which have been exchanged before - this part begins): - - - 1. C generates a random number x (1 < x < q) and computes e = g^x - mod p. C sends "e" to S. - - 2. S generates a random number y (0 < y < q) and computes f = g^y - mod p. S receives "e". It computes K = e^y mod p, H = hash(V_C - || V_S || I_C || I_S || K_S || e || f || K) (these elements are - encoded according to their types; see below), and signature s on - H with its private host key. S sends "K_S || f || s" to C. The - signing operation may involve a second hashing operation. - - 3. C verifies that K_S really is the host key for S (e.g. using - certificates or a local database). C is also allowed to accept - the key without verification; however, doing so will render the - protocol insecure against active attacks (but may be desirable - for practical reasons in the short term in many environments). C - then computes K = f^x mod p, H = hash(V_C || V_S || I_C || I_S || - K_S || e || f || K), and verifies the signature s on H. - - Either side MUST NOT send or accept e or f values that are not in the - range [1, p-1]. If this condition is violated, the key exchange - fails. - - - This is implemented with the following messages. The hash algorithm - for computing the exchange hash is defined by the method name, and is - called HASH. The public key algorithm for signing is negotiated with - the KEXINIT messages. - - First, the client sends the following: - - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 18] - -Internet-Draft SSH Transport Layer Protocol Oct 2003 - - - byte SSH_MSG_KEXDH_INIT - mpint e - - - The server responds with the following: - - byte SSH_MSG_KEXDH_REPLY - string server public host key and certificates (K_S) - mpint f - string signature of H - - The hash H is computed as the HASH hash of the concatenation of the - following: - - string V_C, the client's version string (CR and NL excluded) - string V_S, the server's version string (CR and NL excluded) - string I_C, the payload of the client's SSH_MSG_KEXINIT - string I_S, the payload of the server's SSH_MSG_KEXINIT - string K_S, the host key - mpint e, exchange value sent by the client - mpint f, exchange value sent by the server - mpint K, the shared secret - - This value is called the exchange hash, and it is used to - authenticate the key exchange. The exchange hash SHOULD be kept - secret. - - - The signature algorithm MUST be applied over H, not the original - data. Most signature algorithms include hashing and additional - padding. For example, "ssh-dss" specifies SHA-1 hashing; in that - case, the data is first hashed with HASH to compute H, and H is then - hashed with SHA-1 as part of the signing operation. - -7.1 diffie-hellman-group1-sha1 - - The "diffie-hellman-group1-sha1" method specifies Diffie-Hellman key - exchange with SHA-1 as HASH, and Oakley group 14 [RFC3526] (2048-bit - MODP Group). It is included below in hexadecimal and decimal. - - The prime p is equal to 2^1024 - 2^960 - 1 + 2^64 * floor( 2^894 Pi + - 129093 ). Its hexadecimal value is: - - FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 - 29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD - EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245 - E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED - EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381 - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 19] - -Internet-Draft SSH Transport Layer Protocol Oct 2003 - - - FFFFFFFF FFFFFFFF. - - In decimal, this value is: - - 179769313486231590770839156793787453197860296048756011706444 - 423684197180216158519368947833795864925541502180565485980503 - 646440548199239100050792877003355816639229553136239076508735 - 759914822574862575007425302077447712589550957937778424442426 - 617334727629299387668709205606050270810842907692932019128194 - 467627007. - - The generator used with this prime is g = 2. The group order q is (p - - 1) / 2. - -8. Key Re-Exchange - - Key re-exchange is started by sending an SSH_MSG_KEXINIT packet when - not already doing a key exchange (as described in Section Section - 6.1). When this message is received, a party MUST respond with its - own SSH_MSG_KEXINIT message except when the received SSH_MSG_KEXINIT - already was a reply. Either party MAY initiate the re-exchange, but - roles MUST NOT be changed (i.e., the server remains the server, and - the client remains the client). - - - Key re-exchange is performed using whatever encryption was in effect - when the exchange was started. Encryption, compression, and MAC - methods are not changed before a new SSH_MSG_NEWKEYS is sent after - the key exchange (as in the initial key exchange). Re-exchange is - processed identically to the initial key exchange, except for the - session identifier that will remain unchanged. It is permissible to - change some or all of the algorithms during the re-exchange. Host - keys can also change. All keys and initialization vectors are - recomputed after the exchange. Compression and encryption contexts - are reset. - - - It is recommended that the keys are changed after each gigabyte of - transmitted data or after each hour of connection time, whichever - comes sooner. However, since the re-exchange is a public key - operation, it requires a fair amount of processing power and should - not be performed too often. - - - More application data may be sent after the SSH_MSG_NEWKEYS packet - has been sent; key exchange does not affect the protocols that lie - above the SSH transport layer. - - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 20] - -Internet-Draft SSH Transport Layer Protocol Oct 2003 - - -9. Service Request - - After the key exchange, the client requests a service. The service is - identified by a name. The format of names and procedures for defining - new names are defined in [SSH-ARCH]. - - - Currently, the following names have been reserved: - - ssh-userauth - ssh-connection - - Similar local naming policy is applied to the service names, as is - applied to the algorithm names; a local service should use the - "servicename@domain" syntax. - - byte SSH_MSG_SERVICE_REQUEST - string service name - - If the server rejects the service request, it SHOULD send an - appropriate SSH_MSG_DISCONNECT message and MUST disconnect. - - - When the service starts, it may have access to the session identifier - generated during the key exchange. - - - If the server supports the service (and permits the client to use - it), it MUST respond with the following: - - byte SSH_MSG_SERVICE_ACCEPT - string service name - - Message numbers used by services should be in the area reserved for - them (see Section 6 in [SSH-ARCH]). The transport level will - continue to process its own messages. - - - Note that after a key exchange with implicit server authentication, - the client MUST wait for response to its service request message - before sending any further data. - -10. Additional Messages - - Either party may send any of the following messages at any time. - - - - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 21] - -Internet-Draft SSH Transport Layer Protocol Oct 2003 - - -10.1 Disconnection Message - - byte SSH_MSG_DISCONNECT - uint32 reason code - string description [RFC2279] - string language tag [RFC3066] - - This message causes immediate termination of the connection. All - implementations MUST be able to process this message; they SHOULD be - able to send this message. - - The sender MUST NOT send or receive any data after this message, and - the recipient MUST NOT accept any data after receiving this message. - The description field gives a more specific explanation in a - human-readable form. The error code gives the reason in a more - machine-readable format (suitable for localization), and can have the - following values: - - #define SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1 - #define SSH_DISCONNECT_PROTOCOL_ERROR 2 - #define SSH_DISCONNECT_KEY_EXCHANGE_FAILED 3 - #define SSH_DISCONNECT_RESERVED 4 - #define SSH_DISCONNECT_MAC_ERROR 5 - #define SSH_DISCONNECT_COMPRESSION_ERROR 6 - #define SSH_DISCONNECT_SERVICE_NOT_AVAILABLE 7 - #define SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8 - #define SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9 - #define SSH_DISCONNECT_CONNECTION_LOST 10 - #define SSH_DISCONNECT_BY_APPLICATION 11 - #define SSH_DISCONNECT_TOO_MANY_CONNECTIONS 12 - #define SSH_DISCONNECT_AUTH_CANCELLED_BY_USER 13 - #define SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14 - #define SSH_DISCONNECT_ILLEGAL_USER_NAME 15 - - If the description string is displayed, control character filtering - discussed in [SSH-ARCH] should be used to avoid attacks by sending - terminal control characters. - -10.2 Ignored Data Message - - byte SSH_MSG_IGNORE - string data - - All implementations MUST understand (and ignore) this message at any - time (after receiving the protocol version). No implementation is - required to send them. This message can be used as an additional - protection measure against advanced traffic analysis techniques. - - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 22] - -Internet-Draft SSH Transport Layer Protocol Oct 2003 - - -10.3 Debug Message - - byte SSH_MSG_DEBUG - boolean always_display - string message [RFC2279] - string language tag [RFC3066] - - All implementations MUST understand this message, but they are - allowed to ignore it. This message is used to pass the other side - information that may help debugging. If always_display is TRUE, the - message SHOULD be displayed. Otherwise, it SHOULD NOT be displayed - unless debugging information has been explicitly requested by the - user. - - - The message doesn't need to contain a newline. It is, however, - allowed to consist of multiple lines separated by CRLF (Carriage - Return - Line Feed) pairs. - - - If the message string is displayed, terminal control character - filtering discussed in [SSH-ARCH] should be used to avoid attacks by - sending terminal control characters. - -10.4 Reserved Messages - - An implementation MUST respond to all unrecognized messages with an - SSH_MSG_UNIMPLEMENTED message in the order in which the messages were - received. Such messages MUST be otherwise ignored. Later protocol - versions may define other meanings for these message types. - - byte SSH_MSG_UNIMPLEMENTED - uint32 packet sequence number of rejected message - - -11. Summary of Message Numbers - - The following message numbers have been defined in this protocol: - - #define SSH_MSG_DISCONNECT 1 - #define SSH_MSG_IGNORE 2 - #define SSH_MSG_UNIMPLEMENTED 3 - #define SSH_MSG_DEBUG 4 - #define SSH_MSG_SERVICE_REQUEST 5 - #define SSH_MSG_SERVICE_ACCEPT 6 - - #define SSH_MSG_KEXINIT 20 - #define SSH_MSG_NEWKEYS 21 - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 23] - -Internet-Draft SSH Transport Layer Protocol Oct 2003 - - - /* Numbers 30-49 used for kex packets. - Different kex methods may reuse message numbers in - this range. */ - - #define SSH_MSG_KEXDH_INIT 30 - #define SSH_MSG_KEXDH_REPLY 31 - - -12. IANA Considerations - - This document is part of a set, the IANA considerations for the SSH - protocol as defined in [SSH-ARCH], [SSH-TRANS], [SSH-USERAUTH], - [SSH-CONNECT] are detailed in [SSH-NUMBERS]. - -13. Security Considerations - - This protocol provides a secure encrypted channel over an insecure - network. It performs server host authentication, key exchange, - encryption, and integrity protection. It also derives a unique - session id that may be used by higher-level protocols. - - Full security considerations for this protocol are provided in - Section 8 of [SSH-ARCH] - -14. Intellectual Property - - The IETF takes no position regarding the validity or scope of any - intellectual property or other rights that might be claimed to - pertain to the implementation or use of the technology described in - this document or the extent to which any license under such rights - might or might not be available; neither does it represent that it - has made any effort to identify any such rights. Information on the - IETF's procedures with respect to rights in standards-track and - standards-related documentation can be found in BCP-11. Copies of - claims of rights made available for publication and any assurances of - licenses to be made available, or the result of an attempt made to - obtain a general license or permission for the use of such - proprietary rights by implementers or users of this specification can - be obtained from the IETF Secretariat. - - The IETF has been notified of intellectual property rights claimed in - regard to some or all of the specification contained in this - document. For more information consult the online list of claimed - rights. - -15. Additional Information - - The current document editor is: [email protected]. Comments on - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 24] - -Internet-Draft SSH Transport Layer Protocol Oct 2003 - - - this internet draft should be sent to the IETF SECSH working group, - details at: http://ietf.org/html.charters/secsh-charter.html - -Normative - - [SSH-ARCH] - Ylonen, T., "SSH Protocol Architecture", I-D - draft-ietf-architecture-15.txt, Oct 2003. - - [SSH-TRANS] - Ylonen, T., "SSH Transport Layer Protocol", I-D - draft-ietf-transport-17.txt, Oct 2003. - - [SSH-USERAUTH] - Ylonen, T., "SSH Authentication Protocol", I-D - draft-ietf-userauth-18.txt, Oct 2003. - - [SSH-CONNECT] - Ylonen, T., "SSH Connection Protocol", I-D - draft-ietf-connect-18.txt, Oct 2003. - - [SSH-NUMBERS] - Lehtinen, S. and D. Moffat, "SSH Protocol Assigned - Numbers", I-D draft-ietf-secsh-assignednumbers-05.txt, Oct - 2003. - - [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate - Requirement Levels", BCP 14, RFC 2119, March 1997. - -Informative - - [FIPS-186] - Federal Information Processing Standards Publication, - "FIPS PUB 186, Digital Signature Standard", May 1994. - - [FIPS-197] - NIST, "FIPS PUB 197 Advanced Encryption Standard (AES)", - November 2001. - - [FIPS-46-3] - U.S. Dept. of Commerce, "FIPS PUB 46-3, Data Encryption - Standard (DES)", October 1999. - - [RFC2459] Housley, R., Ford, W., Polk, T. and D. Solo, "Internet - X.509 Public Key Infrastructure Certificate and CRL - Profile", RFC 2459, January 1999. - - [RFC1034] Mockapetris, P., "Domain names - concepts and facilities", - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 25] - -Internet-Draft SSH Transport Layer Protocol Oct 2003 - - - STD 13, RFC 1034, November 1987. - - [RFC3066] Alvestrand, H., "Tags for the Identification of - Languages", BCP 47, RFC 3066, January 2001. - - [RFC1950] Deutsch, L. and J-L. Gailly, "ZLIB Compressed Data Format - Specification version 3.3", RFC 1950, May 1996. - - [RFC1951] Deutsch, P., "DEFLATE Compressed Data Format Specification - version 1.3", RFC 1951, May 1996. - - [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO - 10646", RFC 2279, January 1998. - - [RFC2104] Krawczyk, H., Bellare, M. and R. Canetti, "HMAC: - Keyed-Hashing for Message Authentication", RFC 2104, - February 1997. - - [RFC2144] Adams, C., "The CAST-128 Encryption Algorithm", RFC 2144, - May 1997. - - [RFC2440] Callas, J., Donnerhacke, L., Finney, H. and R. Thayer, - "OpenPGP Message Format", RFC 2440, November 1998. - - [RFC2693] Ellison, C., Frantz, B., Lampson, B., Rivest, R., Thomas, - B. and T. Ylonen, "SPKI Certificate Theory", RFC 2693, - September 1999. - - [RFC3526] Kivinen, T. and M. Kojo, "More Modular Exponential (MODP) - Diffie-Hellman groups for Internet Key Exchange (IKE)", - RFC 3526, May 2003. - - [SCHNEIER] - Schneier, B., "Applied Cryptography Second Edition: - protocols algorithms and source in code in C", 1996. - - [TWOFISH] Schneier, B., "The Twofish Encryptions Algorithm: A - 128-Bit Block Cipher, 1st Edition", March 1999. - - - - - - - - - - - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 26] - -Internet-Draft SSH Transport Layer Protocol Oct 2003 - - -Authors' Addresses - - Tatu Ylonen - SSH Communications Security Corp - Fredrikinkatu 42 - HELSINKI FIN-00100 - Finland - - EMail: [email protected] - - - Darren J. Moffat (editor) - Sun Microsystems, Inc - 17 Network Circle - Menlo Park 95025 - USA - - EMail: [email protected] - -Appendix A. Contibutors - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 27] - -Internet-Draft SSH Transport Layer Protocol Oct 2003 - - -Intellectual Property Statement - - The IETF takes no position regarding the validity or scope of any - intellectual property or other rights that might be claimed to - pertain to the implementation or use of the technology described in - this document or the extent to which any license under such rights - might or might not be available; neither does it represent that it - has made any effort to identify any such rights. Information on the - IETF's procedures with respect to rights in standards-track and - standards-related documentation can be found in BCP-11. Copies of - claims of rights made available for publication and any assurances of - licenses to be made available, or the result of an attempt made to - obtain a general license or permission for the use of such - proprietary rights by implementors or users of this specification can - be obtained from the IETF Secretariat. - - The IETF invites any interested party to bring to its attention any - copyrights, patents or patent applications, or other proprietary - rights which may cover technology that may be required to practice - this standard. Please address the information to the IETF Executive - Director. - - The IETF has been notified of intellectual property rights claimed in - regard to some or all of the specification contained in this - document. For more information consult the online list of claimed - rights. - - -Full Copyright Statement - - Copyright (C) The Internet Society (2003). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assignees. - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 28] - -Internet-Draft SSH Transport Layer Protocol Oct 2003 - - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - - -Acknowledgment - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Ylonen & Moffat, Editor Expires March 31, 2004 [Page 29]
\ No newline at end of file diff --git a/lib/ssh/doc/standard/draft-ietf-secsh-userauth-18.2.ps b/lib/ssh/doc/standard/draft-ietf-secsh-userauth-18.2.ps deleted file mode 100644 index be5799dbce..0000000000 --- a/lib/ssh/doc/standard/draft-ietf-secsh-userauth-18.2.ps +++ /dev/null @@ -1,1881 +0,0 @@ -%!PS-Adobe-3.0 -%%BoundingBox: 75 0 595 747 -%%Title: Enscript Output -%%For: Magnus Thoang -%%Creator: GNU enscript 1.6.1 -%%CreationDate: Fri Oct 31 13:35:32 2003 -%%Orientation: Portrait -%%Pages: 8 0 -%%DocumentMedia: A4 595 842 0 () () -%%DocumentNeededResources: (atend) -%%EndComments -%%BeginProlog -%%BeginProcSet: PStoPS 1 15 -userdict begin -[/showpage/erasepage/copypage]{dup where{pop dup load - type/operatortype eq{1 array cvx dup 0 3 index cvx put - bind def}{pop}ifelse}{pop}ifelse}forall -[/letter/legal/executivepage/a4/a4small/b5/com10envelope - /monarchenvelope/c5envelope/dlenvelope/lettersmall/note - /folio/quarto/a5]{dup where{dup wcheck{exch{}put} - {pop{}def}ifelse}{pop}ifelse}forall -/setpagedevice {pop}bind 1 index where{dup wcheck{3 1 roll put} - {pop def}ifelse}{def}ifelse -/PStoPSmatrix matrix currentmatrix def -/PStoPSxform matrix def/PStoPSclip{clippath}def -/defaultmatrix{PStoPSmatrix exch PStoPSxform exch concatmatrix}bind def -/initmatrix{matrix defaultmatrix setmatrix}bind def -/initclip[{matrix currentmatrix PStoPSmatrix setmatrix - [{currentpoint}stopped{$error/newerror false put{newpath}} - {/newpath cvx 3 1 roll/moveto cvx 4 array astore cvx}ifelse] - {[/newpath cvx{/moveto cvx}{/lineto cvx} - {/curveto cvx}{/closepath cvx}pathforall]cvx exch pop} - stopped{$error/errorname get/invalidaccess eq{cleartomark - $error/newerror false put cvx exec}{stop}ifelse}if}bind aload pop - /initclip dup load dup type dup/operatortype eq{pop exch pop} - {dup/arraytype eq exch/packedarraytype eq or - {dup xcheck{exch pop aload pop}{pop cvx}ifelse} - {pop cvx}ifelse}ifelse - {newpath PStoPSclip clip newpath exec setmatrix} bind aload pop]cvx def -/initgraphics{initmatrix newpath initclip 1 setlinewidth - 0 setlinecap 0 setlinejoin []0 setdash 0 setgray - 10 setmiterlimit}bind def -end -%%EndProcSet -%%BeginResource: procset Enscript-Prolog 1.6 1 -% -% Procedures. -% - -/_S { % save current state - /_s save def -} def -/_R { % restore from saved state - _s restore -} def - -/S { % showpage protecting gstate - gsave - showpage - grestore -} bind def - -/MF { % fontname newfontname -> - make a new encoded font - /newfontname exch def - /fontname exch def - - /fontdict fontname findfont def - /newfont fontdict maxlength dict def - - fontdict { - exch - dup /FID eq { - % skip FID pair - pop pop - } { - % copy to the new font dictionary - exch newfont 3 1 roll put - } ifelse - } forall - - newfont /FontName newfontname put - - % insert only valid encoding vectors - encoding_vector length 256 eq { - newfont /Encoding encoding_vector put - } if - - newfontname newfont definefont pop -} def - -/SF { % fontname width height -> - set a new font - /height exch def - /width exch def - - findfont - [width 0 0 height 0 0] makefont setfont -} def - -/SUF { % fontname width height -> - set a new user font - /height exch def - /width exch def - - /F-gs-user-font MF - /F-gs-user-font width height SF -} def - -/M {moveto} bind def -/s {show} bind def - -/Box { % x y w h -> - define box path - /d_h exch def /d_w exch def /d_y exch def /d_x exch def - d_x d_y moveto - d_w 0 rlineto - 0 d_h rlineto - d_w neg 0 rlineto - closepath -} def - -/bgs { % x y height blskip gray str -> - show string with bg color - /str exch def - /gray exch def - /blskip exch def - /height exch def - /y exch def - /x exch def - - gsave - x y blskip sub str stringwidth pop height Box - gray setgray - fill - grestore - x y M str s -} def - -% Highlight bars. -/highlight_bars { % nlines lineheight output_y_margin gray -> - - gsave - setgray - /ymarg exch def - /lineheight exch def - /nlines exch def - - % This 2 is just a magic number to sync highlight lines to text. - 0 d_header_y ymarg sub 2 sub translate - - /cw d_output_w cols div def - /nrows d_output_h ymarg 2 mul sub lineheight div cvi def - - % for each column - 0 1 cols 1 sub { - cw mul /xp exch def - - % for each rows - 0 1 nrows 1 sub { - /rn exch def - rn lineheight mul neg /yp exch def - rn nlines idiv 2 mod 0 eq { - % Draw highlight bar. 4 is just a magic indentation. - xp 4 add yp cw 8 sub lineheight neg Box fill - } if - } for - } for - - grestore -} def - -% Line highlight bar. -/line_highlight { % x y width height gray -> - - gsave - /gray exch def - Box gray setgray fill - grestore -} def - -% Column separator lines. -/column_lines { - gsave - .1 setlinewidth - 0 d_footer_h translate - /cw d_output_w cols div def - 1 1 cols 1 sub { - cw mul 0 moveto - 0 d_output_h rlineto stroke - } for - grestore -} def - -% Column borders. -/column_borders { - gsave - .1 setlinewidth - 0 d_footer_h moveto - 0 d_output_h rlineto - d_output_w 0 rlineto - 0 d_output_h neg rlineto - closepath stroke - grestore -} def - -% Do the actual underlay drawing -/draw_underlay { - ul_style 0 eq { - ul_str true charpath stroke - } { - ul_str show - } ifelse -} def - -% Underlay -/underlay { % - -> - - gsave - 0 d_page_h translate - d_page_h neg d_page_w atan rotate - - ul_gray setgray - ul_font setfont - /dw d_page_h dup mul d_page_w dup mul add sqrt def - ul_str stringwidth pop dw exch sub 2 div ul_h_ptsize -2 div moveto - draw_underlay - grestore -} def - -/user_underlay { % - -> - - gsave - ul_x ul_y translate - ul_angle rotate - ul_gray setgray - ul_font setfont - 0 0 ul_h_ptsize 2 div sub moveto - draw_underlay - grestore -} def - -% Page prefeed -/page_prefeed { % bool -> - - statusdict /prefeed known { - statusdict exch /prefeed exch put - } { - pop - } ifelse -} def - -% Wrapped line markers -/wrapped_line_mark { % x y charwith charheight type -> - - /type exch def - /h exch def - /w exch def - /y exch def - /x exch def - - type 2 eq { - % Black boxes (like TeX does) - gsave - 0 setlinewidth - x w 4 div add y M - 0 h rlineto w 2 div 0 rlineto 0 h neg rlineto - closepath fill - grestore - } { - type 3 eq { - % Small arrows - gsave - .2 setlinewidth - x w 2 div add y h 2 div add M - w 4 div 0 rlineto - x w 4 div add y lineto stroke - - x w 4 div add w 8 div add y h 4 div add M - x w 4 div add y lineto - w 4 div h 8 div rlineto stroke - grestore - } { - % do nothing - } ifelse - } ifelse -} def - -% EPSF import. - -/BeginEPSF { - /b4_Inc_state save def % Save state for cleanup - /dict_count countdictstack def % Count objects on dict stack - /op_count count 1 sub def % Count objects on operand stack - userdict begin - /showpage { } def - 0 setgray 0 setlinecap - 1 setlinewidth 0 setlinejoin - 10 setmiterlimit [ ] 0 setdash newpath - /languagelevel where { - pop languagelevel - 1 ne { - false setstrokeadjust false setoverprint - } if - } if -} bind def - -/EndEPSF { - count op_count sub { pos } repeat % Clean up stacks - countdictstack dict_count sub { end } repeat - b4_Inc_state restore -} bind def - -% Check PostScript language level. -/languagelevel where { - pop /gs_languagelevel languagelevel def -} { - /gs_languagelevel 1 def -} ifelse -%%EndResource -%%BeginResource: procset Enscript-Encoding-88591 1.6 1 -/encoding_vector [ -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/space /exclam /quotedbl /numbersign -/dollar /percent /ampersand /quoteright -/parenleft /parenright /asterisk /plus -/comma /hyphen /period /slash -/zero /one /two /three -/four /five /six /seven -/eight /nine /colon /semicolon -/less /equal /greater /question -/at /A /B /C -/D /E /F /G -/H /I /J /K -/L /M /N /O -/P /Q /R /S -/T /U /V /W -/X /Y /Z /bracketleft -/backslash /bracketright /asciicircum /underscore -/quoteleft /a /b /c -/d /e /f /g -/h /i /j /k -/l /m /n /o -/p /q /r /s -/t /u /v /w -/x /y /z /braceleft -/bar /braceright /tilde /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/.notdef /.notdef /.notdef /.notdef -/space /exclamdown /cent /sterling -/currency /yen /brokenbar /section -/dieresis /copyright /ordfeminine /guillemotleft -/logicalnot /hyphen /registered /macron -/degree /plusminus /twosuperior /threesuperior -/acute /mu /paragraph /bullet -/cedilla /onesuperior /ordmasculine /guillemotright -/onequarter /onehalf /threequarters /questiondown -/Agrave /Aacute /Acircumflex /Atilde -/Adieresis /Aring /AE /Ccedilla -/Egrave /Eacute /Ecircumflex /Edieresis -/Igrave /Iacute /Icircumflex /Idieresis -/Eth /Ntilde /Ograve /Oacute -/Ocircumflex /Otilde /Odieresis /multiply -/Oslash /Ugrave /Uacute /Ucircumflex -/Udieresis /Yacute /Thorn /germandbls -/agrave /aacute /acircumflex /atilde -/adieresis /aring /ae /ccedilla -/egrave /eacute /ecircumflex /edieresis -/igrave /iacute /icircumflex /idieresis -/eth /ntilde /ograve /oacute -/ocircumflex /otilde /odieresis /divide -/oslash /ugrave /uacute /ucircumflex -/udieresis /yacute /thorn /ydieresis -] def -%%EndResource -%%EndProlog -%%BeginSetup -%%IncludeResource: font Courier-Bold -%%IncludeResource: font Courier -/HFpt_w 10 def -/HFpt_h 10 def -/Courier-Bold /HF-gs-font MF -/HF /HF-gs-font findfont [HFpt_w 0 0 HFpt_h 0 0] makefont def -/Courier /F-gs-font MF -/F-gs-font 10 10 SF -/#copies 1 def -/d_page_w 520 def -/d_page_h 747 def -/d_header_x 0 def -/d_header_y 747 def -/d_header_w 520 def -/d_header_h 0 def -/d_footer_x 0 def -/d_footer_y 0 def -/d_footer_w 520 def -/d_footer_h 0 def -/d_output_w 520 def -/d_output_h 747 def -/cols 1 def -userdict/PStoPSxform PStoPSmatrix matrix currentmatrix - matrix invertmatrix matrix concatmatrix - matrix invertmatrix put -%%EndSetup -%%Page: (0,1) 1 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 1 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 701 M -(Network Working Group T. Ylonen) s -5 690 M -(Internet-Draft SSH Communications Security Corp) s -5 679 M -(Expires: March 2, 2003 D. Moffat, Ed.) s -5 668 M -( Sun Microsystems, Inc) s -5 657 M -( September 2002) s -5 624 M -( SSH Authentication Protocol) s -5 613 M -( draft-ietf-secsh-userauth-18.txt) s -5 591 M -(Status of this Memo) s -5 569 M -( This document is an Internet-Draft and is in full conformance with) s -5 558 M -( all provisions of Section 10 of RFC2026.) s -5 536 M -( Internet-Drafts are working documents of the Internet Engineering) s -5 525 M -( Task Force \(IETF\), its areas, and its working groups. Note that other) s -5 514 M -( groups may also distribute working documents as Internet-Drafts.) s -5 492 M -( Internet-Drafts are draft documents valid for a maximum of six months) s -5 481 M -( and may be updated, replaced, or obsoleted by other documents at any) s -5 470 M -( time. It is inappropriate to use Internet-Drafts as reference) s -5 459 M -( material or to cite them other than as "work in progress.") s -5 437 M -( The list of current Internet-Drafts can be accessed at http://) s -5 426 M -( www.ietf.org/ietf/1id-abstracts.txt.) s -5 404 M -( The list of Internet-Draft Shadow Directories can be accessed at) s -5 393 M -( http://www.ietf.org/shadow.html.) s -5 371 M -( This Internet-Draft will expire on March 2, 2003.) s -5 349 M -(Copyright Notice) s -5 327 M -( Copyright \(C\) The Internet Society \(2002\). All Rights Reserved.) s -5 305 M -(Abstract) s -5 283 M -( SSH is a protocol for secure remote login and other secure network) s -5 272 M -( services over an insecure network. This document describes the SSH) s -5 261 M -( authentication protocol framework and public key, password, and) s -5 250 M -( host-based client authentication methods. Additional authentication) s -5 239 M -( methods are described in separate documents. The SSH authentication) s -5 228 M -( protocol runs on top of the SSH transport layer protocol and provides) s -5 217 M -( a single authenticated tunnel for the SSH connection protocol.) s -5 129 M -(Ylonen & Moffat Expires March 2, 2003 [Page 1]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 2 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Authentication Protocol September 2002) s -5 690 M -(Table of Contents) s -5 668 M -( 1. Contributors . . . . . . . . . . . . . . . . . . . . . . . . 3) s -5 657 M -( 2. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3) s -5 646 M -( 3. Conventions Used in This Document . . . . . . . . . . . . . 3) s -5 635 M -( 3.1 The Authentication Protocol Framework . . . . . . . . . . . 3) s -5 624 M -( 3.1.1 Authentication Requests . . . . . . . . . . . . . . . . . . 4) s -5 613 M -( 3.1.2 Responses to Authentication Requests . . . . . . . . . . . . 5) s -5 602 M -( 3.1.3 The "none" Authentication Request . . . . . . . . . . . . . 6) s -5 591 M -( 3.1.4 Completion of User Authentication . . . . . . . . . . . . . 6) s -5 580 M -( 3.1.5 Banner Message . . . . . . . . . . . . . . . . . . . . . . . 7) s -5 569 M -( 3.2 Authentication Protocol Message Numbers . . . . . . . . . . 7) s -5 558 M -( 3.3 Public Key Authentication Method: publickey . . . . . . . . 8) s -5 547 M -( 3.4 Password Authentication Method: password . . . . . . . . . . 10) s -5 536 M -( 3.5 Host-Based Authentication: hostbased . . . . . . . . . . . . 11) s -5 525 M -( 4. Security Considerations . . . . . . . . . . . . . . . . . . 12) s -5 514 M -( Normative . . . . . . . . . . . . . . . . . . . . . . . . . 13) s -5 503 M -( Informative . . . . . . . . . . . . . . . . . . . . . . . . 13) s -5 492 M -( Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 14) s -5 481 M -( Intellectual Property and Copyright Statements . . . . . . . 15) s -5 129 M -(Ylonen & Moffat Expires March 2, 2003 [Page 2]) s -_R -S -PStoPSsaved restore -%%Page: (2,3) 2 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 3 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Authentication Protocol September 2002) s -5 690 M -(1. Contributors) s -5 668 M -( The major original contributors of this document were: Tatu Ylonen,) s -5 657 M -( Tero Kivinen, Timo J. Rinne, Sami Lehtinen \(all of SSH Communications) s -5 646 M -( Security Corp\), and Markku-Juhani O. Saarinen \(University of) s -5 635 M -( Jyvaskyla\)) s -5 613 M -( The document editor is: [email protected]. Comments on this) s -5 602 M -( internet draft should be sent to the IETF SECSH working group,) s -5 591 M -( details at: http://ietf.org/html.charters/secsh-charter.html) s -5 569 M -(2. Introduction) s -5 547 M -( The SSH authentication protocol is a general-purpose user) s -5 536 M -( authentication protocol. It is intended to be run over the SSH) s -5 525 M -( transport layer protocol [SSH-TRANS]. This protocol assumes that the) s -5 514 M -( underlying protocols provide integrity and confidentiality) s -5 503 M -( protection.) s -5 481 M -( This document should be read only after reading the SSH architecture) s -5 470 M -( document [SSH-ARCH]. This document freely uses terminology and) s -5 459 M -( notation from the architecture document without reference or further) s -5 448 M -( explanation.) s -5 426 M -( The service name for this protocol is "ssh-userauth".) s -5 404 M -( When this protocol starts, it receives the session identifier from) s -5 393 M -( the lower-level protocol \(this is the exchange hash H from the first) s -5 382 M -( key exchange\). The session identifier uniquely identifies this) s -5 371 M -( session and is suitable for signing in order to prove ownership of a) s -5 360 M -( private key. This protocol also needs to know whether the lower-level) s -5 349 M -( protocol provides confidentiality protection.) s -5 327 M -(3. Conventions Used in This Document) s -5 305 M -( The keywords "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT",) s -5 294 M -( and "MAY" that appear in this document are to be interpreted as) s -5 283 M -( described in [RFC2119]) s -5 261 M -( The used data types and terminology are specified in the architecture) s -5 250 M -( document [SSH-ARCH]) s -5 228 M -( The architecture document also discusses the algorithm naming) s -5 217 M -( conventions that MUST be used with the SSH protocols.) s -5 195 M -(3.1 The Authentication Protocol Framework) s -5 173 M -( The server drives the authentication by telling the client which) s -5 129 M -(Ylonen & Moffat Expires March 2, 2003 [Page 3]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 4 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Authentication Protocol September 2002) s -5 690 M -( authentication methods can be used to continue the exchange at any) s -5 679 M -( given time. The client has the freedom to try the methods listed by) s -5 668 M -( the server in any order. This gives the server complete control over) s -5 657 M -( the authentication process if desired, but also gives enough) s -5 646 M -( flexibility for the client to use the methods it supports or that are) s -5 635 M -( most convenient for the user, when multiple methods are offered by) s -5 624 M -( the server.) s -5 602 M -( Authentication methods are identified by their name, as defined in) s -5 591 M -( [SSH-ARCH]. The "none" method is reserved, and MUST NOT be listed as) s -5 580 M -( supported. However, it MAY be sent by the client. The server MUST) s -5 569 M -( always reject this request, unless the client is to be allowed in) s -5 558 M -( without any authentication, in which case the server MUST accept this) s -5 547 M -( request. The main purpose of sending this request is to get the list) s -5 536 M -( of supported methods from the server.) s -5 514 M -( The server SHOULD have a timeout for authentication, and disconnect) s -5 503 M -( if the authentication has not been accepted within the timeout) s -5 492 M -( period. The RECOMMENDED timeout period is 10 minutes. Additionally,) s -5 481 M -( the implementation SHOULD limit the number of failed authentication) s -5 470 M -( attempts a client may perform in a single session \(the RECOMMENDED) s -5 459 M -( limit is 20 attempts\). If the threshold is exceeded, the server) s -5 448 M -( SHOULD disconnect.) s -5 426 M -(3.1.1 Authentication Requests) s -5 404 M -( All authentication requests MUST use the following message format.) s -5 393 M -( Only the first few fields are defined; the remaining fields depend on) s -5 382 M -( the authentication method.) s -5 360 M -( byte SSH_MSG_USERAUTH_REQUEST) s -5 349 M -( string user name \(in ISO-10646 UTF-8 encoding [RFC2279]\)) s -5 338 M -( string service name \(in US-ASCII\)) s -5 327 M -( string method name \(US-ASCII\)) s -5 316 M -( The rest of the packet is method-specific.) s -5 294 M -( The user name and service are repeated in every new authentication) s -5 283 M -( attempt, and MAY change. The server implementation MUST carefully) s -5 272 M -( check them in every message, and MUST flush any accumulated) s -5 261 M -( authentication states if they change. If it is unable to flush some) s -5 250 M -( authentication state, it MUST disconnect if the user or service name) s -5 239 M -( changes.) s -5 217 M -( The service name specifies the service to start after authentication.) s -5 206 M -( There may be several different authenticated services provided. If) s -5 195 M -( the requested service is not available, the server MAY disconnect) s -5 184 M -( immediately or at any later time. Sending a proper disconnect) s -5 173 M -( message is RECOMMENDED. In any case, if the service does not exist,) s -5 129 M -(Ylonen & Moffat Expires March 2, 2003 [Page 4]) s -_R -S -PStoPSsaved restore -%%Page: (4,5) 3 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 5 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Authentication Protocol September 2002) s -5 690 M -( authentication MUST NOT be accepted.) s -5 668 M -( If the requested user does not exist, the server MAY disconnect, or) s -5 657 M -( MAY send a bogus list of acceptable authentication methods, but never) s -5 646 M -( accept any. This makes it possible for the server to avoid) s -5 635 M -( disclosing information on which accounts exist. In any case, if the) s -5 624 M -( user does not exist, the authentication request MUST NOT be accepted.) s -5 602 M -( While there is usually little point for clients to send requests that) s -5 591 M -( the server does not list as acceptable, sending such requests is not) s -5 580 M -( an error, and the server SHOULD simply reject requests that it does) s -5 569 M -( not recognize.) s -5 547 M -( An authentication request MAY result in a further exchange of) s -5 536 M -( messages. All such messages depend on the authentication method) s -5 525 M -( used, and the client MAY at any time continue with a new) s -5 514 M -( SSH_MSG_USERAUTH_REQUEST message, in which case the server MUST) s -5 503 M -( abandon the previous authentication attempt and continue with the new) s -5 492 M -( one.) s -5 470 M -(3.1.2 Responses to Authentication Requests) s -5 448 M -( If the server rejects the authentication request, it MUST respond) s -5 437 M -( with the following:) s -5 415 M -( byte SSH_MSG_USERAUTH_FAILURE) s -5 404 M -( string authentications that can continue) s -5 393 M -( boolean partial success) s -5 371 M -( "Authentications that can continue" is a comma-separated list of) s -5 360 M -( authentication method names that may productively continue the) s -5 349 M -( authentication dialog.) s -5 327 M -( It is RECOMMENDED that servers only include those methods in the list) s -5 316 M -( that are actually useful. However, it is not illegal to include) s -5 305 M -( methods that cannot be used to authenticate the user.) s -5 283 M -( Already successfully completed authentications SHOULD NOT be included) s -5 272 M -( in the list, unless they really should be performed again for some) s -5 261 M -( reason.) s -5 239 M -( "Partial success" MUST be TRUE if the authentication request to which) s -5 228 M -( this is a response was successful. It MUST be FALSE if the request) s -5 217 M -( was not successfully processed.) s -5 195 M -( When the server accepts authentication, it MUST respond with the) s -5 184 M -( following:) s -5 129 M -(Ylonen & Moffat Expires March 2, 2003 [Page 5]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 6 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Authentication Protocol September 2002) s -5 690 M -( byte SSH_MSG_USERAUTH_SUCCESS) s -5 668 M -( Note that this is not sent after each step in a multi-method) s -5 657 M -( authentication sequence, but only when the authentication is) s -5 646 M -( complete.) s -5 624 M -( The client MAY send several authentication requests without waiting) s -5 613 M -( for responses from previous requests. The server MUST process each) s -5 602 M -( request completely and acknowledge any failed requests with a) s -5 591 M -( SSH_MSG_USERAUTH_FAILURE message before processing the next request.) s -5 569 M -( A request that results in further exchange of messages will be) s -5 558 M -( aborted by a second request. It is not possible to send a second) s -5 547 M -( request without waiting for a response from the server, if the first) s -5 536 M -( request will result in further exchange of messages. No) s -5 525 M -( SSH_MSG_USERAUTH_FAILURE message will be sent for the aborted method.) s -5 503 M -( SSH_MSG_USERAUTH_SUCCESS MUST be sent only once. When) s -5 492 M -( SSH_MSG_USERAUTH_SUCCESS has been sent, any further authentication) s -5 481 M -( requests received after that SHOULD be silently ignored.) s -5 459 M -( Any non-authentication messages sent by the client after the request) s -5 448 M -( that resulted in SSH_MSG_USERAUTH_SUCCESS being sent MUST be passed) s -5 437 M -( to the service being run on top of this protocol. Such messages can) s -5 426 M -( be identified by their message numbers \(see Section Message Numbers) s -5 415 M -( \(Section 3.2\)\).) s -5 393 M -(3.1.3 The "none" Authentication Request) s -5 371 M -( A client may request a list of authentication methods that may) s -5 360 M -( continue by using the "none" authentication method.) s -5 338 M -( If no authentication at all is needed for the user, the server MUST) s -5 327 M -( return SSH_MSG_USERAUTH_SUCCESS. Otherwise, the server MUST return) s -5 316 M -( SSH_MSG_USERAUTH_FAILURE and MAY return with it a list of) s -5 305 M -( authentication methods that can continue.) s -5 283 M -( This method MUST NOT be listed as supported by the server.) s -5 261 M -(3.1.4 Completion of User Authentication) s -5 239 M -( Authentication is complete when the server has responded with) s -5 228 M -( SSH_MSG_USERAUTH_SUCCESS; all authentication related messages) s -5 217 M -( received after sending this message SHOULD be silently ignored.) s -5 195 M -( After sending SSH_MSG_USERAUTH_SUCCESS, the server starts the) s -5 184 M -( requested service.) s -5 129 M -(Ylonen & Moffat Expires March 2, 2003 [Page 6]) s -_R -S -PStoPSsaved restore -%%Page: (6,7) 4 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 7 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Authentication Protocol September 2002) s -5 690 M -(3.1.5 Banner Message) s -5 668 M -( In some jurisdictions, sending a warning message before) s -5 657 M -( authentication may be relevant for getting legal protection. Many) s -5 646 M -( UNIX machines, for example, normally display text from `/etc/issue',) s -5 635 M -( or use "tcp wrappers" or similar software to display a banner before) s -5 624 M -( issuing a login prompt.) s -5 602 M -( The SSH server may send a SSH_MSG_USERAUTH_BANNER message at any time) s -5 591 M -( before authentication is successful. This message contains text to) s -5 580 M -( be displayed to the client user before authentication is attempted.) s -5 569 M -( The format is as follows:) s -5 547 M -( byte SSH_MSG_USERAUTH_BANNER) s -5 536 M -( string message \(ISO-10646 UTF-8\)) s -5 525 M -( string language tag \(as defined in [RFC3066]\)) s -5 503 M -( The client SHOULD by default display the message on the screen.) s -5 492 M -( However, since the message is likely to be sent for every login) s -5 481 M -( attempt, and since some client software will need to open a separate) s -5 470 M -( window for this warning, the client software may allow the user to) s -5 459 M -( explicitly disable the display of banners from the server. The) s -5 448 M -( message may consist of multiple lines.) s -5 426 M -( If the message string is displayed, control character filtering) s -5 415 M -( discussed in [SSH-ARCH] SHOULD be used to avoid attacks by sending) s -5 404 M -( terminal control characters.) s -5 382 M -(3.2 Authentication Protocol Message Numbers) s -5 360 M -( All message numbers used by this authentication protocol are in the) s -5 349 M -( range from 50 to 79, which is part of the range reserved for) s -5 338 M -( protocols running on top of the SSH transport layer protocol.) s -5 316 M -( Message numbers of 80 and higher are reserved for protocols running) s -5 305 M -( after this authentication protocol, so receiving one of them before) s -5 294 M -( authentication is complete is an error, to which the server MUST) s -5 283 M -( respond by disconnecting \(preferably with a proper disconnect message) s -5 272 M -( sent first to ease troubleshooting\).) s -5 250 M -( After successful authentication, such messages are passed to the) s -5 239 M -( higher-level service.) s -5 217 M -( These are the general authentication message codes:) s -5 195 M -( #define SSH_MSG_USERAUTH_REQUEST 50) s -5 184 M -( #define SSH_MSG_USERAUTH_FAILURE 51) s -5 173 M -( #define SSH_MSG_USERAUTH_SUCCESS 52) s -5 129 M -(Ylonen & Moffat Expires March 2, 2003 [Page 7]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 8 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Authentication Protocol September 2002) s -5 690 M -( #define SSH_MSG_USERAUTH_BANNER 53) s -5 668 M -( In addition to the above, there is a range of message numbers) s -5 657 M -( \(60..79\) reserved for method-specific messages. These messages are) s -5 646 M -( only sent by the server \(client sends only SSH_MSG_USERAUTH_REQUEST) s -5 635 M -( messages\). Different authentication methods reuse the same message) s -5 624 M -( numbers.) s -5 602 M -(3.3 Public Key Authentication Method: publickey) s -5 580 M -( The only REQUIRED authentication method is public key authentication.) s -5 569 M -( All implementations MUST support this method; however, not all users) s -5 558 M -( need to have public keys, and most local policies are not likely to) s -5 547 M -( require public key authentication for all users in the near future.) s -5 525 M -( With this method, the possession of a private key serves as) s -5 514 M -( authentication. This method works by sending a signature created) s -5 503 M -( with a private key of the user. The server MUST check that the key) s -5 492 M -( is a valid authenticator for the user, and MUST check that the) s -5 481 M -( signature is valid. If both hold, the authentication request MUST be) s -5 470 M -( accepted; otherwise it MUST be rejected. \(Note that the server MAY) s -5 459 M -( require additional authentications after successful authentication.\)) s -5 437 M -( Private keys are often stored in an encrypted form at the client) s -5 426 M -( host, and the user must supply a passphrase before the signature can) s -5 415 M -( be generated. Even if they are not, the signing operation involves) s -5 404 M -( some expensive computation. To avoid unnecessary processing and user) s -5 393 M -( interaction, the following message is provided for querying whether) s -5 382 M -( authentication using the key would be acceptable.) s -5 360 M -( byte SSH_MSG_USERAUTH_REQUEST) s -5 349 M -( string user name) s -5 338 M -( string service) s -5 327 M -( string "publickey") s -5 316 M -( boolean FALSE) s -5 305 M -( string public key algorithm name) s -5 294 M -( string public key blob) s -5 272 M -( Public key algorithms are defined in the transport layer) s -5 261 M -( specification [SSH-TRANS]. The public key blob may contain) s -5 250 M -( certificates.) s -5 228 M -( Any public key algorithm may be offered for use in authentication.) s -5 217 M -( In particular, the list is not constrained by what was negotiated) s -5 206 M -( during key exchange. If the server does not support some algorithm,) s -5 195 M -( it MUST simply reject the request.) s -5 173 M -( The server MUST respond to this message with either) s -5 129 M -(Ylonen & Moffat Expires March 2, 2003 [Page 8]) s -_R -S -PStoPSsaved restore -%%Page: (8,9) 5 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 9 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Authentication Protocol September 2002) s -5 690 M -( SSH_MSG_USERAUTH_FAILURE or with the following:) s -5 668 M -( byte SSH_MSG_USERAUTH_PK_OK) s -5 657 M -( string public key algorithm name from the request) s -5 646 M -( string public key blob from the request) s -5 624 M -( To perform actual authentication, the client MAY then send a) s -5 613 M -( signature generated using the private key. The client MAY send the) s -5 602 M -( signature directly without first verifying whether the key is) s -5 591 M -( acceptable. The signature is sent using the following packet:) s -5 569 M -( byte SSH_MSG_USERAUTH_REQUEST) s -5 558 M -( string user name) s -5 547 M -( string service) s -5 536 M -( string "publickey") s -5 525 M -( boolean TRUE) s -5 514 M -( string public key algorithm name) s -5 503 M -( string public key to be used for authentication) s -5 492 M -( string signature) s -5 470 M -( Signature is a signature by the corresponding private key over the) s -5 459 M -( following data, in the following order:) s -5 437 M -( string session identifier) s -5 426 M -( byte SSH_MSG_USERAUTH_REQUEST) s -5 415 M -( string user name) s -5 404 M -( string service) s -5 393 M -( string "publickey") s -5 382 M -( boolean TRUE) s -5 371 M -( string public key algorithm name) s -5 360 M -( string public key to be used for authentication) s -5 338 M -( When the server receives this message, it MUST check whether the) s -5 327 M -( supplied key is acceptable for authentication, and if so, it MUST) s -5 316 M -( check whether the signature is correct.) s -5 294 M -( If both checks succeed, this method is successful. Note that the) s -5 283 M -( server may require additional authentications. The server MUST) s -5 272 M -( respond with SSH_MSG_USERAUTH_SUCCESS \(if no more authentications are) s -5 261 M -( needed\), or SSH_MSG_USERAUTH_FAILURE \(if the request failed, or more) s -5 250 M -( authentications are needed\).) s -5 228 M -( The following method-specific message numbers are used by the) s -5 217 M -( publickey authentication method.) s -5 195 M -( /* Key-based */) s -5 184 M -( #define SSH_MSG_USERAUTH_PK_OK 60) s -5 129 M -(Ylonen & Moffat Expires March 2, 2003 [Page 9]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 10 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Authentication Protocol September 2002) s -5 690 M -(3.4 Password Authentication Method: password) s -5 668 M -( Password authentication uses the following packets. Note that a) s -5 657 M -( server MAY request the user to change the password. All) s -5 646 M -( implementations SHOULD support password authentication.) s -5 624 M -( byte SSH_MSG_USERAUTH_REQUEST) s -5 613 M -( string user name) s -5 602 M -( string service) s -5 591 M -( string "password") s -5 580 M -( boolean FALSE) s -5 569 M -( string plaintext password \(ISO-10646 UTF-8\)) s -5 547 M -( Note that the password is encoded in ISO-10646 UTF-8. It is up to) s -5 536 M -( the server how it interprets the password and validates it against) s -5 525 M -( the password database. However, if the client reads the password in) s -5 514 M -( some other encoding \(e.g., ISO 8859-1 \(ISO Latin1\)\), it MUST convert) s -5 503 M -( the password to ISO-10646 UTF-8 before transmitting, and the server) s -5 492 M -( MUST convert the password to the encoding used on that system for) s -5 481 M -( passwords.) s -5 459 M -( Note that even though the cleartext password is transmitted in the) s -5 448 M -( packet, the entire packet is encrypted by the transport layer. Both) s -5 437 M -( the server and the client should check whether the underlying) s -5 426 M -( transport layer provides confidentiality \(i.e., if encryption is) s -5 415 M -( being used\). If no confidentiality is provided \(none cipher\),) s -5 404 M -( password authentication SHOULD be disabled. If there is no) s -5 393 M -( confidentiality or no MAC, password change SHOULD be disabled.) s -5 371 M -( Normally, the server responds to this message with success or) s -5 360 M -( failure. However, if the password has expired the server SHOULD) s -5 349 M -( indicate this by responding with SSH_MSG_USERAUTH_PASSWD_CHANGEREQ.) s -5 338 M -( In anycase the server MUST NOT allow an expired password to be used) s -5 327 M -( for authentication.) s -5 305 M -( byte SSH_MSG_USERAUTH_PASSWD_CHANGEREQ) s -5 294 M -( string prompt \(ISO-10646 UTF-8\)) s -5 283 M -( string language tag \(as defined in [RFC3066]\)) s -5 261 M -( In this case, the client MAY continue with a different authentication) s -5 250 M -( method, or request a new password from the user and retry password) s -5 239 M -( authentication using the following message. The client MAY also send) s -5 228 M -( this message instead of the normal password authentication request) s -5 217 M -( without the server asking for it.) s -5 195 M -( byte SSH_MSG_USERAUTH_REQUEST) s -5 184 M -( string user name) s -5 173 M -( string service) s -5 129 M -(Ylonen & Moffat Expires March 2, 2003 [Page 10]) s -_R -S -PStoPSsaved restore -%%Page: (10,11) 6 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 11 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Authentication Protocol September 2002) s -5 690 M -( string "password") s -5 679 M -( boolean TRUE) s -5 668 M -( string plaintext old password \(ISO-10646 UTF-8\)) s -5 657 M -( string plaintext new password \(ISO-10646 UTF-8\)) s -5 635 M -( The server must reply to request message with) s -5 624 M -( SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, or another) s -5 613 M -( SSH_MSG_USERAUTH_PASSWD_CHANGEREQ. The meaning of these is as) s -5 602 M -( follows:) s -5 580 M -( SSH_MSG_USERAUTH_SUCCESS The password has been changed, and) s -5 569 M -( authentication has been successfully completed.) s -5 547 M -( SSH_MSG_USERAUTH_FAILURE with partial success The password has) s -5 536 M -( been changed, but more authentications are needed.) s -5 514 M -( SSH_MSG_USERAUTH_FAILURE without partial success The password has) s -5 503 M -( not been changed. Either password changing was not supported, or) s -5 492 M -( the old password was bad. Note that if the server has already) s -5 481 M -( sent SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, we know that it supports) s -5 470 M -( changing the password.) s -5 448 M -( SSH_MSG_USERAUTH_CHANGEREQ The password was not changed because) s -5 437 M -( the new password was not acceptable \(e.g. too easy to guess\).) s -5 415 M -( The following method-specific message numbers are used by the) s -5 404 M -( password authentication method.) s -5 382 M -( #define SSH_MSG_USERAUTH_PASSWD_CHANGEREQ 60) s -5 349 M -(3.5 Host-Based Authentication: hostbased) s -5 327 M -( Some sites wish to allow authentication based on the host where the) s -5 316 M -( user is coming from, and the user name on the remote host. While) s -5 305 M -( this form of authentication is not suitable for high-security sites,) s -5 294 M -( it can be very convenient in many environments. This form of) s -5 283 M -( authentication is OPTIONAL. When used, special care SHOULD be taken) s -5 272 M -( to prevent a regular user from obtaining the private host key.) s -5 250 M -( The client requests this form of authentication by sending the) s -5 239 M -( following message. It is similar to the UNIX "rhosts" and) s -5 228 M -( "hosts.equiv" styles of authentication, except that the identity of) s -5 217 M -( the client host is checked more rigorously.) s -5 195 M -( This method works by having the client send a signature created with) s -5 184 M -( the private key of the client host, which the server checks with that) s -5 173 M -( host's public key. Once the client host's identity is established,) s -5 129 M -(Ylonen & Moffat Expires March 2, 2003 [Page 11]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 12 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Authentication Protocol September 2002) s -5 690 M -( authorization \(but no further authentication\) is performed based on) s -5 679 M -( the user names on the server and the client, and the client host) s -5 668 M -( name.) s -5 646 M -( byte SSH_MSG_USERAUTH_REQUEST) s -5 635 M -( string user name) s -5 624 M -( string service) s -5 613 M -( string "hostbased") s -5 602 M -( string public key algorithm for host key) s -5 591 M -( string public host key and certificates for client host) s -5 580 M -( string client host name \(FQDN; US-ASCII\)) s -5 569 M -( string user name on the client host \(ISO-10646 UTF-8\)) s -5 558 M -( string signature) s -5 536 M -( Public key algorithm names for use in "public key algorithm for host) s -5 525 M -( key" are defined in the transport layer specification. The "public) s -5 514 M -( host key for client host" may include certificates.) s -5 492 M -( Signature is a signature with the private host key of the following) s -5 481 M -( data, in this order:) s -5 459 M -( string session identifier) s -5 448 M -( byte SSH_MSG_USERAUTH_REQUEST) s -5 437 M -( string user name) s -5 426 M -( string service) s -5 415 M -( string "hostbased") s -5 404 M -( string public key algorithm for host key) s -5 393 M -( string public host key and certificates for client host) s -5 382 M -( string client host name \(FQDN; US-ASCII\)) s -5 371 M -( string user name on the client host\(ISO-10646 UTF-8\)) s -5 349 M -( The server MUST verify that the host key actually belongs to the) s -5 338 M -( client host named in the message, that the given user on that host is) s -5 327 M -( allowed to log in, and that the signature is a valid signature on the) s -5 316 M -( appropriate value by the given host key. The server MAY ignore the) s -5 305 M -( client user name, if it wants to authenticate only the client host.) s -5 283 M -( It is RECOMMENDED that whenever possible, the server perform) s -5 272 M -( additional checks to verify that the network address obtained from) s -5 261 M -( the \(untrusted\) network matches the given client host name. This) s -5 250 M -( makes exploiting compromised host keys more difficult. Note that) s -5 239 M -( this may require special handling for connections coming through a) s -5 228 M -( firewall.) s -5 206 M -(4. Security Considerations) s -5 184 M -( The purpose of this protocol is to perform client user) s -5 173 M -( authentication. It assumed that this runs over a secure transport) s -5 129 M -(Ylonen & Moffat Expires March 2, 2003 [Page 12]) s -_R -S -PStoPSsaved restore -%%Page: (12,13) 7 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 13 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Authentication Protocol September 2002) s -5 690 M -( layer protocol, which has already authenticated the server machine,) s -5 679 M -( established an encrypted communications channel, and computed a) s -5 668 M -( unique session identifier for this session. The transport layer) s -5 657 M -( provides forward secrecy for password authentication and other) s -5 646 M -( methods that rely on secret data.) s -5 624 M -( Full security considerations for this protocol are provided in) s -5 613 M -( Section 8 of [SSH-ARCH]) s -5 591 M -(Normative) s -5 569 M -( [SSH-ARCH]) s -5 558 M -( Ylonen, T., "SSH Protocol Architecture", I-D) s -5 547 M -( draft-ietf-architecture-15.txt, Oct 2003.) s -5 525 M -( [SSH-TRANS]) s -5 514 M -( Ylonen, T., "SSH Transport Layer Protocol", I-D) s -5 503 M -( draft-ietf-transport-17.txt, Oct 2003.) s -5 481 M -( [SSH-USERAUTH]) s -5 470 M -( Ylonen, T., "SSH Authentication Protocol", I-D) s -5 459 M -( draft-ietf-userauth-18.txt, Oct 2003.) s -5 437 M -( [SSH-CONNECT]) s -5 426 M -( Ylonen, T., "SSH Connection Protocol", I-D) s -5 415 M -( draft-ietf-connect-18.txt, Oct 2003.) s -5 393 M -( [SSH-NUMBERS]) s -5 382 M -( Lehtinen, S. and D. Moffat, "SSH Protocol Assigned) s -5 371 M -( Numbers", I-D draft-ietf-secsh-assignednumbers-05.txt, Oct) s -5 360 M -( 2003.) s -5 338 M -( [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate) s -5 327 M -( Requirement Levels", BCP 14, RFC 2119, March 1997.) s -5 305 M -(Informative) s -5 283 M -( [RFC3066] Alvestrand, H., "Tags for the Identification of) s -5 272 M -( Languages", BCP 47, RFC 3066, January 2001.) s -5 250 M -( [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO) s -5 239 M -( 10646", RFC 2279, January 1998.) s -5 129 M -(Ylonen & Moffat Expires March 2, 2003 [Page 13]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 14 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Authentication Protocol September 2002) s -5 690 M -(Authors' Addresses) s -5 668 M -( Tatu Ylonen) s -5 657 M -( SSH Communications Security Corp) s -5 646 M -( Fredrikinkatu 42) s -5 635 M -( HELSINKI FIN-00100) s -5 624 M -( Finland) s -5 602 M -( EMail: [email protected]) s -5 569 M -( Darren J. Moffat \(editor\)) s -5 558 M -( Sun Microsystems, Inc) s -5 547 M -( 17 Network Circle) s -5 536 M -( Menlo Park 95025) s -5 525 M -( USA) s -5 503 M -( EMail: [email protected]) s -5 129 M -(Ylonen & Moffat Expires March 2, 2003 [Page 14]) s -_R -S -PStoPSsaved restore -%%Page: (14,15) 8 -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 0.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -/showpage{}def/copypage{}def/erasepage{}def -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 15 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Authentication Protocol September 2002) s -5 690 M -(Intellectual Property Statement) s -5 668 M -( The IETF takes no position regarding the validity or scope of any) s -5 657 M -( intellectual property or other rights that might be claimed to) s -5 646 M -( pertain to the implementation or use of the technology described in) s -5 635 M -( this document or the extent to which any license under such rights) s -5 624 M -( might or might not be available; neither does it represent that it) s -5 613 M -( has made any effort to identify any such rights. Information on the) s -5 602 M -( IETF's procedures with respect to rights in standards-track and) s -5 591 M -( standards-related documentation can be found in BCP-11. Copies of) s -5 580 M -( claims of rights made available for publication and any assurances of) s -5 569 M -( licenses to be made available, or the result of an attempt made to) s -5 558 M -( obtain a general license or permission for the use of such) s -5 547 M -( proprietary rights by implementors or users of this specification can) s -5 536 M -( be obtained from the IETF Secretariat.) s -5 514 M -( The IETF invites any interested party to bring to its attention any) s -5 503 M -( copyrights, patents or patent applications, or other proprietary) s -5 492 M -( rights which may cover technology that may be required to practice) s -5 481 M -( this standard. Please address the information to the IETF Executive) s -5 470 M -( Director.) s -5 448 M -( The IETF has been notified of intellectual property rights claimed in) s -5 437 M -( regard to some or all of the specification contained in this) s -5 426 M -( document. For more information consult the online list of claimed) s -5 415 M -( rights.) s -5 382 M -(Full Copyright Statement) s -5 360 M -( Copyright \(C\) The Internet Society \(2002\). All Rights Reserved.) s -5 338 M -( This document and translations of it may be copied and furnished to) s -5 327 M -( others, and derivative works that comment on or otherwise explain it) s -5 316 M -( or assist in its implementation may be prepared, copied, published) s -5 305 M -( and distributed, in whole or in part, without restriction of any) s -5 294 M -( kind, provided that the above copyright notice and this paragraph are) s -5 283 M -( included on all such copies and derivative works. However, this) s -5 272 M -( document itself may not be modified in any way, such as by removing) s -5 261 M -( the copyright notice or references to the Internet Society or other) s -5 250 M -( Internet organizations, except as needed for the purpose of) s -5 239 M -( developing Internet standards in which case the procedures for) s -5 228 M -( copyrights defined in the Internet Standards process must be) s -5 217 M -( followed, or as required to translate it into languages other than) s -5 206 M -( English.) s -5 184 M -( The limited permissions granted above are perpetual and will not be) s -5 173 M -( revoked by the Internet Society or its successors or assignees.) s -5 129 M -(Ylonen & Moffat Expires March 2, 2003 [Page 15]) s -_R -S -PStoPSsaved restore -userdict/PStoPSsaved save put -PStoPSmatrix setmatrix -595.000000 421.271378 translate -90 rotate -0.706651 dup scale -userdict/PStoPSmatrix matrix currentmatrix put -userdict/PStoPSclip{0 0 moveto - 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto - closepath}put initclip -PStoPSxform concat -%%BeginPageSetup -_S -75 0 translate -/pagenum 16 def -/fname () def -/fdir () def -/ftail () def -/user_header_p false def -%%EndPageSetup -5 723 M -(Internet-Draft SSH Authentication Protocol September 2002) s -5 690 M -( This document and the information contained herein is provided on an) s -5 679 M -( "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING) s -5 668 M -( TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING) s -5 657 M -( BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION) s -5 646 M -( HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF) s -5 635 M -( MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.) s -5 602 M -(Acknowledgment) s -5 580 M -( Funding for the RFC Editor function is currently provided by the) s -5 569 M -( Internet Society.) s -5 129 M -(Ylonen & Moffat Expires March 2, 2003 [Page 16]) s -_R -S -PStoPSsaved restore -%%Trailer -%%Pages: 16 -%%DocumentNeededResources: font Courier-Bold Courier -%%EOF diff --git a/lib/ssh/doc/standard/draft-ietf-secsh-userauth-18.txt b/lib/ssh/doc/standard/draft-ietf-secsh-userauth-18.txt deleted file mode 100644 index 9dae578a35..0000000000 --- a/lib/ssh/doc/standard/draft-ietf-secsh-userauth-18.txt +++ /dev/null @@ -1,896 +0,0 @@ - - - -Network Working Group T. Ylonen -Internet-Draft SSH Communications Security Corp -Expires: March 2, 2003 D. Moffat, Ed. - Sun Microsystems, Inc - September 2002 - - - SSH Authentication Protocol - draft-ietf-secsh-userauth-18.txt - -Status of this Memo - - This document is an Internet-Draft and is in full conformance with - all provisions of Section 10 of RFC2026. - - Internet-Drafts are working documents of the Internet Engineering - Task Force (IETF), its areas, and its working groups. Note that other - groups may also distribute working documents as Internet-Drafts. - - Internet-Drafts are draft documents valid for a maximum of six months - and may be updated, replaced, or obsoleted by other documents at any - time. It is inappropriate to use Internet-Drafts as reference - material or to cite them other than as "work in progress." - - The list of current Internet-Drafts can be accessed at http:// - www.ietf.org/ietf/1id-abstracts.txt. - - The list of Internet-Draft Shadow Directories can be accessed at - http://www.ietf.org/shadow.html. - - This Internet-Draft will expire on March 2, 2003. - -Copyright Notice - - Copyright (C) The Internet Society (2002). All Rights Reserved. - -Abstract - - SSH is a protocol for secure remote login and other secure network - services over an insecure network. This document describes the SSH - authentication protocol framework and public key, password, and - host-based client authentication methods. Additional authentication - methods are described in separate documents. The SSH authentication - protocol runs on top of the SSH transport layer protocol and provides - a single authenticated tunnel for the SSH connection protocol. - - - - - - - -Ylonen & Moffat Expires March 2, 2003 [Page 1] - -Internet-Draft SSH Authentication Protocol September 2002 - - -Table of Contents - - 1. Contributors . . . . . . . . . . . . . . . . . . . . . . . . 3 - 2. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 - 3. Conventions Used in This Document . . . . . . . . . . . . . 3 - 3.1 The Authentication Protocol Framework . . . . . . . . . . . 3 - 3.1.1 Authentication Requests . . . . . . . . . . . . . . . . . . 4 - 3.1.2 Responses to Authentication Requests . . . . . . . . . . . . 5 - 3.1.3 The "none" Authentication Request . . . . . . . . . . . . . 6 - 3.1.4 Completion of User Authentication . . . . . . . . . . . . . 6 - 3.1.5 Banner Message . . . . . . . . . . . . . . . . . . . . . . . 7 - 3.2 Authentication Protocol Message Numbers . . . . . . . . . . 7 - 3.3 Public Key Authentication Method: publickey . . . . . . . . 8 - 3.4 Password Authentication Method: password . . . . . . . . . . 10 - 3.5 Host-Based Authentication: hostbased . . . . . . . . . . . . 11 - 4. Security Considerations . . . . . . . . . . . . . . . . . . 12 - Normative . . . . . . . . . . . . . . . . . . . . . . . . . 13 - Informative . . . . . . . . . . . . . . . . . . . . . . . . 13 - Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 14 - Intellectual Property and Copyright Statements . . . . . . . 15 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Ylonen & Moffat Expires March 2, 2003 [Page 2] - -Internet-Draft SSH Authentication Protocol September 2002 - - -1. Contributors - - The major original contributors of this document were: Tatu Ylonen, - Tero Kivinen, Timo J. Rinne, Sami Lehtinen (all of SSH Communications - Security Corp), and Markku-Juhani O. Saarinen (University of - Jyvaskyla) - - The document editor is: [email protected]. Comments on this - internet draft should be sent to the IETF SECSH working group, - details at: http://ietf.org/html.charters/secsh-charter.html - -2. Introduction - - The SSH authentication protocol is a general-purpose user - authentication protocol. It is intended to be run over the SSH - transport layer protocol [SSH-TRANS]. This protocol assumes that the - underlying protocols provide integrity and confidentiality - protection. - - This document should be read only after reading the SSH architecture - document [SSH-ARCH]. This document freely uses terminology and - notation from the architecture document without reference or further - explanation. - - The service name for this protocol is "ssh-userauth". - - When this protocol starts, it receives the session identifier from - the lower-level protocol (this is the exchange hash H from the first - key exchange). The session identifier uniquely identifies this - session and is suitable for signing in order to prove ownership of a - private key. This protocol also needs to know whether the lower-level - protocol provides confidentiality protection. - -3. Conventions Used in This Document - - The keywords "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT", - and "MAY" that appear in this document are to be interpreted as - described in [RFC2119] - - The used data types and terminology are specified in the architecture - document [SSH-ARCH] - - The architecture document also discusses the algorithm naming - conventions that MUST be used with the SSH protocols. - -3.1 The Authentication Protocol Framework - - The server drives the authentication by telling the client which - - - -Ylonen & Moffat Expires March 2, 2003 [Page 3] - -Internet-Draft SSH Authentication Protocol September 2002 - - - authentication methods can be used to continue the exchange at any - given time. The client has the freedom to try the methods listed by - the server in any order. This gives the server complete control over - the authentication process if desired, but also gives enough - flexibility for the client to use the methods it supports or that are - most convenient for the user, when multiple methods are offered by - the server. - - Authentication methods are identified by their name, as defined in - [SSH-ARCH]. The "none" method is reserved, and MUST NOT be listed as - supported. However, it MAY be sent by the client. The server MUST - always reject this request, unless the client is to be allowed in - without any authentication, in which case the server MUST accept this - request. The main purpose of sending this request is to get the list - of supported methods from the server. - - The server SHOULD have a timeout for authentication, and disconnect - if the authentication has not been accepted within the timeout - period. The RECOMMENDED timeout period is 10 minutes. Additionally, - the implementation SHOULD limit the number of failed authentication - attempts a client may perform in a single session (the RECOMMENDED - limit is 20 attempts). If the threshold is exceeded, the server - SHOULD disconnect. - -3.1.1 Authentication Requests - - All authentication requests MUST use the following message format. - Only the first few fields are defined; the remaining fields depend on - the authentication method. - - byte SSH_MSG_USERAUTH_REQUEST - string user name (in ISO-10646 UTF-8 encoding [RFC2279]) - string service name (in US-ASCII) - string method name (US-ASCII) - The rest of the packet is method-specific. - - The user name and service are repeated in every new authentication - attempt, and MAY change. The server implementation MUST carefully - check them in every message, and MUST flush any accumulated - authentication states if they change. If it is unable to flush some - authentication state, it MUST disconnect if the user or service name - changes. - - The service name specifies the service to start after authentication. - There may be several different authenticated services provided. If - the requested service is not available, the server MAY disconnect - immediately or at any later time. Sending a proper disconnect - message is RECOMMENDED. In any case, if the service does not exist, - - - -Ylonen & Moffat Expires March 2, 2003 [Page 4] - -Internet-Draft SSH Authentication Protocol September 2002 - - - authentication MUST NOT be accepted. - - If the requested user does not exist, the server MAY disconnect, or - MAY send a bogus list of acceptable authentication methods, but never - accept any. This makes it possible for the server to avoid - disclosing information on which accounts exist. In any case, if the - user does not exist, the authentication request MUST NOT be accepted. - - While there is usually little point for clients to send requests that - the server does not list as acceptable, sending such requests is not - an error, and the server SHOULD simply reject requests that it does - not recognize. - - An authentication request MAY result in a further exchange of - messages. All such messages depend on the authentication method - used, and the client MAY at any time continue with a new - SSH_MSG_USERAUTH_REQUEST message, in which case the server MUST - abandon the previous authentication attempt and continue with the new - one. - -3.1.2 Responses to Authentication Requests - - If the server rejects the authentication request, it MUST respond - with the following: - - byte SSH_MSG_USERAUTH_FAILURE - string authentications that can continue - boolean partial success - - "Authentications that can continue" is a comma-separated list of - authentication method names that may productively continue the - authentication dialog. - - It is RECOMMENDED that servers only include those methods in the list - that are actually useful. However, it is not illegal to include - methods that cannot be used to authenticate the user. - - Already successfully completed authentications SHOULD NOT be included - in the list, unless they really should be performed again for some - reason. - - "Partial success" MUST be TRUE if the authentication request to which - this is a response was successful. It MUST be FALSE if the request - was not successfully processed. - - When the server accepts authentication, it MUST respond with the - following: - - - - -Ylonen & Moffat Expires March 2, 2003 [Page 5] - -Internet-Draft SSH Authentication Protocol September 2002 - - - byte SSH_MSG_USERAUTH_SUCCESS - - Note that this is not sent after each step in a multi-method - authentication sequence, but only when the authentication is - complete. - - The client MAY send several authentication requests without waiting - for responses from previous requests. The server MUST process each - request completely and acknowledge any failed requests with a - SSH_MSG_USERAUTH_FAILURE message before processing the next request. - - A request that results in further exchange of messages will be - aborted by a second request. It is not possible to send a second - request without waiting for a response from the server, if the first - request will result in further exchange of messages. No - SSH_MSG_USERAUTH_FAILURE message will be sent for the aborted method. - - SSH_MSG_USERAUTH_SUCCESS MUST be sent only once. When - SSH_MSG_USERAUTH_SUCCESS has been sent, any further authentication - requests received after that SHOULD be silently ignored. - - Any non-authentication messages sent by the client after the request - that resulted in SSH_MSG_USERAUTH_SUCCESS being sent MUST be passed - to the service being run on top of this protocol. Such messages can - be identified by their message numbers (see Section Message Numbers - (Section 3.2)). - -3.1.3 The "none" Authentication Request - - A client may request a list of authentication methods that may - continue by using the "none" authentication method. - - If no authentication at all is needed for the user, the server MUST - return SSH_MSG_USERAUTH_SUCCESS. Otherwise, the server MUST return - SSH_MSG_USERAUTH_FAILURE and MAY return with it a list of - authentication methods that can continue. - - This method MUST NOT be listed as supported by the server. - -3.1.4 Completion of User Authentication - - Authentication is complete when the server has responded with - SSH_MSG_USERAUTH_SUCCESS; all authentication related messages - received after sending this message SHOULD be silently ignored. - - After sending SSH_MSG_USERAUTH_SUCCESS, the server starts the - requested service. - - - - -Ylonen & Moffat Expires March 2, 2003 [Page 6] - -Internet-Draft SSH Authentication Protocol September 2002 - - -3.1.5 Banner Message - - In some jurisdictions, sending a warning message before - authentication may be relevant for getting legal protection. Many - UNIX machines, for example, normally display text from `/etc/issue', - or use "tcp wrappers" or similar software to display a banner before - issuing a login prompt. - - The SSH server may send a SSH_MSG_USERAUTH_BANNER message at any time - before authentication is successful. This message contains text to - be displayed to the client user before authentication is attempted. - The format is as follows: - - byte SSH_MSG_USERAUTH_BANNER - string message (ISO-10646 UTF-8) - string language tag (as defined in [RFC3066]) - - The client SHOULD by default display the message on the screen. - However, since the message is likely to be sent for every login - attempt, and since some client software will need to open a separate - window for this warning, the client software may allow the user to - explicitly disable the display of banners from the server. The - message may consist of multiple lines. - - If the message string is displayed, control character filtering - discussed in [SSH-ARCH] SHOULD be used to avoid attacks by sending - terminal control characters. - -3.2 Authentication Protocol Message Numbers - - All message numbers used by this authentication protocol are in the - range from 50 to 79, which is part of the range reserved for - protocols running on top of the SSH transport layer protocol. - - Message numbers of 80 and higher are reserved for protocols running - after this authentication protocol, so receiving one of them before - authentication is complete is an error, to which the server MUST - respond by disconnecting (preferably with a proper disconnect message - sent first to ease troubleshooting). - - After successful authentication, such messages are passed to the - higher-level service. - - These are the general authentication message codes: - - #define SSH_MSG_USERAUTH_REQUEST 50 - #define SSH_MSG_USERAUTH_FAILURE 51 - #define SSH_MSG_USERAUTH_SUCCESS 52 - - - -Ylonen & Moffat Expires March 2, 2003 [Page 7] - -Internet-Draft SSH Authentication Protocol September 2002 - - - #define SSH_MSG_USERAUTH_BANNER 53 - - In addition to the above, there is a range of message numbers - (60..79) reserved for method-specific messages. These messages are - only sent by the server (client sends only SSH_MSG_USERAUTH_REQUEST - messages). Different authentication methods reuse the same message - numbers. - -3.3 Public Key Authentication Method: publickey - - The only REQUIRED authentication method is public key authentication. - All implementations MUST support this method; however, not all users - need to have public keys, and most local policies are not likely to - require public key authentication for all users in the near future. - - With this method, the possession of a private key serves as - authentication. This method works by sending a signature created - with a private key of the user. The server MUST check that the key - is a valid authenticator for the user, and MUST check that the - signature is valid. If both hold, the authentication request MUST be - accepted; otherwise it MUST be rejected. (Note that the server MAY - require additional authentications after successful authentication.) - - Private keys are often stored in an encrypted form at the client - host, and the user must supply a passphrase before the signature can - be generated. Even if they are not, the signing operation involves - some expensive computation. To avoid unnecessary processing and user - interaction, the following message is provided for querying whether - authentication using the key would be acceptable. - - byte SSH_MSG_USERAUTH_REQUEST - string user name - string service - string "publickey" - boolean FALSE - string public key algorithm name - string public key blob - - Public key algorithms are defined in the transport layer - specification [SSH-TRANS]. The public key blob may contain - certificates. - - Any public key algorithm may be offered for use in authentication. - In particular, the list is not constrained by what was negotiated - during key exchange. If the server does not support some algorithm, - it MUST simply reject the request. - - The server MUST respond to this message with either - - - -Ylonen & Moffat Expires March 2, 2003 [Page 8] - -Internet-Draft SSH Authentication Protocol September 2002 - - - SSH_MSG_USERAUTH_FAILURE or with the following: - - byte SSH_MSG_USERAUTH_PK_OK - string public key algorithm name from the request - string public key blob from the request - - To perform actual authentication, the client MAY then send a - signature generated using the private key. The client MAY send the - signature directly without first verifying whether the key is - acceptable. The signature is sent using the following packet: - - byte SSH_MSG_USERAUTH_REQUEST - string user name - string service - string "publickey" - boolean TRUE - string public key algorithm name - string public key to be used for authentication - string signature - - Signature is a signature by the corresponding private key over the - following data, in the following order: - - string session identifier - byte SSH_MSG_USERAUTH_REQUEST - string user name - string service - string "publickey" - boolean TRUE - string public key algorithm name - string public key to be used for authentication - - When the server receives this message, it MUST check whether the - supplied key is acceptable for authentication, and if so, it MUST - check whether the signature is correct. - - If both checks succeed, this method is successful. Note that the - server may require additional authentications. The server MUST - respond with SSH_MSG_USERAUTH_SUCCESS (if no more authentications are - needed), or SSH_MSG_USERAUTH_FAILURE (if the request failed, or more - authentications are needed). - - The following method-specific message numbers are used by the - publickey authentication method. - - /* Key-based */ - #define SSH_MSG_USERAUTH_PK_OK 60 - - - - -Ylonen & Moffat Expires March 2, 2003 [Page 9] - -Internet-Draft SSH Authentication Protocol September 2002 - - -3.4 Password Authentication Method: password - - Password authentication uses the following packets. Note that a - server MAY request the user to change the password. All - implementations SHOULD support password authentication. - - byte SSH_MSG_USERAUTH_REQUEST - string user name - string service - string "password" - boolean FALSE - string plaintext password (ISO-10646 UTF-8) - - Note that the password is encoded in ISO-10646 UTF-8. It is up to - the server how it interprets the password and validates it against - the password database. However, if the client reads the password in - some other encoding (e.g., ISO 8859-1 (ISO Latin1)), it MUST convert - the password to ISO-10646 UTF-8 before transmitting, and the server - MUST convert the password to the encoding used on that system for - passwords. - - Note that even though the cleartext password is transmitted in the - packet, the entire packet is encrypted by the transport layer. Both - the server and the client should check whether the underlying - transport layer provides confidentiality (i.e., if encryption is - being used). If no confidentiality is provided (none cipher), - password authentication SHOULD be disabled. If there is no - confidentiality or no MAC, password change SHOULD be disabled. - - Normally, the server responds to this message with success or - failure. However, if the password has expired the server SHOULD - indicate this by responding with SSH_MSG_USERAUTH_PASSWD_CHANGEREQ. - In anycase the server MUST NOT allow an expired password to be used - for authentication. - - byte SSH_MSG_USERAUTH_PASSWD_CHANGEREQ - string prompt (ISO-10646 UTF-8) - string language tag (as defined in [RFC3066]) - - In this case, the client MAY continue with a different authentication - method, or request a new password from the user and retry password - authentication using the following message. The client MAY also send - this message instead of the normal password authentication request - without the server asking for it. - - byte SSH_MSG_USERAUTH_REQUEST - string user name - string service - - - -Ylonen & Moffat Expires March 2, 2003 [Page 10] - -Internet-Draft SSH Authentication Protocol September 2002 - - - string "password" - boolean TRUE - string plaintext old password (ISO-10646 UTF-8) - string plaintext new password (ISO-10646 UTF-8) - - The server must reply to request message with - SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, or another - SSH_MSG_USERAUTH_PASSWD_CHANGEREQ. The meaning of these is as - follows: - - SSH_MSG_USERAUTH_SUCCESS The password has been changed, and - authentication has been successfully completed. - - SSH_MSG_USERAUTH_FAILURE with partial success The password has - been changed, but more authentications are needed. - - SSH_MSG_USERAUTH_FAILURE without partial success The password has - not been changed. Either password changing was not supported, or - the old password was bad. Note that if the server has already - sent SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, we know that it supports - changing the password. - - SSH_MSG_USERAUTH_CHANGEREQ The password was not changed because - the new password was not acceptable (e.g. too easy to guess). - - The following method-specific message numbers are used by the - password authentication method. - - #define SSH_MSG_USERAUTH_PASSWD_CHANGEREQ 60 - - -3.5 Host-Based Authentication: hostbased - - Some sites wish to allow authentication based on the host where the - user is coming from, and the user name on the remote host. While - this form of authentication is not suitable for high-security sites, - it can be very convenient in many environments. This form of - authentication is OPTIONAL. When used, special care SHOULD be taken - to prevent a regular user from obtaining the private host key. - - The client requests this form of authentication by sending the - following message. It is similar to the UNIX "rhosts" and - "hosts.equiv" styles of authentication, except that the identity of - the client host is checked more rigorously. - - This method works by having the client send a signature created with - the private key of the client host, which the server checks with that - host's public key. Once the client host's identity is established, - - - -Ylonen & Moffat Expires March 2, 2003 [Page 11] - -Internet-Draft SSH Authentication Protocol September 2002 - - - authorization (but no further authentication) is performed based on - the user names on the server and the client, and the client host - name. - - byte SSH_MSG_USERAUTH_REQUEST - string user name - string service - string "hostbased" - string public key algorithm for host key - string public host key and certificates for client host - string client host name (FQDN; US-ASCII) - string user name on the client host (ISO-10646 UTF-8) - string signature - - Public key algorithm names for use in "public key algorithm for host - key" are defined in the transport layer specification. The "public - host key for client host" may include certificates. - - Signature is a signature with the private host key of the following - data, in this order: - - string session identifier - byte SSH_MSG_USERAUTH_REQUEST - string user name - string service - string "hostbased" - string public key algorithm for host key - string public host key and certificates for client host - string client host name (FQDN; US-ASCII) - string user name on the client host(ISO-10646 UTF-8) - - The server MUST verify that the host key actually belongs to the - client host named in the message, that the given user on that host is - allowed to log in, and that the signature is a valid signature on the - appropriate value by the given host key. The server MAY ignore the - client user name, if it wants to authenticate only the client host. - - It is RECOMMENDED that whenever possible, the server perform - additional checks to verify that the network address obtained from - the (untrusted) network matches the given client host name. This - makes exploiting compromised host keys more difficult. Note that - this may require special handling for connections coming through a - firewall. - -4. Security Considerations - - The purpose of this protocol is to perform client user - authentication. It assumed that this runs over a secure transport - - - -Ylonen & Moffat Expires March 2, 2003 [Page 12] - -Internet-Draft SSH Authentication Protocol September 2002 - - - layer protocol, which has already authenticated the server machine, - established an encrypted communications channel, and computed a - unique session identifier for this session. The transport layer - provides forward secrecy for password authentication and other - methods that rely on secret data. - - Full security considerations for this protocol are provided in - Section 8 of [SSH-ARCH] - -Normative - - [SSH-ARCH] - Ylonen, T., "SSH Protocol Architecture", I-D - draft-ietf-architecture-15.txt, Oct 2003. - - [SSH-TRANS] - Ylonen, T., "SSH Transport Layer Protocol", I-D - draft-ietf-transport-17.txt, Oct 2003. - - [SSH-USERAUTH] - Ylonen, T., "SSH Authentication Protocol", I-D - draft-ietf-userauth-18.txt, Oct 2003. - - [SSH-CONNECT] - Ylonen, T., "SSH Connection Protocol", I-D - draft-ietf-connect-18.txt, Oct 2003. - - [SSH-NUMBERS] - Lehtinen, S. and D. Moffat, "SSH Protocol Assigned - Numbers", I-D draft-ietf-secsh-assignednumbers-05.txt, Oct - 2003. - - [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate - Requirement Levels", BCP 14, RFC 2119, March 1997. - -Informative - - [RFC3066] Alvestrand, H., "Tags for the Identification of - Languages", BCP 47, RFC 3066, January 2001. - - [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO - 10646", RFC 2279, January 1998. - - - - - - - - - -Ylonen & Moffat Expires March 2, 2003 [Page 13] - -Internet-Draft SSH Authentication Protocol September 2002 - - -Authors' Addresses - - Tatu Ylonen - SSH Communications Security Corp - Fredrikinkatu 42 - HELSINKI FIN-00100 - Finland - - EMail: [email protected] - - - Darren J. Moffat (editor) - Sun Microsystems, Inc - 17 Network Circle - Menlo Park 95025 - USA - - EMail: [email protected] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Ylonen & Moffat Expires March 2, 2003 [Page 14] - -Internet-Draft SSH Authentication Protocol September 2002 - - -Intellectual Property Statement - - The IETF takes no position regarding the validity or scope of any - intellectual property or other rights that might be claimed to - pertain to the implementation or use of the technology described in - this document or the extent to which any license under such rights - might or might not be available; neither does it represent that it - has made any effort to identify any such rights. Information on the - IETF's procedures with respect to rights in standards-track and - standards-related documentation can be found in BCP-11. Copies of - claims of rights made available for publication and any assurances of - licenses to be made available, or the result of an attempt made to - obtain a general license or permission for the use of such - proprietary rights by implementors or users of this specification can - be obtained from the IETF Secretariat. - - The IETF invites any interested party to bring to its attention any - copyrights, patents or patent applications, or other proprietary - rights which may cover technology that may be required to practice - this standard. Please address the information to the IETF Executive - Director. - - The IETF has been notified of intellectual property rights claimed in - regard to some or all of the specification contained in this - document. For more information consult the online list of claimed - rights. - - -Full Copyright Statement - - Copyright (C) The Internet Society (2002). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assignees. - - - -Ylonen & Moffat Expires March 2, 2003 [Page 15] - -Internet-Draft SSH Authentication Protocol September 2002 - - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - - -Acknowledgment - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Ylonen & Moffat Expires March 2, 2003 [Page 16]
\ No newline at end of file diff --git a/lib/ssh/src/Makefile b/lib/ssh/src/Makefile index 61d71d2cf7..b44c8eef35 100644 --- a/lib/ssh/src/Makefile +++ b/lib/ssh/src/Makefile @@ -67,7 +67,6 @@ MODULES= \ ssh_file \ ssh_io \ ssh_info \ - ssh_math \ ssh_message \ ssh_no_io \ ssh_sftp \ @@ -145,3 +144,78 @@ release_spec: opt release_docs_spec: + +deps: + erlc -M $(ERL_FILES) \ + | sed 's@$(ERL_TOP)/lib@../..@g' \ + | sed 's/\.$(EMULATOR)/\.$$\(EMULATOR\)/' \ + | sed 's@^ssh_@$$(EBIN)/ssh_@' + +ssh.$(EMULATOR): ssh.erl ssh.hrl ssh_connect.hrl \ + ../../public_key/include/public_key.hrl \ + ../../public_key/include/OTP-PUB-KEY.hrl \ + ../../public_key/include/PKCS-FRAME.hrl \ + ../../kernel/include/file.hrl +$(EBIN)/ssh_sup.$(EMULATOR): ssh_sup.erl +sshc_sup.$(EMULATOR): sshc_sup.erl +sshd_sup.$(EMULATOR): sshd_sup.erl ssh.hrl +$(EBIN)/ssh_connection_sup.$(EMULATOR): ssh_connection_sup.erl +$(EBIN)/ssh_connection.$(EMULATOR): ssh_connection.erl ssh.hrl ssh_connect.hrl \ + ssh_transport.hrl +$(EBIN)/ssh_connection_handler.$(EMULATOR): ssh_connection_handler.erl ssh.hrl \ + ssh_transport.hrl ssh_auth.hrl ssh_connect.hrl +$(EBIN)/ssh_shell.$(EMULATOR): ssh_shell.erl ssh_connect.hrl +$(EBIN)/ssh_system_sup.$(EMULATOR): ssh_system_sup.erl ssh.hrl +$(EBIN)/ssh_subsystem_sup.$(EMULATOR): ssh_subsystem_sup.erl +$(EBIN)/ssh_channel_sup.$(EMULATOR): ssh_channel_sup.erl +$(EBIN)/ssh_acceptor_sup.$(EMULATOR): ssh_acceptor_sup.erl ssh.hrl +$(EBIN)/ssh_acceptor.$(EMULATOR): ssh_acceptor.erl ssh.hrl +$(EBIN)/ssh_app.$(EMULATOR): ssh_app.erl +$(EBIN)/ssh_auth.$(EMULATOR): ssh_auth.erl \ + ../../public_key/include/public_key.hrl \ + ../../public_key/include/OTP-PUB-KEY.hrl \ + ../../public_key/include/PKCS-FRAME.hrl \ + ssh.hrl ssh_auth.hrl ssh_transport.hrl +$(EBIN)/ssh_bits.$(EMULATOR): ssh_bits.erl ssh.hrl +$(EBIN)/ssh_cli.$(EMULATOR): ssh_cli.erl ssh.hrl ssh_connect.hrl +$(EBIN)/ssh_file.$(EMULATOR): ssh_file.erl \ + ../../public_key/include/public_key.hrl \ + ../../public_key/include/OTP-PUB-KEY.hrl \ + ../../public_key/include/PKCS-FRAME.hrl \ + ../../kernel/include/file.hrl ssh.hrl +$(EBIN)/ssh_io.$(EMULATOR): ssh_io.erl ssh.hrl +$(EBIN)/ssh_info.$(EMULATOR): ssh_info.erl +$(EBIN)/ssh_message.$(EMULATOR): ssh_message.erl \ + ../../public_key/include/public_key.hrl \ + ../../public_key/include/OTP-PUB-KEY.hrl \ + ../../public_key/include/PKCS-FRAME.hrl \ + ssh.hrl ssh_connect.hrl ssh_auth.hrl ssh_transport.hrl +$(EBIN)/ssh_no_io.$(EMULATOR): ssh_no_io.erl ssh_transport.hrl +$(EBIN)/ssh_sftp.$(EMULATOR): ssh_sftp.erl \ + ../../kernel/include/file.hrl ssh.hrl \ + ssh_xfer.hrl +$(EBIN)/ssh_sftpd.$(EMULATOR): ssh_sftpd.erl \ + ../../kernel/include/file.hrl ssh.hrl \ + ssh_xfer.hrl +$(EBIN)/ssh_sftpd_file.$(EMULATOR): ssh_sftpd_file.erl +$(EBIN)/ssh_transport.$(EMULATOR): ssh_transport.erl \ + ../../public_key/include/public_key.hrl \ + ../../public_key/include/OTP-PUB-KEY.hrl \ + ../../public_key/include/PKCS-FRAME.hrl \ + ../../kernel/include/inet.hrl \ + ssh_transport.hrl ssh.hrl +$(EBIN)/ssh_xfer.$(EMULATOR): ssh_xfer.erl ssh.hrl ssh_xfer.hrl +$(EBIN)/ssh_sftpd_file_api.$(EMULATOR): ssh_sftpd_file_api.erl +$(EBIN)/ssh_channel.$(EMULATOR): ssh_channel.erl ssh_connect.hrl +$(EBIN)/ssh_daemon_channel.$(EMULATOR): ssh_daemon_channel.erl +$(EBIN)/ssh_client_key_api.$(EMULATOR): ssh_client_key_api.erl \ + ../../public_key/include/public_key.hrl \ + ../../public_key/include/OTP-PUB-KEY.hrl \ + ../../public_key/include/PKCS-FRAME.hrl \ + ssh.hrl +$(EBIN)/ssh_server_key_api.$(EMULATOR): ssh_server_key_api.erl \ + ../../public_key/include/public_key.hrl \ + ../../public_key/include/OTP-PUB-KEY.hrl \ + ../../public_key/include/PKCS-FRAME.hrl \ + ssh.hrl + diff --git a/lib/ssh/src/ssh.app.src b/lib/ssh/src/ssh.app.src index bc01c539e0..4a76fd9cd3 100644 --- a/lib/ssh/src/ssh.app.src +++ b/lib/ssh/src/ssh.app.src @@ -24,7 +24,6 @@ ssh_file, ssh_io, ssh_info, - ssh_math, ssh_no_io, ssh_server_key_api, ssh_sftp, diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl index 370f086600..54f94acbdc 100644 --- a/lib/ssh/src/ssh.erl +++ b/lib/ssh/src/ssh.erl @@ -33,7 +33,8 @@ default_algorithms/0, stop_listener/1, stop_listener/2, stop_listener/3, stop_daemon/1, stop_daemon/2, stop_daemon/3, - shell/1, shell/2, shell/3]). + shell/1, shell/2, shell/3 + ]). %%-------------------------------------------------------------------- -spec start() -> ok | {error, term()}. @@ -117,9 +118,9 @@ channel_info(ConnectionRef, ChannelId, Options) -> ssh_connection_handler:channel_info(ConnectionRef, ChannelId, Options). %%-------------------------------------------------------------------- --spec daemon(integer()) -> {ok, pid()}. --spec daemon(integer(), proplists:proplist()) -> {ok, pid()}. --spec daemon(any | inet:ip_address(), integer(), proplists:proplist()) -> {ok, pid()}. +-spec daemon(integer()) -> {ok, pid()} | {error, term()}. +-spec daemon(integer(), proplists:proplist()) -> {ok, pid()} | {error, term()}. +-spec daemon(any | inet:ip_address(), integer(), proplists:proplist()) -> {ok, pid()} | {error, term()}. %% Description: Starts a server listening for SSH connections %% on the given port. @@ -234,10 +235,27 @@ start_daemon(Host, Port, Options, Inet) -> {error, _Reason} = Error -> Error; {SocketOptions, SshOptions}-> - do_start_daemon(Host, Port,[{role, server} |SshOptions] , [Inet | SocketOptions]) + try + do_start_daemon(Host, Port,[{role, server} |SshOptions] , [Inet | SocketOptions]) + catch + throw:bad_fd -> {error,bad_fd}; + _C:_E -> {error,{cannot_start_daemon,_C,_E}} + end end. -do_start_daemon(Host, Port, Options, SocketOptions) -> +do_start_daemon(Host0, Port0, Options, SocketOptions) -> + {Host,Port} = try + case proplists:get_value(fd, SocketOptions) of + undefined -> + {Host0,Port0}; + Fd when Port0==0 -> + find_hostport(Fd); + _ -> + {Host0,Port0} + end + catch + _:_ -> throw(bad_fd) + end, Profile = proplists:get_value(profile, Options, ?DEFAULT_PROFILE), case ssh_system_sup:system_supervisor(Host, Port, Profile) of undefined -> @@ -271,6 +289,15 @@ do_start_daemon(Host, Port, Options, SocketOptions) -> end end. +find_hostport(Fd) -> + %% Using internal functions inet:open/8 and inet:close/0. + %% Don't try this at home unless you know what you are doing! + {ok,S} = inet:open(Fd, {0,0,0,0}, 0, [], tcp, inet, stream, inet_tcp), + {ok, HostPort} = inet:sockname(S), + ok = inet:close(S), + HostPort. + + handle_options(Opts) -> try handle_option(algs_compatibility(proplists:unfold(Opts)), [], []) of {Inet, Ssh} -> @@ -281,32 +308,27 @@ handle_options(Opts) -> end. -algs_compatibility(Os) -> +algs_compatibility(Os0) -> %% Take care of old options 'public_key_alg' and 'pref_public_key_algs' - comp_pk(proplists:get_value(preferred_algorithms,Os), - proplists:get_value(pref_public_key_algs,Os), - proplists:get_value(public_key_alg, Os), - [{K,V} || {K,V} <- Os, - K =/= public_key_alg, - K =/= pref_public_key_algs] - ). - -comp_pk(undefined, undefined, undefined, Os) -> Os; -comp_pk( PrefAlgs, _, _, Os) when PrefAlgs =/= undefined -> Os; - -comp_pk(undefined, undefined, ssh_dsa, Os) -> comp_pk(undefined, undefined, 'ssh-dss', Os); -comp_pk(undefined, undefined, ssh_rsa, Os) -> comp_pk(undefined, undefined, 'ssh-rsa', Os); -comp_pk(undefined, undefined, PK, Os) -> - PKs = [PK | ssh_transport:supported_algorithms(public_key)--[PK]], - [{preferred_algorithms, [{public_key,PKs}] } | Os]; - -comp_pk(undefined, PrefPKs, _, Os) when PrefPKs =/= undefined -> - PKs = [case PK of - ssh_dsa -> 'ssh-dss'; - ssh_rsa -> 'ssh-rsa'; - _ -> PK - end || PK <- PrefPKs], - [{preferred_algorithms, [{public_key,PKs}]} | Os]. + case proplists:get_value(public_key_alg, Os0) of + undefined -> + Os0; + A when is_atom(A) -> + %% Skip public_key_alg if pref_public_key_algs is defined: + Os = lists:keydelete(public_key_alg, 1, Os0), + case proplists:get_value(pref_public_key_algs,Os) of + undefined when A == 'ssh-rsa' ; A==ssh_rsa -> + [{pref_public_key_algs,['ssh-rsa','ssh-dss']} | Os]; + undefined when A == 'ssh-dss' ; A==ssh_dsa -> + [{pref_public_key_algs,['ssh-dss','ssh-rsa']} | Os]; + undefined -> + throw({error, {eoptions, {public_key_alg,A} }}); + _ -> + Os + end; + V -> + throw({error, {eoptions, {public_key_alg,V} }}) + end. handle_option([], SocketOptions, SshOptions) -> @@ -335,7 +357,13 @@ handle_option([{user_passwords, _} = Opt | Rest], SocketOptions, SshOptions) -> handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); handle_option([{pwdfun, _} = Opt | Rest], SocketOptions, SshOptions) -> handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); -handle_option([{key_cb, _} = Opt | Rest], SocketOptions, SshOptions) -> +handle_option([{key_cb, {Module, Options}} | Rest], SocketOptions, SshOptions) -> + handle_option(Rest, SocketOptions, [handle_ssh_option({key_cb, Module}), + handle_ssh_priv_option({key_cb_private, Options}) | + SshOptions]); +handle_option([{key_cb, Module} | Rest], SocketOptions, SshOptions) -> + handle_option([{key_cb, {Module, []}} | Rest], SocketOptions, SshOptions); +handle_option([{keyboard_interact_fun, _} = Opt | Rest], SocketOptions, SshOptions) -> handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); %%Backwards compatibility handle_option([{allow_user_interaction, Value} | Rest], SocketOptions, SshOptions) -> @@ -371,8 +399,14 @@ handle_option([{auth_methods, _} = Opt | Rest], SocketOptions, SshOptions) -> handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); handle_option([{auth_method_kb_interactive_data, _} = Opt | Rest], SocketOptions, SshOptions) -> handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); +handle_option([{pref_public_key_algs, _} = Opt | Rest], SocketOptions, SshOptions) -> + handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); handle_option([{preferred_algorithms,_} = Opt | Rest], SocketOptions, SshOptions) -> handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); +handle_option([{dh_gex_groups,_} = Opt | Rest], SocketOptions, SshOptions) -> + handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); +handle_option([{dh_gex_limits,_} = Opt | Rest], SocketOptions, SshOptions) -> + handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); handle_option([{quiet_mode, _} = Opt|Rest], SocketOptions, SshOptions) -> handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); handle_option([{idle_time, _} = Opt | Rest], SocketOptions, SshOptions) -> @@ -381,18 +415,23 @@ handle_option([{rekey_limit, _} = Opt|Rest], SocketOptions, SshOptions) -> handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); handle_option([{max_sessions, _} = Opt|Rest], SocketOptions, SshOptions) -> handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); +handle_option([{max_channels, _} = Opt|Rest], SocketOptions, SshOptions) -> + handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); handle_option([{negotiation_timeout, _} = Opt|Rest], SocketOptions, SshOptions) -> handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); handle_option([{parallel_login, _} = Opt|Rest], SocketOptions, SshOptions) -> handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); -handle_option([parallel_login|Rest], SocketOptions, SshOptions) -> - handle_option(Rest, SocketOptions, [handle_ssh_option({parallel_login,true}) | SshOptions]); +%% (Is handled by proplists:unfold above:) +%% handle_option([parallel_login|Rest], SocketOptions, SshOptions) -> +%% handle_option(Rest, SocketOptions, [handle_ssh_option({parallel_login,true}) | SshOptions]); handle_option([{minimal_remote_max_packet_size, _} = Opt|Rest], SocketOptions, SshOptions) -> handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); handle_option([{id_string, _ID} = Opt|Rest], SocketOptions, SshOptions) -> handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); handle_option([{profile, _ID} = Opt|Rest], SocketOptions, SshOptions) -> handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); +handle_option([{max_random_length_padding, _Bool} = Opt|Rest], SocketOptions, SshOptions) -> + handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); handle_option([Opt | Rest], SocketOptions, SshOptions) -> handle_option(Rest, [handle_inet_option(Opt) | SocketOptions], SshOptions). @@ -411,10 +450,81 @@ handle_ssh_option({user_interaction, Value} = Opt) when is_boolean(Value) -> Opt; handle_ssh_option({preferred_algorithms,[_|_]} = Opt) -> handle_pref_algs(Opt); + +handle_ssh_option({dh_gex_groups,L0}) when is_list(L0) -> + {dh_gex_groups, + collect_per_size( + lists:foldl( + fun({N,G,P}, Acc) when is_integer(N),N>0, + is_integer(G),G>0, + is_integer(P),P>0 -> + [{N,{G,P}} | Acc]; + ({N,{G,P}}, Acc) when is_integer(N),N>0, + is_integer(G),G>0, + is_integer(P),P>0 -> + [{N,{G,P}} | Acc]; + ({N,GPs}, Acc) when is_list(GPs) -> + lists:foldr(fun({Gi,Pi}, Acci) when is_integer(Gi),Gi>0, + is_integer(Pi),Pi>0 -> + [{N,{Gi,Pi}} | Acci] + end, Acc, GPs) + end, [], L0))}; + +handle_ssh_option({dh_gex_groups,{Tag,File=[C|_]}}=Opt) when is_integer(C), C>0, + Tag == file ; + Tag == ssh_moduli_file -> + {ok,GroupDefs} = + case Tag of + file -> + file:consult(File); + ssh_moduli_file -> + case file:open(File,[read]) of + {ok,D} -> + try + {ok,Moduli} = read_moduli_file(D, 1, []), + file:close(D), + {ok, Moduli} + catch + _:_ -> + throw({error, {{eoptions, Opt}, "Bad format in file "++File}}) + end; + {error,enoent} -> + throw({error, {{eoptions, Opt}, "File not found:"++File}}); + {error,Error} -> + throw({error, {{eoptions, Opt}, io_lib:format("Error reading file ~s: ~p",[File,Error])}}) + end + end, + + try + handle_ssh_option({dh_gex_groups,GroupDefs}) + catch + _:_ -> + throw({error, {{eoptions, Opt}, "Bad format in file: "++File}}) + end; + + +handle_ssh_option({dh_gex_limits,{Min,Max}} = Opt) when is_integer(Min), Min>0, + is_integer(Max), Max>=Min -> + %% Server + Opt; +handle_ssh_option({dh_gex_limits,{Min,I,Max}} = Opt) when is_integer(Min), Min>0, + is_integer(I), I>=Min, + is_integer(Max), Max>=I -> + %% Client + Opt; +handle_ssh_option({pref_public_key_algs, Value} = Opt) when is_list(Value), length(Value) >= 1 -> + case handle_user_pref_pubkey_algs(Value, []) of + {true, NewOpts} -> + {pref_public_key_algs, NewOpts}; + _ -> + throw({error, {eoptions, Opt}}) + end; handle_ssh_option({connect_timeout, Value} = Opt) when is_integer(Value); Value == infinity -> Opt; handle_ssh_option({max_sessions, Value} = Opt) when is_integer(Value), Value>0 -> Opt; +handle_ssh_option({max_channels, Value} = Opt) when is_integer(Value), Value>0 -> + Opt; handle_ssh_option({negotiation_timeout, Value} = Opt) when is_integer(Value); Value == infinity -> Opt; handle_ssh_option({parallel_login, Value} = Opt) when Value==true ; Value==false -> @@ -429,10 +539,17 @@ handle_ssh_option({password, Value} = Opt) when is_list(Value) -> Opt; handle_ssh_option({user_passwords, Value} = Opt) when is_list(Value)-> Opt; -handle_ssh_option({pwdfun, Value} = Opt) when is_function(Value) -> +handle_ssh_option({pwdfun, Value} = Opt) when is_function(Value,2) -> + Opt; +handle_ssh_option({pwdfun, Value} = Opt) when is_function(Value,4) -> Opt; handle_ssh_option({key_cb, Value} = Opt) when is_atom(Value) -> Opt; +handle_ssh_option({key_cb, {CallbackMod, CallbackOptions}} = Opt) when is_atom(CallbackMod), + is_list(CallbackOptions) -> + Opt; +handle_ssh_option({keyboard_interact_fun, Value} = Opt) when is_function(Value,3) -> + Opt; handle_ssh_option({compression, Value} = Opt) when is_atom(Value) -> Opt; handle_ssh_option({exec, {Module, Function, _}} = Opt) when is_atom(Module), @@ -489,11 +606,17 @@ handle_ssh_option({id_string, random}) -> {id_string, {random,2,5}}; %% 2 - 5 random characters handle_ssh_option({id_string, ID} = Opt) when is_list(ID) -> Opt; +handle_ssh_option({max_random_length_padding, Value} = Opt) when is_integer(Value), + Value =< 255 -> + Opt; handle_ssh_option({profile, Value} = Opt) when is_atom(Value) -> Opt; handle_ssh_option(Opt) -> throw({error, {eoptions, Opt}}). +handle_ssh_priv_option({key_cb_private, Value} = Opt) when is_list(Value) -> + Opt. + handle_inet_option({active, _} = Opt) -> throw({error, {{eoptions, Opt}, "SSH has built in flow control, " "and active is handled internally, user is not allowed" @@ -624,3 +747,46 @@ directory_exist_readable(Dir) -> +collect_per_size(L) -> + lists:foldr( + fun({Sz,GP}, [{Sz,GPs}|Acc]) -> [{Sz,[GP|GPs]}|Acc]; + ({Sz,GP}, Acc) -> [{Sz,[GP]}|Acc] + end, [], lists:sort(L)). + +read_moduli_file(D, I, Acc) -> + case io:get_line(D,"") of + {error,Error} -> + {error,Error}; + eof -> + {ok, Acc}; + "#" ++ _ -> read_moduli_file(D, I+1, Acc); + <<"#",_/binary>> -> read_moduli_file(D, I+1, Acc); + Data -> + Line = if is_binary(Data) -> binary_to_list(Data); + is_list(Data) -> Data + end, + try + [_Time,_Type,_Tests,_Tries,Size,G,P] = string:tokens(Line," \r\n"), + M = {list_to_integer(Size), + {list_to_integer(G), list_to_integer(P,16)} + }, + read_moduli_file(D, I+1, [M|Acc]) + catch + _:_ -> + read_moduli_file(D, I+1, Acc) + end + end. + +handle_user_pref_pubkey_algs([], Acc) -> + {true, lists:reverse(Acc)}; +handle_user_pref_pubkey_algs([H|T], Acc) -> + case lists:member(H, ?SUPPORTED_USER_KEYS) of + true -> + handle_user_pref_pubkey_algs(T, [H| Acc]); + + false when H==ssh_dsa -> handle_user_pref_pubkey_algs(T, ['ssh-dss'| Acc]); + false when H==ssh_rsa -> handle_user_pref_pubkey_algs(T, ['ssh-rsa'| Acc]); + + false -> + false + end. diff --git a/lib/ssh/src/ssh.hrl b/lib/ssh/src/ssh.hrl index 8df5ee820c..f88098819d 100644 --- a/lib/ssh/src/ssh.hrl +++ b/lib/ssh/src/ssh.hrl @@ -29,21 +29,26 @@ -define(SSH_DEFAULT_PORT, 22). -define(SSH_MAX_PACKET_SIZE, (256*1024)). --define(SSH_LENGHT_INDICATOR_SIZE, 4). -define(REKEY_TIMOUT, 3600000). -define(REKEY_DATA_TIMOUT, 60000). -define(DEFAULT_PROFILE, default). +-define(SUPPORTED_AUTH_METHODS, "publickey,keyboard-interactive,password"). +-define(SUPPORTED_USER_KEYS, ['ssh-rsa','ssh-dss','ecdsa-sha2-nistp256','ecdsa-sha2-nistp384','ecdsa-sha2-nistp521']). + -define(FALSE, 0). -define(TRUE, 1). %% basic binary constructors --define(BOOLEAN(X), X:8/unsigned-big-integer). --define(BYTE(X), X:8/unsigned-big-integer). --define(UINT16(X), X:16/unsigned-big-integer). --define(UINT32(X), X:32/unsigned-big-integer). --define(UINT64(X), X:64/unsigned-big-integer). +-define(BOOLEAN(X), (X):8/unsigned-big-integer). +-define(BYTE(X), (X):8/unsigned-big-integer). +-define(UINT16(X), (X):16/unsigned-big-integer). +-define(UINT32(X), (X):32/unsigned-big-integer). +-define(UINT64(X), (X):64/unsigned-big-integer). -define(STRING(X), ?UINT32((size(X))), (X)/binary). +-define(DEC_BIN(X,Len), ?UINT32(Len), X:Len/binary ). +-define(DEC_MPINT(I,Len), ?UINT32(Len), I:Len/big-signed-integer-unit:8 ). + %% building macros -define(boolean(X), case X of @@ -124,6 +129,7 @@ recv_sequence = 0, keyex_key, keyex_info, + random_length_padding = 255, % From RFC 4253 section 6. %% User auth user, @@ -132,9 +138,9 @@ userauth_supported_methods, % string() eg "keyboard-interactive,password" userauth_methods, % list( string() ) eg ["keyboard-interactive", "password"] kb_tries_left = 0, % integer(), num tries left for "keyboard-interactive" - kb_data, userauth_preference, available_host_keys, + pwdfun_user_state, authenticated = false }). diff --git a/lib/ssh/src/ssh_acceptor.erl b/lib/ssh/src/ssh_acceptor.erl index c5ad1d7b6c..d94dedf1bf 100644 --- a/lib/ssh/src/ssh_acceptor.erl +++ b/lib/ssh/src/ssh_acceptor.erl @@ -56,7 +56,12 @@ acceptor_init(Parent, Port, Address, SockOpts, Opts, AcceptTimeout) -> error end. -do_socket_listen(Callback, Port, Opts) -> +do_socket_listen(Callback, Port0, Opts) -> + Port = + case proplists:get_value(fd, Opts) of + undefined -> Port0; + _ -> 0 + end, case Callback:listen(Port, Opts) of {error, nxdomain} -> Callback:listen(Port, lists:delete(inet6, Opts)); diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl index a91b8c200e..0c378d084b 100644 --- a/lib/ssh/src/ssh_auth.erl +++ b/lib/ssh/src/ssh_auth.erl @@ -31,53 +31,83 @@ -export([publickey_msg/1, password_msg/1, keyboard_interactive_msg/1, service_request_msg/1, init_userauth_request_msg/1, userauth_request_msg/1, handle_userauth_request/3, - handle_userauth_info_request/3, handle_userauth_info_response/2, - default_public_key_algorithms/0 + handle_userauth_info_request/2, handle_userauth_info_response/2 ]). %%-------------------------------------------------------------------- %%% Internal application API %%-------------------------------------------------------------------- -publickey_msg([Alg, #ssh{user = User, - session_id = SessionId, - service = Service, - opts = Opts} = Ssh]) -> +%%%---------------------------------------------------------------- +userauth_request_msg(#ssh{userauth_methods = ServerMethods, + userauth_supported_methods = UserPrefMethods, % Note: this is not documented as supported for clients + userauth_preference = ClientMethods0 + } = Ssh0) -> + case sort_select_mthds(ClientMethods0, UserPrefMethods, ServerMethods) of + [] -> + Msg = #ssh_msg_disconnect{code = ?SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE, + description = "Unable to connect using the available authentication methods", + language = "en"}, + {disconnect, Msg, ssh_transport:ssh_packet(Msg, Ssh0)}; + + [{Pref,Module,Function,Args} | Prefs] -> + Ssh = case Pref of + "keyboard-interactive" -> Ssh0; + _ -> Ssh0#ssh{userauth_preference = Prefs} + end, + case Module:Function(Args ++ [Ssh]) of + {not_ok, Ssh1} -> + userauth_request_msg(Ssh1#ssh{userauth_preference = Prefs}); + Result -> + {Pref,Result} + end + end. - Hash = sha, %% Maybe option?! - KeyCb = proplists:get_value(key_cb, Opts, ssh_file), - case KeyCb:user_key(Alg, Opts) of - {ok, Key} -> - StrAlgo = algorithm_string(Alg), - PubKeyBlob = encode_public_key(Key), - SigData = build_sig_data(SessionId, - User, Service, PubKeyBlob, StrAlgo), - Sig = ssh_transport:sign(SigData, Hash, Key), - SigBlob = list_to_binary([?string(StrAlgo), ?binary(Sig)]), - ssh_transport:ssh_packet( - #ssh_msg_userauth_request{user = User, - service = Service, - method = "publickey", - data = [?TRUE, - ?string(StrAlgo), - ?binary(PubKeyBlob), - ?binary(SigBlob)]}, - Ssh); - _Error -> - not_ok - end. +sort_select_mthds(Clients, undefined, Servers) -> + %% User has not expressed an opinion via option "auth_methods", use the server's prefs + sort_select_mthds1(Clients, Servers, string:tokens(?SUPPORTED_AUTH_METHODS,",")); + +sort_select_mthds(Clients, Users0, Servers0) -> + %% The User has an opinion, use the intersection of that and the Servers whishes but + %% in the Users order + sort_select_mthds1(Clients, string:tokens(Users0,","), Servers0). + + +sort_select_mthds1(Clients, Users0, Servers0) -> + Servers = unique(Servers0), + Users = unique(Users0), + [C || Key <- Users, + lists:member(Key, Servers), + C <- Clients, + element(1,C) == Key]. + +unique(L) -> + lists:reverse( + lists:foldl(fun(E,Acc) -> + case lists:member(E,Acc) of + true -> Acc; + false -> [E|Acc] + end + end, [], L)). + + +%%%---- userauth_request_msg "callbacks" password_msg([#ssh{opts = Opts, io_cb = IoCb, - user = User, service = Service} = Ssh]) -> - Password = case proplists:get_value(password, Opts) of - undefined -> - user_interaction(IoCb, Ssh); - PW -> - PW - end, + user = User, service = Service} = Ssh0]) -> + {Password,Ssh} = + case proplists:get_value(password, Opts) of + undefined when IoCb == ssh_no_io -> + {not_ok, Ssh0}; + undefined -> + {IoCb:read_password("ssh password: ",Ssh0), Ssh0}; + PW -> + %% If "password" option is given it should not be tried again + {PW, Ssh0#ssh{opts = lists:keyreplace(password,1,Opts,{password,not_ok})}} + end, case Password of not_ok -> - not_ok; + {not_ok, Ssh}; _ -> ssh_transport:ssh_packet( #ssh_msg_userauth_request{user = User, @@ -89,27 +119,60 @@ password_msg([#ssh{opts = Opts, io_cb = IoCb, Ssh) end. -user_interaction(ssh_no_io, _) -> - not_ok; -user_interaction(IoCb, Ssh) -> - IoCb:read_password("ssh password: ", Ssh). - - %% See RFC 4256 for info on keyboard-interactive keyboard_interactive_msg([#ssh{user = User, + opts = Opts, service = Service} = Ssh]) -> - ssh_transport:ssh_packet( - #ssh_msg_userauth_request{user = User, - service = Service, - method = "keyboard-interactive", - data = << ?STRING(<<"">>), - ?STRING(<<>>) >> }, - Ssh). + case proplists:get_value(password, Opts) of + not_ok -> + {not_ok,Ssh}; % No need to use a failed pwd once more + _ -> + ssh_transport:ssh_packet( + #ssh_msg_userauth_request{user = User, + service = Service, + method = "keyboard-interactive", + data = << ?STRING(<<"">>), + ?STRING(<<>>) >> }, + Ssh) + end. + +publickey_msg([Alg, #ssh{user = User, + session_id = SessionId, + service = Service, + opts = Opts} = Ssh]) -> + Hash = sha, %% Maybe option?! + KeyCb = proplists:get_value(key_cb, Opts, ssh_file), + case KeyCb:user_key(Alg, Opts) of + {ok, PrivKey} -> + StrAlgo = atom_to_list(Alg), + case encode_public_key(StrAlgo, ssh_transport:extract_public_key(PrivKey)) of + not_ok -> + {not_ok, Ssh}; + PubKeyBlob -> + SigData = build_sig_data(SessionId, + User, Service, PubKeyBlob, StrAlgo), + Sig = ssh_transport:sign(SigData, Hash, PrivKey), + SigBlob = list_to_binary([?string(StrAlgo), ?binary(Sig)]), + ssh_transport:ssh_packet( + #ssh_msg_userauth_request{user = User, + service = Service, + method = "publickey", + data = [?TRUE, + ?string(StrAlgo), + ?binary(PubKeyBlob), + ?binary(SigBlob)]}, + Ssh) + end; + _Error -> + {not_ok, Ssh} + end. +%%%---------------------------------------------------------------- service_request_msg(Ssh) -> ssh_transport:ssh_packet(#ssh_msg_service_request{name = "ssh-userauth"}, Ssh#ssh{service = "ssh-userauth"}). +%%%---------------------------------------------------------------- init_userauth_request_msg(#ssh{opts = Opts} = Ssh) -> case user_name(Opts) of {ok, User} -> @@ -117,11 +180,16 @@ init_userauth_request_msg(#ssh{opts = Opts} = Ssh) -> service = "ssh-connection", method = "none", data = <<>>}, + Algs0 = proplists:get_value(pref_public_key_algs, Opts, ?SUPPORTED_USER_KEYS), + %% The following line is not strictly correct. The call returns the + %% supported HOST key types while we are interested in USER keys. However, + %% they "happens" to be the same (for now). This could change.... + %% There is no danger as long as the set of user keys is a subset of the set + %% of host keys. + CryptoSupported = ssh_transport:supported_algorithms(public_key), + Algs = [A || A <- Algs0, + lists:member(A, CryptoSupported)], - - Algs = proplists:get_value(public_key, - proplists:get_value(preferred_algorithms, Opts, []), - default_public_key_algorithms()), Prefs = method_preference(Algs), ssh_transport:ssh_packet(Msg, Ssh#ssh{user = User, userauth_preference = Prefs, @@ -134,34 +202,9 @@ init_userauth_request_msg(#ssh{opts = Opts} = Ssh) -> language = "en"}) end. -userauth_request_msg(#ssh{userauth_preference = []} = Ssh) -> - Msg = #ssh_msg_disconnect{code = - ?SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE, - description = "Unable to connect using the available" - " authentication methods", - language = "en"}, - {disconnect, Msg, ssh_transport:ssh_packet(Msg, Ssh)}; - -userauth_request_msg(#ssh{userauth_methods = Methods, - userauth_preference = [{Pref, Module, - Function, Args} | Prefs]} - = Ssh0) -> - Ssh = Ssh0#ssh{userauth_preference = Prefs}, - case lists:member(Pref, Methods) of - true -> - case Module:Function(Args ++ [Ssh]) of - not_ok -> - userauth_request_msg(Ssh); - Result -> - Result - end; - false -> - userauth_request_msg(Ssh) - end. - - -handle_userauth_request(#ssh_msg_service_request{name = - Name = "ssh-userauth"}, +%%%---------------------------------------------------------------- +%%% called by server +handle_userauth_request(#ssh_msg_service_request{name = Name = "ssh-userauth"}, _, Ssh) -> {ok, ssh_transport:ssh_packet(#ssh_msg_service_accept{name = Name}, Ssh#ssh{service = "ssh-connection"})}; @@ -173,15 +216,15 @@ handle_userauth_request(#ssh_msg_userauth_request{user = User, #ssh{opts = Opts, userauth_supported_methods = Methods} = Ssh) -> Password = unicode:characters_to_list(BinPwd), - case check_password(User, Password, Opts) of - true -> + case check_password(User, Password, Opts, Ssh) of + {true,Ssh1} -> {authorized, User, - ssh_transport:ssh_packet(#ssh_msg_userauth_success{}, Ssh)}; - false -> + ssh_transport:ssh_packet(#ssh_msg_userauth_success{}, Ssh1)}; + {false,Ssh1} -> {not_authorized, {User, {error,"Bad user or password"}}, ssh_transport:ssh_packet(#ssh_msg_userauth_failure{ authentications = Methods, - partial_success = false}, Ssh)} + partial_success = false}, Ssh1)} end; handle_userauth_request(#ssh_msg_userauth_request{user = User, @@ -299,8 +342,7 @@ handle_userauth_request(#ssh_msg_userauth_request{user = User, >> }, {not_authorized, {User, undefined}, - ssh_transport:ssh_packet(Msg, Ssh#ssh{user = User, - kb_data = Msg + ssh_transport:ssh_packet(Msg, Ssh#ssh{user = User })} end; @@ -313,53 +355,45 @@ handle_userauth_request(#ssh_msg_userauth_request{user = User, #ssh_msg_userauth_failure{authentications = Methods, partial_success = false}, Ssh)}. -handle_userauth_info_request( - #ssh_msg_userauth_info_request{name = Name, - instruction = Instr, - num_prompts = NumPrompts, - data = Data}, IoCb, - #ssh{opts = Opts} = Ssh) -> + +%%%---------------------------------------------------------------- +%%% keyboard-interactive client +handle_userauth_info_request(#ssh_msg_userauth_info_request{name = Name, + instruction = Instr, + num_prompts = NumPrompts, + data = Data}, + #ssh{opts = Opts, + io_cb = IoCb + } = Ssh) -> PromptInfos = decode_keyboard_interactive_prompts(NumPrompts,Data), - Responses = keyboard_interact_get_responses(IoCb, Opts, - Name, Instr, PromptInfos), - {ok, - ssh_transport:ssh_packet( - #ssh_msg_userauth_info_response{num_responses = NumPrompts, - data = Responses}, Ssh)}. + case keyboard_interact_get_responses(IoCb, Opts, Name, Instr, PromptInfos) of + not_ok -> + not_ok; + Responses -> + {ok, + ssh_transport:ssh_packet( + #ssh_msg_userauth_info_response{num_responses = NumPrompts, + data = Responses}, Ssh)} + end. +%%%---------------------------------------------------------------- +%%% keyboard-interactive server handle_userauth_info_response(#ssh_msg_userauth_info_response{num_responses = 1, data = <<?UINT32(Sz), Password:Sz/binary>>}, #ssh{opts = Opts, - kb_tries_left = KbTriesLeft0, - kb_data = InfoMsg, + kb_tries_left = KbTriesLeft, user = User, userauth_supported_methods = Methods} = Ssh) -> - KbTriesLeft = KbTriesLeft0 - 1, - case check_password(User, unicode:characters_to_list(Password), Opts) of - true -> + case check_password(User, unicode:characters_to_list(Password), Opts, Ssh) of + {true,Ssh1} -> {authorized, User, - ssh_transport:ssh_packet(#ssh_msg_userauth_success{}, Ssh)}; - false when KbTriesLeft > 0 -> - UserAuthInfoMsg = - InfoMsg#ssh_msg_userauth_info_request{ - name = "", - instruction = - lists:concat( - ["Bad user or password, try again. ", - integer_to_list(KbTriesLeft), - " tries left."]) - }, - {not_authorized, {User, undefined}, - ssh_transport:ssh_packet(UserAuthInfoMsg, - Ssh#ssh{kb_tries_left = KbTriesLeft})}; - - false -> + ssh_transport:ssh_packet(#ssh_msg_userauth_success{}, Ssh1)}; + {false,Ssh1} -> {not_authorized, {User, {error,"Bad user or password"}}, ssh_transport:ssh_packet(#ssh_msg_userauth_failure{ authentications = Methods, partial_success = false}, - Ssh#ssh{kb_data = undefined, - kb_tries_left = 0} + Ssh1#ssh{kb_tries_left = max(KbTriesLeft-1, 0)} )} end; @@ -371,8 +405,6 @@ handle_userauth_info_response(#ssh_msg_userauth_info_response{}, language = "en"}). -default_public_key_algorithms() -> ?PREFERRED_PK_ALGS. - %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- @@ -404,13 +436,34 @@ user_name(Opts) -> {ok, User} end. -check_password(User, Password, Opts) -> +check_password(User, Password, Opts, Ssh) -> case proplists:get_value(pwdfun, Opts) of undefined -> Static = get_password_option(Opts, User), - Password == Static; - Cheker -> - Cheker(User, Password) + {Password == Static, Ssh}; + + Checker when is_function(Checker,2) -> + {Checker(User, Password), Ssh}; + + Checker when is_function(Checker,4) -> + #ssh{pwdfun_user_state = PrivateState, + peer = {_,PeerAddr={_,_}} + } = Ssh, + case Checker(User, Password, PeerAddr, PrivateState) of + true -> + {true,Ssh}; + false -> + {false,Ssh}; + {true,NewState} -> + {true, Ssh#ssh{pwdfun_user_state=NewState}}; + {false,NewState} -> + {false, Ssh#ssh{pwdfun_user_state=NewState}}; + disconnect -> + throw(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE, + description = + "Unable to connect using the available authentication methods", + language = ""}) + end end. get_password_option(Opts, User) -> @@ -447,10 +500,7 @@ build_sig_data(SessionId, User, Service, KeyBlob, Alg) -> ?binary(KeyBlob)], list_to_binary(Sig). -algorithm_string('ssh-rsa') -> - "ssh-rsa"; -algorithm_string('ssh-dss') -> - "ssh-dss". + decode_keyboard_interactive_prompts(_NumPrompts, Data) -> ssh_message:decode_keyboard_interactive_prompts(Data, []). @@ -462,30 +512,34 @@ keyboard_interact_get_responses(IoCb, Opts, Name, Instr, PromptInfos) -> proplists:get_value(password, Opts, undefined), IoCb, Name, Instr, PromptInfos, Opts, NumPrompts). + +keyboard_interact_get_responses(_, _, not_ok, _, _, _, _, _, _) -> + not_ok; keyboard_interact_get_responses(_, undefined, Password, _, _, _, _, _, 1) when Password =/= undefined -> [Password]; %% Password auth implemented with keyboard-interaction and passwd is known keyboard_interact_get_responses(_, _, _, _, _, _, _, _, 0) -> - [""]; + []; keyboard_interact_get_responses(false, undefined, undefined, _, _, _, [Prompt|_], Opts, _) -> ssh_no_io:read_line(Prompt, Opts); %% Throws error as keyboard interaction is not allowed keyboard_interact_get_responses(true, undefined, _,IoCb, Name, Instr, PromptInfos, Opts, _) -> keyboard_interact(IoCb, Name, Instr, PromptInfos, Opts); -keyboard_interact_get_responses(true, Fun, _, Name, Instr, PromptInfos, _, _, NumPrompts) -> +keyboard_interact_get_responses(true, Fun, _Pwd, _IoCb, Name, Instr, PromptInfos, _Opts, NumPrompts) -> keyboard_interact_fun(Fun, Name, Instr, PromptInfos, NumPrompts). keyboard_interact(IoCb, Name, Instr, Prompts, Opts) -> - if Name /= "" -> IoCb:format("~s", [Name]); - true -> ok - end, - if Instr /= "" -> IoCb:format("~s", [Instr]); - true -> ok - end, + write_if_nonempty(IoCb, Name), + write_if_nonempty(IoCb, Instr), lists:map(fun({Prompt, true}) -> IoCb:read_line(Prompt, Opts); ({Prompt, false}) -> IoCb:read_password(Prompt, Opts) end, Prompts). +write_if_nonempty(_, "") -> ok; +write_if_nonempty(_, <<>>) -> ok; +write_if_nonempty(IoCb, Text) -> IoCb:format("~s~n",[Text]). + + keyboard_interact_fun(KbdInteractFun, Name, Instr, PromptInfos, NumPrompts) -> Prompts = lists:map(fun({Prompt, _Echo}) -> Prompt end, PromptInfos), @@ -501,23 +555,18 @@ keyboard_interact_fun(KbdInteractFun, Name, Instr, PromptInfos, NumPrompts) -> language = "en"}}) end. -decode_public_key_v2(<<?UINT32(Len0), _:Len0/binary, - ?UINT32(Len1), E:Len1/big-signed-integer-unit:8, - ?UINT32(Len2), N:Len2/big-signed-integer-unit:8>> - ,"ssh-rsa") -> - {ok, #'RSAPublicKey'{publicExponent = E, modulus = N}}; -decode_public_key_v2(<<?UINT32(Len0), _:Len0/binary, - ?UINT32(Len1), P:Len1/big-signed-integer-unit:8, - ?UINT32(Len2), Q:Len2/big-signed-integer-unit:8, - ?UINT32(Len3), G:Len3/big-signed-integer-unit:8, - ?UINT32(Len4), Y:Len4/big-signed-integer-unit:8>> - , "ssh-dss") -> - {ok, {Y, #'Dss-Parms'{p = P, q = Q, g = G}}}; - -decode_public_key_v2(_, _) -> - {error, bad_format}. - -encode_public_key(#'RSAPrivateKey'{publicExponent = E, modulus = N}) -> - ssh_bits:encode(["ssh-rsa",E,N], [string,mpint,mpint]); -encode_public_key(#'DSAPrivateKey'{p = P, q = Q, g = G, y = Y}) -> - ssh_bits:encode(["ssh-dss",P,Q,G,Y], [string,mpint,mpint,mpint,mpint]). +decode_public_key_v2(Bin, _Type) -> + try + public_key:ssh_decode(Bin, ssh2_pubkey) + of + Key -> {ok, Key} + catch + _:_ -> {error, bad_format} + end. + +encode_public_key(_Alg, Key) -> + try + public_key:ssh_encode(Key, ssh2_pubkey) + catch + _:_ -> not_ok + end. diff --git a/lib/ssh/src/ssh_auth.hrl b/lib/ssh/src/ssh_auth.hrl index 71f222f6d7..449bc4fa45 100644 --- a/lib/ssh/src/ssh_auth.hrl +++ b/lib/ssh/src/ssh_auth.hrl @@ -22,9 +22,6 @@ %%% Description: Ssh User Authentication Protocol --define(SUPPORTED_AUTH_METHODS, "publickey,keyboard-interactive,password"). - --define(PREFERRED_PK_ALGS, ['ssh-rsa','ssh-dss']). -define(SSH_MSG_USERAUTH_REQUEST, 50). -define(SSH_MSG_USERAUTH_FAILURE, 51). diff --git a/lib/ssh/src/ssh_connect.hrl b/lib/ssh/src/ssh_connect.hrl index 6db89c5d80..9f9f3de8fa 100644 --- a/lib/ssh/src/ssh_connect.hrl +++ b/lib/ssh/src/ssh_connect.hrl @@ -248,6 +248,9 @@ local_id, %% local channel id recv_window_size, + recv_window_pending = 0, %% Sum of window size updates that has not + %% yet been sent. This limits the number + %% of sent update msgs. recv_packet_size, recv_close = false, diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl index 64d2113125..a34478732c 100644 --- a/lib/ssh/src/ssh_connection.erl +++ b/lib/ssh/src/ssh_connection.erl @@ -662,7 +662,7 @@ handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId, ReplyMsg = {subsystem, ChannelId, WantReply, binary_to_list(SsName)}, try - {ok, Pid} = start_subsytem(SsName, Connection, Channel0, ReplyMsg), + {ok, Pid} = start_subsystem(SsName, Connection, Channel0, ReplyMsg), erlang:monitor(process, Pid), Channel = Channel0#channel{user = Pid}, ssh_channel:cache_update(Cache, Channel), @@ -935,14 +935,27 @@ encode_ip(Addr) when is_list(Addr) -> end end. -start_channel(Cb, Id, Args, SubSysSup) -> - start_channel(Cb, Id, Args, SubSysSup, undefined). +start_channel(Cb, Id, Args, SubSysSup, Opts) -> + start_channel(Cb, Id, Args, SubSysSup, undefined, Opts). -start_channel(Cb, Id, Args, SubSysSup, Exec) -> +start_channel(Cb, Id, Args, SubSysSup, Exec, Opts) -> ChildSpec = child_spec(Cb, Id, Args, Exec), ChannelSup = ssh_subsystem_sup:channel_supervisor(SubSysSup), + assert_limit_num_channels_not_exceeded(ChannelSup, Opts), ssh_channel_sup:start_child(ChannelSup, ChildSpec). +assert_limit_num_channels_not_exceeded(ChannelSup, Opts) -> + MaxNumChannels = proplists:get_value(max_channels, Opts, infinity), + NumChannels = length([x || {_,_,worker,[ssh_channel]} <- + supervisor:which_children(ChannelSup)]), + if + %% Note that NumChannels is BEFORE starting a new one + NumChannels < MaxNumChannels -> + ok; + true -> + throw(max_num_channels_exceeded) + end. + %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- @@ -998,17 +1011,19 @@ child_spec(Callback, Id, Args, Exec) -> start_cli(#connection{cli_spec = no_cli}, _) -> {error, cli_disabled}; -start_cli(#connection{cli_spec = {CbModule, Args}, exec = Exec, +start_cli(#connection{options = Options, + cli_spec = {CbModule, Args}, + exec = Exec, sub_system_supervisor = SubSysSup}, ChannelId) -> - start_channel(CbModule, ChannelId, Args, SubSysSup, Exec). + start_channel(CbModule, ChannelId, Args, SubSysSup, Exec, Options). -start_subsytem(BinName, #connection{options = Options, +start_subsystem(BinName, #connection{options = Options, sub_system_supervisor = SubSysSup}, #channel{local_id = ChannelId}, _ReplyMsg) -> Name = binary_to_list(BinName), case check_subsystem(Name, Options) of {Callback, Opts} when is_atom(Callback), Callback =/= none -> - start_channel(Callback, ChannelId, Opts, SubSysSup); + start_channel(Callback, ChannelId, Opts, SubSysSup, Options); {Other, _} when Other =/= none -> {error, legacy_option_not_supported} end. diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl index a9c60d0674..b73f8b23d2 100644 --- a/lib/ssh/src/ssh_connection_handler.erl +++ b/lib/ssh/src/ssh_connection_handler.erl @@ -46,8 +46,13 @@ get_print_info/1]). %% gen_fsm callbacks --export([hello/2, kexinit/2, key_exchange/2, new_keys/2, - userauth/2, connected/2, +-export([hello/2, kexinit/2, key_exchange/2, + key_exchange_dh_gex_init/2, key_exchange_dh_gex_reply/2, + new_keys/2, + service_request/2, connected/2, + userauth/2, + userauth_keyboard_interactive/2, + userauth_keyboard_interactive_info_response/2, error/2]). -export([init/1, handle_event/3, @@ -80,7 +85,12 @@ recbuf }). --type state_name() :: hello | kexinit | key_exchange | new_keys | userauth | connection. +-type state_name() :: hello | kexinit | key_exchange | key_exchange_dh_gex_init | + key_exchange_dh_gex_reply | new_keys | service_request | + userauth | userauth_keyboard_interactive | + userauth_keyboard_interactive_info_response | + connection. + -type gen_fsm_state_return() :: {next_state, state_name(), term()} | {next_state, state_name(), term(), timeout()} | {stop, term(), term()}. @@ -417,27 +427,59 @@ key_exchange(#ssh_msg_kexdh_reply{} = Msg, send_msg(NewKeys, State), {next_state, new_keys, next_packet(State#state{ssh_params = Ssh})}; +key_exchange(#ssh_msg_kex_dh_gex_request{} = Msg, + #state{ssh_params = #ssh{role = server} = Ssh0} = State) -> + {ok, GexGroup, Ssh} = ssh_transport:handle_kex_dh_gex_request(Msg, Ssh0), + send_msg(GexGroup, State), + {next_state, key_exchange_dh_gex_init, next_packet(State#state{ssh_params = Ssh})}; + +key_exchange(#ssh_msg_kex_dh_gex_request_old{} = Msg, + #state{ssh_params = #ssh{role = server} = Ssh0} = State) -> + {ok, GexGroup, Ssh} = ssh_transport:handle_kex_dh_gex_request(Msg, Ssh0), + send_msg(GexGroup, State), + {next_state, key_exchange_dh_gex_init, next_packet(State#state{ssh_params = Ssh})}; + key_exchange(#ssh_msg_kex_dh_gex_group{} = Msg, + #state{ssh_params = #ssh{role = client} = Ssh0} = State) -> + {ok, KexGexInit, Ssh} = ssh_transport:handle_kex_dh_gex_group(Msg, Ssh0), + send_msg(KexGexInit, State), + {next_state, key_exchange_dh_gex_reply, next_packet(State#state{ssh_params = Ssh})}; + +key_exchange(#ssh_msg_kex_ecdh_init{} = Msg, #state{ssh_params = #ssh{role = server} = Ssh0} = State) -> - {ok, NextKexMsg, Ssh1} = ssh_transport:handle_kex_dh_gex_group(Msg, Ssh0), - send_msg(NextKexMsg, State), + {ok, KexEcdhReply, Ssh1} = ssh_transport:handle_kex_ecdh_init(Msg, Ssh0), + send_msg(KexEcdhReply, State), {ok, NewKeys, Ssh} = ssh_transport:new_keys_message(Ssh1), send_msg(NewKeys, State), {next_state, new_keys, next_packet(State#state{ssh_params = Ssh})}; -key_exchange(#ssh_msg_kex_dh_gex_request{} = Msg, +key_exchange(#ssh_msg_kex_ecdh_reply{} = Msg, #state{ssh_params = #ssh{role = client} = Ssh0} = State) -> - {ok, NextKexMsg, Ssh} = ssh_transport:handle_kex_dh_gex_request(Msg, Ssh0), - send_msg(NextKexMsg, State), - {next_state, new_keys, next_packet(State#state{ssh_params = Ssh})}; + {ok, NewKeys, Ssh} = ssh_transport:handle_kex_ecdh_reply(Msg, Ssh0), + send_msg(NewKeys, State), + {next_state, new_keys, next_packet(State#state{ssh_params = Ssh})}. -key_exchange(#ssh_msg_kex_dh_gex_reply{} = Msg, - #state{ssh_params = #ssh{role = client} = Ssh0} = State) -> - {ok, NewKeys, Ssh} = ssh_transport:handle_kex_dh_gex_reply(Msg, Ssh0), +%%-------------------------------------------------------------------- +-spec key_exchange_dh_gex_init(#ssh_msg_kex_dh_gex_init{}, #state{}) -> gen_fsm_state_return(). +%%-------------------------------------------------------------------- +key_exchange_dh_gex_init(#ssh_msg_kex_dh_gex_init{} = Msg, + #state{ssh_params = #ssh{role = server} = Ssh0} = State) -> + {ok, KexGexReply, Ssh1} = ssh_transport:handle_kex_dh_gex_init(Msg, Ssh0), + send_msg(KexGexReply, State), + {ok, NewKeys, Ssh} = ssh_transport:new_keys_message(Ssh1), send_msg(NewKeys, State), {next_state, new_keys, next_packet(State#state{ssh_params = Ssh})}. %%-------------------------------------------------------------------- +-spec key_exchange_dh_gex_reply(#ssh_msg_kex_dh_gex_reply{}, #state{}) -> gen_fsm_state_return(). +%%-------------------------------------------------------------------- +key_exchange_dh_gex_reply(#ssh_msg_kex_dh_gex_reply{} = Msg, + #state{ssh_params = #ssh{role = client} = Ssh0} = State) -> + {ok, NewKeys, Ssh1} = ssh_transport:handle_kex_dh_gex_reply(Msg, Ssh0), + send_msg(NewKeys, State), + {next_state, new_keys, next_packet(State#state{ssh_params = Ssh1})}. + +%%-------------------------------------------------------------------- -spec new_keys(#ssh_msg_newkeys{}, #state{}) -> gen_fsm_state_return(). %%-------------------------------------------------------------------- @@ -446,28 +488,30 @@ new_keys(#ssh_msg_newkeys{} = Msg, #state{ssh_params = Ssh0} = State0) -> after_new_keys(next_packet(State0#state{ssh_params = Ssh})). %%-------------------------------------------------------------------- --spec userauth(#ssh_msg_service_request{} | #ssh_msg_service_accept{} | - #ssh_msg_userauth_request{} | #ssh_msg_userauth_info_request{} | - #ssh_msg_userauth_info_response{} | #ssh_msg_userauth_success{} | - #ssh_msg_userauth_failure{} | #ssh_msg_userauth_banner{}, - #state{}) -> gen_fsm_state_return(). +-spec service_request(#ssh_msg_service_request{} | #ssh_msg_service_accept{}, + #state{}) -> gen_fsm_state_return(). %%-------------------------------------------------------------------- - -userauth(#ssh_msg_service_request{name = "ssh-userauth"} = Msg, +service_request(#ssh_msg_service_request{name = "ssh-userauth"} = Msg, #state{ssh_params = #ssh{role = server, session_id = SessionId} = Ssh0} = State) -> {ok, {Reply, Ssh}} = ssh_auth:handle_userauth_request(Msg, SessionId, Ssh0), send_msg(Reply, State), {next_state, userauth, next_packet(State#state{ssh_params = Ssh})}; -userauth(#ssh_msg_service_accept{name = "ssh-userauth"}, - #state{ssh_params = #ssh{role = client, - service = "ssh-userauth"} = Ssh0} = - State) -> +service_request(#ssh_msg_service_accept{name = "ssh-userauth"}, + #state{ssh_params = #ssh{role = client, + service = "ssh-userauth"} = Ssh0} = + State) -> {Msg, Ssh} = ssh_auth:init_userauth_request_msg(Ssh0), send_msg(Msg, State), - {next_state, userauth, next_packet(State#state{auth_user = Ssh#ssh.user, ssh_params = Ssh})}; + {next_state, userauth, next_packet(State#state{auth_user = Ssh#ssh.user, ssh_params = Ssh})}. +%%-------------------------------------------------------------------- +-spec userauth(#ssh_msg_userauth_request{} | #ssh_msg_userauth_info_request{} | + #ssh_msg_userauth_info_response{} | #ssh_msg_userauth_success{} | + #ssh_msg_userauth_failure{} | #ssh_msg_userauth_banner{}, + #state{}) -> gen_fsm_state_return(). +%%-------------------------------------------------------------------- userauth(#ssh_msg_userauth_request{service = "ssh-connection", method = "none"} = Msg, #state{ssh_params = #ssh{session_id = SessionId, role = server, @@ -492,7 +536,11 @@ userauth(#ssh_msg_userauth_request{service = "ssh-connection", Pid ! ssh_connected, connected_fun(User, Address, Method, Opts), {next_state, connected, - next_packet(State#state{auth_user = User, ssh_params = Ssh})}; + next_packet(State#state{auth_user = User, ssh_params = Ssh#ssh{authenticated = true}})}; + {not_authorized, {User, Reason}, {Reply, Ssh}} when Method == "keyboard-interactive" -> + retry_fun(User, Address, Reason, Opts), + send_msg(Reply, State), + {next_state, userauth_keyboard_interactive, next_packet(State#state{ssh_params = Ssh})}; {not_authorized, {User, Reason}, {Reply, Ssh}} -> retry_fun(User, Address, Reason, Opts), send_msg(Reply, State), @@ -502,30 +550,6 @@ userauth(#ssh_msg_userauth_request{service = "ssh-connection", userauth(Msg#ssh_msg_userauth_request{method="none"}, State) end; -userauth(#ssh_msg_userauth_info_request{} = Msg, - #state{ssh_params = #ssh{role = client, - io_cb = IoCb} = Ssh0} = State) -> - {ok, {Reply, Ssh}} = ssh_auth:handle_userauth_info_request(Msg, IoCb, Ssh0), - send_msg(Reply, State), - {next_state, userauth, next_packet(State#state{ssh_params = Ssh})}; - -userauth(#ssh_msg_userauth_info_response{} = Msg, - #state{ssh_params = #ssh{role = server, - peer = {_, Address}} = Ssh0, - opts = Opts, starter = Pid} = State) -> - case ssh_auth:handle_userauth_info_response(Msg, Ssh0) of - {authorized, User, {Reply, Ssh}} -> - send_msg(Reply, State), - Pid ! ssh_connected, - connected_fun(User, Address, "keyboard-interactive", Opts), - {next_state, connected, - next_packet(State#state{auth_user = User, ssh_params = Ssh})}; - {not_authorized, {User, Reason}, {Reply, Ssh}} -> - retry_fun(User, Address, Reason, Opts), - send_msg(Reply, State), - {next_state, userauth, next_packet(State#state{ssh_params = Ssh})} - end; - userauth(#ssh_msg_userauth_success{}, #state{ssh_params = #ssh{role = client} = Ssh, starter = Pid} = State) -> Pid ! ssh_connected, @@ -552,19 +576,25 @@ userauth(#ssh_msg_userauth_failure{authentications = Methodes}, {disconnect, DisconnectMsg, {Msg, Ssh}} -> send_msg(Msg, State), handle_disconnect(DisconnectMsg, State#state{ssh_params = Ssh}); - {Msg, Ssh} -> + {"keyboard-interactive", {Msg, Ssh}} -> + send_msg(Msg, State), + {next_state, userauth_keyboard_interactive, next_packet(State#state{ssh_params = Ssh})}; + {_Method, {Msg, Ssh}} -> send_msg(Msg, State), {next_state, userauth, next_packet(State#state{ssh_params = Ssh})} end; %% The prefered authentication method failed try next method -userauth(#ssh_msg_userauth_failure{}, +userauth(#ssh_msg_userauth_failure{}, #state{ssh_params = #ssh{role = client} = Ssh0} = State) -> case ssh_auth:userauth_request_msg(Ssh0) of {disconnect, DisconnectMsg,{Msg, Ssh}} -> send_msg(Msg, State), handle_disconnect(DisconnectMsg, State#state{ssh_params = Ssh}); - {Msg, Ssh} -> + {"keyboard-interactive", {Msg, Ssh}} -> + send_msg(Msg, State), + {next_state, userauth_keyboard_interactive, next_packet(State#state{ssh_params = Ssh})}; + {_Method, {Msg, Ssh}} -> send_msg(Msg, State), {next_state, userauth, next_packet(State#state{ssh_params = Ssh})} end; @@ -579,6 +609,66 @@ userauth(#ssh_msg_userauth_banner{message = Msg}, io:format("~s", [Msg]), {next_state, userauth, next_packet(State)}. + + +userauth_keyboard_interactive(#ssh_msg_userauth_info_request{} = Msg, + #state{ssh_params = #ssh{role = client} = Ssh0} = State) -> + case ssh_auth:handle_userauth_info_request(Msg, Ssh0) of + {ok, {Reply, Ssh}} -> + send_msg(Reply, State), + {next_state, userauth_keyboard_interactive_info_response, next_packet(State#state{ssh_params = Ssh})}; + not_ok -> + userauth(Msg, State) + end; + +userauth_keyboard_interactive(#ssh_msg_userauth_info_response{} = Msg, + #state{ssh_params = #ssh{role = server, + peer = {_, Address}} = Ssh0, + opts = Opts, starter = Pid} = State) -> + case ssh_auth:handle_userauth_info_response(Msg, Ssh0) of + {authorized, User, {Reply, Ssh}} -> + send_msg(Reply, State), + Pid ! ssh_connected, + connected_fun(User, Address, "keyboard-interactive", Opts), + {next_state, connected, + next_packet(State#state{auth_user = User, ssh_params = Ssh#ssh{authenticated = true}})}; + {not_authorized, {User, Reason}, {Reply, Ssh}} -> + retry_fun(User, Address, Reason, Opts), + send_msg(Reply, State), + {next_state, userauth, next_packet(State#state{ssh_params = Ssh})} + end; +userauth_keyboard_interactive(Msg = #ssh_msg_userauth_failure{}, + #state{ssh_params = Ssh0 = + #ssh{role = client, + userauth_preference = Prefs0}} + = State) -> + Prefs = [{Method,M,F,A} || {Method,M,F,A} <- Prefs0, + Method =/= "keyboard-interactive"], + userauth(Msg, State#state{ssh_params = Ssh0#ssh{userauth_preference=Prefs}}). + + + +userauth_keyboard_interactive_info_response(Msg=#ssh_msg_userauth_failure{}, + #state{ssh_params = #ssh{role = client, + opts = Opts} = Ssh0} = State0) -> + + State = case proplists:get_value(password, Opts) of + undefined -> + State0; + _ -> + State0#state{ssh_params = + Ssh0#ssh{opts = + lists:keyreplace(password,1,Opts, + {password,not_ok})}} + end, + userauth(Msg, State); +userauth_keyboard_interactive_info_response(Msg=#ssh_msg_userauth_success{}, + #state{ssh_params = #ssh{role = client}} = State) -> + userauth(Msg, State); +userauth_keyboard_interactive_info_response(Msg=#ssh_msg_userauth_info_request{}, + #state{ssh_params = #ssh{role = client}} = State) -> + userauth_keyboard_interactive(Msg, State). + %%-------------------------------------------------------------------- -spec connected({#ssh_msg_kexinit{}, binary()}, %%| %% #ssh_msg_kexdh_init{}, #state{}) -> gen_fsm_state_return(). @@ -663,13 +753,28 @@ handle_event({adjust_window, ChannelId, Bytes}, StateName, #connection{channel_cache = Cache}} = State0) -> State = case ssh_channel:cache_lookup(Cache, ChannelId) of - #channel{recv_window_size = WinSize, remote_id = Id} = Channel -> - ssh_channel:cache_update(Cache, Channel#channel{recv_window_size = - WinSize + Bytes}), - Msg = ssh_connection:channel_adjust_window_msg(Id, Bytes), + #channel{recv_window_size = WinSize, + recv_window_pending = Pending, + recv_packet_size = PktSize} = Channel + when (WinSize-Bytes) >= 2*PktSize -> + %% The peer can send at least two more *full* packet, no hurry. + ssh_channel:cache_update(Cache, + Channel#channel{recv_window_pending = Pending + Bytes}), + State0; + + #channel{recv_window_size = WinSize, + recv_window_pending = Pending, + remote_id = Id} = Channel -> + %% Now we have to update the window - we can't receive so many more pkts + ssh_channel:cache_update(Cache, + Channel#channel{recv_window_size = + WinSize + Bytes + Pending, + recv_window_pending = 0}), + Msg = ssh_connection:channel_adjust_window_msg(Id, Bytes + Pending), send_replies([{connection_reply, Msg}], State0); - undefined -> - State0 + + undefined -> + State0 end, {next_state, StateName, next_packet(State)}; @@ -902,57 +1007,55 @@ handle_info({Protocol, Socket, Info}, hello, transport_protocol = Protocol} = State) -> event({info_line, Info}, hello, State); -handle_info({Protocol, Socket, Data}, Statename, - #state{socket = Socket, - transport_protocol = Protocol, - ssh_params = #ssh{decrypt_block_size = BlockSize, - recv_mac_size = MacSize} = Ssh0, - decoded_data_buffer = <<>>, - encoded_data_buffer = EncData0} = State0) -> - - %% Implementations SHOULD decrypt the length after receiving the - %% first 8 (or cipher block size, whichever is larger) bytes of a - %% packet. (RFC 4253: Section 6 - Binary Packet Protocol) - case size(EncData0) + size(Data) >= erlang:max(8, BlockSize) of - true -> - {Ssh, SshPacketLen, DecData, EncData} = - - ssh_transport:decrypt_first_block(<<EncData0/binary, - Data/binary>>, Ssh0), - case SshPacketLen > ?SSH_MAX_PACKET_SIZE of - true -> - DisconnectMsg = - #ssh_msg_disconnect{code = - ?SSH_DISCONNECT_PROTOCOL_ERROR, - description = "Bad packet length " - ++ integer_to_list(SshPacketLen), - language = "en"}, - handle_disconnect(DisconnectMsg, State0); - false -> - RemainingSshPacketLen = - (SshPacketLen + ?SSH_LENGHT_INDICATOR_SIZE) - - BlockSize + MacSize, - State = State0#state{ssh_params = Ssh}, - handle_ssh_packet_data(RemainingSshPacketLen, - DecData, EncData, Statename, - State) - end; - false -> - {next_state, Statename, - next_packet(State0#state{encoded_data_buffer = - <<EncData0/binary, Data/binary>>})} - end; - -handle_info({Protocol, Socket, Data}, Statename, +handle_info({Protocol, Socket, Data}, StateName, #state{socket = Socket, transport_protocol = Protocol, - decoded_data_buffer = DecData, - encoded_data_buffer = EncData, - undecoded_packet_length = Len} = - State) when is_integer(Len) -> - handle_ssh_packet_data(Len, DecData, <<EncData/binary, Data/binary>>, - Statename, State); + ssh_params = Ssh0, + decoded_data_buffer = DecData0, + encoded_data_buffer = EncData0, + undecoded_packet_length = RemainingSshPacketLen0} = State0) -> + Encoded = <<EncData0/binary, Data/binary>>, + try ssh_transport:handle_packet_part(DecData0, Encoded, RemainingSshPacketLen0, Ssh0) + of + {get_more, DecBytes, EncDataRest, RemainingSshPacketLen, Ssh1} -> + {next_state, StateName, + next_packet(State0#state{encoded_data_buffer = EncDataRest, + decoded_data_buffer = DecBytes, + undecoded_packet_length = RemainingSshPacketLen, + ssh_params = Ssh1})}; + {decoded, MsgBytes, EncDataRest, Ssh1} -> + generate_event(MsgBytes, StateName, + State0#state{ssh_params = Ssh1, + %% Important to be set for + %% next_packet +%%% FIXME: the following three seem to always be set in generate_event! + decoded_data_buffer = <<>>, + undecoded_packet_length = undefined, + encoded_data_buffer = EncDataRest}, + EncDataRest); + {bad_mac, Ssh1} -> + DisconnectMsg = + #ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR, + description = "Bad mac", + language = ""}, + handle_disconnect(DisconnectMsg, State0#state{ssh_params=Ssh1}); + {error, {exceeds_max_size,PacketLen}} -> + DisconnectMsg = + #ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR, + description = "Bad packet length " + ++ integer_to_list(PacketLen), + language = ""}, + handle_disconnect(DisconnectMsg, State0) + catch + _:_ -> + DisconnectMsg = + #ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR, + description = "Bad packet", + language = ""}, + handle_disconnect(DisconnectMsg, State0) + end; + handle_info({CloseTag, _Socket}, _StateName, #state{transport_close_tag = CloseTag, ssh_params = #ssh{role = _Role, opts = _Opts}} = State) -> @@ -1030,7 +1133,7 @@ handle_info(UnexpectedMessage, StateName, #state{opts = Opts, terminate(normal, _, #state{transport_cb = Transport, connection_state = Connection, socket = Socket}) -> - terminate_subsytem(Connection), + terminate_subsystem(Connection), (catch Transport:close(Socket)), ok; @@ -1059,7 +1162,7 @@ terminate({shutdown, _}, StateName, State) -> terminate(Reason, StateName, #state{ssh_params = Ssh0, starter = _Pid, connection_state = Connection} = State) -> - terminate_subsytem(Connection), + terminate_subsystem(Connection), log_error(Reason), DisconnectMsg = #ssh_msg_disconnect{code = ?SSH_DISCONNECT_BY_APPLICATION, @@ -1070,10 +1173,10 @@ terminate(Reason, StateName, #state{ssh_params = Ssh0, starter = _Pid, terminate(normal, StateName, State#state{ssh_params = Ssh}). -terminate_subsytem(#connection{system_supervisor = SysSup, +terminate_subsystem(#connection{system_supervisor = SysSup, sub_system_supervisor = SubSysSup}) when is_pid(SubSysSup) -> ssh_system_sup:stop_subsystem(SysSup, SubSysSup); -terminate_subsytem(_) -> +terminate_subsystem(_) -> ok. format_status(normal, [_, State]) -> @@ -1158,7 +1261,7 @@ init_ssh(client = Role, Vsn, Version, Options, Socket) -> end, AuthMethods = proplists:get_value(auth_methods, Options, - ?SUPPORTED_AUTH_METHODS), + undefined), {ok, PeerAddr} = inet:peername(Socket), PeerName = proplists:get_value(host, Options), @@ -1173,7 +1276,10 @@ init_ssh(client = Role, Vsn, Version, Options, Socket) -> opts = Options, userauth_supported_methods = AuthMethods, peer = {PeerName, PeerAddr}, - available_host_keys = supported_host_keys(Role, KeyCb, Options) + available_host_keys = supported_host_keys(Role, KeyCb, Options), + random_length_padding = proplists:get_value(max_random_length_padding, + Options, + (#ssh{})#ssh.random_length_padding) }; init_ssh(server = Role, Vsn, Version, Options, Socket) -> @@ -1193,7 +1299,10 @@ init_ssh(server = Role, Vsn, Version, Options, Socket) -> userauth_methods = AuthMethodsAsList, kb_tries_left = 3, peer = {undefined, PeerAddr}, - available_host_keys = supported_host_keys(Role, KeyCb, Options) + available_host_keys = supported_host_keys(Role, KeyCb, Options), + random_length_padding = proplists:get_value(max_random_length_padding, + Options, + (#ssh{})#ssh.random_length_padding) }. supported_host_keys(client, _, Options) -> @@ -1202,9 +1311,9 @@ supported_host_keys(client, _, Options) -> proplists:get_value(preferred_algorithms,Options,[]) ) of undefined -> - ssh_auth:default_public_key_algorithms(); + ssh_transport:default_algorithms(public_key); L -> - L -- (L--ssh_auth:default_public_key_algorithms()) + L -- (L--ssh_transport:default_algorithms(public_key)) end of [] -> @@ -1216,21 +1325,17 @@ supported_host_keys(client, _, Options) -> {stop, {shutdown, Reason}} end; supported_host_keys(server, KeyCb, Options) -> - Algs= [atom_to_list(A) || A <- proplists:get_value(public_key, proplists:get_value(preferred_algorithms,Options,[]), - ssh_auth:default_public_key_algorithms() + ssh_transport:default_algorithms(public_key) ), available_host_key(KeyCb, A, Options) - ], - Algs. - + ]. %% Alg :: atom() available_host_key(KeyCb, Alg, Opts) -> element(1, catch KeyCb:host_key(Alg, Opts)) == ok. - send_msg(Msg, #state{socket = Socket, transport_cb = Transport}) -> Transport:send(Socket, Msg). @@ -1287,7 +1392,7 @@ event(Event, StateName, State) -> handle_disconnect(DisconnectMsg, State); throw:{ErrorToDisplay, #ssh_msg_disconnect{} = DisconnectMsg} -> handle_disconnect(DisconnectMsg, State, ErrorToDisplay); - _:_ -> + _C:_Error -> handle_disconnect(#ssh_msg_disconnect{code = error_code(StateName), description = "Invalid state", language = "en"}, State) @@ -1319,46 +1424,57 @@ generate_event(<<?BYTE(Byte), _/binary>> = Msg, StateName, Byte == ?SSH_MSG_CHANNEL_REQUEST; Byte == ?SSH_MSG_CHANNEL_SUCCESS; Byte == ?SSH_MSG_CHANNEL_FAILURE -> - ConnectionMsg = ssh_message:decode(Msg), - State1 = generate_event_new_state(State0, EncData), - try ssh_connection:handle_msg(ConnectionMsg, Connection0, Role) of - {{replies, Replies0}, Connection} -> - if StateName == connected -> - Replies = Replies0, - State2 = State1; - true -> - {ConnReplies, Replies} = - lists:splitwith(fun not_connected_filter/1, Replies0), - Q = State1#state.event_queue ++ ConnReplies, - State2 = State1#state{ event_queue = Q } - end, - State = send_replies(Replies, State2#state{connection_state = Connection}), - {next_state, StateName, next_packet(State)}; - {noreply, Connection} -> - {next_state, StateName, next_packet(State1#state{connection_state = Connection})}; - {disconnect, {_, Reason}, {{replies, Replies}, Connection}} when - Role == client andalso ((StateName =/= connected) and (not Renegotiation)) -> - State = send_replies(Replies, State1#state{connection_state = Connection}), - User ! {self(), not_connected, Reason}, - {stop, {shutdown, normal}, - next_packet(State#state{connection_state = Connection})}; - {disconnect, _Reason, {{replies, Replies}, Connection}} -> - State = send_replies(Replies, State1#state{connection_state = Connection}), - {stop, {shutdown, normal}, State#state{connection_state = Connection}} + try + ssh_message:decode(Msg) + of + ConnectionMsg -> + State1 = generate_event_new_state(State0, EncData), + try ssh_connection:handle_msg(ConnectionMsg, Connection0, Role) of + {{replies, Replies0}, Connection} -> + if StateName == connected -> + Replies = Replies0, + State2 = State1; + true -> + {ConnReplies, Replies} = + lists:splitwith(fun not_connected_filter/1, Replies0), + Q = State1#state.event_queue ++ ConnReplies, + State2 = State1#state{ event_queue = Q } + end, + State = send_replies(Replies, State2#state{connection_state = Connection}), + {next_state, StateName, next_packet(State)}; + {noreply, Connection} -> + {next_state, StateName, next_packet(State1#state{connection_state = Connection})}; + {disconnect, {_, Reason}, {{replies, Replies}, Connection}} when + Role == client andalso ((StateName =/= connected) and (not Renegotiation)) -> + State = send_replies(Replies, State1#state{connection_state = Connection}), + User ! {self(), not_connected, Reason}, + {stop, {shutdown, normal}, + next_packet(State#state{connection_state = Connection})}; + {disconnect, _Reason, {{replies, Replies}, Connection}} -> + State = send_replies(Replies, State1#state{connection_state = Connection}), + {stop, {shutdown, normal}, State#state{connection_state = Connection}} + catch + _:Error -> + {disconnect, _Reason, {{replies, Replies}, Connection}} = + ssh_connection:handle_msg( + #ssh_msg_disconnect{code = ?SSH_DISCONNECT_BY_APPLICATION, + description = "Internal error", + language = "en"}, Connection0, Role), + State = send_replies(Replies, State1#state{connection_state = Connection}), + {stop, {shutdown, Error}, State#state{connection_state = Connection}} + end + catch - _:Error -> - {disconnect, _Reason, {{replies, Replies}, Connection}} = - ssh_connection:handle_msg( - #ssh_msg_disconnect{code = ?SSH_DISCONNECT_BY_APPLICATION, - description = "Internal error", - language = "en"}, Connection0, Role), - State = send_replies(Replies, State1#state{connection_state = Connection}), - {stop, {shutdown, Error}, State#state{connection_state = Connection}} + _:_ -> + handle_disconnect( + #ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR, + description = "Bad packet received", + language = ""}, State0) end; generate_event(Msg, StateName, State0, EncData) -> try - Event = ssh_message:decode(Msg), + Event = ssh_message:decode(set_prefix_if_trouble(Msg,State0)), State = generate_event_new_state(State0, EncData), case Event of #ssh_msg_kexinit{} -> @@ -1368,7 +1484,7 @@ generate_event(Msg, StateName, State0, EncData) -> event(Event, StateName, State) end catch - _:_ -> + _C:_E -> DisconnectMsg = #ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR, description = "Encountered unexpected input", @@ -1377,6 +1493,26 @@ generate_event(Msg, StateName, State0, EncData) -> end. +set_prefix_if_trouble(Msg = <<?BYTE(Op),_/binary>>, #state{ssh_params=SshParams}) + when Op == 30; + Op == 31 + -> + case catch atom_to_list(kex(SshParams)) of + "ecdh-sha2-" ++ _ -> + <<"ecdh",Msg/binary>>; + "diffie-hellman-group-exchange-" ++ _ -> + <<"dh_gex",Msg/binary>>; + "diffie-hellman-group" ++ _ -> + <<"dh",Msg/binary>>; + _ -> + Msg + end; +set_prefix_if_trouble(Msg, _) -> + Msg. + +kex(#ssh{algorithms=#alg{kex=Kex}}) -> Kex; +kex(_) -> undefined. + handle_request(ChannelPid, ChannelId, Type, Data, WantReply, From, #state{connection_state = @@ -1471,6 +1607,7 @@ new_channel_id(#state{connection_state = #connection{channel_id_seed = Id} = = State) -> {Id, State#state{connection_state = Connection#connection{channel_id_seed = Id + 1}}}. + generate_event_new_state(#state{ssh_params = #ssh{recv_sequence = SeqNum0} = Ssh} = State, EncData) -> @@ -1507,10 +1644,10 @@ after_new_keys(#state{renegotiate = false, ssh_params = #ssh{role = client} = Ssh0} = State) -> {Msg, Ssh} = ssh_auth:service_request_msg(Ssh0), send_msg(Msg, State), - {next_state, userauth, State#state{ssh_params = Ssh}}; + {next_state, service_request, State#state{ssh_params = Ssh}}; after_new_keys(#state{renegotiate = false, ssh_params = #ssh{role = server}} = State) -> - {next_state, userauth, State}. + {next_state, service_request, State}. after_new_keys_events({sync, _Event, From}, {stop, _Reason, _StateData}=Terminator) -> gen_fsm:reply(From, {error, closed}), @@ -1539,57 +1676,6 @@ after_new_keys_events({connection_reply, _Data} = Reply, {StateName, State}) -> NewState = send_replies([Reply], State), {next_state, StateName, NewState}. -handle_ssh_packet_data(RemainingSshPacketLen, DecData, EncData, StateName, - State) -> - EncSize = size(EncData), - case RemainingSshPacketLen > EncSize of - true -> - {next_state, StateName, - next_packet(State#state{decoded_data_buffer = DecData, - encoded_data_buffer = EncData, - undecoded_packet_length = - RemainingSshPacketLen})}; - false -> - handle_ssh_packet(RemainingSshPacketLen, StateName, - State#state{decoded_data_buffer = DecData, - encoded_data_buffer = EncData}) - - end. - -handle_ssh_packet(Length, StateName, #state{decoded_data_buffer = DecData0, - encoded_data_buffer = EncData0, - ssh_params = Ssh0, - transport_protocol = _Protocol, - socket = _Socket} = State0) -> - try - {Ssh1, DecData, EncData, Mac} = - ssh_transport:unpack(EncData0, Length, Ssh0), - SshPacket = <<DecData0/binary, DecData/binary>>, - case ssh_transport:is_valid_mac(Mac, SshPacket, Ssh1) of - true -> - PacketData = ssh_transport:msg_data(SshPacket), - {Ssh1, Msg} = ssh_transport:decompress(Ssh1, PacketData), - generate_event(Msg, StateName, - State0#state{ssh_params = Ssh1, - %% Important to be set for - %% next_packet - decoded_data_buffer = <<>>}, - EncData); - false -> - DisconnectMsg = - #ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR, - description = "Bad mac", - language = "en"}, - handle_disconnect(DisconnectMsg, State0) - end - catch _:_ -> - Disconnect = - #ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR, - description = "Bad input", - language = "en"}, - handle_disconnect(Disconnect, State0) - end. - handle_disconnect(DisconnectMsg, State) -> handle_disconnect(own, DisconnectMsg, State). diff --git a/lib/ssh/src/ssh_file.erl b/lib/ssh/src/ssh_file.erl index b98a8a8410..3e066c453d 100644 --- a/lib/ssh/src/ssh_file.erl +++ b/lib/ssh/src/ssh_file.erl @@ -52,8 +52,20 @@ host_key(Algorithm, Opts) -> %% so probably we could hardcod Password = ignore, but %% we keep it as an undocumented option for now. Password = proplists:get_value(identity_pass_phrase(Algorithm), Opts, ignore), - decode(File, Password). - + case decode(File, Password) of + {ok,Key} -> + case {Key,Algorithm} of + {#'RSAPrivateKey'{}, 'ssh-rsa'} -> {ok,Key}; + {#'DSAPrivateKey'{}, 'ssh-dss'} -> {ok,Key}; + {#'ECPrivateKey'{parameters = {namedCurve, ?'secp256r1'}}, 'ecdsa-sha2-nistp256'} -> {ok,Key}; + {#'ECPrivateKey'{parameters = {namedCurve, ?'secp384r1'}}, 'ecdsa-sha2-nistp384'} -> {ok,Key}; + {#'ECPrivateKey'{parameters = {namedCurve, ?'secp521r1'}}, 'ecdsa-sha2-nistp521'} -> {ok,Key}; + _ -> + {error,bad_keytype_in_file} + end; + Other -> + Other + end. is_auth_key(Key, User,Opts) -> case lookup_user_key(Key, User, Opts) of @@ -81,16 +93,15 @@ user_key(Algorithm, Opts) -> %% Internal functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -file_base_name('ssh-rsa') -> - "ssh_host_rsa_key"; -file_base_name('ssh-dss') -> - "ssh_host_dsa_key"; -file_base_name(_) -> - "ssh_host_key". +file_base_name('ssh-rsa' ) -> "ssh_host_rsa_key"; +file_base_name('ssh-dss' ) -> "ssh_host_dsa_key"; +file_base_name('ecdsa-sha2-nistp256') -> "ssh_host_ecdsa_key"; +file_base_name('ecdsa-sha2-nistp384') -> "ssh_host_ecdsa_key"; +file_base_name('ecdsa-sha2-nistp521') -> "ssh_host_ecdsa_key"; +file_base_name(_ ) -> "ssh_host_key". decode(File, Password) -> - try - {ok, decode_ssh_file(read_ssh_file(File), Password)} + try {ok, decode_ssh_file(read_ssh_file(File), Password)} catch throw:Reason -> {error, Reason}; @@ -210,29 +221,32 @@ do_lookup_host_key(KeyToMatch, Host, Alg, Opts) -> {ok, Fd} -> Res = lookup_host_key_fd(Fd, KeyToMatch, Host, Alg), file:close(Fd), - {ok, Res}; - {error, enoent} -> {error, not_found}; - Error -> Error + Res; + {error, enoent} -> + {error, not_found}; + Error -> + Error end. -identity_key_filename('ssh-dss') -> - "id_dsa"; -identity_key_filename('ssh-rsa') -> - "id_rsa". - -identity_pass_phrase("ssh-dss") -> - dsa_pass_phrase; -identity_pass_phrase('ssh-dss') -> - dsa_pass_phrase; -identity_pass_phrase('ssh-rsa') -> - rsa_pass_phrase; -identity_pass_phrase("ssh-rsa") -> - rsa_pass_phrase. - +identity_key_filename('ssh-dss' ) -> "id_dsa"; +identity_key_filename('ssh-rsa' ) -> "id_rsa"; +identity_key_filename('ecdsa-sha2-nistp256') -> "id_ecdsa"; +identity_key_filename('ecdsa-sha2-nistp384') -> "id_ecdsa"; +identity_key_filename('ecdsa-sha2-nistp521') -> "id_ecdsa". + +identity_pass_phrase("ssh-dss" ) -> dsa_pass_phrase; +identity_pass_phrase("ssh-rsa" ) -> rsa_pass_phrase; +identity_pass_phrase("ecdsa-sha2-"++_) -> ecdsa_pass_phrase; +identity_pass_phrase(P) when is_atom(P) -> + identity_pass_phrase(atom_to_list(P)). + lookup_host_key_fd(Fd, KeyToMatch, Host, KeyType) -> case io:get_line(Fd, '') of eof -> {error, not_found}; + {error,Error} -> + %% Rare... For example NFS errors + {error,Error}; Line -> case ssh_decode_line(Line, known_hosts) of [{Key, Attributes}] -> @@ -253,7 +267,7 @@ handle_host(Fd, KeyToMatch, Host, HostList, Key, KeyType) -> Host1 = host_name(Host), case lists:member(Host1, HostList) andalso key_match(Key, KeyType) of true when KeyToMatch == Key -> - Key; + {ok,Key}; _ -> lookup_host_key_fd(Fd, KeyToMatch, Host, KeyType) end. @@ -267,6 +281,13 @@ key_match(#'RSAPublicKey'{}, 'ssh-rsa') -> true; key_match({_, #'Dss-Parms'{}}, 'ssh-dss') -> true; +key_match({#'ECPoint'{},{namedCurve,Curve}}, Alg) -> + case atom_to_list(Alg) of + "ecdsa-sha2-"++IdS -> + Curve == public_key:ssh_curvename2oid(list_to_binary(IdS)); + _ -> + false + end; key_match(_, _) -> false. @@ -293,6 +314,9 @@ lookup_user_key_fd(Fd, Key) -> case io:get_line(Fd, '') of eof -> {error, not_found}; + {error,Error} -> + %% Rare... For example NFS errors + {error,Error}; Line -> case ssh_decode_line(Line, auth_keys) of [{AuthKey, _}] -> @@ -312,8 +336,18 @@ is_auth_key(Key, Key) -> is_auth_key(_,_) -> false. -default_user_dir()-> - {ok,[[Home|_]]} = init:get_argument(home), + +default_user_dir() -> + try + default_user_dir(os:getenv("HOME")) + catch + _:_ -> + default_user_dir(init:get_argument(home)) + end. + +default_user_dir({ok,[[Home|_]]}) -> + default_user_dir(Home); +default_user_dir(Home) when is_list(Home) -> UserDir = filename:join(Home, ".ssh"), ok = filelib:ensure_dir(filename:join(UserDir, "dummy")), {ok,Info} = file:read_file_info(UserDir), diff --git a/lib/ssh/src/ssh_io.erl b/lib/ssh/src/ssh_io.erl index a5e627fdb3..5e335c2063 100644 --- a/lib/ssh/src/ssh_io.erl +++ b/lib/ssh/src/ssh_io.erl @@ -31,56 +31,55 @@ read_line(Prompt, Ssh) -> format("~s", [listify(Prompt)]), proplists:get_value(user_pid, Ssh) ! {self(), question}, receive - Answer -> + Answer when is_list(Answer) -> Answer end. yes_no(Prompt, Ssh) -> - io:format("~s [y/n]?", [Prompt]), + format("~s [y/n]?", [Prompt]), proplists:get_value(user_pid, Ssh#ssh.opts) ! {self(), question}, receive - Answer -> + %% I can't see that the atoms y and n are ever received, but it must + %% be investigated before removing + y -> yes; + n -> no; + + Answer when is_list(Answer) -> case trim(Answer) of "y" -> yes; "n" -> no; "Y" -> yes; "N" -> no; - y -> yes; - n -> no; _ -> - io:format("please answer y or n\n"), + format("please answer y or n\n",[]), yes_no(Prompt, Ssh) end end. -read_password(Prompt, Ssh) -> +read_password(Prompt, #ssh{opts=Opts}) -> read_password(Prompt, Opts); +read_password(Prompt, Opts) when is_list(Opts) -> format("~s", [listify(Prompt)]), - case is_list(Ssh) of - false -> - proplists:get_value(user_pid, Ssh#ssh.opts) ! {self(), user_password}; - _ -> - proplists:get_value(user_pid, Ssh) ! {self(), user_password} - end, + proplists:get_value(user_pid, Opts) ! {self(), user_password}, receive - Answer -> - case Answer of - "" -> - read_password(Prompt, Ssh); - Pass -> Pass - end + Answer when is_list(Answer) -> + case trim(Answer) of + "" -> + read_password(Prompt, Opts); + Pwd -> + Pwd + end end. -listify(A) when is_atom(A) -> - atom_to_list(A); -listify(L) when is_list(L) -> - L; -listify(B) when is_binary(B) -> - binary_to_list(B). format(Fmt, Args) -> io:format(Fmt, Args). +%%%================================================================ +listify(A) when is_atom(A) -> atom_to_list(A); +listify(L) when is_list(L) -> L; +listify(B) when is_binary(B) -> binary_to_list(B). + trim(Line) when is_list(Line) -> lists:reverse(trim1(lists:reverse(trim1(Line)))); @@ -93,6 +92,3 @@ trim1([$\r|Cs]) -> trim(Cs); trim1([$\n|Cs]) -> trim(Cs); trim1([$\t|Cs]) -> trim(Cs); trim1(Cs) -> Cs. - - - diff --git a/lib/ssh/src/ssh_message.erl b/lib/ssh/src/ssh_message.erl index 1f0f6fb15f..b6c4496be2 100644 --- a/lib/ssh/src/ssh_message.erl +++ b/lib/ssh/src/ssh_message.erl @@ -30,7 +30,7 @@ -include("ssh_auth.hrl"). -include("ssh_transport.hrl"). --export([encode/1, decode/1, encode_host_key/1, decode_keyboard_interactive_prompts/2]). +-export([encode/1, decode/1, decode_keyboard_interactive_prompts/2]). encode(#ssh_msg_global_request{ name = Name, @@ -227,8 +227,8 @@ encode(#ssh_msg_kexdh_reply{ f = F, h_sig = Signature }) -> - EncKey = encode_host_key(Key), - EncSign = encode_sign(Key, Signature), + EncKey = public_key:ssh_encode(Key, ssh2_pubkey), + EncSign = encode_signature(Key, Signature), ssh_bits:encode([?SSH_MSG_KEXDH_REPLY, EncKey, F, EncSign], [byte, binary, mpint, binary]); encode(#ssh_msg_kex_dh_gex_request{ @@ -237,7 +237,7 @@ encode(#ssh_msg_kex_dh_gex_request{ max = Max }) -> ssh_bits:encode([?SSH_MSG_KEX_DH_GEX_REQUEST, Min, N, Max], - [byte, uint32, uint32, uint32, uint32]); + [byte, uint32, uint32, uint32]); encode(#ssh_msg_kex_dh_gex_request_old{n = N}) -> ssh_bits:encode([?SSH_MSG_KEX_DH_GEX_REQUEST_OLD, N], [byte, uint32]); @@ -255,9 +255,17 @@ encode(#ssh_msg_kex_dh_gex_reply{ f = F, h_sig = Signature }) -> - EncKey = encode_host_key(Key), - EncSign = encode_sign(Key, Signature), - ssh_bits:encode([?SSH_MSG_KEXDH_REPLY, EncKey, F, EncSign], [byte, binary, mpint, binary]); + EncKey = public_key:ssh_encode(Key, ssh2_pubkey), + EncSign = encode_signature(Key, Signature), + ssh_bits:encode([?SSH_MSG_KEX_DH_GEX_REPLY, EncKey, F, EncSign], [byte, binary, mpint, binary]); + +encode(#ssh_msg_kex_ecdh_init{q_c = Q_c}) -> + ssh_bits:encode([?SSH_MSG_KEX_ECDH_INIT, Q_c], [byte, mpint]); + +encode(#ssh_msg_kex_ecdh_reply{public_host_key = Key, q_s = Q_s, h_sig = Sign}) -> + EncKey = public_key:ssh_encode(Key, ssh2_pubkey), + EncSign = encode_signature(Key, Sign), + ssh_bits:encode([?SSH_MSG_KEX_ECDH_REPLY, EncKey, Q_s, EncSign], [byte, binary, mpint, binary]); encode(#ssh_msg_ignore{data = Data}) -> ssh_bits:encode([?SSH_MSG_IGNORE, Data], [byte, string]); @@ -272,8 +280,7 @@ encode(#ssh_msg_debug{always_display = Bool, %% Connection Messages -decode(<<?BYTE(?SSH_MSG_GLOBAL_REQUEST), ?UINT32(Len), Name:Len/binary, - ?BYTE(Bool), Data/binary>>) -> +decode(<<?BYTE(?SSH_MSG_GLOBAL_REQUEST), ?DEC_BIN(Name,__0), ?BYTE(Bool), Data/binary>>) -> #ssh_msg_global_request{ name = Name, want_reply = erl_boolean(Bool), @@ -284,8 +291,7 @@ decode(<<?BYTE(?SSH_MSG_REQUEST_SUCCESS), Data/binary>>) -> decode(<<?BYTE(?SSH_MSG_REQUEST_FAILURE)>>) -> #ssh_msg_request_failure{}; decode(<<?BYTE(?SSH_MSG_CHANNEL_OPEN), - ?UINT32(Len), Type:Len/binary, - ?UINT32(Sender), ?UINT32(Window), ?UINT32(Max), + ?DEC_BIN(Type,__0), ?UINT32(Sender), ?UINT32(Window), ?UINT32(Max), Data/binary>>) -> #ssh_msg_channel_open{ channel_type = binary_to_list(Type), @@ -305,7 +311,7 @@ decode(<<?BYTE(?SSH_MSG_CHANNEL_OPEN_CONFIRMATION), ?UINT32(Recipient), ?UINT32( data = Data }; decode(<<?BYTE(?SSH_MSG_CHANNEL_OPEN_FAILURE), ?UINT32(Recipient), ?UINT32(Reason), - ?UINT32(Len0), Desc:Len0/binary, ?UINT32(Len1), Lang:Len1/binary >>) -> + ?DEC_BIN(Desc,__0), ?DEC_BIN(Lang,__1) >> ) -> #ssh_msg_channel_open_failure{ recipient_channel = Recipient, reason = Reason, @@ -318,13 +324,13 @@ decode(<<?BYTE(?SSH_MSG_CHANNEL_WINDOW_ADJUST), ?UINT32(Recipient), ?UINT32(Byte bytes_to_add = Bytes }; -decode(<<?BYTE(?SSH_MSG_CHANNEL_DATA), ?UINT32(Recipient), ?UINT32(Len), Data:Len/binary>>) -> +decode(<<?BYTE(?SSH_MSG_CHANNEL_DATA), ?UINT32(Recipient), ?DEC_BIN(Data,__0)>>) -> #ssh_msg_channel_data{ recipient_channel = Recipient, data = Data }; decode(<<?BYTE(?SSH_MSG_CHANNEL_EXTENDED_DATA), ?UINT32(Recipient), - ?UINT32(DataType), ?UINT32(Len), Data:Len/binary>>) -> + ?UINT32(DataType), ?DEC_BIN(Data,__0)>>) -> #ssh_msg_channel_extended_data{ recipient_channel = Recipient, data_type_code = DataType, @@ -339,8 +345,7 @@ decode(<<?BYTE(?SSH_MSG_CHANNEL_CLOSE), ?UINT32(Recipient)>>) -> recipient_channel = Recipient }; decode(<<?BYTE(?SSH_MSG_CHANNEL_REQUEST), ?UINT32(Recipient), - ?UINT32(Len), RequestType:Len/binary, - ?BYTE(Bool), Data/binary>>) -> + ?DEC_BIN(RequestType,__0), ?BYTE(Bool), Data/binary>>) -> #ssh_msg_channel_request{ recipient_channel = Recipient, request_type = unicode:characters_to_list(RequestType), @@ -358,9 +363,7 @@ decode(<<?BYTE(?SSH_MSG_CHANNEL_FAILURE), ?UINT32(Recipient)>>) -> %%% Auth Messages decode(<<?BYTE(?SSH_MSG_USERAUTH_REQUEST), - ?UINT32(Len0), User:Len0/binary, - ?UINT32(Len1), Service:Len1/binary, - ?UINT32(Len2), Method:Len2/binary, + ?DEC_BIN(User,__0), ?DEC_BIN(Service,__1), ?DEC_BIN(Method,__2), Data/binary>>) -> #ssh_msg_userauth_request{ user = unicode:characters_to_list(User), @@ -370,7 +373,7 @@ decode(<<?BYTE(?SSH_MSG_USERAUTH_REQUEST), }; decode(<<?BYTE(?SSH_MSG_USERAUTH_FAILURE), - ?UINT32(Len0), Auths:Len0/binary, + ?DEC_BIN(Auths,__0), ?BYTE(Bool)>>) -> #ssh_msg_userauth_failure { authentications = unicode:characters_to_list(Auths), @@ -380,16 +383,14 @@ decode(<<?BYTE(?SSH_MSG_USERAUTH_FAILURE), decode(<<?BYTE(?SSH_MSG_USERAUTH_SUCCESS)>>) -> #ssh_msg_userauth_success{}; -decode(<<?BYTE(?SSH_MSG_USERAUTH_BANNER), - ?UINT32(Len0), Banner:Len0/binary, - ?UINT32(Len1), Lang:Len1/binary>>) -> +decode(<<?BYTE(?SSH_MSG_USERAUTH_BANNER), ?DEC_BIN(Banner,__0), ?DEC_BIN(Lang,__1) >>) -> #ssh_msg_userauth_banner{ message = Banner, language = Lang }; -decode(<<?BYTE(?SSH_MSG_USERAUTH_INFO_REQUEST), ?UINT32(Len0), Name:Len0/binary, - ?UINT32(Len1), Inst:Len1/binary, ?UINT32(Len2), Lang:Len2/binary, +decode(<<?BYTE(?SSH_MSG_USERAUTH_INFO_REQUEST), + ?DEC_BIN(Name,__0), ?DEC_BIN(Inst,__1), ?DEC_BIN(Lang,__2), ?UINT32(NumPromtps), Data/binary>>) -> #ssh_msg_userauth_info_request{ name = Name, @@ -399,15 +400,14 @@ decode(<<?BYTE(?SSH_MSG_USERAUTH_INFO_REQUEST), ?UINT32(Len0), Name:Len0/binary, data = Data}; %%% Unhandled message, also masked by same 1:st byte value as ?SSH_MSG_USERAUTH_INFO_REQUEST: -decode(<<?BYTE(?SSH_MSG_USERAUTH_PASSWD_CHANGEREQ), ?UINT32(Len0), Prompt:Len0/binary, - ?UINT32(Len1), Lang:Len1/binary>>) -> +decode(<<?BYTE(?SSH_MSG_USERAUTH_PASSWD_CHANGEREQ), ?DEC_BIN(Prompt,__0), ?DEC_BIN(Lang,__1) >>) -> #ssh_msg_userauth_passwd_changereq{ prompt = Prompt, languge = Lang }; %%% Unhandled message, also masked by same 1:st byte value as ?SSH_MSG_USERAUTH_INFO_REQUEST: -decode(<<?BYTE(?SSH_MSG_USERAUTH_PK_OK), ?UINT32(Len), Alg:Len/binary, KeyBlob/binary>>) -> +decode(<<?BYTE(?SSH_MSG_USERAUTH_PK_OK), ?DEC_BIN(Alg,__0), KeyBlob/binary>>) -> #ssh_msg_userauth_pk_ok{ algorithm_name = Alg, key_blob = KeyBlob @@ -422,47 +422,71 @@ decode(<<?BYTE(?SSH_MSG_USERAUTH_INFO_RESPONSE), ?UINT32(Num), Data/binary>>) -> decode(<<?BYTE(?SSH_MSG_KEXINIT), Cookie:128, Data/binary>>) -> decode_kex_init(Data, [Cookie, ssh_msg_kexinit], 10); -decode(<<?BYTE(?SSH_MSG_KEXDH_INIT), ?UINT32(Len), E:Len/big-signed-integer-unit:8>>) -> +decode(<<"dh",?BYTE(?SSH_MSG_KEXDH_INIT), ?DEC_MPINT(E,__0)>>) -> #ssh_msg_kexdh_init{e = E }; + +decode(<<"dh", ?BYTE(?SSH_MSG_KEXDH_REPLY), ?DEC_BIN(Key,__0), ?DEC_MPINT(F,__1), ?DEC_BIN(Hashsign,__2)>>) -> + #ssh_msg_kexdh_reply{ + public_host_key = public_key:ssh_decode(Key, ssh2_pubkey), + f = F, + h_sig = decode_signature(Hashsign) + }; + decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_REQUEST), ?UINT32(Min), ?UINT32(N), ?UINT32(Max)>>) -> #ssh_msg_kex_dh_gex_request{ min = Min, n = N, max = Max }; -decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_REQUEST_OLD), ?UINT32(N)>>) -> + +decode(<<"dh_gex",?BYTE(?SSH_MSG_KEX_DH_GEX_REQUEST_OLD), ?UINT32(N)>>) -> #ssh_msg_kex_dh_gex_request_old{ n = N }; -decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_GROUP), - ?UINT32(Len0), Prime:Len0/big-signed-integer-unit:8, - ?UINT32(Len1), Generator:Len1/big-signed-integer-unit:8>>) -> + +decode(<<"dh_gex",?BYTE(?SSH_MSG_KEX_DH_GEX_GROUP), ?DEC_MPINT(Prime,__0), ?DEC_MPINT(Generator,__1) >>) -> #ssh_msg_kex_dh_gex_group{ p = Prime, g = Generator }; -decode(<<?BYTE(?SSH_MSG_KEXDH_REPLY), ?UINT32(Len0), Key:Len0/binary, - ?UINT32(Len1), F:Len1/big-signed-integer-unit:8, - ?UINT32(Len2), Hashsign:Len2/binary>>) -> - #ssh_msg_kexdh_reply{ - public_host_key = decode_host_key(Key), + +decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_INIT), ?DEC_MPINT(E,__0)>>) -> + #ssh_msg_kex_dh_gex_init{ + e = E + }; + +decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_REPLY), ?DEC_BIN(Key,__0), ?DEC_MPINT(F,__1), ?DEC_BIN(Hashsign,__2)>>) -> + #ssh_msg_kex_dh_gex_reply{ + public_host_key = public_key:ssh_decode(Key, ssh2_pubkey), f = F, - h_sig = decode_sign(Hashsign) + h_sig = decode_signature(Hashsign) + }; + +decode(<<"ecdh",?BYTE(?SSH_MSG_KEX_ECDH_INIT), ?DEC_MPINT(Q_c,__0)>>) -> + #ssh_msg_kex_ecdh_init{ + q_c = Q_c }; -decode(<<?SSH_MSG_SERVICE_REQUEST, ?UINT32(Len0), Service:Len0/binary>>) -> +decode(<<"ecdh",?BYTE(?SSH_MSG_KEX_ECDH_REPLY), + ?DEC_BIN(Key,__1), ?DEC_MPINT(Q_s,__2), ?DEC_BIN(Sig,__3)>>) -> + #ssh_msg_kex_ecdh_reply{ + public_host_key = public_key:ssh_decode(Key, ssh2_pubkey), + q_s = Q_s, + h_sig = decode_signature(Sig) + }; + +decode(<<?SSH_MSG_SERVICE_REQUEST, ?DEC_BIN(Service,__0)>>) -> #ssh_msg_service_request{ name = unicode:characters_to_list(Service) }; -decode(<<?SSH_MSG_SERVICE_ACCEPT, ?UINT32(Len0), Service:Len0/binary>>) -> +decode(<<?SSH_MSG_SERVICE_ACCEPT, ?DEC_BIN(Service,__0)>>) -> #ssh_msg_service_accept{ name = unicode:characters_to_list(Service) }; -decode(<<?BYTE(?SSH_MSG_DISCONNECT), ?UINT32(Code), - ?UINT32(Len0), Desc:Len0/binary, ?UINT32(Len1), Lang:Len1/binary>>) -> +decode(<<?BYTE(?SSH_MSG_DISCONNECT), ?UINT32(Code), ?DEC_BIN(Desc,__0), ?DEC_BIN(Lang,__1)>>) -> #ssh_msg_disconnect{ code = Code, description = unicode:characters_to_list(Desc), @@ -470,8 +494,7 @@ decode(<<?BYTE(?SSH_MSG_DISCONNECT), ?UINT32(Code), }; %% Accept bad disconnects from ancient openssh clients that doesn't send language tag. Use english as a work-around. -decode(<<?BYTE(?SSH_MSG_DISCONNECT), ?UINT32(Code), - ?UINT32(Len0), Desc:Len0/binary>>) -> +decode(<<?BYTE(?SSH_MSG_DISCONNECT), ?UINT32(Code), ?DEC_BIN(Desc,__0)>>) -> #ssh_msg_disconnect{ code = Code, description = unicode:characters_to_list(Desc), @@ -481,21 +504,25 @@ decode(<<?BYTE(?SSH_MSG_DISCONNECT), ?UINT32(Code), decode(<<?SSH_MSG_NEWKEYS>>) -> #ssh_msg_newkeys{}; -decode(<<?BYTE(?SSH_MSG_IGNORE), ?UINT32(Len), Data:Len/binary>>) -> +decode(<<?BYTE(?SSH_MSG_IGNORE), ?DEC_BIN(Data,__0)>>) -> #ssh_msg_ignore{data = Data}; decode(<<?BYTE(?SSH_MSG_UNIMPLEMENTED), ?UINT32(Seq)>>) -> #ssh_msg_unimplemented{sequence = Seq}; -decode(<<?BYTE(?SSH_MSG_DEBUG), ?BYTE(Bool), ?UINT32(Len0), Msg:Len0/binary, - ?UINT32(Len1), Lang:Len1/binary>>) -> +decode(<<?BYTE(?SSH_MSG_DEBUG), ?BYTE(Bool), ?DEC_BIN(Msg,__0), ?DEC_BIN(Lang,__1)>>) -> #ssh_msg_debug{always_display = erl_boolean(Bool), message = Msg, language = Lang}. +%%%================================================================ +%%% +%%% Helper functions +%%% + decode_keyboard_interactive_prompts(<<>>, Acc) -> lists:reverse(Acc); -decode_keyboard_interactive_prompts(<<?UINT32(Len), Prompt:Len/binary, ?BYTE(Bool), Bin/binary>>, +decode_keyboard_interactive_prompts(<<?DEC_BIN(Prompt,__0), ?BYTE(Bool), Bin/binary>>, Acc) -> decode_keyboard_interactive_prompts(Bin, [{Prompt, erl_boolean(Bool)} | Acc]). @@ -511,43 +538,25 @@ decode_kex_init(<<?BYTE(Bool)>>, Acc, 0) -> %% See rfc 4253 7.1 X = 0, list_to_tuple(lists:reverse([X, erl_boolean(Bool) | Acc])); -decode_kex_init(<<?UINT32(Len), Data:Len/binary, Rest/binary>>, Acc, N) -> +decode_kex_init(<<?DEC_BIN(Data,__0), Rest/binary>>, Acc, N) -> Names = string:tokens(unicode:characters_to_list(Data), ","), decode_kex_init(Rest, [Names | Acc], N -1). +%%%================================================================ +%%% +%%% Signature decode/encode +%%% -decode_sign(<<?UINT32(Len), _Alg:Len/binary, ?UINT32(_), Signature/binary>>) -> +decode_signature(<<?DEC_BIN(_Alg,__0), ?UINT32(_), Signature/binary>>) -> Signature. -decode_host_key(<<?UINT32(Len), Alg:Len/binary, Rest/binary>>) -> - decode_host_key(Alg, Rest). - -decode_host_key(<<"ssh-rsa">>, <<?UINT32(Len0), E:Len0/big-signed-integer-unit:8, - ?UINT32(Len1), N:Len1/big-signed-integer-unit:8>>) -> - #'RSAPublicKey'{publicExponent = E, - modulus = N}; - -decode_host_key(<<"ssh-dss">>, - <<?UINT32(Len0), P:Len0/big-signed-integer-unit:8, - ?UINT32(Len1), Q:Len1/big-signed-integer-unit:8, - ?UINT32(Len2), G:Len2/big-signed-integer-unit:8, - ?UINT32(Len3), Y:Len3/big-signed-integer-unit:8>>) -> - {Y, #'Dss-Parms'{p = P, - q = Q, - g = G}}. - -encode_host_key(#'RSAPublicKey'{modulus = N, publicExponent = E}) -> - ssh_bits:encode(["ssh-rsa", E, N], [string, mpint, mpint]); -encode_host_key({Y, #'Dss-Parms'{p = P, q = Q, g = G}}) -> - ssh_bits:encode(["ssh-dss", P, Q, G, Y], - [string, mpint, mpint, mpint, mpint]); -encode_host_key(#'RSAPrivateKey'{modulus = N, publicExponent = E}) -> - ssh_bits:encode(["ssh-rsa", E, N], [string, mpint, mpint]); -encode_host_key(#'DSAPrivateKey'{y = Y, p = P, q = Q, g = G}) -> - ssh_bits:encode(["ssh-dss", P, Q, G, Y], - [string, mpint, mpint, mpint, mpint]). -encode_sign(#'RSAPrivateKey'{}, Signature) -> + +encode_signature(#'RSAPublicKey'{}, Signature) -> ssh_bits:encode(["ssh-rsa", Signature],[string, binary]); -encode_sign(#'DSAPrivateKey'{}, Signature) -> - ssh_bits:encode(["ssh-dss", Signature],[string, binary]). +encode_signature({_, #'Dss-Parms'{}}, Signature) -> + ssh_bits:encode(["ssh-dss", Signature],[string, binary]); +encode_signature({#'ECPoint'{}, {namedCurve,OID}}, Signature) -> + CurveName = public_key:oid2ssh_curvename(OID), + ssh_bits:encode([<<"ecdsa-sha2-",CurveName/binary>>, Signature], [binary,binary]). + diff --git a/lib/ssh/src/ssh_sftp.erl b/lib/ssh/src/ssh_sftp.erl index 9fe2d56759..dbacf730cc 100644 --- a/lib/ssh/src/ssh_sftp.erl +++ b/lib/ssh/src/ssh_sftp.erl @@ -439,7 +439,7 @@ write_file(Pid, Name, List) -> write_file(Pid, Name, List, ?FILEOP_TIMEOUT). write_file(Pid, Name, List, FileOpTimeout) when is_list(List) -> - write_file(Pid, Name, unicode:characters_to_binary(List), FileOpTimeout); + write_file(Pid, Name, list_to_binary(List), FileOpTimeout); write_file(Pid, Name, Bin, FileOpTimeout) -> case open(Pid, Name, [write, binary], FileOpTimeout) of {ok, Handle} -> @@ -611,8 +611,7 @@ do_handle_call({pread,Async,Handle,At,Length}, From, State) -> fun({ok,Data}, State2) -> case get_mode(Handle, State2) of binary -> {{ok,Data}, State2}; - text -> - {{ok,unicode:characters_to_list(Data)}, State2} + text -> {{ok,binary_to_list(Data)}, State2} end; (Rep, State2) -> {Rep, State2} diff --git a/lib/ssh/src/ssh_sftpd.erl b/lib/ssh/src/ssh_sftpd.erl index a6549f1c73..819cba697e 100644 --- a/lib/ssh/src/ssh_sftpd.erl +++ b/lib/ssh/src/ssh_sftpd.erl @@ -30,6 +30,7 @@ -include("ssh.hrl"). -include("ssh_xfer.hrl"). +-include("ssh_connect.hrl"). %% For ?DEFAULT_PACKET_SIZE and ?DEFAULT_WINDOW_SIZE %%-------------------------------------------------------------------- %% External exports @@ -47,6 +48,7 @@ file_handler, % atom() - callback module file_state, % state for the file callback module max_files, % integer >= 0 max no files sent during READDIR + options, % from the subsystem declaration handles % list of open handles %% handle is either {<int>, directory, {Path, unread|eof}} or %% {<int>, file, {Path, IoDevice}} @@ -121,6 +123,7 @@ init(Options) -> MaxLength = proplists:get_value(max_files, Options, 0), Vsn = proplists:get_value(sftpd_vsn, Options, 5), {ok, State#state{cwd = CWD, root = Root, max_files = MaxLength, + options = Options, handles = [], pending = <<>>, xf = #ssh_xfer{vsn = Vsn, ext = []}}}. @@ -164,7 +167,9 @@ handle_ssh_msg({ssh_cm, _, {exit_status, ChannelId, Status}}, State) -> %% Description: Handles other messages %%-------------------------------------------------------------------- handle_msg({ssh_channel_up, ChannelId, ConnectionManager}, - #state{xf =Xf} = State) -> + #state{xf = Xf, + options = Options} = State) -> + maybe_increase_recv_window(ConnectionManager, ChannelId, Options), {ok, State#state{xf = Xf#ssh_xfer{cm = ConnectionManager, channel = ChannelId}}}. @@ -934,3 +939,18 @@ rename(Path, Path2, ReqId, State0) -> {Status, FS1} = FileMod:rename(Path, Path2, FS0), State1 = State0#state{file_state = FS1}, send_status(Status, ReqId, State1). + + +maybe_increase_recv_window(ConnectionManager, ChannelId, Options) -> + WantedRecvWindowSize = + proplists:get_value(recv_window_size, Options, 1000000), + NumPkts = WantedRecvWindowSize div ?DEFAULT_PACKET_SIZE, + Increment = NumPkts*?DEFAULT_PACKET_SIZE - ?DEFAULT_WINDOW_SIZE, + + if + Increment > 0 -> + ssh_connection:adjust_window(ConnectionManager, ChannelId, + Increment); + Increment =< 0 -> + do_nothing + end. diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl index f4e6a23a1e..18037b8461 100644 --- a/lib/ssh/src/ssh_transport.erl +++ b/lib/ssh/src/ssh_transport.erl @@ -31,20 +31,27 @@ -include("ssh.hrl"). -export([versions/2, hello_version_msg/1]). --export([next_seqnum/1, decrypt_first_block/2, decrypt_blocks/3, +-export([next_seqnum/1, supported_algorithms/0, supported_algorithms/1, default_algorithms/0, default_algorithms/1, - is_valid_mac/3, + handle_packet_part/4, handle_hello_version/1, key_exchange_init_msg/1, key_init/3, new_keys_message/1, handle_kexinit_msg/3, handle_kexdh_init/2, - handle_kex_dh_gex_group/2, handle_kex_dh_gex_reply/2, + handle_kex_dh_gex_group/2, handle_kex_dh_gex_init/2, handle_kex_dh_gex_reply/2, handle_new_keys/2, handle_kex_dh_gex_request/2, handle_kexdh_reply/2, - unpack/3, decompress/2, ssh_packet/2, pack/2, msg_data/1, + handle_kex_ecdh_init/2, + handle_kex_ecdh_reply/2, + extract_public_key/1, + ssh_packet/2, pack/2, sign/3, verify/4]). +%%% For test suites +-export([pack/3]). +-export([decompress/2, decrypt_blocks/3, is_valid_mac/3 ]). % FIXME: remove + %%%---------------------------------------------------------------------------- %%% %%% There is a difference between supported and default algorithms. The @@ -53,7 +60,7 @@ %%% user. %%% %%% A supported algorithm can be requested in the option 'preferred_algorithms', -%%% but may give unexpected results because of being promoted to default. +%%% but may give unexpected results before being promoted to default. %%% %%% This makes it possible to add experimental algorithms (in supported_algorithms) %%% and test them without letting the default users know about them. @@ -63,48 +70,68 @@ default_algorithms() -> [{K,default_algorithms(K)} || K <- algo_classes()]. algo_classes() -> [kex, public_key, cipher, mac, compression]. -default_algorithms(compression) -> - %% Do not announce '[email protected]' because there seem to be problems - supported_algorithms(compression, same(['[email protected]'])); + +default_algorithms(cipher) -> + supported_algorithms(cipher, same(['AEAD_AES_128_GCM', + 'AEAD_AES_256_GCM'])); +default_algorithms(mac) -> + supported_algorithms(mac, same(['AEAD_AES_128_GCM', + 'AEAD_AES_256_GCM'])); default_algorithms(Alg) -> - supported_algorithms(Alg). + supported_algorithms(Alg, []). supported_algorithms() -> [{K,supported_algorithms(K)} || K <- algo_classes()]. supported_algorithms(kex) -> - ['diffie-hellman-group1-sha1']; + select_crypto_supported( + [ + {'ecdh-sha2-nistp256', [{public_keys,ecdh}, {ec_curve,secp256r1}, {hashs,sha256}]}, + {'ecdh-sha2-nistp384', [{public_keys,ecdh}, {ec_curve,secp384r1}, {hashs,sha384}]}, + {'diffie-hellman-group14-sha1', [{public_keys,dh}, {hashs,sha}]}, + {'diffie-hellman-group-exchange-sha256', [{public_keys,dh}, {hashs,sha256}]}, + {'diffie-hellman-group-exchange-sha1', [{public_keys,dh}, {hashs,sha}]}, + {'ecdh-sha2-nistp521', [{public_keys,ecdh}, {ec_curve,secp521r1}, {hashs,sha512}]}, + {'diffie-hellman-group1-sha1', [{public_keys,dh}, {hashs,sha}]} + ]); supported_algorithms(public_key) -> - ssh_auth:default_public_key_algorithms(); + select_crypto_supported( + [{'ecdsa-sha2-nistp256', [{public_keys,ecdsa}, {hashs,sha256}, {ec_curve,secp256r1}]}, + {'ecdsa-sha2-nistp384', [{public_keys,ecdsa}, {hashs,sha384}, {ec_curve,secp384r1}]}, + {'ecdsa-sha2-nistp521', [{public_keys,ecdsa}, {hashs,sha512}, {ec_curve,secp521r1}]}, + {'ssh-rsa', [{public_keys,rsa}, {hashs,sha} ]}, + {'ssh-dss', [{public_keys,dss}, {hashs,sha} ]} + ]); + supported_algorithms(cipher) -> - Supports = crypto:supports(), - CipherAlgos = [{aes_ctr, 'aes128-ctr'}, {aes_cbc128, 'aes128-cbc'}, {des3_cbc, '3des-cbc'}], - Algs = [SshAlgo || - {CryptoAlgo, SshAlgo} <- CipherAlgos, - lists:member(CryptoAlgo, proplists:get_value(ciphers, Supports, []))], - same(Algs); + same( + select_crypto_supported( + [{'aes256-ctr', [{ciphers,{aes_ctr,256}}]}, + {'aes192-ctr', [{ciphers,{aes_ctr,192}}]}, + {'aes128-ctr', [{ciphers,{aes_ctr,128}}]}, + {'aes128-cbc', [{ciphers,aes_cbc128}]}, + {'[email protected]', [{ciphers,{aes_gcm,128}}]}, + {'[email protected]', [{ciphers,{aes_gcm,256}}]}, + {'AEAD_AES_128_GCM', [{ciphers,{aes_gcm,128}}]}, + {'AEAD_AES_256_GCM', [{ciphers,{aes_gcm,256}}]}, + {'3des-cbc', [{ciphers,des3_cbc}]} + ] + )); supported_algorithms(mac) -> - Supports = crypto:supports(), - HashAlgos = [{sha256, 'hmac-sha2-256'}, {sha, 'hmac-sha1'}], - Algs = [SshAlgo || - {CryptoAlgo, SshAlgo} <- HashAlgos, - lists:member(CryptoAlgo, proplists:get_value(hashs, Supports, []))], - same(Algs); + same( + select_crypto_supported( + [{'hmac-sha2-256', [{hashs,sha256}]}, + {'hmac-sha2-512', [{hashs,sha512}]}, + {'hmac-sha1', [{hashs,sha}]}, + {'AEAD_AES_128_GCM', [{ciphers,{aes_gcm,128}}]}, + {'AEAD_AES_256_GCM', [{ciphers,{aes_gcm,256}}]} + ] + )); supported_algorithms(compression) -> - same(['none','zlib','[email protected]']). - - -supported_algorithms(Key, [{client2server,BL1},{server2client,BL2}]) -> - [{client2server,As1},{server2client,As2}] = supported_algorithms(Key), - [{client2server,As1--BL1},{server2client,As2--BL2}]; -supported_algorithms(Key, BlackList) -> - supported_algorithms(Key) -- BlackList. - - - - -same(Algs) -> [{client2server,Algs}, {server2client,Algs}]. - + same(['none', + '[email protected]', + 'zlib' + ]). %%%---------------------------------------------------------------------------- versions(client, Options)-> @@ -135,7 +162,7 @@ ssh_vsn() -> _:_ -> "" end. -random_id(Nlo, Nup) -> +random_id(Nlo, Nup) -> [crypto:rand_uniform($a,$z+1) || _<- lists:duplicate(crypto:rand_uniform(Nlo,Nup+1),x) ]. hello_version_msg(Data) -> @@ -144,12 +171,6 @@ hello_version_msg(Data) -> next_seqnum(SeqNum) -> (SeqNum + 1) band 16#ffffffff. -decrypt_first_block(Bin, #ssh{decrypt_block_size = BlockSize} = Ssh0) -> - <<EncBlock:BlockSize/binary, EncData/binary>> = Bin, - {Ssh, <<?UINT32(PacketLen), _/binary>> = DecData} = - decrypt(Ssh0, EncBlock), - {Ssh, PacketLen, DecData, EncData}. - decrypt_blocks(Bin, Length, Ssh0) -> <<EncBlocks:Length/binary, EncData/binary>> = Bin, {Ssh, DecData} = decrypt(Ssh0, EncBlocks), @@ -246,154 +267,411 @@ handle_kexinit_msg(#ssh_msg_kexinit{} = CounterPart, #ssh_msg_kexinit{} = Own, Ssh0#ssh{algorithms = Algoritms}); _ -> %% TODO: Correct code? - throw(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR, + throw(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED, description = "Selection of key exchange" " algorithm failed", - language = "en"}) + language = ""}) end; handle_kexinit_msg(#ssh_msg_kexinit{} = CounterPart, #ssh_msg_kexinit{} = Own, #ssh{role = server} = Ssh) -> {ok, Algoritms} = select_algorithm(server, CounterPart, Own), - {ok, Ssh#ssh{algorithms = Algoritms}}. + case verify_algorithm(Algoritms) of + true -> + {ok, Ssh#ssh{algorithms = Algoritms}}; + _ -> + throw(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED, + description = "Selection of key exchange" + " algorithm failed", + language = ""}) + end. %% TODO: diffie-hellman-group14-sha1 should also be supported. %% Maybe check more things ... -verify_algorithm(#alg{kex = 'diffie-hellman-group1-sha1'}) -> - true; -verify_algorithm(#alg{kex = 'diffie-hellman-group-exchange-sha1'}) -> - true; -verify_algorithm(_) -> - false. -key_exchange_first_msg('diffie-hellman-group1-sha1', Ssh0) -> - {G, P} = dh_group1(), - {Private, Public} = dh_gen_key(G, P, 1024), +verify_algorithm(#alg{kex = undefined}) -> false; +verify_algorithm(#alg{hkey = undefined}) -> false; +verify_algorithm(#alg{send_mac = undefined}) -> false; +verify_algorithm(#alg{recv_mac = undefined}) -> false; +verify_algorithm(#alg{encrypt = undefined}) -> false; +verify_algorithm(#alg{decrypt = undefined}) -> false; +verify_algorithm(#alg{compress = undefined}) -> false; +verify_algorithm(#alg{decompress = undefined}) -> false; +verify_algorithm(#alg{kex = Kex}) -> lists:member(Kex, supported_algorithms(kex)). + +%%%---------------------------------------------------------------- +%%% +%%% Key exchange initialization +%%% +key_exchange_first_msg(Kex, Ssh0) when Kex == 'diffie-hellman-group1-sha1' ; + Kex == 'diffie-hellman-group14-sha1' -> + {G, P} = dh_group(Kex), + {Public, Private} = generate_key(dh, [P,G]), {SshPacket, Ssh1} = ssh_packet(#ssh_msg_kexdh_init{e = Public}, Ssh0), {ok, SshPacket, Ssh1#ssh{keyex_key = {{Private, Public}, {G, P}}}}; -key_exchange_first_msg('diffie-hellman-group-exchange-sha1', Ssh0) -> - Min = ?DEFAULT_DH_GROUP_MIN, - NBits = ?DEFAULT_DH_GROUP_NBITS, - Max = ?DEFAULT_DH_GROUP_MAX, +key_exchange_first_msg(Kex, Ssh0=#ssh{opts=Opts}) when Kex == 'diffie-hellman-group-exchange-sha1' ; + Kex == 'diffie-hellman-group-exchange-sha256' -> + {Min,NBits,Max} = + proplists:get_value(dh_gex_limits, Opts, {?DEFAULT_DH_GROUP_MIN, + ?DEFAULT_DH_GROUP_NBITS, + ?DEFAULT_DH_GROUP_MAX}), {SshPacket, Ssh1} = ssh_packet(#ssh_msg_kex_dh_gex_request{min = Min, - n = NBits, max = Max}, + n = NBits, + max = Max}, Ssh0), {ok, SshPacket, - Ssh1#ssh{keyex_info = {Min, Max, NBits}}}. - + Ssh1#ssh{keyex_info = {Min, Max, NBits}}}; + +key_exchange_first_msg(Kex, Ssh0) when Kex == 'ecdh-sha2-nistp256' ; + Kex == 'ecdh-sha2-nistp384' ; + Kex == 'ecdh-sha2-nistp521' -> + Curve = ecdh_curve(Kex), + {Public, Private} = generate_key(ecdh, Curve), + {SshPacket, Ssh1} = ssh_packet(#ssh_msg_kex_ecdh_init{q_c=Public}, Ssh0), + {ok, SshPacket, + Ssh1#ssh{keyex_key = {{Public,Private},Curve}}}. -handle_kexdh_init(#ssh_msg_kexdh_init{e = E}, Ssh0) -> - {G, P} = dh_group1(), +%%%---------------------------------------------------------------- +%%% +%%% diffie-hellman-group1-sha1 +%%% diffie-hellman-group14-sha1 +%%% +handle_kexdh_init(#ssh_msg_kexdh_init{e = E}, + Ssh0 = #ssh{algorithms = #alg{kex=Kex}}) -> + %% server + {G, P} = dh_group(Kex), if 1=<E, E=<(P-1) -> - {Private, Public} = dh_gen_key(G, P, 1024), - K = ssh_math:ipow(E, Private, P), - Key = get_host_key(Ssh0), - H = kex_h(Ssh0, Key, E, Public, K), - H_SIG = sign_host_key(Ssh0, Key, H), - {SshPacket, Ssh1} = ssh_packet(#ssh_msg_kexdh_reply{public_host_key = Key, - f = Public, - h_sig = H_SIG - }, Ssh0), - + {Public, Private} = generate_key(dh, [P,G]), + K = compute_key(dh, E, Private, [P,G]), + MyPrivHostKey = get_host_key(Ssh0), + MyPubHostKey = extract_public_key(MyPrivHostKey), + H = kex_h(Ssh0, MyPubHostKey, E, Public, K), + H_SIG = sign_host_key(Ssh0, MyPrivHostKey, H), + {SshPacket, Ssh1} = + ssh_packet(#ssh_msg_kexdh_reply{public_host_key = MyPubHostKey, + f = Public, + h_sig = H_SIG + }, Ssh0), {ok, SshPacket, Ssh1#ssh{keyex_key = {{Private, Public}, {G, P}}, shared_secret = K, exchanged_hash = H, session_id = sid(Ssh1, H)}}; + true -> - Error = {error,bad_e_from_peer}, - Disconnect = #ssh_msg_disconnect{ - code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED, - description = "Key exchange failed, 'f' out of bounds", - language = "en"}, - throw({Error, Disconnect}) + throw({{error,bad_e_from_peer}, + #ssh_msg_disconnect{ + code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED, + description = "Key exchange failed, 'e' out of bounds", + language = ""} + }) end. +handle_kexdh_reply(#ssh_msg_kexdh_reply{public_host_key = PeerPubHostKey, + f = F, + h_sig = H_SIG}, + #ssh{keyex_key = {{Private, Public}, {G, P}}} = Ssh0) -> + %% client + if + 1=<F, F=<(P-1)-> + K = compute_key(dh, F, Private, [P,G]), + H = kex_h(Ssh0, PeerPubHostKey, Public, F, K), + + case verify_host_key(Ssh0, PeerPubHostKey, H, H_SIG) of + ok -> + {SshPacket, Ssh} = ssh_packet(#ssh_msg_newkeys{}, Ssh0), + {ok, SshPacket, Ssh#ssh{shared_secret = K, + exchanged_hash = H, + session_id = sid(Ssh, H)}}; + Error -> + throw({Error, + #ssh_msg_disconnect{ + code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED, + description = "Key exchange failed", + language = "en"} + }) + end; + + true -> + throw({{error,bad_f_from_peer}, + #ssh_msg_disconnect{ + code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED, + description = "Key exchange failed, 'f' out of bounds", + language = ""} + }) + end. + + +%%%---------------------------------------------------------------- +%%% +%%% diffie-hellman-group-exchange-sha1 +%%% +handle_kex_dh_gex_request(#ssh_msg_kex_dh_gex_request{min = Min0, + n = NBits, + max = Max0}, + Ssh0=#ssh{opts=Opts}) when Min0=<NBits, NBits=<Max0 -> + %% server + {Min, Max} = adjust_gex_min_max(Min0, Max0, Opts), + case public_key:dh_gex_group(Min, NBits, Max, + proplists:get_value(dh_gex_groups,Opts)) of + {ok, {_Sz, {G,P}}} -> + {Public, Private} = generate_key(dh, [P,G]), + {SshPacket, Ssh} = + ssh_packet(#ssh_msg_kex_dh_gex_group{p = P, g = G}, Ssh0), + {ok, SshPacket, + Ssh#ssh{keyex_key = {{Private, Public}, {G, P}}, + keyex_info = {Min, Max, NBits} + }}; + {error,_} -> + throw(#ssh_msg_disconnect{ + code = ?SSH_DISCONNECT_PROTOCOL_ERROR, + description = "No possible diffie-hellman-group-exchange group found", + language = ""}) + end; + +handle_kex_dh_gex_request(#ssh_msg_kex_dh_gex_request_old{n = NBits}, + Ssh0=#ssh{opts=Opts}) -> + %% server + %% + %% This message was in the draft-00 of rfc4419 + %% (https://tools.ietf.org/html/draft-ietf-secsh-dh-group-exchange-00) + %% In later drafts and the rfc is "is used for backward compatibility". + %% Unfortunatly the rfc does not specify how to treat the parameter n + %% if there is no group of that modulus length :( + %% The draft-00 however specifies that n is the "... number of bits + %% the subgroup should have at least". + %% Further, it says that "Servers and clients SHOULD support groups + %% with a modulus length of k bits, where 1024 <= k <= 8192." + %% + Min0 = NBits, + Max0 = 8192, + {Min, Max} = adjust_gex_min_max(Min0, Max0, Opts), + case public_key:dh_gex_group(Min, NBits, Max, + proplists:get_value(dh_gex_groups,Opts)) of + {ok, {_Sz, {G,P}}} -> + {Public, Private} = generate_key(dh, [P,G]), + {SshPacket, Ssh} = + ssh_packet(#ssh_msg_kex_dh_gex_group{p = P, g = G}, Ssh0), + {ok, SshPacket, + Ssh#ssh{keyex_key = {{Private, Public}, {G, P}}, + keyex_info = {-1, -1, NBits} % flag for kex_h hash calc + }}; + {error,_} -> + throw(#ssh_msg_disconnect{ + code = ?SSH_DISCONNECT_PROTOCOL_ERROR, + description = "No possible diffie-hellman-group-exchange group found", + language = ""}) + end; + +handle_kex_dh_gex_request(_, _) -> + throw({{error,bad_ssh_msg_kex_dh_gex_request}, + #ssh_msg_disconnect{ + code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED, + description = "Key exchange failed, bad values in ssh_msg_kex_dh_gex_request", + language = ""} + }). + + +adjust_gex_min_max(Min0, Max0, Opts) -> + case proplists:get_value(dh_gex_limits, Opts) of + undefined -> + {Min0, Max0}; + {Min1, Max1} -> + Min2 = max(Min0, Min1), + Max2 = min(Max0, Max1), + if + Min2 =< Max2 -> + {Min2, Max2}; + Max2 < Min2 -> + throw(#ssh_msg_disconnect{ + code = ?SSH_DISCONNECT_PROTOCOL_ERROR, + description = "No possible diffie-hellman-group-exchange group possible", + language = ""}) + end + end. + + handle_kex_dh_gex_group(#ssh_msg_kex_dh_gex_group{p = P, g = G}, Ssh0) -> - {Private, Public} = dh_gen_key(G,P,1024), + %% client + {Public, Private} = generate_key(dh, [P,G]), {SshPacket, Ssh1} = - ssh_packet(#ssh_msg_kex_dh_gex_init{e = Public}, Ssh0), + ssh_packet(#ssh_msg_kex_dh_gex_init{e = Public}, Ssh0), % Pub = G^Priv mod P (def) + {ok, SshPacket, Ssh1#ssh{keyex_key = {{Private, Public}, {G, P}}}}. +handle_kex_dh_gex_init(#ssh_msg_kex_dh_gex_init{e = E}, + #ssh{keyex_key = {{Private, Public}, {G, P}}, + keyex_info = {Min, Max, NBits}} = + Ssh0) -> + %% server + if + 1=<E, E=<(P-1) -> + K = compute_key(dh, E, Private, [P,G]), + if + 1<K, K<(P-1) -> + MyPrivHostKey = get_host_key(Ssh0), + MyPubHostKey = extract_public_key(MyPrivHostKey), + H = kex_h(Ssh0, MyPubHostKey, Min, NBits, Max, P, G, E, Public, K), + H_SIG = sign_host_key(Ssh0, MyPrivHostKey, H), + {SshPacket, Ssh} = + ssh_packet(#ssh_msg_kex_dh_gex_reply{public_host_key = MyPubHostKey, + f = Public, + h_sig = H_SIG}, Ssh0), + {ok, SshPacket, Ssh#ssh{shared_secret = K, + exchanged_hash = H, + session_id = sid(Ssh, H) + }}; + true -> + throw({{error,bad_K}, + #ssh_msg_disconnect{ + code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED, + description = "Key exchange failed, 'K' out of bounds", + language = ""} + }) + end; + true -> + throw({{error,bad_e_from_peer}, + #ssh_msg_disconnect{ + code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED, + description = "Key exchange failed, 'e' out of bounds", + language = ""} + }) + end. + +handle_kex_dh_gex_reply(#ssh_msg_kex_dh_gex_reply{public_host_key = PeerPubHostKey, + f = F, + h_sig = H_SIG}, + #ssh{keyex_key = {{Private, Public}, {G, P}}, + keyex_info = {Min, Max, NBits}} = + Ssh0) -> + %% client + if + 1=<F, F=<(P-1)-> + K = compute_key(dh, F, Private, [P,G]), + if + 1<K, K<(P-1) -> + H = kex_h(Ssh0, PeerPubHostKey, Min, NBits, Max, P, G, Public, F, K), + + case verify_host_key(Ssh0, PeerPubHostKey, H, H_SIG) of + ok -> + {SshPacket, Ssh} = ssh_packet(#ssh_msg_newkeys{}, Ssh0), + {ok, SshPacket, Ssh#ssh{shared_secret = K, + exchanged_hash = H, + session_id = sid(Ssh, H)}}; + _Error -> + throw(#ssh_msg_disconnect{ + code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED, + description = "Key exchange failed", + language = ""} + ) + end; + + true -> + throw({{error,bad_K}, + #ssh_msg_disconnect{ + code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED, + description = "Key exchange failed, 'K' out of bounds", + language = ""} + }) + end; + true -> + throw({{error,bad_f_from_peer}, + #ssh_msg_disconnect{ + code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED, + description = "Key exchange failed, 'f' out of bounds", + language = ""} + }) + end. + +%%%---------------------------------------------------------------- +%%% +%%% diffie-hellman-ecdh-sha2-* +%%% +handle_kex_ecdh_init(#ssh_msg_kex_ecdh_init{q_c = PeerPublic}, + Ssh0 = #ssh{algorithms = #alg{kex=Kex}}) -> + %% at server + Curve = ecdh_curve(Kex), + {MyPublic, MyPrivate} = generate_key(ecdh, Curve), + try + compute_key(ecdh, PeerPublic, MyPrivate, Curve) + of + K -> + MyPrivHostKey = get_host_key(Ssh0), + MyPubHostKey = extract_public_key(MyPrivHostKey), + H = kex_h(Ssh0, Curve, MyPubHostKey, PeerPublic, MyPublic, K), + H_SIG = sign_host_key(Ssh0, MyPrivHostKey, H), + {SshPacket, Ssh1} = + ssh_packet(#ssh_msg_kex_ecdh_reply{public_host_key = MyPubHostKey, + q_s = MyPublic, + h_sig = H_SIG}, + Ssh0), + {ok, SshPacket, Ssh1#ssh{keyex_key = {{MyPublic,MyPrivate},Curve}, + shared_secret = K, + exchanged_hash = H, + session_id = sid(Ssh1, H)}} + catch + _:_ -> + throw({{error,invalid_peer_public_key}, + #ssh_msg_disconnect{ + code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED, + description = "Peer ECDH public key is invalid", + language = ""} + }) + end. + +handle_kex_ecdh_reply(#ssh_msg_kex_ecdh_reply{public_host_key = PeerPubHostKey, + q_s = PeerPublic, + h_sig = H_SIG}, + #ssh{keyex_key = {{MyPublic,MyPrivate}, Curve}} = Ssh0 + ) -> + %% at client + try + compute_key(ecdh, PeerPublic, MyPrivate, Curve) + of + K -> + H = kex_h(Ssh0, Curve, PeerPubHostKey, MyPublic, PeerPublic, K), + case verify_host_key(Ssh0, PeerPubHostKey, H, H_SIG) of + ok -> + {SshPacket, Ssh} = ssh_packet(#ssh_msg_newkeys{}, Ssh0), + {ok, SshPacket, Ssh#ssh{shared_secret = K, + exchanged_hash = H, + session_id = sid(Ssh, H)}}; + Error -> + throw({Error, + #ssh_msg_disconnect{ + code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED, + description = "Key exchange failed", + language = ""} + }) + end + catch + _:_ -> + throw({{error,invalid_peer_public_key}, + #ssh_msg_disconnect{ + code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED, + description = "Peer ECDH public key is invalid", + language = ""} + }) + end. + + +%%%---------------------------------------------------------------- handle_new_keys(#ssh_msg_newkeys{}, Ssh0) -> try install_alg(Ssh0) of #ssh{} = Ssh -> {ok, Ssh} catch - error:_Error -> %% TODO: Throw earlier .... + _C:_Error -> %% TODO: Throw earlier .... throw(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR, description = "Install alg failed", language = "en"}) end. - -%% %% Select algorithms -handle_kexdh_reply(#ssh_msg_kexdh_reply{public_host_key = HostKey, f = F, - h_sig = H_SIG}, - #ssh{keyex_key = {{Private, Public}, {_G, P}}} = Ssh0) when 1=<F, F=<(P-1)-> - K = ssh_math:ipow(F, Private, P), - H = kex_h(Ssh0, HostKey, Public, F, K), - - case verify_host_key(Ssh0, HostKey, H, H_SIG) of - ok -> - {SshPacket, Ssh} = ssh_packet(#ssh_msg_newkeys{}, Ssh0), - {ok, SshPacket, Ssh#ssh{shared_secret = K, - exchanged_hash = H, - session_id = sid(Ssh, H)}}; - Error -> - Disconnect = #ssh_msg_disconnect{ - code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED, - description = "Key exchange failed", - language = "en"}, - throw({Error, Disconnect}) - end; -handle_kexdh_reply(#ssh_msg_kexdh_reply{}, _SSH) -> - Error = {error,bad_f_from_peer}, - Disconnect = #ssh_msg_disconnect{ - code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED, - description = "Key exchange failed, 'f' out of bounds", - language = "en"}, - throw({Error, Disconnect}). - - -handle_kex_dh_gex_request(#ssh_msg_kex_dh_gex_request{min = _Min, - n = _NBits, - max = _Max}, Ssh0) -> - {G,P} = dh_group1(), %% TODO real imp this seems to be a hack?! - {Private, Public} = dh_gen_key(G, P, 1024), - {SshPacket, Ssh} = - ssh_packet(#ssh_msg_kex_dh_gex_group{p = P, g = G}, Ssh0), - {ok, SshPacket, - Ssh#ssh{keyex_key = {{Private, Public}, {G, P}}}}. - -handle_kex_dh_gex_reply(#ssh_msg_kex_dh_gex_reply{public_host_key = HostKey, - f = F, - h_sig = H_SIG}, - #ssh{keyex_key = {{Private, Public}, {G, P}}, - keyex_info = {Min, Max, NBits}} = - Ssh0) -> - K = ssh_math:ipow(F, Private, P), - H = kex_h(Ssh0, HostKey, Min, NBits, Max, P, G, Public, F, K), - - case verify_host_key(Ssh0, HostKey, H, H_SIG) of - ok -> - {SshPacket, Ssh} = ssh_packet(#ssh_msg_newkeys{}, Ssh0), - {ok, SshPacket, Ssh#ssh{shared_secret = K, - exchanged_hash = H, - session_id = sid(Ssh, H)}}; - _Error -> - Disconnect = #ssh_msg_disconnect{ - code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED, - description = "Key exchange failed", - language = "en"}, - throw(Disconnect) - end. - %% select session id sid(#ssh{session_id = undefined}, H) -> H; @@ -407,33 +685,49 @@ get_host_key(SSH) -> #ssh{key_cb = Mod, opts = Opts, algorithms = ALG} = SSH, case Mod:host_key(ALG#alg.hkey, Opts) of - {ok, #'RSAPrivateKey'{} = Key} -> - Key; - {ok, #'DSAPrivateKey'{} = Key} -> - Key; + {ok, #'RSAPrivateKey'{} = Key} -> Key; + {ok, #'DSAPrivateKey'{} = Key} -> Key; + {ok, #'ECPrivateKey'{} = Key} -> Key; Result -> exit({error, {Result, unsupported_key_type}}) end. -sign_host_key(_Ssh, #'RSAPrivateKey'{} = Private, H) -> - Hash = sha, %% Option ?! - _Signature = sign(H, Hash, Private); -sign_host_key(_Ssh, #'DSAPrivateKey'{} = Private, H) -> - Hash = sha, %% Option ?! - _RawSignature = sign(H, Hash, Private). +sign_host_key(_Ssh, PrivateKey, H) -> + sign(H, sign_host_key_sha(PrivateKey), PrivateKey). + +sign_host_key_sha(#'ECPrivateKey'{parameters = {namedCurve,OID}}) -> sha(OID); +sign_host_key_sha(#'RSAPrivateKey'{}) -> sha; +sign_host_key_sha(#'DSAPrivateKey'{}) -> sha. + + +extract_public_key(#'RSAPrivateKey'{modulus = N, publicExponent = E}) -> + #'RSAPublicKey'{modulus = N, publicExponent = E}; +extract_public_key(#'DSAPrivateKey'{y = Y, p = P, q = Q, g = G}) -> + {Y, #'Dss-Parms'{p=P, q=Q, g=G}}; +extract_public_key(#'ECPrivateKey'{parameters = {namedCurve,OID}, + publicKey = Q}) -> + {#'ECPoint'{point=Q}, {namedCurve,OID}}. + verify_host_key(SSH, PublicKey, Digest, Signature) -> - case verify(Digest, sha, Signature, PublicKey) of + case verify(Digest, host_key_sha(PublicKey), Signature, PublicKey) of false -> {error, bad_signature}; true -> known_host_key(SSH, PublicKey, public_algo(PublicKey)) end. -public_algo(#'RSAPublicKey'{}) -> - 'ssh-rsa'; -public_algo({_, #'Dss-Parms'{}}) -> - 'ssh-dss'. + +host_key_sha(#'RSAPublicKey'{}) -> sha; +host_key_sha({_, #'Dss-Parms'{}}) -> sha; +host_key_sha({#'ECPoint'{},{namedCurve,OID}}) -> sha(OID). + +public_algo(#'RSAPublicKey'{}) -> 'ssh-rsa'; +public_algo({_, #'Dss-Parms'{}}) -> 'ssh-dss'; +public_algo({#'ECPoint'{},{namedCurve,OID}}) -> + Curve = public_key:oid2ssh_curvename(OID), + list_to_atom("ecdsa-sha2-" ++ binary_to_list(Curve)). + accepted_host(Ssh, PeerName, Opts) -> case proplists:get_value(silently_accept_hosts, Opts, false) of @@ -466,8 +760,12 @@ known_host_key(#ssh{opts = Opts, key_cb = Mod, peer = Peer} = Ssh, %% The first algorithm in each list MUST be the preferred (guessed) %% algorithm. Each string MUST contain at least one algorithm name. select_algorithm(Role, Client, Server) -> - {Encrypt, Decrypt} = select_encrypt_decrypt(Role, Client, Server), - {SendMac, RecvMac} = select_send_recv_mac(Role, Client, Server), + {Encrypt0, Decrypt0} = select_encrypt_decrypt(Role, Client, Server), + {SendMac0, RecvMac0} = select_send_recv_mac(Role, Client, Server), + + {Encrypt, SendMac} = aead_gcm_simultan(Encrypt0, SendMac0), + {Decrypt, RecvMac} = aead_gcm_simultan(Decrypt0, RecvMac0), + {Compression, Decompression} = select_compression_decompression(Role, Client, Server), @@ -496,9 +794,40 @@ select_algorithm(Role, Client, Server) -> decompress = Decompression, c_lng = C_Lng, s_lng = S_Lng}, -%%ct:pal("~p~n Client=~p~n Server=~p~n Alg=~p~n",[Role,Client,Server,Alg]), {ok, Alg}. + +%%% It is an agreed problem with RFC 5674 that if the selection is +%%% Cipher = AEAD_AES_x_GCM and +%%% Mac = AEAD_AES_y_GCM (where x =/= y) +%%% then it is undefined what length should be selected. +%%% +%%% If only one of the two lengths (128,256) is available, I claim that +%%% there is no such ambiguity. + +%%% From https://anongit.mindrot.org/openssh.git/plain/PROTOCOL +%%% (read Nov 20, 2015) +%%% 1.6 transport: AES-GCM +%%% +%%% OpenSSH supports the AES-GCM algorithm as specified in RFC 5647. +%%% Because of problems with the specification of the key exchange +%%% the behaviour of OpenSSH differs from the RFC as follows: +%%% +%%% AES-GCM is only negotiated as the cipher algorithms +%%% "[email protected]" or "[email protected]" and never as +%%% an MAC algorithm. Additionally, if AES-GCM is selected as the cipher +%%% the exchanged MAC algorithms are ignored and there doesn't have to be +%%% a matching MAC. + +aead_gcm_simultan('[email protected]', _) -> {'AEAD_AES_128_GCM', 'AEAD_AES_128_GCM'}; +aead_gcm_simultan('[email protected]', _) -> {'AEAD_AES_256_GCM', 'AEAD_AES_256_GCM'}; +aead_gcm_simultan('AEAD_AES_128_GCM', _) -> {'AEAD_AES_128_GCM', 'AEAD_AES_128_GCM'}; +aead_gcm_simultan('AEAD_AES_256_GCM', _) -> {'AEAD_AES_256_GCM', 'AEAD_AES_256_GCM'}; +aead_gcm_simultan(_, 'AEAD_AES_128_GCM') -> {'AEAD_AES_128_GCM', 'AEAD_AES_128_GCM'}; +aead_gcm_simultan(_, 'AEAD_AES_256_GCM') -> {'AEAD_AES_256_GCM', 'AEAD_AES_256_GCM'}; +aead_gcm_simultan(Cipher, Mac) -> {Cipher,Mac}. + + select_encrypt_decrypt(client, Client, Server) -> Encrypt = select(Client#ssh_msg_kexinit.encryption_algorithms_client_to_server, @@ -533,18 +862,18 @@ select_compression_decompression(client, Client, Server) -> Compression = select(Client#ssh_msg_kexinit.compression_algorithms_client_to_server, Server#ssh_msg_kexinit.compression_algorithms_client_to_server), - Decomprssion = + Decompression = select(Client#ssh_msg_kexinit.compression_algorithms_server_to_client, Server#ssh_msg_kexinit.compression_algorithms_server_to_client), - {Compression, Decomprssion}; + {Compression, Decompression}; select_compression_decompression(server, Client, Server) -> - Decomprssion = + Decompression = select(Client#ssh_msg_kexinit.compression_algorithms_client_to_server, Server#ssh_msg_kexinit.compression_algorithms_client_to_server), Compression = select(Client#ssh_msg_kexinit.compression_algorithms_server_to_client, Server#ssh_msg_kexinit.compression_algorithms_server_to_client), - {Compression, Decomprssion}. + {Compression, Decompression}. install_alg(SSH) -> SSH1 = alg_final(SSH), @@ -586,14 +915,15 @@ alg_final(SSH0) -> {ok,SSH6} = decompress_final(SSH5), SSH6. -select_all(CL, SL) when length(CL) + length(SL) < 50 -> +select_all(CL, SL) when length(CL) + length(SL) < ?MAX_NUM_ALGORITHMS -> A = CL -- SL, %% algortihms only used by client %% algorithms used by client and server (client pref) lists:map(fun(ALG) -> list_to_atom(ALG) end, (CL -- A)); -select_all(_CL, _SL) -> +select_all(CL, SL) -> + Err = lists:concat(["Received too many algorithms (",length(CL),"+",length(SL)," >= ",?MAX_NUM_ALGORITHMS,")."]), throw(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR, - description = "Too many algorithms", - language = "en"}). + description = Err, + language = ""}). select([], []) -> @@ -614,58 +944,147 @@ ssh_packet(Msg, Ssh) -> BinMsg = ssh_message:encode(Msg), pack(BinMsg, Ssh). -pack(Data0, #ssh{encrypt_block_size = BlockSize, - send_sequence = SeqNum, send_mac = MacAlg, - send_mac_key = MacKey} - = Ssh0) when is_binary(Data0) -> - {Ssh1, Data} = compress(Ssh0, Data0), - PL = (BlockSize - ((4 + 1 + size(Data)) rem BlockSize)) rem BlockSize, - PaddingLen = if PL < 4 -> PL + BlockSize; - true -> PL - end, - Padding = ssh_bits:random(PaddingLen), - PacketLen = 1 + PaddingLen + size(Data), - PacketData = <<?UINT32(PacketLen),?BYTE(PaddingLen), - Data/binary, Padding/binary>>, - {Ssh2, EncPacket} = encrypt(Ssh1, PacketData), - MAC = mac(MacAlg, MacKey, SeqNum, PacketData), - Packet = [EncPacket, MAC], - Ssh = Ssh2#ssh{send_sequence = (SeqNum+1) band 16#ffffffff}, - {Packet, Ssh}. - -unpack(EncodedSoFar, ReminingLenght, #ssh{recv_mac_size = MacSize} = Ssh0) -> - SshLength = ReminingLenght - MacSize, - {NoMac, Mac, Rest} = case MacSize of - 0 -> - <<NoMac0:SshLength/binary, - Rest0/binary>> = EncodedSoFar, - {NoMac0, <<>>, Rest0}; - _ -> - <<NoMac0:SshLength/binary, - Mac0:MacSize/binary, - Rest0/binary>> = EncodedSoFar, - {NoMac0, Mac0, Rest0} - end, - {Ssh1, DecData, <<>>} = - case SshLength of - 0 -> - {Ssh0, <<>>, <<>>}; - _ -> - decrypt_blocks(NoMac, SshLength, Ssh0) +pack(Data, Ssh=#ssh{}) -> + pack(Data, Ssh, 0). + +%%% Note: pack/3 is only to be called from tests that wants +%%% to deliberetly send packets with wrong PacketLength! +%%% Use pack/2 for all other purposes! +pack(PlainText, + #ssh{send_sequence = SeqNum, + send_mac = MacAlg, + send_mac_key = MacKey, + encrypt = CryptoAlg} = Ssh0, PacketLenDeviationForTests) when is_binary(PlainText) -> + + {Ssh1, CompressedPlainText} = compress(Ssh0, PlainText), + {EcryptedPacket, MAC, Ssh3} = + case pkt_type(CryptoAlg) of + common -> + PaddingLen = padding_length(4+1+size(CompressedPlainText), Ssh0), + Padding = ssh_bits:random(PaddingLen), + PlainPacketLen = 1 + PaddingLen + size(CompressedPlainText) + PacketLenDeviationForTests, + PlainPacketData = <<?UINT32(PlainPacketLen),?BYTE(PaddingLen), CompressedPlainText/binary, Padding/binary>>, + {Ssh2, EcryptedPacket0} = encrypt(Ssh1, PlainPacketData), + MAC0 = mac(MacAlg, MacKey, SeqNum, PlainPacketData), + {EcryptedPacket0, MAC0, Ssh2}; + aead -> + PaddingLen = padding_length(1+size(CompressedPlainText), Ssh0), + Padding = ssh_bits:random(PaddingLen), + PlainPacketLen = 1 + PaddingLen + size(CompressedPlainText) + PacketLenDeviationForTests, + PlainPacketData = <<?BYTE(PaddingLen), CompressedPlainText/binary, Padding/binary>>, + {Ssh2, {EcryptedPacket0,MAC0}} = encrypt(Ssh1, {<<?UINT32(PlainPacketLen)>>,PlainPacketData}), + {<<?UINT32(PlainPacketLen),EcryptedPacket0/binary>>, MAC0, Ssh2} end, - {Ssh1, DecData, Rest, Mac}. + FinalPacket = [EcryptedPacket, MAC], + Ssh = Ssh3#ssh{send_sequence = (SeqNum+1) band 16#ffffffff}, + {FinalPacket, Ssh}. + + +padding_length(Size, #ssh{encrypt_block_size = BlockSize, + random_length_padding = RandomLengthPadding}) -> + PL = (BlockSize - (Size rem BlockSize)) rem BlockSize, + MinPaddingLen = if PL < 4 -> PL + BlockSize; + true -> PL + end, + PadBlockSize = max(BlockSize,4), + MaxExtraBlocks = (max(RandomLengthPadding,MinPaddingLen) - MinPaddingLen) div PadBlockSize, + ExtraPaddingLen = try crypto:rand_uniform(0,MaxExtraBlocks)*PadBlockSize + catch _:_ -> 0 + end, + MinPaddingLen + ExtraPaddingLen. + + + +handle_packet_part(<<>>, Encrypted0, undefined, #ssh{decrypt = CryptoAlg} = Ssh0) -> + %% New ssh packet + case get_length(pkt_type(CryptoAlg), Encrypted0, Ssh0) of + get_more -> + %% too short to get the length + {get_more, <<>>, Encrypted0, undefined, Ssh0}; + + {ok, PacketLen, _, _, _} when PacketLen > ?SSH_MAX_PACKET_SIZE -> + %% far too long message than expected + {error, {exceeds_max_size,PacketLen}}; + + {ok, PacketLen, Decrypted, Encrypted1, + #ssh{recv_mac_size = MacSize} = Ssh1} -> + %% enough bytes so we got the length and can calculate how many + %% more bytes to expect for a full packet + TotalNeeded = (4 + PacketLen + MacSize), + handle_packet_part(Decrypted, Encrypted1, TotalNeeded, Ssh1) + end; + +handle_packet_part(DecryptedPfx, EncryptedBuffer, TotalNeeded, Ssh0) + when (size(DecryptedPfx)+size(EncryptedBuffer)) < TotalNeeded -> + %% need more bytes to finalize the packet + {get_more, DecryptedPfx, EncryptedBuffer, TotalNeeded, Ssh0}; + +handle_packet_part(DecryptedPfx, EncryptedBuffer, TotalNeeded, + #ssh{recv_mac_size = MacSize, + decrypt = CryptoAlg} = Ssh0) -> + %% enough bytes to decode the packet. + DecryptLen = TotalNeeded - size(DecryptedPfx) - MacSize, + <<EncryptedSfx:DecryptLen/binary, Mac:MacSize/binary, NextPacketBytes/binary>> = EncryptedBuffer, + case pkt_type(CryptoAlg) of + common -> + {Ssh1, DecryptedSfx} = decrypt(Ssh0, EncryptedSfx), + DecryptedPacket = <<DecryptedPfx/binary, DecryptedSfx/binary>>, + case is_valid_mac(Mac, DecryptedPacket, Ssh1) of + false -> + {bad_mac, Ssh1}; + true -> + {Ssh, DecompressedPayload} = decompress(Ssh1, payload(DecryptedPacket)), + {decoded, DecompressedPayload, NextPacketBytes, Ssh} + end; + aead -> + PacketLenBin = DecryptedPfx, + case decrypt(Ssh0, {PacketLenBin,EncryptedSfx,Mac}) of + {Ssh1, error} -> + {bad_mac, Ssh1}; + {Ssh1, DecryptedSfx} -> + DecryptedPacket = <<DecryptedPfx/binary, DecryptedSfx/binary>>, + {Ssh, DecompressedPayload} = decompress(Ssh1, payload(DecryptedPacket)), + {decoded, DecompressedPayload, NextPacketBytes, Ssh} + end + end. + + +get_length(common, EncryptedBuffer, #ssh{decrypt_block_size = BlockSize} = Ssh0) -> + case size(EncryptedBuffer) >= erlang:max(8, BlockSize) of + true -> + <<EncBlock:BlockSize/binary, EncryptedRest/binary>> = EncryptedBuffer, + {Ssh, + <<?UINT32(PacketLen),_/binary>> = Decrypted} = decrypt(Ssh0, EncBlock), + {ok, PacketLen, Decrypted, EncryptedRest, Ssh}; + false -> + get_more + end; +get_length(aead, EncryptedBuffer, Ssh) -> + case size(EncryptedBuffer) >= 4 of + true -> + <<?UINT32(PacketLen), EncryptedRest/binary>> = EncryptedBuffer, + {ok, PacketLen, <<?UINT32(PacketLen)>>, EncryptedRest, Ssh}; + false -> + get_more + end. + +pkt_type('AEAD_AES_128_GCM') -> aead; +pkt_type('AEAD_AES_256_GCM') -> aead; +pkt_type(_) -> common. -msg_data(PacketData) -> - <<Len:32, PaddingLen:8, _/binary>> = PacketData, - DataLen = Len - PaddingLen - 1, - <<_:32, _:8, Data:DataLen/binary, - _:PaddingLen/binary>> = PacketData, - Data. +payload(<<PacketLen:32, PaddingLen:8, PayloadAndPadding/binary>>) -> + PayloadLen = PacketLen - PaddingLen - 1, + <<Payload:PayloadLen/binary, _/binary>> = PayloadAndPadding, + Payload. sign(SigData, Hash, #'DSAPrivateKey'{} = Key) -> DerSignature = public_key:sign(SigData, Hash, Key), #'Dss-Sig-Value'{r = R, s = S} = public_key:der_decode('Dss-Sig-Value', DerSignature), <<R:160/big-unsigned-integer, S:160/big-unsigned-integer>>; +sign(SigData, Hash, Key = #'ECPrivateKey'{}) -> + DerEncodedSign = public_key:sign(SigData, Hash, Key), + #'ECDSA-Sig-Value'{r=R, s=S} = public_key:der_decode('ECDSA-Sig-Value', DerEncodedSign), + ssh_bits:encode([R,S], [mpint,mpint]); sign(SigData, Hash, Key) -> public_key:sign(SigData, Hash, Key). @@ -673,59 +1092,48 @@ verify(PlainText, Hash, Sig, {_, #'Dss-Parms'{}} = Key) -> <<R:160/big-unsigned-integer, S:160/big-unsigned-integer>> = Sig, Signature = public_key:der_encode('Dss-Sig-Value', #'Dss-Sig-Value'{r = R, s = S}), public_key:verify(PlainText, Hash, Signature, Key); +verify(PlainText, Hash, Sig, {#'ECPoint'{},_} = Key) -> + <<?UINT32(Rlen),R:Rlen/big-signed-integer-unit:8, + ?UINT32(Slen),S:Slen/big-signed-integer-unit:8>> = Sig, + Sval = #'ECDSA-Sig-Value'{r=R, s=S}, + DerEncodedSig = public_key:der_encode('ECDSA-Sig-Value',Sval), + public_key:verify(PlainText, Hash, DerEncodedSig, Key); verify(PlainText, Hash, Sig, Key) -> public_key:verify(PlainText, Hash, Sig, Key). -%% public key algorithms -%% -%% ssh-dss REQUIRED sign Raw DSS Key -%% ssh-rsa RECOMMENDED sign Raw RSA Key -%% x509v3-sign-rsa OPTIONAL sign X.509 certificates (RSA key) -%% x509v3-sign-dss OPTIONAL sign X.509 certificates (DSS key) -%% spki-sign-rsa OPTIONAL sign SPKI certificates (RSA key) -%% spki-sign-dss OPTIONAL sign SPKI certificates (DSS key) -%% pgp-sign-rsa OPTIONAL sign OpenPGP certificates (RSA key) -%% pgp-sign-dss OPTIONAL sign OpenPGP certificates (DSS key) -%% - -%% key exchange -%% -%% diffie-hellman-group1-sha1 REQUIRED -%% -%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Encryption -%% -%% chiphers %% -%% 3des-cbc REQUIRED -%% three-key 3DES in CBC mode -%% blowfish-cbc OPTIONAL Blowfish in CBC mode -%% twofish256-cbc OPTIONAL Twofish in CBC mode, -%% with 256-bit key -%% twofish-cbc OPTIONAL alias for "twofish256-cbc" (this -%% is being retained for -%% historical reasons) -%% twofish192-cbc OPTIONAL Twofish with 192-bit key -%% twofish128-cbc OPTIONAL Twofish with 128-bit key -%% aes256-cbc OPTIONAL AES in CBC mode, -%% with 256-bit key -%% aes192-cbc OPTIONAL AES with 192-bit key -%% aes128-cbc RECOMMENDED AES with 128-bit key -%% serpent256-cbc OPTIONAL Serpent in CBC mode, with -%% 256-bit key -%% serpent192-cbc OPTIONAL Serpent with 192-bit key -%% serpent128-cbc OPTIONAL Serpent with 128-bit key -%% arcfour OPTIONAL the ARCFOUR stream cipher -%% idea-cbc OPTIONAL IDEA in CBC mode -%% cast128-cbc OPTIONAL CAST-128 in CBC mode -%% none OPTIONAL no encryption; NOT RECOMMENDED +%% Encryption %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% encrypt_init(#ssh{encrypt = none} = Ssh) -> {ok, Ssh}; +encrypt_init(#ssh{encrypt = 'AEAD_AES_128_GCM', role = client} = Ssh) -> + IV = hash(Ssh, "A", 12*8), + <<K:16/binary>> = hash(Ssh, "C", 128), + {ok, Ssh#ssh{encrypt_keys = K, + encrypt_block_size = 16, + encrypt_ctx = IV}}; +encrypt_init(#ssh{encrypt = 'AEAD_AES_128_GCM', role = server} = Ssh) -> + IV = hash(Ssh, "B", 12*8), + <<K:16/binary>> = hash(Ssh, "D", 128), + {ok, Ssh#ssh{encrypt_keys = K, + encrypt_block_size = 16, + encrypt_ctx = IV}}; +encrypt_init(#ssh{encrypt = 'AEAD_AES_256_GCM', role = client} = Ssh) -> + IV = hash(Ssh, "A", 12*8), + <<K:32/binary>> = hash(Ssh, "C", 256), + {ok, Ssh#ssh{encrypt_keys = K, + encrypt_block_size = 16, + encrypt_ctx = IV}}; +encrypt_init(#ssh{encrypt = 'AEAD_AES_256_GCM', role = server} = Ssh) -> + IV = hash(Ssh, "B", 12*8), + <<K:32/binary>> = hash(Ssh, "D", 256), + {ok, Ssh#ssh{encrypt_keys = K, + encrypt_block_size = 16, + encrypt_ctx = IV}}; encrypt_init(#ssh{encrypt = '3des-cbc', role = client} = Ssh) -> IV = hash(Ssh, "A", 64), <<K1:8/binary, K2:8/binary, K3:8/binary>> = hash(Ssh, "C", 192), @@ -751,18 +1159,46 @@ encrypt_init(#ssh{encrypt = 'aes128-cbc', role = server} = Ssh) -> encrypt_block_size = 16, encrypt_ctx = IV}}; encrypt_init(#ssh{encrypt = 'aes128-ctr', role = client} = Ssh) -> - IV = hash(Ssh, "A", 128), + IV = hash(Ssh, "A", 128), <<K:16/binary>> = hash(Ssh, "C", 128), State = crypto:stream_init(aes_ctr, K, IV), {ok, Ssh#ssh{encrypt_keys = K, encrypt_block_size = 16, encrypt_ctx = State}}; +encrypt_init(#ssh{encrypt = 'aes192-ctr', role = client} = Ssh) -> + IV = hash(Ssh, "A", 128), + <<K:24/binary>> = hash(Ssh, "C", 192), + State = crypto:stream_init(aes_ctr, K, IV), + {ok, Ssh#ssh{encrypt_keys = K, + encrypt_block_size = 16, + encrypt_ctx = State}}; +encrypt_init(#ssh{encrypt = 'aes256-ctr', role = client} = Ssh) -> + IV = hash(Ssh, "A", 128), + <<K:32/binary>> = hash(Ssh, "C", 256), + State = crypto:stream_init(aes_ctr, K, IV), + {ok, Ssh#ssh{encrypt_keys = K, + encrypt_block_size = 16, + encrypt_ctx = State}}; encrypt_init(#ssh{encrypt = 'aes128-ctr', role = server} = Ssh) -> - IV = hash(Ssh, "B", 128), + IV = hash(Ssh, "B", 128), <<K:16/binary>> = hash(Ssh, "D", 128), State = crypto:stream_init(aes_ctr, K, IV), {ok, Ssh#ssh{encrypt_keys = K, encrypt_block_size = 16, + encrypt_ctx = State}}; +encrypt_init(#ssh{encrypt = 'aes192-ctr', role = server} = Ssh) -> + IV = hash(Ssh, "B", 128), + <<K:24/binary>> = hash(Ssh, "D", 192), + State = crypto:stream_init(aes_ctr, K, IV), + {ok, Ssh#ssh{encrypt_keys = K, + encrypt_block_size = 16, + encrypt_ctx = State}}; +encrypt_init(#ssh{encrypt = 'aes256-ctr', role = server} = Ssh) -> + IV = hash(Ssh, "B", 128), + <<K:32/binary>> = hash(Ssh, "D", 256), + State = crypto:stream_init(aes_ctr, K, IV), + {ok, Ssh#ssh{encrypt_keys = K, + encrypt_block_size = 16, encrypt_ctx = State}}. encrypt_final(Ssh) -> @@ -774,6 +1210,18 @@ encrypt_final(Ssh) -> encrypt(#ssh{encrypt = none} = Ssh, Data) -> {Ssh, Data}; +encrypt(#ssh{encrypt = 'AEAD_AES_128_GCM', + encrypt_keys = K, + encrypt_ctx = IV0} = Ssh, Data={_AAD,_Ptext}) -> + Enc = {_Ctext,_Ctag} = crypto:block_encrypt(aes_gcm, K, IV0, Data), + IV = next_gcm_iv(IV0), + {Ssh#ssh{encrypt_ctx = IV}, Enc}; +encrypt(#ssh{encrypt = 'AEAD_AES_256_GCM', + encrypt_keys = K, + encrypt_ctx = IV0} = Ssh, Data={_AAD,_Ptext}) -> + Enc = {_Ctext,_Ctag} = crypto:block_encrypt(aes_gcm, K, IV0, Data), + IV = next_gcm_iv(IV0), + {Ssh#ssh{encrypt_ctx = IV}, Enc}; encrypt(#ssh{encrypt = '3des-cbc', encrypt_keys = {K1,K2,K3}, encrypt_ctx = IV0} = Ssh, Data) -> @@ -789,6 +1237,14 @@ encrypt(#ssh{encrypt = 'aes128-cbc', encrypt(#ssh{encrypt = 'aes128-ctr', encrypt_ctx = State0} = Ssh, Data) -> {State, Enc} = crypto:stream_encrypt(State0,Data), + {Ssh#ssh{encrypt_ctx = State}, Enc}; +encrypt(#ssh{encrypt = 'aes192-ctr', + encrypt_ctx = State0} = Ssh, Data) -> + {State, Enc} = crypto:stream_encrypt(State0,Data), + {Ssh#ssh{encrypt_ctx = State}, Enc}; +encrypt(#ssh{encrypt = 'aes256-ctr', + encrypt_ctx = State0} = Ssh, Data) -> + {State, Enc} = crypto:stream_encrypt(State0,Data), {Ssh#ssh{encrypt_ctx = State}, Enc}. @@ -798,6 +1254,30 @@ encrypt(#ssh{encrypt = 'aes128-ctr', decrypt_init(#ssh{decrypt = none} = Ssh) -> {ok, Ssh}; +decrypt_init(#ssh{decrypt = 'AEAD_AES_128_GCM', role = client} = Ssh) -> + IV = hash(Ssh, "B", 12*8), + <<K:16/binary>> = hash(Ssh, "D", 128), + {ok, Ssh#ssh{decrypt_keys = K, + decrypt_block_size = 16, + decrypt_ctx = IV}}; +decrypt_init(#ssh{decrypt = 'AEAD_AES_128_GCM', role = server} = Ssh) -> + IV = hash(Ssh, "A", 12*8), + <<K:16/binary>> = hash(Ssh, "C", 128), + {ok, Ssh#ssh{decrypt_keys = K, + decrypt_block_size = 16, + decrypt_ctx = IV}}; +decrypt_init(#ssh{decrypt = 'AEAD_AES_256_GCM', role = client} = Ssh) -> + IV = hash(Ssh, "B", 12*8), + <<K:32/binary>> = hash(Ssh, "D", 256), + {ok, Ssh#ssh{decrypt_keys = K, + decrypt_block_size = 16, + decrypt_ctx = IV}}; +decrypt_init(#ssh{decrypt = 'AEAD_AES_256_GCM', role = server} = Ssh) -> + IV = hash(Ssh, "A", 12*8), + <<K:32/binary>> = hash(Ssh, "C", 256), + {ok, Ssh#ssh{decrypt_keys = K, + decrypt_block_size = 16, + decrypt_ctx = IV}}; decrypt_init(#ssh{decrypt = '3des-cbc', role = client} = Ssh) -> {IV, KD} = {hash(Ssh, "B", 64), hash(Ssh, "D", 192)}, @@ -829,12 +1309,40 @@ decrypt_init(#ssh{decrypt = 'aes128-ctr', role = client} = Ssh) -> {ok, Ssh#ssh{decrypt_keys = K, decrypt_block_size = 16, decrypt_ctx = State}}; +decrypt_init(#ssh{decrypt = 'aes192-ctr', role = client} = Ssh) -> + IV = hash(Ssh, "B", 128), + <<K:24/binary>> = hash(Ssh, "D", 192), + State = crypto:stream_init(aes_ctr, K, IV), + {ok, Ssh#ssh{decrypt_keys = K, + decrypt_block_size = 16, + decrypt_ctx = State}}; +decrypt_init(#ssh{decrypt = 'aes256-ctr', role = client} = Ssh) -> + IV = hash(Ssh, "B", 128), + <<K:32/binary>> = hash(Ssh, "D", 256), + State = crypto:stream_init(aes_ctr, K, IV), + {ok, Ssh#ssh{decrypt_keys = K, + decrypt_block_size = 16, + decrypt_ctx = State}}; decrypt_init(#ssh{decrypt = 'aes128-ctr', role = server} = Ssh) -> IV = hash(Ssh, "A", 128), <<K:16/binary>> = hash(Ssh, "C", 128), State = crypto:stream_init(aes_ctr, K, IV), {ok, Ssh#ssh{decrypt_keys = K, decrypt_block_size = 16, + decrypt_ctx = State}}; +decrypt_init(#ssh{decrypt = 'aes192-ctr', role = server} = Ssh) -> + IV = hash(Ssh, "A", 128), + <<K:24/binary>> = hash(Ssh, "C", 192), + State = crypto:stream_init(aes_ctr, K, IV), + {ok, Ssh#ssh{decrypt_keys = K, + decrypt_block_size = 16, + decrypt_ctx = State}}; +decrypt_init(#ssh{decrypt = 'aes256-ctr', role = server} = Ssh) -> + IV = hash(Ssh, "A", 128), + <<K:32/binary>> = hash(Ssh, "C", 256), + State = crypto:stream_init(aes_ctr, K, IV), + {ok, Ssh#ssh{decrypt_keys = K, + decrypt_block_size = 16, decrypt_ctx = State}}. @@ -844,8 +1352,22 @@ decrypt_final(Ssh) -> decrypt_ctx = undefined, decrypt_block_size = 8}}. +decrypt(Ssh, <<>>) -> + {Ssh, <<>>}; decrypt(#ssh{decrypt = none} = Ssh, Data) -> {Ssh, Data}; +decrypt(#ssh{decrypt = 'AEAD_AES_128_GCM', + decrypt_keys = K, + decrypt_ctx = IV0} = Ssh, Data = {_AAD,_Ctext,_Ctag}) -> + Dec = crypto:block_decrypt(aes_gcm, K, IV0, Data), % Dec = PlainText | error + IV = next_gcm_iv(IV0), + {Ssh#ssh{decrypt_ctx = IV}, Dec}; +decrypt(#ssh{decrypt = 'AEAD_AES_256_GCM', + decrypt_keys = K, + decrypt_ctx = IV0} = Ssh, Data = {_AAD,_Ctext,_Ctag}) -> + Dec = crypto:block_decrypt(aes_gcm, K, IV0, Data), % Dec = PlainText | error + IV = next_gcm_iv(IV0), + {Ssh#ssh{decrypt_ctx = IV}, Dec}; decrypt(#ssh{decrypt = '3des-cbc', decrypt_keys = Keys, decrypt_ctx = IV0} = Ssh, Data) -> {K1, K2, K3} = Keys, @@ -860,8 +1382,20 @@ decrypt(#ssh{decrypt = 'aes128-cbc', decrypt_keys = Key, decrypt(#ssh{decrypt = 'aes128-ctr', decrypt_ctx = State0} = Ssh, Data) -> {State, Enc} = crypto:stream_decrypt(State0,Data), + {Ssh#ssh{decrypt_ctx = State}, Enc}; +decrypt(#ssh{decrypt = 'aes192-ctr', + decrypt_ctx = State0} = Ssh, Data) -> + {State, Enc} = crypto:stream_decrypt(State0,Data), + {Ssh#ssh{decrypt_ctx = State}, Enc}; +decrypt(#ssh{decrypt = 'aes256-ctr', + decrypt_ctx = State0} = Ssh, Data) -> + {State, Enc} = crypto:stream_decrypt(State0,Data), {Ssh#ssh{decrypt_ctx = State}, Enc}. + +next_gcm_iv(<<Fixed:32, InvCtr:64>>) -> <<Fixed:32, (InvCtr+1):64>>. + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Compression %% @@ -944,49 +1478,54 @@ decompress(#ssh{decompress = '[email protected]', decompress_ctx = Context, authe {Ssh, list_to_binary(Decompressed)}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% MAC calculation %% -%% hmac-sha1 REQUIRED HMAC-SHA1 (digest length = key -%% length = 20) -%% hmac-sha1-96 RECOMMENDED first 96 bits of HMAC-SHA1 (digest -%% length = 12, key length = 20) -%% hmac-md5 OPTIONAL HMAC-MD5 (digest length = key -%% length = 16) -%% hmac-md5-96 OPTIONAL first 96 bits of HMAC-MD5 (digest -%% length = 12, key length = 16) -%% none OPTIONAL no MAC; NOT RECOMMENDED +%% MAC calculation %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% send_mac_init(SSH) -> - case SSH#ssh.role of - client -> - KeySize =mac_key_size(SSH#ssh.send_mac), - Key = hash(SSH, "E", KeySize), - {ok, SSH#ssh { send_mac_key = Key }}; - server -> - KeySize = mac_key_size(SSH#ssh.send_mac), - Key = hash(SSH, "F", KeySize), - {ok, SSH#ssh { send_mac_key = Key }} + case pkt_type(SSH#ssh.send_mac) of + common -> + case SSH#ssh.role of + client -> + KeySize = mac_key_size(SSH#ssh.send_mac), + Key = hash(SSH, "E", KeySize), + {ok, SSH#ssh { send_mac_key = Key }}; + server -> + KeySize = mac_key_size(SSH#ssh.send_mac), + Key = hash(SSH, "F", KeySize), + {ok, SSH#ssh { send_mac_key = Key }} + end; + aead -> + %% Not applicable + {ok, SSH} end. send_mac_final(SSH) -> - {ok, SSH#ssh { send_mac = none, send_mac_key = undefined }}. + {ok, SSH#ssh {send_mac = none, + send_mac_key = undefined }}. + recv_mac_init(SSH) -> - case SSH#ssh.role of - client -> - Key = hash(SSH, "F", mac_key_size(SSH#ssh.recv_mac)), - {ok, SSH#ssh { recv_mac_key = Key }}; - server -> - Key = hash(SSH, "E", mac_key_size(SSH#ssh.recv_mac)), - {ok, SSH#ssh { recv_mac_key = Key }} + case pkt_type(SSH#ssh.recv_mac) of + common -> + case SSH#ssh.role of + client -> + Key = hash(SSH, "F", mac_key_size(SSH#ssh.recv_mac)), + {ok, SSH#ssh { recv_mac_key = Key }}; + server -> + Key = hash(SSH, "E", mac_key_size(SSH#ssh.recv_mac)), + {ok, SSH#ssh { recv_mac_key = Key }} + end; + aead -> + %% Not applicable + {ok, SSH} end. recv_mac_final(SSH) -> {ok, SSH#ssh { recv_mac = none, recv_mac_key = undefined }}. -mac(none, _ , _, _) -> +mac(none, _ , _, _) -> <<>>; mac('hmac-sha1', Key, SeqNum, Data) -> crypto:hmac(sha, Key, [<<?UINT32(SeqNum)>>, Data]); @@ -997,7 +1536,9 @@ mac('hmac-md5', Key, SeqNum, Data) -> mac('hmac-md5-96', Key, SeqNum, Data) -> crypto:hmac(md5, Key, [<<?UINT32(SeqNum)>>, Data], mac_digest_size('hmac-md5-96')); mac('hmac-sha2-256', Key, SeqNum, Data) -> - crypto:hmac(sha256, Key, [<<?UINT32(SeqNum)>>, Data]). + crypto:hmac(sha256, Key, [<<?UINT32(SeqNum)>>, Data]); +mac('hmac-sha2-512', Key, SeqNum, Data) -> + crypto:hmac(sha512, Key, [<<?UINT32(SeqNum)>>, Data]). %% return N hash bytes (HASH) hash(SSH, Char, Bits) -> @@ -1005,8 +1546,20 @@ hash(SSH, Char, Bits) -> case SSH#ssh.kex of 'diffie-hellman-group1-sha1' -> fun(Data) -> crypto:hash(sha, Data) end; + 'diffie-hellman-group14-sha1' -> + fun(Data) -> crypto:hash(sha, Data) end; + 'diffie-hellman-group-exchange-sha1' -> fun(Data) -> crypto:hash(sha, Data) end; + 'diffie-hellman-group-exchange-sha256' -> + fun(Data) -> crypto:hash(sha256, Data) end; + + 'ecdh-sha2-nistp256' -> + fun(Data) -> crypto:hash(sha256,Data) end; + 'ecdh-sha2-nistp384' -> + fun(Data) -> crypto:hash(sha384,Data) end; + 'ecdh-sha2-nistp521' -> + fun(Data) -> crypto:hash(sha512,Data) end; _ -> exit({bad_algorithm,SSH#ssh.kex}) end, @@ -1030,22 +1583,36 @@ hash(K, H, Ki, N, HASH) -> hash(K, H, <<Ki/binary, Kj/binary>>, N-128, HASH). kex_h(SSH, Key, E, F, K) -> + KeyBin = public_key:ssh_encode(Key, ssh2_pubkey), L = ssh_bits:encode([SSH#ssh.c_version, SSH#ssh.s_version, SSH#ssh.c_keyinit, SSH#ssh.s_keyinit, - ssh_message:encode_host_key(Key), E,F,K], + KeyBin, E,F,K], [string,string,binary,binary,binary, mpint,mpint,mpint]), - crypto:hash(sha,L). - + crypto:hash(sha((SSH#ssh.algorithms)#alg.kex), L). +%% crypto:hash(sha,L). + +kex_h(SSH, Curve, Key, Q_c, Q_s, K) -> + KeyBin = public_key:ssh_encode(Key, ssh2_pubkey), + L = ssh_bits:encode([SSH#ssh.c_version, SSH#ssh.s_version, + SSH#ssh.c_keyinit, SSH#ssh.s_keyinit, + KeyBin, Q_c, Q_s, K], + [string,string,binary,binary,binary, + mpint,mpint,mpint]), + crypto:hash(sha(Curve), L). kex_h(SSH, Key, Min, NBits, Max, Prime, Gen, E, F, K) -> + KeyBin = public_key:ssh_encode(Key, ssh2_pubkey), L = if Min==-1; Max==-1 -> + %% flag from 'ssh_msg_kex_dh_gex_request_old' + %% It was like this before that message was supported, + %% why? Ts = [string,string,binary,binary,binary, uint32, mpint,mpint,mpint,mpint,mpint], ssh_bits:encode([SSH#ssh.c_version,SSH#ssh.s_version, SSH#ssh.c_keyinit,SSH#ssh.s_keyinit, - ssh_message:encode_host_key(Key), NBits, Prime, Gen, E,F,K], + KeyBin, NBits, Prime, Gen, E,F,K], Ts); true -> Ts = [string,string,binary,binary,binary, @@ -1053,16 +1620,30 @@ kex_h(SSH, Key, Min, NBits, Max, Prime, Gen, E, F, K) -> mpint,mpint,mpint,mpint,mpint], ssh_bits:encode([SSH#ssh.c_version,SSH#ssh.s_version, SSH#ssh.c_keyinit,SSH#ssh.s_keyinit, - ssh_message:encode_host_key(Key), Min, NBits, Max, + KeyBin, Min, NBits, Max, Prime, Gen, E,F,K], Ts) end, - crypto:hash(sha,L). + crypto:hash(sha((SSH#ssh.algorithms)#alg.kex), L). + +sha(secp256r1) -> sha256; +sha(secp384r1) -> sha384; +sha(secp521r1) -> sha512; +sha('diffie-hellman-group1-sha1') -> sha; +sha('diffie-hellman-group14-sha1') -> sha; +sha('diffie-hellman-group-exchange-sha1') -> sha; +sha('diffie-hellman-group-exchange-sha256') -> sha256; +sha(?'secp256r1') -> sha(secp256r1); +sha(?'secp384r1') -> sha(secp384r1); +sha(?'secp521r1') -> sha(secp521r1). + + mac_key_size('hmac-sha1') -> 20*8; mac_key_size('hmac-sha1-96') -> 20*8; mac_key_size('hmac-md5') -> 16*8; mac_key_size('hmac-md5-96') -> 16*8; mac_key_size('hmac-sha2-256')-> 32*8; +mac_key_size('hmac-sha2-512')-> 512; mac_key_size(none) -> 0. mac_digest_size('hmac-sha1') -> 20; @@ -1070,6 +1651,9 @@ mac_digest_size('hmac-sha1-96') -> 12; mac_digest_size('hmac-md5') -> 20; mac_digest_size('hmac-md5-96') -> 12; mac_digest_size('hmac-sha2-256') -> 32; +mac_digest_size('hmac-sha2-512') -> 64; +mac_digest_size('AEAD_AES_128_GCM') -> 16; +mac_digest_size('AEAD_AES_256_GCM') -> 16; mac_digest_size(none) -> 0. peer_name({Host, _}) -> @@ -1081,12 +1665,91 @@ peer_name({Host, _}) -> %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -dh_group1() -> - {2, 16#FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF}. +dh_group('diffie-hellman-group1-sha1') -> ?dh_group1; +dh_group('diffie-hellman-group14-sha1') -> ?dh_group14. + +%%%---------------------------------------------------------------- +generate_key(Algorithm, Args) -> + {Public,Private} = crypto:generate_key(Algorithm, Args), + {crypto:bytes_to_integer(Public), crypto:bytes_to_integer(Private)}. + + +compute_key(Algorithm, OthersPublic, MyPrivate, Args) -> + Shared = crypto:compute_key(Algorithm, OthersPublic, MyPrivate, Args), + crypto:bytes_to_integer(Shared). + + +ecdh_curve('ecdh-sha2-nistp256') -> secp256r1; +ecdh_curve('ecdh-sha2-nistp384') -> secp384r1; +ecdh_curve('ecdh-sha2-nistp521') -> secp521r1. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% Utils for default_algorithms/1 and supported_algorithms/1 +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +supported_algorithms(Key, [{client2server,BL1},{server2client,BL2}]) -> + [{client2server,As1},{server2client,As2}] = supported_algorithms(Key), + [{client2server,As1--BL1},{server2client,As2--BL2}]; +supported_algorithms(Key, BlackList) -> + supported_algorithms(Key) -- BlackList. + + +select_crypto_supported(L) -> + Sup = [{ec_curve,crypto_supported_curves()} | crypto:supports()], + [Name || {Name,CryptoRequires} <- L, + crypto_supported(CryptoRequires, Sup)]. + +crypto_supported_curves() -> + try crypto:ec_curves() + catch _:_ -> [] + end. + +crypto_supported(Conditions, Supported) -> + lists:all( fun({Tag,CryptoName}) when is_atom(CryptoName) -> + crypto_name_supported(Tag,CryptoName,Supported); + ({Tag,{Name,Len}}) when is_integer(Len) -> + crypto_name_supported(Tag,Name,Supported) andalso + len_supported(Name,Len) + end, Conditions). + +crypto_name_supported(Tag, CryptoName, Supported) -> + lists:member(CryptoName, proplists:get_value(Tag,Supported,[])). + +len_supported(Name, Len) -> + try + case Name of + aes_ctr -> + {_, <<_/binary>>} = + %% Test encryption + crypto:stream_encrypt(crypto:stream_init(Name, <<0:Len>>, <<0:128>>), <<"">>); + aes_gcm -> + {<<_/binary>>, <<_/binary>>} = + crypto:block_encrypt(Name, + _Key = <<0:Len>>, + _IV = <<0:12/unsigned-unit:8>>, + {<<"AAD">>,"PT"}) + end + of + _ -> true + catch + _:_ -> false + end. + + +same(Algs) -> [{client2server,Algs}, {server2client,Algs}]. + + +%% default_algorithms(kex) -> % Example of how to disable an algorithm +%% supported_algorithms(kex, ['ecdh-sha2-nistp521']); -dh_gen_key(G, P, _) -> - {Public, Private} = crypto:generate_key(dh, [P, G]), - {crypto:bytes_to_integer(Private), crypto:bytes_to_integer(Public)}. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% Other utils +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% trim_tail(Str) -> lists:reverse(trim_head(lists:reverse(Str))). diff --git a/lib/ssh/src/ssh_transport.hrl b/lib/ssh/src/ssh_transport.hrl index 2faf8a9316..fd43326f0d 100644 --- a/lib/ssh/src/ssh_transport.hrl +++ b/lib/ssh/src/ssh_transport.hrl @@ -29,9 +29,12 @@ -define(DEFAULT_CLIENT_VERSION, {2, 0}). -define(DEFAULT_SERVER_VERSION, {2, 0}). --define(DEFAULT_DH_GROUP_MIN, 512). --define(DEFAULT_DH_GROUP_NBITS, 1024). --define(DEFAULT_DH_GROUP_MAX, 4096). + +-define(MAX_NUM_ALGORITHMS, 200). + +-define(DEFAULT_DH_GROUP_MIN, 1024). +-define(DEFAULT_DH_GROUP_NBITS, 2048). +-define(DEFAULT_DH_GROUP_MAX, 8192). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% @@ -109,8 +112,9 @@ %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% diffie-hellman-group1-sha1 --define(SSH_MSG_KEXDH_INIT, 30). +%% diffie-hellman-group1-sha1 | diffie-hellman-group14-sha1 + +-define(SSH_MSG_KEXDH_INIT, 30). -define(SSH_MSG_KEXDH_REPLY, 31). -record(ssh_msg_kexdh_init, @@ -134,7 +138,7 @@ %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% diffie-hellman-group-exchange-sha1 +%% diffie-hellman-group-exchange-sha1 | diffie-hellman-group-exchange-sha256 -define(SSH_MSG_KEX_DH_GEX_REQUEST_OLD, 30). -define(SSH_MSG_KEX_DH_GEX_REQUEST, 34). -define(SSH_MSG_KEX_DH_GEX_GROUP, 31). @@ -171,7 +175,36 @@ h_sig }). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% KEY ECDH messages +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% ecdh-sha2-nistp256 | ecdh-sha2-nistp384 | ecdh-sha2-nistp521 + +-define(SSH_MSG_KEX_ECDH_INIT, 30). +-define(SSH_MSG_KEX_ECDH_REPLY, 31). + +-record(ssh_msg_kex_ecdh_init, + { + q_c % string (client's ephemeral public key octet string) + }). + +-record(ssh_msg_kex_ecdh_reply, + { + public_host_key, % string (server's public host key) (k_s) + q_s, % string (server's ephemeral public key octet string) + h_sig % string (the signature on the exchange hash) + }). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% %% error codes +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + -define(SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT, 1). -define(SSH_DISCONNECT_PROTOCOL_ERROR, 2). -define(SSH_DISCONNECT_KEY_EXCHANGE_FAILED, 3). @@ -189,48 +222,20 @@ -define(SSH_DISCONNECT_ILLEGAL_USER_NAME, 15). -%%%---------------------------------------------------------------------- -%%% # DH_14_xxx -%%% Description: Oakley group 14 prime numbers and generator. Used in -%%% diffie-hellman-group1-sha1 key exchange method. -%%%---------------------------------------------------------------------- -%%%---------------------------------------------------------------------- -%%% # DH_14_P -%%% Description: Prime for this group -%%%---------------------------------------------------------------------- - --define(DH_14_P, - <<000,000,000,129,000,255,255,255,255,255,255,255,255,201,015,218, - 162,033,104,194,052,196,198,098,139,128,220,028,209,041,002,078, - 008,138,103,204,116,002,011,190,166,059,019,155,034,081,074,008, - 121,142,052,004,221,239,149,025,179,205,058,067,027,048,043,010, - 109,242,095,020,055,079,225,053,109,109,081,194,069,228,133,181, - 118,098,094,126,198,244,076,066,233,166,055,237,107,011,255,092, - 182,244,006,183,237,238,056,107,251,090,137,159,165,174,159,036, - 017,124,075,031,230,073,040,102,081,236,230,083,129,255,255,255, - 255,255,255,255,255>>). - -%%%---------------------------------------------------------------------- -%%% # DH_14_G -%%% Description: Generator for DH_14_P. -%%%---------------------------------------------------------------------- - --define(DH_14_G, <<0,0,0,1,2>>). - -%%%---------------------------------------------------------------------- -%%% # DH_14_Q -%%% Description: Group order (DH_14_P - 1) / 2. -%%%---------------------------------------------------------------------- - --define(DH_14_Q, - <<000,000,000,128,127,255,255,255,255,255,255,255,228,135,237,081, - 016,180,097,026,098,099,049,069,192,110,014,104,148,129,039,004, - 069,051,230,058,001,005,223,083,029,137,205,145,040,165,004,060, - 199,026,002,110,247,202,140,217,230,157,033,141,152,021,133,054, - 249,047,138,027,167,240,154,182,182,168,225,034,242,066,218,187, - 049,047,063,099,122,038,033,116,211,027,246,181,133,255,174,091, - 122,003,091,246,247,028,053,253,173,068,207,210,215,079,146,008, - 190,037,143,243,036,148,051,040,246,115,041,192,255,255,255,255, - 255,255,255,255>>). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% groups +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%% rfc 2489, ch 6.2 +%%% Size 1024 +-define(dh_group1, + {2, 16#FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF}). + +%%% rfc 3526, ch3 +%%% Size 2048 +-define(dh_group14, + {2, 16#FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF}). -endif. % -ifdef(ssh_transport). diff --git a/lib/ssh/src/sshc_sup.erl b/lib/ssh/src/sshc_sup.erl index 8ee6aacfb5..b8275ba1eb 100644 --- a/lib/ssh/src/sshc_sup.erl +++ b/lib/ssh/src/sshc_sup.erl @@ -64,7 +64,7 @@ child_spec(_) -> Name = undefined, % As simple_one_for_one is used. StartFunc = {ssh_connection_handler, start_link, []}, Restart = temporary, - Shutdown = infinity, + Shutdown = 4000, Modules = [ssh_connection_handler], - Type = supervisor, + Type = worker, {Name, StartFunc, Restart, Shutdown, Type, Modules}. diff --git a/lib/ssh/test/Makefile b/lib/ssh/test/Makefile index 6503d5b643..9cd98f069f 100644 --- a/lib/ssh/test/Makefile +++ b/lib/ssh/test/Makefile @@ -32,15 +32,23 @@ VSN=$(GS_VSN) # ---------------------------------------------------- MODULES= \ - ssh_test_lib \ - ssh_sup_SUITE \ + ssh_algorithms_SUITE \ + ssh_options_SUITE \ + ssh_renegotiate_SUITE \ ssh_basic_SUITE \ - ssh_to_openssh_SUITE \ + ssh_benchmark_SUITE \ + ssh_connection_SUITE \ + ssh_protocol_SUITE \ ssh_sftp_SUITE \ ssh_sftpd_SUITE \ ssh_sftpd_erlclient_SUITE \ + ssh_sup_SUITE \ + ssh_to_openssh_SUITE \ ssh_upgrade_SUITE \ - ssh_connection_SUITE \ + ssh_test_lib \ + ssh_key_cb \ + ssh_key_cb_options \ + ssh_trpt_test_lib \ ssh_echo_server \ ssh_peername_sockname_server \ ssh_test_cli \ @@ -120,7 +128,7 @@ release_spec: opt release_tests_spec: opt $(INSTALL_DIR) "$(RELSYSDIR)" $(INSTALL_DATA) $(ERL_FILES) "$(RELSYSDIR)" - $(INSTALL_DATA) ssh.spec ssh.cover "$(RELSYSDIR)" + $(INSTALL_DATA) ssh.spec ssh_bench.spec ssh.cover "$(RELSYSDIR)" $(INSTALL_DATA) $(HRL_FILES_NEEDED_IN_TEST) "$(RELSYSDIR)" chmod -R u+w "$(RELSYSDIR)" @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -) diff --git a/lib/ssh/test/ssh.spec b/lib/ssh/test/ssh.spec index 8de0fe44e4..0076fc275e 100644 --- a/lib/ssh/test/ssh.spec +++ b/lib/ssh/test/ssh.spec @@ -1,7 +1,6 @@ {suites,"../ssh_test",all}. -{skip_cases,"../ssh_test",ssh_ssh_SUITE, - [ssh], - "Current implementation is timingdependent and\nhence will succeed/fail on a whim"}. -{skip_cases,"../ssh_test",ssh_ssh_SUITE, - [ssh_compressed], - "Current implementation is timingdependent hence will succeed/fail on a whim"}. + +{skip_suites, "../ssh_test", [ssh_benchmark_SUITE], + "Benchmarks run separately"}. + + diff --git a/lib/ssh/test/ssh_algorithms_SUITE.erl b/lib/ssh/test/ssh_algorithms_SUITE.erl new file mode 100644 index 0000000000..49ed15698c --- /dev/null +++ b/lib/ssh/test/ssh_algorithms_SUITE.erl @@ -0,0 +1,376 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2015. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +%% + +-module(ssh_algorithms_SUITE). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("ssh/src/ssh_transport.hrl"). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-define(TIMEOUT, 50000). + +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- + +suite() -> + [{ct_hooks,[ts_install_cth]}, + {timetrap,{minutes,10}}]. + +all() -> + %% [{group,kex},{group,cipher}... etc + [{group,C} || C <- tags()]. + + +groups() -> + ErlAlgos = extract_algos(ssh:default_algorithms()), + SshcAlgos = extract_algos(ssh_test_lib:default_algorithms(sshc)), + SshdAlgos = extract_algos(ssh_test_lib:default_algorithms(sshd)), + + DoubleAlgos = + [{Tag, double(Algs)} || {Tag,Algs} <- ErlAlgos, + length(Algs) > 1, + lists:member(Tag, two_way_tags())], + TagGroupSet = + [{Tag, [], group_members_for_tag(Tag,Algs,DoubleAlgos)} + || {Tag,Algs} <- ErlAlgos, + lists:member(Tag,tags()) + ], + + AlgoTcSet = + [{Alg, [parallel], specific_test_cases(Tag,Alg,SshcAlgos,SshdAlgos)} + || {Tag,Algs} <- ErlAlgos ++ DoubleAlgos, + Alg <- Algs], + + TagGroupSet ++ AlgoTcSet. + +tags() -> [kex,cipher,mac,compression]. +two_way_tags() -> [cipher,mac,compression]. + +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + ct:log("os:getenv(\"HOME\") = ~p~n" + "init:get_argument(home) = ~p", + [os:getenv("HOME"), init:get_argument(home)]), + ct:log("~n~n" + "OS ssh:~n=======~n~p~n~n~n" + "Erl ssh:~n========~n~p~n~n~n" + "Installed ssh client:~n=====================~n~p~n~n~n" + "Installed ssh server:~n=====================~n~p~n~n~n" + "Misc values:~n============~n" + " -- Default dh group exchange parameters ({min,def,max}): ~p~n" + " -- dh_default_groups: ~p~n" + " -- Max num algorithms: ~p~n" + ,[os:cmd("ssh -V"), + ssh:default_algorithms(), + ssh_test_lib:default_algorithms(sshc), + ssh_test_lib:default_algorithms(sshd), + {?DEFAULT_DH_GROUP_MIN,?DEFAULT_DH_GROUP_NBITS,?DEFAULT_DH_GROUP_MAX}, + public_key:dh_gex_group_sizes(), + ?MAX_NUM_ALGORITHMS + ]), + ct:log("all() ->~n ~p.~n~ngroups()->~n ~p.~n",[all(),groups()]), + ssh:start(), + [{std_simple_sftp_size,25000} % Sftp transferred data size + | setup_pubkey(Config)]. + +end_per_suite(_Config) -> + ssh:stop(). + + +init_per_group(Group, Config) -> + case lists:member(Group, tags()) of + true -> + %% A tag group + Tag = Group, + ct:comment("==== ~p ====",[Tag]), + Config; + false -> + %% An algorithm group + Tag = proplists:get_value(name, + hd(?config(tc_group_path, Config))), + Alg = Group, + PA = + case split(Alg) of + [_] -> + [Alg]; + [A1,A2] -> + [{client2server,[A1]}, + {server2client,[A2]}] + end, + ct:log("Init tests for tag=~p alg=~p",[Tag,PA]), + PrefAlgs = {preferred_algorithms,[{Tag,PA}]}, + start_std_daemon([PrefAlgs], + [{pref_algs,PrefAlgs} | Config]) + end. + +end_per_group(_Alg, Config) -> + case ?config(srvr_pid,Config) of + Pid when is_pid(Pid) -> + ssh:stop_daemon(Pid), + ct:log("stopped ~p",[?config(srvr_addr,Config)]); + _ -> + ok + end. + + + +init_per_testcase(sshc_simple_exec, Config) -> + start_pubkey_daemon([?config(pref_algs,Config)], Config); + +init_per_testcase(_TC, Config) -> + Config. + + +end_per_testcase(sshc_simple_exec, Config) -> + case ?config(srvr_pid,Config) of + Pid when is_pid(Pid) -> + ssh:stop_daemon(Pid), + ct:log("stopped ~p",[?config(srvr_addr,Config)]); + _ -> + ok + end; +end_per_testcase(_TC, Config) -> + Config. + + +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- +%% A simple sftp transfer +simple_sftp(Config) -> + {Host,Port} = ?config(srvr_addr, Config), + ssh_test_lib:std_simple_sftp(Host, Port, Config). + +%%-------------------------------------------------------------------- +%% A simple exec call +simple_exec(Config) -> + {Host,Port} = ?config(srvr_addr, Config), + ssh_test_lib:std_simple_exec(Host, Port, Config). + +%%-------------------------------------------------------------------- +%% Testing if no group matches +simple_exec_groups_no_match_too_small(Config) -> + try simple_exec_group({400,500,600}, Config) + of + _ -> ct:fail("Exec though no group available") + catch + error:{badmatch,{error,"No possible diffie-hellman-group-exchange group found"}} -> + ok + end. + +simple_exec_groups_no_match_too_large(Config) -> + try simple_exec_group({9200,9500,9700}, Config) + of + _ -> ct:fail("Exec though no group available") + catch + error:{badmatch,{error,"No possible diffie-hellman-group-exchange group found"}} -> + ok + end. + +%%-------------------------------------------------------------------- +%% Testing all default groups +simple_exec_groups(Config) -> + Sizes = interpolate( public_key:dh_gex_group_sizes() ), + lists:foreach( + fun(Sz) -> + ct:log("Try size ~p",[Sz]), + ct:comment(Sz), + case simple_exec_group(Sz, Config) of + expected -> ct:log("Size ~p ok",[Sz]); + _ -> ct:log("Size ~p not ok",[Sz]) + end + end, Sizes), + ct:comment("~p",[lists:map(fun({_,I,_}) -> I; + (I) -> I + end,Sizes)]). + + +interpolate([I1,I2|Is]) -> + OneThird = (I2-I1) div 3, + [I1, + {I1, I1 + OneThird, I2}, + {I1, I1 + 2*OneThird, I2} | interpolate([I2|Is])]; +interpolate(Is) -> + Is. + +%%-------------------------------------------------------------------- +%% Use the ssh client of the OS to connect +sshc_simple_exec(Config) -> + PrivDir = ?config(priv_dir, Config), + KnownHosts = filename:join(PrivDir, "known_hosts"), + {Host,Port} = ?config(srvr_addr, Config), + Cmd = lists:concat(["ssh -p ",Port, + " -C -o UserKnownHostsFile=",KnownHosts, + " ",Host," 1+1."]), + ct:log("~p",[Cmd]), + SshPort = open_port({spawn, Cmd}, [binary]), + Expect = <<"2\n">>, + receive + {SshPort, {data,Expect}} -> + ct:log("Got expected ~p from ~p",[Expect,SshPort]), + catch port_close(SshPort), + ok + after ?TIMEOUT -> + ct:fail("Did not receive answer") + end. + +%%-------------------------------------------------------------------- +%% Connect to the ssh server of the OS +sshd_simple_exec(_Config) -> + ConnectionRef = ssh_test_lib:connect(22, [{silently_accept_hosts, true}, + {user_interaction, false}]), + {ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity), + success = ssh_connection:exec(ConnectionRef, ChannelId0, + "echo testing", infinity), + Data0 = {ssh_cm, ConnectionRef, {data, ChannelId0, 0, <<"testing\n">>}}, + case ssh_test_lib:receive_exec_result(Data0) of + expected -> + ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId0); + {unexpected_msg,{ssh_cm, ConnectionRef, {exit_status, ChannelId0, 0}} + = ExitStatus0} -> + ct:log("0: Collected data ~p", [ExitStatus0]), + ssh_test_lib:receive_exec_result(Data0, + ConnectionRef, ChannelId0); + Other0 -> + ct:fail(Other0) + end, + + {ok, ChannelId1} = ssh_connection:session_channel(ConnectionRef, infinity), + success = ssh_connection:exec(ConnectionRef, ChannelId1, + "echo testing1", infinity), + Data1 = {ssh_cm, ConnectionRef, {data, ChannelId1, 0, <<"testing1\n">>}}, + case ssh_test_lib:receive_exec_result(Data1) of + expected -> + ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId1); + {unexpected_msg,{ssh_cm, ConnectionRef, {exit_status, ChannelId1, 0}} + = ExitStatus1} -> + ct:log("0: Collected data ~p", [ExitStatus1]), + ssh_test_lib:receive_exec_result(Data1, + ConnectionRef, ChannelId1); + Other1 -> + ct:fail(Other1) + end, + ssh:close(ConnectionRef). + + +%%%================================================================ +%%% +%%% Lib functions +%%% + +%%%---------------------------------------------------------------- +%%% +%%% For construction of the result of all/0 and groups/0 +%%% +group_members_for_tag(Tag, Algos, DoubleAlgos) -> + [{group,Alg} || Alg <- Algos++proplists:get_value(Tag,DoubleAlgos,[])]. + +double(Algs) -> [concat(A1,A2) || A1 <- Algs, + A2 <- Algs, + A1 =/= A2]. + +concat(A1, A2) -> list_to_atom(lists:concat([A1," + ",A2])). + +split(Alg) -> ssh_test_lib:to_atoms(string:tokens(atom_to_list(Alg), " + ")). + +specific_test_cases(Tag, Alg, SshcAlgos, SshdAlgos) -> + [simple_exec, simple_sftp] ++ + case supports(Tag, Alg, SshcAlgos) of + true -> + case ssh_test_lib:ssh_type() of + openSSH -> + [sshc_simple_exec]; + _ -> + [] + end; + false -> + [] + end ++ + case supports(Tag, Alg, SshdAlgos) of + true -> + [sshd_simple_exec]; + _ -> + [] + end ++ + case {Tag,Alg} of + {kex,_} when Alg == 'diffie-hellman-group-exchange-sha1' ; + Alg == 'diffie-hellman-group-exchange-sha256' -> + [simple_exec_groups, + simple_exec_groups_no_match_too_large, + simple_exec_groups_no_match_too_small + ]; + _ -> + [] + end. + +supports(Tag, Alg, Algos) -> + lists:all(fun(A) -> + lists:member(A, proplists:get_value(Tag, Algos,[])) + end, + split(Alg)). + + +extract_algos(Spec) -> + [{Tag,get_atoms(List)} || {Tag,List} <- Spec]. + +get_atoms(L) -> + lists:usort( + [ A || X <- L, + A <- case X of + {_,L1} when is_list(L1) -> L1; + Y when is_atom(Y) -> [Y] + end]). + +%%%---------------------------------------------------------------- +%%% +%%% Test case related +%%% +start_std_daemon(Opts, Config) -> + {Pid, Host, Port} = ssh_test_lib:std_daemon(Config, Opts), + ct:log("started ~p:~p ~p",[Host,Port,Opts]), + [{srvr_pid,Pid},{srvr_addr,{Host,Port}} | Config]. + +start_pubkey_daemon(Opts, Config) -> + {Pid, Host, Port} = ssh_test_lib:std_daemon1(Config, Opts), + ct:log("started1 ~p:~p ~p",[Host,Port,Opts]), + [{srvr_pid,Pid},{srvr_addr,{Host,Port}} | Config]. + + +setup_pubkey(Config) -> + DataDir = ?config(data_dir, Config), + UserDir = ?config(priv_dir, Config), + ssh_test_lib:setup_dsa(DataDir, UserDir), + ssh_test_lib:setup_rsa(DataDir, UserDir), + ssh_test_lib:setup_ecdsa("256", DataDir, UserDir), + Config. + + +simple_exec_group(I, Config) when is_integer(I) -> + simple_exec_group({I,I,I}, Config); +simple_exec_group({Min,I,Max}, Config) -> + {Host,Port} = ?config(srvr_addr, Config), + ssh_test_lib:std_simple_exec(Host, Port, Config, + [{dh_gex_limits,{Min,I,Max}}]). + diff --git a/lib/ssh/test/ssh_algorithms_SUITE_data/id_dsa b/lib/ssh/test/ssh_algorithms_SUITE_data/id_dsa new file mode 100644 index 0000000000..d306f8b26e --- /dev/null +++ b/lib/ssh/test/ssh_algorithms_SUITE_data/id_dsa @@ -0,0 +1,13 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBvAIBAAKBgQDfi2flSTZZofwT4yQT0NikX/LGNT7UPeB/XEWe/xovEYCElfaQ +APFixXvEgXwoojmZ5kiQRKzLM39wBP0jPERLbnZXfOOD0PDnw0haMh7dD7XKVMod +/EigVgHf/qBdM2M8yz1s/rRF7n1UpLSypziKjkzCm7JoSQ2zbWIPdmBIXwIVAMgP +kpr7Sq3O7sHdb8D601DRjoExAoGAMOQxDfB2Fd8ouz6G96f/UOzRMI/Kdv8kYYKW +JIGY+pRYrLPyYzUeJznwZreOJgrczAX+luHnKFWJ2Dnk5CyeXk67Wsr7pJ/4MBMD +OKeIS0S8qoSBN8+Krp79fgA+yS3IfqbkJLtLu4EBaCX4mKQIX4++k44d4U5lc8pt ++9hlEI8CgYEAznKxx9kyC6bVo7LUYKaGhofRFt0SYFc5PVmT2VUGRs1R6+6DPD+e +uEO6IhFct7JFSRbP9p0JD4Uk+3zlZF+XX6b2PsZkeV8f/02xlNGUSmEzCSiNg1AX +Cy/WusYhul0MncWCHMcOZB5rIvU/aP5EJJtn3xrRaz6u0SThF6AnT34CFQC63czE +ZU8w8Q+H7z0j+a+70x2iAw== +-----END DSA PRIVATE KEY----- + diff --git a/lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa b/lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa new file mode 100644 index 0000000000..4b1eb12eaa --- /dev/null +++ b/lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIJfCaBKIIKhjbJl5F8BedqlXOQYDX5ba9Skypllmx/w+oAoGCCqGSM49 +AwEHoUQDQgAE49RbK2xQ/19ji3uDPM7uT4692LbwWF1TiaA9vUuebMGazoW/98br +N9xZu0L1AWwtEjs3kmJDTB7eJEGXnjUAcQ== +-----END EC PRIVATE KEY----- diff --git a/lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa.pub b/lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa.pub new file mode 100644 index 0000000000..a0147e60fa --- /dev/null +++ b/lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOPUWytsUP9fY4t7gzzO7k+Ovdi28FhdU4mgPb1LnmzBms6Fv/fG6zfcWbtC9QFsLRI7N5JiQ0we3iRBl541AHE= uabhnil@elxadlj3q32 diff --git a/lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa256 b/lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa256 new file mode 100644 index 0000000000..4b1eb12eaa --- /dev/null +++ b/lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa256 @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIJfCaBKIIKhjbJl5F8BedqlXOQYDX5ba9Skypllmx/w+oAoGCCqGSM49 +AwEHoUQDQgAE49RbK2xQ/19ji3uDPM7uT4692LbwWF1TiaA9vUuebMGazoW/98br +N9xZu0L1AWwtEjs3kmJDTB7eJEGXnjUAcQ== +-----END EC PRIVATE KEY----- diff --git a/lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa256.pub b/lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa256.pub new file mode 100644 index 0000000000..a0147e60fa --- /dev/null +++ b/lib/ssh/test/ssh_algorithms_SUITE_data/id_ecdsa256.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOPUWytsUP9fY4t7gzzO7k+Ovdi28FhdU4mgPb1LnmzBms6Fv/fG6zfcWbtC9QFsLRI7N5JiQ0we3iRBl541AHE= uabhnil@elxadlj3q32 diff --git a/lib/ssh/test/ssh_algorithms_SUITE_data/id_rsa b/lib/ssh/test/ssh_algorithms_SUITE_data/id_rsa new file mode 100644 index 0000000000..9d7e0dd5fb --- /dev/null +++ b/lib/ssh/test/ssh_algorithms_SUITE_data/id_rsa @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQD1OET+3O/Bvj/dtjxDTXmj1oiJt4sIph5kGy0RfjoPrZfaS+CU +DhakCmS6t2ivxWFgtpKWaoGMZMJqWj6F6ZsumyFl3FPBtujwY/35cgifrI9Ns4Tl +zR1uuengNBmV+WRQ5cd9F2qS6Z8aDQihzt0r8JUqLcK+VQbrmNzboCCQQwIDAQAB +AoGAPQEyqPTt8JUT7mRXuaacjFXiweAXhp9NEDpyi9eLOjtFe9lElZCrsUOkq47V +TGUeRKEm9qSodfTbKPoqc8YaBJGJPhUaTAcha+7QcDdfHBvIsgxvU7ePVnlpXRp3 +CCUEMPhlnx6xBoTYP+fRU0e3+xJIPVyVCqX1jAdUMkzfRoECQQD6ux7B1QJAIWyK +SGkbDUbBilNmzCFNgIpOP6PA+bwfi5d16diTpra5AX09keQABAo/KaP1PdV8Vg0p +z4P3A7G3AkEA+l+AKG6m0kQTTBMJDqOdVPYwe+5GxunMaqmhokpEbuGsrZBl5Dvd +WpcBjR7jmenrhKZRIuA+Fz5HPo/UQJPl1QJBAKxstDkeED8j/S2XoFhPKAJ+6t39 +sUVICVTIZQeXdmzHJXCcUSkw8+WEhakqw/3SyW0oaK2FSWQJFWJUZ+8eJj8CQEh3 +xeduB5kKnS9CvzdeghZqX6QvVosSdtlUmfUYW/BgH5PpHKTP8wTaeld3XldZTpMJ +dKiMkUw2+XYROVUrubUCQD+Na1LhULlpn4ISEtIEfqpdlUhxDgO15Wg8USmsng+x +ICliVOSQtwaZjm8kwaFt0W7XnpnDxbRs37vIEbIMWak= +-----END RSA PRIVATE KEY----- diff --git a/lib/ssh/test/ssh_unicode_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_dsa_key index 51ab6fbd88..51ab6fbd88 100644 --- a/lib/ssh/test/ssh_unicode_SUITE_data/ssh_host_dsa_key +++ b/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_dsa_key diff --git a/lib/ssh/test/ssh_unicode_SUITE_data/ssh_host_dsa_key.pub b/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_dsa_key.pub index 4dbb1305b0..4dbb1305b0 100644 --- a/lib/ssh/test/ssh_unicode_SUITE_data/ssh_host_dsa_key.pub +++ b/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_dsa_key.pub diff --git a/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ecdsa_key256 b/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ecdsa_key256 new file mode 100644 index 0000000000..2979ea88ed --- /dev/null +++ b/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ecdsa_key256 @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIMe4MDoit0t8RzSVPwkCBemQ9fhXL+xnTSAWISw8HNCioAoGCCqGSM49 +AwEHoUQDQgAEo2q7U3P6r0W5WGOLtM78UQtofM9UalEhiZeDdiyylsR/RR17Op0s +VPGSADLmzzgcucLEKy17j2S+oz42VUJy5A== +-----END EC PRIVATE KEY----- diff --git a/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ecdsa_key256.pub b/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ecdsa_key256.pub new file mode 100644 index 0000000000..85dc419345 --- /dev/null +++ b/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ecdsa_key256.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKNqu1Nz+q9FuVhji7TO/FELaHzPVGpRIYmXg3YsspbEf0UdezqdLFTxkgAy5s84HLnCxCste49kvqM+NlVCcuQ= uabhnil@elxadlj3q32 diff --git a/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_rsa_key b/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_rsa_key new file mode 100644 index 0000000000..79968bdd7d --- /dev/null +++ b/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_rsa_key @@ -0,0 +1,16 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8semM4q843337 +zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RWRWzjaxSB +6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4QIDAQAB +AoGANmvJzJO5hkLuvyDZHKfAnGTtpifcR1wtSa9DjdKUyn8vhKF0mIimnbnYQEmW +NUUb3gXCZLi9PvkpRSVRrASDOZwcjoU/Kvww163vBUVb2cOZfFhyn6o2Sk88Tt++ +udH3hdjpf9i7jTtUkUe+QYPsia+wgvvrmn4QrahLAH86+kECQQDx5gFeXTME3cnW +WMpFz3PPumduzjqgqMMWEccX4FtQkMX/gyGa5UC7OHFyh0N/gSWvPbRHa8A6YgIt +n8DO+fh5AkEAzbqX4DOn8NY6xJIi42q7l/2jIA0RkB6P7YugW5NblhqBZ0XDnpA5 +sMt+rz+K07u9XZtxgh1xi7mNfwY6lEAMqQJBAJBEauCKmRj35Z6OyeQku59SPsnY ++SJEREVvSNw2lH9SOKQQ4wPsYlTGbvKtNVZgAcen91L5MmYfeckYE/fdIZECQQCt +64zxsTnM1I8iFxj/gP/OYlJBikrKt8udWmjaghzvLMEw+T2DExJyb9ZNeT53+UMB +m6O+B/4xzU/djvp+0hbhAkAemIt+rA5kTmYlFndhpvzkSSM8a2EXsO4XIPgGWCTT +tQKS/tTly0ADMjN/TVy11+9d6zcqadNVuHXHGtR4W0GR +-----END RSA PRIVATE KEY----- + diff --git a/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_rsa_key.pub b/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_rsa_key.pub new file mode 100644 index 0000000000..75d2025c71 --- /dev/null +++ b/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_rsa_key.pub @@ -0,0 +1,5 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +AAAAB3NzaC1yc2EAAAADAQABAAAAgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8 +semM4q843337zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RW +RWzjaxSB6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4Q== +---- END SSH2 PUBLIC KEY ---- diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl index 2b3fadbbf4..96d424dc98 100644 --- a/lib/ssh/test/ssh_basic_SUITE.erl +++ b/lib/ssh/test/ssh_basic_SUITE.erl @@ -27,97 +27,127 @@ -include_lib("kernel/include/file.hrl"). %% Note: This directive should only be used in test suites. --compile(export_all). +%%-compile(export_all). + +%%% Test cases +-export([ + app_test/1, + appup_test/1, + cli/1, + close/1, + daemon_already_started/1, + daemon_opt_fd/1, + multi_daemon_opt_fd/1, + double_close/1, + exec/1, + exec_compressed/1, + exec_key_differs1/1, + exec_key_differs2/1, + exec_key_differs3/1, + exec_key_differs_fail/1, + idle_time/1, + inet6_option/1, + inet_option/1, + internal_error/1, + known_hosts/1, + login_bad_pwd_no_retry1/1, + login_bad_pwd_no_retry2/1, + login_bad_pwd_no_retry3/1, + login_bad_pwd_no_retry4/1, + login_bad_pwd_no_retry5/1, + misc_ssh_options/1, + openssh_zlib_basic_test/1, + packet_size_zero/1, + pass_phrase/1, + peername_sockname/1, + send/1, + shell/1, + shell_no_unicode/1, + shell_unicode_string/1, + ssh_info_print/1, + key_callback/1, + key_callback_options/1 + ]). + +%%% Common test callbacks +-export([suite/0, all/0, groups/0, + init_per_suite/1, end_per_suite/1, + init_per_group/2, end_per_group/2, + init_per_testcase/2, end_per_testcase/2 + ]). -define(NEWLINE, <<"\r\n">>). --define(REKEY_DATA_TMO, 65000). %%-------------------------------------------------------------------- %% Common Test interface functions ----------------------------------- %%-------------------------------------------------------------------- suite() -> - [{ct_hooks,[ts_install_cth]}]. + [{ct_hooks,[ts_install_cth]}, + {timetrap,{minutes,10}}]. all() -> [app_test, appup_test, {group, dsa_key}, {group, rsa_key}, + {group, ecdsa_sha2_nistp256_key}, + {group, ecdsa_sha2_nistp384_key}, + {group, ecdsa_sha2_nistp521_key}, {group, dsa_pass_key}, {group, rsa_pass_key}, + {group, host_user_key_differs}, + {group, key_cb}, {group, internal_error}, - connectfun_disconnectfun_server, - connectfun_disconnectfun_client, - {group, renegotiate}, daemon_already_started, - server_password_option, - server_userpassword_option, - {group, dir_options}, double_close, - ssh_connect_timeout, - ssh_connect_arg4_timeout, + daemon_opt_fd, + multi_daemon_opt_fd, packet_size_zero, - ssh_daemon_minimal_remote_max_packet_size_option, - ssh_msg_debug_fun_option_client, - ssh_msg_debug_fun_option_server, - disconnectfun_option_server, - disconnectfun_option_client, - unexpectedfun_option_server, - unexpectedfun_option_client, - preferred_algorithms, - id_string_no_opt_client, - id_string_own_string_client, - id_string_random_client, - id_string_no_opt_server, - id_string_own_string_server, - id_string_random_server, - {group, hardening_tests}, - ssh_info_print + ssh_info_print, + {group, login_bad_pwd_no_retry} ]. groups() -> [{dsa_key, [], basic_tests()}, {rsa_key, [], basic_tests()}, + {ecdsa_sha2_nistp256_key, [], basic_tests()}, + {ecdsa_sha2_nistp384_key, [], basic_tests()}, + {ecdsa_sha2_nistp521_key, [], basic_tests()}, + {host_user_key_differs, [], [exec_key_differs1, + exec_key_differs2, + exec_key_differs3, + exec_key_differs_fail]}, {dsa_pass_key, [], [pass_phrase]}, {rsa_pass_key, [], [pass_phrase]}, + {key_cb, [], [key_callback, key_callback_options]}, {internal_error, [], [internal_error]}, - {renegotiate, [], [rekey, rekey_limit, renegotiate1, renegotiate2]}, - {hardening_tests, [], [ssh_connect_nonegtimeout_connected_parallel, - ssh_connect_nonegtimeout_connected_sequential, - ssh_connect_negtimeout_parallel, - ssh_connect_negtimeout_sequential, - max_sessions_ssh_connect_parallel, - max_sessions_ssh_connect_sequential, - max_sessions_sftp_start_channel_parallel, - max_sessions_sftp_start_channel_sequential - ]}, - {dir_options, [], [user_dir_option, - system_dir_option]} + {login_bad_pwd_no_retry, [], [login_bad_pwd_no_retry1, + login_bad_pwd_no_retry2, + login_bad_pwd_no_retry3, + login_bad_pwd_no_retry4, + login_bad_pwd_no_retry5 + ]} ]. basic_tests() -> [send, close, peername_sockname, - exec, exec_compressed, shell, cli, known_hosts, - idle_time, openssh_zlib_basic_test, misc_ssh_options, inet_option]. + exec, exec_compressed, + shell, shell_no_unicode, shell_unicode_string, + cli, known_hosts, + idle_time, openssh_zlib_basic_test, + misc_ssh_options, inet_option, inet6_option]. %%-------------------------------------------------------------------- init_per_suite(Config) -> - catch crypto:stop(), - case catch crypto:start() of - ok -> - Config; - _Else -> - {skip, "Crypto could not be started!"} - end. + Config. + end_per_suite(_Config) -> - ssh:stop(), - crypto:stop(). + ssh:stop(). + %%-------------------------------------------------------------------- -init_per_group(hardening_tests, Config) -> - init_per_group(dsa_key, Config); init_per_group(dsa_key, Config) -> DataDir = ?config(data_dir, Config), PrivDir = ?config(priv_dir, Config), @@ -128,6 +158,39 @@ init_per_group(rsa_key, Config) -> PrivDir = ?config(priv_dir, Config), ssh_test_lib:setup_rsa(DataDir, PrivDir), Config; +init_per_group(ecdsa_sha2_nistp256_key, Config) -> + case lists:member('ecdsa-sha2-nistp256', + ssh_transport:default_algorithms(public_key)) of + true -> + DataDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + ssh_test_lib:setup_ecdsa("256", DataDir, PrivDir), + Config; + false -> + {skip, unsupported_pub_key} + end; +init_per_group(ecdsa_sha2_nistp384_key, Config) -> + case lists:member('ecdsa-sha2-nistp384', + ssh_transport:default_algorithms(public_key)) of + true -> + DataDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + ssh_test_lib:setup_ecdsa("384", DataDir, PrivDir), + Config; + false -> + {skip, unsupported_pub_key} + end; +init_per_group(ecdsa_sha2_nistp521_key, Config) -> + case lists:member('ecdsa-sha2-nistp521', + ssh_transport:default_algorithms(public_key)) of + true -> + DataDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + ssh_test_lib:setup_ecdsa("521", DataDir, PrivDir), + Config; + false -> + {skip, unsupported_pub_key} + end; init_per_group(rsa_pass_key, Config) -> DataDir = ?config(data_dir, Config), PrivDir = ?config(priv_dir, Config), @@ -138,6 +201,26 @@ init_per_group(dsa_pass_key, Config) -> PrivDir = ?config(priv_dir, Config), ssh_test_lib:setup_dsa_pass_pharse(DataDir, PrivDir, "Password"), [{pass_phrase, {dsa_pass_phrase, "Password"}}| Config]; +init_per_group(host_user_key_differs, Config) -> + Data = ?config(data_dir, Config), + Sys = filename:join(?config(priv_dir, Config), system_rsa), + SysUsr = filename:join(Sys, user), + Usr = filename:join(?config(priv_dir, Config), user_ecdsa_256), + file:make_dir(Sys), + file:make_dir(SysUsr), + file:make_dir(Usr), + file:copy(filename:join(Data, "ssh_host_rsa_key"), filename:join(Sys, "ssh_host_rsa_key")), + file:copy(filename:join(Data, "ssh_host_rsa_key.pub"), filename:join(Sys, "ssh_host_rsa_key.pub")), + file:copy(filename:join(Data, "id_ecdsa256"), filename:join(Usr, "id_ecdsa")), + file:copy(filename:join(Data, "id_ecdsa256.pub"), filename:join(Usr, "id_ecdsa.pub")), + ssh_test_lib:setup_ecdsa_auth_keys("256", Usr, SysUsr), + ssh_test_lib:setup_rsa_known_host(Sys, Usr), + Config; +init_per_group(key_cb, Config) -> + DataDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + ssh_test_lib:setup_dsa(DataDir, PrivDir), + Config; init_per_group(internal_error, Config) -> DataDir = ?config(data_dir, Config), PrivDir = ?config(priv_dir, Config), @@ -189,8 +272,6 @@ init_per_group(dir_options, Config) -> init_per_group(_, Config) -> Config. -end_per_group(hardening_tests, Config) -> - end_per_group(dsa_key, Config); end_per_group(dsa_key, Config) -> PrivDir = ?config(priv_dir, Config), ssh_test_lib:clean_dsa(PrivDir), @@ -207,6 +288,10 @@ end_per_group(rsa_pass_key, Config) -> PrivDir = ?config(priv_dir, Config), ssh_test_lib:clean_rsa(PrivDir), Config; +end_per_group(key_cb, Config) -> + PrivDir = ?config(priv_dir, Config), + ssh_test_lib:clean_dsa(PrivDir), + Config; end_per_group(internal_error, Config) -> PrivDir = ?config(priv_dir, Config), ssh_test_lib:clean_dsa(PrivDir), @@ -215,6 +300,33 @@ end_per_group(internal_error, Config) -> end_per_group(_, Config) -> Config. %%-------------------------------------------------------------------- +init_per_testcase(TC, Config) when TC==shell_no_unicode ; + TC==shell_unicode_string -> + PrivDir = ?config(priv_dir, Config), + UserDir = ?config(priv_dir, Config), + SysDir = ?config(data_dir, Config), + ssh:start(), + Sftpd = {_Pid, _Host, Port} = + ssh_test_lib:daemon([{system_dir, SysDir}, + {user_dir, PrivDir}, + {user_passwords, [{"foo", "bar"}]}]), + ct:sleep(500), + IO = ssh_test_lib:start_io_server(), + Shell = ssh_test_lib:start_shell(Port, IO, UserDir, + [{silently_accept_hosts, true}, + {user,"foo"},{password,"bar"}]), + ct:log("IO=~p, Shell=~p, self()=~p",[IO,Shell,self()]), + ct:log("file:native_name_encoding() = ~p,~nio:getopts() = ~p", + [file:native_name_encoding(),io:getopts()]), + wait_for_erlang_first_line([{io,IO}, {shell,Shell}, {sftpd, Sftpd} | Config]); + +init_per_testcase(inet6_option, Config) -> + case ssh_test_lib:has_inet6_address() of + true -> + init_per_testcase('__default__', Config); + false -> + {skip,"No ipv6 interface address"} + end; init_per_testcase(_TestCase, Config) -> ssh:start(), Config. @@ -224,6 +336,15 @@ end_per_testcase(TestCase, Config) when TestCase == server_password_option; UserDir = filename:join(?config(priv_dir, Config), nopubkey), ssh_test_lib:del_dirs(UserDir), end_per_testcase(Config); +end_per_testcase(TC, Config) when TC==shell_no_unicode ; + TC==shell_unicode_string -> + case ?config(sftpd, Config) of + {Pid, _, _} -> + ssh:stop_daemon(Pid), + ssh:stop(); + _ -> + ssh:stop() + end; end_per_testcase(_TestCase, Config) -> end_per_testcase(Config). end_per_testcase(_Config) -> @@ -233,21 +354,18 @@ end_per_testcase(_Config) -> %%-------------------------------------------------------------------- %% Test Cases -------------------------------------------------------- %%-------------------------------------------------------------------- -app_test() -> - [{doc, "App lication consistency test."}]. +%%% Application consistency test. app_test(Config) when is_list(Config) -> ?t:app_test(ssh), ok. %%-------------------------------------------------------------------- -appup_test() -> - [{doc, "Appup file consistency test."}]. +%%% Appup file consistency test. appup_test(Config) when is_list(Config) -> ok = ?t:appup_test(ssh). %%-------------------------------------------------------------------- -misc_ssh_options() -> - [{doc, "Test that we can set some misc options not tested elsewhere, " - "some options not yet present are not decided if we should support or " - "if they need thier own test case."}]. +%%% Test that we can set some misc options not tested elsewhere +%%% some options not yet present are not decided if we should support or +%%% if they need thier own test case. misc_ssh_options(Config) when is_list(Config) -> SystemDir = filename:join(?config(priv_dir, Config), system), UserDir = ?config(priv_dir, Config), @@ -261,8 +379,7 @@ misc_ssh_options(Config) when is_list(Config) -> basic_test([{client_opts, CMiscOpt1}, {server_opts, SMiscOpt1}]). %%-------------------------------------------------------------------- -inet_option() -> - [{doc, "Test configuring IPv4"}]. +%%% Test configuring IPv4 inet_option(Config) when is_list(Config) -> SystemDir = filename:join(?config(priv_dir, Config), system), UserDir = ?config(priv_dir, Config), @@ -278,8 +395,7 @@ inet_option(Config) when is_list(Config) -> {server_opts, [{inet, inet} | ServerOpts]}]). %%-------------------------------------------------------------------- -inet6_option() -> - [{doc, "Test configuring IPv6"}]. +%%% Test configuring IPv6 inet6_option(Config) when is_list(Config) -> SystemDir = filename:join(?config(priv_dir, Config), system), UserDir = ?config(priv_dir, Config), @@ -295,8 +411,7 @@ inet6_option(Config) when is_list(Config) -> {server_opts, [{inet, inet6} | ServerOpts]}]). %%-------------------------------------------------------------------- -exec() -> - [{doc, "Test api function ssh_connection:exec"}]. +%%% Test api function ssh_connection:exec exec(Config) when is_list(Config) -> process_flag(trap_exit, true), SystemDir = filename:join(?config(priv_dir, Config), system), @@ -334,40 +449,46 @@ exec(Config) when is_list(Config) -> ct:fail(Other1) end, ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId1), + ssh:close(ConnectionRef), ssh:stop_daemon(Pid). %%-------------------------------------------------------------------- -exec_compressed() -> - [{doc, "Test that compression option works"}]. +%%% Test that compression option works exec_compressed(Config) when is_list(Config) -> - process_flag(trap_exit, true), - SystemDir = filename:join(?config(priv_dir, Config), system), - UserDir = ?config(priv_dir, Config), + case ssh_test_lib:ssh_supports(zlib, compression) of + false -> + {skip, "zlib compression is not supported"}; - {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},{user_dir, UserDir}, - {preferred_algorithms,[{compression, [zlib]}]}, - {failfun, fun ssh_test_lib:failfun/2}]), + true -> + process_flag(trap_exit, true), + SystemDir = filename:join(?config(priv_dir, Config), system), + UserDir = ?config(priv_dir, Config), + + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},{user_dir, UserDir}, + {preferred_algorithms,[{compression, [zlib]}]}, + {failfun, fun ssh_test_lib:failfun/2}]), - ConnectionRef = - ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, - {user_dir, UserDir}, - {user_interaction, false}]), - {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity), - success = ssh_connection:exec(ConnectionRef, ChannelId, - "1+1.", infinity), - Data = {ssh_cm, ConnectionRef, {data, ChannelId, 0, <<"2\n">>}}, - case ssh_test_lib:receive_exec_result(Data) of - expected -> - ok; - Other -> - ct:fail(Other) - end, - ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId), - ssh:stop_daemon(Pid). + ConnectionRef = + ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user_dir, UserDir}, + {user_interaction, false}]), + {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity), + success = ssh_connection:exec(ConnectionRef, ChannelId, + "1+1.", infinity), + Data = {ssh_cm, ConnectionRef, {data, ChannelId, 0, <<"2\n">>}}, + case ssh_test_lib:receive_exec_result(Data) of + expected -> + ok; + Other -> + ct:fail(Other) + end, + ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId), + ssh:close(ConnectionRef), + ssh:stop_daemon(Pid) + end. %%-------------------------------------------------------------------- -idle_time() -> - [{doc, "Idle timeout test"}]. +%%% Idle timeout test idle_time(Config) -> SystemDir = filename:join(?config(priv_dir, Config), system), UserDir = ?config(priv_dir, Config), @@ -387,211 +508,117 @@ idle_time(Config) -> {error, closed} = ssh_connection:session_channel(ConnectionRef, 1000) end, ssh:stop_daemon(Pid). + %%-------------------------------------------------------------------- -rekey() -> - [{doc, "Idle timeout test"}]. -rekey(Config) -> - SystemDir = ?config(data_dir, Config), +%%% Test that ssh:shell/2 works +shell(Config) when is_list(Config) -> + process_flag(trap_exit, true), + SystemDir = filename:join(?config(priv_dir, Config), system), UserDir = ?config(priv_dir, Config), + + {_Pid, _Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},{user_dir, UserDir}, + {failfun, fun ssh_test_lib:failfun/2}]), + ct:sleep(500), - {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, - {user_dir, UserDir}, - {failfun, fun ssh_test_lib:failfun/2}, - {user_passwords, - [{"simon", "says"}]}, - {rekey_limit, 0}]), - - ConnectionRef = - ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, - {user_dir, UserDir}, - {user, "simon"}, - {password, "says"}, - {user_interaction, false}, - {rekey_limit, 0}]), + IO = ssh_test_lib:start_io_server(), + Shell = ssh_test_lib:start_shell(Port, IO, UserDir), receive - after ?REKEY_DATA_TMO -> - %%By this time rekeying would have been done - ssh:close(ConnectionRef), - ssh:stop_daemon(Pid) + {'EXIT', _, _} -> + ct:fail(no_ssh_connection); + ErlShellStart -> + ct:log("Erlang shell start: ~p~n", [ErlShellStart]), + do_shell(IO, Shell) + after + 30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end. -%%-------------------------------------------------------------------- -rekey_limit() -> - [{doc, "Test rekeying by data volume"}]. -rekey_limit(Config) -> - SystemDir = ?config(data_dir, Config), - UserDir = ?config(priv_dir, Config), - DataFile = filename:join(UserDir, "rekey.data"), - - {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, - {user_dir, UserDir}, - {user_passwords, - [{"simon", "says"}]}]), - {ok, SftpPid, ConnectionRef} = - ssh_sftp:start_channel(Host, Port, [{system_dir, SystemDir}, - {user_dir, UserDir}, - {user, "simon"}, - {password, "says"}, - {rekey_limit, 2500}, - {user_interaction, false}, - {silently_accept_hosts, true}]), - - Kex1 = get_kex_init(ConnectionRef), - - timer:sleep(?REKEY_DATA_TMO), - Kex1 = get_kex_init(ConnectionRef), - - Data = lists:duplicate(9000,1), - ok = ssh_sftp:write_file(SftpPid, DataFile, Data), - - timer:sleep(?REKEY_DATA_TMO), - Kex2 = get_kex_init(ConnectionRef), - - false = (Kex2 == Kex1), - - timer:sleep(?REKEY_DATA_TMO), - Kex2 = get_kex_init(ConnectionRef), - - ok = ssh_sftp:write_file(SftpPid, DataFile, "hi\n"), - - timer:sleep(?REKEY_DATA_TMO), - Kex2 = get_kex_init(ConnectionRef), - - false = (Kex2 == Kex1), - - timer:sleep(?REKEY_DATA_TMO), - Kex2 = get_kex_init(ConnectionRef), - - - ssh_sftp:stop_channel(SftpPid), - ssh:close(ConnectionRef), - ssh:stop_daemon(Pid). - -%%-------------------------------------------------------------------- -renegotiate1() -> - [{doc, "Test rekeying with simulataneous send request"}]. -renegotiate1(Config) -> - SystemDir = ?config(data_dir, Config), - UserDir = ?config(priv_dir, Config), - DataFile = filename:join(UserDir, "renegotiate1.data"), - - {Pid, Host, DPort} = ssh_test_lib:daemon([{system_dir, SystemDir}, - {user_dir, UserDir}, - {user_passwords, - [{"simon", "says"}]}]), - RPort = ssh_test_lib:inet_port(), - - {ok,RelayPid} = ssh_relay:start_link({0,0,0,0}, RPort, Host, DPort), - - {ok, SftpPid, ConnectionRef} = - ssh_sftp:start_channel(Host, RPort, [{system_dir, SystemDir}, - {user_dir, UserDir}, - {user, "simon"}, - {password, "says"}, - {user_interaction, false}, - {silently_accept_hosts, true}]), - - Kex1 = get_kex_init(ConnectionRef), - - {ok, Handle} = ssh_sftp:open(SftpPid, DataFile, [write]), - - ok = ssh_sftp:write(SftpPid, Handle, "hi\n"), - - ssh_relay:hold(RelayPid, rx, 20, 1000), - ssh_connection_handler:renegotiate(ConnectionRef), - spawn(fun() -> ok=ssh_sftp:write(SftpPid, Handle, "another hi\n") end), - - timer:sleep(2000), - - Kex2 = get_kex_init(ConnectionRef), - - false = (Kex2 == Kex1), - ssh_relay:stop(RelayPid), - ssh_sftp:stop_channel(SftpPid), - ssh:close(ConnectionRef), - ssh:stop_daemon(Pid). - %%-------------------------------------------------------------------- -renegotiate2() -> - [{doc, "Test rekeying with inflight messages from peer"}]. -renegotiate2(Config) -> - SystemDir = ?config(data_dir, Config), - UserDir = ?config(priv_dir, Config), - DataFile = filename:join(UserDir, "renegotiate1.data"), - - {Pid, Host, DPort} = ssh_test_lib:daemon([{system_dir, SystemDir}, - {user_dir, UserDir}, - {user_passwords, - [{"simon", "says"}]}]), - RPort = ssh_test_lib:inet_port(), - - {ok,RelayPid} = ssh_relay:start_link({0,0,0,0}, RPort, Host, DPort), - - {ok, SftpPid, ConnectionRef} = - ssh_sftp:start_channel(Host, RPort, [{system_dir, SystemDir}, - {user_dir, UserDir}, - {user, "simon"}, - {password, "says"}, - {user_interaction, false}, - {silently_accept_hosts, true}]), +%%% Test that we could user different types of host pubkey and user pubkey +exec_key_differs1(Config) -> exec_key_differs(Config, ['ecdsa-sha2-nistp256']). - Kex1 = get_kex_init(ConnectionRef), +exec_key_differs2(Config) -> exec_key_differs(Config, ['ssh-dss','ecdsa-sha2-nistp256']). - {ok, Handle} = ssh_sftp:open(SftpPid, DataFile, [write]), +exec_key_differs3(Config) -> exec_key_differs(Config, ['ecdsa-sha2-nistp384','ecdsa-sha2-nistp256']). - ok = ssh_sftp:write(SftpPid, Handle, "hi\n"), - ssh_relay:hold(RelayPid, rx, 20, infinity), - spawn(fun() -> ok=ssh_sftp:write(SftpPid, Handle, "another hi\n") end), - %% need a small pause here to ensure ssh_sftp:write is executed - ct:sleep(10), - ssh_connection_handler:renegotiate(ConnectionRef), - ssh_relay:release(RelayPid, rx), - timer:sleep(2000), +exec_key_differs(Config, UserPKAlgs) -> + case lists:usort(['ssh-rsa'|UserPKAlgs]) + -- ssh_transport:supported_algorithms(public_key) + of + [] -> + process_flag(trap_exit, true), + SystemDir = filename:join(?config(priv_dir, Config), system_rsa), + SystemUserDir = filename:join(SystemDir, user), + UserDir = filename:join(?config(priv_dir, Config), user_ecdsa_256), + + {_Pid, _Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + {user_dir, SystemUserDir}, + {preferred_algorithms, + [{public_key,['ssh-rsa']}]}]), + ct:sleep(500), - Kex2 = get_kex_init(ConnectionRef), + IO = ssh_test_lib:start_io_server(), + Shell = ssh_test_lib:start_shell(Port, IO, UserDir, + [{preferred_algorithms,[{public_key,['ssh-rsa']}]}, + {pref_public_key_algs,UserPKAlgs} + ]), - false = (Kex2 == Kex1), - ssh_relay:stop(RelayPid), - ssh_sftp:stop_channel(SftpPid), - ssh:close(ConnectionRef), - ssh:stop_daemon(Pid). + receive + {'EXIT', _, _} -> + ct:fail(no_ssh_connection); + ErlShellStart -> + ct:log("Erlang shell start: ~p~n", [ErlShellStart]), + do_shell(IO, Shell) + after + 30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) + end; + UnsupportedPubKeys -> + {skip, io_lib:format("~p unsupported",[UnsupportedPubKeys])} + end. + %%-------------------------------------------------------------------- -shell() -> - [{doc, "Test that ssh:shell/2 works"}]. -shell(Config) when is_list(Config) -> +exec_key_differs_fail(Config) when is_list(Config) -> process_flag(trap_exit, true), - SystemDir = filename:join(?config(priv_dir, Config), system), - UserDir = ?config(priv_dir, Config), + SystemDir = filename:join(?config(priv_dir, Config), system_rsa), + SystemUserDir = filename:join(SystemDir, user), + UserDir = filename:join(?config(priv_dir, Config), user_ecdsa_256), - {_Pid, _Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},{user_dir, UserDir}, - {failfun, fun ssh_test_lib:failfun/2}]), + {_Pid, _Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + {user_dir, SystemUserDir}, + {preferred_algorithms, + [{public_key,['ssh-rsa']}]}]), ct:sleep(500), IO = ssh_test_lib:start_io_server(), - Shell = ssh_test_lib:start_shell(Port, IO, UserDir), + ssh_test_lib:start_shell(Port, IO, UserDir, + [{preferred_algorithms,[{public_key,['ssh-rsa']}]}, + {pref_public_key_algs,['ssh-dss']}]), receive {'EXIT', _, _} -> - ct:fail(no_ssh_connection); + ok; ErlShellStart -> - ct:pal("Erlang shell start: ~p~n", [ErlShellStart]), - do_shell(IO, Shell) + ct:log("Erlang shell start: ~p~n", [ErlShellStart]), + ct:fail(connection_not_rejected) + after + 30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end. %%-------------------------------------------------------------------- -cli() -> - [{doc, ""}]. cli(Config) when is_list(Config) -> process_flag(trap_exit, true), SystemDir = filename:join(?config(priv_dir, Config), system), UserDir = ?config(priv_dir, Config), - + + TmpDir = filename:join(?config(priv_dir,Config), "tmp"), + ok = ssh_test_lib:del_dirs(TmpDir), + ok = file:make_dir(TmpDir), + {_Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},{user_dir, UserDir}, {password, "morot"}, - {ssh_cli, {ssh_test_cli, [cli]}}, + {ssh_cli, {ssh_test_cli, [cli,TmpDir]}}, {subsystems, []}, {failfun, fun ssh_test_lib:failfun/2}]), ct:sleep(500), @@ -609,17 +636,20 @@ cli(Config) when is_list(Config) -> {ssh_cm, ConnectionRef, {data,0,0, <<"\r\nYou are accessing a dummy, type \"q\" to exit\r\n\n">>}} -> ok = ssh_connection:send(ConnectionRef, ChannelId, <<"q">>) + after + 30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end, receive {ssh_cm, ConnectionRef,{closed, ChannelId}} -> ok + after + 30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end. %%-------------------------------------------------------------------- -daemon_already_started() -> - [{doc, "Test that get correct error message if you try to start a daemon", - "on an adress that already runs a daemon see also seq10667"}]. +%%% Test that get correct error message if you try to start a daemon +%%% on an adress that already runs a daemon see also seq10667 daemon_already_started(Config) when is_list(Config) -> SystemDir = ?config(data_dir, Config), UserDir = ?config(priv_dir, Config), @@ -634,427 +664,7 @@ daemon_already_started(Config) when is_list(Config) -> ssh:stop_daemon(Pid). %%-------------------------------------------------------------------- -server_password_option() -> - [{doc, "validate to server that uses the 'password' option"}]. -server_password_option(Config) when is_list(Config) -> - PrivDir = ?config(priv_dir, Config), - UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth - file:make_dir(UserDir), - SysDir = ?config(data_dir, Config), - {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, - {user_dir, UserDir}, - {password, "morot"}]), - - ConnectionRef = - ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, - {user, "foo"}, - {password, "morot"}, - {user_interaction, false}, - {user_dir, UserDir}]), - - Reason = "Unable to connect using the available authentication methods", - - {error, Reason} = - ssh:connect(Host, Port, [{silently_accept_hosts, true}, - {user, "vego"}, - {password, "foo"}, - {user_interaction, false}, - {user_dir, UserDir}]), - - ct:pal("Test of wrong password: Error msg: ~p ~n", [Reason]), - - ssh:close(ConnectionRef), - ssh:stop_daemon(Pid). - -%%-------------------------------------------------------------------- - -server_userpassword_option() -> - [{doc, "validate to server that uses the 'password' option"}]. -server_userpassword_option(Config) when is_list(Config) -> - PrivDir = ?config(priv_dir, Config), - UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth - file:make_dir(UserDir), - SysDir = ?config(data_dir, Config), - {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, - {user_dir, PrivDir}, - {user_passwords, [{"vego", "morot"}]}]), - - ConnectionRef = - ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, - {user, "vego"}, - {password, "morot"}, - {user_interaction, false}, - {user_dir, UserDir}]), - ssh:close(ConnectionRef), - - Reason = "Unable to connect using the available authentication methods", - - {error, Reason} = - ssh:connect(Host, Port, [{silently_accept_hosts, true}, - {user, "foo"}, - {password, "morot"}, - {user_interaction, false}, - {user_dir, UserDir}]), - {error, Reason} = - ssh:connect(Host, Port, [{silently_accept_hosts, true}, - {user, "vego"}, - {password, "foo"}, - {user_interaction, false}, - {user_dir, UserDir}]), - ssh:stop_daemon(Pid). - -%%-------------------------------------------------------------------- -system_dir_option(Config) -> - DirUnread = proplists:get_value(unreadable_dir,Config), - FileRead = proplists:get_value(readable_file,Config), - - case ssh_test_lib:daemon([{system_dir, DirUnread}]) of - {error,{eoptions,{{system_dir,DirUnread},eacces}}} -> - ok; - {Pid1,_Host1,Port1} when is_pid(Pid1),is_integer(Port1) -> - ssh:stop_daemon(Pid1), - ct:fail("Didn't detect that dir is unreadable", []) - end, - - case ssh_test_lib:daemon([{system_dir, FileRead}]) of - {error,{eoptions,{{system_dir,FileRead},enotdir}}} -> - ok; - {Pid2,_Host2,Port2} when is_pid(Pid2),is_integer(Port2) -> - ssh:stop_daemon(Pid2), - ct:fail("Didn't detect that option is a plain file", []) - end. - - -user_dir_option(Config) -> - DirUnread = proplists:get_value(unreadable_dir,Config), - FileRead = proplists:get_value(readable_file,Config), - %% Any port will do (beware, implementation knowledge!): - Port = 65535, - - case ssh:connect("localhost", Port, [{user_dir, DirUnread}]) of - {error,{eoptions,{{user_dir,DirUnread},eacces}}} -> - ok; - {error,econnrefused} -> - ct:fail("Didn't detect that dir is unreadable", []) - end, - - case ssh:connect("localhost", Port, [{user_dir, FileRead}]) of - {error,{eoptions,{{user_dir,FileRead},enotdir}}} -> - ok; - {error,econnrefused} -> - ct:fail("Didn't detect that option is a plain file", []) - end. - -%%-------------------------------------------------------------------- -ssh_msg_debug_fun_option_client() -> - [{doc, "validate client that uses the 'ssh_msg_debug_fun' option"}]. -ssh_msg_debug_fun_option_client(Config) -> - PrivDir = ?config(priv_dir, Config), - UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth - file:make_dir(UserDir), - SysDir = ?config(data_dir, Config), - - {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, - {user_dir, UserDir}, - {password, "morot"}, - {failfun, fun ssh_test_lib:failfun/2}]), - Parent = self(), - DbgFun = fun(ConnRef,Displ,Msg,Lang) -> Parent ! {msg_dbg,{ConnRef,Displ,Msg,Lang}} end, - - ConnectionRef = - ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, - {user, "foo"}, - {password, "morot"}, - {user_dir, UserDir}, - {user_interaction, false}, - {ssh_msg_debug_fun,DbgFun}]), - %% Beware, implementation knowledge: - gen_fsm:send_all_state_event(ConnectionRef,{ssh_msg_debug,false,<<"Hello">>,<<>>}), - receive - {msg_dbg,X={ConnectionRef,false,<<"Hello">>,<<>>}} -> - ct:log("Got expected dbg msg ~p",[X]), - ssh:stop_daemon(Pid); - {msg_dbg,X={_,false,<<"Hello">>,<<>>}} -> - ct:log("Got dbg msg but bad ConnectionRef (~p expected) ~p",[ConnectionRef,X]), - ssh:stop_daemon(Pid), - {fail, "Bad ConnectionRef received"}; - {msg_dbg,X} -> - ct:log("Got bad dbg msg ~p",[X]), - ssh:stop_daemon(Pid), - {fail,"Bad msg received"} - after 1000 -> - ssh:stop_daemon(Pid), - {fail,timeout} - end. - -%%-------------------------------------------------------------------- -connectfun_disconnectfun_server(Config) -> - PrivDir = ?config(priv_dir, Config), - UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth - file:make_dir(UserDir), - SysDir = ?config(data_dir, Config), - - Parent = self(), - Ref = make_ref(), - ConnFun = fun(_,_,_) -> Parent ! {connect,Ref} end, - DiscFun = fun(R) -> Parent ! {disconnect,Ref,R} end, - - {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, - {user_dir, UserDir}, - {password, "morot"}, - {failfun, fun ssh_test_lib:failfun/2}, - {disconnectfun, DiscFun}, - {connectfun, ConnFun}]), - ConnectionRef = - ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, - {user, "foo"}, - {password, "morot"}, - {user_dir, UserDir}, - {user_interaction, false}]), - receive - {connect,Ref} -> - ssh:close(ConnectionRef), - receive - {disconnect,Ref,R} -> - ct:log("Disconnect result: ~p",[R]), - ssh:stop_daemon(Pid) - after 2000 -> - {fail, "No disconnectfun action"} - end - after 2000 -> - {fail, "No connectfun action"} - end. - -%%-------------------------------------------------------------------- -connectfun_disconnectfun_client(Config) -> - PrivDir = ?config(priv_dir, Config), - UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth - file:make_dir(UserDir), - SysDir = ?config(data_dir, Config), - - Parent = self(), - Ref = make_ref(), - DiscFun = fun(R) -> Parent ! {disconnect,Ref,R} end, - - {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, - {user_dir, UserDir}, - {password, "morot"}, - {failfun, fun ssh_test_lib:failfun/2}]), - _ConnectionRef = - ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, - {user, "foo"}, - {password, "morot"}, - {user_dir, UserDir}, - {disconnectfun, DiscFun}, - {user_interaction, false}]), - ssh:stop_daemon(Pid), - receive - {disconnect,Ref,R} -> - ct:log("Disconnect result: ~p",[R]) - after 2000 -> - {fail, "No disconnectfun action"} - end. - -%%-------------------------------------------------------------------- -ssh_msg_debug_fun_option_server() -> - [{doc, "validate client that uses the 'ssh_msg_debug_fun' option"}]. -ssh_msg_debug_fun_option_server(Config) -> - PrivDir = ?config(priv_dir, Config), - UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth - file:make_dir(UserDir), - SysDir = ?config(data_dir, Config), - - Parent = self(), - DbgFun = fun(ConnRef,Displ,Msg,Lang) -> Parent ! {msg_dbg,{ConnRef,Displ,Msg,Lang}} end, - ConnFun = fun(_,_,_) -> Parent ! {connection_pid,self()} end, - - {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, - {user_dir, UserDir}, - {password, "morot"}, - {failfun, fun ssh_test_lib:failfun/2}, - {connectfun, ConnFun}, - {ssh_msg_debug_fun, DbgFun}]), - _ConnectionRef = - ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, - {user, "foo"}, - {password, "morot"}, - {user_dir, UserDir}, - {user_interaction, false}]), - receive - {connection_pid,Server} -> - %% Beware, implementation knowledge: - gen_fsm:send_all_state_event(Server,{ssh_msg_debug,false,<<"Hello">>,<<>>}), - receive - {msg_dbg,X={_,false,<<"Hello">>,<<>>}} -> - ct:log("Got expected dbg msg ~p",[X]), - ssh:stop_daemon(Pid); - {msg_dbg,X} -> - ct:log("Got bad dbg msg ~p",[X]), - ssh:stop_daemon(Pid), - {fail,"Bad msg received"} - after 3000 -> - ssh:stop_daemon(Pid), - {fail,timeout2} - end - after 3000 -> - ssh:stop_daemon(Pid), - {fail,timeout1} - end. - -%%-------------------------------------------------------------------- -disconnectfun_option_server(Config) -> - PrivDir = ?config(priv_dir, Config), - UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth - file:make_dir(UserDir), - SysDir = ?config(data_dir, Config), - - Parent = self(), - DisConnFun = fun(Reason) -> Parent ! {disconnect,Reason} end, - - {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, - {user_dir, UserDir}, - {password, "morot"}, - {failfun, fun ssh_test_lib:failfun/2}, - {disconnectfun, DisConnFun}]), - ConnectionRef = - ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, - {user, "foo"}, - {password, "morot"}, - {user_dir, UserDir}, - {user_interaction, false}]), - ssh:close(ConnectionRef), - receive - {disconnect,Reason} -> - ct:log("Server detected disconnect: ~p",[Reason]), - ssh:stop_daemon(Pid), - ok - after 3000 -> - receive - X -> ct:log("received ~p",[X]) - after 0 -> ok - end, - {fail,"Timeout waiting for disconnect"} - end. - -%%-------------------------------------------------------------------- -disconnectfun_option_client(Config) -> - PrivDir = ?config(priv_dir, Config), - UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth - file:make_dir(UserDir), - SysDir = ?config(data_dir, Config), - - Parent = self(), - DisConnFun = fun(Reason) -> Parent ! {disconnect,Reason} end, - - {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, - {user_dir, UserDir}, - {password, "morot"}, - {failfun, fun ssh_test_lib:failfun/2}]), - _ConnectionRef = - ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, - {user, "foo"}, - {password, "morot"}, - {user_dir, UserDir}, - {user_interaction, false}, - {disconnectfun, DisConnFun}]), - ssh:stop_daemon(Pid), - receive - {disconnect,Reason} -> - ct:log("Client detected disconnect: ~p",[Reason]), - ok - after 3000 -> - receive - X -> ct:log("received ~p",[X]) - after 0 -> ok - end, - {fail,"Timeout waiting for disconnect"} - end. - -%%-------------------------------------------------------------------- -unexpectedfun_option_server(Config) -> - PrivDir = ?config(priv_dir, Config), - UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth - file:make_dir(UserDir), - SysDir = ?config(data_dir, Config), - - Parent = self(), - ConnFun = fun(_,_,_) -> Parent ! {connection_pid,self()} end, - UnexpFun = fun(Msg,Peer) -> - Parent ! {unexpected,Msg,Peer,self()}, - skip - end, - - {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, - {user_dir, UserDir}, - {password, "morot"}, - {failfun, fun ssh_test_lib:failfun/2}, - {connectfun, ConnFun}, - {unexpectedfun, UnexpFun}]), - _ConnectionRef = - ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, - {user, "foo"}, - {password, "morot"}, - {user_dir, UserDir}, - {user_interaction, false}]), - receive - {connection_pid,Server} -> - %% Beware, implementation knowledge: - Server ! unexpected_message, - receive - {unexpected, unexpected_message, {{_,_,_,_},_}, _} -> ok; - {unexpected, unexpected_message, Peer, _} -> ct:fail("Bad peer ~p",[Peer]); - M = {unexpected, _, _, _} -> ct:fail("Bad msg ~p",[M]) - after 3000 -> - ssh:stop_daemon(Pid), - {fail,timeout2} - end - after 3000 -> - ssh:stop_daemon(Pid), - {fail,timeout1} - end. - -%%-------------------------------------------------------------------- -unexpectedfun_option_client(Config) -> - PrivDir = ?config(priv_dir, Config), - UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth - file:make_dir(UserDir), - SysDir = ?config(data_dir, Config), - - Parent = self(), - UnexpFun = fun(Msg,Peer) -> - Parent ! {unexpected,Msg,Peer,self()}, - skip - end, - - {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, - {user_dir, UserDir}, - {password, "morot"}, - {failfun, fun ssh_test_lib:failfun/2}]), - ConnectionRef = - ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, - {user, "foo"}, - {password, "morot"}, - {user_dir, UserDir}, - {user_interaction, false}, - {unexpectedfun, UnexpFun}]), - %% Beware, implementation knowledge: - ConnectionRef ! unexpected_message, - - receive - {unexpected, unexpected_message, {{_,_,_,_},_}, ConnectionRef} -> - ok; - {unexpected, unexpected_message, Peer, ConnectionRef} -> - ct:fail("Bad peer ~p",[Peer]); - M = {unexpected, _, _, _} -> - ct:fail("Bad msg ~p",[M]) - after 3000 -> - ssh:stop_daemon(Pid), - {fail,timeout} - end. - -%%-------------------------------------------------------------------- -known_hosts() -> - [{doc, "check that known_hosts is updated correctly"}]. +%%% check that known_hosts is updated correctly known_hosts(Config) when is_list(Config) -> SystemDir = ?config(data_dir, Config), PrivDir = ?config(priv_dir, Config), @@ -1080,8 +690,7 @@ known_hosts(Config) when is_list(Config) -> ssh:stop_daemon(Pid). %%-------------------------------------------------------------------- -pass_phrase() -> - [{doc, "Test that we can use keyes protected by pass phrases"}]. +%%% Test that we can use keyes protected by pass phrases pass_phrase(Config) when is_list(Config) -> process_flag(trap_exit, true), SystemDir = filename:join(?config(priv_dir, Config), system), @@ -1100,27 +709,75 @@ pass_phrase(Config) when is_list(Config) -> ssh:stop_daemon(Pid). %%-------------------------------------------------------------------- +%%% Test that we can use key callback +key_callback(Config) when is_list(Config) -> + process_flag(trap_exit, true), + SystemDir = filename:join(?config(priv_dir, Config), system), + UserDir = ?config(priv_dir, Config), + NoPubKeyDir = filename:join(UserDir, "nopubkey"), + file:make_dir(NoPubKeyDir), -internal_error() -> - [{doc,"Test that client does not hang if disconnects due to internal error"}]. + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + {user_dir, UserDir}, + {failfun, fun ssh_test_lib:failfun/2}]), + + ConnectOpts = [{silently_accept_hosts, true}, + {user_dir, NoPubKeyDir}, + {user_interaction, false}, + {key_cb, ssh_key_cb}], + + ConnectionRef = ssh_test_lib:connect(Host, Port, ConnectOpts), + + {ok, _ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity), + ssh:stop_daemon(Pid). + + +%%-------------------------------------------------------------------- +%%% Test that we can use key callback with callback options +key_callback_options(Config) when is_list(Config) -> + process_flag(trap_exit, true), + SystemDir = filename:join(?config(priv_dir, Config), system), + UserDir = ?config(priv_dir, Config), + + NoPubKeyDir = filename:join(UserDir, "nopubkey"), + file:make_dir(NoPubKeyDir), + + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + {user_dir, UserDir}, + {failfun, fun ssh_test_lib:failfun/2}]), + + {ok, PrivKey} = file:read_file(filename:join(UserDir, "id_dsa")), + + ConnectOpts = [{silently_accept_hosts, true}, + {user_dir, NoPubKeyDir}, + {user_interaction, false}, + {key_cb, {ssh_key_cb_options, [{priv_key, PrivKey}]}}], + + ConnectionRef = ssh_test_lib:connect(Host, Port, ConnectOpts), + + {ok, _ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity), + ssh:stop_daemon(Pid). + + +%%-------------------------------------------------------------------- +%%% Test that client does not hang if disconnects due to internal error internal_error(Config) when is_list(Config) -> process_flag(trap_exit, true), SystemDir = filename:join(?config(priv_dir, Config), system), UserDir = ?config(priv_dir, Config), {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, - {user_dir, UserDir}, - {failfun, fun ssh_test_lib:failfun/2}]), + {user_dir, UserDir}, + {failfun, fun ssh_test_lib:failfun/2}]), {error, Error} = - ssh:connect(Host, Port, [{silently_accept_hosts, true}, - {user_dir, UserDir}, - {user_interaction, false}]), + ssh:connect(Host, Port, [{silently_accept_hosts, true}, + {user_dir, UserDir}, + {user_interaction, false}]), check_error(Error), ssh:stop_daemon(Pid). %%-------------------------------------------------------------------- -send() -> - [{doc, "Test ssh_connection:send/3"}]. +%%% Test ssh_connection:send/3 send(Config) when is_list(Config) -> process_flag(trap_exit, true), SystemDir = filename:join(?config(priv_dir, Config), system), @@ -1140,8 +797,7 @@ send(Config) when is_list(Config) -> %%-------------------------------------------------------------------- -peername_sockname() -> - [{doc, "Test ssh:connection_info([peername, sockname])"}]. +%%% Test ssh:connection_info([peername, sockname]) peername_sockname(Config) when is_list(Config) -> process_flag(trap_exit, true), SystemDir = filename:join(?config(priv_dir, Config), system), @@ -1163,13 +819,13 @@ peername_sockname(Config) when is_list(Config) -> ssh:connection_info(ConnectionRef, [peer]), [{sockname, {HostSockClient,PortSockClient} = ClientSock}] = ssh:connection_info(ConnectionRef, [sockname]), - ct:pal("Client: ~p ~p", [ClientPeer, ClientSock]), + ct:log("Client: ~p ~p", [ClientPeer, ClientSock]), receive {ssh_cm, ConnectionRef, {data, ChannelId, _, Response}} -> {PeerNameSrv,SockNameSrv} = binary_to_term(Response), {HostPeerSrv,PortPeerSrv} = PeerNameSrv, {HostSockSrv,PortSockSrv} = SockNameSrv, - ct:pal("Server: ~p ~p", [PeerNameSrv, SockNameSrv]), + ct:log("Server: ~p ~p", [PeerNameSrv, SockNameSrv]), host_equal(HostPeerSrv, HostSockClient), PortPeerSrv = PortSockClient, host_equal(HostSockSrv, HostPeerClient), @@ -1177,7 +833,7 @@ peername_sockname(Config) when is_list(Config) -> host_equal(HostSockSrv, Host), PortSockSrv = Port after 10000 -> - throw(timeout) + ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end. host_equal(H1, H2) -> @@ -1191,8 +847,7 @@ ips(Name) when is_list(Name) -> %%-------------------------------------------------------------------- -close() -> - [{doc, "Client receives close when server closes"}]. +%%% Client receives close when server closes close(Config) when is_list(Config) -> process_flag(trap_exit, true), SystemDir = filename:join(?config(priv_dir, Config), system), @@ -1212,12 +867,11 @@ close(Config) when is_list(Config) -> {ssh_cm, Client,{closed, ChannelId}} -> ok after 5000 -> - ct:fail(timeout) + ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end. %%-------------------------------------------------------------------- -double_close() -> - [{doc, "Simulate that we try to close an already closed connection"}]. +%%% Simulate that we try to close an already closed connection double_close(Config) when is_list(Config) -> SystemDir = ?config(data_dir, Config), PrivDir = ?config(priv_dir, Config), @@ -1238,89 +892,66 @@ double_close(Config) when is_list(Config) -> ok = ssh:close(CM). %%-------------------------------------------------------------------- -ssh_connect_timeout() -> - [{doc, "Test connect_timeout option in ssh:connect/4"}]. -ssh_connect_timeout(_Config) -> - ConnTimeout = 2000, - {error,{faked_transport,connect,TimeoutToTransport}} = - ssh:connect("localhost", 12345, - [{transport,{tcp,?MODULE,tcp_closed}}, - {connect_timeout,ConnTimeout}], - 1000), - case TimeoutToTransport of - ConnTimeout -> ok; - Other -> - ct:log("connect_timeout is ~p but transport received ~p",[ConnTimeout,Other]), - {fail,"ssh:connect/4 wrong connect_timeout received in transport"} - end. +daemon_opt_fd(Config) -> + SystemDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), + + {ok,S1} = gen_tcp:listen(0,[]), + {ok,Fd1} = prim_inet:getfd(S1), -%% Help for the test above -connect(_Host, _Port, _Opts, Timeout) -> - {error, {faked_transport,connect,Timeout}}. + {ok,Pid1} = ssh:daemon(0, [{system_dir, SystemDir}, + {fd,Fd1}, + {user_dir, UserDir}, + {user_passwords, [{"vego", "morot"}]}, + {failfun, fun ssh_test_lib:failfun/2}]), + + {ok,{_Host1,Port1}} = inet:sockname(S1), + {ok, C1} = ssh:connect("localhost", Port1, [{silently_accept_hosts, true}, + {user_dir, UserDir}, + {user, "vego"}, + {password, "morot"}, + {user_interaction, false}]), + exit(C1, {shutdown, normal}), + ssh:stop_daemon(Pid1), + gen_tcp:close(S1). %%-------------------------------------------------------------------- -ssh_connect_arg4_timeout() -> - [{doc, "Test fourth argument in ssh:connect/4"}]. -ssh_connect_arg4_timeout(_Config) -> - Timeout = 1000, - Parent = self(), - %% start the server - Server = spawn(fun() -> - {ok,Sl} = gen_tcp:listen(0,[]), - {ok,{_,Port}} = inet:sockname(Sl), - Parent ! {port,self(),Port}, - Rsa = gen_tcp:accept(Sl), - ct:log("Server gen_tcp:accept got ~p",[Rsa]), - receive after 2*Timeout -> ok end %% let client timeout first - end), - - %% Get listening port - Port = receive - {port,Server,ServerPort} -> ServerPort - end, - - %% try to connect with a timeout, but "supervise" it - Client = spawn(fun() -> - T0 = erlang:monotonic_time(), - Rc = ssh:connect("localhost",Port,[],Timeout), - ct:log("Client ssh:connect got ~p",[Rc]), - Parent ! {done,self(),Rc,T0} - end), - - %% Wait for client reaction on the connection try: - receive - {done, Client, {error,timeout}, T0} -> - Msp = ms_passed(T0), - exit(Server,hasta_la_vista___baby), - Low = 0.9*Timeout, - High = 1.1*Timeout, - ct:log("Timeout limits: ~.4f - ~.4f ms, timeout " - "was ~.4f ms, expected ~p ms",[Low,High,Msp,Timeout]), - if - Low<Msp, Msp<High -> ok; - true -> {fail, "timeout not within limits"} - end; +multi_daemon_opt_fd(Config) -> + SystemDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), - {done, Client, {error,Other}, _T0} -> - ct:log("Error message \"~p\" from the client is unexpected.",[{error,Other}]), - {fail, "Unexpected error message"}; - - {done, Client, {ok,_Ref}, _T0} -> - {fail,"ssh-connected ???"} - after - 5000 -> - exit(Server,hasta_la_vista___baby), - exit(Client,hasta_la_vista___baby), - {fail, "Didn't timeout"} - end. + Test = + fun() -> + {ok,S} = gen_tcp:listen(0,[]), + {ok,Fd} = prim_inet:getfd(S), + + {ok,Pid} = ssh:daemon(0, [{system_dir, SystemDir}, + {fd,Fd}, + {user_dir, UserDir}, + {user_passwords, [{"vego", "morot"}]}, + {failfun, fun ssh_test_lib:failfun/2}]), + + {ok,{_Host,Port}} = inet:sockname(S), + {ok, C} = ssh:connect("localhost", Port, [{silently_accept_hosts, true}, + {user_dir, UserDir}, + {user, "vego"}, + {password, "morot"}, + {user_interaction, false}]), + {S,Pid,C} + end, -%% Help function, elapsed milliseconds since T0 -ms_passed(T0) -> - %% OTP 18 - erlang:convert_time_unit(erlang:monotonic_time() - T0, - native, - micro_seconds) / 1000. + Tests = [Test(),Test(),Test(),Test(),Test(),Test()], + + [begin + gen_tcp:close(S), + ssh:stop_daemon(Pid), + exit(C, {shutdown, normal}) + end || {S,Pid,C} <- Tests]. %%-------------------------------------------------------------------- packet_size_zero(Config) -> @@ -1347,371 +978,58 @@ packet_size_zero(Config) -> receive {ssh_cm,Conn,{data,Chan,_Type,_Msg1}} = M -> - ct:pal("Got ~p",[M]), + ct:log("Got ~p",[M]), ct:fail(doesnt_obey_max_packet_size_0) after 5000 -> ok end. %%-------------------------------------------------------------------- -ssh_daemon_minimal_remote_max_packet_size_option(Config) -> - SystemDir = ?config(data_dir, Config), - PrivDir = ?config(priv_dir, Config), - UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth - file:make_dir(UserDir), - - {Server, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, - {user_dir, UserDir}, - {user_passwords, [{"vego", "morot"}]}, - {failfun, fun ssh_test_lib:failfun/2}, - {minimal_remote_max_packet_size, 14}]), - Conn = - ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, - {user_dir, UserDir}, - {user_interaction, false}, - {user, "vego"}, - {password, "morot"}]), - - %% Try the limits of the minimal_remote_max_packet_size: - {ok, _ChannelId} = ssh_connection:session_channel(Conn, 100, 14, infinity), - {open_error,_,"Maximum packet size below 14 not supported",_} = - ssh_connection:session_channel(Conn, 100, 13, infinity), - - ssh:close(Conn), - ssh:stop_daemon(Server). - -%%-------------------------------------------------------------------- -%% This test try every algorithm by connecting to an Erlang server -preferred_algorithms(Config) -> - SystemDir = ?config(data_dir, Config), - PrivDir = ?config(priv_dir, Config), - UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth - file:make_dir(UserDir), - - {Server, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, - {user_dir, UserDir}, - {user_passwords, [{"vego", "morot"}]}, - {failfun, fun ssh_test_lib:failfun/2}]), - Available = ssh:default_algorithms(), - Tests = [[{Tag,[Alg]}] || {Tag, SubAlgs} <- Available, - is_atom(hd(SubAlgs)), - Alg <- SubAlgs] - ++ [[{Tag,[{T1,[A1]},{T2,[A2]}]}] || {Tag, [{T1,As1},{T2,As2}]} <- Available, - A1 <- As1, - A2 <- As2], - ct:log("TESTS: ~p",[Tests]), - [connect_exec_channel(Host,Port,PrefAlgs) || PrefAlgs <- Tests], - ssh:stop_daemon(Server). - - -connect_exec_channel(_Host, Port, Algs) -> - ct:log("Try ~p",[Algs]), - ConnectionRef = ssh_test_lib:connect(Port, [{silently_accept_hosts, true}, - {user_interaction, false}, - {user, "vego"}, - {password, "morot"}, - {preferred_algorithms,Algs} - ]), - chan_exec(ConnectionRef, "2*21.", <<"42\n">>), - ssh:close(ConnectionRef). - -chan_exec(ConnectionRef, Cmnd, Expected) -> - {ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity), - success = ssh_connection:exec(ConnectionRef, ChannelId0,Cmnd, infinity), - Data0 = {ssh_cm, ConnectionRef, {data, ChannelId0, 0, Expected}}, - case ssh_test_lib:receive_exec_result(Data0) of - expected -> - ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId0); - {unexpected_msg,{ssh_cm, ConnectionRef, {exit_status, ChannelId0, 0}} - = ExitStatus0} -> - ct:pal("0: Collected data ~p", [ExitStatus0]), - ssh_test_lib:receive_exec_result(Data0, - ConnectionRef, ChannelId0); - Other0 -> - ct:fail(Other0) - end. - -%%-------------------------------------------------------------------- -id_string_no_opt_client(Config) -> - {Server, _Host, Port} = fake_daemon(Config), - {error,_} = ssh:connect("localhost", Port, [], 1000), - receive - {id,Server,"SSH-2.0-Erlang/"++Vsn} -> - true = expected_ssh_vsn(Vsn); - {id,Server,Other} -> - ct:fail("Unexpected id: ~s.",[Other]) - after 5000 -> - {fail,timeout} - end. - -%%-------------------------------------------------------------------- -id_string_own_string_client(Config) -> - {Server, _Host, Port} = fake_daemon(Config), - {error,_} = ssh:connect("localhost", Port, [{id_string,"Pelle"}], 1000), - receive - {id,Server,"SSH-2.0-Pelle\r\n"} -> - ok; - {id,Server,Other} -> - ct:fail("Unexpected id: ~s.",[Other]) - after 5000 -> - {fail,timeout} - end. - -%%-------------------------------------------------------------------- -id_string_random_client(Config) -> - {Server, _Host, Port} = fake_daemon(Config), - {error,_} = ssh:connect("localhost", Port, [{id_string,random}], 1000), - receive - {id,Server,Id="SSH-2.0-Erlang"++_} -> - ct:fail("Unexpected id: ~s.",[Id]); - {id,Server,Rnd="SSH-2.0-"++_} -> - ct:log("Got correct ~s",[Rnd]); - {id,Server,Id} -> - ct:fail("Unexpected id: ~s.",[Id]) - after 5000 -> - {fail,timeout} - end. - -%%-------------------------------------------------------------------- -id_string_no_opt_server(Config) -> - {_Server, Host, Port} = std_daemon(Config, []), - {ok,S1}=gen_tcp:connect(Host,Port,[{active,false},{packet,line}]), - {ok,"SSH-2.0-Erlang/"++Vsn} = gen_tcp:recv(S1, 0, 2000), - true = expected_ssh_vsn(Vsn). - -%%-------------------------------------------------------------------- -id_string_own_string_server(Config) -> - {_Server, Host, Port} = std_daemon(Config, [{id_string,"Olle"}]), - {ok,S1}=gen_tcp:connect(Host,Port,[{active,false},{packet,line}]), - {ok,"SSH-2.0-Olle\r\n"} = gen_tcp:recv(S1, 0, 2000). - -%%-------------------------------------------------------------------- -id_string_random_server(Config) -> - {_Server, Host, Port} = std_daemon(Config, [{id_string,random}]), - {ok,S1}=gen_tcp:connect(Host,Port,[{active,false},{packet,line}]), - {ok,"SSH-2.0-"++Rnd} = gen_tcp:recv(S1, 0, 2000), - case Rnd of - "Erlang"++_ -> ct:log("Id=~p",[Rnd]), - {fail,got_default_id}; - "Olle\r\n" -> {fail,got_previous_tests_value}; - _ -> ct:log("Got ~s.",[Rnd]) - end. - +shell_no_unicode(Config) -> + new_do_shell(?config(io,Config), + [new_prompt, + {type,"io:format(\"hej ~p~n\",[42])."}, + {expect,"hej 42"}, + {expect,"ok"}, + new_prompt, + {type,"exit()."} + ]). + %%-------------------------------------------------------------------- -ssh_connect_negtimeout_parallel(Config) -> ssh_connect_negtimeout(Config,true). -ssh_connect_negtimeout_sequential(Config) -> ssh_connect_negtimeout(Config,false). - -ssh_connect_negtimeout(Config, Parallel) -> - process_flag(trap_exit, true), - SystemDir = filename:join(?config(priv_dir, Config), system), - UserDir = ?config(priv_dir, Config), - NegTimeOut = 2000, % ms - ct:log("Parallel: ~p",[Parallel]), - - {_Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},{user_dir, UserDir}, - {parallel_login, Parallel}, - {negotiation_timeout, NegTimeOut}, - {failfun, fun ssh_test_lib:failfun/2}]), - - {ok,Socket} = gen_tcp:connect(Host, Port, []), - - Factor = 2, - ct:pal("And now sleeping ~p*NegTimeOut (~p ms)...", [Factor, round(Factor * NegTimeOut)]), - ct:sleep(round(Factor * NegTimeOut)), - - case inet:sockname(Socket) of - {ok,_} -> ct:fail("Socket not closed"); - {error,_} -> ok - end. - -%%-------------------------------------------------------------------- -ssh_connect_nonegtimeout_connected_parallel() -> - [{doc, "Test that ssh connection does not timeout if the connection is established (parallel)"}]. -ssh_connect_nonegtimeout_connected_parallel(Config) -> - ssh_connect_nonegtimeout_connected(Config, true). - -ssh_connect_nonegtimeout_connected_sequential() -> - [{doc, "Test that ssh connection does not timeout if the connection is established (non-parallel)"}]. -ssh_connect_nonegtimeout_connected_sequential(Config) -> - ssh_connect_nonegtimeout_connected(Config, false). - - -ssh_connect_nonegtimeout_connected(Config, Parallel) -> - process_flag(trap_exit, true), - SystemDir = filename:join(?config(priv_dir, Config), system), - UserDir = ?config(priv_dir, Config), - NegTimeOut = 20000, % ms - ct:log("Parallel: ~p",[Parallel]), - - {_Pid, _Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},{user_dir, UserDir}, - {parallel_login, Parallel}, - {negotiation_timeout, NegTimeOut}, - {failfun, fun ssh_test_lib:failfun/2}]), - ct:pal("~p Listen ~p:~p",[_Pid,_Host,Port]), - ct:sleep(500), - - IO = ssh_test_lib:start_io_server(), - Shell = ssh_test_lib:start_shell(Port, IO, UserDir), - receive - Error = {'EXIT', _, _} -> - ct:pal("~p",[Error]), - ct:fail(no_ssh_connection); - ErlShellStart -> - ct:pal("---Erlang shell start: ~p~n", [ErlShellStart]), - one_shell_op(IO, NegTimeOut), - one_shell_op(IO, NegTimeOut), - - Factor = 2, - ct:pal("And now sleeping ~p*NegTimeOut (~p ms)...", [Factor, round(Factor * NegTimeOut)]), - ct:sleep(round(Factor * NegTimeOut)), - - one_shell_op(IO, NegTimeOut) - end, - exit(Shell, kill). - - -one_shell_op(IO, TimeOut) -> - ct:pal("One shell op: Waiting for prompter"), - receive - ErlPrompt0 -> ct:log("Erlang prompt: ~p~n", [ErlPrompt0]) - after TimeOut -> ct:fail("Timeout waiting for promter") - end, - - IO ! {input, self(), "2*3*7.\r\n"}, - receive - Echo0 -> ct:log("Echo: ~p ~n", [Echo0]) - after TimeOut -> ct:fail("Timeout waiting for echo") - end, - - receive - ?NEWLINE -> ct:log("NEWLINE received", []) - after TimeOut -> - receive Any1 -> ct:log("Bad NEWLINE: ~p",[Any1]) - after 0 -> ct:fail("Timeout waiting for NEWLINE") - end - end, - - receive - Result0 -> ct:log("Result: ~p~n", [Result0]) - after TimeOut -> ct:fail("Timeout waiting for result") - end. +shell_unicode_string(Config) -> + new_do_shell(?config(io,Config), + [new_prompt, + {type,"io:format(\"こにちわ~ts~n\",[\"四二\"])."}, + {expect,"こにちわ四二"}, + {expect,"ok"}, + new_prompt, + {type,"exit()."} + ]). %%-------------------------------------------------------------------- - -openssh_zlib_basic_test() -> - [{doc, "Test basic connection with openssh_zlib"}]. +%%% Test basic connection with openssh_zlib openssh_zlib_basic_test(Config) -> - SystemDir = filename:join(?config(priv_dir, Config), system), - UserDir = ?config(priv_dir, Config), + case ssh_test_lib:ssh_supports(['[email protected]',none], compression) of + {false,L} -> + {skip, io_lib:format("~p compression is not supported",[L])}; - {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, - {user_dir, UserDir}, - {preferred_algorithms,[{compression, ['[email protected]']}]}, - {failfun, fun ssh_test_lib:failfun/2}]), - ConnectionRef = - ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, - {user_dir, UserDir}, - {user_interaction, false}, - {preferred_algorithms,[{compression, ['[email protected]', - none]}]} - ]), - ok = ssh:close(ConnectionRef), - ssh:stop_daemon(Pid). - -%%-------------------------------------------------------------------- - -max_sessions_ssh_connect_parallel(Config) -> - max_sessions(Config, true, connect_fun(ssh__connect,Config)). -max_sessions_ssh_connect_sequential(Config) -> - max_sessions(Config, false, connect_fun(ssh__connect,Config)). - -max_sessions_sftp_start_channel_parallel(Config) -> - max_sessions(Config, true, connect_fun(ssh_sftp__start_channel, Config)). -max_sessions_sftp_start_channel_sequential(Config) -> - max_sessions(Config, false, connect_fun(ssh_sftp__start_channel, Config)). - - -%%%---- helpers: -connect_fun(ssh__connect, Config) -> - fun(Host,Port) -> - ssh_test_lib:connect(Host, Port, - [{silently_accept_hosts, true}, - {user_dir, ?config(priv_dir,Config)}, - {user_interaction, false}, - {user, "carni"}, - {password, "meat"} - ]) - %% ssh_test_lib returns R when ssh:connect returns {ok,R} - end; -connect_fun(ssh_sftp__start_channel, _Config) -> - fun(Host,Port) -> - {ok,_Pid,ConnRef} = - ssh_sftp:start_channel(Host, Port, - [{silently_accept_hosts, true}, - {user, "carni"}, - {password, "meat"} - ]), - ConnRef - end. + true -> + SystemDir = filename:join(?config(priv_dir, Config), system), + UserDir = ?config(priv_dir, Config), - -max_sessions(Config, ParallelLogin, Connect0) when is_function(Connect0,2) -> - Connect = fun(Host,Port) -> - R = Connect0(Host,Port), - ct:pal("Connect(~p,~p) -> ~p",[Host,Port,R]), - R - end, - SystemDir = filename:join(?config(priv_dir, Config), system), - UserDir = ?config(priv_dir, Config), - MaxSessions = 5, - {Pid, Host, Port} = ssh_test_lib:daemon([ - {system_dir, SystemDir}, - {user_dir, UserDir}, - {user_passwords, [{"carni", "meat"}]}, - {parallel_login, ParallelLogin}, - {max_sessions, MaxSessions} - ]), - ct:pal("~p Listen ~p:~p for max ~p sessions",[Pid,Host,Port,MaxSessions]), - try [Connect(Host,Port) || _ <- lists:seq(1,MaxSessions)] - of - Connections -> - %% Step 1 ok: could set up max_sessions connections - ct:log("Connections up: ~p",[Connections]), - [_|_] = Connections, - - %% Now try one more than alowed: - ct:pal("Info Report might come here...",[]), - try Connect(Host,Port) - of - _ConnectionRef1 -> - ssh:stop_daemon(Pid), - {fail,"Too many connections accepted"} - catch - error:{badmatch,{error,"Connection closed"}} -> - %% Step 2 ok: could not set up max_sessions+1 connections - %% This is expected - %% Now stop one connection and try to open one more - ok = ssh:close(hd(Connections)), - receive after 250 -> ok end, % sleep so the supervisor has time to count down. Not nice... - try Connect(Host,Port) - of - _ConnectionRef1 -> - %% Step 3 ok: could set up one more connection after killing one - %% Thats good. - ssh:stop_daemon(Pid), - ok - catch - error:{badmatch,{error,"Connection closed"}} -> - %% Bad indeed. Could not set up one more connection even after killing - %% one existing. Very bad. - ssh:stop_daemon(Pid), - {fail,"Does not decrease # active sessions"} - end - end - catch - error:{badmatch,{error,"Connection closed"}} -> - ssh:stop_daemon(Pid), - {fail,"Too few connections accepted"} + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + {user_dir, UserDir}, + {preferred_algorithms,[{compression, ['[email protected]']}]}, + {failfun, fun ssh_test_lib:failfun/2}]), + ConnectionRef = + ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user_dir, UserDir}, + {user_interaction, false}, + {preferred_algorithms,[{compression, ['[email protected]', + none]}]} + ]), + ok = ssh:close(ConnectionRef), + ssh:stop_daemon(Pid) end. %%-------------------------------------------------------------------- @@ -1783,15 +1101,82 @@ ssh_info_print(Config) -> %%-------------------------------------------------------------------- +%% Check that a basd pwd is not tried more times. Could cause lock-out +%% on server + +login_bad_pwd_no_retry1(Config) -> + login_bad_pwd_no_retry(Config, "keyboard-interactive,password"). + +login_bad_pwd_no_retry2(Config) -> + login_bad_pwd_no_retry(Config, "password,keyboard-interactive"). + +login_bad_pwd_no_retry3(Config) -> + login_bad_pwd_no_retry(Config, "password,publickey,keyboard-interactive"). + +login_bad_pwd_no_retry4(Config) -> + login_bad_pwd_no_retry(Config, "password,other,keyboard-interactive"). + +login_bad_pwd_no_retry5(Config) -> + login_bad_pwd_no_retry(Config, "password,other,keyboard-interactive,password,password"). + + + + + +login_bad_pwd_no_retry(Config, AuthMethods) -> + PrivDir = proplists:get_value(priv_dir, Config), + UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), + SysDir = proplists:get_value(data_dir, Config), + + Parent = self(), + PwdFun = fun(_, _, _, undefined) -> {false, 1}; + (_, _, _, _) -> Parent ! retry_bad_pwd, + false + end, + + {DaemonRef, _Host, Port} = + ssh_test_lib:daemon([{system_dir, SysDir}, + {user_dir, UserDir}, + {auth_methods, AuthMethods}, + {user_passwords, [{"foo","somepwd"}]}, + {pwdfun, PwdFun} + ]), + + ConnRes = ssh:connect("localhost", Port, + [{silently_accept_hosts, true}, + {user, "foo"}, + {password, "badpwd"}, + {user_dir, UserDir}, + {user_interaction, false}]), + + receive + retry_bad_pwd -> + ssh:stop_daemon(DaemonRef), + {fail, "Retry bad password"} + after 0 -> + case ConnRes of + {error,"Unable to connect using the available authentication methods"} -> + ssh:stop_daemon(DaemonRef), + ok; + {ok,Conn} -> + ssh:close(Conn), + ssh:stop_daemon(DaemonRef), + {fail, "Connect erroneosly succeded"} + end + end. + +%%-------------------------------------------------------------------- %% Internal functions ------------------------------------------------ %%-------------------------------------------------------------------- - %% Due to timing the error message may or may not be delivered to %% the "tcp-application" before the socket closed message is recived check_error("Invalid state") -> ok; check_error("Connection closed") -> ok; +check_error("Selection of key exchange algorithm failed") -> + ok; check_error(Error) -> ct:fail(Error). @@ -1807,28 +1192,38 @@ basic_test(Config) -> do_shell(IO, Shell) -> receive ErlPrompt0 -> - ct:pal("Erlang prompt: ~p~n", [ErlPrompt0]) + ct:log("Erlang prompt: ~p~n", [ErlPrompt0]) end, IO ! {input, self(), "1+1.\r\n"}, receive Echo0 -> - ct:pal("Echo: ~p ~n", [Echo0]) + ct:log("Echo: ~p ~n", [Echo0]) + after + 10000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end, receive ?NEWLINE -> ok + after + 10000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end, receive Result0 = <<"2">> -> - ct:pal("Result: ~p~n", [Result0]) + ct:log("Result: ~p~n", [Result0]) + after + 10000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end, receive ?NEWLINE -> ok + after + 10000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end, receive ErlPrompt1 -> - ct:pal("Erlang prompt: ~p~n", [ErlPrompt1]) + ct:log("Erlang prompt: ~p~n", [ErlPrompt1]) + after + 10000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end, exit(Shell, kill). %%Does not seem to work in the testserver! @@ -1839,7 +1234,7 @@ do_shell(IO, Shell) -> %% end, %% receive %% Echo1 -> - %% ct:pal("Echo: ~p ~n", [Echo1]) + %% ct:log("Echo: ~p ~n", [Echo1]) %% end, %% receive %% ?NEWLINE -> @@ -1847,7 +1242,7 @@ do_shell(IO, Shell) -> %% end, %% receive %% Result1 -> - %% ct:pal("Result: ~p~n", [Result1]) + %% ct:log("Result: ~p~n", [Result1]) %% end, %% receive %% {'EXIT', Shell, killed} -> @@ -1855,60 +1250,90 @@ do_shell(IO, Shell) -> %% end. -std_daemon(Config, ExtraOpts) -> - SystemDir = ?config(data_dir, Config), - PrivDir = ?config(priv_dir, Config), - UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth - file:make_dir(UserDir), - {_Server, _Host, _Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, - {user_dir, UserDir}, - {failfun, fun ssh_test_lib:failfun/2} | ExtraOpts]). - -expected_ssh_vsn(Str) -> - try - {ok,L} = application:get_all_key(ssh), - proplists:get_value(vsn,L,"")++"\r\n" - of - Str -> true; - "\r\n" -> true; - _ -> false - catch - _:_ -> true %% ssh not started so we dont't know +%%-------------------------------------------------------------------- +wait_for_erlang_first_line(Config) -> + receive + {'EXIT', _, _} -> + {fail,no_ssh_connection}; + <<"Eshell ",_/binary>> = _ErlShellStart -> + ct:log("Erlang shell start: ~p~n", [_ErlShellStart]), + Config; + Other -> + ct:log("Unexpected answer from ssh server: ~p",[Other]), + {fail,unexpected_answer} + after 10000 -> + ct:log("No answer from ssh-server"), + {fail,timeout} end. - -fake_daemon(_Config) -> - Parent = self(), - %% start the server - Server = spawn(fun() -> - {ok,Sl} = gen_tcp:listen(0,[{packet,line}]), - {ok,{Host,Port}} = inet:sockname(Sl), - ct:log("fake_daemon listening on ~p:~p~n",[Host,Port]), - Parent ! {sockname,self(),Host,Port}, - Rsa = gen_tcp:accept(Sl), - ct:log("Server gen_tcp:accept got ~p",[Rsa]), - {ok,S} = Rsa, - receive - {tcp, S, Id} -> Parent ! {id,self(),Id} - end - end), - %% Get listening host and port + + +new_do_shell(IO, List) -> new_do_shell(IO, 0, List). + +new_do_shell(IO, N, [new_prompt|More]) -> + new_do_shell(IO, N+1, More); + +new_do_shell(IO, N, Ops=[{Order,Arg}|More]) -> + Pfx = prompt_prefix(), + PfxSize = size(Pfx), receive - {sockname,Server,ServerHost,ServerPort} -> {Server, ServerHost, ServerPort} - end. + _X = <<"\r\n">> -> + ct:log("Skip newline ~p",[_X]), + new_do_shell(IO, N, Ops); + + <<Pfx:PfxSize/binary,P1,"> ">> when (P1-$0)==N -> + new_do_shell_prompt(IO, N, Order, Arg, More); + + <<Pfx:PfxSize/binary,P1,P2,"> ">> when (P1-$0)*10 + (P2-$0) == N -> + new_do_shell_prompt(IO, N, Order, Arg, More); + + <<Pfx:PfxSize/binary,P1,P2,P3,"> ">> when (P1-$0)*100 + (P2-$0)*10 + (P3-$0) == N -> + new_do_shell_prompt(IO, N, Order, Arg, More); + + Err when element(1,Err)==error -> + ct:fail("new_do_shell error: ~p~n",[Err]); + + RecBin when Order==expect ; Order==expect_echo -> + ct:log("received ~p",[RecBin]), + RecStr = string:strip(unicode:characters_to_list(RecBin)), + ExpStr = string:strip(Arg), + case lists:prefix(ExpStr, RecStr) of + true when Order==expect -> + ct:log("Matched ~ts",[RecStr]), + new_do_shell(IO, N, More); + true when Order==expect_echo -> + ct:log("Matched echo ~ts",[RecStr]), + new_do_shell(IO, N, More); + false -> + ct:fail("*** Expected ~p, but got ~p",[string:strip(ExpStr),RecStr]) + end + after 30000 -> + ct:log("Meassage queue of ~p:~n~p", + [self(), erlang:process_info(self(), messages)]), + case Order of + expect -> ct:fail("timeout, expected ~p",[string:strip(Arg)]); + type -> ct:fail("timeout, no prompt") + end + end; -%% get_kex_init - helper function to get key_exchange_init_msg -get_kex_init(Conn) -> - %% First, validate the key exchange is complete (StateName == connected) - {connected,S} = sys:get_state(Conn), - %% Next, walk through the elements of the #state record looking - %% for the #ssh_msg_kexinit record. This method is robust against - %% changes to either record. The KEXINIT message contains a cookie - %% unique to each invocation of the key exchange procedure (RFC4253) - SL = tuple_to_list(S), - case lists:keyfind(ssh_msg_kexinit, 1, SL) of - false -> - throw(not_found); - KexInit -> - KexInit +new_do_shell(_, _, []) -> + ok. + +prompt_prefix() -> + case node() of + nonode@nohost -> <<>>; + Node -> list_to_binary( + lists:concat(["(",Node,")"])) end. + + +new_do_shell_prompt(IO, N, type, Str, More) -> + ct:log("Matched prompt ~p to trigger sending of next line to server",[N]), + IO ! {input, self(), Str++"\r\n"}, + ct:log("Promt '~p> ', Sent ~ts",[N,Str++"\r\n"]), + new_do_shell(IO, N, [{expect_echo,Str}|More]); % expect echo of the sent line +new_do_shell_prompt(IO, N, Op, Str, More) -> + ct:log("Matched prompt ~p",[N]), + new_do_shell(IO, N, [{Op,Str}|More]). + +%%-------------------------------------------------------------------- diff --git a/lib/ssh/test/ssh_basic_SUITE_data/id_ecdsa256 b/lib/ssh/test/ssh_basic_SUITE_data/id_ecdsa256 new file mode 100644 index 0000000000..4b1eb12eaa --- /dev/null +++ b/lib/ssh/test/ssh_basic_SUITE_data/id_ecdsa256 @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIJfCaBKIIKhjbJl5F8BedqlXOQYDX5ba9Skypllmx/w+oAoGCCqGSM49 +AwEHoUQDQgAE49RbK2xQ/19ji3uDPM7uT4692LbwWF1TiaA9vUuebMGazoW/98br +N9xZu0L1AWwtEjs3kmJDTB7eJEGXnjUAcQ== +-----END EC PRIVATE KEY----- diff --git a/lib/ssh/test/ssh_basic_SUITE_data/id_ecdsa256.pub b/lib/ssh/test/ssh_basic_SUITE_data/id_ecdsa256.pub new file mode 100644 index 0000000000..a0147e60fa --- /dev/null +++ b/lib/ssh/test/ssh_basic_SUITE_data/id_ecdsa256.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOPUWytsUP9fY4t7gzzO7k+Ovdi28FhdU4mgPb1LnmzBms6Fv/fG6zfcWbtC9QFsLRI7N5JiQ0we3iRBl541AHE= uabhnil@elxadlj3q32 diff --git a/lib/ssh/test/ssh_basic_SUITE_data/id_ecdsa384 b/lib/ssh/test/ssh_basic_SUITE_data/id_ecdsa384 new file mode 100644 index 0000000000..4e8aa40959 --- /dev/null +++ b/lib/ssh/test/ssh_basic_SUITE_data/id_ecdsa384 @@ -0,0 +1,6 @@ +-----BEGIN EC PRIVATE KEY----- +MIGkAgEBBDCYXb6OSAZyXRfLXOtMo43za197Hdc/T0YKjgQQjwDt6rlRwqTh7v7S +PV2kXwNGdWigBwYFK4EEACKhZANiAARN2khlJUOOIiwsWHEALwDieeZR96qL4pUd +ci7aeGaczdUK5jOA9D9zmBZtSYTfO8Cr7ekVghDlcWAIJ/BXcswgQwSEQ6wyfaTF +8FYfyr4l3u9IirsnyaFzeIgeoNis8Gw= +-----END EC PRIVATE KEY----- diff --git a/lib/ssh/test/ssh_basic_SUITE_data/id_ecdsa384.pub b/lib/ssh/test/ssh_basic_SUITE_data/id_ecdsa384.pub new file mode 100644 index 0000000000..41e722e545 --- /dev/null +++ b/lib/ssh/test/ssh_basic_SUITE_data/id_ecdsa384.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBE3aSGUlQ44iLCxYcQAvAOJ55lH3qovilR1yLtp4ZpzN1QrmM4D0P3OYFm1JhN87wKvt6RWCEOVxYAgn8FdyzCBDBIRDrDJ9pMXwVh/KviXe70iKuyfJoXN4iB6g2KzwbA== uabhnil@elxadlj3q32 diff --git a/lib/ssh/test/ssh_basic_SUITE_data/id_ecdsa521 b/lib/ssh/test/ssh_basic_SUITE_data/id_ecdsa521 new file mode 100644 index 0000000000..7196f46e97 --- /dev/null +++ b/lib/ssh/test/ssh_basic_SUITE_data/id_ecdsa521 @@ -0,0 +1,7 @@ +-----BEGIN EC PRIVATE KEY----- +MIHbAgEBBEFMadoz4ckEcClfqXa2tiUuYkJdDfwq+/iFQcpt8ESuEd26IY/vm47Q +9UzbPkO4ou8xkNsQ3WvCRQBBWtn5O2kUU6AHBgUrgQQAI6GBiQOBhgAEAde5BRu5 +01/jS0jRk212xsb2DxPrxNpgp6IMCV8TA4Eps+8bSqHB091nLiBcP422HXYfuCd7 +XDjSs8ihcmhp0hCRASLqZR9EzW9W/SOt876May1Huj5X+WSO6RLe7vPn9vmf7kHf +pip6m7M7qp2qGgQ3q2vRwS2K/O6156ohiOlmuuFs +-----END EC PRIVATE KEY----- diff --git a/lib/ssh/test/ssh_basic_SUITE_data/id_ecdsa521.pub b/lib/ssh/test/ssh_basic_SUITE_data/id_ecdsa521.pub new file mode 100644 index 0000000000..8f059120bc --- /dev/null +++ b/lib/ssh/test/ssh_basic_SUITE_data/id_ecdsa521.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAHXuQUbudNf40tI0ZNtdsbG9g8T68TaYKeiDAlfEwOBKbPvG0qhwdPdZy4gXD+Nth12H7gne1w40rPIoXJoadIQkQEi6mUfRM1vVv0jrfO+jGstR7o+V/lkjukS3u7z5/b5n+5B36YqepuzO6qdqhoEN6tr0cEtivzuteeqIYjpZrrhbA== uabhnil@elxadlj3q32 diff --git a/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ecdsa_key256 b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ecdsa_key256 new file mode 100644 index 0000000000..2979ea88ed --- /dev/null +++ b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ecdsa_key256 @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIMe4MDoit0t8RzSVPwkCBemQ9fhXL+xnTSAWISw8HNCioAoGCCqGSM49 +AwEHoUQDQgAEo2q7U3P6r0W5WGOLtM78UQtofM9UalEhiZeDdiyylsR/RR17Op0s +VPGSADLmzzgcucLEKy17j2S+oz42VUJy5A== +-----END EC PRIVATE KEY----- diff --git a/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ecdsa_key256.pub b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ecdsa_key256.pub new file mode 100644 index 0000000000..85dc419345 --- /dev/null +++ b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ecdsa_key256.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKNqu1Nz+q9FuVhji7TO/FELaHzPVGpRIYmXg3YsspbEf0UdezqdLFTxkgAy5s84HLnCxCste49kvqM+NlVCcuQ= uabhnil@elxadlj3q32 diff --git a/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ecdsa_key384 b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ecdsa_key384 new file mode 100644 index 0000000000..fb1a862ded --- /dev/null +++ b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ecdsa_key384 @@ -0,0 +1,6 @@ +-----BEGIN EC PRIVATE KEY----- +MIGkAgEBBDArxbDfh3p1okrD9wQw6jJ4d4DdlBPD5GqXE8bIeRJiK41Sh40LgvPw +mkqEDSXK++CgBwYFK4EEACKhZANiAAScl43Ih2lWTDKrSox5ve5uiTXil4smsup3 +CfS1XPjKxgBAmlfBim8izbdrT0BFdQzz2joduNMtpt61wO4rGs6jm0UP7Kim9PC7 +Hneb/99fIYopdMH5NMnk60zGO1uZ2vc= +-----END EC PRIVATE KEY----- diff --git a/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ecdsa_key384.pub b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ecdsa_key384.pub new file mode 100644 index 0000000000..428d5fb7d7 --- /dev/null +++ b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ecdsa_key384.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBJyXjciHaVZMMqtKjHm97m6JNeKXiyay6ncJ9LVc+MrGAECaV8GKbyLNt2tPQEV1DPPaOh240y2m3rXA7isazqObRQ/sqKb08Lsed5v/318hiil0wfk0yeTrTMY7W5na9w== uabhnil@elxadlj3q32 diff --git a/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ecdsa_key521 b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ecdsa_key521 new file mode 100644 index 0000000000..3e51ec2ecd --- /dev/null +++ b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ecdsa_key521 @@ -0,0 +1,7 @@ +-----BEGIN EC PRIVATE KEY----- +MIHcAgEBBEIB8O1BFkl2HQjQLRLonEZ97da/h39DMa9/0/hvPZWAI8gUPEQcHxRx +U7b09p3Zh+EBbMFq8+1ae9ds+ZTxE4WFSvKgBwYFK4EEACOhgYkDgYYABAAlWVjq +Bzg7Wt4gE6UNb1lRE2cnlmH2L/A5uo6qZRx5lPnSKOxEhxSb/Oay1+9d6KRdrh6/ +vlhd9SHDBhLcAPDvWgBnJIEj92Q3pXX4JtoitL0yl+SvvU+vUh966mzHShHzj8p5 +ccOgPkPNoA70yrpGzkIhPezpZOQdCaOXj/jFqNCTDg== +-----END EC PRIVATE KEY----- diff --git a/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ecdsa_key521.pub b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ecdsa_key521.pub new file mode 100644 index 0000000000..017a29f4da --- /dev/null +++ b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ecdsa_key521.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAAlWVjqBzg7Wt4gE6UNb1lRE2cnlmH2L/A5uo6qZRx5lPnSKOxEhxSb/Oay1+9d6KRdrh6/vlhd9SHDBhLcAPDvWgBnJIEj92Q3pXX4JtoitL0yl+SvvU+vUh966mzHShHzj8p5ccOgPkPNoA70yrpGzkIhPezpZOQdCaOXj/jFqNCTDg== uabhnil@elxadlj3q32 diff --git a/lib/ssh/test/ssh_bench.spec b/lib/ssh/test/ssh_bench.spec new file mode 100644 index 0000000000..029f0bd074 --- /dev/null +++ b/lib/ssh/test/ssh_bench.spec @@ -0,0 +1 @@ +{suites,"../ssh_test",[ssh_benchmark_SUITE]}. diff --git a/lib/ssh/test/ssh_benchmark_SUITE.erl b/lib/ssh/test/ssh_benchmark_SUITE.erl new file mode 100644 index 0000000000..fe90da3028 --- /dev/null +++ b/lib/ssh/test/ssh_benchmark_SUITE.erl @@ -0,0 +1,536 @@ +%%%------------------------------------------------------------------- +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2015. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% +-module(ssh_benchmark_SUITE). +-compile(export_all). + +-include_lib("common_test/include/ct_event.hrl"). +-include_lib("common_test/include/ct.hrl"). + +-include_lib("ssh/src/ssh.hrl"). +-include_lib("ssh/src/ssh_transport.hrl"). +-include_lib("ssh/src/ssh_connect.hrl"). +-include_lib("ssh/src/ssh_userauth.hrl"). + + +suite() -> [{ct_hooks,[{ts_install_cth,[{nodenames,2}]}]}]. +%%suite() -> [{ct_hooks,[ts_install_cth]}]. + +all() -> [{group, opensshc_erld} +%% {group, erlc_opensshd} + ]. + +groups() -> + [{opensshc_erld, [{repeat, 3}], [openssh_client_shell, + openssh_client_sftp]} + ]. + + +init_per_suite(Config) -> + catch ssh:stop(), + try + report_client_algorithms(), + ok = ssh:start(), + {ok,TracerPid} = erlang_trace(), + [{tracer_pid,TracerPid} | init_sftp_dirs(Config)] + catch + C:E -> + {skip, io_lib:format("Couldn't start ~p:~p",[C,E])} + end. + +end_per_suite(_Config) -> + catch ssh:stop(), + ok. + + + +init_per_group(opensshc_erld, Config) -> + case ssh_test_lib:ssh_type() of + openSSH -> + DataDir = ?config(data_dir, Config), + UserDir = ?config(priv_dir, Config), + ssh_test_lib:setup_dsa(DataDir, UserDir), + ssh_test_lib:setup_rsa(DataDir, UserDir), + ssh_test_lib:setup_ecdsa("256", DataDir, UserDir), + Common = ssh_test_lib:intersect_bi_dir( + ssh_test_lib:intersection(ssh:default_algorithms(), + ssh_test_lib:default_algorithms(sshc))), + [{c_kexs, ssh_test_lib:sshc(kex)}, + {c_ciphers, ssh_test_lib:sshc(cipher)}, + {common_algs, Common} + | Config]; + _ -> + {skip, "No OpenSsh client found"} + end; + +init_per_group(erlc_opensshd, _) -> + {skip, "Group erlc_opensshd not implemented"}; + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, _Config) -> + ok. + + +init_per_testcase(_Func, Conf) -> + Conf. + +end_per_testcase(_Func, _Conf) -> + ok. + + +init_sftp_dirs(Config) -> + UserDir = ?config(priv_dir, Config), + SrcDir = filename:join(UserDir, "sftp_src"), + ok = file:make_dir(SrcDir), + SrcFile = "big_data", + DstDir = filename:join(UserDir, "sftp_dst"), + ok = file:make_dir(DstDir), + N = 100 * 1024*1024, + ok = file:write_file(filename:join(SrcDir,SrcFile), crypto:rand_bytes(N)), + [{sftp_src_dir,SrcDir}, {sftp_dst_dir,DstDir}, {src_file,SrcFile}, {sftp_size,N} + | Config]. + +%%%================================================================ +openssh_client_shell(Config) -> + lists:foreach( + fun(PrefAlgs=[{kex,[Kex]}]) when Kex == 'diffie-hellman-group-exchange-sha256' -> + lists:foreach( + fun(Grp) -> + openssh_client_shell(Config, + [{preferred_algorithms, PrefAlgs}, + {dh_gex_groups, [Grp]} + ]) + end, moduli()); + (PrefAlgs) -> + openssh_client_shell(Config, + [{preferred_algorithms, PrefAlgs}]) + end, variants(kex,Config) ++ variants(cipher,Config) + ). + + +openssh_client_shell(Config, Options) -> + SystemDir = ?config(data_dir, Config), + UserDir = ?config(priv_dir, Config), + KnownHosts = filename:join(UserDir, "known_hosts"), + + {ok, TracerPid} = erlang_trace(), + {ServerPid, _Host, Port} = + ssh_test_lib:daemon([{system_dir, SystemDir}, + {public_key_alg, ssh_dsa}, + {failfun, fun ssh_test_lib:failfun/2} | + Options]), + ct:sleep(500), + + Data = lists:duplicate(100000, $a), + Cmd = lists:concat(["ssh -p ",Port, + " -o UserKnownHostsFile=", KnownHosts, + " -o \"StrictHostKeyChecking no\"", + " localhost '\"",Data,"\"'."]), +%% ct:pal("Cmd ="++Cmd), + + Parent = self(), + SlavePid = spawn(fun() -> + Parent ! {self(),os:cmd(Cmd)} + end), + receive + {SlavePid, _ClientResponse} -> +%% ct:pal("ClientResponse = ~p",[_ClientResponse]), + {ok, List} = get_trace_list(TracerPid), + Times = find_times(List, [accept_to_hello, kex, kex_to_auth, auth, to_prompt]), + Algs = find_algs(List), + ct:pal("Algorithms = ~p~n~nTimes = ~p",[Algs,Times]), + lists:foreach( + fun({Tag,Value,Unit}) -> + EventData = + case Tag of + {A,B} when A==encrypt ; A==decrypt -> + [{value, Value}, + {suite, ?MODULE}, + {name, mk_name(["Cipher ",A," ",B," [",Unit,"]"])} + ]; + kex -> + KexAlgStr = fmt_alg(Algs#alg.kex, List), + [{value, Value}, + {suite, ?MODULE}, + {name, mk_name(["Erl server kex ",KexAlgStr," [",Unit,"]"])} + ]; + _ when is_atom(Tag) -> + [{value, Value}, + {suite, ?MODULE}, + {name, mk_name(["Erl server ",Tag," [",Unit,"]"])} + ] + end, + ct:pal("ct_event:notify ~p",[EventData]), + ct_event:notify(#event{name = benchmark_data, + data = EventData}) + end, Times), + ssh:stop_daemon(ServerPid), + ok + after 10000 -> + ssh:stop_daemon(ServerPid), + exit(SlavePid, kill), + {fail, timeout} + end. + + +%%%================================================================ +openssh_client_sftp(Config) -> + lists:foreach( + fun(PrefAlgs) -> + openssh_client_sftp(Config, [{preferred_algorithms,PrefAlgs}]) + end, variants(cipher,Config)). + + +openssh_client_sftp(Config, Options) -> + SystemDir = ?config(data_dir, Config), + UserDir = ?config(priv_dir, Config), + SftpSrcDir = ?config(sftp_src_dir, Config), + SrcFile = ?config(src_file, Config), + SrcSize = ?config(sftp_size, Config), + KnownHosts = filename:join(UserDir, "known_hosts"), + + {ok, TracerPid} = erlang_trace(), + {ServerPid, _Host, Port} = + ssh_test_lib:daemon([{system_dir, SystemDir}, + {public_key_alg, ssh_dsa}, + {subsystems,[ssh_sftpd:subsystem_spec([%{cwd, SftpSrcDir}, + {root, SftpSrcDir}])]}, + {failfun, fun ssh_test_lib:failfun/2} + | Options]), + ct:sleep(500), + Cmd = lists:concat(["sftp", + " -b -", + " -P ",Port, + " -o UserKnownHostsFile=", KnownHosts, + " -o \"StrictHostKeyChecking no\"", + " localhost:",SrcFile + ]), +%% ct:pal("Cmd = ~p",[Cmd]), + + Parent = self(), + SlavePid = spawn(fun() -> + Parent ! {self(),os:cmd(Cmd)} + end), + receive + {SlavePid, _ClientResponse} -> + ct:pal("ClientResponse = ~p",[_ClientResponse]), + {ok, List} = get_trace_list(TracerPid), +%%ct:pal("List=~p",[List]), + Times = find_times(List, [channel_open_close]), + Algs = find_algs(List), + ct:pal("Algorithms = ~p~n~nTimes = ~p",[Algs,Times]), + lists:foreach( + fun({{A,B},Value,Unit}) when A==encrypt ; A==decrypt -> + Data = [{value, Value}, + {suite, ?MODULE}, + {name, mk_name(["Sftp Cipher ",A," ",B," [",Unit,"]"])} + ], + ct:pal("sftp ct_event:notify ~p",[Data]), + ct_event:notify(#event{name = benchmark_data, + data = Data}); + ({channel_open_close,Value,Unit}) -> + Cipher = fmt_alg(Algs#alg.encrypt, List), + Data = [{value, round( (1024*Value) / SrcSize )}, + {suite, ?MODULE}, + {name, mk_name(["Sftp transfer ",Cipher," [",Unit," per kbyte]"])} + ], + ct:pal("sftp ct_event:notify ~p",[Data]), + ct_event:notify(#event{name = benchmark_data, + data = Data}); + (_) -> + skip + end, Times), + ssh:stop_daemon(ServerPid), + ok + after 10000 -> + ssh:stop_daemon(ServerPid), + exit(SlavePid, kill), + {fail, timeout} + end. + +%%%================================================================ +variants(Tag, Config) -> + TagType = + case proplists:get_value(Tag, ssh:default_algorithms()) of + [{_,_}|_] -> one_way; + [A|_] when is_atom(A) -> two_way + end, + [ [{Tag,tag_value(TagType,Alg)}] + || Alg <- proplists:get_value(Tag, ?config(common_algs,Config)) + ]. + +tag_value(two_way, Alg) -> [Alg]; +tag_value(one_way, Alg) -> [{client2server,[Alg]}, + {server2client,[Alg]}]. + +%%%---------------------------------------------------------------- +fmt_alg(Alg, List) when is_atom(Alg) -> + fmt_alg(atom_to_list(Alg), List); +fmt_alg(Alg = "diffie-hellman-group-exchange-sha" ++ _, List) -> + try + integer_to_list(find_gex_size_string(List)) + of + GexSize -> lists:concat([Alg," ",GexSize]) + catch + _:_ -> Alg + end; +fmt_alg(Alg, _List) -> + Alg. + +%%%---------------------------------------------------------------- +mk_name(Name) -> [char(C) || C <- lists:concat(Name)]. + +char($-) -> $_; +char(C) -> C. + +%%%---------------------------------------------------------------- +find_times(L, Xs) -> + [find_time(X,L) || X <- Xs] ++ + function_algs_times_sizes([{ssh_transport,encrypt,2}, + {ssh_transport,decrypt,2}, + {ssh_message,decode,1}, + {ssh_message,encode,1}], L). + +-record(call, { + mfa, + pid, + t_call, + t_return, + args, + result + }). + +%%%---------------- +-define(send(M), fun(C=#call{mfa = {ssh_message,encode,1}, + args = [M]}) -> + C#call.t_return + end). + +-define(recv(M), fun(C=#call{mfa = {ssh_message,decode,1}, + result = M}) -> + C#call.t_call + end). + +find_time(accept_to_hello, L) -> + [T0,T1] = find([fun(C=#call{mfa = {ssh_acceptor,handle_connection,5}}) -> + C#call.t_call + end, + fun(C=#call{mfa = {ssh_connection_handler,hello,_}, + args = [socket_control|_]}) -> + C#call.t_return + end + ], L, []), + {accept_to_hello, now2micro_sec(now_diff(T1,T0)), microsec}; +find_time(kex, L) -> + [T0,T1] = find([fun(C=#call{mfa = {ssh_connection_handler,hello,_}, + args = [socket_control|_]}) -> + C#call.t_call + end, + ?send(#ssh_msg_newkeys{}) + ], L, []), + {kex, now2micro_sec(now_diff(T1,T0)), microsec}; +find_time(kex_to_auth, L) -> + [T0,T1] = find([?send(#ssh_msg_newkeys{}), + ?recv(#ssh_msg_userauth_request{}) + ], L, []), + {kex_to_auth, now2micro_sec(now_diff(T1,T0)), microsec}; +find_time(auth, L) -> + [T0,T1] = find([?recv(#ssh_msg_userauth_request{}), + ?send(#ssh_msg_userauth_success{}) + ], L, []), + {auth, now2micro_sec(now_diff(T1,T0)), microsec}; +find_time(to_prompt, L) -> + [T0,T1] = find([fun(C=#call{mfa = {ssh_acceptor,handle_connection,5}}) -> + C#call.t_call + end, + ?recv(#ssh_msg_channel_request{request_type="env"}) + ], L, []), + {to_prompt, now2micro_sec(now_diff(T1,T0)), microsec}; +find_time(channel_open_close, L) -> + [T0,T1] = find([?recv(#ssh_msg_channel_request{request_type="subsystem"}), + ?send(#ssh_msg_channel_close{}) + ], L, []), + {channel_open_close, now2micro_sec(now_diff(T1,T0)), microsec}. + + + +find([F|Fs], [C|Cs], Acc) when is_function(F,1) -> + try + F(C) + of + T -> find(Fs, Cs, [T|Acc]) + catch + _:_ -> find([F|Fs], Cs, Acc) + end; +find([], _, Acc) -> + lists:reverse(Acc). + + +find_algs(L) -> + {value, #call{result={ok,Algs}}} = + lists:keysearch({ssh_transport,select_algorithm,3}, #call.mfa, L), + Algs. + +find_gex_size_string(L) -> + %% server + {value, #call{result={ok,{Size, _}}}} = + lists:keysearch({public_key,dh_gex_group,4}, #call.mfa, L), + Size. + +%%%---------------- +function_algs_times_sizes(EncDecs, L) -> + Raw = [begin + {Tag,Size} = function_ats_result(EncDec, C), + {Tag, Size, now2micro_sec(now_diff(T1,T0))} + end + || EncDec <- EncDecs, + C = #call{mfa = ED, + % args = Args, %%[S,Data], + t_call = T0, + t_return = T1} <- L, + ED == EncDec + ], + [{Alg, round(1024*Time/Size), "microsec per kbyte"} % Microseconds per 1k bytes. + || {Alg,Size,Time} <- lists:foldl(fun increment/2, [], Raw)]. + +function_ats_result({ssh_transport,encrypt,2}, #call{args=[S,Data]}) -> + {{encrypt,S#ssh.encrypt}, size(Data)}; +function_ats_result({ssh_transport,decrypt,2}, #call{args=[S,Data]}) -> + {{decrypt,S#ssh.decrypt}, size(Data)}; +function_ats_result({ssh_message,encode,1}, #call{result=Data}) -> + {encode, size(Data)}; +function_ats_result({ssh_message,decode,1}, #call{args=[Data]}) -> + {decode, size(Data)}. + + +increment({Alg,Sz,T}, [{Alg,SumSz,SumT}|Acc]) -> + [{Alg,SumSz+Sz,SumT+T} | Acc]; +increment(Spec, [X|Acc]) -> + [X | increment(Spec,Acc)]; % Not so many Alg, 2 or 3 +increment({Alg,Sz,T},[]) -> + [{Alg,Sz,T}]. + +%%%---------------------------------------------------------------- +%%% +%%% API for the traceing +%%% +get_trace_list(TracerPid) -> + TracerPid ! {get_trace_list,self()}, + receive + {trace_list,L} -> {ok, pair_events(lists:reverse(L))} + after 5000 -> {error,no_reply} + end. + +erlang_trace() -> + TracerPid = spawn(fun trace_loop/0), + 0 = erlang:trace(new, true, [call,timestamp,{tracer,TracerPid}]), + [init_trace(MFA, tp(MFA)) + || MFA <- [{ssh_acceptor,handle_connection,5}, + {ssh_connection_handler,hello,2}, + {ssh_message,encode,1}, + {ssh_message,decode,1}, + {ssh_transport,select_algorithm,3}, + {ssh_transport,encrypt,2}, + {ssh_transport,decrypt,2}, + {ssh_message,encode,1}, + {ssh_message,decode,1}, + {public_key,dh_gex_group,4} % To find dh_gex group size + ]], + {ok, TracerPid}. + +tp({_M,_F,Arity}) -> + [{lists:duplicate(Arity,'_'), [], [{return_trace}]}]. + +%%%---------------------------------------------------------------- +init_trace(MFA = {Module,_,_}, TP) -> + case code:is_loaded(Module) of + false -> code:load_file(Module); + _ -> ok + end, + erlang:trace_pattern(MFA, TP, [local]). + + +trace_loop() -> + trace_loop([]). + +trace_loop(L) -> + receive + {get_trace_list, From} -> + From ! {trace_list, L}, + trace_loop(L); + Ev -> + trace_loop([Ev|L]) + end. + +pair_events(L) -> + pair_events(L, []). + +pair_events([{trace_ts,Pid,call,{M,F,Args},TS0} | L], Acc) -> + Arity = length(Args), + {ReturnValue,TS1} = find_return(Pid, {M,F,Arity}, L), + pair_events(L, [#call{mfa = {M,F,Arity}, + pid = Pid, + t_call = TS0, + t_return = TS1, + args = Args, + result = ReturnValue} | Acc]); +pair_events([_|L], Acc) -> + pair_events(L, Acc); +pair_events([], Acc) -> + lists:reverse(Acc). + + +find_return(Pid, MFA, + [{trace_ts, Pid, return_from, MFA, ReturnValue, TS}|_]) -> + {ReturnValue, TS}; +find_return(Pid, MFA, [_|L]) -> + find_return(Pid, MFA, L); +find_return(_, _, []) -> + {undefined, undefined}. + +%%%---------------------------------------------------------------- +report_client_algorithms() -> + try + ssh_test_lib:extract_algos( ssh_test_lib:default_algorithms(sshc) ) + of + ClientAlgs -> + ct:pal("The client supports:~n~p",[ClientAlgs]) + catch + Cls:Err -> + ct:pal("Testing client about algorithms failed:~n~p ~p",[Cls,Err]) + end. + +%%%---------------------------------------------------------------- + + +now2sec({A,B,C}) -> A*1000000 + B + C/1000000. + +now2micro_sec({A,B,C}) -> (A*1000000 + B)*1000000 + C. + +now_diff({A1,B1,C1}, {A0,B0,C0}) -> {A1-A0, B1-B0, C1-C0}. + +%%%================================================================ +moduli() -> + [{1023, 5, 16#CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D182EB7}, + {2047, 5, 16#F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE5E381EF}, + {4095, 2, 16#C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156BA7321EB}, + {6143, 5, 16#FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23C3BEB637}, + {8191, 2, 16#DC61EF13E4F3FC10CC946EEABC33F83EFCB35E0F47E4EC25C1CCBB2C7B502B2EFB0691AA231C8476DD51BA73204E6EA10B1A970FE2CF14AF01E72E1AEA87519A91D00D1499189F94A6CDA9E29C05F11F17FE74A4919A710A2787E180744465DF81C62AA65662FDA46FA6175E8A31E5B29E66DED6701C8FC4217E91D733FE94380F046680967D4CEA7BAC8F3916CDF96AA2C474FAD9650F48403FD0B5B756D34667D36A07767FA33027AE55484D0F701C3CA16632F413A14E4B8645AFAF15B78978C19A7661EDC569BEC72394B1204B166A48FCD5F56BE29840C7794CA6D3440356F15858CDCA9B429C7EA92E17242893FDC8C9C63841A382C32F20CFAB121B4BCAFD7BF9EF07FBF7CDFFECA0CEF3A49C3E2B24FA836F3318435255655E1B281071F62D5E4CD63361299B7828F72936E3FEA9E8044562A6F6ADD5321187C3101E4669C6271598FE1A866C93FE2870A4CEB9254BA32A4719E439317EA42200A335B5CFFA7946A7D0F1BD1A69AA11288B73C71C80B77FE3707CB077DDDEA5CA36A449FAB230C9625A0B12F8275D3FF82F5DA380E7A3F11B6F155FE7E91AC960BD95D9B13F7423AB9B15CC3C4DC34EF296033F009468EA16A721AD659F56C18516025050749ABF05E6D3EBD9778142A530979291F46DAA399A86B7BCDF09CC3E6EEF101419762A306DB45AEFC96C64E83F28338D55905F6A387E0F515E580C3A9B35330E21C32198CDEE3AFB355967A098F635FCA7C49CB4E1E82464B2B390EF1F259E40B9A06235C0273F76284FE6BD534EF3AF7CB01A4A5252B8B94CADC2850B2E56D53F9A31D7C029DF967D0A30C05BC64E119BED6076818FABC8CDD93F3255693E14EFC1A740A5D63A5E847FFE87BAB1DDE0506E1762EA61EFA9F9756151ECCCADD91B98A961A901A2D8B01ABDDD29EC804E8C8D28214BBA26048F924CA66316696E51A49D02FF034D20E44914B1115339CAD3819E0CB1640F0084886FEDDE5E28C29DC48ED30A8C3D789734338F5A9DF42584326E536FD1CF30BC85B8DCBD6120D127C98FE4B3614074F13C2CA4854E6D794156C185C40EB3DA7619CE96ADAF0941BD5499848B034C2B11DFECC0BDFA81C594241F759EF53FC7CDE7F2DE4F23CF81A5A0B7D62E31DABB9198D40307F7824DD130B7D1B80E9B6D322FEEDB5ACE34944F0BFB7D016762A9B2E173BFDD69303766AFBAB45FAB75D05430B4A3515858C4B7F04E23414E4AD03842CB0A20D8FF4B59B7C852BA9A5BE982A8ADA5CB70C36CE2A4D2C31A7015C9F3275E43D192C1B2924424088907A057DA7F2D32A2149922AB2E33F2147D637A3508911CB3FEA5E1AAB4525BACF27B6DD7A3E0AFA978FC3A39DE8882FB22688C3CCC92B6E69ACB0BBF575AB3368E51A2F6A20C414C6F146727CC0045F29061E695D29F7C030CE6929EB3AD11A5CBD0CDEE37347869A3}]. diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/id_dsa b/lib/ssh/test/ssh_benchmark_SUITE_data/id_dsa new file mode 100644 index 0000000000..d306f8b26e --- /dev/null +++ b/lib/ssh/test/ssh_benchmark_SUITE_data/id_dsa @@ -0,0 +1,13 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBvAIBAAKBgQDfi2flSTZZofwT4yQT0NikX/LGNT7UPeB/XEWe/xovEYCElfaQ +APFixXvEgXwoojmZ5kiQRKzLM39wBP0jPERLbnZXfOOD0PDnw0haMh7dD7XKVMod +/EigVgHf/qBdM2M8yz1s/rRF7n1UpLSypziKjkzCm7JoSQ2zbWIPdmBIXwIVAMgP +kpr7Sq3O7sHdb8D601DRjoExAoGAMOQxDfB2Fd8ouz6G96f/UOzRMI/Kdv8kYYKW +JIGY+pRYrLPyYzUeJznwZreOJgrczAX+luHnKFWJ2Dnk5CyeXk67Wsr7pJ/4MBMD +OKeIS0S8qoSBN8+Krp79fgA+yS3IfqbkJLtLu4EBaCX4mKQIX4++k44d4U5lc8pt ++9hlEI8CgYEAznKxx9kyC6bVo7LUYKaGhofRFt0SYFc5PVmT2VUGRs1R6+6DPD+e +uEO6IhFct7JFSRbP9p0JD4Uk+3zlZF+XX6b2PsZkeV8f/02xlNGUSmEzCSiNg1AX +Cy/WusYhul0MncWCHMcOZB5rIvU/aP5EJJtn3xrRaz6u0SThF6AnT34CFQC63czE +ZU8w8Q+H7z0j+a+70x2iAw== +-----END DSA PRIVATE KEY----- + diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa256 b/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa256 new file mode 100644 index 0000000000..4b1eb12eaa --- /dev/null +++ b/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa256 @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIJfCaBKIIKhjbJl5F8BedqlXOQYDX5ba9Skypllmx/w+oAoGCCqGSM49 +AwEHoUQDQgAE49RbK2xQ/19ji3uDPM7uT4692LbwWF1TiaA9vUuebMGazoW/98br +N9xZu0L1AWwtEjs3kmJDTB7eJEGXnjUAcQ== +-----END EC PRIVATE KEY----- diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa256.pub b/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa256.pub new file mode 100644 index 0000000000..a0147e60fa --- /dev/null +++ b/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa256.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOPUWytsUP9fY4t7gzzO7k+Ovdi28FhdU4mgPb1LnmzBms6Fv/fG6zfcWbtC9QFsLRI7N5JiQ0we3iRBl541AHE= uabhnil@elxadlj3q32 diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa384 b/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa384 new file mode 100644 index 0000000000..4e8aa40959 --- /dev/null +++ b/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa384 @@ -0,0 +1,6 @@ +-----BEGIN EC PRIVATE KEY----- +MIGkAgEBBDCYXb6OSAZyXRfLXOtMo43za197Hdc/T0YKjgQQjwDt6rlRwqTh7v7S +PV2kXwNGdWigBwYFK4EEACKhZANiAARN2khlJUOOIiwsWHEALwDieeZR96qL4pUd +ci7aeGaczdUK5jOA9D9zmBZtSYTfO8Cr7ekVghDlcWAIJ/BXcswgQwSEQ6wyfaTF +8FYfyr4l3u9IirsnyaFzeIgeoNis8Gw= +-----END EC PRIVATE KEY----- diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa384.pub b/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa384.pub new file mode 100644 index 0000000000..41e722e545 --- /dev/null +++ b/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa384.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBE3aSGUlQ44iLCxYcQAvAOJ55lH3qovilR1yLtp4ZpzN1QrmM4D0P3OYFm1JhN87wKvt6RWCEOVxYAgn8FdyzCBDBIRDrDJ9pMXwVh/KviXe70iKuyfJoXN4iB6g2KzwbA== uabhnil@elxadlj3q32 diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa521 b/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa521 new file mode 100644 index 0000000000..7196f46e97 --- /dev/null +++ b/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa521 @@ -0,0 +1,7 @@ +-----BEGIN EC PRIVATE KEY----- +MIHbAgEBBEFMadoz4ckEcClfqXa2tiUuYkJdDfwq+/iFQcpt8ESuEd26IY/vm47Q +9UzbPkO4ou8xkNsQ3WvCRQBBWtn5O2kUU6AHBgUrgQQAI6GBiQOBhgAEAde5BRu5 +01/jS0jRk212xsb2DxPrxNpgp6IMCV8TA4Eps+8bSqHB091nLiBcP422HXYfuCd7 +XDjSs8ihcmhp0hCRASLqZR9EzW9W/SOt876May1Huj5X+WSO6RLe7vPn9vmf7kHf +pip6m7M7qp2qGgQ3q2vRwS2K/O6156ohiOlmuuFs +-----END EC PRIVATE KEY----- diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa521.pub b/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa521.pub new file mode 100644 index 0000000000..8f059120bc --- /dev/null +++ b/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa521.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAHXuQUbudNf40tI0ZNtdsbG9g8T68TaYKeiDAlfEwOBKbPvG0qhwdPdZy4gXD+Nth12H7gne1w40rPIoXJoadIQkQEi6mUfRM1vVv0jrfO+jGstR7o+V/lkjukS3u7z5/b5n+5B36YqepuzO6qdqhoEN6tr0cEtivzuteeqIYjpZrrhbA== uabhnil@elxadlj3q32 diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/id_rsa b/lib/ssh/test/ssh_benchmark_SUITE_data/id_rsa new file mode 100644 index 0000000000..9d7e0dd5fb --- /dev/null +++ b/lib/ssh/test/ssh_benchmark_SUITE_data/id_rsa @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQD1OET+3O/Bvj/dtjxDTXmj1oiJt4sIph5kGy0RfjoPrZfaS+CU +DhakCmS6t2ivxWFgtpKWaoGMZMJqWj6F6ZsumyFl3FPBtujwY/35cgifrI9Ns4Tl +zR1uuengNBmV+WRQ5cd9F2qS6Z8aDQihzt0r8JUqLcK+VQbrmNzboCCQQwIDAQAB +AoGAPQEyqPTt8JUT7mRXuaacjFXiweAXhp9NEDpyi9eLOjtFe9lElZCrsUOkq47V +TGUeRKEm9qSodfTbKPoqc8YaBJGJPhUaTAcha+7QcDdfHBvIsgxvU7ePVnlpXRp3 +CCUEMPhlnx6xBoTYP+fRU0e3+xJIPVyVCqX1jAdUMkzfRoECQQD6ux7B1QJAIWyK +SGkbDUbBilNmzCFNgIpOP6PA+bwfi5d16diTpra5AX09keQABAo/KaP1PdV8Vg0p +z4P3A7G3AkEA+l+AKG6m0kQTTBMJDqOdVPYwe+5GxunMaqmhokpEbuGsrZBl5Dvd +WpcBjR7jmenrhKZRIuA+Fz5HPo/UQJPl1QJBAKxstDkeED8j/S2XoFhPKAJ+6t39 +sUVICVTIZQeXdmzHJXCcUSkw8+WEhakqw/3SyW0oaK2FSWQJFWJUZ+8eJj8CQEh3 +xeduB5kKnS9CvzdeghZqX6QvVosSdtlUmfUYW/BgH5PpHKTP8wTaeld3XldZTpMJ +dKiMkUw2+XYROVUrubUCQD+Na1LhULlpn4ISEtIEfqpdlUhxDgO15Wg8USmsng+x +ICliVOSQtwaZjm8kwaFt0W7XnpnDxbRs37vIEbIMWak= +-----END RSA PRIVATE KEY----- diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_dsa_key new file mode 100644 index 0000000000..51ab6fbd88 --- /dev/null +++ b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_dsa_key @@ -0,0 +1,13 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBuwIBAAKBgQCClaHzE2ul0gKSUxah5W0W8UiJLy4hXngKEqpaUq9SSdVdY2LK +wVfKH1gt5iuaf1FfzOhsIC9G/GLnjYttXZc92cv/Gfe3gR+s0ni2++MX+T++mE/Q +diltXv/Hp27PybS67SmiFW7I+RWnT2OKlMPtw2oUuKeztCe5UWjaj/y5FQIVAPLA +l9RpiU30Z87NRAHY3NTRaqtrAoGANMRxw8UfdtNVR0CrQj3AgPaXOGE4d+G4Gp4X +skvnCHycSVAjtYxebUkzUzt5Q6f/IabuLUdge3gXrc8BetvrcKbp+XZgM0/Vj2CF +Ymmy3in6kzGZq7Fw1sZaku6AOU8vLa5woBT2vAcHLLT1bLAzj7viL048T6MfjrOP +ef8nHvACgYBhDWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah +/XcF3DeRF+eEoz48wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+U +ykSTXYUbtsfTNRFQGBW2/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0CgIVAN4wtL5W +Lv62jKcdskxNyz2NQoBx +-----END DSA PRIVATE KEY----- + diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_dsa_key.pub b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_dsa_key.pub new file mode 100644 index 0000000000..4dbb1305b0 --- /dev/null +++ b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_dsa_key.pub @@ -0,0 +1,11 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +AAAAB3NzaC1kc3MAAACBAIKVofMTa6XSApJTFqHlbRbxSIkvLiFeeAoSqlpSr1JJ1V1j +YsrBV8ofWC3mK5p/UV/M6GwgL0b8YueNi21dlz3Zy/8Z97eBH6zSeLb74xf5P76YT9B2 +KW1e/8enbs/JtLrtKaIVbsj5FadPY4qUw+3DahS4p7O0J7lRaNqP/LkVAAAAFQDywJfU +aYlN9GfOzUQB2NzU0WqrawAAAIA0xHHDxR9201VHQKtCPcCA9pc4YTh34bganheyS+cI +fJxJUCO1jF5tSTNTO3lDp/8hpu4tR2B7eBetzwF62+twpun5dmAzT9WPYIViabLeKfqT +MZmrsXDWxlqS7oA5Ty8trnCgFPa8BwcstPVssDOPu+IvTjxPox+Os495/yce8AAAAIBh +DWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah/XcF3DeRF+eEoz48 +wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+UykSTXYUbtsfTNRFQGBW2 +/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0Cg== +---- END SSH2 PUBLIC KEY ---- diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key256 b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key256 new file mode 100644 index 0000000000..2979ea88ed --- /dev/null +++ b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key256 @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIMe4MDoit0t8RzSVPwkCBemQ9fhXL+xnTSAWISw8HNCioAoGCCqGSM49 +AwEHoUQDQgAEo2q7U3P6r0W5WGOLtM78UQtofM9UalEhiZeDdiyylsR/RR17Op0s +VPGSADLmzzgcucLEKy17j2S+oz42VUJy5A== +-----END EC PRIVATE KEY----- diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key256.pub b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key256.pub new file mode 100644 index 0000000000..85dc419345 --- /dev/null +++ b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key256.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKNqu1Nz+q9FuVhji7TO/FELaHzPVGpRIYmXg3YsspbEf0UdezqdLFTxkgAy5s84HLnCxCste49kvqM+NlVCcuQ= uabhnil@elxadlj3q32 diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key384 b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key384 new file mode 100644 index 0000000000..fb1a862ded --- /dev/null +++ b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key384 @@ -0,0 +1,6 @@ +-----BEGIN EC PRIVATE KEY----- +MIGkAgEBBDArxbDfh3p1okrD9wQw6jJ4d4DdlBPD5GqXE8bIeRJiK41Sh40LgvPw +mkqEDSXK++CgBwYFK4EEACKhZANiAAScl43Ih2lWTDKrSox5ve5uiTXil4smsup3 +CfS1XPjKxgBAmlfBim8izbdrT0BFdQzz2joduNMtpt61wO4rGs6jm0UP7Kim9PC7 +Hneb/99fIYopdMH5NMnk60zGO1uZ2vc= +-----END EC PRIVATE KEY----- diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key384.pub b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key384.pub new file mode 100644 index 0000000000..428d5fb7d7 --- /dev/null +++ b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key384.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBJyXjciHaVZMMqtKjHm97m6JNeKXiyay6ncJ9LVc+MrGAECaV8GKbyLNt2tPQEV1DPPaOh240y2m3rXA7isazqObRQ/sqKb08Lsed5v/318hiil0wfk0yeTrTMY7W5na9w== uabhnil@elxadlj3q32 diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key521 b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key521 new file mode 100644 index 0000000000..3e51ec2ecd --- /dev/null +++ b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key521 @@ -0,0 +1,7 @@ +-----BEGIN EC PRIVATE KEY----- +MIHcAgEBBEIB8O1BFkl2HQjQLRLonEZ97da/h39DMa9/0/hvPZWAI8gUPEQcHxRx +U7b09p3Zh+EBbMFq8+1ae9ds+ZTxE4WFSvKgBwYFK4EEACOhgYkDgYYABAAlWVjq +Bzg7Wt4gE6UNb1lRE2cnlmH2L/A5uo6qZRx5lPnSKOxEhxSb/Oay1+9d6KRdrh6/ +vlhd9SHDBhLcAPDvWgBnJIEj92Q3pXX4JtoitL0yl+SvvU+vUh966mzHShHzj8p5 +ccOgPkPNoA70yrpGzkIhPezpZOQdCaOXj/jFqNCTDg== +-----END EC PRIVATE KEY----- diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key521.pub b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key521.pub new file mode 100644 index 0000000000..017a29f4da --- /dev/null +++ b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key521.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAAlWVjqBzg7Wt4gE6UNb1lRE2cnlmH2L/A5uo6qZRx5lPnSKOxEhxSb/Oay1+9d6KRdrh6/vlhd9SHDBhLcAPDvWgBnJIEj92Q3pXX4JtoitL0yl+SvvU+vUh966mzHShHzj8p5ccOgPkPNoA70yrpGzkIhPezpZOQdCaOXj/jFqNCTDg== uabhnil@elxadlj3q32 diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_rsa_key b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_rsa_key new file mode 100644 index 0000000000..79968bdd7d --- /dev/null +++ b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_rsa_key @@ -0,0 +1,16 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8semM4q843337 +zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RWRWzjaxSB +6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4QIDAQAB +AoGANmvJzJO5hkLuvyDZHKfAnGTtpifcR1wtSa9DjdKUyn8vhKF0mIimnbnYQEmW +NUUb3gXCZLi9PvkpRSVRrASDOZwcjoU/Kvww163vBUVb2cOZfFhyn6o2Sk88Tt++ +udH3hdjpf9i7jTtUkUe+QYPsia+wgvvrmn4QrahLAH86+kECQQDx5gFeXTME3cnW +WMpFz3PPumduzjqgqMMWEccX4FtQkMX/gyGa5UC7OHFyh0N/gSWvPbRHa8A6YgIt +n8DO+fh5AkEAzbqX4DOn8NY6xJIi42q7l/2jIA0RkB6P7YugW5NblhqBZ0XDnpA5 +sMt+rz+K07u9XZtxgh1xi7mNfwY6lEAMqQJBAJBEauCKmRj35Z6OyeQku59SPsnY ++SJEREVvSNw2lH9SOKQQ4wPsYlTGbvKtNVZgAcen91L5MmYfeckYE/fdIZECQQCt +64zxsTnM1I8iFxj/gP/OYlJBikrKt8udWmjaghzvLMEw+T2DExJyb9ZNeT53+UMB +m6O+B/4xzU/djvp+0hbhAkAemIt+rA5kTmYlFndhpvzkSSM8a2EXsO4XIPgGWCTT +tQKS/tTly0ADMjN/TVy11+9d6zcqadNVuHXHGtR4W0GR +-----END RSA PRIVATE KEY----- + diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_rsa_key.pub b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_rsa_key.pub new file mode 100644 index 0000000000..75d2025c71 --- /dev/null +++ b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_rsa_key.pub @@ -0,0 +1,5 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +AAAAB3NzaC1yc2EAAAADAQABAAAAgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8 +semM4q843337zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RW +RWzjaxSB6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4Q== +---- END SSH2 PUBLIC KEY ---- diff --git a/lib/ssh/test/ssh_connection_SUITE.erl b/lib/ssh/test/ssh_connection_SUITE.erl index eb7c641d8a..6e90faf0e8 100644 --- a/lib/ssh/test/ssh_connection_SUITE.erl +++ b/lib/ssh/test/ssh_connection_SUITE.erl @@ -36,6 +36,9 @@ %% suite() -> %% [{ct_hooks,[ts_install_cth]}]. +suite() -> + [{timetrap,{minutes,2}}]. + all() -> [ {group, openssh}, @@ -48,7 +51,8 @@ all() -> gracefull_invalid_long_start, gracefull_invalid_long_start_no_nl, stop_listener, - start_subsystem_on_closed_channel + start_subsystem_on_closed_channel, + max_channels_option ]. groups() -> [{openssh, [], payload() ++ ptty()}]. @@ -66,16 +70,10 @@ ptty() -> %%-------------------------------------------------------------------- init_per_suite(Config) -> - catch crypto:stop(), - case catch crypto:start() of - ok -> - Config; - _Else -> - {skip, "Crypto could not be started!"} - end. + Config. -end_per_suite(_Config) -> - crypto:stop(). +end_per_suite(Config) -> + Config. %%-------------------------------------------------------------------- init_per_group(openssh, Config) -> @@ -119,20 +117,28 @@ simple_exec(Config) when is_list(Config) -> receive {ssh_cm, ConnectionRef, {data, ChannelId0, 0, <<"testing\n">>}} -> ok + after + 10000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end, %% receive close messages receive {ssh_cm, ConnectionRef, {eof, ChannelId0}} -> ok + after + 10000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end, receive {ssh_cm, ConnectionRef, {exit_status, ChannelId0, 0}} -> ok + after + 10000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end, receive {ssh_cm, ConnectionRef,{closed, ChannelId0}} -> ok + after + 10000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end. %%-------------------------------------------------------------------- @@ -154,20 +160,28 @@ small_cat(Config) when is_list(Config) -> receive {ssh_cm, ConnectionRef, {data, ChannelId0, 0, Data}} -> ok + after + 10000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end, %% receive close messages receive {ssh_cm, ConnectionRef, {eof, ChannelId0}} -> ok + after + 10000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end, receive {ssh_cm, ConnectionRef, {exit_status, ChannelId0, 0}} -> ok + after + 10000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end, receive {ssh_cm, ConnectionRef,{closed, ChannelId0}} -> ok + after + 10000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end. %%-------------------------------------------------------------------- big_cat() -> @@ -186,7 +200,7 @@ big_cat(Config) when is_list(Config) -> %% pre-adjust receive window so the other end doesn't block ssh_connection:adjust_window(ConnectionRef, ChannelId0, size(Data)), - ct:pal("sending ~p byte binary~n",[size(Data)]), + ct:log("sending ~p byte binary~n",[size(Data)]), ok = ssh_connection:send(ConnectionRef, ChannelId0, Data, 10000), ok = ssh_connection:send_eof(ConnectionRef, ChannelId0), @@ -197,10 +211,10 @@ big_cat(Config) when is_list(Config) -> {ok, Other} -> case size(Data) =:= size(Other) of true -> - ct:pal("received and sent data are same" + ct:log("received and sent data are same" "size but do not match~n",[]); false -> - ct:pal("sent ~p but only received ~p~n", + ct:log("sent ~p but only received ~p~n", [size(Data), size(Other)]) end, ct:fail(receive_data_mismatch); @@ -211,11 +225,15 @@ big_cat(Config) when is_list(Config) -> %% receive close messages (eof already consumed) receive {ssh_cm, ConnectionRef, {exit_status, ChannelId0, 0}} -> - ok + ok + after + 10000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end, receive {ssh_cm, ConnectionRef,{closed, ChannelId0}} -> ok + after + 10000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end. %%-------------------------------------------------------------------- @@ -234,14 +252,20 @@ send_after_exit(Config) when is_list(Config) -> receive {ssh_cm, ConnectionRef, {eof, ChannelId0}} -> ok + after + 10000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end, receive {ssh_cm, ConnectionRef, {exit_status, ChannelId0, _ExitStatus}} -> ok + after + 10000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end, receive {ssh_cm, ConnectionRef,{closed, ChannelId0}} -> ok + after + 10000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end, case ssh_connection:send(ConnectionRef, ChannelId0, Data, 2000) of {error, closed} -> ok; @@ -450,11 +474,13 @@ gracefull_invalid_version(Config) when is_list(Config) -> ok = gen_tcp:send(S, ["SSH-8.-1","\r\n"]), receive Verstring -> - ct:pal("Server version: ~p~n", [Verstring]), + ct:log("Server version: ~p~n", [Verstring]), receive {tcp_closed, S} -> ok end + after + 10000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end. gracefull_invalid_start(Config) when is_list(Config) -> @@ -470,11 +496,13 @@ gracefull_invalid_start(Config) when is_list(Config) -> ok = gen_tcp:send(S, ["foobar","\r\n"]), receive Verstring -> - ct:pal("Server version: ~p~n", [Verstring]), + ct:log("Server version: ~p~n", [Verstring]), receive {tcp_closed, S} -> ok end + after + 10000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end. gracefull_invalid_long_start(Config) when is_list(Config) -> @@ -490,11 +518,13 @@ gracefull_invalid_long_start(Config) when is_list(Config) -> ok = gen_tcp:send(S, [lists:duplicate(257, $a), "\r\n"]), receive Verstring -> - ct:pal("Server version: ~p~n", [Verstring]), + ct:log("Server version: ~p~n", [Verstring]), receive {tcp_closed, S} -> ok end + after + 10000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end. @@ -511,11 +541,13 @@ gracefull_invalid_long_start_no_nl(Config) when is_list(Config) -> ok = gen_tcp:send(S, [lists:duplicate(257, $a), "\r\n"]), receive Verstring -> - ct:pal("Server version: ~p~n", [Verstring]), + ct:log("Server version: ~p~n", [Verstring]), receive {tcp_closed, S} -> ok end + after + 10000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end. stop_listener() -> @@ -606,6 +638,88 @@ start_subsystem_on_closed_channel(Config) -> ssh:stop_daemon(Pid). %%-------------------------------------------------------------------- +max_channels_option() -> + [{doc, "Test max_channels option"}]. + +max_channels_option(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), + SysDir = ?config(data_dir, Config), + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, + {user_dir, UserDir}, + {password, "morot"}, + {max_channels, 3}, + {subsystems, [{"echo_n", {ssh_echo_server, [4000000]}}]} + ]), + + ConnectionRef = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "foo"}, + {password, "morot"}, + {user_interaction, true}, + {user_dir, UserDir}]), + + {ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity), + {ok, ChannelId1} = ssh_connection:session_channel(ConnectionRef, infinity), + {ok, ChannelId2} = ssh_connection:session_channel(ConnectionRef, infinity), + {ok, ChannelId3} = ssh_connection:session_channel(ConnectionRef, infinity), + {ok, ChannelId4} = ssh_connection:session_channel(ConnectionRef, infinity), + {ok, ChannelId5} = ssh_connection:session_channel(ConnectionRef, infinity), + {ok, _ChannelId6} = ssh_connection:session_channel(ConnectionRef, infinity), + + %%%---- shell + ok = ssh_connection:shell(ConnectionRef,ChannelId0), + receive + {ssh_cm,ConnectionRef, {data, ChannelId0, 0, <<"Eshell",_/binary>>}} -> + ok + after 5000 -> + ct:fail("CLI Timeout") + end, + + %%%---- subsystem "echo_n" + success = ssh_connection:subsystem(ConnectionRef, ChannelId1, "echo_n", infinity), + + %%%---- exec #1 + success = ssh_connection:exec(ConnectionRef, ChannelId2, "testing1.\n", infinity), + receive + {ssh_cm, ConnectionRef, {data, ChannelId2, 0, <<"testing1",_/binary>>}} -> + ok + after 5000 -> + ct:fail("Exec #1 Timeout") + end, + + %%%---- ptty + success = ssh_connection:ptty_alloc(ConnectionRef, ChannelId3, []), + + %%%---- exec #2 + failure = ssh_connection:exec(ConnectionRef, ChannelId4, "testing2.\n", infinity), + + %%%---- close the shell + ok = ssh_connection:send(ConnectionRef, ChannelId0, "exit().\n", 5000), + + %%%---- wait for the subsystem to terminate + receive + {ssh_cm,ConnectionRef,{closed,ChannelId0}} -> ok + after 5000 -> + ct:log("Timeout waiting for '{ssh_cm,~p,{closed,~p}}'~n" + "Message queue:~n~p", + [ConnectionRef,ChannelId0,erlang:process_info(self(),messages)]), + ct:fail("exit Timeout",[]) + end, + + %%%---- exec #3 + success = ssh_connection:exec(ConnectionRef, ChannelId5, "testing3.\n", infinity), + receive + {ssh_cm, ConnectionRef, {data, ChannelId5, 0, <<"testing3",_/binary>>}} -> + ok + after 5000 -> + ct:fail("Exec #3 Timeout") + end, + + ssh:close(ConnectionRef), + ssh:stop_daemon(Pid). + +%%-------------------------------------------------------------------- %% Internal functions ------------------------------------------------ %%-------------------------------------------------------------------- big_cat_rx(ConnectionRef, ChannelId) -> diff --git a/lib/ssh/test/ssh_key_cb.erl b/lib/ssh/test/ssh_key_cb.erl new file mode 100644 index 0000000000..388ec2ecc1 --- /dev/null +++ b/lib/ssh/test/ssh_key_cb.erl @@ -0,0 +1,45 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2015. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- + +%% Note: This module is used by ssh_basic_SUITE + +-module(ssh_key_cb). +-behaviour(ssh_client_key_api). +-compile(export_all). + +add_host_key(_, _, _) -> + ok. + +is_host_key(_, _, _, _) -> + true. + +user_key('ssh-dss', Opts) -> + UserDir = proplists:get_value(user_dir, Opts), + KeyFile = filename:join(filename:dirname(UserDir), "id_dsa"), + {ok, KeyBin} = file:read_file(KeyFile), + [Entry] = public_key:pem_decode(KeyBin), + Key = public_key:pem_entry_decode(Entry), + {ok, Key}; + +user_key(_Alg, _Opt) -> + {error, "Not Supported"}. diff --git a/lib/ssh/test/ssh_key_cb_options.erl b/lib/ssh/test/ssh_key_cb_options.erl new file mode 100644 index 0000000000..afccb34f0f --- /dev/null +++ b/lib/ssh/test/ssh_key_cb_options.erl @@ -0,0 +1,44 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2015. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- + +%% Note: This module is used by ssh_basic_SUITE + +-module(ssh_key_cb_options). +-behaviour(ssh_client_key_api). +-compile(export_all). + +add_host_key(_, _, _) -> + ok. + +is_host_key(_, _, _, _) -> + true. + +user_key('ssh-dss', Opts) -> + KeyCbOpts = proplists:get_value(key_cb_private, Opts), + KeyBin = proplists:get_value(priv_key, KeyCbOpts), + [Entry] = public_key:pem_decode(KeyBin), + Key = public_key:pem_entry_decode(Entry), + {ok, Key}; + +user_key(_Alg, _Opt) -> + {error, "Not Supported"}. diff --git a/lib/ssh/test/ssh_options_SUITE.erl b/lib/ssh/test/ssh_options_SUITE.erl new file mode 100644 index 0000000000..ba0107efd6 --- /dev/null +++ b/lib/ssh/test/ssh_options_SUITE.erl @@ -0,0 +1,1187 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2015. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +%% + +-module(ssh_options_SUITE). + +%%% This test suite tests different options for the ssh functions + + +-include_lib("common_test/include/ct.hrl"). +-include_lib("kernel/include/file.hrl"). + + +%%% Test cases +-export([connectfun_disconnectfun_client/1, + disconnectfun_option_client/1, + disconnectfun_option_server/1, + id_string_no_opt_client/1, + id_string_no_opt_server/1, + id_string_own_string_client/1, + id_string_own_string_server/1, + id_string_random_client/1, + id_string_random_server/1, + max_sessions_sftp_start_channel_parallel/1, + max_sessions_sftp_start_channel_sequential/1, + max_sessions_ssh_connect_parallel/1, + max_sessions_ssh_connect_sequential/1, + server_password_option/1, + server_userpassword_option/1, + server_pwdfun_option/1, + server_pwdfun_4_option/1, + server_pwdfun_4_option_repeat/1, + ssh_connect_arg4_timeout/1, + ssh_connect_negtimeout_parallel/1, + ssh_connect_negtimeout_sequential/1, + ssh_connect_nonegtimeout_connected_parallel/1, + ssh_connect_nonegtimeout_connected_sequential/1, + ssh_connect_timeout/1, connect/4, + ssh_daemon_minimal_remote_max_packet_size_option/1, + ssh_msg_debug_fun_option_client/1, + ssh_msg_debug_fun_option_server/1, + system_dir_option/1, + unexpectedfun_option_client/1, + unexpectedfun_option_server/1, + user_dir_option/1, + connectfun_disconnectfun_server/1 + ]). + +%%% Common test callbacks +-export([suite/0, all/0, groups/0, + init_per_suite/1, end_per_suite/1, + init_per_group/2, end_per_group/2, + init_per_testcase/2, end_per_testcase/2 + ]). + + +-define(NEWLINE, <<"\r\n">>). + +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- + +suite() -> + [{ct_hooks,[ts_install_cth]}, + {timetrap,{minutes,6}}]. + +all() -> + [connectfun_disconnectfun_server, + connectfun_disconnectfun_client, + server_password_option, + server_userpassword_option, + server_pwdfun_option, + server_pwdfun_4_option, + server_pwdfun_4_option_repeat, + {group, dir_options}, + ssh_connect_timeout, + ssh_connect_arg4_timeout, + ssh_daemon_minimal_remote_max_packet_size_option, + ssh_msg_debug_fun_option_client, + ssh_msg_debug_fun_option_server, + disconnectfun_option_server, + disconnectfun_option_client, + unexpectedfun_option_server, + unexpectedfun_option_client, + id_string_no_opt_client, + id_string_own_string_client, + id_string_random_client, + id_string_no_opt_server, + id_string_own_string_server, + id_string_random_server, + {group, hardening_tests} + ]. + +groups() -> + [{hardening_tests, [], [ssh_connect_nonegtimeout_connected_parallel, + ssh_connect_nonegtimeout_connected_sequential, + ssh_connect_negtimeout_parallel, + ssh_connect_negtimeout_sequential, + max_sessions_ssh_connect_parallel, + max_sessions_ssh_connect_sequential, + max_sessions_sftp_start_channel_parallel, + max_sessions_sftp_start_channel_sequential + ]}, + {dir_options, [], [user_dir_option, + system_dir_option]} + ]. + + +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + Config. + +end_per_suite(_Config) -> + ssh:stop(). + +%%-------------------------------------------------------------------- +init_per_group(hardening_tests, Config) -> + DataDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + ssh_test_lib:setup_dsa(DataDir, PrivDir), + Config; +init_per_group(dir_options, Config) -> + PrivDir = ?config(priv_dir, Config), + %% Make unreadable dir: + Dir_unreadable = filename:join(PrivDir, "unread"), + ok = file:make_dir(Dir_unreadable), + {ok,F1} = file:read_file_info(Dir_unreadable), + ok = file:write_file_info(Dir_unreadable, + F1#file_info{mode = F1#file_info.mode band (bnot 8#00444)}), + %% Make readable file: + File_readable = filename:join(PrivDir, "file"), + ok = file:write_file(File_readable, <<>>), + + %% Check: + case {file:read_file_info(Dir_unreadable), + file:read_file_info(File_readable)} of + {{ok, Id=#file_info{type=directory, access=Md}}, + {ok, If=#file_info{type=regular, access=Mf}}} -> + AccessOK = + case {Md, Mf} of + {read, _} -> false; + {read_write, _} -> false; + {_, read} -> true; + {_, read_write} -> true; + _ -> false + end, + + case AccessOK of + true -> + %% Save: + [{unreadable_dir, Dir_unreadable}, + {readable_file, File_readable} + | Config]; + false -> + ct:log("File#file_info : ~p~n" + "Dir#file_info : ~p",[If,Id]), + {skip, "File or dir mode settings failed"} + end; + + NotDirFile -> + ct:log("{Dir,File} -> ~p",[NotDirFile]), + {skip, "File/Dir creation failed"} + end; +init_per_group(_, Config) -> + Config. + +end_per_group(_, Config) -> + Config. +%%-------------------------------------------------------------------- +init_per_testcase(_TestCase, Config) -> + ssh:start(), + Config. + +end_per_testcase(TestCase, Config) when TestCase == server_password_option; + TestCase == server_userpassword_option; + TestCase == server_pwdfun_option; + TestCase == server_pwdfun_4_option -> + UserDir = filename:join(?config(priv_dir, Config), nopubkey), + ssh_test_lib:del_dirs(UserDir), + end_per_testcase(Config); +end_per_testcase(_TestCase, Config) -> + end_per_testcase(Config). + +end_per_testcase(_Config) -> + ssh:stop(), + ok. + +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- +%%-------------------------------------------------------------------- + +%%% validate to server that uses the 'password' option +server_password_option(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), + SysDir = ?config(data_dir, Config), + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, + {user_dir, UserDir}, + {password, "morot"}]), + + ConnectionRef = + ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "foo"}, + {password, "morot"}, + {user_interaction, false}, + {user_dir, UserDir}]), + + Reason = "Unable to connect using the available authentication methods", + + {error, Reason} = + ssh:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "vego"}, + {password, "foo"}, + {user_interaction, false}, + {user_dir, UserDir}]), + + ct:log("Test of wrong password: Error msg: ~p ~n", [Reason]), + + ssh:close(ConnectionRef), + ssh:stop_daemon(Pid). + +%%-------------------------------------------------------------------- + +%%% validate to server that uses the 'password' option +server_userpassword_option(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), + SysDir = ?config(data_dir, Config), + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, + {user_dir, PrivDir}, + {user_passwords, [{"vego", "morot"}]}]), + + ConnectionRef = + ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "vego"}, + {password, "morot"}, + {user_interaction, false}, + {user_dir, UserDir}]), + ssh:close(ConnectionRef), + + Reason = "Unable to connect using the available authentication methods", + + {error, Reason} = + ssh:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "foo"}, + {password, "morot"}, + {user_interaction, false}, + {user_dir, UserDir}]), + {error, Reason} = + ssh:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "vego"}, + {password, "foo"}, + {user_interaction, false}, + {user_dir, UserDir}]), + ssh:stop_daemon(Pid). + +%%-------------------------------------------------------------------- +%%% validate to server that uses the 'pwdfun' option +server_pwdfun_option(Config) -> + PrivDir = ?config(priv_dir, Config), + UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), + SysDir = ?config(data_dir, Config), + CHKPWD = fun("foo",Pwd) -> Pwd=="bar"; + (_,_) -> false + end, + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, + {user_dir, PrivDir}, + {pwdfun,CHKPWD}]), + ConnectionRef = + ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "foo"}, + {password, "bar"}, + {user_interaction, false}, + {user_dir, UserDir}]), + ssh:close(ConnectionRef), + + Reason = "Unable to connect using the available authentication methods", + + {error, Reason} = + ssh:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "foo"}, + {password, "morot"}, + {user_interaction, false}, + {user_dir, UserDir}]), + {error, Reason} = + ssh:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "vego"}, + {password, "foo"}, + {user_interaction, false}, + {user_dir, UserDir}]), + ssh:stop_daemon(Pid). + + +%%-------------------------------------------------------------------- +%%% validate to server that uses the 'pwdfun/4' option +server_pwdfun_4_option(Config) -> + PrivDir = ?config(priv_dir, Config), + UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), + SysDir = ?config(data_dir, Config), + PWDFUN = fun("foo",Pwd,{_,_},undefined) -> Pwd=="bar"; + ("fie",Pwd,{_,_},undefined) -> {Pwd=="bar",new_state}; + ("bandit",_,_,_) -> disconnect; + (_,_,_,_) -> false + end, + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, + {user_dir, PrivDir}, + {pwdfun,PWDFUN}]), + ConnectionRef1 = + ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "foo"}, + {password, "bar"}, + {user_interaction, false}, + {user_dir, UserDir}]), + ssh:close(ConnectionRef1), + + ConnectionRef2 = + ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "fie"}, + {password, "bar"}, + {user_interaction, false}, + {user_dir, UserDir}]), + ssh:close(ConnectionRef2), + + Reason = "Unable to connect using the available authentication methods", + + {error, Reason} = + ssh:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "foo"}, + {password, "morot"}, + {user_interaction, false}, + {user_dir, UserDir}]), + {error, Reason} = + ssh:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "fie"}, + {password, "morot"}, + {user_interaction, false}, + {user_dir, UserDir}]), + {error, Reason} = + ssh:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "vego"}, + {password, "foo"}, + {user_interaction, false}, + {user_dir, UserDir}]), + + {error, Reason} = + ssh:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "bandit"}, + {password, "pwd breaking"}, + {user_interaction, false}, + {user_dir, UserDir}]), + ssh:stop_daemon(Pid). + + +%%-------------------------------------------------------------------- +server_pwdfun_4_option_repeat(Config) -> + PrivDir = ?config(priv_dir, Config), + UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), + SysDir = ?config(data_dir, Config), + %% Test that the state works + Parent = self(), + PWDFUN = fun("foo",P="bar",_,S) -> Parent!{P,S},true; + (_,P,_,S=undefined) -> Parent!{P,S},{false,1}; + (_,P,_,S) -> Parent!{P,S}, {false,S+1} + end, + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, + {user_dir, PrivDir}, + {auth_methods,"keyboard-interactive"}, + {pwdfun,PWDFUN}]), + + %% Try with passwords "incorrect", "Bad again" and finally "bar" + KIFFUN = fun(_,_,_) -> + K={k,self()}, + case get(K) of + undefined -> + put(K,1), + ["incorrect"]; + 2 -> + put(K,3), + ["bar"]; + S-> + put(K,S+1), + ["Bad again"] + end + end, + + ConnectionRef2 = + ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "foo"}, + {keyboard_interact_fun, KIFFUN}, + {user_dir, UserDir}]), + ssh:close(ConnectionRef2), + ssh:stop_daemon(Pid), + + lists:foreach(fun(Expect) -> + receive + Expect -> ok; + Other -> ct:fail("Expect: ~p~nReceived ~p",[Expect,Other]) + after + 2000 -> ct:fail("Timeout expecting ~p",[Expect]) + end + end, [{"incorrect",undefined}, + {"Bad again",1}, + {"bar",2}]). + +%%-------------------------------------------------------------------- +system_dir_option(Config) -> + DirUnread = proplists:get_value(unreadable_dir,Config), + FileRead = proplists:get_value(readable_file,Config), + + case ssh_test_lib:daemon([{system_dir, DirUnread}]) of + {error,{eoptions,{{system_dir,DirUnread},eacces}}} -> + ok; + {Pid1,_Host1,Port1} when is_pid(Pid1),is_integer(Port1) -> + ssh:stop_daemon(Pid1), + ct:fail("Didn't detect that dir is unreadable", []) + end, + + case ssh_test_lib:daemon([{system_dir, FileRead}]) of + {error,{eoptions,{{system_dir,FileRead},enotdir}}} -> + ok; + {Pid2,_Host2,Port2} when is_pid(Pid2),is_integer(Port2) -> + ssh:stop_daemon(Pid2), + ct:fail("Didn't detect that option is a plain file", []) + end. + + +user_dir_option(Config) -> + DirUnread = proplists:get_value(unreadable_dir,Config), + FileRead = proplists:get_value(readable_file,Config), + %% Any port will do (beware, implementation knowledge!): + Port = 65535, + + case ssh:connect("localhost", Port, [{user_dir, DirUnread}]) of + {error,{eoptions,{{user_dir,DirUnread},eacces}}} -> + ok; + {error,econnrefused} -> + ct:fail("Didn't detect that dir is unreadable", []) + end, + + case ssh:connect("localhost", Port, [{user_dir, FileRead}]) of + {error,{eoptions,{{user_dir,FileRead},enotdir}}} -> + ok; + {error,econnrefused} -> + ct:fail("Didn't detect that option is a plain file", []) + end. + +%%-------------------------------------------------------------------- +%%% validate client that uses the 'ssh_msg_debug_fun' option +ssh_msg_debug_fun_option_client(Config) -> + PrivDir = ?config(priv_dir, Config), + UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), + SysDir = ?config(data_dir, Config), + + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, + {user_dir, UserDir}, + {password, "morot"}, + {failfun, fun ssh_test_lib:failfun/2}]), + Parent = self(), + DbgFun = fun(ConnRef,Displ,Msg,Lang) -> Parent ! {msg_dbg,{ConnRef,Displ,Msg,Lang}} end, + + ConnectionRef = + ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "foo"}, + {password, "morot"}, + {user_dir, UserDir}, + {user_interaction, false}, + {ssh_msg_debug_fun,DbgFun}]), + %% Beware, implementation knowledge: + gen_fsm:send_all_state_event(ConnectionRef,{ssh_msg_debug,false,<<"Hello">>,<<>>}), + receive + {msg_dbg,X={ConnectionRef,false,<<"Hello">>,<<>>}} -> + ct:log("Got expected dbg msg ~p",[X]), + ssh:stop_daemon(Pid); + {msg_dbg,X={_,false,<<"Hello">>,<<>>}} -> + ct:log("Got dbg msg but bad ConnectionRef (~p expected) ~p",[ConnectionRef,X]), + ssh:stop_daemon(Pid), + {fail, "Bad ConnectionRef received"}; + {msg_dbg,X} -> + ct:log("Got bad dbg msg ~p",[X]), + ssh:stop_daemon(Pid), + {fail,"Bad msg received"} + after 1000 -> + ssh:stop_daemon(Pid), + {fail,timeout} + end. + +%%-------------------------------------------------------------------- +connectfun_disconnectfun_server(Config) -> + PrivDir = ?config(priv_dir, Config), + UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), + SysDir = ?config(data_dir, Config), + + Parent = self(), + Ref = make_ref(), + ConnFun = fun(_,_,_) -> Parent ! {connect,Ref} end, + DiscFun = fun(R) -> Parent ! {disconnect,Ref,R} end, + + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, + {user_dir, UserDir}, + {password, "morot"}, + {failfun, fun ssh_test_lib:failfun/2}, + {disconnectfun, DiscFun}, + {connectfun, ConnFun}]), + ConnectionRef = + ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "foo"}, + {password, "morot"}, + {user_dir, UserDir}, + {user_interaction, false}]), + receive + {connect,Ref} -> + ssh:close(ConnectionRef), + receive + {disconnect,Ref,R} -> + ct:log("Disconnect result: ~p",[R]), + ssh:stop_daemon(Pid) + after 2000 -> + {fail, "No disconnectfun action"} + end + after 2000 -> + {fail, "No connectfun action"} + end. + +%%-------------------------------------------------------------------- +connectfun_disconnectfun_client(Config) -> + PrivDir = ?config(priv_dir, Config), + UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), + SysDir = ?config(data_dir, Config), + + Parent = self(), + Ref = make_ref(), + DiscFun = fun(R) -> Parent ! {disconnect,Ref,R} end, + + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, + {user_dir, UserDir}, + {password, "morot"}, + {failfun, fun ssh_test_lib:failfun/2}]), + _ConnectionRef = + ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "foo"}, + {password, "morot"}, + {user_dir, UserDir}, + {disconnectfun, DiscFun}, + {user_interaction, false}]), + ssh:stop_daemon(Pid), + receive + {disconnect,Ref,R} -> + ct:log("Disconnect result: ~p",[R]) + after 2000 -> + {fail, "No disconnectfun action"} + end. + +%%-------------------------------------------------------------------- +%%% validate client that uses the 'ssh_msg_debug_fun' option +ssh_msg_debug_fun_option_server(Config) -> + PrivDir = ?config(priv_dir, Config), + UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), + SysDir = ?config(data_dir, Config), + + Parent = self(), + DbgFun = fun(ConnRef,Displ,Msg,Lang) -> Parent ! {msg_dbg,{ConnRef,Displ,Msg,Lang}} end, + ConnFun = fun(_,_,_) -> Parent ! {connection_pid,self()} end, + + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, + {user_dir, UserDir}, + {password, "morot"}, + {failfun, fun ssh_test_lib:failfun/2}, + {connectfun, ConnFun}, + {ssh_msg_debug_fun, DbgFun}]), + _ConnectionRef = + ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "foo"}, + {password, "morot"}, + {user_dir, UserDir}, + {user_interaction, false}]), + receive + {connection_pid,Server} -> + %% Beware, implementation knowledge: + gen_fsm:send_all_state_event(Server,{ssh_msg_debug,false,<<"Hello">>,<<>>}), + receive + {msg_dbg,X={_,false,<<"Hello">>,<<>>}} -> + ct:log("Got expected dbg msg ~p",[X]), + ssh:stop_daemon(Pid); + {msg_dbg,X} -> + ct:log("Got bad dbg msg ~p",[X]), + ssh:stop_daemon(Pid), + {fail,"Bad msg received"} + after 3000 -> + ssh:stop_daemon(Pid), + {fail,timeout2} + end + after 3000 -> + ssh:stop_daemon(Pid), + {fail,timeout1} + end. + +%%-------------------------------------------------------------------- +disconnectfun_option_server(Config) -> + PrivDir = ?config(priv_dir, Config), + UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), + SysDir = ?config(data_dir, Config), + + Parent = self(), + DisConnFun = fun(Reason) -> Parent ! {disconnect,Reason} end, + + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, + {user_dir, UserDir}, + {password, "morot"}, + {failfun, fun ssh_test_lib:failfun/2}, + {disconnectfun, DisConnFun}]), + ConnectionRef = + ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "foo"}, + {password, "morot"}, + {user_dir, UserDir}, + {user_interaction, false}]), + ssh:close(ConnectionRef), + receive + {disconnect,Reason} -> + ct:log("Server detected disconnect: ~p",[Reason]), + ssh:stop_daemon(Pid), + ok + after 3000 -> + receive + X -> ct:log("received ~p",[X]) + after 0 -> ok + end, + {fail,"Timeout waiting for disconnect"} + end. + +%%-------------------------------------------------------------------- +disconnectfun_option_client(Config) -> + PrivDir = ?config(priv_dir, Config), + UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), + SysDir = ?config(data_dir, Config), + + Parent = self(), + DisConnFun = fun(Reason) -> Parent ! {disconnect,Reason} end, + + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, + {user_dir, UserDir}, + {password, "morot"}, + {failfun, fun ssh_test_lib:failfun/2}]), + _ConnectionRef = + ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "foo"}, + {password, "morot"}, + {user_dir, UserDir}, + {user_interaction, false}, + {disconnectfun, DisConnFun}]), + ssh:stop_daemon(Pid), + receive + {disconnect,Reason} -> + ct:log("Client detected disconnect: ~p",[Reason]), + ok + after 3000 -> + receive + X -> ct:log("received ~p",[X]) + after 0 -> ok + end, + {fail,"Timeout waiting for disconnect"} + end. + +%%-------------------------------------------------------------------- +unexpectedfun_option_server(Config) -> + PrivDir = ?config(priv_dir, Config), + UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), + SysDir = ?config(data_dir, Config), + + Parent = self(), + ConnFun = fun(_,_,_) -> Parent ! {connection_pid,self()} end, + UnexpFun = fun(Msg,Peer) -> + Parent ! {unexpected,Msg,Peer,self()}, + skip + end, + + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, + {user_dir, UserDir}, + {password, "morot"}, + {failfun, fun ssh_test_lib:failfun/2}, + {connectfun, ConnFun}, + {unexpectedfun, UnexpFun}]), + _ConnectionRef = + ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "foo"}, + {password, "morot"}, + {user_dir, UserDir}, + {user_interaction, false}]), + receive + {connection_pid,Server} -> + %% Beware, implementation knowledge: + Server ! unexpected_message, + receive + {unexpected, unexpected_message, {{_,_,_,_},_}, _} -> ok; + {unexpected, unexpected_message, Peer, _} -> ct:fail("Bad peer ~p",[Peer]); + M = {unexpected, _, _, _} -> ct:fail("Bad msg ~p",[M]) + after 3000 -> + ssh:stop_daemon(Pid), + {fail,timeout2} + end + after 3000 -> + ssh:stop_daemon(Pid), + {fail,timeout1} + end. + +%%-------------------------------------------------------------------- +unexpectedfun_option_client(Config) -> + PrivDir = ?config(priv_dir, Config), + UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), + SysDir = ?config(data_dir, Config), + + Parent = self(), + UnexpFun = fun(Msg,Peer) -> + Parent ! {unexpected,Msg,Peer,self()}, + skip + end, + + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, + {user_dir, UserDir}, + {password, "morot"}, + {failfun, fun ssh_test_lib:failfun/2}]), + ConnectionRef = + ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "foo"}, + {password, "morot"}, + {user_dir, UserDir}, + {user_interaction, false}, + {unexpectedfun, UnexpFun}]), + %% Beware, implementation knowledge: + ConnectionRef ! unexpected_message, + + receive + {unexpected, unexpected_message, {{_,_,_,_},_}, ConnectionRef} -> + ok; + {unexpected, unexpected_message, Peer, ConnectionRef} -> + ct:fail("Bad peer ~p",[Peer]); + M = {unexpected, _, _, _} -> + ct:fail("Bad msg ~p",[M]) + after 3000 -> + ssh:stop_daemon(Pid), + {fail,timeout} + end. + +%%-------------------------------------------------------------------- +%%% Test connect_timeout option in ssh:connect/4 +ssh_connect_timeout(_Config) -> + ConnTimeout = 2000, + {error,{faked_transport,connect,TimeoutToTransport}} = + ssh:connect("localhost", 12345, + [{transport,{tcp,?MODULE,tcp_closed}}, + {connect_timeout,ConnTimeout}], + 1000), + case TimeoutToTransport of + ConnTimeout -> ok; + Other -> + ct:log("connect_timeout is ~p but transport received ~p",[ConnTimeout,Other]), + {fail,"ssh:connect/4 wrong connect_timeout received in transport"} + end. + +%% Plugin function for the test above +connect(_Host, _Port, _Opts, Timeout) -> + {error, {faked_transport,connect,Timeout}}. + +%%-------------------------------------------------------------------- +%%% Test fourth argument in ssh:connect/4 +ssh_connect_arg4_timeout(_Config) -> + Timeout = 1000, + Parent = self(), + %% start the server + Server = spawn(fun() -> + {ok,Sl} = gen_tcp:listen(0,[]), + {ok,{_,Port}} = inet:sockname(Sl), + Parent ! {port,self(),Port}, + Rsa = gen_tcp:accept(Sl), + ct:log("Server gen_tcp:accept got ~p",[Rsa]), + receive after 2*Timeout -> ok end %% let client timeout first + end), + + %% Get listening port + Port = receive + {port,Server,ServerPort} -> ServerPort + after + 10000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) + end, + + %% try to connect with a timeout, but "supervise" it + Client = spawn(fun() -> + T0 = erlang:monotonic_time(), + Rc = ssh:connect("localhost",Port,[],Timeout), + ct:log("Client ssh:connect got ~p",[Rc]), + Parent ! {done,self(),Rc,T0} + end), + + %% Wait for client reaction on the connection try: + receive + {done, Client, {error,timeout}, T0} -> + Msp = ms_passed(T0), + exit(Server,hasta_la_vista___baby), + Low = 0.9*Timeout, + High = 2.5*Timeout, + ct:log("Timeout limits: ~.4f - ~.4f ms, timeout " + "was ~.4f ms, expected ~p ms",[Low,High,Msp,Timeout]), + if + Low<Msp, Msp<High -> ok; + true -> {fail, "timeout not within limits"} + end; + + {done, Client, {error,Other}, _T0} -> + ct:log("Error message \"~p\" from the client is unexpected.",[{error,Other}]), + {fail, "Unexpected error message"}; + + {done, Client, {ok,_Ref}, _T0} -> + {fail,"ssh-connected ???"} + after + 5000 -> + exit(Server,hasta_la_vista___baby), + exit(Client,hasta_la_vista___baby), + {fail, "Didn't timeout"} + end. + +%% Help function, elapsed milliseconds since T0 +ms_passed(T0) -> + %% OTP 18 + erlang:convert_time_unit(erlang:monotonic_time() - T0, + native, + micro_seconds) / 1000. + +%%-------------------------------------------------------------------- +ssh_daemon_minimal_remote_max_packet_size_option(Config) -> + SystemDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), + + {Server, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + {user_dir, UserDir}, + {user_passwords, [{"vego", "morot"}]}, + {failfun, fun ssh_test_lib:failfun/2}, + {minimal_remote_max_packet_size, 14}]), + Conn = + ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user_dir, UserDir}, + {user_interaction, false}, + {user, "vego"}, + {password, "morot"}]), + + %% Try the limits of the minimal_remote_max_packet_size: + {ok, _ChannelId} = ssh_connection:session_channel(Conn, 100, 14, infinity), + {open_error,_,"Maximum packet size below 14 not supported",_} = + ssh_connection:session_channel(Conn, 100, 13, infinity), + + ssh:close(Conn), + ssh:stop_daemon(Server). + +%%-------------------------------------------------------------------- +%% This test try every algorithm by connecting to an Erlang server +id_string_no_opt_client(Config) -> + {Server, _Host, Port} = fake_daemon(Config), + {error,_} = ssh:connect("localhost", Port, [], 1000), + receive + {id,Server,"SSH-2.0-Erlang/"++Vsn} -> + true = expected_ssh_vsn(Vsn); + {id,Server,Other} -> + ct:fail("Unexpected id: ~s.",[Other]) + after 5000 -> + {fail,timeout} + end. + +%%-------------------------------------------------------------------- +id_string_own_string_client(Config) -> + {Server, _Host, Port} = fake_daemon(Config), + {error,_} = ssh:connect("localhost", Port, [{id_string,"Pelle"}], 1000), + receive + {id,Server,"SSH-2.0-Pelle\r\n"} -> + ok; + {id,Server,Other} -> + ct:fail("Unexpected id: ~s.",[Other]) + after 5000 -> + {fail,timeout} + end. + +%%-------------------------------------------------------------------- +id_string_random_client(Config) -> + {Server, _Host, Port} = fake_daemon(Config), + {error,_} = ssh:connect("localhost", Port, [{id_string,random}], 1000), + receive + {id,Server,Id="SSH-2.0-Erlang"++_} -> + ct:fail("Unexpected id: ~s.",[Id]); + {id,Server,Rnd="SSH-2.0-"++_} -> + ct:log("Got correct ~s",[Rnd]); + {id,Server,Id} -> + ct:fail("Unexpected id: ~s.",[Id]) + after 5000 -> + {fail,timeout} + end. + +%%-------------------------------------------------------------------- +id_string_no_opt_server(Config) -> + {_Server, Host, Port} = ssh_test_lib:std_daemon(Config, []), + {ok,S1}=gen_tcp:connect(Host,Port,[{active,false},{packet,line}]), + {ok,"SSH-2.0-Erlang/"++Vsn} = gen_tcp:recv(S1, 0, 2000), + true = expected_ssh_vsn(Vsn). + +%%-------------------------------------------------------------------- +id_string_own_string_server(Config) -> + {_Server, Host, Port} = ssh_test_lib:std_daemon(Config, [{id_string,"Olle"}]), + {ok,S1}=gen_tcp:connect(Host,Port,[{active,false},{packet,line}]), + {ok,"SSH-2.0-Olle\r\n"} = gen_tcp:recv(S1, 0, 2000). + +%%-------------------------------------------------------------------- +id_string_random_server(Config) -> + {_Server, Host, Port} = ssh_test_lib:std_daemon(Config, [{id_string,random}]), + {ok,S1}=gen_tcp:connect(Host,Port,[{active,false},{packet,line}]), + {ok,"SSH-2.0-"++Rnd} = gen_tcp:recv(S1, 0, 2000), + case Rnd of + "Erlang"++_ -> ct:log("Id=~p",[Rnd]), + {fail,got_default_id}; + "Olle\r\n" -> {fail,got_previous_tests_value}; + _ -> ct:log("Got ~s.",[Rnd]) + end. + +%%-------------------------------------------------------------------- +ssh_connect_negtimeout_parallel(Config) -> ssh_connect_negtimeout(Config,true). +ssh_connect_negtimeout_sequential(Config) -> ssh_connect_negtimeout(Config,false). + +ssh_connect_negtimeout(Config, Parallel) -> + process_flag(trap_exit, true), + SystemDir = filename:join(?config(priv_dir, Config), system), + UserDir = ?config(priv_dir, Config), + NegTimeOut = 2000, % ms + ct:log("Parallel: ~p",[Parallel]), + + {_Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},{user_dir, UserDir}, + {parallel_login, Parallel}, + {negotiation_timeout, NegTimeOut}, + {failfun, fun ssh_test_lib:failfun/2}]), + + {ok,Socket} = gen_tcp:connect(Host, Port, []), + + Factor = 2, + ct:log("And now sleeping ~p*NegTimeOut (~p ms)...", [Factor, round(Factor * NegTimeOut)]), + ct:sleep(round(Factor * NegTimeOut)), + + case inet:sockname(Socket) of + {ok,_} -> ct:fail("Socket not closed"); + {error,_} -> ok + end. + +%%-------------------------------------------------------------------- +%%% Test that ssh connection does not timeout if the connection is established (parallel) +ssh_connect_nonegtimeout_connected_parallel(Config) -> + ssh_connect_nonegtimeout_connected(Config, true). + +%%% Test that ssh connection does not timeout if the connection is established (non-parallel) +ssh_connect_nonegtimeout_connected_sequential(Config) -> + ssh_connect_nonegtimeout_connected(Config, false). + + +ssh_connect_nonegtimeout_connected(Config, Parallel) -> + process_flag(trap_exit, true), + SystemDir = filename:join(?config(priv_dir, Config), system), + UserDir = ?config(priv_dir, Config), + NegTimeOut = 20000, % ms + ct:log("Parallel: ~p",[Parallel]), + + {_Pid, _Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},{user_dir, UserDir}, + {parallel_login, Parallel}, + {negotiation_timeout, NegTimeOut}, + {failfun, fun ssh_test_lib:failfun/2}]), + ct:log("~p Listen ~p:~p",[_Pid,_Host,Port]), + ct:sleep(500), + + IO = ssh_test_lib:start_io_server(), + Shell = ssh_test_lib:start_shell(Port, IO, UserDir), + receive + Error = {'EXIT', _, _} -> + ct:log("~p",[Error]), + ct:fail(no_ssh_connection); + ErlShellStart -> + ct:log("---Erlang shell start: ~p~n", [ErlShellStart]), + one_shell_op(IO, NegTimeOut), + one_shell_op(IO, NegTimeOut), + + Factor = 2, + ct:log("And now sleeping ~p*NegTimeOut (~p ms)...", [Factor, round(Factor * NegTimeOut)]), + ct:sleep(round(Factor * NegTimeOut)), + + one_shell_op(IO, NegTimeOut) + after + 10000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) + end, + exit(Shell, kill). + + +one_shell_op(IO, TimeOut) -> + ct:log("One shell op: Waiting for prompter"), + receive + ErlPrompt0 -> ct:log("Erlang prompt: ~p~n", [ErlPrompt0]) + after TimeOut -> ct:fail("Timeout waiting for promter") + end, + + IO ! {input, self(), "2*3*7.\r\n"}, + receive + Echo0 -> ct:log("Echo: ~p ~n", [Echo0]) + after TimeOut -> ct:fail("Timeout waiting for echo") + end, + + receive + ?NEWLINE -> ct:log("NEWLINE received", []) + after TimeOut -> + receive Any1 -> ct:log("Bad NEWLINE: ~p",[Any1]) + after 0 -> ct:fail("Timeout waiting for NEWLINE") + end + end, + + receive + Result0 -> ct:log("Result: ~p~n", [Result0]) + after TimeOut -> ct:fail("Timeout waiting for result") + end. + +%%-------------------------------------------------------------------- +max_sessions_ssh_connect_parallel(Config) -> + max_sessions(Config, true, connect_fun(ssh__connect,Config)). +max_sessions_ssh_connect_sequential(Config) -> + max_sessions(Config, false, connect_fun(ssh__connect,Config)). + +max_sessions_sftp_start_channel_parallel(Config) -> + max_sessions(Config, true, connect_fun(ssh_sftp__start_channel, Config)). +max_sessions_sftp_start_channel_sequential(Config) -> + max_sessions(Config, false, connect_fun(ssh_sftp__start_channel, Config)). + + +%%%---- helpers: +connect_fun(ssh__connect, Config) -> + fun(Host,Port) -> + ssh_test_lib:connect(Host, Port, + [{silently_accept_hosts, true}, + {user_dir, ?config(priv_dir,Config)}, + {user_interaction, false}, + {user, "carni"}, + {password, "meat"} + ]) + %% ssh_test_lib returns R when ssh:connect returns {ok,R} + end; +connect_fun(ssh_sftp__start_channel, _Config) -> + fun(Host,Port) -> + {ok,_Pid,ConnRef} = + ssh_sftp:start_channel(Host, Port, + [{silently_accept_hosts, true}, + {user, "carni"}, + {password, "meat"} + ]), + ConnRef + end. + + +max_sessions(Config, ParallelLogin, Connect0) when is_function(Connect0,2) -> + Connect = fun(Host,Port) -> + R = Connect0(Host,Port), + ct:log("Connect(~p,~p) -> ~p",[Host,Port,R]), + R + end, + SystemDir = filename:join(?config(priv_dir, Config), system), + UserDir = ?config(priv_dir, Config), + MaxSessions = 5, + {Pid, Host, Port} = ssh_test_lib:daemon([ + {system_dir, SystemDir}, + {user_dir, UserDir}, + {user_passwords, [{"carni", "meat"}]}, + {parallel_login, ParallelLogin}, + {max_sessions, MaxSessions} + ]), + ct:log("~p Listen ~p:~p for max ~p sessions",[Pid,Host,Port,MaxSessions]), + try [Connect(Host,Port) || _ <- lists:seq(1,MaxSessions)] + of + Connections -> + %% Step 1 ok: could set up max_sessions connections + ct:log("Connections up: ~p",[Connections]), + [_|_] = Connections, + + %% Now try one more than alowed: + ct:log("Info Report might come here...",[]), + try Connect(Host,Port) + of + _ConnectionRef1 -> + ssh:stop_daemon(Pid), + {fail,"Too many connections accepted"} + catch + error:{badmatch,{error,"Connection closed"}} -> + %% Step 2 ok: could not set up max_sessions+1 connections + %% This is expected + %% Now stop one connection and try to open one more + ok = ssh:close(hd(Connections)), + receive after 250 -> ok end, % sleep so the supervisor has time to count down. Not nice... + try Connect(Host,Port) + of + _ConnectionRef1 -> + %% Step 3 ok: could set up one more connection after killing one + %% Thats good. + ssh:stop_daemon(Pid), + ok + catch + error:{badmatch,{error,"Connection closed"}} -> + %% Bad indeed. Could not set up one more connection even after killing + %% one existing. Very bad. + ssh:stop_daemon(Pid), + {fail,"Does not decrease # active sessions"} + end + end + catch + error:{badmatch,{error,"Connection closed"}} -> + ssh:stop_daemon(Pid), + {fail,"Too few connections accepted"} + end. + +%%-------------------------------------------------------------------- +%% Internal functions ------------------------------------------------ +%%-------------------------------------------------------------------- + +expected_ssh_vsn(Str) -> + try + {ok,L} = application:get_all_key(ssh), + proplists:get_value(vsn,L,"")++"\r\n" + of + Str -> true; + "\r\n" -> true; + _ -> false + catch + _:_ -> true %% ssh not started so we dont't know + end. + + +fake_daemon(_Config) -> + Parent = self(), + %% start the server + Server = spawn(fun() -> + {ok,Sl} = gen_tcp:listen(0,[{packet,line}]), + {ok,{Host,Port}} = inet:sockname(Sl), + ct:log("fake_daemon listening on ~p:~p~n",[Host,Port]), + Parent ! {sockname,self(),Host,Port}, + Rsa = gen_tcp:accept(Sl), + ct:log("Server gen_tcp:accept got ~p",[Rsa]), + {ok,S} = Rsa, + receive + {tcp, S, Id} -> Parent ! {id,self(),Id} + after + 10000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) + end + end), + %% Get listening host and port + receive + {sockname,Server,ServerHost,ServerPort} -> {Server, ServerHost, ServerPort} + after + 10000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) + end. diff --git a/lib/ssh/test/ssh_options_SUITE_data/id_dsa b/lib/ssh/test/ssh_options_SUITE_data/id_dsa new file mode 100644 index 0000000000..d306f8b26e --- /dev/null +++ b/lib/ssh/test/ssh_options_SUITE_data/id_dsa @@ -0,0 +1,13 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBvAIBAAKBgQDfi2flSTZZofwT4yQT0NikX/LGNT7UPeB/XEWe/xovEYCElfaQ +APFixXvEgXwoojmZ5kiQRKzLM39wBP0jPERLbnZXfOOD0PDnw0haMh7dD7XKVMod +/EigVgHf/qBdM2M8yz1s/rRF7n1UpLSypziKjkzCm7JoSQ2zbWIPdmBIXwIVAMgP +kpr7Sq3O7sHdb8D601DRjoExAoGAMOQxDfB2Fd8ouz6G96f/UOzRMI/Kdv8kYYKW +JIGY+pRYrLPyYzUeJznwZreOJgrczAX+luHnKFWJ2Dnk5CyeXk67Wsr7pJ/4MBMD +OKeIS0S8qoSBN8+Krp79fgA+yS3IfqbkJLtLu4EBaCX4mKQIX4++k44d4U5lc8pt ++9hlEI8CgYEAznKxx9kyC6bVo7LUYKaGhofRFt0SYFc5PVmT2VUGRs1R6+6DPD+e +uEO6IhFct7JFSRbP9p0JD4Uk+3zlZF+XX6b2PsZkeV8f/02xlNGUSmEzCSiNg1AX +Cy/WusYhul0MncWCHMcOZB5rIvU/aP5EJJtn3xrRaz6u0SThF6AnT34CFQC63czE +ZU8w8Q+H7z0j+a+70x2iAw== +-----END DSA PRIVATE KEY----- + diff --git a/lib/ssh/test/ssh_options_SUITE_data/id_rsa b/lib/ssh/test/ssh_options_SUITE_data/id_rsa new file mode 100644 index 0000000000..9d7e0dd5fb --- /dev/null +++ b/lib/ssh/test/ssh_options_SUITE_data/id_rsa @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQD1OET+3O/Bvj/dtjxDTXmj1oiJt4sIph5kGy0RfjoPrZfaS+CU +DhakCmS6t2ivxWFgtpKWaoGMZMJqWj6F6ZsumyFl3FPBtujwY/35cgifrI9Ns4Tl +zR1uuengNBmV+WRQ5cd9F2qS6Z8aDQihzt0r8JUqLcK+VQbrmNzboCCQQwIDAQAB +AoGAPQEyqPTt8JUT7mRXuaacjFXiweAXhp9NEDpyi9eLOjtFe9lElZCrsUOkq47V +TGUeRKEm9qSodfTbKPoqc8YaBJGJPhUaTAcha+7QcDdfHBvIsgxvU7ePVnlpXRp3 +CCUEMPhlnx6xBoTYP+fRU0e3+xJIPVyVCqX1jAdUMkzfRoECQQD6ux7B1QJAIWyK +SGkbDUbBilNmzCFNgIpOP6PA+bwfi5d16diTpra5AX09keQABAo/KaP1PdV8Vg0p +z4P3A7G3AkEA+l+AKG6m0kQTTBMJDqOdVPYwe+5GxunMaqmhokpEbuGsrZBl5Dvd +WpcBjR7jmenrhKZRIuA+Fz5HPo/UQJPl1QJBAKxstDkeED8j/S2XoFhPKAJ+6t39 +sUVICVTIZQeXdmzHJXCcUSkw8+WEhakqw/3SyW0oaK2FSWQJFWJUZ+8eJj8CQEh3 +xeduB5kKnS9CvzdeghZqX6QvVosSdtlUmfUYW/BgH5PpHKTP8wTaeld3XldZTpMJ +dKiMkUw2+XYROVUrubUCQD+Na1LhULlpn4ISEtIEfqpdlUhxDgO15Wg8USmsng+x +ICliVOSQtwaZjm8kwaFt0W7XnpnDxbRs37vIEbIMWak= +-----END RSA PRIVATE KEY----- diff --git a/lib/ssh/test/ssh_options_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_options_SUITE_data/ssh_host_dsa_key new file mode 100644 index 0000000000..51ab6fbd88 --- /dev/null +++ b/lib/ssh/test/ssh_options_SUITE_data/ssh_host_dsa_key @@ -0,0 +1,13 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBuwIBAAKBgQCClaHzE2ul0gKSUxah5W0W8UiJLy4hXngKEqpaUq9SSdVdY2LK +wVfKH1gt5iuaf1FfzOhsIC9G/GLnjYttXZc92cv/Gfe3gR+s0ni2++MX+T++mE/Q +diltXv/Hp27PybS67SmiFW7I+RWnT2OKlMPtw2oUuKeztCe5UWjaj/y5FQIVAPLA +l9RpiU30Z87NRAHY3NTRaqtrAoGANMRxw8UfdtNVR0CrQj3AgPaXOGE4d+G4Gp4X +skvnCHycSVAjtYxebUkzUzt5Q6f/IabuLUdge3gXrc8BetvrcKbp+XZgM0/Vj2CF +Ymmy3in6kzGZq7Fw1sZaku6AOU8vLa5woBT2vAcHLLT1bLAzj7viL048T6MfjrOP +ef8nHvACgYBhDWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah +/XcF3DeRF+eEoz48wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+U +ykSTXYUbtsfTNRFQGBW2/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0CgIVAN4wtL5W +Lv62jKcdskxNyz2NQoBx +-----END DSA PRIVATE KEY----- + diff --git a/lib/ssh/test/ssh_options_SUITE_data/ssh_host_dsa_key.pub b/lib/ssh/test/ssh_options_SUITE_data/ssh_host_dsa_key.pub new file mode 100644 index 0000000000..4dbb1305b0 --- /dev/null +++ b/lib/ssh/test/ssh_options_SUITE_data/ssh_host_dsa_key.pub @@ -0,0 +1,11 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +AAAAB3NzaC1kc3MAAACBAIKVofMTa6XSApJTFqHlbRbxSIkvLiFeeAoSqlpSr1JJ1V1j +YsrBV8ofWC3mK5p/UV/M6GwgL0b8YueNi21dlz3Zy/8Z97eBH6zSeLb74xf5P76YT9B2 +KW1e/8enbs/JtLrtKaIVbsj5FadPY4qUw+3DahS4p7O0J7lRaNqP/LkVAAAAFQDywJfU +aYlN9GfOzUQB2NzU0WqrawAAAIA0xHHDxR9201VHQKtCPcCA9pc4YTh34bganheyS+cI +fJxJUCO1jF5tSTNTO3lDp/8hpu4tR2B7eBetzwF62+twpun5dmAzT9WPYIViabLeKfqT +MZmrsXDWxlqS7oA5Ty8trnCgFPa8BwcstPVssDOPu+IvTjxPox+Os495/yce8AAAAIBh +DWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah/XcF3DeRF+eEoz48 +wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+UykSTXYUbtsfTNRFQGBW2 +/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0Cg== +---- END SSH2 PUBLIC KEY ---- diff --git a/lib/ssh/test/ssh_options_SUITE_data/ssh_host_rsa_key b/lib/ssh/test/ssh_options_SUITE_data/ssh_host_rsa_key new file mode 100644 index 0000000000..79968bdd7d --- /dev/null +++ b/lib/ssh/test/ssh_options_SUITE_data/ssh_host_rsa_key @@ -0,0 +1,16 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8semM4q843337 +zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RWRWzjaxSB +6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4QIDAQAB +AoGANmvJzJO5hkLuvyDZHKfAnGTtpifcR1wtSa9DjdKUyn8vhKF0mIimnbnYQEmW +NUUb3gXCZLi9PvkpRSVRrASDOZwcjoU/Kvww163vBUVb2cOZfFhyn6o2Sk88Tt++ +udH3hdjpf9i7jTtUkUe+QYPsia+wgvvrmn4QrahLAH86+kECQQDx5gFeXTME3cnW +WMpFz3PPumduzjqgqMMWEccX4FtQkMX/gyGa5UC7OHFyh0N/gSWvPbRHa8A6YgIt +n8DO+fh5AkEAzbqX4DOn8NY6xJIi42q7l/2jIA0RkB6P7YugW5NblhqBZ0XDnpA5 +sMt+rz+K07u9XZtxgh1xi7mNfwY6lEAMqQJBAJBEauCKmRj35Z6OyeQku59SPsnY ++SJEREVvSNw2lH9SOKQQ4wPsYlTGbvKtNVZgAcen91L5MmYfeckYE/fdIZECQQCt +64zxsTnM1I8iFxj/gP/OYlJBikrKt8udWmjaghzvLMEw+T2DExJyb9ZNeT53+UMB +m6O+B/4xzU/djvp+0hbhAkAemIt+rA5kTmYlFndhpvzkSSM8a2EXsO4XIPgGWCTT +tQKS/tTly0ADMjN/TVy11+9d6zcqadNVuHXHGtR4W0GR +-----END RSA PRIVATE KEY----- + diff --git a/lib/ssh/test/ssh_options_SUITE_data/ssh_host_rsa_key.pub b/lib/ssh/test/ssh_options_SUITE_data/ssh_host_rsa_key.pub new file mode 100644 index 0000000000..75d2025c71 --- /dev/null +++ b/lib/ssh/test/ssh_options_SUITE_data/ssh_host_rsa_key.pub @@ -0,0 +1,5 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +AAAAB3NzaC1yc2EAAAADAQABAAAAgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8 +semM4q843337zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RW +RWzjaxSB6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4Q== +---- END SSH2 PUBLIC KEY ---- diff --git a/lib/ssh/test/ssh_protocol_SUITE.erl b/lib/ssh/test/ssh_protocol_SUITE.erl new file mode 100644 index 0000000000..44da0f4d6f --- /dev/null +++ b/lib/ssh/test/ssh_protocol_SUITE.erl @@ -0,0 +1,705 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2015. 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(ssh_protocol_SUITE). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("kernel/include/inet.hrl"). +-include_lib("ssh/src/ssh.hrl"). % ?UINT32, ?BYTE, #ssh{} ... +-include_lib("ssh/src/ssh_transport.hrl"). +-include_lib("ssh/src/ssh_auth.hrl"). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-define(NEWLINE, <<"\r\n">>). +-define(REKEY_DATA_TMO, 65000). + +-define(v(Key, Config), proplists:get_value(Key, Config)). +-define(v(Key, Config, Default), proplists:get_value(Key, Config, Default)). + + +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- + +suite() -> + [{ct_hooks,[ts_install_cth]}, + {timetrap,{minutes,2}}]. + +all() -> + [{group,tool_tests}, + {group,kex}, + {group,service_requests}, + {group,authentication}, + {group,packet_size_error}, + {group,field_size_error} + ]. + +groups() -> + [{tool_tests, [], [lib_works_as_client, + lib_works_as_server, + lib_match, + lib_no_match + ]}, + {packet_size_error, [], [packet_length_too_large, + packet_length_too_short]}, + + {field_size_error, [], [service_name_length_too_large, + service_name_length_too_short]}, + + {kex, [], [no_common_alg_server_disconnects, + no_common_alg_client_disconnects, + gex_client_init_option_groups, + gex_server_gex_limit, + gex_client_init_option_groups_moduli_file, + gex_client_init_option_groups_file, + gex_client_old_request_exact, + gex_client_old_request_noexact + ]}, + {service_requests, [], [bad_service_name, + bad_long_service_name, + bad_very_long_service_name, + empty_service_name, + bad_service_name_then_correct + ]}, + {authentication, [], [client_handles_keyboard_interactive_0_pwds + ]} + ]. + + +init_per_suite(Config) -> + start_std_daemon( setup_dirs( start_apps(Config))). + +end_per_suite(Config) -> + stop_apps(Config). + + + +init_per_testcase(no_common_alg_server_disconnects, Config) -> + start_std_daemon(Config, [{preferred_algorithms,[{public_key,['ssh-rsa']}]}]); + +init_per_testcase(TC, Config) when TC == gex_client_init_option_groups ; + TC == gex_client_init_option_groups_moduli_file ; + TC == gex_client_init_option_groups_file ; + TC == gex_server_gex_limit ; + TC == gex_client_old_request_exact ; + TC == gex_client_old_request_noexact -> + Opts = case TC of + gex_client_init_option_groups -> + [{dh_gex_groups, [{2345, 3, 41}]}]; + gex_client_init_option_groups_file -> + DataDir = ?config(data_dir, Config), + F = filename:join(DataDir, "dh_group_test"), + [{dh_gex_groups, {file,F}}]; + gex_client_init_option_groups_moduli_file -> + DataDir = ?config(data_dir, Config), + F = filename:join(DataDir, "dh_group_test.moduli"), + [{dh_gex_groups, {ssh_moduli_file,F}}]; + _ when TC == gex_server_gex_limit ; + TC == gex_client_old_request_exact ; + TC == gex_client_old_request_noexact -> + [{dh_gex_groups, [{ 500, 3, 17}, + {1000, 7, 91}, + {3000, 5, 61}]}, + {dh_gex_limits,{500,1500}} + ]; + _ -> + [] + end, + start_std_daemon(Config, + [{preferred_algorithms, ssh:default_algorithms()} + | Opts]); +init_per_testcase(_TestCase, Config) -> + check_std_daemon_works(Config, ?LINE). + +end_per_testcase(no_common_alg_server_disconnects, Config) -> + stop_std_daemon(Config); +end_per_testcase(TC, Config) when TC == gex_client_init_option_groups ; + TC == gex_client_init_option_groups_moduli_file ; + TC == gex_client_init_option_groups_file ; + TC == gex_server_gex_limit ; + TC == gex_client_old_request_exact ; + TC == gex_client_old_request_noexact -> + stop_std_daemon(Config); +end_per_testcase(_TestCase, Config) -> + check_std_daemon_works(Config, ?LINE). + +%%%-------------------------------------------------------------------- +%%% Test Cases -------------------------------------------------------- +%%%-------------------------------------------------------------------- + +%%%-------------------------------------------------------------------- +%%% Connect to an erlang server and check that the testlib acts as a client. +lib_works_as_client(Config) -> + %% Connect and negotiate keys + {ok,InitialState} = ssh_trpt_test_lib:exec( + [{set_options, [print_ops, print_seqnums, print_messages]}] + ), + {ok,AfterKexState} = connect_and_kex(Config, InitialState), + + %% Do the authentcation + {User,Pwd} = server_user_password(Config), + {ok,EndState} = + ssh_trpt_test_lib:exec( + [{send, #ssh_msg_service_request{name = "ssh-userauth"}}, + {match, #ssh_msg_service_accept{name = "ssh-userauth"}, receive_msg}, + {send, #ssh_msg_userauth_request{user = User, + service = "ssh-connection", + method = "password", + data = <<?BOOLEAN(?FALSE), + ?STRING(unicode:characters_to_binary(Pwd))>> + }}, + {match, #ssh_msg_userauth_success{_='_'}, receive_msg} + ], AfterKexState), + + %% Disconnect + {ok,_} = + ssh_trpt_test_lib:exec( + [{send, #ssh_msg_disconnect{code = ?SSH_DISCONNECT_BY_APPLICATION, + description = "End of the fun", + language = "" + }}, + close_socket + ], EndState). + + +%%-------------------------------------------------------------------- +%%% Connect an erlang client and check that the testlib can act as a server. +lib_works_as_server(Config) -> + {User,_Pwd} = server_user_password(Config), + + %% Create a listening socket as server socket: + {ok,InitialState} = ssh_trpt_test_lib:exec(listen), + HostPort = ssh_trpt_test_lib:server_host_port(InitialState), + + %% Start a process handling one connection on the server side: + spawn_link( + fun() -> + {ok,_} = + ssh_trpt_test_lib:exec( + [{set_options, [print_ops, print_messages]}, + {accept, [{system_dir, system_dir(Config)}, + {user_dir, user_dir(Config)}]}, + receive_hello, + {send, hello}, + + {send, ssh_msg_kexinit}, + {match, #ssh_msg_kexinit{_='_'}, receive_msg}, + + {match, #ssh_msg_kexdh_init{_='_'}, receive_msg}, + {send, ssh_msg_kexdh_reply}, + + {send, #ssh_msg_newkeys{}}, + {match, #ssh_msg_newkeys{_='_'}, receive_msg}, + + {match, #ssh_msg_service_request{name="ssh-userauth"}, receive_msg}, + {send, #ssh_msg_service_accept{name="ssh-userauth"}}, + + {match, #ssh_msg_userauth_request{service="ssh-connection", + method="none", + user=User, + _='_'}, receive_msg}, + + {send, #ssh_msg_userauth_failure{authentications = "password", + partial_success = false}}, + + {match, #ssh_msg_userauth_request{service="ssh-connection", + method="password", + user=User, + _='_'}, receive_msg}, + {send, #ssh_msg_userauth_success{}}, + close_socket, + print_state + ], + InitialState) + end), + + %% and finally connect to it with a regular Erlang SSH client: + {ok,_} = std_connect(HostPort, Config, + [{preferred_algorithms,[{kex,['diffie-hellman-group1-sha1']}]}] + ). + +%%-------------------------------------------------------------------- +%%% Matching +lib_match(_Config) -> + {ok,_} = + ssh_trpt_test_lib:exec([{set_options, [print_ops]}, + {match, abc, abc}, + {match, '$a', {cde,fgh}}, + {match, {cde,fgh}, '$a'}, + {match, '_', {cde,fgh}}, + {match, [a,'$a',b], [a,{cde,fgh},b]}, + {match, [a,'$a'|'$b'], [a,{cde,fgh},b,c]}, + {match, '$b', [b,c]} + ]). + +%%-------------------------------------------------------------------- +%%% Not matching +lib_no_match(_Config) -> + case ssh_trpt_test_lib:exec([{set_options, [print_ops]}, + {match, '$x', b}, + {match, a, '$x'}]) + of + {ok,_} -> {fail,"Unexpected match"}; + {error, {_Op,{expected,a,b},_State}} -> ok + end. + +%%-------------------------------------------------------------------- +%%% Algo negotiation fail. This should result in a ssh_msg_disconnect +%%% being sent from the server. +no_common_alg_server_disconnects(Config) -> + {ok,_} = + ssh_trpt_test_lib:exec( + [{set_options, [print_ops, {print_messages,detail}]}, + {connect, + server_host(Config),server_port(Config), + [{silently_accept_hosts, true}, + {user_dir, user_dir(Config)}, + {user_interaction, false}, + {preferred_algorithms,[{public_key,['ssh-dss']}]} + ]}, + receive_hello, + {send, hello}, + {match, #ssh_msg_kexinit{_='_'}, receive_msg}, + {send, ssh_msg_kexinit}, % with server unsupported 'ssh-dss' ! + {match, disconnect(), receive_msg} + ] + ). + +%%-------------------------------------------------------------------- +%%% Algo negotiation fail. This should result in a ssh_msg_disconnect +%%% being sent from the client. +no_common_alg_client_disconnects(Config) -> + %% Create a listening socket as server socket: + {ok,InitialState} = ssh_trpt_test_lib:exec(listen), + HostPort = ssh_trpt_test_lib:server_host_port(InitialState), + Parent = self(), + + %% Start a process handling one connection on the server side: + Pid = + spawn_link( + fun() -> + Parent ! + {result,self(), + ssh_trpt_test_lib:exec( + [{set_options, [print_ops, {print_messages,detail}]}, + {accept, [{system_dir, system_dir(Config)}, + {user_dir, user_dir(Config)}]}, + receive_hello, + {send, hello}, + {match, #ssh_msg_kexinit{_='_'}, receive_msg}, + {send, #ssh_msg_kexinit{ % with unsupported "SOME-UNSUPPORTED" + cookie = 247381486335508958743193106082599558706, + kex_algorithms = ["diffie-hellman-group1-sha1"], + server_host_key_algorithms = ["SOME-UNSUPPORTED"], % SIC! + encryption_algorithms_client_to_server = ["aes128-ctr"], + encryption_algorithms_server_to_client = ["aes128-ctr"], + mac_algorithms_client_to_server = ["hmac-sha2-256"], + mac_algorithms_server_to_client = ["hmac-sha2-256"], + compression_algorithms_client_to_server = ["none"], + compression_algorithms_server_to_client = ["none"], + languages_client_to_server = [], + languages_server_to_client = [], + first_kex_packet_follows = false, + reserved = 0 + }}, + {match, disconnect(?SSH_DISCONNECT_KEY_EXCHANGE_FAILED), receive_msg} + ], + InitialState) + } + end), + + %% and finally connect to it with a regular Erlang SSH client + %% which of course does not support SOME-UNSUPPORTED as pub key algo: + Result = std_connect(HostPort, Config, [{preferred_algorithms,[{public_key,['ssh-dss']}]}]), + ct:log("Result of connect is ~p",[Result]), + + receive + {result,Pid,{ok,_}} -> + ok; + {result,Pid,{error,{Op,ExecResult,S}}} -> + ct:log("ERROR!~nOp = ~p~nExecResult = ~p~nState =~n~s", + [Op,ExecResult,ssh_trpt_test_lib:format_msg(S)]), + {fail, ExecResult}; + X -> + ct:log("¤¤¤¤¤"), + ct:fail(X) + after + 30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) + end. + +%%%-------------------------------------------------------------------- +gex_client_init_option_groups(Config) -> + do_gex_client_init(Config, {2000, 2048, 4000}, + {3,41}). + +gex_client_init_option_groups_file(Config) -> + do_gex_client_init(Config, {2000, 2048, 4000}, + {5,61}). + +gex_client_init_option_groups_moduli_file(Config) -> + do_gex_client_init(Config, {2000, 2048, 4000}, + {5,16#B7}). + +gex_server_gex_limit(Config) -> + do_gex_client_init(Config, {1000, 3000, 4000}, + {7,91}). + + +do_gex_client_init(Config, {Min,N,Max}, {G,P}) -> + {ok,_} = + ssh_trpt_test_lib:exec( + [{set_options, [print_ops, print_seqnums, print_messages]}, + {connect, + server_host(Config),server_port(Config), + [{silently_accept_hosts, true}, + {user_dir, user_dir(Config)}, + {user_interaction, false}, + {preferred_algorithms,[{kex,['diffie-hellman-group-exchange-sha1']}]} + ]}, + receive_hello, + {send, hello}, + {send, ssh_msg_kexinit}, + {match, #ssh_msg_kexinit{_='_'}, receive_msg}, + {send, #ssh_msg_kex_dh_gex_request{min = Min, + n = N, + max = Max}}, + {match, #ssh_msg_kex_dh_gex_group{p=P, g=G, _='_'}, receive_msg} + ] + ). + +%%%-------------------------------------------------------------------- +gex_client_old_request_exact(Config) -> do_gex_client_init_old(Config, 500, {3,17}). +gex_client_old_request_noexact(Config) -> do_gex_client_init_old(Config, 800, {7,91}). + +do_gex_client_init_old(Config, N, {G,P}) -> + {ok,_} = + ssh_trpt_test_lib:exec( + [{set_options, [print_ops, print_seqnums, print_messages]}, + {connect, + server_host(Config),server_port(Config), + [{silently_accept_hosts, true}, + {user_dir, user_dir(Config)}, + {user_interaction, false}, + {preferred_algorithms,[{kex,['diffie-hellman-group-exchange-sha1']}]} + ]}, + receive_hello, + {send, hello}, + {send, ssh_msg_kexinit}, + {match, #ssh_msg_kexinit{_='_'}, receive_msg}, + {send, #ssh_msg_kex_dh_gex_request_old{n = N}}, + {match, #ssh_msg_kex_dh_gex_group{p=P, g=G, _='_'}, receive_msg} + ] + ). + +%%%-------------------------------------------------------------------- +bad_service_name(Config) -> + bad_service_name(Config, "kfglkjf"). + +bad_long_service_name(Config) -> + bad_service_name(Config, + lists:duplicate(?SSH_MAX_PACKET_SIZE div 2, $a)). + +bad_very_long_service_name(Config) -> + bad_service_name(Config, + lists:duplicate(4*?SSH_MAX_PACKET_SIZE, $a)). + +empty_service_name(Config) -> + bad_service_name(Config, ""). + +bad_service_name_then_correct(Config) -> + {ok,InitialState} = connect_and_kex(Config), + {ok,_} = + ssh_trpt_test_lib:exec( + [{set_options, [print_ops, print_seqnums, print_messages]}, + {send, #ssh_msg_service_request{name = "kdjglkfdjgkldfjglkdfjglkfdjglkj"}}, + {send, #ssh_msg_service_request{name = "ssh-connection"}}, + {match, disconnect(), receive_msg} + ], InitialState). + + +bad_service_name(Config, Name) -> + {ok,InitialState} = connect_and_kex(Config), + {ok,_} = + ssh_trpt_test_lib:exec( + [{set_options, [print_ops, print_seqnums, print_messages]}, + {send, #ssh_msg_service_request{name = Name}}, + {match, disconnect(), receive_msg} + ], InitialState). + +%%%-------------------------------------------------------------------- +packet_length_too_large(Config) -> bad_packet_length(Config, +4). + +packet_length_too_short(Config) -> bad_packet_length(Config, -4). + +bad_packet_length(Config, LengthExcess) -> + PacketFun = + fun(Msg, Ssh) -> + BinMsg = ssh_message:encode(Msg), + ssh_transport:pack(BinMsg, Ssh, LengthExcess) + end, + {ok,InitialState} = connect_and_kex(Config), + {ok,_} = + ssh_trpt_test_lib:exec( + [{set_options, [print_ops, print_seqnums, print_messages]}, + {send, {special, + #ssh_msg_service_request{name="ssh-userauth"}, + PacketFun}}, + %% Prohibit remote decoder starvation: + {send, #ssh_msg_service_request{name="ssh-userauth"}}, + {match, disconnect(), receive_msg} + ], InitialState). + +%%%-------------------------------------------------------------------- +service_name_length_too_large(Config) -> bad_service_name_length(Config, +4). + +service_name_length_too_short(Config) -> bad_service_name_length(Config, -4). + + +bad_service_name_length(Config, LengthExcess) -> + PacketFun = + fun(#ssh_msg_service_request{name=Service}, Ssh) -> + BinName = list_to_binary(Service), + BinMsg = + <<?BYTE(?SSH_MSG_SERVICE_REQUEST), + %% A bad string encoding of Service: + ?UINT32(size(BinName)+LengthExcess), BinName/binary + >>, + ssh_transport:pack(BinMsg, Ssh) + end, + {ok,InitialState} = connect_and_kex(Config), + {ok,_} = + ssh_trpt_test_lib:exec( + [{set_options, [print_ops, print_seqnums, print_messages]}, + {send, {special, + #ssh_msg_service_request{name="ssh-userauth"}, + PacketFun} }, + %% Prohibit remote decoder starvation: + {send, #ssh_msg_service_request{name="ssh-userauth"}}, + {match, disconnect(), receive_msg} + ], InitialState). + +%%%-------------------------------------------------------------------- +%%% This is due to a fault report (OTP-13255) with OpenSSH-6.6.1 +client_handles_keyboard_interactive_0_pwds(Config) -> + {User,_Pwd} = server_user_password(Config), + + %% Create a listening socket as server socket: + {ok,InitialState} = ssh_trpt_test_lib:exec(listen), + HostPort = ssh_trpt_test_lib:server_host_port(InitialState), + + %% Start a process handling one connection on the server side: + spawn_link( + fun() -> + {ok,_} = + ssh_trpt_test_lib:exec( + [{set_options, [print_ops, print_messages]}, + {accept, [{system_dir, system_dir(Config)}, + {user_dir, user_dir(Config)}]}, + receive_hello, + {send, hello}, + + {send, ssh_msg_kexinit}, + {match, #ssh_msg_kexinit{_='_'}, receive_msg}, + + {match, #ssh_msg_kexdh_init{_='_'}, receive_msg}, + {send, ssh_msg_kexdh_reply}, + + {send, #ssh_msg_newkeys{}}, + {match, #ssh_msg_newkeys{_='_'}, receive_msg}, + + {match, #ssh_msg_service_request{name="ssh-userauth"}, receive_msg}, + {send, #ssh_msg_service_accept{name="ssh-userauth"}}, + + {match, #ssh_msg_userauth_request{service="ssh-connection", + method="none", + user=User, + _='_'}, receive_msg}, + {send, #ssh_msg_userauth_failure{authentications = "keyboard-interactive", + partial_success = false}}, + + {match, #ssh_msg_userauth_request{service="ssh-connection", + method="keyboard-interactive", + user=User, + _='_'}, receive_msg}, + {send, #ssh_msg_userauth_info_request{name = "", + instruction = "", + language_tag = "", + num_prompts = 1, + data = <<0,0,0,10,80,97,115,115,119,111,114,100,58,32,0>> + }}, + {match, #ssh_msg_userauth_info_response{num_responses = 1, + _='_'}, receive_msg}, + + %% the next is strange, but openssh 6.6.1 does this and this is what this testcase is about + {send, #ssh_msg_userauth_info_request{name = "", + instruction = "", + language_tag = "", + num_prompts = 0, + data = <<>> + }}, + {match, #ssh_msg_userauth_info_response{num_responses = 0, + data = <<>>, + _='_'}, receive_msg}, + %% Here we know that the tested fault is fixed + {send, #ssh_msg_userauth_success{}}, + close_socket, + print_state + ], + InitialState) + end), + + %% and finally connect to it with a regular Erlang SSH client: + {ok,_} = std_connect(HostPort, Config, + [{preferred_algorithms,[{kex,['diffie-hellman-group1-sha1']}]}] + ). + + +%%%================================================================ +%%%==== Internal functions ======================================== +%%%================================================================ + +%%%---- init_suite and end_suite --------------------------------------- +start_apps(Config) -> + catch ssh:stop(), + ok = ssh:start(), + Config. + +stop_apps(_Config) -> + ssh:stop(). + + +setup_dirs(Config) -> + DataDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + ssh_test_lib:setup_rsa(DataDir, PrivDir), + Config. + +system_dir(Config) -> filename:join(?config(priv_dir, Config), system). + +user_dir(Config) -> ?config(priv_dir, Config). + +%%%---------------------------------------------------------------- +start_std_daemon(Config) -> + start_std_daemon(Config, []). + +start_std_daemon(Config, ExtraOpts) -> + PrivDir = ?config(priv_dir, Config), + UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), + UserPasswords = [{"user1","pwd1"}], + Options = [%%{preferred_algorithms,[{public_key,['ssh-rsa']}]}, %% For some test cases + {system_dir, system_dir(Config)}, + {user_dir, UserDir}, + {user_passwords, UserPasswords}, + {failfun, fun ssh_test_lib:failfun/2} + | ExtraOpts], + Ref = {Server, Host, Port} = ssh_test_lib:daemon(Options), + ct:log("Std server ~p started at ~p:~p~nOptions=~p",[Server, Host, Port, Options]), + [{server,Ref}, {user_passwords, UserPasswords} | Config]. + + +stop_std_daemon(Config) -> + ssh:stop_daemon(server_pid(Config)), + ct:log("Std server ~p at ~p:~p stopped", [server_pid(Config), server_host(Config), server_port(Config)]), + lists:keydelete(server, 1, Config). + + +check_std_daemon_works(Config, Line) -> + case std_connect(Config) of + {ok,C} -> + ct:log("Server ~p:~p ~p is ok at line ~p", + [server_host(Config), server_port(Config), + server_pid(Config), Line]), + ok = ssh:close(C), + Config; + Error = {error,_} -> + ct:fail("Standard server ~p:~p ~p is ill at line ~p: ~p", + [server_host(Config), server_port(Config), + server_pid(Config), Line, Error]) + end. + +server_pid(Config) -> element(1,?v(server,Config)). +server_host(Config) -> element(2,?v(server,Config)). +server_port(Config) -> element(3,?v(server,Config)). + +server_user_password(Config) -> server_user_password(1, Config). + +server_user_password(N, Config) -> lists:nth(N, ?v(user_passwords,Config)). + + +std_connect(Config) -> + std_connect({server_host(Config), server_port(Config)}, Config). + +std_connect({Host,Port}, Config) -> + std_connect({Host,Port}, Config, []). + +std_connect({Host,Port}, Config, Opts) -> + std_connect(Host, Port, Config, Opts). + +std_connect(Host, Port, Config, Opts) -> + {User,Pwd} = server_user_password(Config), + ssh:connect(Host, Port, + %% Prefere User's Opts to the default opts + [O || O = {Tag,_} <- [{user,User},{password,Pwd}, + {silently_accept_hosts, true}, + {user_dir, user_dir(Config)}, + {user_interaction, false}], + not lists:keymember(Tag, 1, Opts) + ] ++ Opts, + 30000). + +%%%---------------------------------------------------------------- +connect_and_kex(Config) -> + connect_and_kex(Config, ssh_trpt_test_lib:exec([]) ). + +connect_and_kex(Config, InitialState) -> + ssh_trpt_test_lib:exec( + [{connect, + server_host(Config),server_port(Config), + [{preferred_algorithms,[{kex,['diffie-hellman-group1-sha1']}]}, + {silently_accept_hosts, true}, + {user_dir, user_dir(Config)}, + {user_interaction, false}]}, + receive_hello, + {send, hello}, + {send, ssh_msg_kexinit}, + {match, #ssh_msg_kexinit{_='_'}, receive_msg}, + {send, ssh_msg_kexdh_init}, + {match,# ssh_msg_kexdh_reply{_='_'}, receive_msg}, + {send, #ssh_msg_newkeys{}}, + {match, #ssh_msg_newkeys{_='_'}, receive_msg} + ], + InitialState). + +%%%---------------------------------------------------------------- + +%%% For matching peer disconnection +disconnect() -> + disconnect('_'). + +disconnect(Code) -> + {'or',[#ssh_msg_disconnect{code = Code, + _='_'}, + tcp_closed, + {tcp_error,econnaborted} + ]}. diff --git a/lib/ssh/test/ssh_protocol_SUITE_data/dh_group_test b/lib/ssh/test/ssh_protocol_SUITE_data/dh_group_test new file mode 100644 index 0000000000..2887bb4b60 --- /dev/null +++ b/lib/ssh/test/ssh_protocol_SUITE_data/dh_group_test @@ -0,0 +1,3 @@ +{2222, 5, 61}. +{1111, 7, 91}. + diff --git a/lib/ssh/test/ssh_protocol_SUITE_data/dh_group_test.moduli b/lib/ssh/test/ssh_protocol_SUITE_data/dh_group_test.moduli new file mode 100644 index 0000000000..f6995ba4c9 --- /dev/null +++ b/lib/ssh/test/ssh_protocol_SUITE_data/dh_group_test.moduli @@ -0,0 +1,3 @@ +20151021104105 2 6 100 2222 5 B7 +20151021104106 2 6 100 1111 5 4F + diff --git a/lib/ssh/test/ssh_protocol_SUITE_data/id_dsa b/lib/ssh/test/ssh_protocol_SUITE_data/id_dsa new file mode 100644 index 0000000000..d306f8b26e --- /dev/null +++ b/lib/ssh/test/ssh_protocol_SUITE_data/id_dsa @@ -0,0 +1,13 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBvAIBAAKBgQDfi2flSTZZofwT4yQT0NikX/LGNT7UPeB/XEWe/xovEYCElfaQ +APFixXvEgXwoojmZ5kiQRKzLM39wBP0jPERLbnZXfOOD0PDnw0haMh7dD7XKVMod +/EigVgHf/qBdM2M8yz1s/rRF7n1UpLSypziKjkzCm7JoSQ2zbWIPdmBIXwIVAMgP +kpr7Sq3O7sHdb8D601DRjoExAoGAMOQxDfB2Fd8ouz6G96f/UOzRMI/Kdv8kYYKW +JIGY+pRYrLPyYzUeJznwZreOJgrczAX+luHnKFWJ2Dnk5CyeXk67Wsr7pJ/4MBMD +OKeIS0S8qoSBN8+Krp79fgA+yS3IfqbkJLtLu4EBaCX4mKQIX4++k44d4U5lc8pt ++9hlEI8CgYEAznKxx9kyC6bVo7LUYKaGhofRFt0SYFc5PVmT2VUGRs1R6+6DPD+e +uEO6IhFct7JFSRbP9p0JD4Uk+3zlZF+XX6b2PsZkeV8f/02xlNGUSmEzCSiNg1AX +Cy/WusYhul0MncWCHMcOZB5rIvU/aP5EJJtn3xrRaz6u0SThF6AnT34CFQC63czE +ZU8w8Q+H7z0j+a+70x2iAw== +-----END DSA PRIVATE KEY----- + diff --git a/lib/ssh/test/ssh_protocol_SUITE_data/id_rsa b/lib/ssh/test/ssh_protocol_SUITE_data/id_rsa new file mode 100644 index 0000000000..9d7e0dd5fb --- /dev/null +++ b/lib/ssh/test/ssh_protocol_SUITE_data/id_rsa @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQD1OET+3O/Bvj/dtjxDTXmj1oiJt4sIph5kGy0RfjoPrZfaS+CU +DhakCmS6t2ivxWFgtpKWaoGMZMJqWj6F6ZsumyFl3FPBtujwY/35cgifrI9Ns4Tl +zR1uuengNBmV+WRQ5cd9F2qS6Z8aDQihzt0r8JUqLcK+VQbrmNzboCCQQwIDAQAB +AoGAPQEyqPTt8JUT7mRXuaacjFXiweAXhp9NEDpyi9eLOjtFe9lElZCrsUOkq47V +TGUeRKEm9qSodfTbKPoqc8YaBJGJPhUaTAcha+7QcDdfHBvIsgxvU7ePVnlpXRp3 +CCUEMPhlnx6xBoTYP+fRU0e3+xJIPVyVCqX1jAdUMkzfRoECQQD6ux7B1QJAIWyK +SGkbDUbBilNmzCFNgIpOP6PA+bwfi5d16diTpra5AX09keQABAo/KaP1PdV8Vg0p +z4P3A7G3AkEA+l+AKG6m0kQTTBMJDqOdVPYwe+5GxunMaqmhokpEbuGsrZBl5Dvd +WpcBjR7jmenrhKZRIuA+Fz5HPo/UQJPl1QJBAKxstDkeED8j/S2XoFhPKAJ+6t39 +sUVICVTIZQeXdmzHJXCcUSkw8+WEhakqw/3SyW0oaK2FSWQJFWJUZ+8eJj8CQEh3 +xeduB5kKnS9CvzdeghZqX6QvVosSdtlUmfUYW/BgH5PpHKTP8wTaeld3XldZTpMJ +dKiMkUw2+XYROVUrubUCQD+Na1LhULlpn4ISEtIEfqpdlUhxDgO15Wg8USmsng+x +ICliVOSQtwaZjm8kwaFt0W7XnpnDxbRs37vIEbIMWak= +-----END RSA PRIVATE KEY----- diff --git a/lib/ssh/test/ssh_protocol_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_protocol_SUITE_data/ssh_host_dsa_key new file mode 100644 index 0000000000..51ab6fbd88 --- /dev/null +++ b/lib/ssh/test/ssh_protocol_SUITE_data/ssh_host_dsa_key @@ -0,0 +1,13 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBuwIBAAKBgQCClaHzE2ul0gKSUxah5W0W8UiJLy4hXngKEqpaUq9SSdVdY2LK +wVfKH1gt5iuaf1FfzOhsIC9G/GLnjYttXZc92cv/Gfe3gR+s0ni2++MX+T++mE/Q +diltXv/Hp27PybS67SmiFW7I+RWnT2OKlMPtw2oUuKeztCe5UWjaj/y5FQIVAPLA +l9RpiU30Z87NRAHY3NTRaqtrAoGANMRxw8UfdtNVR0CrQj3AgPaXOGE4d+G4Gp4X +skvnCHycSVAjtYxebUkzUzt5Q6f/IabuLUdge3gXrc8BetvrcKbp+XZgM0/Vj2CF +Ymmy3in6kzGZq7Fw1sZaku6AOU8vLa5woBT2vAcHLLT1bLAzj7viL048T6MfjrOP +ef8nHvACgYBhDWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah +/XcF3DeRF+eEoz48wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+U +ykSTXYUbtsfTNRFQGBW2/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0CgIVAN4wtL5W +Lv62jKcdskxNyz2NQoBx +-----END DSA PRIVATE KEY----- + diff --git a/lib/ssh/test/ssh_protocol_SUITE_data/ssh_host_dsa_key.pub b/lib/ssh/test/ssh_protocol_SUITE_data/ssh_host_dsa_key.pub new file mode 100644 index 0000000000..4dbb1305b0 --- /dev/null +++ b/lib/ssh/test/ssh_protocol_SUITE_data/ssh_host_dsa_key.pub @@ -0,0 +1,11 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +AAAAB3NzaC1kc3MAAACBAIKVofMTa6XSApJTFqHlbRbxSIkvLiFeeAoSqlpSr1JJ1V1j +YsrBV8ofWC3mK5p/UV/M6GwgL0b8YueNi21dlz3Zy/8Z97eBH6zSeLb74xf5P76YT9B2 +KW1e/8enbs/JtLrtKaIVbsj5FadPY4qUw+3DahS4p7O0J7lRaNqP/LkVAAAAFQDywJfU +aYlN9GfOzUQB2NzU0WqrawAAAIA0xHHDxR9201VHQKtCPcCA9pc4YTh34bganheyS+cI +fJxJUCO1jF5tSTNTO3lDp/8hpu4tR2B7eBetzwF62+twpun5dmAzT9WPYIViabLeKfqT +MZmrsXDWxlqS7oA5Ty8trnCgFPa8BwcstPVssDOPu+IvTjxPox+Os495/yce8AAAAIBh +DWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah/XcF3DeRF+eEoz48 +wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+UykSTXYUbtsfTNRFQGBW2 +/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0Cg== +---- END SSH2 PUBLIC KEY ---- diff --git a/lib/ssh/test/ssh_protocol_SUITE_data/ssh_host_rsa_key b/lib/ssh/test/ssh_protocol_SUITE_data/ssh_host_rsa_key new file mode 100644 index 0000000000..79968bdd7d --- /dev/null +++ b/lib/ssh/test/ssh_protocol_SUITE_data/ssh_host_rsa_key @@ -0,0 +1,16 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8semM4q843337 +zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RWRWzjaxSB +6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4QIDAQAB +AoGANmvJzJO5hkLuvyDZHKfAnGTtpifcR1wtSa9DjdKUyn8vhKF0mIimnbnYQEmW +NUUb3gXCZLi9PvkpRSVRrASDOZwcjoU/Kvww163vBUVb2cOZfFhyn6o2Sk88Tt++ +udH3hdjpf9i7jTtUkUe+QYPsia+wgvvrmn4QrahLAH86+kECQQDx5gFeXTME3cnW +WMpFz3PPumduzjqgqMMWEccX4FtQkMX/gyGa5UC7OHFyh0N/gSWvPbRHa8A6YgIt +n8DO+fh5AkEAzbqX4DOn8NY6xJIi42q7l/2jIA0RkB6P7YugW5NblhqBZ0XDnpA5 +sMt+rz+K07u9XZtxgh1xi7mNfwY6lEAMqQJBAJBEauCKmRj35Z6OyeQku59SPsnY ++SJEREVvSNw2lH9SOKQQ4wPsYlTGbvKtNVZgAcen91L5MmYfeckYE/fdIZECQQCt +64zxsTnM1I8iFxj/gP/OYlJBikrKt8udWmjaghzvLMEw+T2DExJyb9ZNeT53+UMB +m6O+B/4xzU/djvp+0hbhAkAemIt+rA5kTmYlFndhpvzkSSM8a2EXsO4XIPgGWCTT +tQKS/tTly0ADMjN/TVy11+9d6zcqadNVuHXHGtR4W0GR +-----END RSA PRIVATE KEY----- + diff --git a/lib/ssh/test/ssh_protocol_SUITE_data/ssh_host_rsa_key.pub b/lib/ssh/test/ssh_protocol_SUITE_data/ssh_host_rsa_key.pub new file mode 100644 index 0000000000..75d2025c71 --- /dev/null +++ b/lib/ssh/test/ssh_protocol_SUITE_data/ssh_host_rsa_key.pub @@ -0,0 +1,5 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +AAAAB3NzaC1yc2EAAAADAQABAAAAgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8 +semM4q843337zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RW +RWzjaxSB6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4Q== +---- END SSH2 PUBLIC KEY ---- diff --git a/lib/ssh/test/ssh_relay.erl b/lib/ssh/test/ssh_relay.erl index a4f2bad2e2..28000fbb97 100644 --- a/lib/ssh/test/ssh_relay.erl +++ b/lib/ssh/test/ssh_relay.erl @@ -117,7 +117,7 @@ stop(Srv) -> %% {stop, Reason} %% @end %%-------------------------------------------------------------------- -init([ListenAddr, ListenPort, PeerAddr, PeerPort | Options]) -> +init([ListenAddr, ListenPort, PeerAddr, PeerPort | _Options]) -> IfAddr = case ListenAddr of {0,0,0,0} -> []; diff --git a/lib/ssh/test/ssh_renegotiate_SUITE.erl b/lib/ssh/test/ssh_renegotiate_SUITE.erl new file mode 100644 index 0000000000..6d2c97aa68 --- /dev/null +++ b/lib/ssh/test/ssh_renegotiate_SUITE.erl @@ -0,0 +1,250 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2015. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +-module(ssh_renegotiate_SUITE). + +-include_lib("common_test/include/ct.hrl"). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-define(REKEY_DATA_TMO, 65000). +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- + +suite() -> [{ct_hooks,[ts_install_cth]}, + {timetrap,{minutes,12}}]. + + +all() -> [{group,default_algs}, + {group,aes_gcm} + ]. + +groups() -> [{default_algs, [], tests()}, + {aes_gcm, [], tests()} + ]. + +tests() -> [rekey, rekey_limit, renegotiate1, renegotiate2]. + +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + Config. + +end_per_suite(_Config) -> + ssh:stop(). + +%%-------------------------------------------------------------------- +init_per_group(aes_gcm, Config) -> + case lists:member({client2server,['[email protected]']}, + ssh_transport:supported_algorithms(cipher)) of + true -> + [{preferred_algorithms, [{cipher,[{client2server,['[email protected]']}, + {server2client,['[email protected]']}]}]} + | Config]; + false -> + {skip, "aes_gcm not supported"} + end; +init_per_group(_, Config) -> + [{preferred_algorithms, ssh:default_algorithms()} | Config]. + + +end_per_group(_, Config) -> + Config. + +%%-------------------------------------------------------------------- +init_per_testcase(_TestCase, Config) -> + ssh:start(), + Config. + +end_per_testcase(_TestCase, _Config) -> + ssh:stop(), + ok. + +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- + +%%% Idle timeout test + +rekey(Config) -> + {Pid, Host, Port} = + ssh_test_lib:std_daemon(Config, + [{rekey_limit, 0}]), + ConnectionRef = + ssh_test_lib:std_connect(Config, Host, Port, + [{rekey_limit, 0}]), + Kex1 = get_kex_init(ConnectionRef), + receive + after ?REKEY_DATA_TMO -> + %%By this time rekeying would have been done + Kex2 = get_kex_init(ConnectionRef), + false = (Kex2 == Kex1), + ssh:close(ConnectionRef), + ssh:stop_daemon(Pid) + end. + +%%-------------------------------------------------------------------- + +%%% Test rekeying by data volume + +rekey_limit(Config) -> + UserDir = ?config(priv_dir, Config), + DataFile = filename:join(UserDir, "rekey.data"), + + Algs = ?config(preferred_algorithms, Config), + {Pid, Host, Port} = ssh_test_lib:std_daemon(Config,[{max_random_length_padding,0}, + {preferred_algorithms,Algs}]), + + ConnectionRef = ssh_test_lib:std_connect(Config, Host, Port, [{rekey_limit, 6000}, + {max_random_length_padding,0}]), + {ok, SftpPid} = ssh_sftp:start_channel(ConnectionRef), + + Kex1 = get_kex_init(ConnectionRef), + + timer:sleep(?REKEY_DATA_TMO), + Kex1 = get_kex_init(ConnectionRef), + + Data = lists:duplicate(159000,1), + ok = ssh_sftp:write_file(SftpPid, DataFile, Data), + + timer:sleep(?REKEY_DATA_TMO), + Kex2 = get_kex_init(ConnectionRef), + + false = (Kex2 == Kex1), + + timer:sleep(?REKEY_DATA_TMO), + Kex2 = get_kex_init(ConnectionRef), + + ok = ssh_sftp:write_file(SftpPid, DataFile, "hi\n"), + + timer:sleep(?REKEY_DATA_TMO), + Kex2 = get_kex_init(ConnectionRef), + + false = (Kex2 == Kex1), + + timer:sleep(?REKEY_DATA_TMO), + Kex2 = get_kex_init(ConnectionRef), + + ssh_sftp:stop_channel(SftpPid), + ssh:close(ConnectionRef), + ssh:stop_daemon(Pid). + +%%-------------------------------------------------------------------- + +%%% Test rekeying with simulataneous send request + +renegotiate1(Config) -> + UserDir = ?config(priv_dir, Config), + DataFile = filename:join(UserDir, "renegotiate1.data"), + + Algs = ?config(preferred_algorithms, Config), + {Pid, Host, DPort} = ssh_test_lib:std_daemon(Config,[{max_random_length_padding,0}, + {preferred_algorithms,Algs}]), + + RPort = ssh_test_lib:inet_port(), + {ok,RelayPid} = ssh_relay:start_link({0,0,0,0}, RPort, Host, DPort), + + + ConnectionRef = ssh_test_lib:std_connect(Config, Host, RPort, [{max_random_length_padding,0}]), + {ok, SftpPid} = ssh_sftp:start_channel(ConnectionRef), + + Kex1 = get_kex_init(ConnectionRef), + + {ok, Handle} = ssh_sftp:open(SftpPid, DataFile, [write]), + + ok = ssh_sftp:write(SftpPid, Handle, "hi\n"), + + ssh_relay:hold(RelayPid, rx, 20, 1000), + ssh_connection_handler:renegotiate(ConnectionRef), + spawn(fun() -> ok=ssh_sftp:write(SftpPid, Handle, "another hi\n") end), + + timer:sleep(2000), + + Kex2 = get_kex_init(ConnectionRef), + + false = (Kex2 == Kex1), + + ssh_relay:stop(RelayPid), + ssh_sftp:stop_channel(SftpPid), + ssh:close(ConnectionRef), + ssh:stop_daemon(Pid). + +%%-------------------------------------------------------------------- + +%%% Test rekeying with inflight messages from peer + +renegotiate2(Config) -> + UserDir = ?config(priv_dir, Config), + DataFile = filename:join(UserDir, "renegotiate2.data"), + + Algs = ?config(preferred_algorithms, Config), + {Pid, Host, DPort} = ssh_test_lib:std_daemon(Config,[{max_random_length_padding,0}, + {preferred_algorithms,Algs}]), + + RPort = ssh_test_lib:inet_port(), + {ok,RelayPid} = ssh_relay:start_link({0,0,0,0}, RPort, Host, DPort), + + ConnectionRef = ssh_test_lib:std_connect(Config, Host, RPort, [{max_random_length_padding,0}]), + {ok, SftpPid} = ssh_sftp:start_channel(ConnectionRef), + + Kex1 = get_kex_init(ConnectionRef), + + {ok, Handle} = ssh_sftp:open(SftpPid, DataFile, [write]), + + ok = ssh_sftp:write(SftpPid, Handle, "hi\n"), + + ssh_relay:hold(RelayPid, rx, 20, infinity), + spawn(fun() -> ok=ssh_sftp:write(SftpPid, Handle, "another hi\n") end), + %% need a small pause here to ensure ssh_sftp:write is executed + ct:sleep(10), + ssh_connection_handler:renegotiate(ConnectionRef), + ssh_relay:release(RelayPid, rx), + + timer:sleep(2000), + + Kex2 = get_kex_init(ConnectionRef), + + false = (Kex2 == Kex1), + + ssh_relay:stop(RelayPid), + ssh_sftp:stop_channel(SftpPid), + ssh:close(ConnectionRef), + ssh:stop_daemon(Pid). + +%%-------------------------------------------------------------------- +%% Internal functions ------------------------------------------------ +%%-------------------------------------------------------------------- +%% get_kex_init - helper function to get key_exchange_init_msg +get_kex_init(Conn) -> + %% First, validate the key exchange is complete (StateName == connected) + {connected,S} = sys:get_state(Conn), + %% Next, walk through the elements of the #state record looking + %% for the #ssh_msg_kexinit record. This method is robust against + %% changes to either record. The KEXINIT message contains a cookie + %% unique to each invocation of the key exchange procedure (RFC4253) + SL = tuple_to_list(S), + case lists:keyfind(ssh_msg_kexinit, 1, SL) of + false -> + throw(not_found); + KexInit -> + KexInit + end. + diff --git a/lib/ssh/test/ssh_renegotiate_SUITE_data/id_dsa b/lib/ssh/test/ssh_renegotiate_SUITE_data/id_dsa new file mode 100644 index 0000000000..d306f8b26e --- /dev/null +++ b/lib/ssh/test/ssh_renegotiate_SUITE_data/id_dsa @@ -0,0 +1,13 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBvAIBAAKBgQDfi2flSTZZofwT4yQT0NikX/LGNT7UPeB/XEWe/xovEYCElfaQ +APFixXvEgXwoojmZ5kiQRKzLM39wBP0jPERLbnZXfOOD0PDnw0haMh7dD7XKVMod +/EigVgHf/qBdM2M8yz1s/rRF7n1UpLSypziKjkzCm7JoSQ2zbWIPdmBIXwIVAMgP +kpr7Sq3O7sHdb8D601DRjoExAoGAMOQxDfB2Fd8ouz6G96f/UOzRMI/Kdv8kYYKW +JIGY+pRYrLPyYzUeJznwZreOJgrczAX+luHnKFWJ2Dnk5CyeXk67Wsr7pJ/4MBMD +OKeIS0S8qoSBN8+Krp79fgA+yS3IfqbkJLtLu4EBaCX4mKQIX4++k44d4U5lc8pt ++9hlEI8CgYEAznKxx9kyC6bVo7LUYKaGhofRFt0SYFc5PVmT2VUGRs1R6+6DPD+e +uEO6IhFct7JFSRbP9p0JD4Uk+3zlZF+XX6b2PsZkeV8f/02xlNGUSmEzCSiNg1AX +Cy/WusYhul0MncWCHMcOZB5rIvU/aP5EJJtn3xrRaz6u0SThF6AnT34CFQC63czE +ZU8w8Q+H7z0j+a+70x2iAw== +-----END DSA PRIVATE KEY----- + diff --git a/lib/ssh/test/ssh_renegotiate_SUITE_data/id_rsa b/lib/ssh/test/ssh_renegotiate_SUITE_data/id_rsa new file mode 100644 index 0000000000..9d7e0dd5fb --- /dev/null +++ b/lib/ssh/test/ssh_renegotiate_SUITE_data/id_rsa @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQD1OET+3O/Bvj/dtjxDTXmj1oiJt4sIph5kGy0RfjoPrZfaS+CU +DhakCmS6t2ivxWFgtpKWaoGMZMJqWj6F6ZsumyFl3FPBtujwY/35cgifrI9Ns4Tl +zR1uuengNBmV+WRQ5cd9F2qS6Z8aDQihzt0r8JUqLcK+VQbrmNzboCCQQwIDAQAB +AoGAPQEyqPTt8JUT7mRXuaacjFXiweAXhp9NEDpyi9eLOjtFe9lElZCrsUOkq47V +TGUeRKEm9qSodfTbKPoqc8YaBJGJPhUaTAcha+7QcDdfHBvIsgxvU7ePVnlpXRp3 +CCUEMPhlnx6xBoTYP+fRU0e3+xJIPVyVCqX1jAdUMkzfRoECQQD6ux7B1QJAIWyK +SGkbDUbBilNmzCFNgIpOP6PA+bwfi5d16diTpra5AX09keQABAo/KaP1PdV8Vg0p +z4P3A7G3AkEA+l+AKG6m0kQTTBMJDqOdVPYwe+5GxunMaqmhokpEbuGsrZBl5Dvd +WpcBjR7jmenrhKZRIuA+Fz5HPo/UQJPl1QJBAKxstDkeED8j/S2XoFhPKAJ+6t39 +sUVICVTIZQeXdmzHJXCcUSkw8+WEhakqw/3SyW0oaK2FSWQJFWJUZ+8eJj8CQEh3 +xeduB5kKnS9CvzdeghZqX6QvVosSdtlUmfUYW/BgH5PpHKTP8wTaeld3XldZTpMJ +dKiMkUw2+XYROVUrubUCQD+Na1LhULlpn4ISEtIEfqpdlUhxDgO15Wg8USmsng+x +ICliVOSQtwaZjm8kwaFt0W7XnpnDxbRs37vIEbIMWak= +-----END RSA PRIVATE KEY----- diff --git a/lib/ssh/test/ssh_renegotiate_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_renegotiate_SUITE_data/ssh_host_dsa_key new file mode 100644 index 0000000000..51ab6fbd88 --- /dev/null +++ b/lib/ssh/test/ssh_renegotiate_SUITE_data/ssh_host_dsa_key @@ -0,0 +1,13 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBuwIBAAKBgQCClaHzE2ul0gKSUxah5W0W8UiJLy4hXngKEqpaUq9SSdVdY2LK +wVfKH1gt5iuaf1FfzOhsIC9G/GLnjYttXZc92cv/Gfe3gR+s0ni2++MX+T++mE/Q +diltXv/Hp27PybS67SmiFW7I+RWnT2OKlMPtw2oUuKeztCe5UWjaj/y5FQIVAPLA +l9RpiU30Z87NRAHY3NTRaqtrAoGANMRxw8UfdtNVR0CrQj3AgPaXOGE4d+G4Gp4X +skvnCHycSVAjtYxebUkzUzt5Q6f/IabuLUdge3gXrc8BetvrcKbp+XZgM0/Vj2CF +Ymmy3in6kzGZq7Fw1sZaku6AOU8vLa5woBT2vAcHLLT1bLAzj7viL048T6MfjrOP +ef8nHvACgYBhDWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah +/XcF3DeRF+eEoz48wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+U +ykSTXYUbtsfTNRFQGBW2/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0CgIVAN4wtL5W +Lv62jKcdskxNyz2NQoBx +-----END DSA PRIVATE KEY----- + diff --git a/lib/ssh/test/ssh_renegotiate_SUITE_data/ssh_host_dsa_key.pub b/lib/ssh/test/ssh_renegotiate_SUITE_data/ssh_host_dsa_key.pub new file mode 100644 index 0000000000..4dbb1305b0 --- /dev/null +++ b/lib/ssh/test/ssh_renegotiate_SUITE_data/ssh_host_dsa_key.pub @@ -0,0 +1,11 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +AAAAB3NzaC1kc3MAAACBAIKVofMTa6XSApJTFqHlbRbxSIkvLiFeeAoSqlpSr1JJ1V1j +YsrBV8ofWC3mK5p/UV/M6GwgL0b8YueNi21dlz3Zy/8Z97eBH6zSeLb74xf5P76YT9B2 +KW1e/8enbs/JtLrtKaIVbsj5FadPY4qUw+3DahS4p7O0J7lRaNqP/LkVAAAAFQDywJfU +aYlN9GfOzUQB2NzU0WqrawAAAIA0xHHDxR9201VHQKtCPcCA9pc4YTh34bganheyS+cI +fJxJUCO1jF5tSTNTO3lDp/8hpu4tR2B7eBetzwF62+twpun5dmAzT9WPYIViabLeKfqT +MZmrsXDWxlqS7oA5Ty8trnCgFPa8BwcstPVssDOPu+IvTjxPox+Os495/yce8AAAAIBh +DWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah/XcF3DeRF+eEoz48 +wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+UykSTXYUbtsfTNRFQGBW2 +/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0Cg== +---- END SSH2 PUBLIC KEY ---- diff --git a/lib/ssh/test/ssh_renegotiate_SUITE_data/ssh_host_rsa_key b/lib/ssh/test/ssh_renegotiate_SUITE_data/ssh_host_rsa_key new file mode 100644 index 0000000000..79968bdd7d --- /dev/null +++ b/lib/ssh/test/ssh_renegotiate_SUITE_data/ssh_host_rsa_key @@ -0,0 +1,16 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8semM4q843337 +zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RWRWzjaxSB +6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4QIDAQAB +AoGANmvJzJO5hkLuvyDZHKfAnGTtpifcR1wtSa9DjdKUyn8vhKF0mIimnbnYQEmW +NUUb3gXCZLi9PvkpRSVRrASDOZwcjoU/Kvww163vBUVb2cOZfFhyn6o2Sk88Tt++ +udH3hdjpf9i7jTtUkUe+QYPsia+wgvvrmn4QrahLAH86+kECQQDx5gFeXTME3cnW +WMpFz3PPumduzjqgqMMWEccX4FtQkMX/gyGa5UC7OHFyh0N/gSWvPbRHa8A6YgIt +n8DO+fh5AkEAzbqX4DOn8NY6xJIi42q7l/2jIA0RkB6P7YugW5NblhqBZ0XDnpA5 +sMt+rz+K07u9XZtxgh1xi7mNfwY6lEAMqQJBAJBEauCKmRj35Z6OyeQku59SPsnY ++SJEREVvSNw2lH9SOKQQ4wPsYlTGbvKtNVZgAcen91L5MmYfeckYE/fdIZECQQCt +64zxsTnM1I8iFxj/gP/OYlJBikrKt8udWmjaghzvLMEw+T2DExJyb9ZNeT53+UMB +m6O+B/4xzU/djvp+0hbhAkAemIt+rA5kTmYlFndhpvzkSSM8a2EXsO4XIPgGWCTT +tQKS/tTly0ADMjN/TVy11+9d6zcqadNVuHXHGtR4W0GR +-----END RSA PRIVATE KEY----- + diff --git a/lib/ssh/test/ssh_renegotiate_SUITE_data/ssh_host_rsa_key.pub b/lib/ssh/test/ssh_renegotiate_SUITE_data/ssh_host_rsa_key.pub new file mode 100644 index 0000000000..75d2025c71 --- /dev/null +++ b/lib/ssh/test/ssh_renegotiate_SUITE_data/ssh_host_rsa_key.pub @@ -0,0 +1,5 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +AAAAB3NzaC1yc2EAAAADAQABAAAAgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8 +semM4q843337zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RW +RWzjaxSB6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4Q== +---- END SSH2 PUBLIC KEY ---- diff --git a/lib/ssh/test/ssh_sftp_SUITE.erl b/lib/ssh/test/ssh_sftp_SUITE.erl index c19ede296f..c2b04d7a05 100644 --- a/lib/ssh/test/ssh_sftp_SUITE.erl +++ b/lib/ssh/test/ssh_sftp_SUITE.erl @@ -27,100 +27,166 @@ -include_lib("common_test/include/ct.hrl"). -include_lib("kernel/include/file.hrl"). -% Default timetrap timeout + % Default timetrap timeout -define(default_timeout, ?t:minutes(1)). --define(USER, "Alladin"). --define(PASSWD, "Sesame"). - --define(tar_file_name, "sftp_tar_test.tar"). - %%-------------------------------------------------------------------- %% Common Test interface functions ----------------------------------- %%-------------------------------------------------------------------- suite() -> - [{ct_hooks,[ts_install_cth]}]. + [{ct_hooks,[ts_install_cth]}, + {timetrap,{minutes,2}}]. + all() -> - [{group, erlang_server}, - {group, openssh_server}, - sftp_nonexistent_subsystem + [{group, not_unicode}, + {group, unicode} ]. init_per_suite(Config) -> - catch crypto:stop(), - case (catch crypto:start()) of - ok -> - ssh:start(), - Config; - _ -> - {skip,"Could not start crypto!"} - end. - -end_per_suite(Config) -> - ssh:stop(), - crypto:stop(), + ct:log("file:native_name_encoding() = ~p,~nio:getopts() = ~p", + [file:native_name_encoding(),io:getopts()]), + ssh:start(), Config. +end_per_suite(_onfig) -> + ssh:stop(). + %%-------------------------------------------------------------------- groups() -> - [{erlang_server, [], [open_close_file, open_close_dir, read_file, read_dir, - write_file, write_big_file, sftp_read_big_file, - rename_file, mk_rm_dir, remove_file, links, - retrieve_attributes, set_attributes, async_read, - async_write, position, pos_read, pos_write, version_option, + [{not_unicode, [], [{group,erlang_server}, + {group,openssh_server}, + sftp_nonexistent_subsystem]}, + + {unicode, [], [{group,erlang_server}, + {group,openssh_server}, + sftp_nonexistent_subsystem]}, + + {erlang_server, [], [{group,write_read_tests}, + version_option, {group,remote_tar}]}, - {openssh_server, [], [open_close_file, open_close_dir, read_file, read_dir, - write_file, write_big_file, sftp_read_big_file, - rename_file, mk_rm_dir, remove_file, links, - retrieve_attributes, set_attributes, async_read, - async_write, position, pos_read, pos_write, + {openssh_server, [], [{group,write_read_tests}, {group,remote_tar}]}, - {remote_tar, [], [create_empty_tar, files_to_tar, big_file_to_tar, files_chunked_to_tar, + {remote_tar, [], [create_empty_tar, + ascii_filename_ascii_contents_to_tar, + ascii_filename_unicode_contents_to_tar, + unicode_filename_ascii_contents_to_tar, + files_to_tar, + big_file_to_tar, files_chunked_to_tar, directory_to_tar, binaries_to_tar, null_crypto_tar, simple_crypto_tar_small, simple_crypto_tar_big, read_tar, read_null_crypto_tar, read_crypto_tar, aes_cbc256_crypto_tar, aes_ctr_stream_crypto_tar - ]} + ]}, + + {write_read_tests, [], [open_close_file, open_close_dir, read_file, read_dir, + write_file, write_file_iolist, write_big_file, sftp_read_big_file, + rename_file, mk_rm_dir, remove_file, links, + retrieve_attributes, set_attributes, async_read, + async_write, position, pos_read, pos_write + ]} ]. - + +init_per_group(not_unicode, Config) -> + ct:comment("Begin ~p",[grps(Config)]), + DataDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + [{user, "Alladin"}, + {passwd, "Sesame"}, + {data, <<"Hello world!">>}, + {filename, filename:join(PrivDir, "sftp.txt")}, + {testfile, filename:join(PrivDir, "test.txt")}, + {linktest, filename:join(PrivDir, "link_test.txt")}, + {tar_filename, filename:join(PrivDir, "sftp_tar_test.tar")}, + {tar_F1_txt, "f1.txt"}, + {datadir_tar, filename:join(DataDir,"sftp_tar_test_data")} + | Config]; + +init_per_group(unicode, Config) -> + case file:native_name_encoding() of + utf8 -> + ct:comment("Begin ~p",[grps(Config)]), + DataDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + NewConfig = + [{user, "åke高兴"}, + {passwd, "ärlig日本じん"}, + {data, <<"foobar å 一二三四いちにさんち">>}, + {filename, filename:join(PrivDir, "sftp瑞点.txt")}, + {testfile, filename:join(PrivDir, "testハンス.txt")}, + {linktest, filename:join(PrivDir, "link_test語.txt")}, + {tar_filename, filename:join(PrivDir, "sftp_tar_test一二三.tar")}, + {tar_F1_txt, "F一.txt"}, + {tar_F3_txt, "f3.txt"}, + {tar_F4_txt, "g四.txt"}, + {datadir_tar, filename:join(DataDir,"sftp_tar_test_data_高兴")} + | lists:foldl(fun(K,Cf) -> lists:keydelete(K,1,Cf) end, + Config, + [user, passwd, data, + filename, testfile, linktest, + tar_filename, tar_F1_txt, datadir_tar + ] + ) + ], + FN = fn(?config(tar_F1_txt,NewConfig), NewConfig), + case catch file:read_file(FN) of + {ok,FN_contents} -> + ct:log("Readable file:read_file(~tp) ->~n~tp",[FN,FN_contents]), + NewConfig; + Other -> + ct:log("Unreadable file:read_file(~tp) ->~n~p",[FN,Other]), + {skip, "Not unicode file reading"} + end; + + _ -> + {skip, "Not unicode file encoding"} + end; init_per_group(erlang_server, Config) -> + ct:comment("Begin ~p",[grps(Config)]), PrivDir = ?config(priv_dir, Config), SysDir = ?config(data_dir, Config), + User = ?config(user, Config), + Passwd = ?config(passwd, Config), Sftpd = {_, HostX, PortX} = ssh_test_lib:daemon([{system_dir, SysDir}, {user_dir, PrivDir}, {user_passwords, - [{?USER, ?PASSWD}]}]), + [{User, Passwd}]}]), [{peer, {fmt_host(HostX),PortX}}, {group, erlang_server}, {sftpd, Sftpd} | Config]; init_per_group(openssh_server, Config) -> + ct:comment("Begin ~p",[grps(Config)]), Host = ssh_test_lib:hostname(), - case (catch ssh_sftp:start_channel(Host, + case (catch ssh_sftp:start_channel(Host, [{user_interaction, false}, {silently_accept_hosts, true}])) of {ok, _ChannelPid, Connection} -> [{peer, {_HostName,{IPx,Portx}}}] = ssh:connection_info(Connection,[peer]), ssh:close(Connection), [{peer, {fmt_host(IPx),Portx}}, {group, openssh_server} | Config]; + {error,"Key exchange failed"} -> + {skip, "openssh server doesn't support the tested kex algorithm"}; _ -> {skip, "No openssh server"} end; init_per_group(remote_tar, Config) -> + ct:comment("Begin ~p",[grps(Config)]), {Host,Port} = ?config(peer, Config), ct:log("Server (~p) at ~p:~p",[?config(group,Config),Host,Port]), + User = ?config(user, Config), + Passwd = ?config(passwd, Config), {ok, Connection} = case ?config(group, Config) of erlang_server -> ssh:connect(Host, Port, - [{user, ?USER}, - {password, ?PASSWD}, + [{user, User}, + {password, Passwd}, {user_interaction, false}, {silently_accept_hosts, true}]); openssh_server -> @@ -129,11 +195,23 @@ init_per_group(remote_tar, Config) -> {silently_accept_hosts, true}]) end, [{remote_tar, true}, - {connection, Connection} | Config]. + {connection, Connection} | Config]; + +init_per_group(write_read_tests, Config) -> + ct:comment("Begin ~p",[grps(Config)]), + Config. + +grps(Config) -> + proplists:get_all_values( + name, + lists:flatten([proplists:get_value(tc_group_properties,Config,[]), + proplists:get_value(tc_group_path,Config,[])])). end_per_group(erlang_server, Config) -> + ct:comment("End ~p",[grps(Config)]), Config; end_per_group(_, Config) -> + ct:comment("End ~p",[grps(Config)]), Config. %%-------------------------------------------------------------------- @@ -141,11 +219,13 @@ end_per_group(_, Config) -> init_per_testcase(sftp_nonexistent_subsystem, Config) -> PrivDir = ?config(priv_dir, Config), SysDir = ?config(data_dir, Config), + User = ?config(user, Config), + Passwd = ?config(passwd, Config), Sftpd = ssh_test_lib:daemon([{system_dir, SysDir}, {user_dir, PrivDir}, {subsystems, []}, {user_passwords, - [{?USER, ?PASSWD}]} + [{User, Passwd}]} ]), [{sftpd, Sftpd} | Config]; @@ -155,11 +235,13 @@ init_per_testcase(version_option, Config) -> TmpConfig = lists:keydelete(sftp, 1, TmpConfig0), Dog = ct:timetrap(?default_timeout), {_,Host, Port} = ?config(sftpd, Config), + User = ?config(user, Config), + Passwd = ?config(passwd, Config), {ok, ChannelPid, Connection} = ssh_sftp:start_channel(Host, Port, [{sftp_vsn, 3}, - {user, ?USER}, - {password, ?PASSWD}, + {user, User}, + {password, Passwd}, {user_interaction, false}, {silently_accept_hosts, true}]), Sftp = {ChannelPid, Connection}, @@ -169,7 +251,9 @@ init_per_testcase(Case, Config0) -> prep(Config0), Config1 = lists:keydelete(watchdog, 1, Config0), Config2 = lists:keydelete(sftp, 1, Config1), - Dog = ct:timetrap(?default_timeout), + Dog = ct:timetrap(2 * ?default_timeout), + User = ?config(user, Config0), + Passwd = ?config(passwd, Config0), Config = case ?config(group,Config2) of @@ -177,10 +261,11 @@ init_per_testcase(Case, Config0) -> {_,Host, Port} = ?config(sftpd, Config2), {ok, ChannelPid, Connection} = ssh_sftp:start_channel(Host, Port, - [{user, ?USER}, - {password, ?PASSWD}, + [{user, User}, + {password, Passwd}, {user_interaction, false}, - {silently_accept_hosts, true}]), + {silently_accept_hosts, true}] + ), Sftp = {ChannelPid, Connection}, [{sftp, Sftp}, {watchdog, Dog} | Config2]; openssh_server when Case == links -> @@ -208,8 +293,7 @@ init_per_testcase(Case, Config0) -> end_per_testcase(sftp_nonexistent_subsystem, Config) -> Config; end_per_testcase(rename_file, Config) -> - PrivDir = ?config(priv_dir, Config), - NewFileName = filename:join(PrivDir, "test.txt"), + NewFileName = ?config(testfile, Config), file:delete(NewFileName), end_per_testcase(Config); end_per_testcase(_, Config) -> @@ -227,8 +311,7 @@ end_per_testcase(Config) -> open_close_file() -> [{doc, "Test API functions open/3 and close/2"}]. open_close_file(Config) when is_list(Config) -> - PrivDir = ?config(priv_dir, Config), - FileName = filename:join(PrivDir, "sftp.txt"), + FileName = ?config(filename, Config), {Sftp, _} = ?config(sftp, Config), @@ -249,7 +332,7 @@ open_close_dir() -> open_close_dir(Config) when is_list(Config) -> PrivDir = ?config(priv_dir, Config), {Sftp, _} = ?config(sftp, Config), - FileName = filename:join(PrivDir, "sftp.txt"), + FileName = ?config(filename, Config), {ok, Handle} = ssh_sftp:opendir(Sftp, PrivDir), ok = ssh_sftp:close(Sftp, Handle), @@ -259,8 +342,7 @@ open_close_dir(Config) when is_list(Config) -> read_file() -> [{doc, "Test API funtion read_file/2"}]. read_file(Config) when is_list(Config) -> - PrivDir = ?config(priv_dir, Config), - FileName = filename:join(PrivDir, "sftp.txt"), + FileName = ?config(filename, Config), {Sftp, _} = ?config(sftp, Config), {ok, Data} = ssh_sftp:read_file(Sftp, FileName), {ok, Data} = ssh_sftp:read_file(Sftp, FileName), @@ -273,14 +355,13 @@ read_dir(Config) when is_list(Config) -> PrivDir = ?config(priv_dir, Config), {Sftp, _} = ?config(sftp, Config), {ok, Files} = ssh_sftp:list_dir(Sftp, PrivDir), - ct:pal("sftp list dir: ~p~n", [Files]). + ct:log("sftp list dir: ~p~n", [Files]). %%-------------------------------------------------------------------- write_file() -> [{doc, "Test API function write_file/2"}]. write_file(Config) when is_list(Config) -> - PrivDir = ?config(priv_dir, Config), - FileName = filename:join(PrivDir, "sftp.txt"), + FileName = ?config(filename, Config), {Sftp, _} = ?config(sftp, Config), Data = list_to_binary("Hej hopp!"), @@ -288,11 +369,31 @@ write_file(Config) when is_list(Config) -> {ok, Data} = file:read_file(FileName). %%-------------------------------------------------------------------- +write_file_iolist() -> + [{doc, "Test API function write_file/2 with iolists"}]. +write_file_iolist(Config) when is_list(Config) -> + FileName = ?config(filename, Config), + {Sftp, _} = ?config(sftp, Config), + + Data = list_to_binary("Hej hopp!"), + lists:foreach( + fun(D) -> + ssh_sftp:write_file(Sftp, FileName, [D]), + Expected = if is_binary(D) -> D; + is_list(D) -> list_to_binary(D) + end, + {ok, Expected} = file:read_file(FileName) + end, + [Data, [Data,Data], [[Data],[Data]], [[[Data]],[[[[Data]],Data]]], + [[[[Data]],Data],binary_to_list(Data)], + [[[[Data]],Data],[[binary_to_list(Data)],[[binary_to_list(Data)]]]] + ]). + +%%-------------------------------------------------------------------- write_big_file() -> [{doc, "Test API function write_file/2 with big data"}]. write_big_file(Config) when is_list(Config) -> - PrivDir = ?config(priv_dir, Config), - FileName = filename:join(PrivDir, "sftp.txt"), + FileName = ?config(filename, Config), {Sftp, _} = ?config(sftp, Config), Data = list_to_binary(lists:duplicate(750000,"a")), @@ -303,8 +404,7 @@ write_big_file(Config) when is_list(Config) -> sftp_read_big_file() -> [{doc, "Test API function read_file/2 with big data"}]. sftp_read_big_file(Config) when is_list(Config) -> - PrivDir = ?config(priv_dir, Config), - FileName = filename:join(PrivDir, "sftp.txt"), + FileName = ?config(filename, Config), {Sftp, _} = ?config(sftp, Config), Data = list_to_binary(lists:duplicate(750000,"a")), @@ -317,7 +417,7 @@ remove_file() -> [{doc,"Test API function delete/2"}]. remove_file(Config) when is_list(Config) -> PrivDir = ?config(priv_dir, Config), - FileName = filename:join(PrivDir, "sftp.txt"), + FileName = ?config(filename, Config), {Sftp, _} = ?config(sftp, Config), {ok, Files} = ssh_sftp:list_dir(Sftp, PrivDir), @@ -331,17 +431,17 @@ rename_file() -> [{doc, "Test API function rename_file/2"}]. rename_file(Config) when is_list(Config) -> PrivDir = ?config(priv_dir, Config), - FileName = filename:join(PrivDir, "sftp.txt"), - NewFileName = filename:join(PrivDir, "test.txt"), + FileName = ?config(filename, Config), + NewFileName = ?config(testfile, Config), {Sftp, _} = ?config(sftp, Config), {ok, Files} = ssh_sftp:list_dir(Sftp, PrivDir), - ct:pal("FileName: ~p, Files: ~p~n", [FileName, Files]), + ct:log("FileName: ~p, Files: ~p~n", [FileName, Files]), true = lists:member(filename:basename(FileName), Files), false = lists:member(filename:basename(NewFileName), Files), ok = ssh_sftp:rename(Sftp, FileName, NewFileName), {ok, NewFiles} = ssh_sftp:list_dir(Sftp, PrivDir), - ct:pal("FileName: ~p, Files: ~p~n", [FileName, NewFiles]), + ct:log("FileName: ~p, Files: ~p~n", [FileName, NewFiles]), false = lists:member(filename:basename(FileName), NewFiles), true = lists:member(filename:basename(NewFileName), NewFiles). @@ -352,7 +452,7 @@ mk_rm_dir() -> mk_rm_dir(Config) when is_list(Config) -> PrivDir = ?config(priv_dir, Config), {Sftp, _} = ?config(sftp, Config), - + DirName = filename:join(PrivDir, "test"), ok = ssh_sftp:make_dir(Sftp, DirName), ok = ssh_sftp:del_dir(Sftp, DirName), @@ -369,9 +469,8 @@ links(Config) when is_list(Config) -> {skip, "Links are not fully supported by windows"}; _ -> {Sftp, _} = ?config(sftp, Config), - PrivDir = ?config(priv_dir, Config), - FileName = filename:join(PrivDir, "sftp.txt"), - LinkFileName = filename:join(PrivDir, "link_test.txt"), + FileName = ?config(filename, Config), + LinkFileName = ?config(linktest, Config), ok = ssh_sftp:make_symlink(Sftp, LinkFileName, FileName), {ok, FileName} = ssh_sftp:read_link(Sftp, LinkFileName) @@ -381,22 +480,20 @@ links(Config) when is_list(Config) -> retrieve_attributes() -> [{doc, "Test API function read_file_info/3"}]. retrieve_attributes(Config) when is_list(Config) -> - PrivDir = ?config(priv_dir, Config), - FileName = filename:join(PrivDir, "sftp.txt"), + FileName = ?config(filename, Config), {Sftp, _} = ?config(sftp, Config), {ok, FileInfo} = ssh_sftp:read_file_info(Sftp, FileName), {ok, NewFileInfo} = file:read_file_info(FileName), %% TODO comparison. There are some differences now is that ok? - ct:pal("SFTP: ~p FILE: ~p~n", [FileInfo, NewFileInfo]). + ct:log("SFTP: ~p FILE: ~p~n", [FileInfo, NewFileInfo]). %%-------------------------------------------------------------------- set_attributes() -> [{doc,"Test API function write_file_info/3"}]. set_attributes(Config) when is_list(Config) -> - PrivDir = ?config(priv_dir, Config), - FileName = filename:join(PrivDir, "test.txt"), + FileName = ?config(testfile, Config), {Sftp, _} = ?config(sftp, Config), {ok,Fd} = file:open(FileName, write), @@ -412,26 +509,26 @@ async_read() -> [{doc,"Test API aread/3"}]. async_read(Config) when is_list(Config) -> {Sftp, _} = ?config(sftp, Config), - PrivDir = ?config(priv_dir, Config), - FileName = filename:join(PrivDir, "sftp.txt"), + FileName = ?config(filename, Config), {ok, Handle} = ssh_sftp:open(Sftp, FileName, [read]), {async, Ref} = ssh_sftp:aread(Sftp, Handle, 20), receive {async_reply, Ref, {ok, Data}} -> - ct:pal("Data: ~p~n", [Data]), + ct:log("Data: ~p~n", [Data]), ok; Msg -> ct:fail(Msg) + after + 30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end. %%-------------------------------------------------------------------- async_write() -> [{doc,"Test API awrite/3"}]. async_write(Config) when is_list(Config) -> {Sftp, _} = ?config(sftp, Config), - PrivDir = ?config(priv_dir, Config), - FileName = filename:join(PrivDir, "test.txt"), + FileName = ?config(testfile, Config), {ok, Handle} = ssh_sftp:open(Sftp, FileName, [write]), Data = list_to_binary("foobar"), {async, Ref} = ssh_sftp:awrite(Sftp, Handle, Data), @@ -448,8 +545,7 @@ async_write(Config) when is_list(Config) -> position() -> [{doc, "Test API functions position/3"}]. position(Config) when is_list(Config) -> - PrivDir = ?config(priv_dir, Config), - FileName = filename:join(PrivDir, "test.txt"), + FileName = ?config(testfile, Config), {Sftp, _} = ?config(sftp, Config), Data = list_to_binary("1234567890"), @@ -478,8 +574,7 @@ position(Config) when is_list(Config) -> pos_read() -> [{doc,"Test API functions pread/3 and apread/3"}]. pos_read(Config) when is_list(Config) -> - PrivDir = ?config(priv_dir, Config), - FileName = filename:join(PrivDir, "test.txt"), + FileName = ?config(testfile, Config), {Sftp, _} = ?config(sftp, Config), Data = list_to_binary("Hej hopp!"), ssh_sftp:write_file(Sftp, FileName, [Data]), @@ -494,6 +589,8 @@ pos_read(Config) when is_list(Config) -> ok; Msg -> ct:fail(Msg) + after + 30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end, NewData1 = "hopp", @@ -504,8 +601,7 @@ pos_read(Config) when is_list(Config) -> pos_write() -> [{doc,"Test API functions pwrite/4 and apwrite/4"}]. pos_write(Config) when is_list(Config) -> - PrivDir = ?config(priv_dir, Config), - FileName = filename:join(PrivDir, "test.txt"), + FileName = ?config(testfile, Config), {Sftp, _} = ?config(sftp, Config), {ok, Handle} = ssh_sftp:open(Sftp, FileName, [write]), @@ -520,6 +616,8 @@ pos_write(Config) when is_list(Config) -> ok; Msg -> ct:fail(Msg) + after + 30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end, ok = ssh_sftp:pwrite(Sftp, Handle, eof, list_to_binary("!")), @@ -532,10 +630,13 @@ sftp_nonexistent_subsystem() -> [{doc, "Try to execute sftp subsystem on a server that does not support it"}]. sftp_nonexistent_subsystem(Config) when is_list(Config) -> {_,Host, Port} = ?config(sftpd, Config), + User = ?config(user, Config), + Passwd = ?config(passwd, Config), {error,"server failed to start sftp subsystem"} = ssh_sftp:start_channel(Host, Port, [{user_interaction, false}, - {user, ?USER}, {password, ?PASSWD}, + {user, User}, + {password, Passwd}, {silently_accept_hosts, true}]). %%-------------------------------------------------------------------- @@ -547,25 +648,66 @@ version_option(Config) when is_list(Config) -> %%-------------------------------------------------------------------- create_empty_tar(Config) -> ChPid2 = ?config(channel_pid2, Config), - {ok,Handle} = ssh_sftp:open_tar(ChPid2, fnp(?tar_file_name,Config), [write]), + TarFileName = ?config(tar_filename, Config), + {ok,Handle} = ssh_sftp:open_tar(ChPid2, TarFileName, [write]), erl_tar:close(Handle), {ChPid,_} = ?config(sftp,Config), {ok, #file_info{type=regular}} = - ssh_sftp:read_file_info(ChPid,fnp(?tar_file_name,Config)). + ssh_sftp:read_file_info(ChPid, TarFileName). %%-------------------------------------------------------------------- files_to_tar(Config) -> ChPid2 = ?config(channel_pid2, Config), - {ok,Handle} = ssh_sftp:open_tar(ChPid2, fnp(?tar_file_name,Config), [write]), - ok = erl_tar:add(Handle, fn("f1.txt",Config), "f1.txt", [verbose]), + TarFileName = ?config(tar_filename, Config), + {ok,Handle} = ssh_sftp:open_tar(ChPid2, TarFileName, [write]), + F1 = ?config(tar_F1_txt, Config), + ok = erl_tar:add(Handle, fn(F1,Config), F1, [verbose]), ok = erl_tar:add(Handle, fn("f2.txt",Config), "f2.txt", [verbose]), ok = erl_tar:close(Handle), - chk_tar(["f1.txt", "f2.txt"], Config). + chk_tar([F1, "f2.txt"], Config). + +%%-------------------------------------------------------------------- +ascii_filename_ascii_contents_to_tar(Config) -> + ChPid2 = ?config(channel_pid2, Config), + TarFileName = ?config(tar_filename, Config), + {ok,Handle} = ssh_sftp:open_tar(ChPid2, TarFileName, [write]), + ok = erl_tar:add(Handle, fn("f2.txt",Config), "f2.txt", [verbose]), + ok = erl_tar:close(Handle), + chk_tar(["f2.txt"], Config). + +%%-------------------------------------------------------------------- +ascii_filename_unicode_contents_to_tar(Config) -> + case ?config(tar_F3_txt, Config) of + undefined -> + {skip, "Unicode test"}; + Fn -> + ChPid2 = ?config(channel_pid2, Config), + TarFileName = ?config(tar_filename, Config), + {ok,Handle} = ssh_sftp:open_tar(ChPid2, TarFileName, [write]), + ok = erl_tar:add(Handle, fn(Fn,Config), Fn, [verbose]), + ok = erl_tar:close(Handle), + chk_tar([Fn], Config) + end. + +%%-------------------------------------------------------------------- +unicode_filename_ascii_contents_to_tar(Config) -> + case ?config(tar_F4_txt, Config) of + undefined -> + {skip, "Unicode test"}; + Fn -> + ChPid2 = ?config(channel_pid2, Config), + TarFileName = ?config(tar_filename, Config), + {ok,Handle} = ssh_sftp:open_tar(ChPid2, TarFileName, [write]), + ok = erl_tar:add(Handle, fn(Fn,Config), Fn, [verbose]), + ok = erl_tar:close(Handle), + chk_tar([Fn], Config) + end. %%-------------------------------------------------------------------- big_file_to_tar(Config) -> ChPid2 = ?config(channel_pid2, Config), - {ok,Handle} = ssh_sftp:open_tar(ChPid2, fnp(?tar_file_name,Config), [write]), + TarFileName = ?config(tar_filename, Config), + {ok,Handle} = ssh_sftp:open_tar(ChPid2, TarFileName, [write]), ok = erl_tar:add(Handle, fn("big.txt",Config), "big.txt", [verbose]), ok = erl_tar:close(Handle), chk_tar(["big.txt"], Config). @@ -574,23 +716,27 @@ big_file_to_tar(Config) -> %%-------------------------------------------------------------------- files_chunked_to_tar(Config) -> ChPid2 = ?config(channel_pid2, Config), - {ok,Handle} = ssh_sftp:open_tar(ChPid2, fnp(?tar_file_name,Config), [write]), - ok = erl_tar:add(Handle, fn("f1.txt",Config), "f1.txt", [verbose,{chunks,2}]), + TarFileName = ?config(tar_filename, Config), + {ok,Handle} = ssh_sftp:open_tar(ChPid2, TarFileName, [write]), + F1 = ?config(tar_F1_txt, Config), + ok = erl_tar:add(Handle, fn(F1,Config), F1, [verbose,{chunks,2}]), ok = erl_tar:close(Handle), - chk_tar(["f1.txt"], Config). + chk_tar([F1], Config). %%-------------------------------------------------------------------- directory_to_tar(Config) -> ChPid2 = ?config(channel_pid2, Config), - {ok,Handle} = ssh_sftp:open_tar(ChPid2, fnp(?tar_file_name,Config), [write]), + TarFileName = ?config(tar_filename, Config), + {ok,Handle} = ssh_sftp:open_tar(ChPid2, TarFileName, [write]), ok = erl_tar:add(Handle, fn("d1",Config), "d1", [verbose]), ok = erl_tar:close(Handle), chk_tar(["d1"], Config). - + %%-------------------------------------------------------------------- binaries_to_tar(Config) -> ChPid2 = ?config(channel_pid2, Config), - {ok,Handle} = ssh_sftp:open_tar(ChPid2, fnp(?tar_file_name,Config), [write]), + TarFileName = ?config(tar_filename, Config), + {ok,Handle} = ssh_sftp:open_tar(ChPid2, TarFileName, [write]), Bin = <<"A binary">>, ok = erl_tar:add(Handle, Bin, "b1", [verbose]), ok = erl_tar:close(Handle), @@ -603,13 +749,15 @@ null_crypto_tar(Config) -> Cenc = fun(Bin,CState) -> {ok,Bin,CState,_SendSize=5} end, Cend = fun(Bin,_CState) -> {ok,Bin} end, C = {Cinit,Cenc,Cend}, - {ok,Handle} = ssh_sftp:open_tar(ChPid2, fnp(?tar_file_name,Config), [write,{crypto,C}]), + TarFileName = ?config(tar_filename, Config), + {ok,Handle} = ssh_sftp:open_tar(ChPid2, TarFileName, [write,{crypto,C}]), Bin = <<"A binary">>, + F1 = ?config(tar_F1_txt, Config), ok = erl_tar:add(Handle, Bin, "b1", [verbose]), - ok = erl_tar:add(Handle, fn("f1.txt",Config), "f1.txt", [verbose,{chunks,2}]), + ok = erl_tar:add(Handle, fn(F1,Config), F1, [verbose,{chunks,2}]), ok = erl_tar:add(Handle, fn("big.txt",Config), "big.txt", [verbose,{chunks,15000}]), ok = erl_tar:close(Handle), - chk_tar([{"b1",Bin}, "f1.txt", "big.txt"], Config). + chk_tar([{"b1",Bin}, F1, "big.txt"], Config). %%-------------------------------------------------------------------- simple_crypto_tar_small(Config) -> @@ -619,12 +767,14 @@ simple_crypto_tar_small(Config) -> Cdec = fun(Bin,CState) -> {ok,unstuff(Bin),CState,_Size=4} end, Cend = fun(Bin,_CState) -> {ok,stuff(Bin)} end, C = {Cinit,Cenc,Cend}, - {ok,Handle} = ssh_sftp:open_tar(ChPid2, fnp(?tar_file_name,Config), [write,{crypto,C}]), + TarFileName = ?config(tar_filename, Config), + {ok,Handle} = ssh_sftp:open_tar(ChPid2, TarFileName, [write,{crypto,C}]), Bin = <<"A binary">>, + F1 = ?config(tar_F1_txt, Config), ok = erl_tar:add(Handle, Bin, "b1", [verbose]), - ok = erl_tar:add(Handle, fn("f1.txt",Config), "f1.txt", [verbose,{chunks,2}]), + ok = erl_tar:add(Handle, fn(F1,Config), F1, [verbose,{chunks,2}]), ok = erl_tar:close(Handle), - chk_tar([{"b1",Bin}, "f1.txt"], Config, [{crypto,{Cinit,Cdec}}]). + chk_tar([{"b1",Bin}, F1], Config, [{crypto,{Cinit,Cdec}}]). %%-------------------------------------------------------------------- simple_crypto_tar_big(Config) -> @@ -634,18 +784,20 @@ simple_crypto_tar_big(Config) -> Cdec = fun(Bin,CState) -> {ok,unstuff(Bin),CState,_SendSize=4} end, Cend = fun(Bin,_CState) -> {ok,stuff(Bin)} end, C = {Cinit,Cenc,Cend}, - {ok,Handle} = ssh_sftp:open_tar(ChPid2, fnp(?tar_file_name,Config), [write,{crypto,C}]), + TarFileName = ?config(tar_filename, Config), + {ok,Handle} = ssh_sftp:open_tar(ChPid2, TarFileName, [write,{crypto,C}]), Bin = <<"A binary">>, + F1 = ?config(tar_F1_txt, Config), ok = erl_tar:add(Handle, Bin, "b1", [verbose]), - ok = erl_tar:add(Handle, fn("f1.txt",Config), "f1.txt", [verbose,{chunks,2}]), + ok = erl_tar:add(Handle, fn(F1,Config), F1, [verbose,{chunks,2}]), ok = erl_tar:add(Handle, fn("big.txt",Config), "big.txt", [verbose,{chunks,15000}]), ok = erl_tar:close(Handle), - chk_tar([{"b1",Bin}, "f1.txt", "big.txt"], Config, [{crypto,{Cinit,Cdec}}]). + chk_tar([{"b1",Bin}, F1, "big.txt"], Config, [{crypto,{Cinit,Cdec}}]). stuff(Bin) -> << <<C,C>> || <<C>> <= Bin >>. - + unstuff(Bin) -> << <<C>> || <<C,C>> <= Bin >>. - + %%-------------------------------------------------------------------- read_tar(Config) -> ChPid2 = ?config(channel_pid2, Config), @@ -653,7 +805,8 @@ read_tar(Config) -> [{"b1",<<"A binary">>}, {"b2",list_to_binary(lists:duplicate(750000,"a"))} ]), - {ok,HandleWrite} = ssh_sftp:open_tar(ChPid2, fnp(?tar_file_name,Config), [write]), + TarFileName = ?config(tar_filename, Config), + {ok,HandleWrite} = ssh_sftp:open_tar(ChPid2, TarFileName, [write]), [ok = erl_tar:add(HandleWrite, Bin, Name, [verbose]) || {Name,Bin} <- NameBins], ok = erl_tar:close(HandleWrite), @@ -675,7 +828,8 @@ read_null_crypto_tar(Config) -> Cw = {Cinitw,Cenc,Cendw}, Cr = {Cinitr,Cdec}, - {ok,HandleWrite} = ssh_sftp:open_tar(ChPid2, fnp(?tar_file_name,Config), [write,{crypto,Cw}]), + TarFileName = ?config(tar_filename, Config), + {ok,HandleWrite} = ssh_sftp:open_tar(ChPid2, TarFileName, [write,{crypto,Cw}]), [ok = erl_tar:add(HandleWrite, Bin, Name, [verbose]) || {Name,Bin} <- NameBins], ok = erl_tar:close(HandleWrite), @@ -698,7 +852,8 @@ read_crypto_tar(Config) -> Cw = {Cinitw,Cenc,Cendw}, Cr = {Cinitr,Cdec}, - {ok,HandleWrite} = ssh_sftp:open_tar(ChPid2, fnp(?tar_file_name,Config), [write,{crypto,Cw}]), + TarFileName = ?config(tar_filename, Config), + {ok,HandleWrite} = ssh_sftp:open_tar(ChPid2, TarFileName, [write,{crypto,Cw}]), [ok = erl_tar:add(HandleWrite, Bin, Name, [verbose]) || {Name,Bin} <- NameBins], ok = erl_tar:close(HandleWrite), @@ -737,7 +892,8 @@ aes_cbc256_crypto_tar(Config) -> end, Cw = {Cinitw,Cenc,Cendw}, - {ok,HandleWrite} = ssh_sftp:open_tar(ChPid2, fnp(?tar_file_name,Config), [write,{crypto,Cw}]), + TarFileName = ?config(tar_filename, Config), + {ok,HandleWrite} = ssh_sftp:open_tar(ChPid2, TarFileName, [write,{crypto,Cw}]), [ok = erl_tar:add(HandleWrite, Bin, Name, [verbose]) || {Name,Bin} <- NameBins], ok = erl_tar:close(HandleWrite), @@ -779,7 +935,8 @@ aes_ctr_stream_crypto_tar(Config) -> end, Cw = {Cinitw,Cenc,Cendw}, - {ok,HandleWrite} = ssh_sftp:open_tar(ChPid2, fnp(?tar_file_name,Config), [write,{crypto,Cw}]), + TarFileName = ?config(tar_filename, Config), + {ok,HandleWrite} = ssh_sftp:open_tar(ChPid2, TarFileName, [write,{crypto,Cw}]), [ok = erl_tar:add(HandleWrite, Bin, Name, [verbose]) || {Name,Bin} <- NameBins], ok = erl_tar:close(HandleWrite), @@ -790,18 +947,18 @@ aes_ctr_stream_crypto_tar(Config) -> %% Internal functions ------------------------------------------------ %%-------------------------------------------------------------------- prep(Config) -> - PrivDir = ?config(priv_dir, Config), - TestFile = filename:join(PrivDir, "sftp.txt"), - TestFile1 = filename:join(PrivDir, "test.txt"), - TestLink = filename:join(PrivDir, "link_test.txt"), + DataDir = ?config(data_dir, Config), + TestFile = ?config(filename, Config), + TestFile1 = ?config(testfile, Config), + TestLink = ?config(linktest, Config), + TarFileName = ?config(tar_filename, Config), file:delete(TestFile), file:delete(TestFile1), file:delete(TestLink), - file:delete(fnp(?tar_file_name,Config)), + file:delete(TarFileName), %% Initial config - DataDir = ?config(data_dir, Config), FileName = filename:join(DataDir, "sftp.txt"), file:copy(FileName, TestFile), Mode = 8#00400 bor 8#00200 bor 8#00040, % read & write owner, read group @@ -809,13 +966,12 @@ prep(Config) -> ok = file:write_file_info(TestFile, FileInfo#file_info{mode = Mode}). - - chk_tar(Items, Config) -> chk_tar(Items, Config, []). chk_tar(Items, Config, Opts) -> - chk_tar(Items, fnp(?tar_file_name,Config), Config, Opts). + TarFileName = ?config(tar_filename, Config), + chk_tar(Items, TarFileName, Config, Opts). chk_tar(Items, TarFileName, Config, Opts) when is_list(Opts) -> tar_size(TarFileName, Config), @@ -846,7 +1002,7 @@ analyze_report([E={NameE,BinE}|Es], [A={NameA,BinA}|As]) -> NameE < NameA -> [["Component ",NameE," is missing.\n\n"] | analyze_report(Es,[A|As])]; - + NameE > NameA -> [["Component ",NameA," is not expected.\n\n"] | analyze_report([E|Es],As)]; @@ -859,7 +1015,7 @@ analyze_report([], [{NameA,_BinA}|As]) -> [["Component ",NameA," not expected.\n\n"] | analyze_report([],As)]; analyze_report([], []) -> "". - + tar_size(TarFileName, Config) -> {ChPid,_} = ?config(sftp,Config), {ok,Data} = ssh_sftp:read_file(ChPid, TarFileName), @@ -888,14 +1044,9 @@ read_item_contents(ItemName, FileName) -> end. fn(Name, Config) -> - Dir = ?config(data_dir, Config), - filename:join([Dir,"sftp_tar_test_data",Name]). - -fnp(Name, Config) -> - Dir = ?config(priv_dir, Config), - filename:join([Dir,Name]). - + Dir = ?config(datadir_tar, Config), + filename:join(Dir,Name). fmt_host({A,B,C,D}) -> lists:concat([A,".",B,".",C,".",D]); fmt_host(S) -> S. - + diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/F一.txt b/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/F一.txt new file mode 100644 index 0000000000..e6076a05b5 --- /dev/null +++ b/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/F一.txt @@ -0,0 +1 @@ +你好 diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/big.txt b/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/big.txt new file mode 100644 index 0000000000..f597b69d4c --- /dev/null +++ b/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/big.txt @@ -0,0 +1,16384 @@ +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. +All work and no play makes Jack a dull boy. diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/d1/f1 b/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/d1/f1 new file mode 100644 index 0000000000..1bafa9761e --- /dev/null +++ b/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/d1/f1 @@ -0,0 +1 @@ +And hi from the subdirectory too! diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/d1/f2 b/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/d1/f2 new file mode 100644 index 0000000000..8566adaeef --- /dev/null +++ b/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/d1/f2 @@ -0,0 +1 @@ +one more file diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/f2.txt b/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/f2.txt new file mode 100644 index 0000000000..d18c6b11fc --- /dev/null +++ b/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/f2.txt @@ -0,0 +1 @@ +How are you? diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/f3.txt b/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/f3.txt new file mode 100644 index 0000000000..e6076a05b5 --- /dev/null +++ b/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/f3.txt @@ -0,0 +1 @@ +你好 diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/g四.txt b/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/g四.txt new file mode 100644 index 0000000000..d18c6b11fc --- /dev/null +++ b/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/g四.txt @@ -0,0 +1 @@ +How are you? diff --git a/lib/ssh/test/ssh_sftpd_SUITE.erl b/lib/ssh/test/ssh_sftpd_SUITE.erl index f38fcc5521..45439ce0fa 100644 --- a/lib/ssh/test/ssh_sftpd_SUITE.erl +++ b/lib/ssh/test/ssh_sftpd_SUITE.erl @@ -44,6 +44,9 @@ %% Common Test interface functions ----------------------------------- %%-------------------------------------------------------------------- +suite() -> + [{timetrap,{minutes,3}}]. + all() -> [open_close_file, open_close_dir, @@ -69,28 +72,21 @@ groups() -> %%-------------------------------------------------------------------- init_per_suite(Config) -> - catch crypto:stop(), - case (catch crypto:start()) of - ok -> - DataDir = ?config(data_dir, Config), - PrivDir = ?config(priv_dir, Config), - ssh_test_lib:setup_dsa(DataDir, PrivDir), - %% to make sure we don't use public-key-auth - %% this should be tested by other test suites - UserDir = filename:join(?config(priv_dir, Config), nopubkey), - file:make_dir(UserDir), - Config; - _ -> - {skip,"Could not start crypto!"} - end. + DataDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + ssh_test_lib:setup_dsa(DataDir, PrivDir), + %% to make sure we don't use public-key-auth + %% this should be tested by other test suites + UserDir = filename:join(?config(priv_dir, Config), nopubkey), + file:make_dir(UserDir), + Config. end_per_suite(Config) -> SysDir = ?config(priv_dir, Config), ssh_test_lib:clean_dsa(SysDir), UserDir = filename:join(?config(priv_dir, Config), nopubkey), file:del_dir(UserDir), - ssh:stop(), - crypto:stop(). + ssh:stop(). %%-------------------------------------------------------------------- @@ -152,7 +148,7 @@ init_per_testcase(TestCase, Config) -> {ok, <<?SSH_FXP_VERSION, ?UINT32(Version), _Ext/binary>>, _} = reply(Cm, Channel), - ct:pal("Client: ~p Server ~p~n", [ProtocolVer, Version]), + ct:log("Client: ~p Server ~p~n", [ProtocolVer, Version]), [{sftp, {Cm, Channel}}, {sftpd, Sftpd }| Config]. @@ -418,7 +414,7 @@ real_path(Config) when is_list(Config) -> RealPath = filename:absname(binary_to_list(Path)), AbsPrivDir = filename:absname(PrivDir), - ct:pal("Path: ~p PrivDir: ~p~n", [RealPath, AbsPrivDir]), + ct:log("Path: ~p PrivDir: ~p~n", [RealPath, AbsPrivDir]), true = RealPath == AbsPrivDir end. @@ -447,7 +443,7 @@ links(Config) when is_list(Config) -> true = binary_to_list(Path) == FileName, - ct:pal("Path: ~p~n", [binary_to_list(Path)]) + ct:log("Path: ~p~n", [binary_to_list(Path)]) end. %%-------------------------------------------------------------------- @@ -548,10 +544,10 @@ set_attributes(Config) when is_list(Config) -> %% Can not test that NewPermissions = Permissions as %% on Unix platforms, other bits than those listed in the %% API may be set. - ct:pal("Org: ~p New: ~p~n", [OrigPermissions, NewPermissions]), + ct:log("Org: ~p New: ~p~n", [OrigPermissions, NewPermissions]), true = OrigPermissions =/= NewPermissions, - ct:pal("Try to open the file"), + ct:log("Try to open the file"), NewReqId = 2, {ok, <<?SSH_FXP_HANDLE, ?UINT32(NewReqId), Handle/binary>>, _} = open_file(FileName, Cm, Channel, NewReqId, @@ -563,7 +559,7 @@ set_attributes(Config) when is_list(Config) -> NewReqId1 = 3, - ct:pal("Set original permissions on the now open file"), + ct:log("Set original permissions on the now open file"), {ok, <<?SSH_FXP_STATUS, ?UINT32(NewReqId1), ?UINT32(?SSH_FX_OK), _/binary>>, _} = @@ -683,6 +679,8 @@ reply(Cm, Channel, RBuf) -> closed; {ssh_cm, Cm, Msg} -> ct:fail(Msg) + after + 30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end. @@ -786,7 +784,7 @@ read_dir(Handle, Cm, Channel, ReqId) -> case reply(Cm, Channel) of {ok, <<?SSH_FXP_NAME, ?UINT32(ReqId), ?UINT32(Count), ?UINT32(Len), Listing:Len/binary, _/binary>>, _} -> - ct:pal("Count: ~p Listing: ~p~n", + ct:log("Count: ~p Listing: ~p~n", [Count, binary_to_list(Listing)]), read_dir(Handle, Cm, Channel, ReqId); {ok, <<?SSH_FXP_STATUS, ?UINT32(ReqId), diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl b/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl index 321e3546cf..02a2ac4cf9 100644 --- a/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl +++ b/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl @@ -36,7 +36,9 @@ %%-------------------------------------------------------------------- suite() -> - [{ct_hooks,[ts_install_cth]}]. + [{ct_hooks,[ts_install_cth]}, + {timetrap,{minutes,2}}]. + all() -> [close_file, @@ -53,29 +55,22 @@ groups() -> init_per_suite(Config) -> catch ssh:stop(), - catch crypto:stop(), - case catch crypto:start() of - ok -> - DataDir = ?config(data_dir, Config), - PrivDir = ?config(priv_dir, Config), - FileAlt = filename:join(DataDir, "ssh_sftpd_file_alt.erl"), - c:c(FileAlt), - FileName = filename:join(DataDir, "test.txt"), - {ok, FileInfo} = file:read_file_info(FileName), - ok = file:write_file_info(FileName, - FileInfo#file_info{mode = 8#400}), - ssh_test_lib:setup_dsa(DataDir, PrivDir), - Config; - _Else -> - {skip,"Could not start ssh!"} - end. + DataDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + FileAlt = filename:join(DataDir, "ssh_sftpd_file_alt.erl"), + c:c(FileAlt), + FileName = filename:join(DataDir, "test.txt"), + {ok, FileInfo} = file:read_file_info(FileName), + ok = file:write_file_info(FileName, + FileInfo#file_info{mode = 8#400}), + ssh_test_lib:setup_dsa(DataDir, PrivDir), + Config. end_per_suite(Config) -> UserDir = filename:join(?config(priv_dir, Config), nopubkey), file:del_dir(UserDir), SysDir = ?config(priv_dir, Config), ssh_test_lib:clean_dsa(SysDir), - crypto:stop(), ok. %%-------------------------------------------------------------------- @@ -159,7 +154,7 @@ close_file(Config) when is_list(Config) -> NumOfPorts = length(erlang:ports()), - ct:pal("Number of open ports: ~p~n", [NumOfPorts]), + ct:log("Number of open ports: ~p~n", [NumOfPorts]), {ok, <<_/binary>>} = ssh_sftp:read_file(Sftp, FileName), @@ -255,14 +250,14 @@ root_dir(Config) when is_list(Config) -> {ok, Bin} = ssh_sftp:read_file(Sftp, FileName), {ok, Listing} = ssh_sftp:list_dir(Sftp, "."), - ct:pal("Listing: ~p~n", [Listing]). + ct:log("Listing: ~p~n", [Listing]). %%-------------------------------------------------------------------- list_dir_limited(Config) when is_list(Config) -> {Sftp, _} = ?config(sftp, Config), {ok, Listing} = ssh_sftp:list_dir(Sftp, "."), - ct:pal("Listing: ~p~n", [Listing]). + ct:log("Listing: ~p~n", [Listing]). %%-------------------------------------------------------------------- ver6_basic() -> diff --git a/lib/ssh/test/ssh_sup_SUITE.erl b/lib/ssh/test/ssh_sup_SUITE.erl index 5c77fcf1ef..98441e0046 100644 --- a/lib/ssh/test/ssh_sup_SUITE.erl +++ b/lib/ssh/test/ssh_sup_SUITE.erl @@ -34,6 +34,10 @@ %% Common Test interface functions ----------------------------------- %%-------------------------------------------------------------------- +suite() -> + [{ct_hooks,[ts_install_cth]}, + {timetrap,{minutes,1}}]. + all() -> [default_tree, sshc_subtree, sshd_subtree, sshd_subtree_profile]. @@ -101,16 +105,16 @@ sshc_subtree(Config) when is_list(Config) -> {ok, Pid1} = ssh:connect(Host, Port, [{silently_accept_hosts, true}, {user_interaction, false}, {user, ?USER}, {password, ?PASSWD},{user_dir, UserDir}]), - [{_, _,supervisor,[ssh_connection_handler]}] = + [{_, _,worker,[ssh_connection_handler]}] = supervisor:which_children(sshc_sup), {ok, Pid2} = ssh:connect(Host, Port, [{silently_accept_hosts, true}, {user_interaction, false}, {user, ?USER}, {password, ?PASSWD}, {user_dir, UserDir}]), - [{_,_,supervisor,[ssh_connection_handler]}, - {_,_,supervisor,[ssh_connection_handler]}] = + [{_,_,worker,[ssh_connection_handler]}, + {_,_,worker,[ssh_connection_handler]}] = supervisor:which_children(sshc_sup), ssh:close(Pid1), - [{_,_,supervisor,[ssh_connection_handler]}] = + [{_,_,worker,[ssh_connection_handler]}] = supervisor:which_children(sshc_sup), ssh:close(Pid2), ct:sleep(?WAIT_FOR_SHUTDOWN), diff --git a/lib/ssh/test/ssh_test_cli.erl b/lib/ssh/test/ssh_test_cli.erl index cd9ad5f2ff..697ddb730d 100644 --- a/lib/ssh/test/ssh_test_cli.erl +++ b/lib/ssh/test/ssh_test_cli.erl @@ -4,20 +4,25 @@ -record(state, { type, + tmpdir, id, ref, port }). -init([Type]) -> - {ok, #state{type = Type}}. + +init([Type]) -> init([Type,"/tmp"]); + +init([Type,TmpDir]) -> + {ok, #state{type = Type, + tmpdir = TmpDir}}. handle_msg({ssh_channel_up, Id, Ref}, S) -> User = get_ssh_user(Ref), ok = ssh_connection:send(Ref, Id, << "\r\nYou are accessing a dummy, type \"q\" to exit\r\n\n" >>), - Port = run_portprog(User, S#state.type), + Port = run_portprog(User, S#state.type, S#state.tmpdir), {ok, S#state{port = Port, id = Id, ref = Ref}}; handle_msg({Port, {data, Data}}, S = #state{port = Port}) -> @@ -68,10 +73,10 @@ handle_ssh_msg({ssh_cm, _, {exit_signal, Id, _, _, _}}, terminate(_Why, _S) -> nop. -run_portprog(User, cli) -> +run_portprog(User, cli, TmpDir) -> Pty_bin = os:find_executable("cat"), open_port({spawn_executable, Pty_bin}, - [stream, {cd, "/tmp"}, {env, [{"USER", User}]}, + [stream, {cd, TmpDir}, {env, [{"USER", User}]}, {args, []}, binary, exit_status, use_stdio, stderr_to_stdout]). diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl index 97c35e549c..5f91fb627a 100644 --- a/lib/ssh/test/ssh_test_lib.erl +++ b/lib/ssh/test/ssh_test_lib.erl @@ -27,6 +27,8 @@ -include_lib("public_key/include/public_key.hrl"). -include_lib("common_test/include/ct.hrl"). +-include_lib("ssh/src/ssh_transport.hrl"). + -define(TIMEOUT, 50000). @@ -65,6 +67,62 @@ daemon(Host, Port, Options) -> end. +std_daemon(Config, ExtraOpts) -> + PrivDir = ?config(priv_dir, Config), + UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), + std_daemon1(Config, + ExtraOpts ++ + [{user_dir, UserDir}, + {user_passwords, [{"usr1","pwd1"}]}]). + +std_daemon1(Config, ExtraOpts) -> + SystemDir = ?config(data_dir, Config), + {_Server, _Host, _Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + {failfun, fun ssh_test_lib:failfun/2} + | ExtraOpts]). + +std_connect(Config, Host, Port, ExtraOpts) -> + UserDir = ?config(priv_dir, Config), + _ConnectionRef = + ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user_dir, UserDir}, + {user, "usr1"}, + {password, "pwd1"}, + {user_interaction, false} + | ExtraOpts]). + +std_simple_sftp(Host, Port, Config) -> + std_simple_sftp(Host, Port, Config, []). + +std_simple_sftp(Host, Port, Config, Opts) -> + UserDir = ?config(priv_dir, Config), + DataFile = filename:join(UserDir, "test.data"), + ConnectionRef = ssh_test_lib:std_connect(Config, Host, Port, Opts), + {ok, ChannelRef} = ssh_sftp:start_channel(ConnectionRef), + Data = crypto:rand_bytes(proplists:get_value(std_simple_sftp_size,Config,10)), + ok = ssh_sftp:write_file(ChannelRef, DataFile, Data), + {ok,ReadData} = file:read_file(DataFile), + ok = ssh:close(ConnectionRef), + Data == ReadData. + +std_simple_exec(Host, Port, Config) -> + std_simple_exec(Host, Port, Config, []). + +std_simple_exec(Host, Port, Config, Opts) -> + ConnectionRef = ssh_test_lib:std_connect(Config, Host, Port, Opts), + {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity), + success = ssh_connection:exec(ConnectionRef, ChannelId, "23+21-2.", infinity), + Data = {ssh_cm, ConnectionRef, {data, ChannelId, 0, <<"42\n">>}}, + case ssh_test_lib:receive_exec_result(Data) of + expected -> + ok; + Other -> + ct:fail(Other) + end, + ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId), + ssh:close(ConnectionRef). + start_shell(Port, IOServer, UserDir) -> start_shell(Port, IOServer, UserDir, []). @@ -97,16 +155,16 @@ loop_io_server(TestCase, Buff0) -> {input, TestCase, Line} -> loop_io_server(TestCase, Buff0 ++ [Line]); {io_request, From, ReplyAs, Request} -> -%%ct:pal("~p",[{io_request, From, ReplyAs, Request}]), {ok, Reply, Buff} = io_request(Request, TestCase, From, ReplyAs, Buff0), -%%ct:pal("io_request(~p)-->~p",[Request,{ok, Reply, Buff}]), io_reply(From, ReplyAs, Reply), loop_io_server(TestCase, Buff); - {'EXIT',_, _} -> - erlang:display('ssh_test_lib:loop_io_server/2 EXIT'), + {'EXIT',_, _} = _Exit -> +%% ct:log("ssh_test_lib:loop_io_server/2 got ~p",[_Exit]), ok - end. + after + 30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) + end. io_request({put_chars, Chars}, TestCase, _, _, Buff) -> reply(TestCase, Chars), @@ -134,27 +192,29 @@ io_request({get_line, _Enc,_}, _, _, _, [Line | Buff]) -> io_reply(_, _, []) -> ok; io_reply(From, ReplyAs, Reply) -> -%%ct:pal("io_reply ~p sending ~p ! ~p",[self(),From, {io_reply, ReplyAs, Reply}]), +%%ct:log("io_reply ~p sending ~p ! ~p",[self(),From, {io_reply, ReplyAs, Reply}]), From ! {io_reply, ReplyAs, Reply}. reply(_, []) -> ok; reply(TestCase, Result) -> -%%ct:pal("reply ~p sending ~p ! ~p",[self(), TestCase, Result]), +%%ct:log("reply ~p sending ~p ! ~p",[self(), TestCase, Result]), TestCase ! Result. receive_exec_result(Msg) -> - ct:pal("Expect data! ~p", [Msg]), + ct:log("Expect data! ~p", [Msg]), receive {ssh_cm,_,{data,_,1, Data}} -> - ct:pal("StdErr: ~p~n", [Data]), + ct:log("StdErr: ~p~n", [Data]), receive_exec_result(Msg); Msg -> - ct:pal("1: Collected data ~p", [Msg]), + ct:log("1: Collected data ~p", [Msg]), expected; Other -> - ct:pal("Other ~p", [Other]), + ct:log("Other ~p", [Other]), {unexpected_msg, Other} + after + 30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end. @@ -165,15 +225,15 @@ receive_exec_end(ConnectionRef, ChannelId) -> case receive_exec_result(ExitStatus) of {unexpected_msg, Eof} -> %% Open ssh seems to not allways send these messages %% in the same order! - ct:pal("2: Collected data ~p", [Eof]), + ct:log("2: Collected data ~p", [Eof]), case receive_exec_result(ExitStatus) of expected -> expected = receive_exec_result(Closed); {unexpected_msg, Closed} -> - ct:pal("3: Collected data ~p", [Closed]) + ct:log("3: Collected data ~p", [Closed]) end; expected -> - ct:pal("4: Collected data ~p", [ExitStatus]), + ct:log("4: Collected data ~p", [ExitStatus]), expected = receive_exec_result(Eof), expected = receive_exec_result(Closed); Other -> @@ -235,6 +295,7 @@ setup_dsa(DataDir, UserDir) -> file:make_dir(System), file:copy(filename:join(DataDir, "ssh_host_dsa_key"), filename:join(System, "ssh_host_dsa_key")), file:copy(filename:join(DataDir, "ssh_host_dsa_key.pub"), filename:join(System, "ssh_host_dsa_key.pub")), +ct:log("DataDir ~p:~n ~p~n~nSystDir ~p:~n ~p~n~nUserDir ~p:~n ~p",[DataDir, file:list_dir(DataDir), System, file:list_dir(System), UserDir, file:list_dir(UserDir)]), setup_dsa_known_host(DataDir, UserDir), setup_dsa_auth_keys(DataDir, UserDir). @@ -243,10 +304,21 @@ setup_rsa(DataDir, UserDir) -> System = filename:join(UserDir, "system"), file:make_dir(System), file:copy(filename:join(DataDir, "ssh_host_rsa_key"), filename:join(System, "ssh_host_rsa_key")), - file:copy(filename:join(DataDir, "ssh_host_rsa_key"), filename:join(System, "ssh_host_rsa_key.pub")), + file:copy(filename:join(DataDir, "ssh_host_rsa_key.pub"), filename:join(System, "ssh_host_rsa_key.pub")), +ct:log("DataDir ~p:~n ~p~n~nSystDir ~p:~n ~p~n~nUserDir ~p:~n ~p",[DataDir, file:list_dir(DataDir), System, file:list_dir(System), UserDir, file:list_dir(UserDir)]), setup_rsa_known_host(DataDir, UserDir), setup_rsa_auth_keys(DataDir, UserDir). +setup_ecdsa(Size, DataDir, UserDir) -> + file:copy(filename:join(DataDir, "id_ecdsa"++Size), filename:join(UserDir, "id_ecdsa")), + System = filename:join(UserDir, "system"), + file:make_dir(System), + file:copy(filename:join(DataDir, "ssh_host_ecdsa_key"++Size), filename:join(System, "ssh_host_ecdsa_key")), + file:copy(filename:join(DataDir, "ssh_host_ecdsa_key"++Size++".pub"), filename:join(System, "ssh_host_ecdsa_key.pub")), +ct:log("DataDir ~p:~n ~p~n~nSystDir ~p:~n ~p~n~nUserDir ~p:~n ~p",[DataDir, file:list_dir(DataDir), System, file:list_dir(System), UserDir, file:list_dir(UserDir)]), + setup_ecdsa_known_host(Size, System, UserDir), + setup_ecdsa_auth_keys(Size, UserDir, UserDir). + clean_dsa(UserDir) -> del_dirs(filename:join(UserDir, "system")), file:delete(filename:join(UserDir,"id_dsa")), @@ -298,6 +370,11 @@ setup_rsa_known_host(SystemDir, UserDir) -> [{Key, _}] = public_key:ssh_decode(SshBin, public_key), setup_known_hosts(Key, UserDir). +setup_ecdsa_known_host(_Size, SystemDir, UserDir) -> + {ok, SshBin} = file:read_file(filename:join(SystemDir, "ssh_host_ecdsa_key.pub")), + [{Key, _}] = public_key:ssh_decode(SshBin, public_key), + setup_known_hosts(Key, UserDir). + setup_known_hosts(Key, UserDir) -> {ok, Hostname} = inet:gethostname(), {ok, {A, B, C, D}} = inet:getaddr(Hostname, inet), @@ -325,6 +402,14 @@ setup_rsa_auth_keys(Dir, UserDir) -> PKey = #'RSAPublicKey'{publicExponent = E, modulus = N}, setup_auth_keys([{ PKey, [{comment, "Test"}]}], UserDir). +setup_ecdsa_auth_keys(_Size, Dir, UserDir) -> + {ok, Pem} = file:read_file(filename:join(Dir, "id_ecdsa")), + ECDSA = public_key:pem_entry_decode(hd(public_key:pem_decode(Pem))), + #'ECPrivateKey'{publicKey = Q, + parameters = Param = {namedCurve,_Id0}} = ECDSA, + PKey = #'ECPoint'{point = Q}, + setup_auth_keys([{ {PKey,Param}, [{comment, "Test"}]}], UserDir). + setup_auth_keys(Keys, Dir) -> AuthKeys = public_key:ssh_encode(Keys, auth_keys), AuthKeysFile = filename:join(Dir, "authorized_keys"), @@ -372,3 +457,236 @@ openssh_sanity_check(Config) -> ssh:stop(), {skip, Str} end. + +openssh_supports(ClientOrServer, Tag, Alg) when ClientOrServer == sshc ; + ClientOrServer == sshd -> + SSH_algos = ssh_test_lib:default_algorithms(ClientOrServer), + L = proplists:get_value(Tag, SSH_algos, []), + lists:member(Alg, L) orelse + lists:member(Alg, proplists:get_value(client2server, L, [])) orelse + lists:member(Alg, proplists:get_value(server2client, L, [])). + +%%-------------------------------------------------------------------- +%% Check if we have a "newer" ssh client that supports these test cases + +ssh_client_supports_Q() -> + ErlPort = open_port({spawn, "ssh -Q cipher"}, [exit_status, stderr_to_stdout]), + 0 == check_ssh_client_support2(ErlPort). + +check_ssh_client_support2(P) -> + receive + {P, {data, _A}} -> + check_ssh_client_support2(P); + {P, {exit_status, E}} -> + E + after 5000 -> + + ct:log("Openssh command timed out ~n"), + -1 + end. + +%%%-------------------------------------------------------------------- +%%% Probe a server or a client about algorithm support + +default_algorithms(sshd) -> + default_algorithms(sshd, "localhost", 22); + +default_algorithms(sshc) -> + default_algorithms(sshc, []). + +default_algorithms(sshd, Host, Port) -> + try run_fake_ssh( + ssh_trpt_test_lib:exec( + [{connect,Host,Port, [{silently_accept_hosts, true}, + {user_interaction, false}]}])) + catch + _C:_E -> + ct:log("***~p:~p: ~p:~p",[?MODULE,?LINE,_C,_E]), + [] + end. + +default_algorithms(sshc, DaemonOptions) -> + Parent = self(), + %% Start a process handling one connection on the server side: + Srvr = + spawn_link( + fun() -> + Parent ! + {result, self(), + try + {ok,InitialState} = ssh_trpt_test_lib:exec(listen), + Parent ! {hostport,self(),ssh_trpt_test_lib:server_host_port(InitialState)}, + run_fake_ssh( + ssh_trpt_test_lib:exec([{accept, DaemonOptions}], + InitialState)) + catch + _C:_E -> + ct:log("***~p:~p: ~p:~p",[?MODULE,?LINE,_C,_E]), + [] + end} + end), + + receive + {hostport,Srvr,{_Host,Port}} -> + spawn(fun()-> os:cmd(lists:concat(["ssh -o \"StrictHostKeyChecking no\" -p ",Port," localhost"])) end) + after ?TIMEOUT -> + ct:fail("No server respons 1") + end, + + receive + {result,Srvr,L} -> + L + after ?TIMEOUT -> + ct:fail("No server respons 2") + end. + +run_fake_ssh({ok,InitialState}) -> + KexInitPattern = + #ssh_msg_kexinit{ + kex_algorithms = '$kex_algorithms', + server_host_key_algorithms = '$server_host_key_algorithms', + encryption_algorithms_client_to_server = '$encryption_algorithms_client_to_server', + encryption_algorithms_server_to_client = '$encryption_algorithms_server_to_client', + mac_algorithms_client_to_server = '$mac_algorithms_client_to_server', + mac_algorithms_server_to_client = '$mac_algorithms_server_to_client', + compression_algorithms_client_to_server = '$compression_algorithms_client_to_server', + compression_algorithms_server_to_client = '$compression_algorithms_server_to_client', + _ = '_' + }, + {ok,E} = ssh_trpt_test_lib:exec([{set_options,[silent]}, + {send, hello}, + receive_hello, + {send, ssh_msg_kexinit}, + {match, KexInitPattern, receive_msg}, + close_socket + ], + InitialState), + [Kex, PubKey, EncC2S, EncS2C, MacC2S, MacS2C, CompC2S, CompS2C] = + ssh_trpt_test_lib:instantiate(['$kex_algorithms', + '$server_host_key_algorithms', + '$encryption_algorithms_client_to_server', + '$encryption_algorithms_server_to_client', + '$mac_algorithms_client_to_server', + '$mac_algorithms_server_to_client', + '$compression_algorithms_client_to_server', + '$compression_algorithms_server_to_client' + ], E), + [{kex, to_atoms(Kex)}, + {public_key, to_atoms(PubKey)}, + {cipher, [{client2server, to_atoms(EncC2S)}, + {server2client, to_atoms(EncS2C)}]}, + {mac, [{client2server, to_atoms(MacC2S)}, + {server2client, to_atoms(MacS2C)}]}, + {compression, [{client2server, to_atoms(CompC2S)}, + {server2client, to_atoms(CompS2C)}]}]. + + +%%%---------------------------------------------------------------- +extract_algos(Spec) -> + [{Tag,get_atoms(List)} || {Tag,List} <- Spec]. + +get_atoms(L) -> + lists:usort( + [ A || X <- L, + A <- case X of + {_,L1} when is_list(L1) -> L1; + Y when is_atom(Y) -> [Y] + end]). + + +intersection(AlgoSpec1, AlgoSpec2) -> intersect(sort_spec(AlgoSpec1), sort_spec(AlgoSpec2)). + +intersect([{Tag,S1}|Ss1], [{Tag,S2}|Ss2]) -> + [{Tag,intersect(S1,S2)} | intersect(Ss1,Ss2)]; +intersect(L1=[A1|_], L2=[A2|_]) when is_atom(A1),is_atom(A2) -> + Diff = L1 -- L2, + L1 -- Diff; +intersect(_, _) -> + []. + +intersect_bi_dir([{Tag,[{client2server,L1},{server2client,L2}]}|T]) -> + [{Tag,intersect(L1,L2)} | intersect_bi_dir(T)]; +intersect_bi_dir([H={_,[A|_]}|T]) when is_atom(A) -> + [H | intersect_bi_dir(T)]; +intersect_bi_dir([]) -> + []. + + +sort_spec(L = [{_,_}|_] ) -> [{Tag,sort_spec(Es)} || {Tag,Es} <- L]; +sort_spec(L) -> lists:usort(L). + +%%-------------------------------------------------------------------- +sshc(Tag) -> + to_atoms( + string:tokens(os:cmd(lists:concat(["ssh -Q ",Tag])), "\n") + ). + +ssh_type() -> + case os:find_executable("ssh") of + false -> not_found; + _ -> + case os:cmd("ssh -V") of + "OpenSSH" ++ _ -> + openSSH; + Str -> + ct:log("ssh client ~p is unknown",[Str]), + unknown + end + end. + +algo_intersection([], _) -> []; +algo_intersection(_, []) -> []; +algo_intersection(L1=[A1|_], L2=[A2|_]) when is_atom(A1), is_atom(A2) -> + true = lists:all(fun erlang:is_atom/1, L1++L2), + lists:foldr(fun(A,Acc) -> + case lists:member(A,L2) of + true -> [A|Acc]; + false -> Acc + end + end, [], L1); +algo_intersection([{K,V1}|T1], L2) -> + case lists:keysearch(K,1,L2) of + {value, {K,V2}} -> + [{K,algo_intersection(V1,V2)} | algo_intersection(T1,L2)]; + false -> + algo_intersection(T1,L2) + end; +algo_intersection(_, _) -> + []. + + +to_atoms(L) -> lists:map(fun erlang:list_to_atom/1, L). + +%%%---------------------------------------------------------------- +ssh_supports(Alg, SshDefaultAlg_tag) -> + SupAlgs = + case proplists:get_value(SshDefaultAlg_tag, + ssh:default_algorithms()) of + [{_K1,L1}, {_K2,L2}] -> + lists:usort(L1++L2); + L -> + L + end, + if + is_atom(Alg) -> + lists:member(Alg, SupAlgs); + is_list(Alg) -> + case Alg--SupAlgs of + [] -> + true; + UnSup -> + {false,UnSup} + end + end. + +%%%---------------------------------------------------------------- +has_inet6_address() -> + try + [throw(6) || {ok,L} <- [inet:getifaddrs()], + {_,L1} <- L, + {addr,{_,_,_,_,_,_,_,_}} <- L1] + of + [] -> false + catch + throw:6 -> true + end. diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl index b7283202a3..2788bc6b58 100644 --- a/lib/ssh/test/ssh_to_openssh_SUITE.erl +++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl @@ -33,6 +33,9 @@ %% Common Test interface functions ----------------------------------- %%-------------------------------------------------------------------- +suite() -> + [{timetrap,{minutes,1}}]. + all() -> case os:find_executable("ssh") of false -> @@ -45,37 +48,26 @@ all() -> groups() -> [{erlang_client, [], [erlang_shell_client_openssh_server, - erlang_client_openssh_server_exec, erlang_client_openssh_server_exec_compressed, erlang_client_openssh_server_setenv, erlang_client_openssh_server_publickey_rsa, erlang_client_openssh_server_publickey_dsa, erlang_client_openssh_server_password, + erlang_client_openssh_server_kexs, erlang_client_openssh_server_nonexistent_subsystem ]}, - {erlang_server, [], [erlang_server_openssh_client_exec, - erlang_server_openssh_client_exec_compressed, - erlang_server_openssh_client_pulic_key_dsa, - erlang_server_openssh_client_cipher_suites, - erlang_server_openssh_client_macs]} + {erlang_server, [], [erlang_server_openssh_client_public_key_dsa]} ]. init_per_suite(Config) -> - catch crypto:stop(), - case catch crypto:start() of - ok -> - case gen_tcp:connect("localhost", 22, []) of - {error,econnrefused} -> - {skip,"No openssh deamon"}; - _ -> - ssh_test_lib:openssh_sanity_check(Config) - end; - _Else -> - {skip,"Could not start crypto!"} + case gen_tcp:connect("localhost", 22, []) of + {error,econnrefused} -> + {skip,"No openssh deamon"}; + _ -> + ssh_test_lib:openssh_sanity_check(Config) end. end_per_suite(_Config) -> - crypto:stop(), ok. init_per_group(erlang_server, Config) -> @@ -83,6 +75,11 @@ init_per_group(erlang_server, Config) -> UserDir = ?config(priv_dir, Config), ssh_test_lib:setup_dsa_known_host(DataDir, UserDir), Config; +init_per_group(erlang_client, Config) -> + CommonAlgs = ssh_test_lib:algo_intersection( + ssh:default_algorithms(), + ssh_test_lib:default_algorithms(sshd)), + [{common_algs,CommonAlgs} | Config]; init_per_group(_, Config) -> Config. @@ -93,12 +90,11 @@ end_per_group(erlang_server, Config) -> end_per_group(_, Config) -> Config. -init_per_testcase(erlang_server_openssh_client_cipher_suites, Config) -> - check_ssh_client_support(Config); - -init_per_testcase(erlang_server_openssh_client_macs, Config) -> - check_ssh_client_support(Config); +init_per_testcase(erlang_server_openssh_client_public_key_dsa, Config) -> + chk_key(sshc, 'ssh-dss', ".ssh/id_dsa", Config); +init_per_testcase(erlang_client_openssh_server_publickey_dsa, Config) -> + chk_key(sshd, 'ssh-dss', ".ssh/id_dsa", Config); init_per_testcase(_TestCase, Config) -> ssh:start(), Config. @@ -107,6 +103,27 @@ end_per_testcase(_TestCase, _Config) -> ssh:stop(), ok. + +chk_key(Pgm, Name, File, Config) -> + case ssh_test_lib:openssh_supports(Pgm, public_key, Name) of + false -> + {skip,lists:concat(["openssh client does not support ",Name])}; + true -> + {ok,[[Home]]} = init:get_argument(home), + KeyFile = filename:join(Home, File), + case file:read_file(KeyFile) of + {ok, Pem} -> + case public_key:pem_decode(Pem) of + [{_,_, not_encrypted}] -> + init_per_testcase('__default__',Config); + _ -> + {skip, {error, "Has pass phrase can not be used by automated test case"}} + end; + _ -> + {skip, lists:concat(["no ~/",File])} + end + end. + %%-------------------------------------------------------------------- %% Test Cases -------------------------------------------------------- %%-------------------------------------------------------------------- @@ -140,7 +157,7 @@ erlang_client_openssh_server_exec(Config) when is_list(Config) -> ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId0); {unexpected_msg,{ssh_cm, ConnectionRef, {exit_status, ChannelId0, 0}} = ExitStatus0} -> - ct:pal("0: Collected data ~p", [ExitStatus0]), + ct:log("0: Collected data ~p", [ExitStatus0]), ssh_test_lib:receive_exec_result(Data0, ConnectionRef, ChannelId0); Other0 -> @@ -156,7 +173,7 @@ erlang_client_openssh_server_exec(Config) when is_list(Config) -> ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId1); {unexpected_msg,{ssh_cm, ConnectionRef, {exit_status, ChannelId1, 0}} = ExitStatus1} -> - ct:pal("0: Collected data ~p", [ExitStatus1]), + ct:log("0: Collected data ~p", [ExitStatus1]), ssh_test_lib:receive_exec_result(Data1, ConnectionRef, ChannelId1); Other1 -> @@ -169,188 +186,80 @@ erlang_client_openssh_server_exec_compressed() -> erlang_client_openssh_server_exec_compressed(Config) when is_list(Config) -> CompressAlgs = [zlib, '[email protected]',none], - ConnectionRef = ssh_test_lib:connect(?SSH_DEFAULT_PORT, [{silently_accept_hosts, true}, - {user_interaction, false}, - {preferred_algorithms, - [{compression,CompressAlgs}]}]), - {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity), - success = ssh_connection:exec(ConnectionRef, ChannelId, - "echo testing", infinity), - Data = {ssh_cm, ConnectionRef, {data, ChannelId, 0, <<"testing\n">>}}, - case ssh_test_lib:receive_exec_result(Data) of - expected -> - ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId); - {unexpected_msg,{ssh_cm, ConnectionRef, - {exit_status, ChannelId, 0}} = ExitStatus} -> - ct:pal("0: Collected data ~p", [ExitStatus]), - ssh_test_lib:receive_exec_result(Data, ConnectionRef, ChannelId); - Other -> - ct:fail(Other) + case ssh_test_lib:ssh_supports(CompressAlgs, compression) of + {false,L} -> + {skip, io_lib:format("~p compression is not supported",[L])}; + + true -> + ConnectionRef = ssh_test_lib:connect(?SSH_DEFAULT_PORT, [{silently_accept_hosts, true}, + {user_interaction, false}, + {preferred_algorithms, + [{compression,CompressAlgs}]}]), + {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity), + success = ssh_connection:exec(ConnectionRef, ChannelId, + "echo testing", infinity), + Data = {ssh_cm, ConnectionRef, {data, ChannelId, 0, <<"testing\n">>}}, + case ssh_test_lib:receive_exec_result(Data) of + expected -> + ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId); + {unexpected_msg,{ssh_cm, ConnectionRef, + {exit_status, ChannelId, 0}} = ExitStatus} -> + ct:log("0: Collected data ~p", [ExitStatus]), + ssh_test_lib:receive_exec_result(Data, ConnectionRef, ChannelId); + Other -> + ct:fail(Other) + end end. %%-------------------------------------------------------------------- -erlang_server_openssh_client_exec() -> - [{doc, "Test that exec command works."}]. - -erlang_server_openssh_client_exec(Config) when is_list(Config) -> - SystemDir = ?config(data_dir, Config), - PrivDir = ?config(priv_dir, Config), - KnownHosts = filename:join(PrivDir, "known_hosts"), - - {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, - {failfun, fun ssh_test_lib:failfun/2}]), - - - ct:sleep(500), - - Cmd = "ssh -p " ++ integer_to_list(Port) ++ - " -o UserKnownHostsFile=" ++ KnownHosts ++ " " ++ Host ++ " 1+1.", - - ct:pal("Cmd: ~p~n", [Cmd]), - - SshPort = open_port({spawn, Cmd}, [binary]), - - receive - {SshPort,{data, <<"2\n">>}} -> - ok - after ?TIMEOUT -> - ct:fail("Did not receive answer") - - end, - ssh:stop_daemon(Pid). - -%%-------------------------------------------------------------------- -erlang_server_openssh_client_cipher_suites() -> - [{doc, "Test that we can connect with different cipher suites."}]. - -erlang_server_openssh_client_cipher_suites(Config) when is_list(Config) -> - SystemDir = ?config(data_dir, Config), - PrivDir = ?config(priv_dir, Config), - KnownHosts = filename:join(PrivDir, "known_hosts"), - - {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, - {failfun, fun ssh_test_lib:failfun/2}]), - - - ct:sleep(500), - - Supports = crypto:supports(), - Ciphers = proplists:get_value(ciphers, Supports), - Tests = [ - {"3des-cbc", lists:member(des3_cbc, Ciphers)}, - {"aes128-cbc", lists:member(aes_cbc128, Ciphers)}, - {"aes128-ctr", lists:member(aes_ctr, Ciphers)}, - {"aes256-cbc", false} - ], - lists:foreach(fun({Cipher, Expect}) -> - Cmd = "ssh -p " ++ integer_to_list(Port) ++ - " -o UserKnownHostsFile=" ++ KnownHosts ++ " " ++ Host ++ " " ++ - " -c " ++ Cipher ++ " 1+1.", - - ct:pal("Cmd: ~p~n", [Cmd]), - - SshPort = open_port({spawn, Cmd}, [binary, stderr_to_stdout]), - - case Expect of - true -> - receive - {SshPort,{data, <<"2\n">>}} -> - ok - after ?TIMEOUT -> - ct:fail("Did not receive answer") - end; - false -> - receive - {SshPort,{data, <<"no matching cipher found", _/binary>>}} -> - ok - after ?TIMEOUT -> - ct:fail("Did not receive no matching cipher message") - end - end - end, Tests), - - ssh:stop_daemon(Pid). - -%%-------------------------------------------------------------------- -erlang_server_openssh_client_macs() -> - [{doc, "Test that we can connect with different MACs."}]. - -erlang_server_openssh_client_macs(Config) when is_list(Config) -> - SystemDir = ?config(data_dir, Config), - PrivDir = ?config(priv_dir, Config), - KnownHosts = filename:join(PrivDir, "known_hosts"), - - {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, - {failfun, fun ssh_test_lib:failfun/2}]), - - - ct:sleep(500), - - Supports = crypto:supports(), - Hashs = proplists:get_value(hashs, Supports), - MACs = [{"hmac-sha1", lists:member(sha, Hashs)}, - {"hmac-sha2-256", lists:member(sha256, Hashs)}, - {"hmac-md5-96", false}, - {"hmac-ripemd160", false}], - lists:foreach(fun({MAC, Expect}) -> - Cmd = "ssh -p " ++ integer_to_list(Port) ++ - " -o UserKnownHostsFile=" ++ KnownHosts ++ " " ++ Host ++ " " ++ - " -o MACs=" ++ MAC ++ " 1+1.", - - ct:pal("Cmd: ~p~n", [Cmd]), - - SshPort = open_port({spawn, Cmd}, [binary, stderr_to_stdout]), - - case Expect of - true -> - receive - {SshPort,{data, <<"2\n">>}} -> - ok - after ?TIMEOUT -> - ct:fail("Did not receive answer") - end; - false -> - receive - {SshPort,{data, <<"no matching mac found", _/binary>>}} -> - ok - after ?TIMEOUT -> - ct:fail("Did not receive no matching mac message") - end - end - end, MACs), - - ssh:stop_daemon(Pid). - -%%-------------------------------------------------------------------- -erlang_server_openssh_client_exec_compressed() -> - [{doc, "Test that exec command works."}]. - -erlang_server_openssh_client_exec_compressed(Config) when is_list(Config) -> - SystemDir = ?config(data_dir, Config), - PrivDir = ?config(priv_dir, Config), - KnownHosts = filename:join(PrivDir, "known_hosts"), - -%% CompressAlgs = [zlib, '[email protected]'], % Does not work - CompressAlgs = [zlib], - {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, - {preferred_algorithms, - [{compression, CompressAlgs}]}, - {failfun, fun ssh_test_lib:failfun/2}]), - - ct:sleep(500), - - Cmd = "ssh -p " ++ integer_to_list(Port) ++ - " -o UserKnownHostsFile=" ++ KnownHosts ++ " -C "++ Host ++ " 1+1.", - SshPort = open_port({spawn, Cmd}, [binary]), - - receive - {SshPort,{data, <<"2\n">>}} -> - ok - after ?TIMEOUT -> - ct:fail("Did not receive answer") - - end, - ssh:stop_daemon(Pid). +erlang_client_openssh_server_kexs() -> + [{doc, "Test that we can connect with different KEXs."}]. + +erlang_client_openssh_server_kexs(Config) when is_list(Config) -> + KexAlgos = try proplists:get_value(kex, ?config(common_algs,Config)) + catch _:_ -> [] + end, + comment(KexAlgos), + case KexAlgos of + [] -> {skip, "No common kex algorithms"}; + _ -> + Success = + lists:foldl( + fun(Kex, Acc) -> + ConnectionRef = + ssh_test_lib:connect(?SSH_DEFAULT_PORT, [{silently_accept_hosts, true}, + {user_interaction, false}, + {preferred_algorithms, + [{kex,[Kex]}]}]), + + {ok, ChannelId} = + ssh_connection:session_channel(ConnectionRef, infinity), + success = + ssh_connection:exec(ConnectionRef, ChannelId, + "echo testing", infinity), + + ExpectedData = {ssh_cm, ConnectionRef, {data, ChannelId, 0, <<"testing\n">>}}, + case ssh_test_lib:receive_exec_result(ExpectedData) of + expected -> + ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId), + Acc; + {unexpected_msg,{ssh_cm, ConnectionRef, + {exit_status, ChannelId, 0}} = ExitStatus} -> + ct:log("0: Collected data ~p", [ExitStatus]), + ssh_test_lib:receive_exec_result(ExpectedData, ConnectionRef, ChannelId), + Acc; + Other -> + ct:log("~p failed: ~p",[Kex,Other]), + false + end + end, true, KexAlgos), + case Success of + true -> + ok; + false -> + {fail, "Kex failed for one or more algos"} + end + end. %%-------------------------------------------------------------------- erlang_client_openssh_server_setenv() -> @@ -380,11 +289,11 @@ erlang_client_openssh_server_setenv(Config) when is_list(Config) -> {data,0,1, UnxpectedData}}} -> %% Some os may return things as %% ENV_TEST: Undefined variable.\n" - ct:pal("UnxpectedData: ~p", [UnxpectedData]), + ct:log("UnxpectedData: ~p", [UnxpectedData]), ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId); {unexpected_msg,{ssh_cm, ConnectionRef, {exit_status, ChannelId, 0}} = ExitStatus} -> - ct:pal("0: Collected data ~p", [ExitStatus]), + ct:log("0: Collected data ~p", [ExitStatus]), ssh_test_lib:receive_exec_result(Data, ConnectionRef, ChannelId); Other -> @@ -426,31 +335,20 @@ erlang_client_openssh_server_publickey_rsa(Config) when is_list(Config) -> erlang_client_openssh_server_publickey_dsa() -> [{doc, "Validate using dsa publickey."}]. erlang_client_openssh_server_publickey_dsa(Config) when is_list(Config) -> - {ok,[[Home]]} = init:get_argument(home), - KeyFile = filename:join(Home, ".ssh/id_dsa"), - case file:read_file(KeyFile) of - {ok, Pem} -> - case public_key:pem_decode(Pem) of - [{_,_, not_encrypted}] -> - ConnectionRef = - ssh_test_lib:connect(?SSH_DEFAULT_PORT, - [{public_key_alg, ssh_dsa}, - {user_interaction, false}, - silently_accept_hosts]), - {ok, Channel} = - ssh_connection:session_channel(ConnectionRef, infinity), - ok = ssh_connection:close(ConnectionRef, Channel), - ok = ssh:close(ConnectionRef); - _ -> - {skip, {error, "Has pass phrase can not be used by automated test case"}} - end; - _ -> - {skip, "no ~/.ssh/id_dsa"} - end. + ConnectionRef = + ssh_test_lib:connect(?SSH_DEFAULT_PORT, + [{public_key_alg, ssh_dsa}, + {user_interaction, false}, + silently_accept_hosts]), + {ok, Channel} = + ssh_connection:session_channel(ConnectionRef, infinity), + ok = ssh_connection:close(ConnectionRef, Channel), + ok = ssh:close(ConnectionRef). + %%-------------------------------------------------------------------- -erlang_server_openssh_client_pulic_key_dsa() -> +erlang_server_openssh_client_public_key_dsa() -> [{doc, "Validate using dsa publickey."}]. -erlang_server_openssh_client_pulic_key_dsa(Config) when is_list(Config) -> +erlang_server_openssh_client_public_key_dsa(Config) when is_list(Config) -> SystemDir = ?config(data_dir, Config), PrivDir = ?config(priv_dir, Config), KnownHosts = filename:join(PrivDir, "known_hosts"), @@ -458,21 +356,25 @@ erlang_server_openssh_client_pulic_key_dsa(Config) when is_list(Config) -> {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, {public_key_alg, ssh_dsa}, {failfun, fun ssh_test_lib:failfun/2}]), - + ct:sleep(500), Cmd = "ssh -p " ++ integer_to_list(Port) ++ " -o UserKnownHostsFile=" ++ KnownHosts ++ " " ++ Host ++ " 1+1.", - SshPort = open_port({spawn, Cmd}, [binary]), + SshPort = open_port({spawn, Cmd}, [binary, stderr_to_stdout]), receive - {SshPort,{data, <<"2\n">>}} -> + {SshPort,{data, <<"2\n">>}} -> ok after ?TIMEOUT -> - ct:fail("Did not receive answer") + receive + X -> ct:fail("Received: ~p",[X]) + after 0 -> + ct:fail("Did not receive answer") + end end, - ssh:stop_daemon(Pid). + ssh:stop_daemon(Pid). %%-------------------------------------------------------------------- erlang_client_openssh_server_password() -> @@ -482,12 +384,12 @@ erlang_client_openssh_server_password(Config) when is_list(Config) -> UserDir = ?config(data_dir, Config), {error, Reason0} = ssh:connect(any, ?SSH_DEFAULT_PORT, [{silently_accept_hosts, true}, - {user, "foo"}, - {password, "morot"}, - {user_interaction, false}, - {user_dir, UserDir}]), + {user, "foo"}, + {password, "morot"}, + {user_interaction, false}, + {user_dir, UserDir}]), - ct:pal("Test of user foo that does not exist. " + ct:log("Test of user foo that does not exist. " "Error msg: ~p~n", [Reason0]), User = string:strip(os:cmd("whoami"), right, $\n), @@ -501,10 +403,10 @@ erlang_client_openssh_server_password(Config) when is_list(Config) -> {password, "foo"}, {user_interaction, false}, {user_dir, UserDir}]), - ct:pal("Test of wrong Pasword. " + ct:log("Test of wrong Pasword. " "Error msg: ~p~n", [Reason1]); _ -> - ct:pal("Whoami failed reason: ~n", []) + ct:log("Whoami failed reason: ~n", []) end. %%-------------------------------------------------------------------- @@ -532,21 +434,23 @@ erlang_client_openssh_server_nonexistent_subsystem(Config) when is_list(Config) receive_hej() -> receive <<"Hej", _binary>> = Hej -> - ct:pal("Expected result: ~p~n", [Hej]); + ct:log("Expected result: ~p~n", [Hej]); <<"Hej\n", _binary>> = Hej -> - ct:pal("Expected result: ~p~n", [Hej]); + ct:log("Expected result: ~p~n", [Hej]); <<"Hej\r\n", _/binary>> = Hej -> - ct:pal("Expected result: ~p~n", [Hej]); + ct:log("Expected result: ~p~n", [Hej]); Info -> Lines = binary:split(Info, [<<"\r\n">>], [global]), case lists:member(<<"Hej">>, Lines) of true -> - ct:pal("Expected result found in lines: ~p~n", [Lines]), + ct:log("Expected result found in lines: ~p~n", [Lines]), ok; false -> - ct:pal("Extra info: ~p~n", [Info]), + ct:log("Extra info: ~p~n", [Info]), receive_hej() end + after + 30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end. receive_logout() -> @@ -556,11 +460,15 @@ receive_logout() -> receive <<"Connection closed">> -> ok + after + 30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end; Info -> - ct:pal("Extra info when logging out: ~p~n", [Info]), + ct:log("Extra info when logging out: ~p~n", [Info]), receive_logout() - end. + after + 30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) + end. receive_normal_exit(Shell) -> receive @@ -570,6 +478,8 @@ receive_normal_exit(Shell) -> receive_normal_exit(Shell); Other -> ct:fail({unexpected_msg, Other}) + after + 30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end. extra_logout() -> @@ -581,26 +491,17 @@ extra_logout() -> end. %%-------------------------------------------------------------------- -%%-------------------------------------------------------------------- %% Check if we have a "newer" ssh client that supports these test cases -%%-------------------------------------------------------------------- check_ssh_client_support(Config) -> - Port = open_port({spawn, "ssh -Q cipher"}, [exit_status, stderr_to_stdout]), - case check_ssh_client_support2(Port) of - 0 -> % exit status from command (0 == ok) + case ssh_test_lib:ssh_client_supports_Q() of + true -> ssh:start(), Config; _ -> {skip, "test case not supported by ssh client"} end. -check_ssh_client_support2(P) -> - receive - {P, {data, _A}} -> - check_ssh_client_support2(P); - {P, {exit_status, E}} -> - E - after 5000 -> - ct:pal("Openssh command timed out ~n"), - -1 - end. +comment(AtomList) -> + ct:comment( + string:join(lists:map(fun erlang:atom_to_list/1, AtomList), + ", ")). diff --git a/lib/ssh/test/ssh_trpt_test_lib.erl b/lib/ssh/test/ssh_trpt_test_lib.erl new file mode 100644 index 0000000000..4269529ae8 --- /dev/null +++ b/lib/ssh/test/ssh_trpt_test_lib.erl @@ -0,0 +1,772 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-2015. 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(ssh_trpt_test_lib). + +%%-compile(export_all). + +-export([exec/1, exec/2, + instantiate/2, + format_msg/1, + server_host_port/1 + ] + ). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("ssh/src/ssh.hrl"). % ?UINT32, ?BYTE, #ssh{} ... +-include_lib("ssh/src/ssh_transport.hrl"). +-include_lib("ssh/src/ssh_auth.hrl"). + +%%%---------------------------------------------------------------- +-record(s, { + socket, + listen_socket, + opts = [], + timeout = 5000, % ms + seen_hello = false, + enc = <<>>, + ssh = #ssh{}, % #ssh{} + alg_neg = {undefined,undefined}, % {own_kexinit, peer_kexinit} + alg, % #alg{} + vars = dict:new(), + reply = [], % Some repy msgs are generated hidden in ssh_transport :[ + prints = [], + return_value + }). + +-define(role(S), ((S#s.ssh)#ssh.role) ). + + +server_host_port(S=#s{}) -> + {Host,Port} = ok(inet:sockname(S#s.listen_socket)), + {host(Host), Port}. + + +%%% Options: {print_messages, false} true|detail +%%% {print_seqnums,false} true +%%% {print_ops,false} true + +exec(L) -> exec(L, #s{}). + +exec(L, S) when is_list(L) -> lists:foldl(fun exec/2, S, L); + +exec(Op, S0=#s{}) -> + S1 = init_op_traces(Op, S0), + try seqnum_trace( + op(Op, S1)) + of + S = #s{} -> + case proplists:get_value(silent,S#s.opts) of + true -> ok; + _ -> print_traces(S) + end, + {ok,S} + catch + {fail,Reason,Se} -> + report_trace('', Reason, Se), + {error,{Op,Reason,Se}}; + + throw:Term -> + report_trace(throw, Term, S1), + throw(Term); + + error:Error -> + report_trace(error, Error, S1), + error(Error); + + exit:Exit -> + report_trace(exit, Exit, S1), + exit(Exit) + end; +exec(Op, {ok,S=#s{}}) -> exec(Op, S); +exec(_, Error) -> Error. + + +%%%---- Server ops +op(listen, S) when ?role(S) == undefined -> op({listen,0}, S); + +op({listen,Port}, S) when ?role(S) == undefined -> + S#s{listen_socket = ok(gen_tcp:listen(Port, mangle_opts([]))), + ssh = (S#s.ssh)#ssh{role=server} + }; + +op({accept,Opts}, S) when ?role(S) == server -> + {ok,Socket} = gen_tcp:accept(S#s.listen_socket, S#s.timeout), + {Host,_Port} = ok(inet:sockname(Socket)), + S#s{socket = Socket, + ssh = init_ssh(server,Socket,[{host,host(Host)}|Opts]), + return_value = ok}; + +%%%---- Client ops +op({connect,Host,Port,Opts}, S) when ?role(S) == undefined -> + Socket = ok(gen_tcp:connect(host(Host), Port, mangle_opts([]))), + S#s{socket = Socket, + ssh = init_ssh(client, Socket, [{host,host(Host)}|Opts]), + return_value = ok}; + +%%%---- ops for both client and server +op(close_socket, S) -> + catch tcp_gen:close(S#s.socket), + catch tcp_gen:close(S#s.listen_socket), + S#s{socket = undefined, + listen_socket = undefined, + return_value = ok}; + +op({set_options,Opts}, S) -> + S#s{opts = Opts}; + +op({send,X}, S) -> + send(S, instantiate(X,S)); + +op(receive_hello, S0) when S0#s.seen_hello =/= true -> + case recv(S0) of + S1=#s{return_value={hello,_}} -> S1; + S1=#s{} -> op(receive_hello, receive_wait(S1)) + end; + +op(receive_msg, S) when S#s.seen_hello == true -> + try recv(S) + catch + {tcp,Exc} -> + S1 = opt(print_messages, S, + fun(X) when X==true;X==detail -> {"Recv~n~p~n",[Exc]} end), + S1#s{return_value=Exc} + end; + + +op({expect,timeout,E}, S0) -> + try op(E, S0) + of + S=#s{} -> fail({expected,timeout,S#s.return_value}, S) + catch + {receive_timeout,_} -> S0#s{return_value=timeout} + end; + +op({match,M,E}, S0) -> + {Val,S2} = op_val(E, S0), + case match(M, Val, S2) of + {true,S3} -> + opt(print_ops,S3, + fun(true) -> + case dict:fold( + fun(K,V,Acc) -> + case dict:find(K,S0#s.vars) of + error -> [{K,V}|Acc]; + _ -> Acc + end + end, [], S3#s.vars) + of + [] -> {"Matches! No new bindings.",[]}; + New -> + Width = lists:max([length(atom_to_list(K)) || {K,_} <- New]), + {lists:flatten( + ["Matches! New bindings:~n" | + [io_lib:format(" ~*s = ~p~n",[Width,K,V]) || {K,V}<-New]]), + []} + end + end); + false -> + fail({expected,M,Val}, + opt(print_ops,S2,fun(true) -> {"nomatch!!~n",[]} end) + ) + end; + +op({print,E}, S0) -> + {Val,S} = op_val(E, S0), + io:format("Result of ~p ~p =~n~s~n",[?role(S0),E,format_msg(Val)]), + S; + +op(print_state, S) -> + io:format("State(~p)=~n~s~n",[?role(S), format_msg(S)]), + S; + +op('$$', S) -> + %% For matching etc + S. + + +op_val(E, S0) -> + case catch op(E, S0) of + {'EXIT',{function_clause,[{ssh_trpt_test_lib,op,[E,S0],_}|_]}} -> + {instantiate(E,S0), S0}; + S=#s{} -> + {S#s.return_value, S}; + F={fail,receive_timeout,_St} -> + throw(F) + end. + + +fail(Reason, {Fmt,Args}, S) when is_list(Fmt), is_list(Args) -> + fail(Reason, save_prints({Fmt,Args}, S)). + +fail(Reason, S) -> + throw({fail, Reason, S}). + +%%%---------------------------------------------------------------- +%% No optimizations :) + +match('$$', V, S) -> + match(S#s.return_value, V, S); + +match('_', _, S) -> + {true, S}; + +match({'or',[P]}, V, S) -> match(P,V,S); +match({'or',[Ph|Pt]}, V, S) -> + case match(Ph,V,S) of + false -> match({'or',Pt}, V, S); + {true,S} -> {true,S} + end; + +match(P, V, S) when is_atom(P) -> + case atom_to_list(P) of + "$"++_ -> + %% Variable + case dict:find(P,S#s.vars) of + {ok,Val} -> match(Val, V, S); + error -> {true,S#s{vars = dict:store(P,V,S#s.vars)}} + end; + _ when P==V -> + {true,S}; + _ -> + false + end; + +match(P, V, S) when P==V -> + {true, S}; + +match(P, V, S) when is_tuple(P), + is_tuple(V) -> + match(tuple_to_list(P), tuple_to_list(V), S); + +match([Hp|Tp], [Hv|Tv], S0) -> + case match(Hp, Hv, S0) of + {true,S} -> match(Tp, Tv, S); + false -> false + end; + +match(_, _, _) -> + false. + + + +instantiate('$$', S) -> + S#s.return_value; % FIXME: What if $$ or $... in return_value? + +instantiate(A, S) when is_atom(A) -> + case atom_to_list(A) of + "$"++_ -> + %% Variable + case dict:find(A,S#s.vars) of + {ok,Val} -> Val; % FIXME: What if $$ or $... in Val? + error -> throw({unbound,A}) + end; + _ -> + A + end; + +instantiate(T, S) when is_tuple(T) -> + list_to_tuple( instantiate(tuple_to_list(T),S) ); + +instantiate([H|T], S) -> + [instantiate(H,S) | instantiate(T,S)]; + +instantiate(X, _S) -> + X. + +%%%================================================================ +%%% +init_ssh(Role, Socket, Options0) -> + Options = [{user_interaction,false} + | Options0], + ssh_connection_handler:init_ssh(Role, + {2,0}, + lists:concat(["SSH-2.0-ErlangTestLib ",Role]), + Options, Socket). + +mangle_opts(Options) -> + SysOpts = [{reuseaddr, true}, + {active, false}, + {mode, binary} + ], + SysOpts ++ lists:foldl(fun({K,_},Opts) -> + lists:keydelete(K,1,Opts) + end, Options, SysOpts). + +host({0,0,0,0}) -> "localhost"; +host(H) -> H. + +%%%---------------------------------------------------------------- +send(S=#s{ssh=C}, hello) -> + Hello = case ?role(S) of + client -> C#ssh.c_version; + server -> C#ssh.s_version + end ++ "\r\n", + send(S, list_to_binary(Hello)); + +send(S0, ssh_msg_kexinit) -> + {Msg, _Bytes, _C0} = ssh_transport:key_exchange_init_msg(S0#s.ssh), + send(S0, Msg); + +send(S0=#s{alg_neg={undefined,PeerMsg}}, Msg=#ssh_msg_kexinit{}) -> + S1 = opt(print_messages, S0, + fun(X) when X==true;X==detail -> {"Send~n~s~n",[format_msg(Msg)]} end), + S2 = case PeerMsg of + #ssh_msg_kexinit{} -> + try ssh_transport:handle_kexinit_msg(PeerMsg, Msg, S1#s.ssh) of + {ok,Cx} when ?role(S1) == server -> + S1#s{alg = Cx#ssh.algorithms}; + {ok,_NextKexMsgBin,Cx} when ?role(S1) == client -> + S1#s{alg = Cx#ssh.algorithms} + catch + Class:Exc -> + save_prints({"Algoritm negotiation failed at line ~p:~p~n~p:~s~nPeer: ~s~n Own: ~s~n", + [?MODULE,?LINE,Class,format_msg(Exc),format_msg(PeerMsg),format_msg(Msg)]}, + S1) + end; + undefined -> + S1 + end, + {Bytes, C} = ssh_transport:ssh_packet(Msg, S2#s.ssh), + send_bytes(Bytes, S2#s{return_value = Msg, + alg_neg = {Msg,PeerMsg}, + ssh = C}); + +send(S0, ssh_msg_kexdh_init) when ?role(S0) == client -> + {OwnMsg, PeerMsg} = S0#s.alg_neg, + {ok, NextKexMsgBin, C} = + try ssh_transport:handle_kexinit_msg(PeerMsg, OwnMsg, S0#s.ssh) + catch + Class:Exc -> + fail("Algoritm negotiation failed!", + {"Algoritm negotiation failed at line ~p:~p~n~p:~s~nPeer: ~s~n Own: ~s", + [?MODULE,?LINE,Class,format_msg(Exc),format_msg(PeerMsg),format_msg(OwnMsg)]}, + S0) + end, + S = opt(print_messages, S0, + fun(X) when X==true;X==detail -> + #ssh{keyex_key = {{_Private, Public}, {_G, _P}}} = C, + Msg = #ssh_msg_kexdh_init{e = Public}, + {"Send (reconstructed)~n~s~n",[format_msg(Msg)]} + end), + send_bytes(NextKexMsgBin, S#s{ssh = C}); + +send(S0, ssh_msg_kexdh_reply) -> + Bytes = proplists:get_value(ssh_msg_kexdh_reply, S0#s.reply), + S = opt(print_messages, S0, + fun(X) when X==true;X==detail -> + {{_Private, Public}, _} = (S0#s.ssh)#ssh.keyex_key, + Msg = #ssh_msg_kexdh_reply{public_host_key = 'Key', + f = Public, + h_sig = 'H_SIG' + }, + {"Send (reconstructed)~n~s~n",[format_msg(Msg)]} + end), + send_bytes(Bytes, S#s{return_value = Bytes}); + +send(S0, Line) when is_binary(Line) -> + S = opt(print_messages, S0, + fun(X) when X==true;X==detail -> {"Send line~n~p~n",[Line]} end), + send_bytes(Line, S#s{return_value = Line}); + +send(S0, {special,Msg,PacketFun}) when is_tuple(Msg), + is_function(PacketFun,2) -> + S = opt(print_messages, S0, + fun(X) when X==true;X==detail -> {"Send~n~s~n",[format_msg(Msg)]} end), + {Packet, C} = PacketFun(Msg, S#s.ssh), + send_bytes(Packet, S#s{ssh = C, %%inc_send_seq_num(C), + return_value = Msg}); + +send(S0, Msg) when is_tuple(Msg) -> + S = opt(print_messages, S0, + fun(X) when X==true;X==detail -> {"Send~n~s~n",[format_msg(Msg)]} end), + {Packet, C} = ssh_transport:ssh_packet(Msg, S#s.ssh), + send_bytes(Packet, S#s{ssh = C, %%inc_send_seq_num(C), + return_value = Msg}). + +send_bytes(B, S0) -> + S = opt(print_messages, S0, fun(detail) -> {"Send bytes~n~p~n",[B]} end), + ok(gen_tcp:send(S#s.socket, B)), + S. + +%%%---------------------------------------------------------------- +recv(S0 = #s{}) -> + S1 = receive_poll(S0), + case S1#s.seen_hello of + {more,Seen} -> + %% Has received parts of a line. Has not seen a complete hello. + try_find_crlf(Seen, S1); + false -> + %% Must see hello before binary messages + try_find_crlf(<<>>, S1); + true -> + %% Has seen hello, therefore no more crlf-messages are alowed. + S = receive_binary_msg(S1), + case PeerMsg = S#s.return_value of + #ssh_msg_kexinit{} -> + case S#s.alg_neg of + {undefined,undefined} -> + S#s{alg_neg = {undefined,PeerMsg}}; + + {undefined,_} -> + fail("2 kexint received!!", S); + + {OwnMsg, _} -> + try ssh_transport:handle_kexinit_msg(PeerMsg, OwnMsg, S#s.ssh) of + {ok,C} when ?role(S) == server -> + S#s{alg_neg = {OwnMsg, PeerMsg}, + alg = C#ssh.algorithms, + ssh = C}; + {ok,_NextKexMsgBin,C} when ?role(S) == client -> + S#s{alg_neg = {OwnMsg, PeerMsg}, + alg = C#ssh.algorithms} + catch + Class:Exc -> + save_prints({"Algoritm negotiation failed at line ~p:~p~n~p:~s~nPeer: ~s~n Own: ~s~n", + [?MODULE,?LINE,Class,format_msg(Exc),format_msg(PeerMsg),format_msg(OwnMsg)]}, + S#s{alg_neg = {OwnMsg, PeerMsg}}) + end + end; + + #ssh_msg_kexdh_init{} -> % Always the server + {ok, Reply, C} = ssh_transport:handle_kexdh_init(PeerMsg, S#s.ssh), + S#s{ssh = C, + reply = [{ssh_msg_kexdh_reply,Reply} | S#s.reply] + }; + #ssh_msg_kexdh_reply{} -> + {ok, _NewKeys, C} = ssh_transport:handle_kexdh_reply(PeerMsg, S#s.ssh), + S#s{ssh=C#ssh{send_sequence=S#s.ssh#ssh.send_sequence}}; % Back the number + #ssh_msg_newkeys{} -> + {ok, C} = ssh_transport:handle_new_keys(PeerMsg, S#s.ssh), + S#s{ssh=C}; + _ -> + S + end + end. + +%%%================================================================ +try_find_crlf(Seen, S0) -> + case erlang:decode_packet(line,S0#s.enc,[]) of + {more,_} -> + Line = <<Seen/binary,(S0#s.enc)/binary>>, + S0#s{seen_hello = {more,Line}, + enc = <<>>, % didn't find a complete line + % -> no more characters to test + return_value = {more,Line} + }; + {ok,Used,Rest} -> + Line = <<Seen/binary,Used/binary>>, + case handle_hello(Line, S0) of + false -> + S = opt(print_messages, S0, + fun(X) when X==true;X==detail -> {"Recv info~n~p~n",[Line]} end), + S#s{seen_hello = false, + enc = Rest, + return_value = {info,Line}}; + S1=#s{} -> + S = opt(print_messages, S1, + fun(X) when X==true;X==detail -> {"Recv hello~n~p~n",[Line]} end), + S#s{seen_hello = true, + enc = Rest, + return_value = {hello,Line}} + end + end. + + +handle_hello(Bin, S=#s{ssh=C}) -> + case {ssh_transport:handle_hello_version(binary_to_list(Bin)), + ?role(S)} + of + {{undefined,_}, _} -> false; + {{Vp,Vs}, client} -> S#s{ssh = C#ssh{s_vsn=Vp, s_version=Vs}}; + {{Vp,Vs}, server} -> S#s{ssh = C#ssh{c_vsn=Vp, c_version=Vs}} + end. + +receive_binary_msg(S0=#s{ssh=C0=#ssh{decrypt_block_size = BlockSize, + recv_mac_size = MacSize + } + }) -> + case size(S0#s.enc) >= max(8,BlockSize) of + false -> + %% Need more bytes to decode the packet_length field + Remaining = max(8,BlockSize) - size(S0#s.enc), + receive_binary_msg( receive_wait(Remaining, S0) ); + true -> + %% Has enough bytes to decode the packet_length field + {_, <<?UINT32(PacketLen), _/binary>>, _} = + ssh_transport:decrypt_blocks(S0#s.enc, BlockSize, C0), % FIXME: BlockSize should be at least 4 + + %% FIXME: Check that ((4+PacketLen) rem BlockSize) == 0 ? + + S1 = if + PacketLen > ?SSH_MAX_PACKET_SIZE -> + fail({too_large_message,PacketLen},S0); % FIXME: disconnect + + ((4+PacketLen) rem BlockSize) =/= 0 -> + fail(bad_packet_length_modulo, S0); % FIXME: disconnect + + size(S0#s.enc) >= (4 + PacketLen + MacSize) -> + %% has the whole packet + S0; + + true -> + %% need more bytes to get have the whole packet + Remaining = (4 + PacketLen + MacSize) - size(S0#s.enc), + receive_wait(Remaining, S0) + end, + + %% Decrypt all, including the packet_length part (re-use the initial #ssh{}) + {C1, SshPacket = <<?UINT32(_),?BYTE(PadLen),Tail/binary>>, EncRest} = + ssh_transport:decrypt_blocks(S1#s.enc, PacketLen+4, C0), + + PayloadLen = PacketLen - 1 - PadLen, + <<CompressedPayload:PayloadLen/binary, _Padding:PadLen/binary>> = Tail, + + {C2, Payload} = ssh_transport:decompress(C1, CompressedPayload), + + <<Mac:MacSize/binary, Rest/binary>> = EncRest, + + case {ssh_transport:is_valid_mac(Mac, SshPacket, C2), + catch ssh_message:decode(set_prefix_if_trouble(Payload,S1))} + of + {false, _} -> fail(bad_mac,S1); + {_, {'EXIT',_}} -> fail(decode_failed,S1); + + {true, Msg} -> + C3 = case Msg of + #ssh_msg_kexinit{} -> + ssh_transport:key_init(opposite_role(C2), C2, Payload); + _ -> + C2 + end, + S2 = opt(print_messages, S1, + fun(X) when X==true;X==detail -> {"Recv~n~s~n",[format_msg(Msg)]} end), + S3 = opt(print_messages, S2, + fun(detail) -> {"decrypted bytes ~p~n",[SshPacket]} end), + S3#s{ssh = inc_recv_seq_num(C3), + enc = Rest, + return_value = Msg + } + end + end. + + +set_prefix_if_trouble(Msg = <<?BYTE(Op),_/binary>>, #s{alg=#alg{kex=Kex}}) + when Op == 30; + Op == 31 + -> + case catch atom_to_list(Kex) of + "ecdh-sha2-" ++ _ -> + <<"ecdh",Msg/binary>>; + "diffie-hellman-group-exchange-" ++ _ -> + <<"dh_gex",Msg/binary>>; + "diffie-hellman-group" ++ _ -> + <<"dh",Msg/binary>>; + _ -> + Msg + end; +set_prefix_if_trouble(Msg, _) -> + Msg. + + +receive_poll(S=#s{socket=Sock}) -> + inet:setopts(Sock, [{active,once}]), + receive + {tcp,Sock,Data} -> + receive_poll( S#s{enc = <<(S#s.enc)/binary,Data/binary>>} ); + {tcp_closed,Sock} -> + throw({tcp,tcp_closed}); + {tcp_error, Sock, Reason} -> + throw({tcp,{tcp_error,Reason}}) + after 0 -> + S + end. + +receive_wait(S=#s{socket=Sock, + timeout=Timeout}) -> + inet:setopts(Sock, [{active,once}]), + receive + {tcp,Sock,Data} -> + S#s{enc = <<(S#s.enc)/binary,Data/binary>>}; + {tcp_closed,Sock} -> + throw({tcp,tcp_closed}); + {tcp_error, Sock, Reason} -> + throw({tcp,{tcp_error,Reason}}) + after Timeout -> + fail(receive_timeout,S) + end. + +receive_wait(N, S=#s{socket=Sock, + timeout=Timeout, + enc=Enc0}) when N>0 -> + inet:setopts(Sock, [{active,once}]), + receive + {tcp,Sock,Data} -> + receive_wait(N-size(Data), S#s{enc = <<Enc0/binary,Data/binary>>}); + {tcp_closed,Sock} -> + throw({tcp,tcp_closed}); + {tcp_error, Sock, Reason} -> + throw({tcp,{tcp_error,Reason}}) + after Timeout -> + fail(receive_timeout, S) + end; +receive_wait(_N, S) -> + S. + +%% random_padding_len(PaddingLen1, ChunkSize) -> +%% MaxAdditionalRandomPaddingLen = % max 255 bytes padding totaö +%% (255 - PaddingLen1) - ((255 - PaddingLen1) rem ChunkSize), +%% AddLen0 = crypto:rand_uniform(0,MaxAdditionalRandomPaddingLen), +%% AddLen0 - (AddLen0 rem ChunkSize). % preserve the blocking + +inc_recv_seq_num(C=#ssh{recv_sequence=N}) -> C#ssh{recv_sequence=(N+1) band 16#ffffffff}. +%%%inc_send_seq_num(C=#ssh{send_sequence=N}) -> C#ssh{send_sequence=(N+1) band 16#ffffffff}. + +opposite_role(#ssh{role=R}) -> opposite_role(R); +opposite_role(client) -> server; +opposite_role(server) -> client. + +ok(ok) -> ok; +ok({ok,R}) -> R; +ok({error,E}) -> erlang:error(E). + + +%%%================================================================ +%%% +%%% Formating of records +%%% + +format_msg(M) -> format_msg(M, 0). + +format_msg(M, I0) -> + case fields(M) of + undefined -> io_lib:format('~p',[M]); + Fields -> + [Name|Args] = tuple_to_list(M), + Head = io_lib:format('#~p{',[Name]), + I = lists:flatlength(Head)+I0, + NL = io_lib:format('~n~*c',[I,$ ]), + Sep = io_lib:format(',~n~*c',[I,$ ]), + Tail = [begin + S0 = io_lib:format('~p = ',[F]), + I1 = I + lists:flatlength(S0), + [S0,format_msg(A,I1)] + end + || {F,A} <- lists:zip(Fields,Args)], + [[Head|string:join(Tail,Sep)],NL,"}"] + end. + +fields(M) -> + case M of + #ssh_msg_debug{} -> record_info(fields, ssh_msg_debug); + #ssh_msg_disconnect{} -> record_info(fields, ssh_msg_disconnect); + #ssh_msg_ignore{} -> record_info(fields, ssh_msg_ignore); + #ssh_msg_kex_dh_gex_group{} -> record_info(fields, ssh_msg_kex_dh_gex_group); + #ssh_msg_kex_dh_gex_init{} -> record_info(fields, ssh_msg_kex_dh_gex_init); + #ssh_msg_kex_dh_gex_reply{} -> record_info(fields, ssh_msg_kex_dh_gex_reply); + #ssh_msg_kex_dh_gex_request{} -> record_info(fields, ssh_msg_kex_dh_gex_request); + #ssh_msg_kex_dh_gex_request_old{} -> record_info(fields, ssh_msg_kex_dh_gex_request_old); + #ssh_msg_kexdh_init{} -> record_info(fields, ssh_msg_kexdh_init); + #ssh_msg_kexdh_reply{} -> record_info(fields, ssh_msg_kexdh_reply); + #ssh_msg_kexinit{} -> record_info(fields, ssh_msg_kexinit); + #ssh_msg_newkeys{} -> record_info(fields, ssh_msg_newkeys); + #ssh_msg_service_accept{} -> record_info(fields, ssh_msg_service_accept); + #ssh_msg_service_request{} -> record_info(fields, ssh_msg_service_request); + #ssh_msg_unimplemented{} -> record_info(fields, ssh_msg_unimplemented); + #ssh_msg_userauth_request{} -> record_info(fields, ssh_msg_userauth_request); + #ssh_msg_userauth_failure{} -> record_info(fields, ssh_msg_userauth_failure); + #ssh_msg_userauth_success{} -> record_info(fields, ssh_msg_userauth_success); + #ssh_msg_userauth_banner{} -> record_info(fields, ssh_msg_userauth_banner); + #ssh_msg_userauth_passwd_changereq{} -> record_info(fields, ssh_msg_userauth_passwd_changereq); + #ssh_msg_userauth_pk_ok{} -> record_info(fields, ssh_msg_userauth_pk_ok); + #ssh_msg_userauth_info_request{} -> record_info(fields, ssh_msg_userauth_info_request); + #ssh_msg_userauth_info_response{} -> record_info(fields, ssh_msg_userauth_info_response); + #s{} -> record_info(fields, s); + #ssh{} -> record_info(fields, ssh); + #alg{} -> record_info(fields, alg); + _ -> undefined + end. + +%%%================================================================ +%%% +%%% Trace handling +%%% + +init_op_traces(Op, S0) -> + opt(print_ops, S0#s{prints=[]}, + fun(true) -> + case ?role(S0) of + undefined -> {"-- ~p~n",[Op]}; + Role -> {"-- ~p ~p~n",[Role,Op]} + end + end + ). + +report_trace(Class, Term, S) -> + print_traces( + opt(print_ops, S, + fun(true) -> {"~s ~p",[Class,Term]} end) + ). + +seqnum_trace(S) -> + opt(print_seqnums, S, + fun(true) when S#s.ssh#ssh.send_sequence =/= S#s.ssh#ssh.send_sequence, + S#s.ssh#ssh.recv_sequence =/= S#s.ssh#ssh.recv_sequence -> + {"~p seq num: send ~p->~p, recv ~p->~p~n", + [?role(S), + S#s.ssh#ssh.send_sequence, S#s.ssh#ssh.send_sequence, + S#s.ssh#ssh.recv_sequence, S#s.ssh#ssh.recv_sequence + ]}; + (true) when S#s.ssh#ssh.send_sequence =/= S#s.ssh#ssh.send_sequence -> + {"~p seq num: send ~p->~p~n", + [?role(S), + S#s.ssh#ssh.send_sequence, S#s.ssh#ssh.send_sequence]}; + (true) when S#s.ssh#ssh.recv_sequence =/= S#s.ssh#ssh.recv_sequence -> + {"~p seq num: recv ~p->~p~n", + [?role(S), + S#s.ssh#ssh.recv_sequence, S#s.ssh#ssh.recv_sequence]} + end). + +print_traces(S) when S#s.prints == [] -> S; +print_traces(S) -> + Len = length(S#s.prints), + ct:log("~s", + [lists:foldl( + fun({Fmt,Args}, Acc) -> + [case Len-length(Acc)-1 of + 0 -> + io_lib:format(Fmt,Args); + _N -> + io_lib:format(lists:concat(['~p --------~n',Fmt]), + [Len-length(Acc)-1|Args]) + end | Acc] + end, "", S#s.prints)] + ). + +opt(Flag, S, Fun) when is_function(Fun,1) -> + try Fun(proplists:get_value(Flag,S#s.opts)) + of P={Fmt,Args} when is_list(Fmt), is_list(Args) -> + save_prints(P, S) + catch _:_ -> + S + end. + +save_prints({Fmt,Args}, S) -> + S#s{prints = [{Fmt,Args}|S#s.prints]}. diff --git a/lib/ssh/test/ssh_unicode_SUITE.erl b/lib/ssh/test/ssh_unicode_SUITE.erl deleted file mode 100644 index f0b97554b3..0000000000 --- a/lib/ssh/test/ssh_unicode_SUITE.erl +++ /dev/null @@ -1,589 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2014. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%% -%% %CopyrightEnd% -%% - -%% gerl +fnu -%% ct:run_test([{suite,"ssh_unicode_SUITE"}, {logdir,"LOG"}]). - --module(ssh_unicode_SUITE). - -%% Note: This directive should only be used in test suites. --compile(export_all). - --include_lib("common_test/include/ct.hrl"). --include_lib("kernel/include/file.hrl"). - -% Default timetrap timeout --define(default_timeout, ?t:minutes(1)). - --define(USER, "åke高兴"). --define(PASSWD, "ärlig日本じん"). --define('sftp.txt', "sftp瑞点.txt"). --define('test.txt', "testハンス.txt"). --define('link_test.txt', "link_test語.txt"). - --define(bindata, unicode:characters_to_binary("foobar å 一二三四いちにさんち") ). - --define(NEWLINE, <<"\r\n">>). - -%%-------------------------------------------------------------------- -%% Common Test interface functions ----------------------------------- -%%-------------------------------------------------------------------- - -%% suite() -> -%% [{ct_hooks,[ts_install_cth]}]. - -all() -> - [{group, sftp}, - {group, shell} - ]. - - -init_per_suite(Config) -> - catch crypto:stop(), - case {file:native_name_encoding(), (catch crypto:start())} of - {utf8, ok} -> - ssh:start(), - Config; - {utf8, _} -> - {skip,"Could not start crypto!"}; - _ -> - {skip,"Not unicode filename enabled emulator"} - end. - -end_per_suite(Config) -> - ssh:stop(), - crypto:stop(), - Config. - -%%-------------------------------------------------------------------- -groups() -> - [{shell, [], [shell_no_unicode, shell_unicode_string]}, - {sftp, [], [open_close_file, open_close_dir, read_file, read_dir, - write_file, rename_file, mk_rm_dir, remove_file, links, - retrieve_attributes, set_attributes, async_read, async_read_bin, - async_write - %% , position, pos_read, pos_write - ]}]. - -init_per_group(Group, Config) when Group==sftp - ; Group==shell -> - PrivDir = ?config(priv_dir, Config), - SysDir = ?config(data_dir, Config), - Sftpd = - ssh_test_lib:daemon([{system_dir, SysDir}, - {user_dir, PrivDir}, - {user_passwords, [{?USER, ?PASSWD}]}]), - [{group,Group}, {sftpd, Sftpd} | Config]; - -init_per_group(Group, Config) -> - [{group,Group} | Config]. - - -end_per_group(erlang_server, Config) -> - Config; -end_per_group(_, Config) -> - Config. - -%%-------------------------------------------------------------------- -init_per_testcase(_Case, Config) -> - prep(Config), - TmpConfig0 = lists:keydelete(watchdog, 1, Config), - TmpConfig = lists:keydelete(sftp, 1, TmpConfig0), - Dog = ct:timetrap(?default_timeout), - - case ?config(group, Config) of - sftp -> - {_Pid, Host, Port} = ?config(sftpd, Config), - {ok, ChannelPid, Connection} = - ssh_sftp:start_channel(Host, Port, - [{user, ?USER}, - {password, ?PASSWD}, - {user_interaction, false}, - {silently_accept_hosts, true}]), - Sftp = {ChannelPid, Connection}, - [{sftp, Sftp}, {watchdog, Dog} | TmpConfig]; - shell -> - UserDir = ?config(priv_dir, Config), - process_flag(trap_exit, true), - {_Pid, _Host, Port} = ?config(sftpd, Config), - ct:sleep(500), - IO = ssh_test_lib:start_io_server(), - Shell = ssh_test_lib:start_shell(Port, IO, UserDir, - [{silently_accept_hosts, true}, - {user,?USER},{password,?PASSWD}]), -%%ct:pal("IO=~p, Shell=~p, self()=~p",[IO,Shell,self()]), - wait_for_erlang_first_line([{io,IO}, {shell,Shell} | Config]) - end. - - -wait_for_erlang_first_line(Config) -> - receive - {'EXIT', _, _} -> - {fail,no_ssh_connection}; - <<"Eshell ",_/binary>> = ErlShellStart -> -%% ct:pal("Erlang shell start: ~p~n", [ErlShellStart]), - Config; - Other -> - ct:pal("Unexpected answer from ssh server: ~p",[Other]), - {fail,unexpected_answer} - after 10000 -> - ct:pal("No answer from ssh-server"), - {fail,timeout} - end. - - - -end_per_testcase(rename_file, Config) -> - PrivDir = ?config(priv_dir, Config), - NewFileName = filename:join(PrivDir, ?'test.txt'), - file:delete(NewFileName), - end_per_testcase(Config); -end_per_testcase(_TC, Config) -> - end_per_testcase(Config). - -end_per_testcase(Config) -> - catch exit(?config(shell,Config), kill), - case ?config(sftp, Config) of - {Sftp, Connection} -> - ssh_sftp:stop_channel(Sftp), - ssh:close(Connection); - _ -> - ok - end. - -%%-------------------------------------------------------------------- -%% Test Cases -------------------------------------------------------- - --define(chk_expected(Received,Expected), - (fun(R_,E_) when R_==E_ -> ok; - (R_,E_) -> ct:pal("Expected: ~p~nReceived: ~p~n", [E_,R_]), - E_ = R_ - end)(Received,Expected)). - --define(receive_chk(Ref,Expected), - (fun(E__) -> - receive - {async_reply, Ref, Received} when Received==E__ -> - ?chk_expected(Received, E__); - {async_reply, Ref, Received} when Received=/=E__ -> - ct:pal("Expected: ~p~nReceived: ~p~n", [E__,Received]), - E__ = Received; - Msg -> - ct:pal("Expected (Ref=~p): ~p", [Ref,E__]), - ct:fail(Msg) - end - end)(Expected)). - -%%-------------------------------------------------------------------- - - -open_close_file() -> - [{doc, "Test API functions open/3 and close/2"}]. -open_close_file(Config) when is_list(Config) -> - PrivDir = ?config(priv_dir, Config), - FileName = filename:join(PrivDir, ?'sftp.txt'), - {Sftp, _} = ?config(sftp, Config), - - lists:foreach( - fun(Mode) -> - ct:log("Mode: ~p",[Mode]), - %% list_dir(PrivDir), - ok = open_close_file(Sftp, FileName, Mode) - end, - [ - [read], - [write], - [write, creat], - [write, trunc], - [append], - [read, binary] - ]). - -open_close_file(Server, File, Mode) -> - {ok, Handle} = ssh_sftp:open(Server, File, Mode), - ok = ssh_sftp:close(Server, Handle). - -%%-------------------------------------------------------------------- -open_close_dir() -> - [{doc, "Test API functions opendir/2 and close/2"}]. -open_close_dir(Config) when is_list(Config) -> - PrivDir = ?config(priv_dir, Config), - {Sftp, _} = ?config(sftp, Config), - FileName = filename:join(PrivDir, ?'sftp.txt'), - - {ok, Handle} = ssh_sftp:opendir(Sftp, PrivDir), - ok = ssh_sftp:close(Sftp, Handle), - {error, _} = ssh_sftp:opendir(Sftp, FileName). - -%%-------------------------------------------------------------------- -read_file() -> - [{doc, "Test API funtion read_file/2"}]. -read_file(Config) when is_list(Config) -> - PrivDir = ?config(priv_dir, Config), - FileName = filename:join(PrivDir, ?'sftp.txt'), - {Sftp, _} = ?config(sftp, Config), - ?chk_expected(ssh_sftp:read_file(Sftp,FileName), file:read_file(FileName)). - -%%-------------------------------------------------------------------- -read_dir() -> - [{doc,"Test API function list_dir/2"}]. -read_dir(Config) when is_list(Config) -> - PrivDir = ?config(priv_dir, Config), - {Sftp, _} = ?config(sftp, Config), - {ok, Files} = ssh_sftp:list_dir(Sftp, PrivDir), - ct:pal("sftp list dir: ~ts~n", [Files]). - -%%-------------------------------------------------------------------- -write_file() -> - [{doc, "Test API function write_file/2"}]. -write_file(Config) when is_list(Config) -> - PrivDir = ?config(priv_dir, Config), - FileName = filename:join(PrivDir, ?'sftp.txt'), - {Sftp, _} = ?config(sftp, Config), - ok = ssh_sftp:write_file(Sftp, FileName, [?bindata]), - ?chk_expected(file:read_file(FileName), {ok,?bindata}). - -%%-------------------------------------------------------------------- -remove_file() -> - [{doc,"Test API function delete/2"}]. -remove_file(Config) when is_list(Config) -> - PrivDir = ?config(priv_dir, Config), - FileName = filename:join(PrivDir, ?'sftp.txt'), - {Sftp, _} = ?config(sftp, Config), - - {ok, Files} = ssh_sftp:list_dir(Sftp, PrivDir), - true = lists:member(filename:basename(FileName), Files), - ok = ssh_sftp:delete(Sftp, FileName), - {ok, NewFiles} = ssh_sftp:list_dir(Sftp, PrivDir), - false = lists:member(filename:basename(FileName), NewFiles), - {error, _} = ssh_sftp:delete(Sftp, FileName). -%%-------------------------------------------------------------------- -rename_file() -> - [{doc, "Test API function rename_file/2"}]. -rename_file(Config) when is_list(Config) -> - PrivDir = ?config(priv_dir, Config), - FileName = filename:join(PrivDir, ?'sftp.txt'), - NewFileName = filename:join(PrivDir, ?'test.txt'), - - {Sftp, _} = ?config(sftp, Config), - {ok, Files} = ssh_sftp:list_dir(Sftp, PrivDir), - ct:pal("FileName: ~ts~nFiles: ~ts~n", [FileName, [[$\n,$ ,F]||F<-Files] ]), - true = lists:member(filename:basename(FileName), Files), - false = lists:member(filename:basename(NewFileName), Files), - ok = ssh_sftp:rename(Sftp, FileName, NewFileName), - {ok, NewFiles} = ssh_sftp:list_dir(Sftp, PrivDir), - ct:pal("FileName: ~ts, Files: ~ts~n", [FileName, [[$\n,F]||F<-NewFiles] ]), - - false = lists:member(filename:basename(FileName), NewFiles), - true = lists:member(filename:basename(NewFileName), NewFiles). - -%%-------------------------------------------------------------------- -mk_rm_dir() -> - [{doc,"Test API functions make_dir/2, del_dir/2"}]. -mk_rm_dir(Config) when is_list(Config) -> - PrivDir = ?config(priv_dir, Config), - {Sftp, _} = ?config(sftp, Config), - - DirName = filename:join(PrivDir, "test"), - ok = ssh_sftp:make_dir(Sftp, DirName), - ok = ssh_sftp:del_dir(Sftp, DirName), - NewDirName = filename:join(PrivDir, "foo/bar"), - {error, _} = ssh_sftp:make_dir(Sftp, NewDirName), - {error, _} = ssh_sftp:del_dir(Sftp, PrivDir). - -%%-------------------------------------------------------------------- -links() -> - [{doc,"Tests API function make_symlink/3"}]. -links(Config) when is_list(Config) -> - case os:type() of - {win32, _} -> - {skip, "Links are not fully supported by windows"}; - _ -> - {Sftp, _} = ?config(sftp, Config), - PrivDir = ?config(priv_dir, Config), - FileName = filename:join(PrivDir, ?'sftp.txt'), - LinkFileName = filename:join(PrivDir, ?'link_test.txt'), - - ok = ssh_sftp:make_symlink(Sftp, LinkFileName, FileName), - {ok, FileName} = ssh_sftp:read_link(Sftp, LinkFileName) - end. - -%%-------------------------------------------------------------------- -retrieve_attributes() -> - [{doc, "Test API function read_file_info/3"}]. -retrieve_attributes(Config) when is_list(Config) -> - PrivDir = ?config(priv_dir, Config), - FileName = filename:join(PrivDir, ?'sftp.txt'), - - {Sftp, _} = ?config(sftp, Config), - {ok, FileInfo} = ssh_sftp:read_file_info(Sftp, FileName), - {ok, NewFileInfo} = file:read_file_info(FileName), - - %% TODO comparison. There are some differences now is that ok? - ct:pal("SFTP: ~p~nFILE: ~p~n", [FileInfo, NewFileInfo]). - -%%-------------------------------------------------------------------- -set_attributes() -> - [{doc,"Test API function write_file_info/3"}]. -set_attributes(Config) when is_list(Config) -> - PrivDir = ?config(priv_dir, Config), - FileName = filename:join(PrivDir, ?'test.txt'), - - {Sftp, _} = ?config(sftp, Config), - {ok,Fd} = file:open(FileName, write), - io:put_chars(Fd,"foo"), - ok = ssh_sftp:write_file_info(Sftp, FileName, #file_info{mode=8#400}), - {error, eacces} = file:write_file(FileName, "hello again"), - ssh_sftp:write_file_info(Sftp, FileName, #file_info{mode=8#600}), - ok = file:write_file(FileName, "hello again"). - -%%-------------------------------------------------------------------- - -async_read() -> - [{doc,"Test API aread/3"}]. -async_read(Config) when is_list(Config) -> - do_async_read(Config, false). - -async_read_bin() -> - [{doc,"Test API aread/3"}]. -async_read_bin(Config) when is_list(Config) -> - do_async_read(Config, true). - -do_async_read(Config, BinaryFlag) -> - {Sftp, _} = ?config(sftp, Config), - PrivDir = ?config(priv_dir, Config), - FileName = filename:join(PrivDir, ?'sftp.txt'), - {ok,ExpDataBin} = file:read_file(FileName), - ExpData = case BinaryFlag of - true -> ExpDataBin; - false -> binary_to_list(ExpDataBin) - end, - {ok, Handle} = ssh_sftp:open(Sftp, FileName, [read|case BinaryFlag of - true -> [binary]; - false -> [] - end]), - {async, Ref} = ssh_sftp:aread(Sftp, Handle, 20), - ?receive_chk(Ref, {ok,ExpData}). - -%%-------------------------------------------------------------------- -async_write() -> - [{doc,"Test API awrite/3"}]. -async_write(Config) when is_list(Config) -> - {Sftp, _} = ?config(sftp, Config), - PrivDir = ?config(priv_dir, Config), - FileName = filename:join(PrivDir, ?'test.txt'), - {ok, Handle} = ssh_sftp:open(Sftp, FileName, [write]), - Expected = ?bindata, - {async, Ref} = ssh_sftp:awrite(Sftp, Handle, Expected), - - receive - {async_reply, Ref, ok} -> - {ok, Data} = file:read_file(FileName), - ?chk_expected(Data, Expected); - Msg -> - ct:fail(Msg) - end. - -%%-------------------------------------------------------------------- - -position() -> - [{doc, "Test API functions position/3"}]. -position(Config) when is_list(Config) -> - PrivDir = ?config(priv_dir, Config), - FileName = filename:join(PrivDir, ?'test.txt'), - {Sftp, _} = ?config(sftp, Config), - - Data = list_to_binary("1234567890"), - ssh_sftp:write_file(Sftp, FileName, [Data]), - {ok, Handle} = ssh_sftp:open(Sftp, FileName, [read]), - - {ok, 3} = ssh_sftp:position(Sftp, Handle, {bof, 3}), - {ok, "4"} = ssh_sftp:read(Sftp, Handle, 1), - - {ok, 10} = ssh_sftp:position(Sftp, Handle, eof), - eof = ssh_sftp:read(Sftp, Handle, 1), - - {ok, 6} = ssh_sftp:position(Sftp, Handle, {bof, 6}), - {ok, "7"} = ssh_sftp:read(Sftp, Handle, 1), - - {ok, 9} = ssh_sftp:position(Sftp, Handle, {cur, 2}), - {ok, "0"} = ssh_sftp:read(Sftp, Handle, 1), - - {ok, 0} = ssh_sftp:position(Sftp, Handle, bof), - {ok, "1"} = ssh_sftp:read(Sftp, Handle, 1), - - {ok, 1} = ssh_sftp:position(Sftp, Handle, cur), - {ok, "2"} = ssh_sftp:read(Sftp, Handle, 1). - -%%-------------------------------------------------------------------- -pos_read() -> - [{doc,"Test API functions pread/3 and apread/3"}]. -pos_read(Config) when is_list(Config) -> - PrivDir = ?config(priv_dir, Config), - FileName = filename:join(PrivDir, ?'test.txt'), - {Sftp, _} = ?config(sftp, Config), - Data = ?bindata, - ssh_sftp:write_file(Sftp, FileName, [Data]), - - {ok, Handle} = ssh_sftp:open(Sftp, FileName, [read]), - {async, Ref} = ssh_sftp:apread(Sftp, Handle, {bof,5}, 4), - - ?receive_chk(Ref, {ok,binary_part(Data,5,4)}), - ?chk_expected(ssh_sftp:pread(Sftp,Handle,{bof,4},4), {ok,binary_part(Data,4,4)}). - - -%%-------------------------------------------------------------------- -pos_write() -> - [{doc,"Test API functions pwrite/4 and apwrite/4"}]. -pos_write(Config) when is_list(Config) -> - PrivDir = ?config(priv_dir, Config), - FileName = filename:join(PrivDir, ?'test.txt'), - {Sftp, _} = ?config(sftp, Config), - - {ok, Handle} = ssh_sftp:open(Sftp, FileName, [write]), - - Data = unicode:characters_to_list("再见"), - ssh_sftp:write_file(Sftp, FileName, [Data]), - - NewData = unicode:characters_to_list(" さようなら"), - {async, Ref} = ssh_sftp:apwrite(Sftp, Handle, {bof, 2}, NewData), - ?receive_chk(Ref, ok), - - ok = ssh_sftp:pwrite(Sftp, Handle, eof, unicode:characters_to_list(" adjö ")), - - ?chk_expected(ssh_sftp:read_file(Sftp,FileName), - {ok,unicode:characters_to_binary("再见 さようなら adjö ")}). - -%%-------------------------------------------------------------------- -sftp_nonexistent_subsystem() -> - [{doc, "Try to execute sftp subsystem on a server that does not support it"}]. -sftp_nonexistent_subsystem(Config) when is_list(Config) -> - {_,Host, Port} = ?config(sftpd, Config), - {error,"server failed to start sftp subsystem"} = - ssh_sftp:start_channel(Host, Port, - [{user_interaction, false}, - {user, ?USER}, - {password, ?PASSWD}, - {silently_accept_hosts, true}]). - -%%-------------------------------------------------------------------- -shell_no_unicode(Config) -> - do_shell(?config(io,Config), - [new_prompt, - {type,"io:format(\"hej ~p~n\",[42])."}, - {expect,"hej 42"} - ]). - -%%-------------------------------------------------------------------- -shell_unicode_string(Config) -> - do_shell(?config(io,Config), - [new_prompt, - {type,"io:format(\"こにちわ~ts~n\",[\"四二\"])."}, - {expect,"こにちわ四二"}, - {expect,"ok"} - ]). - -%%-------------------------------------------------------------------- -%% Internal functions ------------------------------------------------ -%%-------------------------------------------------------------------- -prep(Config) -> - PrivDir = ?config(priv_dir, Config), - TestFile = filename:join(PrivDir, ?'sftp.txt'), - TestFile1 = filename:join(PrivDir, ?'test.txt'), - TestLink = filename:join(PrivDir, ?'link_test.txt'), - - file:delete(TestFile), - file:delete(TestFile1), - file:delete(TestLink), - - %% Initial config - DataDir = ?config(data_dir, Config), - FileName = filename:join(DataDir, ?'sftp.txt'), - {ok,_BytesCopied} = file:copy(FileName, TestFile), - Mode = 8#00400 bor 8#00200 bor 8#00040, % read & write owner, read group - {ok, FileInfo} = file:read_file_info(TestFile), - ok = file:write_file_info(TestFile, - FileInfo#file_info{mode = Mode}). - - -%% list_dir(Dir) -> -%% ct:pal("prep/1: ls(~p):~n~p~n~ts",[Dir, file:list_dir(Dir), -%% begin -%% {ok,DL} = file:list_dir(Dir), -%% [[$\n|FN] || FN <- DL] -%% end]). - - -%%-------------------------------------------------------------------- -do_shell(IO, List) -> do_shell(IO, 0, List). - -do_shell(IO, N, [new_prompt|More]) -> - do_shell(IO, N+1, More); - -do_shell(IO, N, Ops=[{Order,Arg}|More]) -> - receive - X = <<"\r\n">> -> -%% ct:pal("Skip newline ~p",[X]), - do_shell(IO, N, Ops); - - <<P1,"> ">> when (P1-$0)==N -> - do_shell_prompt(IO, N, Order, Arg, More); - - <<P1,P2,"> ">> when (P1-$0)*10 + (P2-$0) == N -> - do_shell_prompt(IO, N, Order, Arg, More); - - Err when element(1,Err)==error -> - ct:fail("do_shell error: ~p~n",[Err]); - - RecBin when Order==expect ; Order==expect_echo -> -%% ct:pal("received ~p",[RecBin]), - RecStr = string:strip(unicode:characters_to_list(RecBin)), - ExpStr = string:strip(Arg), - case lists:prefix(ExpStr, RecStr) of - true when Order==expect -> - ct:pal("Matched ~ts",[RecStr]), - do_shell(IO, N, More); - true when Order==expect_echo -> - ct:pal("Matched echo ~ts",[RecStr]), - do_shell(IO, N, More); - false -> - ct:fail("*** Expected ~p, but got ~p",[string:strip(ExpStr),RecStr]) - end - after 10000 -> - case Order of - expect -> ct:fail("timeout, expected ~p",[string:strip(Arg)]); - type -> ct:fail("timeout, no prompt") - end - end; - -do_shell(_, _, []) -> - ok. - - -do_shell_prompt(IO, N, type, Str, More) -> -%% ct:pal("Matched prompt ~p to trigger sending of next line to server",[N]), - IO ! {input, self(), Str++"\r\n"}, - ct:pal("Promt '~p> ', Sent ~ts",[N,Str++"\r\n"]), - do_shell(IO, N, [{expect_echo,Str}|More]); % expect echo of the sent line -do_shell_prompt(IO, N, Op, Str, More) -> -%% ct:pal("Matched prompt ~p",[N]), - do_shell(IO, N, [{Op,Str}|More]). - -%%-------------------------------------------------------------------- diff --git a/lib/ssh/test/ssh_unicode_SUITE_data/sftp.txt b/lib/ssh/test/ssh_unicode_SUITE_data/sftp.txt deleted file mode 100644 index 3eaaddca21..0000000000 --- a/lib/ssh/test/ssh_unicode_SUITE_data/sftp.txt +++ /dev/null @@ -1 +0,0 @@ -åäöÅÄÖ瑞語 diff --git a/lib/ssh/test/ssh_unicode_SUITE_data/sftp瑞点.txt b/lib/ssh/test/ssh_unicode_SUITE_data/sftp瑞点.txt deleted file mode 100644 index 3eaaddca21..0000000000 --- a/lib/ssh/test/ssh_unicode_SUITE_data/sftp瑞点.txt +++ /dev/null @@ -1 +0,0 @@ -åäöÅÄÖ瑞語 diff --git a/lib/ssh/test/ssh_upgrade_SUITE.erl b/lib/ssh/test/ssh_upgrade_SUITE.erl index c0645f3b01..bf8874b118 100644 --- a/lib/ssh/test/ssh_upgrade_SUITE.erl +++ b/lib/ssh/test/ssh_upgrade_SUITE.erl @@ -38,6 +38,9 @@ %%% %%% CommonTest callbacks %%% +suite() -> + [{timetrap,{minutes,2}}]. + all() -> [ minor_upgrade, @@ -45,27 +48,17 @@ all() -> ]. init_per_suite(Config0) -> - catch crypto:stop(), - try {crypto:start(), erlang:system_info({wordsize, internal}) == - erlang:system_info({wordsize, external})} of - {ok, true} -> - case ct_release_test:init(Config0) of - {skip, Reason} -> - {skip, Reason}; - Config -> - ssh:start(), - Config - end; - {ok, false} -> - {skip, "Test server will not handle halfwordemulator correctly. Skip as halfwordemulator is deprecated"} - catch _:_ -> - {skip, "Crypto did not start"} + case ct_release_test:init(Config0) of + {skip, Reason} -> + {skip, Reason}; + Config -> + ssh:start(), + Config end. end_per_suite(Config) -> ct_release_test:cleanup(Config), ssh:stop(), - crypto:stop(), UserDir = ?config(priv_dir, Config), ssh_test_lib:clean_rsa(UserDir). @@ -94,8 +87,8 @@ minor_upgrade(Config) when is_list(Config) -> %%% Called by ct_release_test:upgrade/4 upgrade_init(CTData, State) -> {ok, AppUp={_, _, Up, _Down}} = ct_release_test:get_appup(CTData, ssh), - ct:pal("AppUp: ~p", [AppUp]), - ct:pal("Up: ~p", [Up]), + ct:log("AppUp: ~p", [AppUp]), + ct:log("Up: ~p", [Up]), case Soft = is_soft(Up) of %% It is symmetrical, if upgrade is soft so is downgrade true -> @@ -134,12 +127,12 @@ is_soft(_) -> test_hard(State0, FileName) -> - ct:pal("test_hard State0=~p, FileName=~p",[State0, FileName]), + ct:log("test_hard State0=~p, FileName=~p",[State0, FileName]), State = setup_server_client(State0), test_connection(FileName, random_contents(), State). test_soft(State0, FileName) -> - ct:pal("test_soft State0=~p, FileName=~p",[State0, FileName]), + ct:log("test_soft State0=~p, FileName=~p",[State0, FileName]), State = test_connection(FileName, random_contents(), State0), setup_server_client( close(State) ). @@ -171,7 +164,7 @@ setup_server_client(#state{config=Config} = State) -> test_connection(FileName, FileContents, #state{client = ChannelPid, root_dir = FtpRootDir} = State) -> - ct:pal("test_connection Writing with ssh_sftp:write_file",[]), + ct:log("test_connection Writing with ssh_sftp:write_file",[]), case ssh_sftp:write_file(ChannelPid, FileName, FileContents) of ok -> case ssh_sftp:read_file(ChannelPid, FileName) of diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk index cef9992f1b..c62faf8357 100644 --- a/lib/ssh/vsn.mk +++ b/lib/ssh/vsn.mk @@ -1,4 +1,5 @@ #-*-makefile-*- ; force emacs to enter makefile-mode -SSH_VSN = 4.0 +SSH_VSN = 4.2.2.2 + APP_VSN = "ssh-$(SSH_VSN)" diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml index b87b1b4fa7..1e8de1a8a3 100644 --- a/lib/ssl/doc/src/notes.xml +++ b/lib/ssl/doc/src/notes.xml @@ -26,7 +26,382 @@ <file>notes.xml</file> </header> <p>This document describes the changes made to the SSL application.</p> - <section><title>SSL 7.0</title> + + +<section><title>SSL 7.3.3.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The TLS/SSL protocol version selection for the SSL server + has been corrected to follow RFC 5246 Appendix E.1 + especially in case where the list of supported versions + has gaps. Now the server selects the highest protocol + version it supports that is not higher than what the + client supports.</p> + <p> + Own Id: OTP-13753 Aux Id: seq13150 </p> + </item> + </list> + </section> + +</section> + +<section><title>SSL 7.3.3</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Correct ssl:prf/5 to use the negotiated cipher suite's + prf function in ssl:prf/5 instead of the default prf.</p> + <p> + Own Id: OTP-13546</p> + </item> + <item> + <p> + Timeouts may have the value 0, guards have been corrected + to allow this</p> + <p> + Own Id: OTP-13635</p> + </item> + <item> + <p> + Change of internal handling of hash sign pairs as the + used one enforced to much restrictions making some valid + combinations unavailable.</p> + <p> + Own Id: OTP-13670</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Create a little randomness in sending of session + invalidation messages, to mitigate load when whole table + is invalidated.</p> + <p> + Own Id: OTP-13490</p> + </item> + </list> + </section> + +</section> + +<section><title>SSL 7.3.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Correct cipher suites conversion and gaurd expression. + Caused problems with GCM cipher suites and client side + option to set signature_algorithms extention values.</p> + <p> + Own Id: OTP-13525</p> + </item> + </list> + </section> + +</section> + +<section><title>SSL 7.3.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Corrections to cipher suite handling using the 3 and 4 + tuple format in addition to commit + 89d7e21cf4ae988c57c8ef047bfe85127875c70c</p> + <p> + Own Id: OTP-13511</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Make values for the TLS-1.2 signature_algorithms + extension configurable</p> + <p> + Own Id: OTP-13261</p> + </item> + </list> + </section> + +</section> + +<section><title>SSL 7.3</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Make sure there is only one poller validator at a time + for validating the session cache.</p> + <p> + Own Id: OTP-13185</p> + </item> + <item> + <p> + A timing related issue could cause ssl to hang, + especially happened with newer versions of OpenSSL in + combination with ECC ciphers.</p> + <p> + Own Id: OTP-13253</p> + </item> + <item> + <p> + Work around a race condition in the TLS distribution + start.</p> + <p> + Own Id: OTP-13268</p> + </item> + <item> + <p> + Big handshake messages are now correctly fragmented in + the TLS record layer.</p> + <p> + Own Id: OTP-13306</p> + </item> + <item> + <p> + Improve portability of ECC tests in Crypto and SSL for + "exotic" OpenSSL versions.</p> + <p> + Own Id: OTP-13311</p> + </item> + <item> + <p> + Certificate extensions marked as critical are ignored + when using verify_none</p> + <p> + Own Id: OTP-13377</p> + </item> + <item> + <p> + If a certificate doesn't contain a CRL Distribution + Points extension, and the relevant CRL is not in the + cache, and the <c>crl_check</c> option is not set to + <c>best_effort</c> , the revocation check should fail.</p> + <p> + Own Id: OTP-13378</p> + </item> + <item> + <p> + Enable TLS distribution over IPv6</p> + <p> + Own Id: OTP-13391</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Improve error reporting for TLS distribution</p> + <p> + Own Id: OTP-13219</p> + </item> + <item> + <p> + Include options from connect, listen and accept in + <c>connection_information/1,2</c></p> + <p> + Own Id: OTP-13232</p> + </item> + <item> + <p> + Allow adding extra options for outgoing TLS distribution + connections, as supported for plain TCP connections.</p> + <p> + Own Id: OTP-13285</p> + </item> + <item> + <p> + Use loopback as server option in TLS-distribution module</p> + <p> + Own Id: OTP-13300</p> + </item> + <item> + <p> + Verify certificate signature against original certificate + binary.</p> + <p> + This avoids bugs due to encoding errors when re-encoding + a decode certificate. As there exists several decode step + and using of different ASN.1 specification this is a risk + worth avoiding.</p> + <p> + Own Id: OTP-13334</p> + </item> + <item> + <p> + Use <c>application:ensure_all_started/2</c> instead of + hard-coding dependencies</p> + <p> + Own Id: OTP-13363</p> + </item> + </list> + </section> + +</section> + +<section><title>SSL 7.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Honor distribution port range options</p> + <p> + Own Id: OTP-12838</p> + </item> + <item> + <p> + Correct supervisor specification in TLS distribution.</p> + <p> + Own Id: OTP-13134</p> + </item> + <item> + <p> + Correct cache timeout</p> + <p> + Own Id: OTP-13141</p> + </item> + <item> + <p> + Avoid crash and restart of ssl process when key file does + not exist.</p> + <p> + Own Id: OTP-13144</p> + </item> + <item> + <p> + Enable passing of raw socket options on the format + {raw,_,_,_} to the underlying socket.</p> + <p> + Own Id: OTP-13166</p> + </item> + <item> + <p> + Hibernation with small or a zero timeout will now work as + expected</p> + <p> + Own Id: OTP-13189</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Add upper limit for session cache, configurable on ssl + application level.</p> + <p> + If upper limit is reached, invalidate the current cache + entries, e.i the session lifetime is the max time a + session will be keept, but it may be invalidated earlier + if the max limit for the table is reached. This will keep + the ssl manager process well behaved, not exhusting + memeory. Invalidating the entries will incrementally + empty the cache to make room for fresh sessions entries.</p> + <p> + Own Id: OTP-12392</p> + </item> + <item> + <p> + Use new time functions to measure passed time.</p> + <p> + Own Id: OTP-12457</p> + </item> + <item> + <p> + Improved error handling in TLS distribution</p> + <p> + Own Id: OTP-13142</p> + </item> + <item> + <p> + Distribution over TLS now honors the nodelay distribution + flag</p> + <p> + Own Id: OTP-13143</p> + </item> + </list> + </section> + +</section> + +<section><title>SSL 7.1</title> + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Add DER encoded ECPrivateKey as valid input format for + key option.</p> + <p> + Own Id: OTP-12974</p> + </item> + <item> + <p> + Correct return value of default session callback module</p> + <p> + This error had the symptom that the client check for + unique session would always fail, potentially making the + client session table grow a lot and causing long setup + times.</p> + <p> + Own Id: OTP-12980</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Add possibility to downgrade an SSL/TLS connection to a + tcp connection, and give back the socket control to a + user process.</p> + <p> + This also adds the possibility to specify a timeout to + the ssl:close function.</p> + <p> + Own Id: OTP-11397</p> + </item> + <item> + <p> + Add application setting to be able to change fatal alert + shutdown timeout, also shorten the default timeout. The + fatal alert timeout is the number of milliseconds between + sending of a fatal alert and closing the connection. + Waiting a little while improves the peers chances to + properly receiving the alert so it may shutdown + gracefully.</p> + <p> + Own Id: OTP-12832</p> + </item> + </list> + </section> + +</section> + +<section><title>SSL 7.0</title> <section><title>Fixed Bugs and Malfunctions</title> <list> @@ -51,12 +426,6 @@ <p> Own Id: OTP-12815</p> </item> - <item> - <p> - Gracefully ignore proprietary hash_sign algorithms</p> - <p> - Own Id: OTP-12829</p> - </item> </list> </section> @@ -107,6 +476,20 @@ </section> +<section><title>SSL 6.0.1.1</title> + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Gracefully ignore proprietary hash_sign algorithms</p> + <p> + Own Id: OTP-12829</p> + </item> + </list> + </section> +</section> + + <section><title>SSL 6.0.1</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml index f23b71e28b..e831f73530 100644 --- a/lib/ssl/doc/src/ssl.xml +++ b/lib/ssl/doc/src/ssl.xml @@ -31,37 +31,13 @@ <module>ssl</module> <modulesummary>Interface Functions for Secure Socket Layer</modulesummary> <description> - <p>This module contains interface functions for the SSL.</p> + <p> + This module contains interface functions for the SSL/TLS protocol. + For detailed information about the supported standards see + <seealso marker="ssl_app">ssl(6)</seealso>. + </p> </description> - - <section> - <title>SSL</title> - - <list type="bulleted"> - <item>For application dependencies see <seealso marker="ssl_app"> ssl(6)</seealso> </item> - <item>Supported SSL/TLS-versions are SSL-3.0, TLS-1.0, - TLS-1.1, and TLS-1.2.</item> - <item>For security reasons SSL-2.0 is not supported.</item> - <item>For security reasons SSL-3.0 is no longer supported by default, - but can be configured.</item> - <item>Ephemeral Diffie-Hellman cipher suites are supported, - but not Diffie Hellman Certificates cipher suites.</item> - <item>Elliptic Curve cipher suites are supported if the Crypto - application supports it and named curves are used. - </item> - <item>Export cipher suites are not supported as the - U.S. lifted its export restrictions in early 2000.</item> - <item>IDEA cipher suites are not supported as they have - become deprecated by the latest TLS specification so it is not - motivated to implement them.</item> - <item>CRL validation is supported.</item> - <item>Policy certificate extensions are not supported.</item> - <item>'Server Name Indication' extension client side - (RFC 6066, Section 3) is supported.</item> - </list> - - </section> - + <section> <title>DATA TYPES</title> <p>The following data types are used in the functions for SSL:</p> @@ -84,11 +60,12 @@ <seealso marker="kernel:gen_tcp">gen_tcp(3)</seealso> manual pages in Kernel.</p></item> - <tag><marker id="type-ssloption"></marker><c>ssloption() =</c></tag> + <tag><marker id="type-ssloption"/><c>ssloption() =</c></tag> <item> <p><c>{verify, verify_type()}</c></p> <p><c>| {verify_fun, {fun(), term()}}</c></p> - <p><c>| {fail_if_no_peer_cert, boolean()} {depth, integer()}</c></p> + <p><c>| {fail_if_no_peer_cert, boolean()}</c></p> + <p><c>| {depth, integer()}</c></p> <p><c>| {cert, public_key:der_encoded()}</c></p> <p><c>| {certfile, path()}</c></p> <p><c>| {key, {'RSAPrivateKey'| 'DSAPrivateKey' | 'ECPrivateKey' @@ -159,7 +136,7 @@ <tag><c>sslsocket() =</c></tag> <item><p>opaque()</p></item> - <tag><c>protocol() =</c></tag> + <tag><marker id="type-protocol"/><c>protocol() =</c></tag> <item><p><c>sslv3 | tlsv1 | 'tlsv1.1' | 'tlsv1.2'</c></p></item> <tag><c>ciphers() =</c></tag> @@ -167,7 +144,9 @@ <p>According to old API.</p></item> <tag><c>ciphersuite() =</c></tag> - <item><p><c>{key_exchange(), cipher(), hash()}</c></p></item> + + <item><p><c>{key_exchange(), cipher(), MAC::hash()} | + {key_exchange(), cipher(), MAC::hash(), PRF::hash()}</c></p></item> <tag><c>key_exchange()=</c></tag> <item><p><c>rsa | dhe_dss | dhe_rsa | dh_anon | psk | dhe_psk @@ -179,7 +158,7 @@ | aes_128_cbc | aes_256_cbc | aes_128_gcm | aes_256_gcm</c></p></item> <tag><c>hash() =</c></tag> - <item><p><c>md5 | sha</c></p></item> + <item><p><c>md5 | sha | sha224 | sha256 | sha348 | sha512</c></p></item> <tag><c>prf_random() =</c></tag> <item><p><c>client_random | server_random</c></p></item> @@ -244,7 +223,7 @@ <url href="http://www.ietf.org/rfc/rfc5746.txt">RFC 5746</url>. By default <c>secure_renegotiate</c> is set to <c>false</c>, that is, secure renegotiation is used if possible, - but it fallback to unsecure renegotiation if the peer + but it falls back to insecure renegotiation if the peer does not support <url href="http://www.ietf.org/rfc/rfc5746.txt">RFC 5746</url>.</p> </item> @@ -292,7 +271,11 @@ atom()}} | terminate regarding verification failures and the connection is established.</p></item> <item><p>If called with an extension unknown to the user application, - return value <c>{unknown, UserState}</c> is to be used.</p></item> + return value <c>{unknown, UserState}</c> is to be used.</p> + + <p>Note that if the fun returns <c>unknown</c> for an extension marked + as critical, validation will fail.</p> + </item> </list> <p>Default option <c>verify_fun</c> in <c>verify_peer mode</c>:</p> @@ -314,6 +297,8 @@ atom()}} | <code> {fun(_,{bad_cert, _}, UserState) -> {valid, UserState}; + (_,{extension, #'Extension'{critical = true}}, UserState) -> + {valid, UserState}; (_,{extension, _}, UserState) -> {unknown, UserState}; (_, valid, UserState) -> @@ -330,7 +315,7 @@ atom()}} | <tag><c>unknown_ca</c></tag> <item><p>No trusted CA was found in the trusted store. The trusted CA is normally a so called ROOT CA, which is a self-signed certificate. Trust can - be claimed for an intermediat CA (trusted anchor does not have to be + be claimed for an intermediate CA (trusted anchor does not have to be self-signed according to X-509) by using option <c>partial_chain</c>.</p> </item> @@ -375,7 +360,7 @@ marker="public_key:public_key#pkix_path_validation-3">public_key:pkix_path_valid <tag><c>{http, timeout()}</c></tag> <item><p> Enables fetching of CRLs specified as http URIs in<seealso - marker="public_key:public_key_records"> X509 cerificate extensions.</seealso> + marker="public_key:public_key_records"> X509 certificate extensions.</seealso> Requires the OTP inets application.</p> </item> </taglist> @@ -436,7 +421,6 @@ fun(srp, Username :: string(), UserState :: term()) -> <warning><p>Using <c>{padding_check, boolean()}</c> makes TLS vulnerable to the Poodle attack.</p></warning> - </section> <section> @@ -479,8 +463,8 @@ fun(srp, Username :: string(), UserState :: term()) -> <p>The negotiated protocol can be retrieved using the <c>negotiated_protocol/1</c> function.</p> </item> - <tag><c>{client_preferred_next_protocols, {Precedence :: server | client, ClientPrefs :: [binary()]}}</c></tag> - <tag><c>{client_preferred_next_protocols, {Precedence :: server | client, ClientPrefs :: [binary()], Default :: binary()}}</c></tag> + <tag><c>{client_preferred_next_protocols, {Precedence :: server | client, ClientPrefs :: [binary()]}}</c><br/> + <c>{client_preferred_next_protocols, {Precedence :: server | client, ClientPrefs :: [binary()], Default :: binary()}}</c></tag> <item> <p>Indicates that the client is to try to perform Next Protocol Negotiation.</p> @@ -537,10 +521,45 @@ fun(srp, Username :: string(), UserState :: term()) -> be supported by the server for the prevention to work. </p></warning> </item> - - </taglist> + <tag><marker id="client_signature_algs"/><c>{signature_algs, [{hash(), ecdsa | rsa | dsa}]}</c></tag> + <item> + <p>In addition to the algorithms negotiated by the cipher + suite used for key exchange, payload encryption, message + authentication and pseudo random calculation, the TLS signature + algorithm extension <url + href="http://www.ietf.org/rfc/rfc5246.txt">Section 7.4.1.4.1 in RFC 5246</url> may be + used, from TLS 1.2, to negotiate which signature algorithm to use during the + TLS handshake. If no lower TLS versions than 1.2 are supported, + the client will send a TLS signature algorithm extension + with the algorithms specified by this option. + Defaults to + + <code>[ +%% SHA2 +{sha512, ecdsa}, +{sha512, rsa}, +{sha384, ecdsa}, +{sha384, rsa}, +{sha256, ecdsa}, +{sha256, rsa}, +{sha224, ecdsa}, +{sha224, rsa}, +%% SHA +{sha, ecdsa}, +{sha, rsa}, +{sha, dsa}, +%% MD5 +{md5, rsa} +]</code> + + The algorithms should be in the preferred order. + Selected signature algorithm can restrict which hash functions + that may be selected. + </p> + </item> + </taglist> </section> - + <section> <title>SSL OPTION DESCRIPTIONS - SERVER SIDE</title> @@ -635,14 +654,14 @@ fun(srp, Username :: string(), UserState :: term()) -> <tag><c>{sni_hosts, [{hostname(), ssloptions()}]}</c></tag> <item><p>If the server receives a SNI (Server Name Indication) from the client - matching a host listed in the <c>sni_hosts</c> option, the speicific options for + matching a host listed in the <c>sni_hosts</c> option, the specific options for that host will override previously specified options. The option <c>sni_fun</c>, and <c>sni_hosts</c> are mutually exclusive.</p></item> <tag><c>{sni_fun, SNIfun::fun()}</c></tag> <item><p>If the server receives a SNI (Server Name Indication) from the client, - the given function will be called to retrive <c>ssloptions()</c> for indicated server. + the given function will be called to retrieve <c>ssloptions()</c> for the indicated server. These options will be merged into predefined <c>ssloptions()</c>. The function should be defined as: @@ -656,22 +675,25 @@ fun(srp, Username :: string(), UserState :: term()) -> of resources of such an operation is higher for the server than the client. This can act as a vector for denial of service attacks. The SSL application already takes measures to counter-act such attempts, - but client-initiated renegotiation can be stricly disabled by setting + but client-initiated renegotiation can be strictly disabled by setting this option to <c>false</c>. The default value is <c>true</c>. Note that disabling renegotiation can result in long-lived connections becoming unusable due to limits on the number of messages the underlying cipher suite can encipher. </item> - <tag><c>{psk_identity, string()}</c></tag> - <item>Specifies the server identity hint the server presents to the client. - </item> - <tag><c>{log_alert, boolean()}</c></tag> - <item>If false, error reports will not be displayed.</item> <tag><c>{honor_cipher_order, boolean()}</c></tag> <item>If true, use the server's preference for cipher selection. If false (the default), use the client's preference. </item> + + <tag><c>{signature_algs, [{hash(), ecdsa | rsa | dsa}]}</c></tag> + <item><p> The algorithms specified by + this option will be the ones accepted by the server in a signature algorithm + negotiation, introduced in TLS-1.2. The algorithms will also be offered to the client if a + client certificate is requested. For more details see the <seealso marker="#client_signature_algs">corresponding client option</seealso>. + </p> </item> + </taglist> </section> @@ -770,18 +792,20 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>connection_info(SslSocket) -> - {ok, {ProtocolVersion, CipherSuite}} | {error, Reason}</name> - <fsummary>Returns the Negotiated Protocol version and cipher suite. - </fsummary> + <name>close(SslSocket, How) -> ok | {ok, port()} | {error, Reason}</name> + <fsummary>Closes an SSL connection.</fsummary> <type> - <v>CipherSuite = ciphersuite()</v> - <v>ProtocolVersion = protocol()</v> + <v>SslSocket = sslsocket()</v> + <v>How = timeout() | {NewController::pid(), timeout()} </v> + <v>Reason = term()</v> </type> - <desc><p>Returns the Negotiated Protocol version and cipher suite.</p> + <desc><p>Closes or downgrades an SSL connection. In the latter case the transport + connection will be handed over to the <c>NewController</c> process after receiving + the TLS close alert from the peer. The returned transport socket will have + the following options set: <c>[{active, false}, {packet, 0}, {mode, binary}]</c></p> </desc> </func> - + <func> <name>controlling_process(SslSocket, NewOwner) -> ok | {error, Reason}</name> @@ -800,40 +824,36 @@ fun(srp, Username :: string(), UserState :: term()) -> <func> <name>connection_information(SslSocket) -> - {ok, Info} | {error, Reason} </name> + {ok, Result} | {error, Reason} </name> <fsummary>Returns all the connection information. </fsummary> <type> - <v>Info = [InfoTuple]</v> - <v>InfoTuple = {protocol, Protocol} | {cipher_suite, CipherSuite} | {sni_hostname, SNIHostname}</v> - <v>CipherSuite = ciphersuite()</v> - <v>ProtocolVersion = protocol()</v> - <v>SNIHostname = string()</v> + <v>Item = protocol | cipher_suite | sni_hostname | atom()</v> + <d>Meaningful atoms, not specified above, are the ssl option names.</d> + <v>Result = [{Item::atom(), Value::term()}]</v> <v>Reason = term()</v> </type> - <desc><p>Return all the connection information containing negotiated protocol version, cipher suite, and the hostname of SNI extension. - Info will be a proplists containing all the connection information on success, otherwise <c>{error, Reason}</c> will be returned.</p> + <desc><p>Returns all relevant information about the connection, ssl options that + are undefined will be filtered out.</p> </desc> </func> <func> <name>connection_information(SslSocket, Items) -> - {ok, Info} | {error, Reason} </name> + {ok, Result} | {error, Reason} </name> <fsummary>Returns the requested connection information. </fsummary> <type> - <v>Items = [Item]</v> - <v>Item = protocol | cipher_suite | sni_hostname</v> - <v>Info = [InfoTuple]</v> - <v>InfoTuple = {protocol, Protocol} | {cipher_suite, CipherSuite} | {sni_hostname, SNIHostname}</v> - <v>CipherSuite = ciphersuite()</v> - <v>ProtocolVersion = protocol()</v> - <v>SNIHostname = string()</v> + <v>Items = [Item]</v> + <v>Item = protocol | cipher_suite | sni_hostname | atom()</v> + <d>Meaningful atoms, not specified above, are the ssl option names.</d> + <v>Result = [{Item::atom(), Value::term()}]</v> <v>Reason = term()</v> </type> - <desc><p>Returns the connection information you requested. The connection information you can request contains protocol, cipher_suite, and sni_hostname. - <c>{ok, Info}</c> will be returned if it executes sucessfully. The Info is a proplists containing the information you requested. - Otherwise, <c>{error, Reason}</c> will be returned.</p> + <desc><p>Returns the requested information items about the connection, + if they are defined.</p> + <note><p>If only undefined options are requested the + resulting list can be empty.</p></note> </desc> </func> @@ -1160,7 +1180,7 @@ fun(srp, Username :: string(), UserState :: term()) -> <seealso marker="#listen-2"> listen/2</seealso>, and <seealso marker="#ssl_accept-2">ssl_accept/[1,2,3]</seealso>. For the negotiated TLS/SSL version, see <seealso - marker="#connection_info-1">ssl:connection_info/1 + marker="#connection_information-1">ssl:connection_information/1 </seealso>.</item> <tag><c>available</c></tag> diff --git a/lib/ssl/doc/src/ssl_app.xml b/lib/ssl/doc/src/ssl_app.xml index 2b6dc7e8be..6c82e32a74 100644 --- a/lib/ssl/doc/src/ssl_app.xml +++ b/lib/ssl/doc/src/ssl_app.xml @@ -33,7 +33,33 @@ <appsummary>The ssl application provides secure communication over sockets.</appsummary> - <description></description> + <description> + <p> + The ssl application is an implementation of the SSL/TLS protocol in Erlang. + </p> + <list type="bulleted"> + <item>Supported SSL/TLS-versions are SSL-3.0, TLS-1.0, + TLS-1.1, and TLS-1.2.</item> + <item>For security reasons SSL-2.0 is not supported.</item> + <item>For security reasons SSL-3.0 is no longer supported by default, + but can be configured.</item> + <item>Ephemeral Diffie-Hellman cipher suites are supported, + but not Diffie Hellman Certificates cipher suites.</item> + <item>Elliptic Curve cipher suites are supported if the Crypto + application supports it and named curves are used. + </item> + <item>Export cipher suites are not supported as the + U.S. lifted its export restrictions in early 2000.</item> + <item>IDEA cipher suites are not supported as they have + become deprecated by the latest TLS specification so it is not + motivated to implement them.</item> + <item>CRL validation is supported.</item> + <item>Policy certificate extensions are not supported.</item> + <item>'Server Name Indication' extension client side + (RFC 6066, Section 3) is supported.</item> + </list> + </description> + <section> <title>DEPENDENCIES</title> <p>The SSL application uses the <c>public_key</c> and @@ -58,7 +84,7 @@ <p><c>erl -ssl protocol_version "['tlsv1.2', 'tlsv1.1']"</c></p> <taglist> - <tag><c><![CDATA[protocol_version = <seealso marker="kernel:error_logger">ssl:protocol()</seealso> <optional>]]></c>.</tag> + <tag><c>protocol_version = </c><seealso marker="ssl#type-protocol">ssl:protocol()</seealso><c><![CDATA[<optional>]]></c></tag> <item><p>Protocol supported by started clients and servers. If this option is not set, it defaults to all protocols currently supported by the SSL application. @@ -66,17 +92,24 @@ to <c>ssl:connect/[2,3]</c> and <c>ssl:listen/2</c>.</p></item> <tag><c><![CDATA[session_lifetime = integer() <optional>]]></c></tag> - <item><p>Lifetime of the session data in seconds.</p></item> + <item><p>Maximum lifetime of the session data in seconds.</p></item> <tag><c><![CDATA[session_cb = atom() <optional>]]></c></tag> <item><p>Name of the session cache callback module that implements the <c>ssl_session_cache_api</c> behavior. Defaults to - <c>ssl_session_cache.erl</c>.</p></item> + <c>ssl_session_cache</c>.</p></item> <tag><c><![CDATA[session_cb_init_args = proplist:proplist() <optional>]]></c></tag> <item><p>List of extra user-defined arguments to the <c>init</c> function in the session cache callback module. Defaults to <c>[]</c>.</p></item> + + <tag><c><![CDATA[session_cache_client_max = integer() <optional>]]></c><br/> + <c><![CDATA[session_cache_server_max = integer() <optional>]]></c></tag> + <item><p>Limits the growth of the clients/servers session cache, + if the maximum number of sessions is reached, the current cache entries will + be invalidated regardless of their remaining lifetime. Defaults to 1000. + </p></item> <tag><c><![CDATA[ssl_pem_cache_clean = integer() <optional>]]></c></tag> <item> @@ -87,12 +120,26 @@ marker="ssl#clear_pem_cache-0">ssl:clear_pem_cache/0</seealso> </item> + <tag><c><![CDATA[alert_timeout = integer() <optional>]]></c></tag> + <item> + <p> + Number of milliseconds between sending of a fatal alert and + closing the connection. Waiting a little while improves the + peers chances to properly receiving the alert so it may + shutdown gracefully. Defaults to 5000 milliseconds. + </p> + </item> + + </taglist> </section> <section> <title>ERROR LOGGER AND EVENT HANDLERS</title> - <p>The SSL application uses the default <seealso marker="kernel:error_logger">OTP error logger</seealso> to log unexpected errors and TLS alerts. The logging of TLS alerts may be turned off with the <c>log_alert</c> option. </p> + <p>The SSL application uses the default <seealso + marker="kernel:error_logger">OTP error logger</seealso> to log + unexpected errors and TLS alerts. The logging of TLS alerts may be + turned off with the <c>log_alert</c> option. </p> </section> <section> diff --git a/lib/ssl/doc/src/ssl_crl_cache_api.xml b/lib/ssl/doc/src/ssl_crl_cache_api.xml index 71c1c61fe8..03ac010bfe 100644 --- a/lib/ssl/doc/src/ssl_crl_cache_api.xml +++ b/lib/ssl/doc/src/ssl_crl_cache_api.xml @@ -84,9 +84,9 @@ <v> CRLs = [<seealso marker="public_key:public_key">public_key:der_encoded()</seealso>] </v> </type> - <desc> <p>Lookup the CRLs belonging to the distribution point <c> Distributionpoint</c>. </p> + <desc> <p>Lookup the CRLs belonging to the distribution point <c> Distributionpoint</c>. This function may choose to only look in the cache or to follow distribution point - links depending on how the cache is administrated. + links depending on how the cache is administrated. </p> </desc> </func> @@ -103,4 +103,4 @@ </desc> </func> </funcs> -</erlref>
\ No newline at end of file +</erlref> diff --git a/lib/ssl/doc/src/ssl_distribution.xml b/lib/ssl/doc/src/ssl_distribution.xml index a347ce5ae6..dc04d446b0 100644 --- a/lib/ssl/doc/src/ssl_distribution.xml +++ b/lib/ssl/doc/src/ssl_distribution.xml @@ -271,4 +271,27 @@ Eshell V5.0 (abort with ^G) <p>The <c>init:get_arguments()</c> call verifies that the correct arguments are supplied to the emulator.</p> </section> + + <section> + <title>Using SSL distribution over IPv6</title> + <p>It is possible to use SSL distribution over IPv6 instead of + IPv4. To do this, pass the option <c>-proto_dist inet6_tls</c> + instead of <c>-proto_dist inet_tls</c> when starting Erlang, + either on the command line or in the <c>ERL_FLAGS</c> environment + variable.</p> + + <p>An example command line with this option would look like this:</p> + <code type="none"> +$ erl -boot /home/me/ssl/start_ssl -proto_dist inet6_tls + -ssl_dist_opt server_certfile "/home/me/ssl/erlserver.pem" + -ssl_dist_opt server_secure_renegotiate true client_secure_renegotiate true + -sname ssl_test +Erlang (BEAM) emulator version 5.0 [source] + +Eshell V5.0 (abort with ^G) +(ssl_test@myhost)1> </code> + + <p>A node started in this way will only be able to communicate with + other nodes using SSL distribution over IPv6.</p> + </section> </chapter> diff --git a/lib/ssl/doc/src/ssl_session_cache_api.xml b/lib/ssl/doc/src/ssl_session_cache_api.xml index bd9330056d..b85d8fb284 100644 --- a/lib/ssl/doc/src/ssl_session_cache_api.xml +++ b/lib/ssl/doc/src/ssl_session_cache_api.xml @@ -31,9 +31,13 @@ <module>ssl_session_cache_api</module> <modulesummary>TLS session cache API</modulesummary> - <description>Defines the API for the TLS session cache so - that the data storage scheme can be replaced by - defining a new callback module implementing this API.</description> + <description> + <p> + Defines the API for the TLS session cache so + that the data storage scheme can be replaced by + defining a new callback module implementing this API. + </p> + </description> <section> <title>DATA TYPES</title> diff --git a/lib/ssl/examples/src/client_server.erl b/lib/ssl/examples/src/client_server.erl index 799027123f..019b5130d2 100644 --- a/lib/ssl/examples/src/client_server.erl +++ b/lib/ssl/examples/src/client_server.erl @@ -26,9 +26,7 @@ start() -> %% Start ssl application - application:start(crypto), - application:start(public_key), - application:start(ssl), + {ok, StartedApps} = application:ensure_all_started(ssl), %% Let the current process be the server that listens and accepts %% Listen @@ -52,7 +50,8 @@ start() -> ssl:close(ASock), io:fwrite("Listen: closing and terminating.~n"), ssl:close(LSock), - application:stop(ssl). + + lists:foreach(fun application:stop/1, lists:reverse(StartedApps)). %% Client connect diff --git a/lib/ssl/src/Makefile b/lib/ssl/src/Makefile index 790328dc45..7a7a373487 100644 --- a/lib/ssl/src/Makefile +++ b/lib/ssl/src/Makefile @@ -51,6 +51,7 @@ MODULES= \ ssl_dist_sup\ ssl_sup \ inet_tls_dist \ + inet6_tls_dist \ ssl_certificate\ ssl_pkix_db\ ssl_cipher \ diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl index 78662e0ea2..e490de7eeb 100644 --- a/lib/ssl/src/dtls_connection.erl +++ b/lib/ssl/src/dtls_connection.erl @@ -145,7 +145,7 @@ init([Role, Host, Port, Socket, {SSLOpts0, _} = Options, User, CbInfo]) -> process_flag(trap_exit, true), State0 = initial_state(Role, Host, Port, Socket, Options, User, CbInfo), Handshake = ssl_handshake:init_handshake_history(), - TimeStamp = calendar:datetime_to_gregorian_seconds({date(), time()}), + TimeStamp = erlang:monotonic_time(), try ssl_config:init(SSLOpts0, Role) of {ok, Ref, CertDbHandle, FileRefHandle, CacheHandle, CRLDbInfo, OwnCert, Key, DHParams} -> Session = State0#state.session, @@ -196,8 +196,7 @@ hello(start, #state{host = Host, port = Port, role = client, {Record, State} = next_record(State1), next_state(hello, hello, Record, State); -hello(Hello = #client_hello{client_version = ClientVersion, - extensions = #hello_extensions{hash_signs = HashSigns}}, +hello(Hello = #client_hello{client_version = ClientVersion}, State = #state{connection_states = ConnectionStates0, port = Port, session = #session{own_certificate = Cert} = Session0, renegotiation = {Renegotiation, _}, @@ -209,9 +208,7 @@ hello(Hello = #client_hello{client_version = ClientVersion, {Version, {Type, Session}, ConnectionStates, #hello_extensions{ec_point_formats = EcPointFormats, - elliptic_curves = EllipticCurves} = ServerHelloExt} -> - HashSign = ssl_handshake:select_hashsign(HashSigns, Cert, - dtls_v1:corresponding_tls_version(Version)), + elliptic_curves = EllipticCurves} = ServerHelloExt, HashSign} -> ssl_connection:hello({common_client_hello, Type, ServerHelloExt, HashSign}, State#state{connection_states = ConnectionStates, negotiated_version = Version, diff --git a/lib/ssl/src/dtls_handshake.erl b/lib/ssl/src/dtls_handshake.erl index 22c0ce7a13..50c84b712f 100644 --- a/lib/ssl/src/dtls_handshake.erl +++ b/lib/ssl/src/dtls_handshake.erl @@ -94,7 +94,10 @@ hello(#server_hello{server_version = Version, random = Random, hello(#client_hello{client_version = ClientVersion}, _Options, {_,_,_,_,ConnectionStates,_}, _Renegotiation) -> %% Return correct typ to make dialyzer happy until we have time to make the real imp. - {ClientVersion, {new, #session{}}, ConnectionStates, #hello_extensions{}}. + HashSigns = tls_v1:default_signature_algs(dtls_v1:corresponding_tls_version(ClientVersion)), + {ClientVersion, {new, #session{}}, ConnectionStates, #hello_extensions{}, + %% Placeholder for real hasign handling + hd(HashSigns)}. %% hello(Address, Port, %% #ssl_tls{epoch = _Epoch, sequence_number = _Seq, diff --git a/lib/ssl/src/inet6_tls_dist.erl b/lib/ssl/src/inet6_tls_dist.erl new file mode 100644 index 0000000000..ffd7296f93 --- /dev/null +++ b/lib/ssl/src/inet6_tls_dist.erl @@ -0,0 +1,46 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2015. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(inet6_tls_dist). + +-export([childspecs/0, listen/1, accept/1, accept_connection/5, + setup/5, close/1, select/1]). + +childspecs() -> + inet_tls_dist:childspecs(). + +select(Node) -> + inet_tls_dist:gen_select(inet6_tcp, Node). + +listen(Name) -> + inet_tls_dist:gen_listen(inet6_tcp, Name). + +accept(Listen) -> + inet_tls_dist:gen_accept(inet6_tcp, Listen). + +accept_connection(AcceptPid, Socket, MyNode, Allowed, SetupTime) -> + inet_tls_dist:gen_accept_connection(inet6_tcp, AcceptPid, Socket, MyNode, Allowed, SetupTime). + +setup(Node, Type, MyNode, LongOrShortNames,SetupTime) -> + inet_tls_dist:gen_setup(inet6_tcp, Node, Type, MyNode, LongOrShortNames,SetupTime). + +close(Socket) -> + inet_tls_dist:close(Socket). diff --git a/lib/ssl/src/inet_tls_dist.erl b/lib/ssl/src/inet_tls_dist.erl index b6e62a18c9..ec26142a75 100644 --- a/lib/ssl/src/inet_tls_dist.erl +++ b/lib/ssl/src/inet_tls_dist.erl @@ -24,18 +24,28 @@ -export([childspecs/0, listen/1, accept/1, accept_connection/5, setup/5, close/1, select/1, is_node_name/1]). +%% Generalized dist API +-export([gen_listen/2, gen_accept/2, gen_accept_connection/6, + gen_setup/6, gen_select/2]). + -include_lib("kernel/include/net_address.hrl"). -include_lib("kernel/include/dist.hrl"). -include_lib("kernel/include/dist_util.hrl"). childspecs() -> {ok, [{ssl_dist_sup,{ssl_dist_sup, start_link, []}, - permanent, 2000, worker, [ssl_dist_sup]}]}. + permanent, infinity, supervisor, [ssl_dist_sup]}]}. select(Node) -> + gen_select(inet_tcp, Node). + +gen_select(Driver, Node) -> case split_node(atom_to_list(Node), $@, []) of - [_,_Host] -> - true; + [_, Host] -> + case inet:getaddr(Host, Driver:family()) of + {ok, _} -> true; + _ -> false + end; _ -> false end. @@ -46,23 +56,35 @@ is_node_name(_) -> false. listen(Name) -> - ssl_tls_dist_proxy:listen(Name). + gen_listen(inet_tcp, Name). + +gen_listen(Driver, Name) -> + ssl_tls_dist_proxy:listen(Driver, Name). accept(Listen) -> - ssl_tls_dist_proxy:accept(Listen). + gen_accept(inet_tcp, Listen). + +gen_accept(Driver, Listen) -> + ssl_tls_dist_proxy:accept(Driver, Listen). accept_connection(AcceptPid, Socket, MyNode, Allowed, SetupTime) -> + gen_accept_connection(inet_tcp, AcceptPid, Socket, MyNode, Allowed, SetupTime). + +gen_accept_connection(Driver, AcceptPid, Socket, MyNode, Allowed, SetupTime) -> Kernel = self(), - spawn_link(fun() -> do_accept(Kernel, AcceptPid, Socket, + spawn_link(fun() -> do_accept(Driver, Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) end). setup(Node, Type, MyNode, LongOrShortNames,SetupTime) -> + gen_setup(inet_tcp, Node, Type, MyNode, LongOrShortNames,SetupTime). + +gen_setup(Driver, Node, Type, MyNode, LongOrShortNames,SetupTime) -> Kernel = self(), - spawn_opt(fun() -> do_setup(Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) end, [link, {priority, max}]). + spawn_opt(fun() -> do_setup(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) end, [link, {priority, max}]). -do_setup(Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) -> - [Name, Address] = splitnode(Node, LongOrShortNames), - case inet:getaddr(Address, inet) of +do_setup(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) -> + [Name, Address] = splitnode(Driver, Node, LongOrShortNames), + case inet:getaddr(Address, Driver:family()) of {ok, Ip} -> Timer = dist_util:start_timer(SetupTime), case erl_epmd:port_please(Name, Ip) of @@ -70,41 +92,41 @@ do_setup(Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) -> ?trace("port_please(~p) -> version ~p~n", [Node,Version]), dist_util:reset_timer(Timer), - case ssl_tls_dist_proxy:connect(Ip, TcpPort) of + case ssl_tls_dist_proxy:connect(Driver, Ip, TcpPort) of {ok, Socket} -> HSData = connect_hs_data(Kernel, Node, MyNode, Socket, Timer, Version, Ip, TcpPort, Address, Type), dist_util:handshake_we_started(HSData); - _ -> + Other -> %% Other Node may have closed since %% port_please ! ?trace("other node (~p) " "closed since port_please.~n", [Node]), - ?shutdown(Node) + ?shutdown2(Node, {shutdown, {connect_failed, Other}}) end; - _ -> + Other -> ?trace("port_please (~p) " "failed.~n", [Node]), - ?shutdown(Node) + ?shutdown2(Node, {shutdown, {port_please_failed, Other}}) end; - _Other -> + Other -> ?trace("inet_getaddr(~p) " "failed (~p).~n", [Node,Other]), - ?shutdown(Node) + ?shutdown2(Node, {shutdown, {inet_getaddr_failed, Other}}) end. close(Socket) -> gen_tcp:close(Socket), ok. -do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) -> +do_accept(Driver, Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) -> process_flag(priority, max), receive {AcceptPid, controller} -> Timer = dist_util:start_timer(SetupTime), - case check_ip(Socket) of + case check_ip(Driver, Socket) of true -> HSData = accept_hs_data(Kernel, MyNode, Socket, Timer, Allowed), dist_util:handshake_other_started(HSData); @@ -118,12 +140,12 @@ do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) -> %% Do only accept new connection attempts from nodes at our %% own LAN, if the check_ip environment parameter is true. %% ------------------------------------------------------------ -check_ip(Socket) -> +check_ip(Driver, Socket) -> case application:get_env(check_ip) of {ok, true} -> case get_ifs(Socket) of {ok, IFs, IP} -> - check_ip(IFs, IP); + check_ip(Driver, IFs, IP); _ -> ?shutdown(no_node) end; @@ -142,37 +164,21 @@ get_ifs(Socket) -> Error end. -check_ip([{OwnIP, _, Netmask}|IFs], PeerIP) -> - case {mask(Netmask, PeerIP), mask(Netmask, OwnIP)} of +check_ip(Driver, [{OwnIP, _, Netmask}|IFs], PeerIP) -> + case {Driver:mask(Netmask, PeerIP), Driver:mask(Netmask, OwnIP)} of {M, M} -> true; _ -> check_ip(IFs, PeerIP) end; -check_ip([], PeerIP) -> +check_ip(_Driver, [], PeerIP) -> {false, PeerIP}. -mask({M1,M2,M3,M4}, {IP1,IP2,IP3,IP4}) -> - {M1 band IP1, - M2 band IP2, - M3 band IP3, - M4 band IP4}; - -mask({M1,M2,M3,M4, M5, M6, M7, M8}, {IP1,IP2,IP3,IP4, IP5, IP6, IP7, IP8}) -> - {M1 band IP1, - M2 band IP2, - M3 band IP3, - M4 band IP4, - M5 band IP5, - M6 band IP6, - M7 band IP7, - M8 band IP8}. - %% If Node is illegal terminate the connection setup!! -splitnode(Node, LongOrShortNames) -> +splitnode(Driver, Node, LongOrShortNames) -> case split_node(atom_to_list(Node), $@, []) of [Name|Tail] when Tail =/= [] -> Host = lists:append(Tail), - check_node(Name, Node, Host, LongOrShortNames); + check_node(Driver, Name, Node, Host, LongOrShortNames); [_] -> error_logger:error_msg("** Nodename ~p illegal, no '@' character **~n", [Node]), @@ -182,15 +188,20 @@ splitnode(Node, LongOrShortNames) -> ?shutdown(Node) end. -check_node(Name, Node, Host, LongOrShortNames) -> +check_node(Driver, Name, Node, Host, LongOrShortNames) -> case split_node(Host, $., []) of [_] when LongOrShortNames == longnames -> - error_logger:error_msg("** System running to use " - "fully qualified " - "hostnames **~n" - "** Hostname ~s is illegal **~n", - [Host]), - ?shutdown(Node); + case Driver:parse_address(Host) of + {ok, _} -> + [Name, Host]; + _ -> + error_logger:error_msg("** System running to use " + "fully qualified " + "hostnames **~n" + "** Hostname ~s is illegal **~n", + [Host]), + ?shutdown(Node) + end; [_, _ | _] when LongOrShortNames == shortnames -> error_logger:error_msg("** System NOT running to use fully qualified " "hostnames **~n" diff --git a/lib/ssl/src/ssl.app.src b/lib/ssl/src/ssl.app.src index be8ef6f85f..1a2bf90ccf 100644 --- a/lib/ssl/src/ssl.app.src +++ b/lib/ssl/src/ssl.app.src @@ -31,6 +31,7 @@ ssl_listen_tracker_sup, %% Erlang Distribution over SSL/TLS inet_tls_dist, + inet6_tls_dist, ssl_tls_dist_proxy, ssl_dist_sup, %% SSL/TLS session handling @@ -54,6 +55,6 @@ {env, []}, {mod, {ssl_app, []}}, {runtime_dependencies, ["stdlib-2.0","public_key-1.0","kernel-3.0", - "erts-6.0","crypto-3.3", "inets-5.10.7"]}]}. + "erts-7.0","crypto-3.3", "inets-5.10.7"]}]}. diff --git a/lib/ssl/src/ssl.appup.src b/lib/ssl/src/ssl.appup.src index 1476336039..203a4f7d10 100644 --- a/lib/ssl/src/ssl.appup.src +++ b/lib/ssl/src/ssl.appup.src @@ -1,12 +1,20 @@ %% -*- erlang -*- {"%VSN%", [ + {<<"^7[.]3[.]3$">>, + [{load_module, ssl_handshake, soft_purge, soft_purge, []} + ]}, + {<<"^7[.][^.].*">>, [{restart_application, ssl}]}, {<<"6\\..*">>, [{restart_application, ssl}]}, {<<"5\\..*">>, [{restart_application, ssl}]}, {<<"4\\..*">>, [{restart_application, ssl}]}, {<<"3\\..*">>, [{restart_application, ssl}]} ], [ + {<<"^7[.]3[.]3$">>, + [{load_module, ssl_handshake, soft_purge, soft_purge, []} + ]}, + {<<"^7[.][^.].*">>, [{restart_application, ssl}]}, {<<"6\\..*">>, [{restart_application, ssl}]}, {<<"5\\..*">>, [{restart_application, ssl}]}, {<<"4\\..*">>, [{restart_application, ssl}]}, diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index 9f2af73204..97a1e2b5a8 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -34,10 +34,10 @@ listen/2, transport_accept/1, transport_accept/2, ssl_accept/1, ssl_accept/2, ssl_accept/3, controlling_process/2, peername/1, peercert/1, sockname/1, - close/1, shutdown/2, recv/2, recv/3, send/2, getopts/2, setopts/2 + close/1, close/2, shutdown/2, recv/2, recv/3, send/2, getopts/2, setopts/2 ]). %% SSL/TLS protocol handling --export([cipher_suites/0, cipher_suites/1, suite_definition/1, +-export([cipher_suites/0, cipher_suites/1, connection_info/1, versions/0, session_info/1, format_error/1, renegotiate/1, prf/5, negotiated_protocol/1, negotiated_next_protocol/1, connection_information/1, connection_information/2]). @@ -60,22 +60,19 @@ -spec start() -> ok | {error, reason()}. -spec start(permanent | transient | temporary) -> ok | {error, reason()}. %% -%% Description: Utility function that starts the ssl, -%% crypto and public_key applications. Default type -%% is temporary. see application(3) +%% Description: Utility function that starts the ssl and applications +%% that it depends on. +%% see application(3) %%-------------------------------------------------------------------- start() -> - application:start(crypto), - application:start(asn1), - application:start(public_key), - application:start(ssl). - + start(temporary). start(Type) -> - application:start(crypto, Type), - application:start(asn1), - application:start(public_key, Type), - application:start(ssl, Type). - + case application:ensure_all_started(ssl, Type) of + {ok, _} -> + ok; + Other -> + Other + end. %%-------------------------------------------------------------------- -spec stop() -> ok. %% @@ -99,12 +96,13 @@ stop() -> connect(Socket, SslOptions) when is_port(Socket) -> connect(Socket, SslOptions, infinity). -connect(Socket, SslOptions0, Timeout) when is_port(Socket) -> +connect(Socket, SslOptions0, Timeout) when is_port(Socket), + (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) -> {Transport,_,_,_} = proplists:get_value(cb_info, SslOptions0, {gen_tcp, tcp, tcp_closed, tcp_error}), EmulatedOptions = ssl_socket:emulated_options(), {ok, SocketValues} = ssl_socket:getopts(Transport, Socket, EmulatedOptions), - try handle_options(SslOptions0 ++ SocketValues) of + try handle_options(SslOptions0 ++ SocketValues, client) of {ok, #config{transport_info = CbInfo, ssl = SslOptions, emulated = EmOpts, connection_cb = ConnectionCb}} -> @@ -125,8 +123,8 @@ connect(Socket, SslOptions0, Timeout) when is_port(Socket) -> connect(Host, Port, Options) -> connect(Host, Port, Options, infinity). -connect(Host, Port, Options, Timeout) -> - try handle_options(Options) of +connect(Host, Port, Options, Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) -> + try handle_options(Options, client) of {ok, Config} -> do_connect(Host,Port,Config,Timeout) catch @@ -144,7 +142,7 @@ listen(_Port, []) -> {error, nooptions}; listen(Port, Options0) -> try - {ok, Config} = handle_options(Options0), + {ok, Config} = handle_options(Options0, server), ConnectionCb = connection_cb(Options0), #config{transport_info = {Transport, _, _, _}, inet_user = Options, connection_cb = ConnectionCb, ssl = SslOpts, emulated = EmOpts} = Config, @@ -175,7 +173,7 @@ transport_accept(#sslsocket{pid = {ListenSocket, #config{transport_info = {Transport,_,_, _} =CbInfo, connection_cb = ConnectionCb, ssl = SslOpts, - emulated = Tracker}}}, Timeout) -> + emulated = Tracker}}}, Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) -> case Transport:accept(ListenSocket, Timeout) of {ok, Socket} -> {ok, EmOpts} = ssl_socket:get_emulated_opts(Tracker), @@ -208,29 +206,31 @@ transport_accept(#sslsocket{pid = {ListenSocket, ssl_accept(ListenSocket) -> ssl_accept(ListenSocket, infinity). -ssl_accept(#sslsocket{} = Socket, Timeout) -> +ssl_accept(#sslsocket{} = Socket, Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) -> ssl_connection:handshake(Socket, Timeout); - -ssl_accept(ListenSocket, SslOptions) when is_port(ListenSocket) -> + +ssl_accept(ListenSocket, SslOptions) when is_port(ListenSocket) -> ssl_accept(ListenSocket, SslOptions, infinity). -ssl_accept(#sslsocket{} = Socket, [], Timeout) -> +ssl_accept(#sslsocket{} = Socket, [], Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity)-> ssl_accept(#sslsocket{} = Socket, Timeout); -ssl_accept(#sslsocket{fd = {_, _, _, Tracker}} = Socket, SslOpts0, Timeout) -> - try - {ok, EmOpts, InheritedSslOpts} = ssl_socket:get_all_opts(Tracker), +ssl_accept(#sslsocket{fd = {_, _, _, Tracker}} = Socket, SslOpts0, Timeout) when + (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity)-> + try + {ok, EmOpts, InheritedSslOpts} = ssl_socket:get_all_opts(Tracker), SslOpts = handle_options(SslOpts0, InheritedSslOpts), ssl_connection:handshake(Socket, {SslOpts, emulated_socket_options(EmOpts, #socket_options{})}, Timeout) catch Error = {error, _Reason} -> Error end; -ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket) -> +ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket), + (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) -> {Transport,_,_,_} = proplists:get_value(cb_info, SslOptions, {gen_tcp, tcp, tcp_closed, tcp_error}), EmulatedOptions = ssl_socket:emulated_options(), {ok, SocketValues} = ssl_socket:getopts(Transport, Socket, EmulatedOptions), ConnetionCb = connection_cb(SslOptions), - try handle_options(SslOptions ++ SocketValues) of + try handle_options(SslOptions ++ SocketValues, server) of {ok, #config{transport_info = CbInfo, ssl = SslOpts, emulated = EmOpts}} -> ok = ssl_socket:setopts(Transport, Socket, ssl_socket:internal_inet_values()), {ok, Port} = ssl_socket:port(Transport, Socket), @@ -247,11 +247,27 @@ ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket) -> %% Description: Close an ssl connection %%-------------------------------------------------------------------- close(#sslsocket{pid = Pid}) when is_pid(Pid) -> - ssl_connection:close(Pid); + ssl_connection:close(Pid, {close, ?DEFAULT_TIMEOUT}); close(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport,_, _, _}}}}) -> Transport:close(ListenSocket). %%-------------------------------------------------------------------- +-spec close(#sslsocket{}, timeout() | {pid(), integer()}) -> term(). +%% +%% Description: Close an ssl connection +%%-------------------------------------------------------------------- +close(#sslsocket{pid = TLSPid}, + {Pid, Timeout} = DownGrade) when is_pid(TLSPid), + is_pid(Pid), + (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) -> + ssl_connection:close(TLSPid, {close, DownGrade}); +close(#sslsocket{pid = TLSPid}, Timeout) when is_pid(TLSPid), + (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) -> + ssl_connection:close(TLSPid, {close, Timeout}); +close(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport,_, _, _}}}}, _) -> + Transport:close(ListenSocket). + +%%-------------------------------------------------------------------- -spec send(#sslsocket{}, iodata()) -> ok | {error, reason()}. %% %% Description: Sends data over the ssl connection @@ -269,7 +285,8 @@ send(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport, _, _, _} %%-------------------------------------------------------------------- recv(Socket, Length) -> recv(Socket, Length, infinity). -recv(#sslsocket{pid = Pid}, Length, Timeout) when is_pid(Pid) -> +recv(#sslsocket{pid = Pid}, Length, Timeout) when is_pid(Pid), + (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity)-> ssl_connection:recv(Pid, Length, Timeout); recv(#sslsocket{pid = {Listen, #config{transport_info = {Transport, _, _, _}}}}, _,_) when is_port(Listen)-> @@ -295,24 +312,32 @@ controlling_process(#sslsocket{pid = {Listen, %% %% Description: Return SSL information for the connection %%-------------------------------------------------------------------- -connection_information(#sslsocket{pid = Pid}) when is_pid(Pid) -> ssl_connection:connection_information(Pid); -connection_information(#sslsocket{pid = {Listen, _}}) when is_port(Listen) -> {error, enotconn}. - +connection_information(#sslsocket{pid = Pid}) when is_pid(Pid) -> + case ssl_connection:connection_information(Pid) of + {ok, Info} -> + {ok, [Item || Item = {_Key, Value} <- Info, Value =/= undefined]}; + Error -> + Error + end; +connection_information(#sslsocket{pid = {Listen, _}}) when is_port(Listen) -> + {error, enotconn}. %%-------------------------------------------------------------------- --spec connection_information(#sslsocket{}, [atom]) -> {ok, list()} | {error, reason()}. +-spec connection_information(#sslsocket{}, [atom()]) -> {ok, list()} | {error, reason()}. %% %% Description: Return SSL information for the connection %%-------------------------------------------------------------------- connection_information(#sslsocket{} = SSLSocket, Items) -> case connection_information(SSLSocket) of - {ok, I} -> - {ok, lists:filter(fun({K, _}) -> lists:foldl(fun(K1, Acc) when K1 =:= K -> Acc + 1; (_, Acc) -> Acc end, 0, Items) > 0 end, I)}; - E -> - E + {ok, Info} -> + {ok, [Item || Item = {Key, Value} <- Info, lists:member(Key, Items), + Value =/= undefined]}; + Error -> + Error end. %%-------------------------------------------------------------------- +%% Deprecated -spec connection_info(#sslsocket{}) -> {ok, {tls_record:tls_atom_version(), ssl_cipher:erl_cipher_suite()}} | {error, reason()}. %% @@ -352,15 +377,6 @@ peercert(#sslsocket{pid = {Listen, _}}) when is_port(Listen) -> {error, enotconn}. %%-------------------------------------------------------------------- --spec suite_definition(ssl_cipher:cipher_suite()) -> ssl_cipher:erl_cipher_suite(). -%% -%% Description: Return erlang cipher suite definition. -%%-------------------------------------------------------------------- -suite_definition(S) -> - {KeyExchange, Cipher, Hash, _} = ssl_cipher:suite_definition(S), - {KeyExchange, Cipher, Hash}. - -%%-------------------------------------------------------------------- -spec negotiated_protocol(#sslsocket{}) -> {ok, binary()} | {error, reason()}. %% %% Description: Returns the protocol that has been negotiated. If no @@ -390,7 +406,7 @@ negotiated_next_protocol(Socket) -> %%-------------------------------------------------------------------- cipher_suites(erlang) -> Version = tls_record:highest_protocol_version([]), - ssl_cipher:filter_suites([suite_definition(S) + ssl_cipher:filter_suites([ssl_cipher:erl_suite_definition(S) || S <- ssl_cipher:suites(Version)]); cipher_suites(openssl) -> Version = tls_record:highest_protocol_version([]), @@ -398,7 +414,7 @@ cipher_suites(openssl) -> || S <- ssl_cipher:filter_suites(ssl_cipher:suites(Version))]; cipher_suites(all) -> Version = tls_record:highest_protocol_version([]), - ssl_cipher:filter_suites([suite_definition(S) + ssl_cipher:filter_suites([ssl_cipher:erl_suite_definition(S) || S <-ssl_cipher:all_suites(Version)]). cipher_suites() -> cipher_suites(erlang). @@ -610,7 +626,8 @@ handle_options(Opts0, #ssl_options{protocol = Protocol, cacerts = CaCerts0, cacertfile = CaCertFile0} = InheritedSslOpts) -> RecordCB = record_cb(Protocol), CaCerts = handle_option(cacerts, Opts0, CaCerts0), - {Verify, FailIfNoPeerCert, CaCertDefault, VerifyFun, PartialChainHanlder} = handle_verify_options(Opts0, CaCerts), + {Verify, FailIfNoPeerCert, CaCertDefault, VerifyFun, PartialChainHanlder, + VerifyClientOnce} = handle_verify_options(Opts0, CaCerts), CaCertFile = case proplists:get_value(cacertfile, Opts0, CaCertFile0) of undefined -> CaCertDefault; @@ -623,11 +640,12 @@ handle_options(Opts0, #ssl_options{protocol = Protocol, cacerts = CaCerts0, verify = Verify, verify_fun = VerifyFun, partial_chain = PartialChainHanlder, - fail_if_no_peer_cert = FailIfNoPeerCert}, + fail_if_no_peer_cert = FailIfNoPeerCert, + verify_client_once = VerifyClientOnce}, SslOpts1 = lists:foldl(fun(Key, PropList) -> proplists:delete(Key, PropList) end, Opts0, [cacerts, cacertfile, verify, verify_fun, partial_chain, - fail_if_no_peer_cert]), + fail_if_no_peer_cert, verify_client_once]), case handle_option(versions, SslOpts1, []) of [] -> new_ssl_options(SslOpts1, NewVerifyOpts, RecordCB); @@ -635,10 +653,10 @@ handle_options(Opts0, #ssl_options{protocol = Protocol, cacerts = CaCerts0, Versions = [RecordCB:protocol_version(Vsn) || Vsn <- Value], new_ssl_options(proplists:delete(versions, SslOpts1), NewVerifyOpts#ssl_options{versions = Versions}, record_cb(Protocol)) - end. + end; %% Handle all options in listen and connect -handle_options(Opts0) -> +handle_options(Opts0, Role) -> Opts = proplists:expand([{binary, [{mode, binary}]}, {list, [{mode, list}]}], Opts0), assert_proplist(Opts), @@ -647,7 +665,7 @@ handle_options(Opts0) -> ReuseSessionFun = fun(_, _, _, _) -> true end, CaCerts = handle_option(cacerts, Opts, undefined), - {Verify, FailIfNoPeerCert, CaCertDefault, VerifyFun, PartialChainHanlder} = + {Verify, FailIfNoPeerCert, CaCertDefault, VerifyFun, PartialChainHanlder, VerifyClientOnce} = handle_verify_options(Opts, CaCerts), CertFile = handle_option(certfile, Opts, <<>>), @@ -666,7 +684,7 @@ handle_options(Opts0) -> verify_fun = VerifyFun, partial_chain = PartialChainHanlder, fail_if_no_peer_cert = FailIfNoPeerCert, - verify_client_once = handle_option(verify_client_once, Opts, false), + verify_client_once = VerifyClientOnce, depth = handle_option(depth, Opts, 1), cert = handle_option(cert, Opts, undefined), certfile = CertFile, @@ -682,11 +700,17 @@ handle_options(Opts0) -> srp_identity = handle_option(srp_identity, Opts, undefined), ciphers = handle_cipher_option(proplists:get_value(ciphers, Opts, []), RecordCb:highest_protocol_version(Versions)), + signature_algs = handle_hashsigns_option(proplists:get_value(signature_algs, Opts, + default_option_role(server, + tls_v1:default_signature_algs(Versions), Role)), + RecordCb:highest_protocol_version(Versions)), %% Server side option reuse_session = handle_option(reuse_session, Opts, ReuseSessionFun), reuse_sessions = handle_option(reuse_sessions, Opts, true), secure_renegotiate = handle_option(secure_renegotiate, Opts, false), - client_renegotiation = handle_option(client_renegotiation, Opts, true), + client_renegotiation = handle_option(client_renegotiation, Opts, + default_option_role(server, true, Role), + server, Role), renegotiate_at = handle_option(renegotiate_at, Opts, ?DEFAULT_RENEGOTIATE_AT), hibernate_after = handle_option(hibernate_after, Opts, undefined), erl_dist = handle_option(erl_dist, Opts, false), @@ -703,10 +727,16 @@ handle_options(Opts0) -> server_name_indication = handle_option(server_name_indication, Opts, undefined), sni_hosts = handle_option(sni_hosts, Opts, []), sni_fun = handle_option(sni_fun, Opts, undefined), - honor_cipher_order = handle_option(honor_cipher_order, Opts, false), + honor_cipher_order = handle_option(honor_cipher_order, Opts, + default_option_role(server, false, Role), + server, Role), protocol = proplists:get_value(protocol, Opts, tls), padding_check = proplists:get_value(padding_check, Opts, true), - fallback = proplists:get_value(fallback, Opts, false), + fallback = handle_option(fallback, Opts, + proplists:get_value(fallback, Opts, + default_option_role(client, + false, Role)), + client, Role), crl_check = handle_option(crl_check, Opts, false), crl_cache = handle_option(crl_cache, Opts, {ssl_crl_cache, {internal, []}}) }, @@ -723,7 +753,7 @@ handle_options(Opts0) -> alpn_preferred_protocols, next_protocols_advertised, client_preferred_next_protocols, log_alert, server_name_indication, honor_cipher_order, padding_check, crl_check, crl_cache, - fallback], + fallback, signature_algs], SockOpts = lists:foldl(fun(Key, PropList) -> proplists:delete(Key, PropList) @@ -736,6 +766,13 @@ handle_options(Opts0) -> inet_user = SockOpts, transport_info = CbInfo, connection_cb = ConnetionCb }}. + + +handle_option(OptionName, Opts, Default, Role, Role) -> + handle_option(OptionName, Opts, Default); +handle_option(_, _, undefined = Value, _, _) -> + Value. + handle_option(sni_fun, Opts, Default) -> OptFun = validate_option(sni_fun, proplists:get_value(sni_fun, Opts, Default)), @@ -752,7 +789,6 @@ handle_option(OptionName, Opts, Default) -> validate_option(OptionName, proplists:get_value(OptionName, Opts, Default)). - validate_option(versions, Versions) -> validate_versions(Versions, Versions); validate_option(verify, Value) @@ -804,6 +840,7 @@ validate_option(key, {KeyType, Value}) when is_binary(Value), KeyType == dsa; %% Backwards compatibility KeyType == 'RSAPrivateKey'; KeyType == 'DSAPrivateKey'; + KeyType == 'ECPrivateKey'; KeyType == 'PrivateKeyInfo' -> {KeyType, Value}; @@ -956,6 +993,18 @@ validate_option(crl_cache, {Cb, {_Handle, Options}} = Value) when is_atom(Cb) an validate_option(Opt, Value) -> throw({error, {options, {Opt, Value}}}). +handle_hashsigns_option(Value, {Major, Minor} = Version) when is_list(Value) + andalso Major >= 3 andalso Minor >= 3-> + case tls_v1:signature_algs(Version, Value) of + [] -> + throw({error, {options, no_supported_algorithms, {signature_algs, Value}}}); + _ -> + Value + end; +handle_hashsigns_option(_, {Major, Minor} = Version) when Major >= 3 andalso Minor >= 3-> + handle_hashsigns_option(tls_v1:default_signature_algs(Version), Version); +handle_hashsigns_option(_, _Version) -> + undefined. validate_options([]) -> []; @@ -1056,10 +1105,7 @@ binary_cipher_suites(Version, []) -> %% Defaults to all supported suites that does %% not require explicit configuration ssl_cipher:filter_suites(ssl_cipher:suites(Version)); -binary_cipher_suites(Version, [{_,_,_,_}| _] = Ciphers0) -> %% Backwards compatibility - Ciphers = [{KeyExchange, Cipher, Hash} || {KeyExchange, Cipher, Hash, _} <- Ciphers0], - binary_cipher_suites(Version, Ciphers); -binary_cipher_suites(Version, [{_,_,_}| _] = Ciphers0) -> +binary_cipher_suites(Version, [Tuple|_] = Ciphers0) when is_tuple(Tuple) -> Ciphers = [ssl_cipher:suite(C) || C <- Ciphers0], binary_cipher_suites(Version, Ciphers); @@ -1169,6 +1215,8 @@ assert_proplist([]) -> assert_proplist([{Key,_} | Rest]) when is_atom(Key) -> assert_proplist(Rest); %% Handle exceptions +assert_proplist([{raw,_,_,_} | Rest]) -> + assert_proplist(Rest); assert_proplist([inet | Rest]) -> assert_proplist(Rest); assert_proplist([inet6 | Rest]) -> @@ -1193,7 +1241,8 @@ emulated_socket_options(InetValues, #socket_options{ new_ssl_options([], #ssl_options{} = Opts, _) -> Opts; new_ssl_options([{verify_client_once, Value} | Rest], #ssl_options{} = Opts, RecordCB) -> - new_ssl_options(Rest, Opts#ssl_options{verify_client_once = validate_option(verify_client_once, Value)}, RecordCB); + new_ssl_options(Rest, Opts#ssl_options{verify_client_once = + validate_option(verify_client_once, Value)}, RecordCB); new_ssl_options([{depth, Value} | Rest], #ssl_options{} = Opts, RecordCB) -> new_ssl_options(Rest, Opts#ssl_options{depth = validate_option(depth, Value)}, RecordCB); new_ssl_options([{cert, Value} | Rest], #ssl_options{} = Opts, RecordCB) -> @@ -1249,6 +1298,13 @@ new_ssl_options([{server_name_indication, Value} | Rest], #ssl_options{} = Opts, new_ssl_options(Rest, Opts#ssl_options{server_name_indication = validate_option(server_name_indication, Value)}, RecordCB); new_ssl_options([{honor_cipher_order, Value} | Rest], #ssl_options{} = Opts, RecordCB) -> new_ssl_options(Rest, Opts#ssl_options{honor_cipher_order = validate_option(honor_cipher_order, Value)}, RecordCB); +new_ssl_options([{signature_algs, Value} | Rest], #ssl_options{} = Opts, RecordCB) -> + new_ssl_options(Rest, + Opts#ssl_options{signature_algs = + handle_hashsigns_option(Value, + RecordCB:highest_protocol_version())}, + RecordCB); + new_ssl_options([{Key, Value} | _Rest], #ssl_options{}, _) -> throw({error, {options, {Key, Value}}}). @@ -1257,6 +1313,12 @@ handle_verify_options(Opts, CaCerts) -> DefaultVerifyNoneFun = {fun(_,{bad_cert, _}, UserState) -> {valid, UserState}; + (_,{extension, #'Extension'{critical = true}}, UserState) -> + %% This extension is marked as critical, so + %% certificate verification should fail if we don't + %% understand the extension. However, this is + %% `verify_none', so let's accept it anyway. + {valid, UserState}; (_,{extension, _}, UserState) -> {unknown, UserState}; (_, valid, UserState) -> @@ -1272,29 +1334,35 @@ handle_verify_options(Opts, CaCerts) -> PartialChainHanlder = handle_option(partial_chain, Opts, fun(_) -> unknown_ca end), + VerifyClientOnce = handle_option(verify_client_once, Opts, false), + %% Handle 0, 1, 2 for backwards compatibility case proplists:get_value(verify, Opts, verify_none) of 0 -> {verify_none, false, ca_cert_default(verify_none, VerifyNoneFun, CaCerts), - VerifyNoneFun, PartialChainHanlder}; + VerifyNoneFun, PartialChainHanlder, VerifyClientOnce}; 1 -> {verify_peer, false, ca_cert_default(verify_peer, UserVerifyFun, CaCerts), - UserVerifyFun, PartialChainHanlder}; + UserVerifyFun, PartialChainHanlder, VerifyClientOnce}; 2 -> {verify_peer, true, ca_cert_default(verify_peer, UserVerifyFun, CaCerts), - UserVerifyFun, PartialChainHanlder}; + UserVerifyFun, PartialChainHanlder, VerifyClientOnce}; verify_none -> {verify_none, false, ca_cert_default(verify_none, VerifyNoneFun, CaCerts), - VerifyNoneFun, PartialChainHanlder}; + VerifyNoneFun, PartialChainHanlder, VerifyClientOnce}; verify_peer -> {verify_peer, UserFailIfNoPeerCert, ca_cert_default(verify_peer, UserVerifyFun, CaCerts), - UserVerifyFun, PartialChainHanlder}; + UserVerifyFun, PartialChainHanlder, VerifyClientOnce}; Value -> throw({error, {options, {verify, Value}}}) end. +default_option_role(Role, Value, Role) -> + Value; +default_option_role(_,_,_) -> + undefined. diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl index 4658e76ab1..e9dc5764a3 100644 --- a/lib/ssl/src/ssl_certificate.erl +++ b/lib/ssl/src/ssl_certificate.erl @@ -56,15 +56,15 @@ %% errors. Returns {RootCert, Path, VerifyErrors} %%-------------------------------------------------------------------- trusted_cert_and_path(CertChain, CertDbHandle, CertDbRef, PartialChainHandler) -> - Path = [Cert | _] = lists:reverse(CertChain), - OtpCert = public_key:pkix_decode_cert(Cert, otp), + Path = [BinCert | _] = lists:reverse(CertChain), + OtpCert = public_key:pkix_decode_cert(BinCert, otp), SignedAndIssuerID = case public_key:pkix_is_self_signed(OtpCert) of true -> {ok, IssuerId} = public_key:pkix_issuer_id(OtpCert, self), {self, IssuerId}; false -> - other_issuer(OtpCert, CertDbHandle) + other_issuer(OtpCert, BinCert, CertDbHandle) end, case SignedAndIssuerID of @@ -187,7 +187,7 @@ public_key_type(?'id-ecPublicKey') -> %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- -certificate_chain(OtpCert, _Cert, CertDbHandle, CertsDbRef, Chain) -> +certificate_chain(OtpCert, BinCert, CertDbHandle, CertsDbRef, Chain) -> IssuerAndSelfSigned = case public_key:pkix_is_self_signed(OtpCert) of true -> @@ -200,7 +200,7 @@ certificate_chain(OtpCert, _Cert, CertDbHandle, CertsDbRef, Chain) -> {_, true = SelfSigned} -> certificate_chain(CertDbHandle, CertsDbRef, Chain, ignore, ignore, SelfSigned); {{error, issuer_not_found}, SelfSigned} -> - case find_issuer(OtpCert, CertDbHandle) of + case find_issuer(OtpCert, BinCert, CertDbHandle) of {ok, {SerialNr, Issuer}} -> certificate_chain(CertDbHandle, CertsDbRef, Chain, SerialNr, Issuer, SelfSigned); @@ -232,12 +232,12 @@ certificate_chain(CertDbHandle, CertsDbRef, Chain, SerialNr, Issuer, _SelfSigned {ok, undefined, lists:reverse(Chain)} end. -find_issuer(OtpCert, CertDbHandle) -> +find_issuer(OtpCert, BinCert, CertDbHandle) -> IsIssuerFun = fun({_Key, {_Der, #'OTPCertificate'{} = ErlCertCandidate}}, Acc) -> case public_key:pkix_is_issuer(OtpCert, ErlCertCandidate) of true -> - case verify_cert_signer(OtpCert, ErlCertCandidate#'OTPCertificate'.tbsCertificate) of + case verify_cert_signer(BinCert, ErlCertCandidate#'OTPCertificate'.tbsCertificate) of true -> throw(public_key:pkix_issuer_id(ErlCertCandidate, self)); false -> @@ -265,9 +265,9 @@ is_valid_extkey_usage(KeyUse, server) -> %% Server wants to verify client is_valid_key_usage(KeyUse, ?'id-kp-clientAuth'). -verify_cert_signer(OtpCert, SignerTBSCert) -> +verify_cert_signer(BinCert, SignerTBSCert) -> PublicKey = public_key(SignerTBSCert#'OTPTBSCertificate'.subjectPublicKeyInfo), - public_key:pkix_verify(public_key:pkix_encode('OTPCertificate', OtpCert, otp), PublicKey). + public_key:pkix_verify(BinCert, PublicKey). public_key(#'OTPSubjectPublicKeyInfo'{algorithm = #'PublicKeyAlgorithm'{algorithm = ?'id-ecPublicKey', parameters = Params}, @@ -281,12 +281,12 @@ public_key(#'OTPSubjectPublicKeyInfo'{algorithm = #'PublicKeyAlgorithm'{algorith subjectPublicKey = Key}) -> {Key, Params}. -other_issuer(OtpCert, CertDbHandle) -> +other_issuer(OtpCert, BinCert, CertDbHandle) -> case public_key:pkix_issuer_id(OtpCert, other) of {ok, IssuerId} -> {other, IssuerId}; {error, issuer_not_found} -> - case find_issuer(OtpCert, CertDbHandle) of + case find_issuer(OtpCert, BinCert, CertDbHandle) of {ok, IssuerId} -> {other, IssuerId}; Other -> diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index 8c2a16ba96..af53d4abf9 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -34,6 +34,7 @@ -include_lib("public_key/include/public_key.hrl"). -export([security_parameters/2, security_parameters/3, suite_definition/1, + erl_suite_definition/1, cipher_init/3, decipher/6, cipher/5, decipher_aead/6, cipher_aead/6, suite/1, suites/1, all_suites/1, ec_keyed_suites/0, anonymous_suites/1, psk_suites/1, srp_suites/0, @@ -42,14 +43,18 @@ -export_type([cipher_suite/0, erl_cipher_suite/0, openssl_cipher_suite/0, - key_algo/0]). + hash/0, key_algo/0, sign_algo/0]). -type cipher() :: null |rc4_128 | idea_cbc | des40_cbc | des_cbc | '3des_ede_cbc' | aes_128_cbc | aes_256_cbc | aes_128_gcm | aes_256_gcm | chacha20_poly1305. -type hash() :: null | sha | md5 | sha224 | sha256 | sha384 | sha512. +-type sign_algo() :: rsa | dsa | ecdsa. -type key_algo() :: null | rsa | dhe_rsa | dhe_dss | ecdhe_ecdsa| ecdh_ecdsa | ecdh_rsa| srp_rsa| srp_dss | psk | dhe_psk | rsa_psk | dh_anon | ecdh_anon | srp_anon. --type erl_cipher_suite() :: {key_algo(), cipher(), hash()}. --type int_cipher_suite() :: {key_algo(), cipher(), hash(), hash() | default_prf}. +-type erl_cipher_suite() :: {key_algo(), cipher(), hash()} % Pre TLS 1.2 + %% TLS 1.2, internally PRE TLS 1.2 will use default_prf + | {key_algo(), cipher(), hash(), hash() | default_prf}. + + -type cipher_suite() :: binary(). -type cipher_enum() :: integer(). -type openssl_cipher_suite() :: string(). @@ -417,7 +422,7 @@ rc4_suites({3, N}) when N =< 3 -> ?TLS_ECDH_RSA_WITH_RC4_128_SHA]. %%-------------------------------------------------------------------- --spec suite_definition(cipher_suite()) -> int_cipher_suite(). +-spec suite_definition(cipher_suite()) -> erl_cipher_suite(). %% %% Description: Return erlang cipher suite definition. %% Note: Currently not supported suites are commented away. @@ -722,6 +727,20 @@ suite_definition(?TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256) -> {dhe_rsa, chacha20_poly1305, null, sha256}. %%-------------------------------------------------------------------- +-spec erl_suite_definition(cipher_suite()) -> erl_cipher_suite(). +%% +%% Description: Return erlang cipher suite definition. Filters last value +%% for now (compatibility reasons). +%%-------------------------------------------------------------------- +erl_suite_definition(S) -> + case suite_definition(S) of + {KeyExchange, Cipher, Hash, default_prf} -> + {KeyExchange, Cipher, Hash}; + Suite -> + Suite + end. + +%%-------------------------------------------------------------------- -spec suite(erl_cipher_suite()) -> cipher_suite(). %% %% Description: Return TLS cipher suite definition. @@ -823,17 +842,17 @@ suite({rsa_psk, aes_256_cbc,sha}) -> %%% TLS 1.2 PSK Cipher Suites RFC 5487 -suite({psk, aes_128_gcm, null}) -> +suite({psk, aes_128_gcm, null, sha256}) -> ?TLS_PSK_WITH_AES_128_GCM_SHA256; -suite({psk, aes_256_gcm, null}) -> +suite({psk, aes_256_gcm, null, sha384}) -> ?TLS_PSK_WITH_AES_256_GCM_SHA384; -suite({dhe_psk, aes_128_gcm, null}) -> +suite({dhe_psk, aes_128_gcm, null, sha256}) -> ?TLS_DHE_PSK_WITH_AES_128_GCM_SHA256; -suite({dhe_psk, aes_256_gcm, null}) -> +suite({dhe_psk, aes_256_gcm, null, sha384}) -> ?TLS_DHE_PSK_WITH_AES_256_GCM_SHA384; -suite({rsa_psk, aes_128_gcm, null}) -> +suite({rsa_psk, aes_128_gcm, null, sha256}) -> ?TLS_RSA_PSK_WITH_AES_128_GCM_SHA256; -suite({rsa_psk, aes_256_gcm, null}) -> +suite({rsa_psk, aes_256_gcm, null, sha384}) -> ?TLS_RSA_PSK_WITH_AES_256_GCM_SHA384; suite({psk, aes_128_cbc, sha256}) -> @@ -940,74 +959,74 @@ suite({ecdh_anon, aes_256_cbc, sha}) -> ?TLS_ECDH_anon_WITH_AES_256_CBC_SHA; %%% RFC 5289 EC TLS suites -suite({ecdhe_ecdsa, aes_128_cbc, sha256}) -> +suite({ecdhe_ecdsa, aes_128_cbc, sha256, sha256}) -> ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256; -suite({ecdhe_ecdsa, aes_256_cbc, sha384}) -> +suite({ecdhe_ecdsa, aes_256_cbc, sha384, sha384}) -> ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384; -suite({ecdh_ecdsa, aes_128_cbc, sha256}) -> +suite({ecdh_ecdsa, aes_128_cbc, sha256, sha256}) -> ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256; -suite({ecdh_ecdsa, aes_256_cbc, sha384}) -> +suite({ecdh_ecdsa, aes_256_cbc, sha384, sha384}) -> ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384; -suite({ecdhe_rsa, aes_128_cbc, sha256}) -> +suite({ecdhe_rsa, aes_128_cbc, sha256, sha256}) -> ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256; -suite({ecdhe_rsa, aes_256_cbc, sha384}) -> +suite({ecdhe_rsa, aes_256_cbc, sha384, sha384}) -> ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384; -suite({ecdh_rsa, aes_128_cbc, sha256}) -> +suite({ecdh_rsa, aes_128_cbc, sha256, sha256}) -> ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256; -suite({ecdh_rsa, aes_256_cbc, sha384}) -> +suite({ecdh_rsa, aes_256_cbc, sha384, sha384}) -> ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384; %% RFC 5288 AES-GCM Cipher Suites -suite({rsa, aes_128_gcm, null}) -> +suite({rsa, aes_128_gcm, null, sha256}) -> ?TLS_RSA_WITH_AES_128_GCM_SHA256; -suite({rsa, aes_256_gcm, null}) -> +suite({rsa, aes_256_gcm, null, sha384}) -> ?TLS_RSA_WITH_AES_256_GCM_SHA384; -suite({dhe_rsa, aes_128_gcm, null}) -> +suite({dhe_rsa, aes_128_gcm, null, sha256}) -> ?TLS_DHE_RSA_WITH_AES_128_GCM_SHA256; -suite({dhe_rsa, aes_256_gcm, null}) -> +suite({dhe_rsa, aes_256_gcm, null, sha384}) -> ?TLS_DHE_RSA_WITH_AES_256_GCM_SHA384; -suite({dh_rsa, aes_128_gcm, null}) -> +suite({dh_rsa, aes_128_gcm, null, sha256}) -> ?TLS_DH_RSA_WITH_AES_128_GCM_SHA256; -suite({dh_rsa, aes_256_gcm, null}) -> +suite({dh_rsa, aes_256_gcm, null, sha384}) -> ?TLS_DH_RSA_WITH_AES_256_GCM_SHA384; -suite({dhe_dss, aes_128_gcm, null}) -> +suite({dhe_dss, aes_128_gcm, null, sha256}) -> ?TLS_DHE_DSS_WITH_AES_128_GCM_SHA256; -suite({dhe_dss, aes_256_gcm, null}) -> +suite({dhe_dss, aes_256_gcm, null, sha384}) -> ?TLS_DHE_DSS_WITH_AES_256_GCM_SHA384; -suite({dh_dss, aes_128_gcm, null}) -> +suite({dh_dss, aes_128_gcm, null, sha256}) -> ?TLS_DH_DSS_WITH_AES_128_GCM_SHA256; -suite({dh_dss, aes_256_gcm, null}) -> +suite({dh_dss, aes_256_gcm, null, sha384}) -> ?TLS_DH_DSS_WITH_AES_256_GCM_SHA384; -suite({dh_anon, aes_128_gcm, null}) -> +suite({dh_anon, aes_128_gcm, null, sha256}) -> ?TLS_DH_anon_WITH_AES_128_GCM_SHA256; -suite({dh_anon, aes_256_gcm, null}) -> +suite({dh_anon, aes_256_gcm, null, sha384}) -> ?TLS_DH_anon_WITH_AES_256_GCM_SHA384; %% RFC 5289 ECC AES-GCM Cipher Suites -suite({ecdhe_ecdsa, aes_128_gcm, null}) -> +suite({ecdhe_ecdsa, aes_128_gcm, null, sha256}) -> ?TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256; -suite({ecdhe_ecdsa, aes_256_gcm, null}) -> +suite({ecdhe_ecdsa, aes_256_gcm, null, sha384}) -> ?TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384; -suite({ecdh_ecdsa, aes_128_gcm, null}) -> +suite({ecdh_ecdsa, aes_128_gcm, null, sha256}) -> ?TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256; -suite({ecdh_ecdsa, aes_256_gcm, null}) -> +suite({ecdh_ecdsa, aes_256_gcm, null, sha384}) -> ?TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384; -suite({ecdhe_rsa, aes_128_gcm, null}) -> +suite({ecdhe_rsa, aes_128_gcm, null, sha256}) -> ?TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256; -suite({ecdhe_rsa, aes_256_gcm, null}) -> +suite({ecdhe_rsa, aes_256_gcm, null, sha384}) -> ?TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384; -suite({ecdh_rsa, aes_128_gcm, null}) -> +suite({ecdh_rsa, aes_128_gcm, null, sha256}) -> ?TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256; -suite({ecdh_rsa, aes_256_gcm, null}) -> +suite({ecdh_rsa, aes_256_gcm, null, sha384}) -> ?TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384; %% draft-agl-tls-chacha20poly1305-04 Chacha20/Poly1305 Suites -suite({ecdhe_rsa, chacha20_poly1305, null}) -> +suite({ecdhe_rsa, chacha20_poly1305, null, sha256}) -> ?TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256; -suite({ecdhe_ecdsa, chacha20_poly1305, null}) -> +suite({ecdhe_ecdsa, chacha20_poly1305, null, sha256}) -> ?TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256; -suite({dhe_rsa, chacha20_poly1305, null}) -> +suite({dhe_rsa, chacha20_poly1305, null, sha256}) -> ?TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256. %%-------------------------------------------------------------------- @@ -1384,18 +1403,14 @@ filter(DerCert, Ciphers) -> %% %% Description: Filter suites for algorithms supported by crypto. %%------------------------------------------------------------------- -filter_suites(Suites = [{_,_,_}|_]) -> +filter_suites(Suites = [Value|_]) when is_tuple(Value) -> Algos = crypto:supports(), + Hashs = proplists:get_value(hashs, Algos), lists:filter(fun({KeyExchange, Cipher, Hash}) -> is_acceptable_keyexchange(KeyExchange, proplists:get_value(public_keys, Algos)) andalso is_acceptable_cipher(Cipher, proplists:get_value(ciphers, Algos)) andalso - is_acceptable_hash(Hash, proplists:get_value(hashs, Algos)) - end, Suites); - -filter_suites(Suites = [{_,_,_,_}|_]) -> - Algos = crypto:supports(), - Hashs = proplists:get_value(hashs, Algos), - lists:filter(fun({KeyExchange, Cipher, Hash, Prf}) -> + is_acceptable_hash(Hash, proplists:get_value(hashs, Algos)); + ({KeyExchange, Cipher, Hash, Prf}) -> is_acceptable_keyexchange(KeyExchange, proplists:get_value(public_keys, Algos)) andalso is_acceptable_cipher(Cipher, proplists:get_value(ciphers, Algos)) andalso is_acceptable_hash(Hash, Hashs) andalso diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 5b754c16bc..0f0072ba34 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -41,7 +41,7 @@ socket_control/4, socket_control/5]). %% User Events --export([send/2, recv/3, close/1, shutdown/2, +-export([send/2, recv/3, close/2, shutdown/2, new_user/2, get_opts/2, set_opts/2, session_info/1, peer_certificate/1, renegotiation/1, negotiated_protocol/1, prf/5, connection_information/1 @@ -171,18 +171,19 @@ connection_information(Pid) when is_pid(Pid) -> sync_send_all_state_event(Pid, connection_information). %%-------------------------------------------------------------------- --spec close(pid()) -> ok | {error, reason()}. +-spec close(pid(), {close, Timeout::integer() | + {NewController::pid(), Timeout::integer()}}) -> + ok | {ok, port()} | {error, reason()}. %% %% Description: Close an ssl connection %%-------------------------------------------------------------------- -close(ConnectionPid) -> - case sync_send_all_state_event(ConnectionPid, close) of +close(ConnectionPid, How) -> + case sync_send_all_state_event(ConnectionPid, How) of {error, closed} -> ok; Other -> Other end. - %%-------------------------------------------------------------------- -spec shutdown(pid(), atom()) -> ok | {error, reason()}. %% @@ -303,13 +304,9 @@ hello(#hello_request{}, #state{role = client} = State0, Connection) -> {Record, State} = Connection:next_record(State0), Connection:next_state(hello, hello, Record, State); -hello({common_client_hello, Type, ServerHelloExt, NegotiatedHashSign}, +hello({common_client_hello, Type, ServerHelloExt}, State, Connection) -> - do_server_hello(Type, ServerHelloExt, - %% Note NegotiatedHashSign is only negotiated for real if - %% if TLS version is at least TLS-1.2 - State#state{hashsign_algorithm = NegotiatedHashSign}, Connection); - + do_server_hello(Type, ServerHelloExt, State, Connection); hello(timeout, State, _) -> {next_state, hello, State, hibernate}; @@ -441,7 +438,8 @@ certify(#server_key_exchange{exchange_keys = Keys}, Alg == srp_dss; Alg == srp_rsa; Alg == srp_anon -> Params = ssl_handshake:decode_server_key(Keys, Alg, Version), - HashSign = negotiated_hashsign(Params#server_key_params.hashsign, Alg, Version), + %% Use negotiated value if TLS-1.2 otherwhise return default + HashSign = negotiated_hashsign(Params#server_key_params.hashsign, Alg, PubKeyInfo, Version), case is_anonymous(Alg) of true -> calculate_secret(Params#server_key_params.params, @@ -463,11 +461,18 @@ certify(#server_key_exchange{} = Msg, certify(#certificate_request{hashsign_algorithms = HashSigns}, #state{session = #session{own_certificate = Cert}, - negotiated_version = Version} = State0, Connection) -> - HashSign = ssl_handshake:select_hashsign(HashSigns, Cert, Version), - {Record, State} = Connection:next_record(State0#state{client_certificate_requested = true}), - Connection:next_state(certify, certify, Record, - State#state{cert_hashsign_algorithm = HashSign}); + key_algorithm = KeyExAlg, + ssl_options = #ssl_options{signature_algs = SupportedHashSigns}, + negotiated_version = Version} = State0, Connection) -> + + case ssl_handshake:select_hashsign(HashSigns, Cert, KeyExAlg, SupportedHashSigns, Version) of + #alert {} = Alert -> + Connection:handle_own_alert(Alert, Version, certify, State0); + NegotiatedHashSign -> + {Record, State} = Connection:next_record(State0#state{client_certificate_requested = true}), + Connection:next_state(certify, certify, Record, + State#state{cert_hashsign_algorithm = NegotiatedHashSign}) + end; %% PSK and RSA_PSK might bypass the Server-Key-Exchange certify(#server_hello_done{}, @@ -575,13 +580,15 @@ cipher(#hello_request{}, State0, Connection) -> cipher(#certificate_verify{signature = Signature, hashsign_algorithm = CertHashSign}, #state{role = server, - public_key_info = {Algo, _, _} =PublicKeyInfo, + key_algorithm = KexAlg, + public_key_info = PublicKeyInfo, negotiated_version = Version, session = #session{master_secret = MasterSecret}, tls_handshake_history = Handshake } = State0, Connection) -> - - HashSign = ssl_handshake:select_hashsign_algs(CertHashSign, Algo, Version), + + %% Use negotiated value if TLS-1.2 otherwhise return default + HashSign = negotiated_hashsign(CertHashSign, KexAlg, PublicKeyInfo, Version), case ssl_handshake:certificate_verify(Signature, PublicKeyInfo, Version, HashSign, MasterSecret, Handshake) of valid -> @@ -706,12 +713,12 @@ handle_sync_event({start, Timeout}, StartFrom, StateName, #state{role = Role, s {stop, normal, {error, Error}, State0} end; -handle_sync_event(close, _, StateName, #state{protocol_cb = Connection} = State) -> - %% Run terminate before returning - %% so that the reuseaddr inet-option will work - %% as intended. - (catch Connection:terminate(user_close, StateName, State)), - {stop, normal, ok, State#state{terminated = true}}; +handle_sync_event({close, _} = Close, _, StateName, #state{protocol_cb = Connection} = State) -> + %% Run terminate before returning so that the reuseaddr + %% inet-option and possible downgrade will work as intended. + Result = Connection:terminate(Close, StateName, State), + {stop, normal, Result, State#state{terminated = true}}; + handle_sync_event({shutdown, How0}, _, StateName, #state{transport_cb = Transport, negotiated_version = Version, @@ -814,7 +821,8 @@ handle_sync_event({prf, Secret, Label, Seed, WantedLength}, _, StateName, SecParams = ConnectionState#connection_state.security_parameters, #security_parameters{master_secret = MasterSecret, client_random = ClientRandom, - server_random = ServerRandom} = SecParams, + server_random = ServerRandom, + prf_algorithm = PRFAlgorithm} = SecParams, Reply = try SecretToUse = case Secret of _ when is_binary(Secret) -> Secret; @@ -825,7 +833,7 @@ handle_sync_event({prf, Secret, Label, Seed, WantedLength}, _, StateName, (client_random, Acc) -> [ClientRandom|Acc]; (server_random, Acc) -> [ServerRandom|Acc] end, [], Seed)), - ssl_handshake:prf(Version, SecretToUse, Label, SeedToUse, WantedLength) + ssl_handshake:prf(Version, PRFAlgorithm, SecretToUse, Label, SeedToUse, WantedLength) catch exit:_ -> {error, badarg}; error:Reason -> {error, Reason} @@ -835,15 +843,22 @@ handle_sync_event(session_info, _, StateName, #state{session = #session{session_id = Id, cipher_suite = Suite}} = State) -> {reply, [{session_id, Id}, - {cipher_suite, ssl:suite_definition(Suite)}], + {cipher_suite, ssl_cipher:erl_suite_definition(Suite)}], StateName, State, get_timeout(State)}; handle_sync_event(peer_certificate, _, StateName, #state{session = #session{peer_certificate = Cert}} = State) -> {reply, {ok, Cert}, StateName, State, get_timeout(State)}; -handle_sync_event(connection_information, _, StateName, #state{sni_hostname = SNIHostname, session = #session{cipher_suite = CipherSuite}, negotiated_version = Version} = State) -> - {reply, {ok, [{protocol, tls_record:protocol_version(Version)}, {cipher_suite, ssl:suite_definition(CipherSuite)}, {sni_hostname, SNIHostname}]}, StateName, State, get_timeout(State)}. +handle_sync_event(connection_information, _, StateName, State) -> + Info = connection_info(State), + {reply, {ok, Info}, StateName, State, get_timeout(State)}. +connection_info(#state{sni_hostname = SNIHostname, + session = #session{cipher_suite = CipherSuite}, + negotiated_version = Version, ssl_options = Opts}) -> + [{protocol, tls_record:protocol_version(Version)}, + {cipher_suite, ssl_cipher:erl_suite_definition(CipherSuite)}, + {sni_hostname, SNIHostname}] ++ ssl_options_list(Opts). handle_info({ErrorTag, Socket, econnaborted}, StateName, #state{socket = Socket, transport_cb = Transport, @@ -901,41 +916,46 @@ terminate(_, _, #state{terminated = true}) -> %% we want to guarantee that Transport:close has been called %% when ssl:close/1 returns. ok; -terminate({shutdown, transport_closed}, StateName, #state{send_queue = SendQueue, - renegotiation = Renegotiate} = State) -> - handle_unrecv_data(StateName, State), +terminate({shutdown, transport_closed} = Reason, + _StateName, #state{send_queue = SendQueue, protocol_cb = Connection, + socket = Socket, transport_cb = Transport, + renegotiation = Renegotiate} = State) -> handle_trusted_certs_db(State), notify_senders(SendQueue), - notify_renegotiater(Renegotiate); - -terminate({shutdown, own_alert}, _StateName, #state{send_queue = SendQueue, - renegotiation = Renegotiate} = State) -> + notify_renegotiater(Renegotiate), + Connection:close(Reason, Socket, Transport, undefined, undefined); +terminate({shutdown, own_alert}, _StateName, #state{send_queue = SendQueue, protocol_cb = Connection, + socket = Socket, transport_cb = Transport, + renegotiation = Renegotiate} = State) -> handle_trusted_certs_db(State), notify_senders(SendQueue), - notify_renegotiater(Renegotiate); + notify_renegotiater(Renegotiate), + case application:get_env(ssl, alert_timeout) of + {ok, Timeout} when is_integer(Timeout) -> + Connection:close({timeout, Timeout}, Socket, Transport, undefined, undefined); + _ -> + Connection:close({timeout, ?DEFAULT_TIMEOUT}, Socket, Transport, undefined, undefined) + end; terminate(Reason, connection, #state{negotiated_version = Version, protocol_cb = Connection, - connection_states = ConnectionStates, + connection_states = ConnectionStates0, + ssl_options = #ssl_options{padding_check = Check}, transport_cb = Transport, socket = Socket, send_queue = SendQueue, renegotiation = Renegotiate} = State) -> handle_trusted_certs_db(State), notify_senders(SendQueue), notify_renegotiater(Renegotiate), - BinAlert = terminate_alert(Reason, Version, ConnectionStates), + {BinAlert, ConnectionStates} = terminate_alert(Reason, Version, ConnectionStates0), Transport:send(Socket, BinAlert), - case Connection of - tls_connection -> - tls_connection:workaround_transport_delivery_problems(Socket, Transport); - _ -> - ok - end; -terminate(_Reason, _StateName, #state{transport_cb = Transport, + Connection:close(Reason, Socket, Transport, ConnectionStates, Check); + +terminate(Reason, _StateName, #state{transport_cb = Transport, protocol_cb = Connection, socket = Socket, send_queue = SendQueue, renegotiation = Renegotiate} = State) -> handle_trusted_certs_db(State), notify_senders(SendQueue), notify_renegotiater(Renegotiate), - Transport:close(Socket). + Connection:close(Reason, Socket, Transport, undefined, undefined). format_status(normal, [_, State]) -> [{data, [{"StateData", State}]}]; @@ -968,7 +988,7 @@ ssl_config(Opts, Role, State) -> {ok, Ref, CertDbHandle, FileRefHandle, CacheHandle, CRLDbInfo, OwnCert, Key, DHParams} = ssl_config:init(Opts, Role), Handshake = ssl_handshake:init_handshake_history(), - TimeStamp = calendar:datetime_to_gregorian_seconds({date(), time()}), + TimeStamp = erlang:monotonic_time(), Session = State#state.session, State#state{tls_handshake_history = Handshake, session = Session#session{own_certificate = OwnCert, @@ -1435,7 +1455,8 @@ rsa_psk_key_exchange(Version, PskIdentity, PremasterSecret, PublicKeyInfo = {Alg rsa_psk_key_exchange(_, _, _, _) -> throw (?ALERT_REC(?FATAL,?HANDSHAKE_FAILURE)). -request_client_cert(#state{ssl_options = #ssl_options{verify = verify_peer}, +request_client_cert(#state{ssl_options = #ssl_options{verify = verify_peer, + signature_algs = SupportedHashSigns}, connection_states = ConnectionStates0, cert_db = CertDbHandle, cert_db_ref = CertDbRef, @@ -1443,7 +1464,9 @@ request_client_cert(#state{ssl_options = #ssl_options{verify = verify_peer}, #connection_state{security_parameters = #security_parameters{cipher_suite = CipherSuite}} = ssl_record:pending_connection_state(ConnectionStates0, read), - Msg = ssl_handshake:certificate_request(CipherSuite, CertDbHandle, CertDbRef, Version), + HashSigns = ssl_handshake:available_signature_algs(SupportedHashSigns, Version, [Version]), + Msg = ssl_handshake:certificate_request(CipherSuite, CertDbHandle, CertDbRef, + HashSigns, Version), State = Connection:send_handshake(Msg, State0), State#state{client_certificate_requested = true}; @@ -1758,37 +1781,24 @@ get_timeout(#state{ssl_options=#ssl_options{hibernate_after = undefined}}) -> get_timeout(#state{ssl_options=#ssl_options{hibernate_after = HibernateAfter}}) -> HibernateAfter. -terminate_alert(Reason, Version, ConnectionStates) when Reason == normal; - Reason == user_close -> - {BinAlert, _} = ssl_alert:encode(?ALERT_REC(?WARNING, ?CLOSE_NOTIFY), - Version, ConnectionStates), - BinAlert; -terminate_alert({shutdown, _}, Version, ConnectionStates) -> - {BinAlert, _} = ssl_alert:encode(?ALERT_REC(?WARNING, ?CLOSE_NOTIFY), - Version, ConnectionStates), - BinAlert; +terminate_alert(normal, Version, ConnectionStates) -> + ssl_alert:encode(?ALERT_REC(?WARNING, ?CLOSE_NOTIFY), + Version, ConnectionStates); +terminate_alert({Reason, _}, Version, ConnectionStates) when Reason == close; + Reason == shutdown -> + ssl_alert:encode(?ALERT_REC(?WARNING, ?CLOSE_NOTIFY), + Version, ConnectionStates); terminate_alert(_, Version, ConnectionStates) -> - {BinAlert, _} = ssl_alert:encode(?ALERT_REC(?FATAL, ?INTERNAL_ERROR), - Version, ConnectionStates), - BinAlert. - -handle_unrecv_data(StateName, #state{socket = Socket, transport_cb = Transport, - protocol_cb = Connection} = State) -> - ssl_socket:setopts(Transport, Socket, [{active, false}]), - case Transport:recv(Socket, 0, 0) of - {error, closed} -> - ok; - {ok, Data} -> - Connection:handle_close_alert(Data, StateName, State) - end. + ssl_alert:encode(?ALERT_REC(?FATAL, ?INTERNAL_ERROR), + Version, ConnectionStates). handle_trusted_certs_db(#state{ssl_options = #ssl_options{cacertfile = <<>>, cacerts = []}}) -> %% No trusted certs specified ok; handle_trusted_certs_db(#state{cert_db_ref = Ref, cert_db = CertDb, - ssl_options = #ssl_options{cacertfile = <<>>}}) -> + ssl_options = #ssl_options{cacertfile = <<>>}}) when CertDb =/= undefined -> %% Certs provided as DER directly can not be shared %% with other connections and it is safe to delete them when the connection ends. ssl_pkix_db:remove_trusted_certs(Ref, CertDb); @@ -1881,14 +1891,40 @@ make_premaster_secret({MajVer, MinVer}, rsa) -> make_premaster_secret(_, _) -> undefined. -negotiated_hashsign(undefined, Alg, Version) -> +negotiated_hashsign(undefined, KexAlg, PubKeyInfo, Version) -> %% Not negotiated choose default - case is_anonymous(Alg) of + case is_anonymous(KexAlg) of true -> {null, anon}; false -> - ssl_handshake:select_hashsign_algs(Alg, Version) + {PubAlg, _, _} = PubKeyInfo, + ssl_handshake:select_hashsign_algs(undefined, PubAlg, Version) end; -negotiated_hashsign(HashSign = {_, _}, _, _) -> +negotiated_hashsign(HashSign = {_, _}, _, _, _) -> HashSign. +ssl_options_list(SslOptions) -> + Fileds = record_info(fields, ssl_options), + Values = tl(tuple_to_list(SslOptions)), + ssl_options_list(Fileds, Values, []). + +ssl_options_list([],[], Acc) -> + lists:reverse(Acc); +%% Skip internal options, only return user options +ssl_options_list([protocol | Keys], [_ | Values], Acc) -> + ssl_options_list(Keys, Values, Acc); +ssl_options_list([erl_dist | Keys], [_ | Values], Acc) -> + ssl_options_list(Keys, Values, Acc); +ssl_options_list([renegotiate_at | Keys], [_ | Values], Acc) -> + ssl_options_list(Keys, Values, Acc); +ssl_options_list([ciphers = Key | Keys], [Value | Values], Acc) -> + ssl_options_list(Keys, Values, + [{Key, lists:map( + fun(Suite) -> + ssl_cipher:erl_suite_definition(Suite) + end, Value)} + | Acc]); +ssl_options_list([Key | Keys], [Value | Values], Acc) -> + ssl_options_list(Keys, Values, [{Key, Value} | Acc]). + + diff --git a/lib/ssl/src/ssl_dist_sup.erl b/lib/ssl/src/ssl_dist_sup.erl index aa1fa57db8..435ad27a44 100644 --- a/lib/ssl/src/ssl_dist_sup.erl +++ b/lib/ssl/src/ssl_dist_sup.erl @@ -70,7 +70,7 @@ connection_manager_child_spec() -> Name = ssl_connection_dist, StartFunc = {tls_connection_sup, start_link_dist, []}, Restart = permanent, - Shutdown = 4000, + Shutdown = infinity, Modules = [tls_connection_sup], Type = supervisor, {Name, StartFunc, Restart, Shutdown, Type, Modules}. diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index e9e140836b..43b0c42f8d 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2013-2015. All Rights Reserved. +%% Copyright Ericsson AB 2013-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -46,7 +46,7 @@ %% Handshake messages -export([hello_request/0, server_hello/4, server_hello_done/0, - certificate/4, certificate_request/4, key_exchange/3, + certificate/4, certificate_request/5, key_exchange/3, finished/5, next_protocol/1]). %% Handle handshake messages @@ -64,8 +64,8 @@ ]). %% Cipher suites handling --export([available_suites/2, cipher_suites/2, - select_session/10, supported_ecc/1]). +-export([available_suites/2, available_signature_algs/3, cipher_suites/2, + select_session/11, supported_ecc/1]). %% Extensions handling -export([client_hello_extensions/6, @@ -74,8 +74,8 @@ ]). %% MISC --export([select_version/3, prf/5, select_hashsign/3, - select_hashsign_algs/2, select_hashsign_algs/3, +-export([select_version/3, prf/6, select_hashsign/5, + select_hashsign_algs/3, premaster_secret/2, premaster_secret/3, premaster_secret/4]). %%==================================================================== @@ -120,7 +120,8 @@ server_hello(SessionId, Version, ConnectionStates, Extensions) -> server_hello_done() -> #server_hello_done{}. -client_hello_extensions(Host, Version, CipherSuites, SslOpts, ConnectionStates, Renegotiation) -> +client_hello_extensions(Host, Version, CipherSuites, + #ssl_options{signature_algs = SupportedHashSigns, versions = AllVersions} = SslOpts, ConnectionStates, Renegotiation) -> {EcPointFormats, EllipticCurves} = case advertises_ec_ciphers(lists:map(fun ssl_cipher:suite_definition/1, CipherSuites)) of true -> @@ -134,7 +135,7 @@ client_hello_extensions(Host, Version, CipherSuites, SslOpts, ConnectionStates, renegotiation_info = renegotiation_info(tls_record, client, ConnectionStates, Renegotiation), srp = SRP, - hash_signs = advertised_hash_signs(Version), + signature_algs = available_signature_algs(SupportedHashSigns, Version, AllVersions), ec_point_formats = EcPointFormats, elliptic_curves = EllipticCurves, alpn = encode_alpn(SslOpts#ssl_options.alpn_advertised_protocols, Renegotiation), @@ -203,14 +204,14 @@ client_certificate_verify(OwnCert, MasterSecret, Version, end. %%-------------------------------------------------------------------- --spec certificate_request(ssl_cipher:cipher_suite(), db_handle(), certdb_ref(), ssl_record:ssl_version()) -> - #certificate_request{}. +-spec certificate_request(ssl_cipher:cipher_suite(), db_handle(), + certdb_ref(), #hash_sign_algos{}, ssl_record:ssl_version()) -> + #certificate_request{}. %% %% Description: Creates a certificate_request message, called by the server. %%-------------------------------------------------------------------- -certificate_request(CipherSuite, CertDbHandle, CertDbRef, Version) -> +certificate_request(CipherSuite, CertDbHandle, CertDbRef, HashSigns, Version) -> Types = certificate_types(ssl_cipher:suite_definition(CipherSuite), Version), - HashSigns = advertised_hash_signs(Version), Authorities = certificate_authorities(CertDbHandle, CertDbRef), #certificate_request{ certificate_types = Types, @@ -351,6 +352,9 @@ verify_server_key(#server_key_params{params_bin = EncParams, %% %% Description: Checks that the certificate_verify message is valid. %%-------------------------------------------------------------------- +certificate_verify(_, _, _, undefined, _, _) -> + ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE); + certificate_verify(Signature, PublicKeyInfo, Version, HashSign = {HashAlgo, _}, MasterSecret, {_, Handshake}) -> Hash = calc_certificate_verify(Version, HashAlgo, MasterSecret, Handshake), @@ -379,10 +383,11 @@ verify_signature(_Version, Hash, _HashAlgo, Signature, {?rsaEncryption, PubKey, end; verify_signature(_Version, Hash, {HashAlgo, dsa}, Signature, {?'id-dsa', PublicKey, PublicKeyParams}) -> public_key:verify({digest, Hash}, HashAlgo, Signature, {PublicKey, PublicKeyParams}); -verify_signature(_Version, Hash, {HashAlgo, ecdsa}, Signature, +verify_signature(_, Hash, {HashAlgo, _SignAlg}, Signature, {?'id-ecPublicKey', PublicKey, PublicKeyParams}) -> public_key:verify({digest, Hash}, HashAlgo, Signature, {PublicKey, PublicKeyParams}). + %%-------------------------------------------------------------------- -spec certify(#certificate{}, db_handle(), certdb_ref(), integer() | nolimit, verify_peer | verify_none, {fun(), term}, fun(), term(), term(), @@ -559,57 +564,58 @@ server_key_exchange_hash(md5sha, Value) -> server_key_exchange_hash(Hash, Value) -> crypto:hash(Hash, Value). %%-------------------------------------------------------------------- --spec prf(ssl_record:ssl_version(), binary(), binary(), [binary()], non_neg_integer()) -> +-spec prf(ssl_record:ssl_version(), non_neg_integer(), binary(), binary(), [binary()], non_neg_integer()) -> {ok, binary()} | {error, undefined}. %% %% Description: use the TLS PRF to generate key material %%-------------------------------------------------------------------- -prf({3,0}, _, _, _, _) -> +prf({3,0}, _, _, _, _, _) -> {error, undefined}; -prf({3,1}, Secret, Label, Seed, WantedLength) -> - {ok, tls_v1:prf(?MD5SHA, Secret, Label, Seed, WantedLength)}; -prf({3,_N}, Secret, Label, Seed, WantedLength) -> - {ok, tls_v1:prf(?SHA256, Secret, Label, Seed, WantedLength)}. +prf({3,_N}, PRFAlgo, Secret, Label, Seed, WantedLength) -> + {ok, tls_v1:prf(PRFAlgo, Secret, Label, Seed, WantedLength)}. %%-------------------------------------------------------------------- --spec select_hashsign(#hash_sign_algos{}| undefined, undefined | binary(), ssl_record:ssl_version()) -> - {atom(), atom()} | undefined. +-spec select_hashsign(#hash_sign_algos{} | undefined, undefined | binary(), + atom(), [atom()], ssl_record:ssl_version()) -> + {atom(), atom()} | undefined | #alert{}. %% -%% Description: +%% Description: Handles signature_algorithms extension %%-------------------------------------------------------------------- -select_hashsign(_, undefined, _Version) -> +select_hashsign(_, undefined, _, _, _Version) -> {null, anon}; %% The signature_algorithms extension was introduced with TLS 1.2. Ignore it if we have %% negotiated a lower version. -select_hashsign(#hash_sign_algos{hash_sign_algos = HashSigns}, Cert, {Major, Minor} = Version) - when Major >= 3 andalso Minor >= 3 -> - #'OTPCertificate'{tbsCertificate = TBSCert} =public_key:pkix_decode_cert(Cert, otp), +select_hashsign(HashSigns, Cert, KeyExAlgo, + undefined, {Major, Minor} = Version) when Major >= 3 andalso Minor >= 3-> + select_hashsign(HashSigns, Cert, KeyExAlgo, tls_v1:default_signature_algs(Version), Version); +select_hashsign(#hash_sign_algos{hash_sign_algos = HashSigns}, Cert, KeyExAlgo, SupportedHashSigns, + {Major, Minor}) when Major >= 3 andalso Minor >= 3 -> + #'OTPCertificate'{tbsCertificate = TBSCert} = public_key:pkix_decode_cert(Cert, otp), #'OTPSubjectPublicKeyInfo'{algorithm = {_,Algo, _}} = TBSCert#'OTPTBSCertificate'.subjectPublicKeyInfo, - DefaultHashSign = {_, Sign} = select_hashsign_algs(undefined, Algo, Version), - case lists:filter(fun({sha, dsa}) -> + Sign = cert_sign(Algo), + case lists:filter(fun({sha, dsa = S}) when S == Sign -> true; ({_, dsa}) -> false; - ({Hash, S}) when S == Sign -> - ssl_cipher:is_acceptable_hash(Hash, - proplists:get_value(hashs, crypto:supports())); + ({_, _} = Algos) -> + is_acceptable_hash_sign(Algos, Sign, KeyExAlgo, SupportedHashSigns); (_) -> false end, HashSigns) of [] -> - DefaultHashSign; - [HashSign| _] -> + ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY); + [HashSign | _] -> HashSign end; -select_hashsign(_, Cert, Version) -> +select_hashsign(_, Cert, _, _, Version) -> #'OTPCertificate'{tbsCertificate = TBSCert} = public_key:pkix_decode_cert(Cert, otp), #'OTPSubjectPublicKeyInfo'{algorithm = {_,Algo, _}} = TBSCert#'OTPTBSCertificate'.subjectPublicKeyInfo, select_hashsign_algs(undefined, Algo, Version). %%-------------------------------------------------------------------- --spec select_hashsign_algs(#hash_sign_algos{}| undefined, oid(), ssl_record:ssl_version()) -> +-spec select_hashsign_algs({atom(), atom()}| undefined, oid(), ssl_record:ssl_version()) -> {atom(), atom()}. %% Description: For TLS 1.2 hash function and signature algorithm pairs can be @@ -642,24 +648,6 @@ select_hashsign_algs(undefined, ?rsaEncryption, _) -> select_hashsign_algs(undefined, ?'id-dsa', _) -> {sha, dsa}. --spec select_hashsign_algs(atom(), ssl_record:ssl_version()) -> {atom(), atom()}. -%% Wrap function to keep the knowledge of the default values in -%% one place only -select_hashsign_algs(Alg, Version) when (Alg == rsa orelse - Alg == dhe_rsa orelse - Alg == dh_rsa orelse - Alg == ecdhe_rsa orelse - Alg == ecdh_rsa orelse - Alg == srp_rsa) -> - select_hashsign_algs(undefined, ?rsaEncryption, Version); -select_hashsign_algs(Alg, Version) when (Alg == dhe_dss orelse - Alg == dh_dss orelse - Alg == srp_dss) -> - select_hashsign_algs(undefined, ?'id-dsa', Version); -select_hashsign_algs(Alg, Version) when (Alg == ecdhe_ecdsa orelse - Alg == ecdh_ecdsa) -> - select_hashsign_algs(undefined, ?'id-ecPublicKey', Version). - %%-------------------------------------------------------------------- -spec master_secret(atom(), ssl_record:ssl_version(), #session{} | binary(), #connection_states{}, client | server) -> {binary(), #connection_states{}} | #alert{}. @@ -1063,9 +1051,56 @@ available_suites(UserSuites, Version) -> lists:member(Suite, ssl_cipher:all_suites(Version)) end, UserSuites). -available_suites(ServerCert, UserSuites, Version, Curve) -> +available_suites(ServerCert, UserSuites, Version, undefined, Curve) -> ssl_cipher:filter(ServerCert, available_suites(UserSuites, Version)) - -- unavailable_ecc_suites(Curve). + -- unavailable_ecc_suites(Curve); +available_suites(ServerCert, UserSuites, Version, HashSigns, Curve) -> + Suites = available_suites(ServerCert, UserSuites, Version, undefined, Curve), + filter_hashsigns(Suites, [ssl_cipher:suite_definition(Suite) || Suite <- Suites], HashSigns, []). +filter_hashsigns([], [], _, Acc) -> + lists:reverse(Acc); +filter_hashsigns([Suite | Suites], [{KeyExchange,_,_,_} | Algos], HashSigns, + Acc) when KeyExchange == dhe_ecdsa; + KeyExchange == ecdhe_ecdsa -> + do_filter_hashsigns(ecdsa, Suite, Suites, Algos, HashSigns, Acc); + +filter_hashsigns([Suite | Suites], [{KeyExchange,_,_,_} | Algos], HashSigns, + Acc) when KeyExchange == rsa; + KeyExchange == dhe_rsa; + KeyExchange == ecdhe_rsa; + KeyExchange == srp_rsa; + KeyExchange == rsa_psk -> + do_filter_hashsigns(rsa, Suite, Suites, Algos, HashSigns, Acc); +filter_hashsigns([Suite | Suites], [{KeyExchange,_,_,_} | Algos], HashSigns, Acc) when + KeyExchange == dhe_dss; + KeyExchange == srp_dss -> + do_filter_hashsigns(dsa, Suite, Suites, Algos, HashSigns, Acc); +filter_hashsigns([Suite | Suites], [{KeyExchange,_,_,_} | Algos], HashSigns, Acc) when + KeyExchange == dh_dss; + KeyExchange == dh_rsa; + KeyExchange == dh_ecdsa; + KeyExchange == ecdh_rsa; + KeyExchange == ecdh_ecdsa -> + %% Fixed DH certificates MAY be signed with any hash/signature + %% algorithm pair appearing in the hash_sign extension. The names + %% DH_DSS, DH_RSA, ECDH_ECDSA, and ECDH_RSA are historical. + filter_hashsigns(Suites, Algos, HashSigns, [Suite| Acc]); +filter_hashsigns([Suite | Suites], [{KeyExchange,_,_,_} | Algos], HashSigns, Acc) when + KeyExchange == dh_anon; + KeyExchange == ecdh_anon; + KeyExchange == srp_anon; + KeyExchange == psk; + KeyExchange == dhe_psk -> + %% In this case hashsigns is not used as the kexchange is anonaymous + filter_hashsigns(Suites, Algos, HashSigns, [Suite| Acc]). + +do_filter_hashsigns(SignAlgo, Suite, Suites, Algos, HashSigns, Acc) -> + case lists:keymember(SignAlgo, 2, HashSigns) of + true -> + filter_hashsigns(Suites, Algos, HashSigns, [Suite| Acc]); + false -> + filter_hashsigns(Suites, Algos, HashSigns, Acc) + end. unavailable_ecc_suites(no_curve) -> ssl_cipher:ec_keyed_suites(); @@ -1077,17 +1112,17 @@ cipher_suites(Suites, false) -> cipher_suites(Suites, true) -> Suites. -select_session(SuggestedSessionId, CipherSuites, Compressions, Port, #session{ecc = ECCCurve} = +select_session(SuggestedSessionId, CipherSuites, HashSigns, Compressions, Port, #session{ecc = ECCCurve} = Session, Version, - #ssl_options{ciphers = UserSuites, honor_cipher_order = HCO} = SslOpts, + #ssl_options{ciphers = UserSuites, honor_cipher_order = HonorCipherOrder} = SslOpts, Cache, CacheCb, Cert) -> {SessionId, Resumed} = ssl_session:server_id(Port, SuggestedSessionId, SslOpts, Cert, Cache, CacheCb), case Resumed of undefined -> - Suites = available_suites(Cert, UserSuites, Version, ECCCurve), - CipherSuite = select_cipher_suite(CipherSuites, Suites, HCO), + Suites = available_suites(Cert, UserSuites, Version, HashSigns, ECCCurve), + CipherSuite = select_cipher_suite(CipherSuites, Suites, HonorCipherOrder), Compression = select_compression(Compressions), {new, Session#session{session_id = SessionId, cipher_suite = CipherSuite, @@ -1155,7 +1190,7 @@ handle_client_hello_extensions(RecordCB, Random, ClientCipherSuites, #hello_extensions{renegotiation_info = Info, srp = SRP, ec_point_formats = ECCFormat, - alpn = ALPN, + alpn = ALPN, next_protocol_negotiation = NextProtocolNegotiation}, Version, #ssl_options{secure_renegotiate = SecureRenegotation, alpn_preferred_protocols = ALPNPreferredProtocols} = Opts, @@ -1223,8 +1258,40 @@ handle_server_hello_extensions(RecordCB, Random, CipherSuite, Compression, end. select_version(RecordCB, ClientVersion, Versions) -> - ServerVersion = RecordCB:highest_protocol_version(Versions), - RecordCB:lowest_protocol_version(ClientVersion, ServerVersion). + do_select_version(RecordCB, ClientVersion, Versions). + +do_select_version(_, ClientVersion, []) -> + ClientVersion; +do_select_version(RecordCB, ClientVersion, [Version | Versions]) -> + case RecordCB:is_higher(Version, ClientVersion) of + true -> + %% Version too high for client - keep looking + do_select_version(RecordCB, ClientVersion, Versions); + false -> + %% Version ok for client - look for a higher + do_select_version(RecordCB, ClientVersion, Versions, Version) + end. +%% +do_select_version(_, _, [], GoodVersion) -> + GoodVersion; +do_select_version( + RecordCB, ClientVersion, [Version | Versions], GoodVersion) -> + BetterVersion = + case RecordCB:is_higher(Version, ClientVersion) of + true -> + %% Version too high for client + GoodVersion; + false -> + %% Version ok for client + case RecordCB:is_higher(Version, GoodVersion) of + true -> + %% Use higher version + Version; + false -> + GoodVersion + end + end, + do_select_version(RecordCB, ClientVersion, Versions, BetterVersion). renegotiation_info(_, client, _, false) -> #renegotiation_info{renegotiated_connection = undefined}; @@ -1324,7 +1391,7 @@ handle_renegotiation_info(_RecordCB, ConnectionStates, SecureRenegotation) -> hello_extensions_list(#hello_extensions{renegotiation_info = RenegotiationInfo, srp = SRP, - hash_signs = HashSigns, + signature_algs = HashSigns, ec_point_formats = EcPointFormats, elliptic_curves = EllipticCurves, alpn = ALPN, @@ -1799,7 +1866,7 @@ dec_hello_extensions(<<?UINT16(?SIGNATURE_ALGORITHMS_EXT), ?UINT16(Len), <<?UINT16(SignAlgoListLen), SignAlgoList/binary>> = ExtData, HashSignAlgos = [{ssl_cipher:hash_algorithm(Hash), ssl_cipher:sign_algorithm(Sign)} || <<?BYTE(Hash), ?BYTE(Sign)>> <= SignAlgoList], - dec_hello_extensions(Rest, Acc#hello_extensions{hash_signs = + dec_hello_extensions(Rest, Acc#hello_extensions{signature_algs = #hash_sign_algos{hash_sign_algos = HashSignAlgos}}); dec_hello_extensions(<<?UINT16(?ELLIPTIC_CURVES_EXT), ?UINT16(Len), @@ -1899,7 +1966,7 @@ from_2bytes(<<?UINT16(N), Rest/binary>>, Acc) -> key_exchange_alg(rsa) -> ?KEY_EXCHANGE_RSA; key_exchange_alg(Alg) when Alg == dhe_rsa; Alg == dhe_dss; - Alg == dh_dss; Alg == dh_rsa; Alg == dh_anon -> + Alg == dh_dss; Alg == dh_rsa; Alg == dh_anon -> ?KEY_EXCHANGE_DIFFIE_HELLMAN; key_exchange_alg(Alg) when Alg == ecdhe_rsa; Alg == ecdh_rsa; Alg == ecdhe_ecdsa; Alg == ecdh_ecdsa; @@ -2008,27 +2075,16 @@ is_member(Suite, SupportedSuites) -> select_compression(_CompressionMetodes) -> ?NULL. --define(TLSEXT_SIGALG_RSA(MD), {MD, rsa}). --define(TLSEXT_SIGALG_DSA(MD), {MD, dsa}). --define(TLSEXT_SIGALG_ECDSA(MD), {MD, ecdsa}). - --define(TLSEXT_SIGALG(MD), ?TLSEXT_SIGALG_ECDSA(MD), ?TLSEXT_SIGALG_RSA(MD)). - -advertised_hash_signs({Major, Minor}) when Major >= 3 andalso Minor >= 3 -> - HashSigns = [?TLSEXT_SIGALG(sha512), - ?TLSEXT_SIGALG(sha384), - ?TLSEXT_SIGALG(sha256), - ?TLSEXT_SIGALG(sha224), - ?TLSEXT_SIGALG(sha), - ?TLSEXT_SIGALG_DSA(sha), - ?TLSEXT_SIGALG_RSA(md5)], - CryptoSupport = crypto:supports(), - HasECC = proplists:get_bool(ecdsa, proplists:get_value(public_keys, CryptoSupport)), - Hashs = proplists:get_value(hashs, CryptoSupport), - #hash_sign_algos{hash_sign_algos = - lists:filter(fun({Hash, ecdsa}) -> HasECC andalso proplists:get_bool(Hash, Hashs); - ({Hash, _}) -> proplists:get_bool(Hash, Hashs) end, HashSigns)}; -advertised_hash_signs(_) -> +available_signature_algs(undefined, _, _) -> + undefined; +available_signature_algs(SupportedHashSigns, {Major, Minor}, AllVersions) when Major >= 3 andalso Minor >= 3 -> + case tls_record:lowest_protocol_version(AllVersions) of + {3, 3} -> + #hash_sign_algos{hash_sign_algos = SupportedHashSigns}; + _ -> + undefined + end; +available_signature_algs(_, _, _) -> undefined. psk_secret(PSKIdentity, PSKLookup) -> @@ -2072,12 +2128,9 @@ crl_check(OtpCert, Check, CertDbHandle, CertDbRef, {Callback, CRLDbHandle}, _) - ], case dps_and_crls(OtpCert, Callback, CRLDbHandle, ext) of no_dps -> - case dps_and_crls(OtpCert, Callback, CRLDbHandle, same_issuer) of - [] -> - valid; %% No relevant CRL existed - DpsAndCRls -> - crl_check_same_issuer(OtpCert, Check, DpsAndCRls, Options) - end; + crl_check_same_issuer(OtpCert, Check, + dps_and_crls(OtpCert, Callback, CRLDbHandle, same_issuer), + Options); DpsAndCRLs -> %% This DP list may be empty if relevant CRLs existed %% but could not be retrived, will result in {bad_cert, revocation_status_undetermined} case public_key:pkix_crls_validate(OtpCert, DpsAndCRLs, Options) of @@ -2126,3 +2179,25 @@ distpoints_lookup([DistPoint | Rest], Callback, CRLDbHandle) -> CRLs -> [{DistPoint, {CRL, public_key:der_decode('CertificateList', CRL)}} || CRL <- CRLs] end. + +cert_sign(?rsaEncryption) -> + rsa; +cert_sign(?'id-ecPublicKey') -> + ecdsa; +cert_sign(?'id-dsa') -> + dsa; +cert_sign(Alg) -> + {_, Sign} =public_key:pkix_sign_types(Alg), + Sign. + +is_acceptable_hash_sign({_, Sign} = Algos, Sign, _, SupportedHashSigns) -> + is_acceptable_hash_sign(Algos, SupportedHashSigns); +is_acceptable_hash_sign(Algos,_, KeyExAlgo, SupportedHashSigns) when KeyExAlgo == dh_ecdsa; + KeyExAlgo == ecdh_rsa; + KeyExAlgo == ecdh_ecdsa -> + is_acceptable_hash_sign(Algos, SupportedHashSigns); +is_acceptable_hash_sign(_,_,_,_) -> + false. +is_acceptable_hash_sign(Algos, SupportedHashSigns) -> + lists:member(Algos, SupportedHashSigns). + diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl index 58b4d5a23d..b74a65939b 100644 --- a/lib/ssl/src/ssl_handshake.hrl +++ b/lib/ssl/src/ssl_handshake.hrl @@ -95,7 +95,7 @@ -record(hello_extensions, { renegotiation_info, - hash_signs, % supported combinations of hashes/signature algos + signature_algs, % supported combinations of hashes/signature algos alpn, next_protocol_negotiation = undefined, % [binary()] srp, diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl index 3851b2bc6e..20f0b7d0da 100644 --- a/lib/ssl/src/ssl_internal.hrl +++ b/lib/ssl/src/ssl_internal.hrl @@ -78,6 +78,9 @@ -define(ALL_DATAGRAM_SUPPORTED_VERSIONS, ['dtlsv1.2', dtlsv1]). -define(MIN_DATAGRAM_SUPPORTED_VERSIONS, ['dtlsv1.2', dtlsv1]). +-define('24H_in_msec', 86400000). +-define('24H_in_sec', 86400). + -record(ssl_options, { protocol :: tls | dtls, versions :: [ssl_record:ssl_version()], %% ssl_record:atom_version() in API @@ -132,7 +135,8 @@ padding_check = true :: boolean(), fallback = false :: boolean(), crl_check :: boolean() | peer | best_effort, - crl_cache + crl_cache, + signature_algs }). -record(socket_options, diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl index 2e05ba5aa5..8ed29cc6b0 100644 --- a/lib/ssl/src/ssl_manager.erl +++ b/lib/ssl/src/ssl_manager.erl @@ -46,25 +46,28 @@ -include_lib("kernel/include/file.hrl"). -record(state, { - session_cache_client, - session_cache_server, - session_cache_cb, - session_lifetime, - certificate_db, - session_validation_timer, + session_cache_client :: db_handle(), + session_cache_server :: db_handle(), + session_cache_cb :: atom(), + session_lifetime :: integer(), + certificate_db :: db_handle(), + session_validation_timer :: reference(), last_delay_timer = {undefined, undefined},%% Keep for testing purposes - last_pem_check, - clear_pem_cache + last_pem_check :: erlang:timestamp(), + clear_pem_cache :: integer(), + session_cache_client_max :: integer(), + session_cache_server_max :: integer(), + session_server_invalidator :: undefined | pid(), + session_client_invalidator :: undefined | pid() }). --define('24H_in_msec', 86400000). --define('24H_in_sec', 86400). -define(GEN_UNIQUE_ID_MAX_TRIES, 10). -define(SESSION_VALIDATION_INTERVAL, 60000). -define(CLEAR_PEM_CACHE, 120000). -define(CLEAN_SESSION_DB, 60000). -define(CLEAN_CERT_DB, 500). --define(NOT_TO_BIG, 10). +-define(DEFAULT_MAX_SESSION_CACHE, 1000). +-define(LOAD_MITIGATION, 10). %%==================================================================== %% API @@ -89,7 +92,8 @@ manager_name(dist) -> %%-------------------------------------------------------------------- start_link(Opts) -> DistMangerName = manager_name(normal), - gen_server:start_link({local, DistMangerName}, ?MODULE, [DistMangerName, Opts], []). + gen_server:start_link({local, DistMangerName}, + ?MODULE, [DistMangerName, Opts], []). %%-------------------------------------------------------------------- -spec start_link_dist(list()) -> {ok, pid()} | ignore | {error, term()}. @@ -99,7 +103,8 @@ start_link(Opts) -> %%-------------------------------------------------------------------- start_link_dist(Opts) -> DistMangerName = manager_name(dist), - gen_server:start_link({local, DistMangerName}, ?MODULE, [DistMangerName, Opts], []). + gen_server:start_link({local, DistMangerName}, + ?MODULE, [DistMangerName, Opts], []). %%-------------------------------------------------------------------- -spec connection_init(binary()| {der, list()}, client | server, @@ -169,7 +174,8 @@ new_session_id(Port) -> %% be called by ssl-connection processes. %%-------------------------------------------------------------------- clean_cert_db(Ref, File) -> - erlang:send_after(?CLEAN_CERT_DB, get(ssl_manager), {clean_cert_db, Ref, File}), + erlang:send_after(?CLEAN_CERT_DB, get(ssl_manager), + {clean_cert_db, Ref, File}), ok. %%-------------------------------------------------------------------- @@ -191,10 +197,12 @@ register_session(Port, Session) -> %%-------------------------------------------------------------------- -spec invalidate_session(host(), inet:port_number(), #session{}) -> ok. invalidate_session(Host, Port, Session) -> + load_mitigation(), cast({invalidate_session, Host, Port, Session}). -spec invalidate_session(inet:port_number(), #session{}) -> ok. invalidate_session(Port, Session) -> + load_mitigation(), cast({invalidate_session, Port, Session}). -spec invalidate_pem(File::binary()) -> ok. @@ -237,10 +245,12 @@ init([Name, Opts]) -> SessionLifeTime = proplists:get_value(session_lifetime, Opts, ?'24H_in_sec'), CertDb = ssl_pkix_db:create(), - ClientSessionCache = CacheCb:init([{role, client} | - proplists:get_value(session_cb_init_args, Opts, [])]), - ServerSessionCache = CacheCb:init([{role, server} | - proplists:get_value(session_cb_init_args, Opts, [])]), + ClientSessionCache = + CacheCb:init([{role, client} | + proplists:get_value(session_cb_init_args, Opts, [])]), + ServerSessionCache = + CacheCb:init([{role, server} | + proplists:get_value(session_cb_init_args, Opts, [])]), Timer = erlang:send_after(SessionLifeTime * 1000 + 5000, self(), validate_sessions), Interval = pem_check_interval(), @@ -252,7 +262,13 @@ init([Name, Opts]) -> session_lifetime = SessionLifeTime, session_validation_timer = Timer, last_pem_check = os:timestamp(), - clear_pem_cache = Interval + clear_pem_cache = Interval, + session_cache_client_max = + max_session_cache_size(session_cache_client_max), + session_cache_server_max = + max_session_cache_size(session_cache_server_max), + session_client_invalidator = undefined, + session_server_invalidator = undefined }}. %%-------------------------------------------------------------------- @@ -269,7 +285,8 @@ init([Name, Opts]) -> handle_call({{connection_init, <<>>, Role, {CRLCb, UserCRLDb}}, _Pid}, _From, #state{certificate_db = [CertDb, FileRefDb, PemChace | _] = Db} = State) -> Ref = make_ref(), - Result = {ok, Ref, CertDb, FileRefDb, PemChace, session_cache(Role, State), {CRLCb, crl_db_info(Db, UserCRLDb)}}, + Result = {ok, Ref, CertDb, FileRefDb, PemChace, + session_cache(Role, State), {CRLCb, crl_db_info(Db, UserCRLDb)}}, {reply, Result, State#state{certificate_db = Db}}; handle_call({{connection_init, Trustedcerts, Role, {CRLCb, UserCRLDb}}, Pid}, _From, @@ -307,7 +324,8 @@ handle_call({{cache_pem,File}, _Pid}, _, _:Reason -> {reply, {error, Reason}, State} end; -handle_call({unconditionally_clear_pem_cache, _},_, #state{certificate_db = [_,_,PemChace | _]} = State) -> +handle_call({unconditionally_clear_pem_cache, _},_, + #state{certificate_db = [_,_,PemChace | _]} = State) -> ssl_pkix_db:clear(PemChace), {reply, ok, State}. @@ -319,27 +337,12 @@ handle_call({unconditionally_clear_pem_cache, _},_, #state{certificate_db = [_,_ %% %% Description: Handling cast messages %%-------------------------------------------------------------------- -handle_cast({register_session, Host, Port, Session}, - #state{session_cache_client = Cache, - session_cache_cb = CacheCb} = State) -> - TimeStamp = calendar:datetime_to_gregorian_seconds({date(), time()}), - NewSession = Session#session{time_stamp = TimeStamp}, - - case CacheCb:select_session(Cache, {Host, Port}) of - no_session -> - CacheCb:update(Cache, {{Host, Port}, - NewSession#session.session_id}, NewSession); - Sessions -> - register_unique_session(Sessions, NewSession, CacheCb, Cache, {Host, Port}) - end, +handle_cast({register_session, Host, Port, Session}, State0) -> + State = ssl_client_register_session(Host, Port, Session, State0), {noreply, State}; -handle_cast({register_session, Port, Session}, - #state{session_cache_server = Cache, - session_cache_cb = CacheCb} = State) -> - TimeStamp = calendar:datetime_to_gregorian_seconds({date(), time()}), - NewSession = Session#session{time_stamp = TimeStamp}, - CacheCb:update(Cache, {Port, NewSession#session.session_id}, NewSession), +handle_cast({register_session, Port, Session}, State0) -> + State = server_register_session(Port, Session, State0), {noreply, State}; handle_cast({invalidate_session, Host, Port, @@ -380,13 +383,17 @@ handle_cast({invalidate_pem, File}, handle_info(validate_sessions, #state{session_cache_cb = CacheCb, session_cache_client = ClientCache, session_cache_server = ServerCache, - session_lifetime = LifeTime + session_lifetime = LifeTime, + session_client_invalidator = Client, + session_server_invalidator = Server } = State) -> Timer = erlang:send_after(?SESSION_VALIDATION_INTERVAL, self(), validate_sessions), - start_session_validator(ClientCache, CacheCb, LifeTime), - start_session_validator(ServerCache, CacheCb, LifeTime), - {noreply, State#state{session_validation_timer = Timer}}; + CPid = start_session_validator(ClientCache, CacheCb, LifeTime, Client), + SPid = start_session_validator(ServerCache, CacheCb, LifeTime, Server), + {noreply, State#state{session_validation_timer = Timer, + session_client_invalidator = CPid, + session_server_invalidator = SPid}}; handle_info({delayed_clean_session, Key, Cache}, #state{session_cache_cb = CacheCb @@ -413,10 +420,10 @@ handle_info({clean_cert_db, Ref, File}, end, {noreply, State}; -handle_info({'EXIT', _, _}, State) -> - %% Session validator died!! Do we need to take any action? - %% maybe error log - {noreply, State}; +handle_info({'EXIT', Pid, _}, #state{session_client_invalidator = Pid} = State) -> + {noreply, State#state{session_client_invalidator = undefined}}; +handle_info({'EXIT', Pid, _}, #state{session_server_invalidator = Pid} = State) -> + {noreply, State#state{session_server_invalidator = undefined}}; handle_info(_Info, State) -> {noreply, State}. @@ -473,9 +480,11 @@ validate_session(Port, Session, LifeTime) -> invalidate_session(Port, Session) end. -start_session_validator(Cache, CacheCb, LifeTime) -> +start_session_validator(Cache, CacheCb, LifeTime, undefined) -> spawn_link(?MODULE, init_session_validator, - [[get(ssl_manager), Cache, CacheCb, LifeTime]]). + [[get(ssl_manager), Cache, CacheCb, LifeTime]]); +start_session_validator(_,_,_, Pid) -> + Pid. init_session_validator([SslManagerName, Cache, CacheCb, LifeTime]) -> put(ssl_manager, SslManagerName), @@ -497,7 +506,15 @@ delay_time() -> ?CLEAN_SESSION_DB end. -invalidate_session(Cache, CacheCb, Key, Session, #state{last_delay_timer = LastTimer} = State) -> +max_session_cache_size(CacheType) -> + case application:get_env(ssl, CacheType) of + {ok, Size} when is_integer(Size) -> + Size; + _ -> + ?DEFAULT_MAX_SESSION_CACHE + end. + +invalidate_session(Cache, CacheCb, Key, Session, State) -> case CacheCb:lookup(Cache, Key) of undefined -> %% Session is already invalidated {noreply, State}; @@ -505,15 +522,23 @@ invalidate_session(Cache, CacheCb, Key, Session, #state{last_delay_timer = LastT CacheCb:delete(Cache, Key), {noreply, State}; _ -> - %% When a registered session is invalidated we need to wait a while before deleting - %% it as there might be pending connections that rightfully needs to look - %% up the session data but new connections should not get to use this session. - CacheCb:update(Cache, Key, Session#session{is_resumable = false}), - TRef = - erlang:send_after(delay_time(), self(), {delayed_clean_session, Key, Cache}), - {noreply, State#state{last_delay_timer = last_delay_timer(Key, TRef, LastTimer)}} + delayed_invalidate_session(CacheCb, Cache, Key, Session, State) end. +delayed_invalidate_session(CacheCb, Cache, Key, Session, + #state{last_delay_timer = LastTimer} = State) -> + %% When a registered session is invalidated we need to + %% wait a while before deleting it as there might be + %% pending connections that rightfully needs to look up + %% the session data but new connections should not get to + %% use this session. + CacheCb:update(Cache, Key, Session#session{is_resumable = false}), + TRef = + erlang:send_after(delay_time(), self(), + {delayed_clean_session, Key, Cache}), + {noreply, State#state{last_delay_timer = + last_delay_timer(Key, TRef, LastTimer)}}. + last_delay_timer({{_,_},_}, TRef, {LastServer, _}) -> {LastServer, TRef}; last_delay_timer({_,_}, TRef, {_, LastClient}) -> @@ -532,12 +557,12 @@ new_id(Port, Tries, Cache, CacheCb) -> Id = crypto:rand_bytes(?NUM_OF_SESSION_ID_BYTES), case CacheCb:lookup(Cache, {Port, Id}) of undefined -> - Now = calendar:datetime_to_gregorian_seconds({date(), time()}), + Now = erlang:monotonic_time(), %% New sessions can not be set to resumable %% until handshake is compleate and the %% other session values are set. CacheCb:update(Cache, {Port, Id}, #session{session_id = Id, - is_resumable = false, + is_resumable = new, time_stamp = Now}), Id; _ -> @@ -559,15 +584,62 @@ clean_cert_db(Ref, CertDb, RefDb, PemCache, File) -> ok end. +ssl_client_register_session(Host, Port, Session, #state{session_cache_client = Cache, + session_cache_cb = CacheCb, + session_cache_client_max = Max, + session_client_invalidator = Pid0} = State) -> + TimeStamp = erlang:monotonic_time(), + NewSession = Session#session{time_stamp = TimeStamp}, + + case CacheCb:select_session(Cache, {Host, Port}) of + no_session -> + Pid = do_register_session({{Host, Port}, + NewSession#session.session_id}, + NewSession, Max, Pid0, Cache, CacheCb), + State#state{session_client_invalidator = Pid}; + Sessions -> + register_unique_session(Sessions, NewSession, {Host, Port}, State) + end. + +server_register_session(Port, Session, #state{session_cache_server_max = Max, + session_cache_server = Cache, + session_cache_cb = CacheCb, + session_server_invalidator = Pid0} = State) -> + TimeStamp = erlang:monotonic_time(), + NewSession = Session#session{time_stamp = TimeStamp}, + Pid = do_register_session({Port, NewSession#session.session_id}, + NewSession, Max, Pid0, Cache, CacheCb), + State#state{session_server_invalidator = Pid}. + +do_register_session(Key, Session, Max, Pid, Cache, CacheCb) -> + try CacheCb:size(Cache) of + N when N > Max -> + invalidate_session_cache(Pid, CacheCb, Cache); + _ -> + CacheCb:update(Cache, Key, Session), + Pid + catch + error:undef -> + CacheCb:update(Cache, Key, Session), + Pid + end. + + %% Do not let dumb clients create a gigantic session table %% for itself creating big delays at connection time. -register_unique_session(Sessions, Session, CacheCb, Cache, PartialKey) -> +register_unique_session(Sessions, Session, PartialKey, + #state{session_cache_client_max = Max, + session_cache_client = Cache, + session_cache_cb = CacheCb, + session_client_invalidator = Pid0} = State) -> case exists_equivalent(Session , Sessions) of true -> - ok; + State; false -> - CacheCb:update(Cache, {PartialKey, - Session#session.session_id}, Session) + Pid = do_register_session({PartialKey, + Session#session.session_id}, + Session, Max, Pid0, Cache, CacheCb), + State#state{session_client_invalidator = Pid} end. exists_equivalent(_, []) -> @@ -622,7 +694,8 @@ pem_check_interval() -> end. is_before_checkpoint(Time, CheckPoint) -> - calendar:datetime_to_gregorian_seconds(calendar:now_to_datetime(CheckPoint)) - + calendar:datetime_to_gregorian_seconds( + calendar:now_to_datetime(CheckPoint)) - calendar:datetime_to_gregorian_seconds(Time) > 0. add_trusted_certs(Pid, Trustedcerts, Db) -> @@ -643,3 +716,17 @@ crl_db_info([_,_,_,Local], {internal, Info}) -> crl_db_info(_, UserCRLDb) -> UserCRLDb. +%% Only start a session invalidator if there is not +%% one already active +invalidate_session_cache(undefined, CacheCb, Cache) -> + start_session_validator(Cache, CacheCb, {invalidate_before, erlang:monotonic_time()}, undefined); +invalidate_session_cache(Pid, _CacheCb, _Cache) -> + Pid. + +load_mitigation() -> + MSec = rand:uniform(?LOAD_MITIGATION), + receive + after + MSec -> + continue + end. diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl index 75cfecdf5e..ce6b8fb84f 100644 --- a/lib/ssl/src/ssl_record.erl +++ b/lib/ssl/src/ssl_record.erl @@ -311,9 +311,19 @@ set_pending_cipher_state(#connection_states{pending_read = Read, %% %% Description: Encodes a handshake message to send on the ssl-socket. %%-------------------------------------------------------------------- -encode_handshake(Frag, Version, ConnectionStates) -> - encode_plain_text(?HANDSHAKE, Version, Frag, ConnectionStates). - +encode_handshake(Frag, Version, + #connection_states{current_write = + #connection_state{ + security_parameters = + #security_parameters{bulk_cipher_algorithm = BCA}}} = + ConnectionStates) -> + case iolist_size(Frag) of + N when N > ?MAX_PLAIN_TEXT_LENGTH -> + Data = split_bin(iolist_to_binary(Frag), ?MAX_PLAIN_TEXT_LENGTH, Version, BCA), + encode_iolist(?HANDSHAKE, Data, Version, ConnectionStates); + _ -> + encode_plain_text(?HANDSHAKE, Version, Frag, ConnectionStates) + end. %%-------------------------------------------------------------------- -spec encode_alert_record(#alert{}, ssl_version(), #connection_states{}) -> {iolist(), #connection_states{}}. diff --git a/lib/ssl/src/ssl_session.erl b/lib/ssl/src/ssl_session.erl index 1770faf1ff..2b24bff5ff 100644 --- a/lib/ssl/src/ssl_session.erl +++ b/lib/ssl/src/ssl_session.erl @@ -31,8 +31,6 @@ %% Internal application API -export([is_new/2, client_id/4, server_id/6, valid_session/2]). --define('24H_in_sec', 8640). - -type seconds() :: integer(). %%-------------------------------------------------------------------- @@ -63,13 +61,16 @@ client_id(ClientInfo, Cache, CacheCb, OwnCert) -> SessionId end. --spec valid_session(#session{}, seconds()) -> boolean(). +-spec valid_session(#session{}, seconds() | {invalidate_before, integer()}) -> boolean(). %% %% Description: Check that the session has not expired %%-------------------------------------------------------------------- +valid_session(#session{time_stamp = TimeStamp}, {invalidate_before, Before}) -> + TimeStamp > Before; valid_session(#session{time_stamp = TimeStamp}, LifeTime) -> - Now = calendar:datetime_to_gregorian_seconds({date(), time()}), - Now - TimeStamp < LifeTime. + Now = erlang:monotonic_time(), + Lived = erlang:convert_time_unit(Now-TimeStamp, native, seconds), + Lived < LifeTime. server_id(Port, <<>>, _SslOpts, _Cert, _, _) -> {ssl_manager:new_session_id(Port), undefined}; @@ -100,14 +101,14 @@ select_session([], _, _) -> no_session; select_session(Sessions, #ssl_options{ciphers = Ciphers}, OwnCert) -> IsNotResumable = - fun([_Id, Session]) -> + fun(Session) -> not (resumable(Session#session.is_resumable) andalso lists:member(Session#session.cipher_suite, Ciphers) andalso (OwnCert == Session#session.own_certificate)) end, case lists:dropwhile(IsNotResumable, Sessions) of [] -> no_session; - [[Id, _]|_] -> Id + [Session | _] -> Session#session.session_id end. is_resumable(_, _, #ssl_options{reuse_sessions = false}, _, _, _, _) -> diff --git a/lib/ssl/src/ssl_session_cache.erl b/lib/ssl/src/ssl_session_cache.erl index 11ed310477..9585e613e6 100644 --- a/lib/ssl/src/ssl_session_cache.erl +++ b/lib/ssl/src/ssl_session_cache.erl @@ -27,7 +27,7 @@ -include("ssl_internal.hrl"). -export([init/1, terminate/1, lookup/2, update/3, delete/2, foldl/3, - select_session/2]). + select_session/2, size/1]). %%-------------------------------------------------------------------- %% Description: Return table reference. Called by ssl_manager process. @@ -83,7 +83,13 @@ foldl(Fun, Acc0, Cache) -> %%-------------------------------------------------------------------- select_session(Cache, PartialKey) -> ets:select(Cache, - [{{{PartialKey,'$1'}, '$2'},[],['$$']}]). + [{{{PartialKey,'_'}, '$1'},[],['$1']}]). + +%%-------------------------------------------------------------------- +%% Description: Returns the cache size +%%-------------------------------------------------------------------- +size(Cache) -> + ets:info(Cache, size). %%-------------------------------------------------------------------- %%% Internal functions diff --git a/lib/ssl/src/ssl_session_cache_api.erl b/lib/ssl/src/ssl_session_cache_api.erl index 536b52c44b..8f62c25be5 100644 --- a/lib/ssl/src/ssl_session_cache_api.erl +++ b/lib/ssl/src/ssl_session_cache_api.erl @@ -33,3 +33,4 @@ -callback delete(db_handle(), key()) -> any(). -callback foldl(fun(), term(), db_handle()) -> term(). -callback select_session(db_handle(), {host(), inet:port_number()} | inet:port_number()) -> [#session{}]. +-callback size(db_handle()) -> integer(). diff --git a/lib/ssl/src/ssl_tls_dist_proxy.erl b/lib/ssl/src/ssl_tls_dist_proxy.erl index 273d3b5521..4c789793ec 100644 --- a/lib/ssl/src/ssl_tls_dist_proxy.erl +++ b/lib/ssl/src/ssl_tls_dist_proxy.erl @@ -20,7 +20,7 @@ -module(ssl_tls_dist_proxy). --export([listen/1, accept/1, connect/2, get_tcp_address/1]). +-export([listen/2, accept/2, connect/3, get_tcp_address/1]). -export([init/1, start_link/0, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3, ssl_options/2]). @@ -39,14 +39,63 @@ %% Internal application API %%==================================================================== -listen(Name) -> - gen_server:call(?MODULE, {listen, Name}, infinity). +listen(Driver, Name) -> + gen_server:call(?MODULE, {listen, Driver, Name}, infinity). + +accept(Driver, Listen) -> + gen_server:call(?MODULE, {accept, Driver, Listen}, infinity). + +connect(Driver, Ip, Port) -> + gen_server:call(?MODULE, {connect, Driver, Ip, Port}, infinity). + + +do_listen(Options) -> + {First,Last} = case application:get_env(kernel,inet_dist_listen_min) of + {ok,N} when is_integer(N) -> + case application:get_env(kernel, + inet_dist_listen_max) of + {ok,M} when is_integer(M) -> + {N,M}; + _ -> + {N,N} + end; + _ -> + {0,0} + end, + do_listen(First, Last, listen_options([{backlog,128}|Options])). + +do_listen(First,Last,_) when First > Last -> + {error,eaddrinuse}; +do_listen(First,Last,Options) -> + case gen_tcp:listen(First, Options) of + {error, eaddrinuse} -> + do_listen(First+1,Last,Options); + Other -> + Other + end. -accept(Listen) -> - gen_server:call(?MODULE, {accept, Listen}, infinity). +listen_options(Opts0) -> + Opts1 = + case application:get_env(kernel, inet_dist_use_interface) of + {ok, Ip} -> + [{ip, Ip} | Opts0]; + _ -> + Opts0 + end, + case application:get_env(kernel, inet_dist_listen_options) of + {ok,ListenOpts} -> + ListenOpts ++ Opts1; + _ -> + Opts1 + end. -connect(Ip, Port) -> - gen_server:call(?MODULE, {connect, Ip, Port}, infinity). +connect_options(Opts) -> + case application:get_env(kernel, inet_dist_connect_options) of + {ok,ConnectOpts} -> + lists:ukeysort(1, ConnectOpts ++ Opts); + _ -> + Opts + end. %%==================================================================== %% gen_server callbacks @@ -59,29 +108,34 @@ init([]) -> process_flag(priority, max), {ok, #state{}}. -handle_call({listen, Name}, _From, State) -> - case gen_tcp:listen(0, [{active, false}, {packet,?PPRE}]) of +handle_call({listen, Driver, Name}, _From, State) -> + case gen_tcp:listen(0, [{active, false}, {packet,?PPRE}, {ip, loopback}]) of {ok, Socket} -> - {ok, World} = gen_tcp:listen(0, [{active, false}, binary, {packet,?PPRE}]), + {ok, World} = do_listen([{active, false}, binary, {packet,?PPRE}, {reuseaddr, true}, + Driver:family()]), {ok, TcpAddress} = get_tcp_address(Socket), {ok, WorldTcpAddress} = get_tcp_address(World), {_,Port} = WorldTcpAddress#net_address.address, - {ok, Creation} = erl_epmd:register_node(Name, Port), - {reply, {ok, {Socket, TcpAddress, Creation}}, - State#state{listen={Socket, World}}}; + case erl_epmd:register_node(Name, Port) of + {ok, Creation} -> + {reply, {ok, {Socket, TcpAddress, Creation}}, + State#state{listen={Socket, World}}}; + {error, _} = Error -> + {reply, Error, State} + end; Error -> {reply, Error, State} end; -handle_call({accept, Listen}, {From, _}, State = #state{listen={_, World}}) -> +handle_call({accept, _Driver, Listen}, {From, _}, State = #state{listen={_, World}}) -> Self = self(), ErtsPid = spawn_link(fun() -> accept_loop(Self, erts, Listen, From) end), WorldPid = spawn_link(fun() -> accept_loop(Self, world, World, Listen) end), {reply, ErtsPid, State#state{accept_loop={ErtsPid, WorldPid}}}; -handle_call({connect, Ip, Port}, {From, _}, State) -> +handle_call({connect, Driver, Ip, Port}, {From, _}, State) -> Me = self(), - Pid = spawn_link(fun() -> setup_proxy(Ip, Port, Me) end), + Pid = spawn_link(fun() -> setup_proxy(Driver, Ip, Port, Me) end), receive {Pid, go_ahead, LPort} -> Res = {ok, Socket} = try_connect(LPort), @@ -134,6 +188,7 @@ accept_loop(Proxy, erts = Type, Listen, Extra) -> Extra ! {accept,self(),Socket,inet,proxy}, receive {_Kernel, controller, Pid} -> + inet:setopts(Socket, [nodelay()]), ok = gen_tcp:controlling_process(Socket, Pid), flush_old_controller(Pid, Socket), Pid ! {self(), controller}; @@ -150,6 +205,7 @@ accept_loop(Proxy, world = Type, Listen, Extra) -> case gen_tcp:accept(Listen) of {ok, Socket} -> Opts = get_ssl_options(server), + wait_for_code_server(), case ssl:ssl_accept(Socket, Opts) of {ok, SslSocket} -> PairHandler = @@ -158,6 +214,11 @@ accept_loop(Proxy, world = Type, Listen, Extra) -> end), ok = ssl:controlling_process(SslSocket, PairHandler), flush_old_controller(PairHandler, SslSocket); + {error, {options, _}} = Error -> + %% Bad options: that's probably our fault. Let's log that. + error_logger:error_msg("Cannot accept TLS distribution connection: ~s~n", + [ssl:format_error(Error)]), + gen_tcp:close(Socket); _ -> gen_tcp:close(Socket) end; @@ -166,20 +227,50 @@ accept_loop(Proxy, world = Type, Listen, Extra) -> end, accept_loop(Proxy, Type, Listen, Extra). +wait_for_code_server() -> + %% This is an ugly hack. Upgrading a socket to TLS requires the + %% crypto module to be loaded. Loading the crypto module triggers + %% its on_load function, which calls code:priv_dir/1 to find the + %% directory where its NIF library is. However, distribution is + %% started earlier than the code server, so the code server is not + %% necessarily started yet, and code:priv_dir/1 might fail because + %% of that, if we receive an incoming connection on the + %% distribution port early enough. + %% + %% If the on_load function of a module fails, the module is + %% unloaded, and the function call that triggered loading it fails + %% with 'undef', which is rather confusing. + %% + %% Thus, the ssl_tls_dist_proxy process will terminate, and be + %% restarted by ssl_dist_sup. However, it won't have any memory + %% of being asked by net_kernel to listen for incoming + %% connections. Hence, the node will believe that it's open for + %% distribution, but it actually isn't. + %% + %% So let's avoid that by waiting for the code server to start. + case whereis(code_server) of + undefined -> + timer:sleep(10), + wait_for_code_server(); + Pid when is_pid(Pid) -> + ok + end. + try_connect(Port) -> - case gen_tcp:connect({127,0,0,1}, Port, [{active, false}, {packet,?PPRE}]) of + case gen_tcp:connect({127,0,0,1}, Port, [{active, false}, {packet,?PPRE}, nodelay()]) of R = {ok, _S} -> R; {error, _R} -> try_connect(Port) end. -setup_proxy(Ip, Port, Parent) -> +setup_proxy(Driver, Ip, Port, Parent) -> process_flag(trap_exit, true), - Opts = get_ssl_options(client), - case ssl:connect(Ip, Port, [{active, true}, binary, {packet,?PPRE}] ++ Opts) of + Opts = connect_options(get_ssl_options(client)), + case ssl:connect(Ip, Port, [{active, true}, binary, {packet,?PPRE}, nodelay(), + Driver:family()] ++ Opts) of {ok, World} -> - {ok, ErtsL} = gen_tcp:listen(0, [{active, true}, {ip, {127,0,0,1}}, binary, {packet,?PPRE}]), + {ok, ErtsL} = gen_tcp:listen(0, [{active, true}, {ip, loopback}, binary, {packet,?PPRE}]), {ok, #net_address{address={_,LPort}}} = get_tcp_address(ErtsL), Parent ! {self(), go_ahead, LPort}, case gen_tcp:accept(ErtsL) of @@ -189,29 +280,50 @@ setup_proxy(Ip, Port, Parent) -> Err -> Parent ! {self(), Err} end; + {error, {options, _}} = Err -> + %% Bad options: that's probably our fault. Let's log that. + error_logger:error_msg("Cannot open TLS distribution connection: ~s~n", + [ssl:format_error(Err)]), + Parent ! {self(), Err}; Err -> Parent ! {self(), Err} end. + +%% we may not always want the nodelay behaviour +%% %% for performance reasons + +nodelay() -> + case application:get_env(kernel, dist_nodelay) of + undefined -> + {nodelay, true}; + {ok, true} -> + {nodelay, true}; + {ok, false} -> + {nodelay, false}; + _ -> + {nodelay, true} + end. + setup_connection(World, ErtsListen) -> process_flag(trap_exit, true), {ok, TcpAddress} = get_tcp_address(ErtsListen), {_Addr,Port} = TcpAddress#net_address.address, - {ok, Erts} = gen_tcp:connect({127,0,0,1}, Port, [{active, true}, binary, {packet,?PPRE}]), - ssl:setopts(World, [{active,true}, {packet,?PPRE}]), + {ok, Erts} = gen_tcp:connect({127,0,0,1}, Port, [{active, true}, binary, {packet,?PPRE}, nodelay()]), + ssl:setopts(World, [{active,true}, {packet,?PPRE}, nodelay()]), loop_conn_setup(World, Erts). loop_conn_setup(World, Erts) -> receive {ssl, World, Data = <<$a, _/binary>>} -> gen_tcp:send(Erts, Data), - ssl:setopts(World, [{packet,?PPOST}]), - inet:setopts(Erts, [{packet,?PPOST}]), + ssl:setopts(World, [{packet,?PPOST}, nodelay()]), + inet:setopts(Erts, [{packet,?PPOST}, nodelay()]), loop_conn(World, Erts); {tcp, Erts, Data = <<$a, _/binary>>} -> ssl:send(World, Data), - ssl:setopts(World, [{packet,?PPOST}]), - inet:setopts(Erts, [{packet,?PPOST}]), + ssl:setopts(World, [{packet,?PPOST}, nodelay()]), + inet:setopts(Erts, [{packet,?PPOST}, nodelay()]), loop_conn(World, Erts); {ssl, World, Data = <<_, _/binary>>} -> gen_tcp:send(Erts, Data), diff --git a/lib/ssl/src/ssl_v3.erl b/lib/ssl/src/ssl_v3.erl index 5e043624a7..f169059a75 100644 --- a/lib/ssl/src/ssl_v3.erl +++ b/lib/ssl/src/ssl_v3.erl @@ -144,6 +144,7 @@ suites() -> ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA, ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA, ?TLS_RSA_WITH_AES_128_CBC_SHA, + ?TLS_DHE_RSA_WITH_DES_CBC_SHA, ?TLS_RSA_WITH_DES_CBC_SHA ]. diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl index 7fda2377ee..93716d31b8 100644 --- a/lib/ssl/src/tls_connection.erl +++ b/lib/ssl/src/tls_connection.erl @@ -54,7 +54,7 @@ %% Alert and close handling -export([send_alert/2, handle_own_alert/4, handle_close_alert/3, handle_normal_shutdown/3, handle_unexpected_message/3, - workaround_transport_delivery_problems/2, alert_user/6, alert_user/9 + close/5, alert_user/6, alert_user/9 ]). %% Data handling @@ -168,9 +168,10 @@ hello(start, #state{host = Host, port = Port, role = client, Cache, CacheCb, Renegotiation, Cert), Version = Hello#client_hello.client_version, + HelloVersion = tls_record:lowest_protocol_version(SslOpts#ssl_options.versions), Handshake0 = ssl_handshake:init_handshake_history(), {BinMsg, ConnectionStates, Handshake} = - encode_handshake(Hello, Version, ConnectionStates0, Handshake0), + encode_handshake(Hello, HelloVersion, ConnectionStates0, Handshake0), Transport:send(Socket, BinMsg), State1 = State0#state{connection_states = ConnectionStates, negotiated_version = Version, %% Requested version @@ -181,8 +182,7 @@ hello(start, #state{host = Host, port = Port, role = client, next_state(hello, hello, Record, State); hello(Hello = #client_hello{client_version = ClientVersion, - extensions = #hello_extensions{hash_signs = HashSigns, - ec_point_formats = EcPointFormats, + extensions = #hello_extensions{ec_point_formats = EcPointFormats, elliptic_curves = EllipticCurves}}, State = #state{connection_states = ConnectionStates0, port = Port, session = #session{own_certificate = Cert} = Session0, @@ -190,28 +190,29 @@ hello(Hello = #client_hello{client_version = ClientVersion, session_cache = Cache, session_cache_cb = CacheCb, negotiated_protocol = CurrentProtocol, + key_algorithm = KeyExAlg, ssl_options = SslOpts}) -> + case tls_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb, - ConnectionStates0, Cert}, Renegotiation) of + ConnectionStates0, Cert, KeyExAlg}, Renegotiation) of #alert{} = Alert -> handle_own_alert(Alert, ClientVersion, hello, State); {Version, {Type, Session}, - ConnectionStates, Protocol0, ServerHelloExt} -> - + ConnectionStates, Protocol0, ServerHelloExt, HashSign} -> Protocol = case Protocol0 of - undefined -> CurrentProtocol; - _ -> Protocol0 - end, - - HashSign = ssl_handshake:select_hashsign(HashSigns, Cert, Version), - ssl_connection:hello({common_client_hello, Type, ServerHelloExt, HashSign}, + undefined -> CurrentProtocol; + _ -> Protocol0 + end, + ssl_connection:hello({common_client_hello, Type, ServerHelloExt}, State#state{connection_states = ConnectionStates, negotiated_version = Version, + hashsign_algorithm = HashSign, session = Session, client_ecc = {EllipticCurves, EcPointFormats}, negotiated_protocol = Protocol}, ?MODULE) end; -hello(Hello, + +hello(Hello = #server_hello{}, #state{connection_states = ConnectionStates0, negotiated_version = ReqVersion, role = client, @@ -763,6 +764,8 @@ handle_tls_handshake(Handle, StateName, case Handle(Packet, FsmReturn) of {next_state, NextStateName, State, _Timeout} -> handle_tls_handshake(Handle, NextStateName, State); + {next_state, NextStateName, State} -> + handle_tls_handshake(Handle, NextStateName, State); {stop, _,_} = Stop -> Stop end; @@ -924,8 +927,7 @@ handle_own_alert(Alert, Version, StateName, try %% Try to tell the other side {BinMsg, _} = ssl_alert:encode(Alert, Version, ConnectionStates), - Transport:send(Socket, BinMsg), - workaround_transport_delivery_problems(Socket, Transport) + Transport:send(Socket, BinMsg) catch _:_ -> %% Can crash if we are in a uninitialized state ignore end, @@ -977,21 +979,57 @@ invalidate_session(client, Host, Port, Session) -> invalidate_session(server, _, Port, Session) -> ssl_manager:invalidate_session(Port, Session). -workaround_transport_delivery_problems(Socket, gen_tcp = Transport) -> +%% User downgrades connection +%% When downgrading an TLS connection to a transport connection +%% we must recive the close message before releasing the +%% transport socket. +close({close, {Pid, Timeout}}, Socket, Transport, ConnectionStates, Check) when is_pid(Pid) -> + ssl_socket:setopts(Transport, Socket, [{active, false}, {packet, ssl_tls}]), + case Transport:recv(Socket, 0, Timeout) of + {ok, {ssl_tls, Socket, ?ALERT, Version, Fragment}} -> + case tls_record:decode_cipher_text(#ssl_tls{type = ?ALERT, + version = Version, + fragment = Fragment + }, ConnectionStates, Check) of + {#ssl_tls{fragment = Plain}, _} -> + [Alert| _] = decode_alerts(Plain), + downgrade(Alert, Transport, Socket, Pid) + end; + {error, timeout} -> + {error, timeout}; + _ -> + {error, no_tls_close} + end; +%% User closes or recursive call! +close({close, Timeout}, Socket, Transport = gen_tcp, _,_) -> + ssl_socket:setopts(Transport, Socket, [{active, false}]), + Transport:shutdown(Socket, write), + _ = Transport:recv(Socket, 0, Timeout), + ok; +%% Peer closed socket +close({shutdown, transport_closed}, Socket, Transport = gen_tcp, ConnectionStates, Check) -> + close({close, 0}, Socket, Transport, ConnectionStates, Check); +%% We generate fatal alert +close({shutdown, own_alert}, Socket, Transport = gen_tcp, ConnectionStates, Check) -> %% Standard trick to try to make sure all %% data sent to the tcp port is really delivered to the %% peer application before tcp port is closed so that the peer will %% get the correct TLS alert message and not only a transport close. - ssl_socket:setopts(Transport, Socket, [{active, false}]), - Transport:shutdown(Socket, write), - %% Will return when other side has closed or after 30 s + %% Will return when other side has closed or after timout millisec %% e.g. we do not want to hang if something goes wrong %% with the network but we want to maximise the odds that %% peer application gets all data sent on the tcp connection. - Transport:recv(Socket, 0, 30000); -workaround_transport_delivery_problems(Socket, Transport) -> + close({close, ?DEFAULT_TIMEOUT}, Socket, Transport, ConnectionStates, Check); +%% Other +close(_, Socket, Transport, _,_) -> Transport:close(Socket). - +downgrade(#alert{description = ?CLOSE_NOTIFY}, Transport, Socket, Pid) -> + ssl_socket:setopts(Transport, Socket, [{active, false}, {packet, 0}, {mode, binary}]), + Transport:controlling_process(Socket, Pid), + {ok, Socket}; +downgrade(_, _,_,_) -> + {error, no_tls_close}. + convert_state(#state{ssl_options = Options} = State, up, "5.3.5", "5.3.6") -> State#state{ssl_options = convert_options_partial_chain(Options, up)}; convert_state(#state{ssl_options = Options} = State, down, "5.3.6", "5.3.5") -> @@ -1031,3 +1069,4 @@ handle_sni_extension(#client_hello{extensions = HelloExtensions}, State0) -> end; handle_sni_extension(_, State0) -> State0. + diff --git a/lib/ssl/src/tls_handshake.erl b/lib/ssl/src/tls_handshake.erl index 0a6cb9f92d..f34eebb0e4 100644 --- a/lib/ssl/src/tls_handshake.erl +++ b/lib/ssl/src/tls_handshake.erl @@ -56,7 +56,7 @@ client_hello(Host, Port, ConnectionStates, Version = tls_record:highest_protocol_version(Versions), Pending = ssl_record:pending_connection_state(ConnectionStates, read), SecParams = Pending#connection_state.security_parameters, - AvailableCipherSuites = ssl_handshake:available_suites(UserSuites, Version), + AvailableCipherSuites = ssl_handshake:available_suites(UserSuites, Version), Extensions = ssl_handshake:client_hello_extensions(Host, Version, AvailableCipherSuites, SslOpts, ConnectionStates, Renegotiation), @@ -80,13 +80,13 @@ client_hello(Host, Port, ConnectionStates, -spec hello(#server_hello{} | #client_hello{}, #ssl_options{}, #connection_states{} | {inet:port_number(), #session{}, db_handle(), atom(), #connection_states{}, - binary() | undefined}, + binary() | undefined, ssl_cipher:key_algo()}, boolean()) -> {tls_record:tls_version(), session_id(), #connection_states{}, alpn | npn, binary() | undefined}| {tls_record:tls_version(), {resumed | new, #session{}}, #connection_states{}, binary() | undefined, - #hello_extensions{}} | + #hello_extensions{}, {ssl_cipher:hash(), ssl_cipher:sign_algo()} | undefined} | #alert{}. %% %% Description: Handles a recieved hello message @@ -149,26 +149,35 @@ get_tls_handshake(Version, Data, Buffer) -> %%% Internal functions %%-------------------------------------------------------------------- handle_client_hello(Version, #client_hello{session_id = SugesstedId, - cipher_suites = CipherSuites, - compression_methods = Compressions, - random = Random, - extensions = #hello_extensions{elliptic_curves = Curves} = HelloExt}, - #ssl_options{versions = Versions} = SslOpts, - {Port, Session0, Cache, CacheCb, ConnectionStates0, Cert}, Renegotiation) -> + cipher_suites = CipherSuites, + compression_methods = Compressions, + random = Random, + extensions = #hello_extensions{elliptic_curves = Curves, + signature_algs = ClientHashSigns} = HelloExt}, + #ssl_options{versions = Versions, + signature_algs = SupportedHashSigns} = SslOpts, + {Port, Session0, Cache, CacheCb, ConnectionStates0, Cert, _}, Renegotiation) -> case tls_record:is_acceptable_version(Version, Versions) of true -> + AvailableHashSigns = available_signature_algs(ClientHashSigns, SupportedHashSigns, Cert, Version), ECCCurve = ssl_handshake:select_curve(Curves, ssl_handshake:supported_ecc(Version)), {Type, #session{cipher_suite = CipherSuite} = Session1} - = ssl_handshake:select_session(SugesstedId, CipherSuites, Compressions, + = ssl_handshake:select_session(SugesstedId, CipherSuites, AvailableHashSigns, Compressions, Port, Session0#session{ecc = ECCCurve}, Version, SslOpts, Cache, CacheCb, Cert), case CipherSuite of no_suite -> ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY); _ -> - handle_client_hello_extensions(Version, Type, Random, CipherSuites, HelloExt, - SslOpts, Session1, ConnectionStates0, - Renegotiation) + {KeyExAlg,_,_,_} = ssl_cipher:suite_definition(CipherSuite), + case ssl_handshake:select_hashsign(ClientHashSigns, Cert, KeyExAlg, SupportedHashSigns, Version) of + #alert{} = Alert -> + Alert; + HashSign -> + handle_client_hello_extensions(Version, Type, Random, CipherSuites, HelloExt, + SslOpts, Session1, ConnectionStates0, + Renegotiation, HashSign) + end end; false -> ?ALERT_REC(?FATAL, ?PROTOCOL_VERSION) @@ -245,14 +254,14 @@ enc_handshake(HandshakeMsg, Version) -> handle_client_hello_extensions(Version, Type, Random, CipherSuites, - HelloExt, SslOpts, Session0, ConnectionStates0, Renegotiation) -> + HelloExt, SslOpts, Session0, ConnectionStates0, Renegotiation, HashSign) -> try ssl_handshake:handle_client_hello_extensions(tls_record, Random, CipherSuites, HelloExt, Version, SslOpts, Session0, ConnectionStates0, Renegotiation) of #alert{} = Alert -> Alert; {Session, ConnectionStates, Protocol, ServerHelloExt} -> - {Version, {Type, Session}, ConnectionStates, Protocol, ServerHelloExt} + {Version, {Type, Session}, ConnectionStates, Protocol, ServerHelloExt, HashSign} catch throw:Alert -> Alert end. @@ -269,3 +278,14 @@ handle_server_hello_extensions(Version, SessionId, Random, CipherSuite, {Version, SessionId, ConnectionStates, ProtoExt, Protocol} end. +available_signature_algs(undefined, SupportedHashSigns, _, {Major, Minor}) when + (Major >= 3) andalso (Minor >= 3) -> + SupportedHashSigns; +available_signature_algs(#hash_sign_algos{hash_sign_algos = ClientHashSigns}, SupportedHashSigns, + _, {Major, Minor}) when (Major >= 3) andalso (Minor >= 3) -> + sets:to_list(sets:intersection(sets:from_list(ClientHashSigns), + sets:from_list(SupportedHashSigns))); +available_signature_algs(_, _, _, _) -> + undefined. + + diff --git a/lib/ssl/src/tls_record.erl b/lib/ssl/src/tls_record.erl index aa524f0225..9348c8bbdd 100644 --- a/lib/ssl/src/tls_record.erl +++ b/lib/ssl/src/tls_record.erl @@ -41,8 +41,9 @@ -export([encode_plain_text/4]). %% Protocol version handling --export([protocol_version/1, lowest_protocol_version/2, - highest_protocol_version/1, is_higher/2, supported_protocol_versions/0, +-export([protocol_version/1, lowest_protocol_version/1, lowest_protocol_version/2, + highest_protocol_version/1, highest_protocol_version/2, + is_higher/2, supported_protocol_versions/0, is_acceptable_version/1, is_acceptable_version/2]). -export_type([tls_version/0, tls_atom_version/0]). @@ -257,6 +258,18 @@ lowest_protocol_version(Version = {M,_}, Version; lowest_protocol_version(_,Version) -> Version. + +%%-------------------------------------------------------------------- +-spec lowest_protocol_version([tls_version()]) -> tls_version(). +%% +%% Description: Lowest protocol version present in a list +%%-------------------------------------------------------------------- +lowest_protocol_version([]) -> + lowest_protocol_version(); +lowest_protocol_version(Versions) -> + [Ver | Vers] = Versions, + lowest_list_protocol_version(Ver, Vers). + %%-------------------------------------------------------------------- -spec highest_protocol_version([tls_version()]) -> tls_version(). %% @@ -266,19 +279,29 @@ highest_protocol_version([]) -> highest_protocol_version(); highest_protocol_version(Versions) -> [Ver | Vers] = Versions, - highest_protocol_version(Ver, Vers). + highest_list_protocol_version(Ver, Vers). -highest_protocol_version(Version, []) -> +%%-------------------------------------------------------------------- +-spec highest_protocol_version(tls_version(), tls_version()) -> tls_version(). +%% +%% Description: Highest protocol version of two given versions +%%-------------------------------------------------------------------- +highest_protocol_version(Version = {M, N}, {M, O}) when N > O -> + Version; +highest_protocol_version({M, _}, + Version = {M, _}) -> Version; -highest_protocol_version(Version = {N, M}, [{N, O} | Rest]) when M > O -> - highest_protocol_version(Version, Rest); -highest_protocol_version({M, _}, [Version = {M, _} | Rest]) -> - highest_protocol_version(Version, Rest); -highest_protocol_version(Version = {M,_}, [{N,_} | Rest]) when M > N -> - highest_protocol_version(Version, Rest); -highest_protocol_version(_, [Version | Rest]) -> - highest_protocol_version(Version, Rest). +highest_protocol_version(Version = {M,_}, + {N, _}) when M > N -> + Version; +highest_protocol_version(_,Version) -> + Version. +%%-------------------------------------------------------------------- +-spec is_higher(V1 :: tls_version(), V2::tls_version()) -> boolean(). +%% +%% Description: Is V1 > V2 +%%-------------------------------------------------------------------- is_higher({M, N}, {M, O}) when N > O -> true; is_higher({M, _}, {N, _}) when M > N -> @@ -352,6 +375,17 @@ is_acceptable_version(_,_) -> %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- + +lowest_list_protocol_version(Ver, []) -> + Ver; +lowest_list_protocol_version(Ver1, [Ver2 | Rest]) -> + lowest_list_protocol_version(lowest_protocol_version(Ver1, Ver2), Rest). + +highest_list_protocol_version(Ver, []) -> + Ver; +highest_list_protocol_version(Ver1, [Ver2 | Rest]) -> + highest_list_protocol_version(highest_protocol_version(Ver1, Ver2), Rest). + encode_tls_cipher_text(Type, {MajVer, MinVer}, Fragment) -> Length = erlang:iolist_size(Fragment), [<<?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer), ?UINT16(Length)>>, Fragment]. @@ -370,6 +404,10 @@ mac_hash({3, N} = Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment) highest_protocol_version() -> highest_protocol_version(supported_protocol_versions()). +lowest_protocol_version() -> + lowest_protocol_version(supported_protocol_versions()). + + sufficient_tlsv1_2_crypto_support() -> CryptoSupport = crypto:supports(), proplists:get_bool(sha256, proplists:get_value(hashs, CryptoSupport)). diff --git a/lib/ssl/src/tls_v1.erl b/lib/ssl/src/tls_v1.erl index 71e5f349dd..543bd33833 100644 --- a/lib/ssl/src/tls_v1.erl +++ b/lib/ssl/src/tls_v1.erl @@ -31,7 +31,8 @@ -export([master_secret/4, finished/5, certificate_verify/3, mac_hash/7, setup_keys/8, suites/1, prf/5, - ecc_curves/1, oid_to_enum/1, enum_to_oid/1]). + ecc_curves/1, oid_to_enum/1, enum_to_oid/1, + default_signature_algs/1, signature_algs/2]). %%==================================================================== %% Internal application API @@ -258,6 +259,54 @@ suites(3) -> ] ++ suites(2). + +signature_algs({3, 3}, HashSigns) -> + CryptoSupports = crypto:supports(), + Hashes = proplists:get_value(hashs, CryptoSupports), + PubKeys = proplists:get_value(public_keys, CryptoSupports), + Supported = lists:foldl(fun({Hash, dsa = Sign} = Alg, Acc) -> + case proplists:get_bool(dss, PubKeys) + andalso proplists:get_bool(Hash, Hashes) + andalso is_pair(Hash, Sign, Hashes) + of + true -> + [Alg | Acc]; + false -> + Acc + end; + ({Hash, Sign} = Alg, Acc) -> + case proplists:get_bool(Sign, PubKeys) + andalso proplists:get_bool(Hash, Hashes) + andalso is_pair(Hash, Sign, Hashes) + of + true -> + [Alg | Acc]; + false -> + Acc + end + end, [], HashSigns), + lists:reverse(Supported). + +default_signature_algs({3, 3} = Version) -> + Default = [%% SHA2 + {sha512, ecdsa}, + {sha512, rsa}, + {sha384, ecdsa}, + {sha384, rsa}, + {sha256, ecdsa}, + {sha256, rsa}, + {sha224, ecdsa}, + {sha224, rsa}, + %% SHA + {sha, ecdsa}, + {sha, rsa}, + {sha, dsa}, + %% MD5 + {md5, rsa}], + signature_algs(Version, Default); +default_signature_algs(_) -> + undefined. + %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- @@ -342,6 +391,17 @@ finished_label(client) -> finished_label(server) -> <<"server finished">>. +is_pair(sha, dsa, _) -> + true; +is_pair(_, dsa, _) -> + false; +is_pair(Hash, ecdsa, Hashs) -> + AtLeastSha = Hashs -- [md2,md4,md5], + lists:member(Hash, AtLeastSha); +is_pair(Hash, rsa, Hashs) -> + AtLeastMd5 = Hashs -- [md2,md4], + lists:member(Hash, AtLeastMd5). + %% list ECC curves in prefered order ecc_curves(_Minor) -> TLSCurves = [sect571r1,sect571k1,secp521r1,brainpoolP512r1, diff --git a/lib/ssl/test/erl_make_certs.erl b/lib/ssl/test/erl_make_certs.erl index 8e909a5b74..f5cada9021 100644 --- a/lib/ssl/test/erl_make_certs.erl +++ b/lib/ssl/test/erl_make_certs.erl @@ -334,7 +334,9 @@ make_key(dsa, _Opts) -> gen_dsa2(128, 20); %% Bytes i.e. {1024, 160} make_key(ec, _Opts) -> %% (OBS: for testing only) - gen_ec2(secp256k1). + CurveOid = hd(tls_v1:ecc_curves(0)), + NamedCurve = pubkey_cert_records:namedCurves(CurveOid), + gen_ec2(NamedCurve). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% RSA key generation (OBS: for testing only) diff --git a/lib/ssl/test/make_certs.erl b/lib/ssl/test/make_certs.erl index 7215a59823..5eebf773a7 100644 --- a/lib/ssl/test/make_certs.erl +++ b/lib/ssl/test/make_certs.erl @@ -116,16 +116,16 @@ do_append_files([F|Fs], RF) -> do_append_files(Fs, RF). rootCA(Root, Name, C) -> - create_ca_dir(Root, Name, ca_cnf(C#config{commonName = Name})), - create_self_signed_cert(Root, Name, req_cnf(C#config{commonName = Name}), C), + create_ca_dir(Root, Name, ca_cnf(Root, C#config{commonName = Name})), + create_self_signed_cert(Root, Name, req_cnf(Root, C#config{commonName = Name}), C), file:copy(filename:join([Root, Name, "cert.pem"]), filename:join([Root, Name, "cacerts.pem"])), gencrl(Root, Name, C). intermediateCA(Root, CA, ParentCA, C) -> - create_ca_dir(Root, CA, ca_cnf(C#config{commonName = CA})), + create_ca_dir(Root, CA, ca_cnf(Root, C#config{commonName = CA})), CARoot = filename:join([Root, CA]), CnfFile = filename:join([CARoot, "req.cnf"]), - file:write_file(CnfFile, req_cnf(C#config{commonName = CA})), + file:write_file(CnfFile, req_cnf(Root, C#config{commonName = CA})), KeyFile = filename:join([CARoot, "private", "key.pem"]), ReqFile = filename:join([CARoot, "req.pem"]), create_req(Root, CnfFile, KeyFile, ReqFile, C), @@ -147,7 +147,7 @@ enduser(Root, CA, User, C) -> UsrRoot = filename:join([Root, User]), file:make_dir(UsrRoot), CnfFile = filename:join([UsrRoot, "req.cnf"]), - file:write_file(CnfFile, req_cnf(C#config{commonName = User})), + file:write_file(CnfFile, req_cnf(Root, C#config{commonName = User})), KeyFile = filename:join([UsrRoot, "key.pem"]), ReqFile = filename:join([UsrRoot, "req.pem"]), create_req(Root, CnfFile, KeyFile, ReqFile, C), @@ -337,10 +337,10 @@ eval_cmd(Port, Cmd) -> %% Contents of configuration files %% -req_cnf(C) -> +req_cnf(Root, C) -> ["# Purpose: Configuration for requests (end users and CAs)." "\n" - "ROOTDIR = $ENV::ROOTDIR\n" + "ROOTDIR = " ++ Root ++ "\n" "\n" "[req]\n" @@ -371,10 +371,10 @@ req_cnf(C) -> "subjectKeyIdentifier = hash\n" "subjectAltName = email:copy\n"]. -ca_cnf(C = #config{issuing_distribution_point = true}) -> +ca_cnf(Root, C = #config{issuing_distribution_point = true}) -> ["# Purpose: Configuration for CAs.\n" "\n" - "ROOTDIR = $ENV::ROOTDIR\n" + "ROOTDIR = " ++ Root ++ "\n" "default_ca = ca\n" "\n" @@ -450,10 +450,10 @@ ca_cnf(C = #config{issuing_distribution_point = true}) -> "crlDistributionPoints=@crl_section\n" ]; -ca_cnf(C = #config{issuing_distribution_point = false}) -> +ca_cnf(Root, C = #config{issuing_distribution_point = false}) -> ["# Purpose: Configuration for CAs.\n" "\n" - "ROOTDIR = $ENV::ROOTDIR\n" + "ROOTDIR = " ++ Root ++ "\n" "default_ca = ca\n" "\n" diff --git a/lib/ssl/test/ssl_ECC_SUITE.erl b/lib/ssl/test/ssl_ECC_SUITE.erl index 6ea0466dde..75b639b23b 100644 --- a/lib/ssl/test/ssl_ECC_SUITE.erl +++ b/lib/ssl/test/ssl_ECC_SUITE.erl @@ -46,7 +46,7 @@ groups() -> {'tlsv1', [], all_versions_groups()}, {'erlang_server', [], key_cert_combinations()}, {'erlang_client', [], key_cert_combinations()}, - {'erlang', [], key_cert_combinations()} + {'erlang', [], key_cert_combinations() ++ misc()} ]. all_versions_groups ()-> @@ -65,6 +65,9 @@ key_cert_combinations() -> client_rsa_server_ecdsa ]. +misc()-> + [client_ecdsa_server_ecdsa_with_raw_key]. + %%-------------------------------------------------------------------- init_per_suite(Config0) -> end_per_suite(Config0), @@ -143,7 +146,7 @@ init_per_testcase(TestCase, Config) -> ct:log("Ciphers: ~p~n ", [ ssl:cipher_suites()]), end_per_testcase(TestCase, Config), ssl:start(), - ct:timetrap({seconds, 5}), + ct:timetrap({seconds, 15}), Config. end_per_testcase(_TestCase, Config) -> @@ -189,6 +192,32 @@ client_rsa_server_ecdsa(Config) when is_list(Config) -> SOpts = ?config(server_ecdsa_verify_opts, Config), basic_test(COpts, SOpts, Config). +client_ecdsa_server_ecdsa_with_raw_key(Config) when is_list(Config) -> + COpts = ?config(client_ecdsa_opts, Config), + SOpts = ?config(server_ecdsa_verify_opts, Config), + ServerCert = proplists:get_value(certfile, SOpts), + ServerKeyFile = proplists:get_value(keyfile, SOpts), + {ok, PemBin} = file:read_file(ServerKeyFile), + PemEntries = public_key:pem_decode(PemBin), + {'ECPrivateKey', Key, not_encrypted} = proplists:lookup('ECPrivateKey', PemEntries), + ServerKey = {'ECPrivateKey', Key}, + ServerCA = proplists:get_value(cacertfile, SOpts), + ClientCert = proplists:get_value(certfile, COpts), + ClientKey = proplists:get_value(keyfile, COpts), + ClientCA = proplists:get_value(cacertfile, COpts), + SType = ?config(server_type, Config), + CType = ?config(client_type, Config), + {Server, Port} = start_server_with_raw_key(SType, + ClientCA, ServerCA, + ServerCert, + ServerKey, + Config), + Client = start_client(CType, Port, ServerCA, ClientCA, + ClientCert, + ClientKey, Config), + check_result(Server, SType, Client, CType), + close(Server, Client). + %%-------------------------------------------------------------------- %% Internal functions ------------------------------------------------ %%-------------------------------------------------------------------- @@ -219,10 +248,13 @@ start_client(openssl, Port, CA, OwnCa, Cert, Key, Config) -> PrivDir = ?config(priv_dir, Config), NewCA = new_ca(filename:join(PrivDir, "new_ca.pem"), CA, OwnCa), Version = tls_record:protocol_version(tls_record:highest_protocol_version([])), - Cmd = "openssl s_client -verify 2 -port " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -cert " ++ Cert ++ " -CAfile " ++ NewCA - ++ " -key " ++ Key ++ " -host localhost -msg -debug", - OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + Exe = "openssl", + Args = ["s_client", "-verify", "2", "-port", integer_to_list(Port), + ssl_test_lib:version_flag(Version), + "-cert", Cert, "-CAfile", NewCA, + "-key", Key, "-host","localhost", "-msg", "-debug"], + + OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), true = port_command(OpenSslPort, "Hello world"), OpenSslPort; start_client(erlang, Port, CA, _, Cert, Key, Config) -> @@ -241,15 +273,14 @@ start_server(openssl, CA, OwnCa, Cert, Key, Config) -> Port = ssl_test_lib:inet_port(node()), Version = tls_record:protocol_version(tls_record:highest_protocol_version([])), - Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -verify 2 -cert " ++ Cert ++ " -CAfile " ++ NewCA - ++ " -key " ++ Key ++ " -msg -debug", - OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + Exe = "openssl", + Args = ["s_server", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version), + "-verify", "2", "-cert", Cert, "-CAfile", NewCA, + "-key", Key, "-msg", "-debug"], + OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), true = port_command(OpenSslPort, "Hello world"), {OpenSslPort, Port}; - start_server(erlang, CA, _, Cert, Key, Config) -> - {_, ServerNode, _} = ssl_test_lib:run_where(Config), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, @@ -260,6 +291,17 @@ start_server(erlang, CA, _, Cert, Key, Config) -> [{verify, verify_peer}, {cacertfile, CA}, {certfile, Cert}, {keyfile, Key}]}]), {Server, ssl_test_lib:inet_port(Server)}. +start_server_with_raw_key(erlang, CA, _, Cert, Key, Config) -> + {_, ServerNode, _} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, + send_recv_result_active, + []}}, + {options, + [{verify, verify_peer}, {cacertfile, CA}, + {certfile, Cert}, {key, Key}]}]), + {Server, ssl_test_lib:inet_port(Server)}. check_result(Server, erlang, Client, erlang) -> ssl_test_lib:check_result(Server, ok, Client, ok); diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index ecedb89c23..a07739d3de 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -35,7 +35,6 @@ -include("tls_record.hrl"). -include("tls_handshake.hrl"). --define('24H_in_sec', 86400). -define(TIMEOUT, 20000). -define(EXPIRE, 10). -define(SLEEP, 500). @@ -59,7 +58,7 @@ all() -> groups() -> [{basic, [], basic_tests()}, {options, [], options_tests()}, - {'tlsv1.2', [], all_versions_groups()}, + {'tlsv1.2', [], all_versions_groups() ++ [conf_signature_algs, no_common_signature_algs]}, {'tlsv1.1', [], all_versions_groups()}, {'tlsv1', [], all_versions_groups() ++ rizzo_tests()}, {'sslv3', [], all_versions_groups() ++ rizzo_tests() ++ [ciphersuite_vs_version]}, @@ -89,13 +88,15 @@ basic_tests() -> connect_dist, clear_pem_cache, defaults, - fallback + fallback, + cipher_format ]. options_tests() -> [der_input, misc_ssl_options, ssl_options_not_proplist, + raw_ssl_option, socket_options, invalid_inet_get_option, invalid_inet_get_option_not_list, @@ -121,6 +122,7 @@ options_tests() -> api_tests() -> [connection_info, + connection_information, peername, peercert, peercert_with_client_cert, @@ -129,18 +131,22 @@ api_tests() -> controlling_process, upgrade, upgrade_with_timeout, + downgrade, + close_with_timeout, shutdown, shutdown_write, shutdown_both, shutdown_error, hibernate, + hibernate_right_away, listen_socket, ssl_accept_timeout, ssl_recv_timeout, versions_option, server_name_indication_option, accept_pool, - new_options_in_accept + new_options_in_accept, + prf ]. session_tests() -> @@ -164,6 +170,7 @@ renegotiate_tests() -> cipher_tests() -> [cipher_suites, + cipher_suites_mix, ciphers_rsa_signed_certs, ciphers_rsa_signed_certs_openssl_names, ciphers_dsa_signed_certs, @@ -265,12 +272,12 @@ init_per_testcase(protocol_versions, Config) -> Config; init_per_testcase(reuse_session_expired, Config) -> - ct:timetrap({seconds, 30}), ssl:stop(), application:load(ssl), application:set_env(ssl, session_lifetime, ?EXPIRE), application:set_env(ssl, session_delay_cleanup_time, 500), ssl:start(), + ct:timetrap({seconds, 30}), Config; init_per_testcase(empty_protocol_versions, Config) -> @@ -303,7 +310,50 @@ init_per_testcase(TestCase, Config) when TestCase == client_renegotiate; ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()]), ct:timetrap({seconds, 30}), Config; -init_per_testcase(ssl_accept_timeout, Config) -> + +init_per_testcase(TestCase, Config) when TestCase == psk_cipher_suites; + TestCase == psk_with_hint_cipher_suites; + TestCase == ciphers_rsa_signed_certs; + TestCase == ciphers_rsa_signed_certs_openssl_names; + TestCase == versions_option, + TestCase == tcp_connect_big -> + ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()]), + + ct:timetrap({seconds, 30}), + Config; +init_per_testcase(rizzo, Config) -> + ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()]), + ct:timetrap({seconds, 40}), + Config; +init_per_testcase(prf, Config) -> + ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()]), + ct:timetrap({seconds, 40}), + case ?config(tc_group_path, Config) of + [] -> Prop = []; + [Prop] -> Prop + end, + case ?config(name, Prop) of + undefined -> TlsVersions = [sslv3, tlsv1, 'tlsv1.1', 'tlsv1.2']; + TlsVersion when is_atom(TlsVersion) -> + TlsVersions = [TlsVersion] + end, + PRFS=[md5, sha, sha256, sha384, sha512], + %All are the result of running tls_v1:prf(PrfAlgo, <<>>, <<>>, <<>>, 16) + %with the specified PRF algorithm + ExpectedPrfResults= + [{md5, <<96,139,180,171,236,210,13,10,28,32,2,23,88,224,235,199>>}, + {sha, <<95,3,183,114,33,169,197,187,231,243,19,242,220,228,70,151>>}, + {sha256, <<166,249,145,171,43,95,158,232,6,60,17,90,183,180,0,155>>}, + {sha384, <<153,182,217,96,186,130,105,85,65,103,123,247,146,91,47,106>>}, + {sha512, <<145,8,98,38,243,96,42,94,163,33,53,49,241,4,127,28>>}, + %TLS 1.0 and 1.1 PRF: + {md5sha, <<63,136,3,217,205,123,200,177,251,211,17,229,132,4,173,80>>}], + TestPlan = prf_create_plan(TlsVersions, PRFS, ExpectedPrfResults), + [{prf_test_plan, TestPlan} | Config]; + +init_per_testcase(TestCase, Config) when TestCase == ssl_accept_timeout; + TestCase == client_closes_socket; + TestCase == downgrade -> ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()]), ct:timetrap({seconds, 15}), Config; @@ -311,6 +361,14 @@ init_per_testcase(clear_pem_cache, Config) -> ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()]), ct:timetrap({seconds, 20}), Config; +init_per_testcase(raw_ssl_option, Config) -> + ct:timetrap({seconds, 5}), + case os:type() of + {unix,linux} -> + Config; + _ -> + {skip, "Raw options are platform-specific"} + end; init_per_testcase(_TestCase, Config) -> ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()]), @@ -397,6 +455,25 @@ new_options_in_accept(Config) when is_list(Config) -> ssl_test_lib:close(Server), ssl_test_lib:close(Client). %%-------------------------------------------------------------------- +prf() -> + [{doc,"Test that ssl:prf/5 uses the negotiated PRF."}]. +prf(Config) when is_list(Config) -> + TestPlan = ?config(prf_test_plan, Config), + case TestPlan of + [] -> ct:fail({error, empty_prf_test_plan}); + _ -> lists:foreach(fun(Suite) -> + lists:foreach( + fun(Test) -> + V = ?config(tls_ver, Test), + C = ?config(ciphers, Test), + E = ?config(expected, Test), + P = ?config(prf, Test), + prf_run_test(Config, V, C, E, P) + end, Suite) + end, TestPlan) + end. + +%%-------------------------------------------------------------------- connection_info() -> [{doc,"Test the API function ssl:connection_information/1"}]. @@ -415,7 +492,7 @@ connection_info(Config) when is_list(Config) -> {from, self()}, {mfa, {?MODULE, connection_info_result, []}}, {options, - [{ciphers,[{rsa,des_cbc,sha,no_export}]} | + [{ciphers,[{rsa,des_cbc,sha}]} | ClientOpts]}]), ct:log("Testcase ~p, Client ~p Server ~p ~n", @@ -432,6 +509,37 @@ connection_info(Config) when is_list(Config) -> ssl_test_lib:close(Client). %%-------------------------------------------------------------------- + +connection_information() -> + [{doc,"Test the API function ssl:connection_information/1"}]. +connection_information(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, connection_information_result, []}}, + {options, ServerOpts}]), + + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, connection_information_result, []}}, + {options, ClientOpts}]), + + ct:log("Testcase ~p, Client ~p Server ~p ~n", + [self(), Client, Server]), + + ServerMsg = ClientMsg = ok, + + ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + + +%%-------------------------------------------------------------------- protocol_versions() -> [{doc,"Test to set a list of protocol versions in app environment."}]. @@ -700,6 +808,14 @@ fallback(Config) when is_list(Config) -> Client, {error,{tls_alert,"inappropriate fallback"}}). %%-------------------------------------------------------------------- +cipher_format() -> + [{doc, "Test that cipher conversion from tuples to binarys works"}]. +cipher_format(Config) when is_list(Config) -> + {ok, Socket} = ssl:listen(0, [{ciphers, ssl:cipher_suites()}]), + ssl:close(Socket). + +%%-------------------------------------------------------------------- + peername() -> [{doc,"Test API function peername/1"}]. @@ -850,6 +966,31 @@ cipher_suites(Config) when is_list(Config) -> [_|_] =ssl:cipher_suites(openssl). %%-------------------------------------------------------------------- +cipher_suites_mix() -> + [{doc,"Test to have old and new cipher suites at the same time"}]. + +cipher_suites_mix(Config) when is_list(Config) -> + CipherSuites = [{ecdh_rsa,aes_128_cbc,sha256,sha256}, {rsa,aes_128_cbc,sha}], + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, + {options, [{ciphers, CipherSuites} | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). +%%-------------------------------------------------------------------- socket_options() -> [{doc,"Test API function getopts/2 and setopts/2"}]. @@ -1136,6 +1277,23 @@ ssl_options_not_proplist(Config) when is_list(Config) -> BadOption]). %%-------------------------------------------------------------------- +raw_ssl_option() -> + [{doc,"Ensure that a single 'raw' option is passed to ssl:listen correctly."}]. + +raw_ssl_option(Config) when is_list(Config) -> + % 'raw' option values are platform-specific; these are the Linux values: + IpProtoTcp = 6, + % Use TCP_KEEPIDLE, because (e.g.) TCP_MAXSEG can't be read back reliably. + TcpKeepIdle = 4, + KeepAliveTimeSecs = 55, + LOptions = [{raw, IpProtoTcp, TcpKeepIdle, <<KeepAliveTimeSecs:32/native>>}], + {ok, LSocket} = ssl:listen(0, LOptions), + % Per http://www.erlang.org/doc/man/inet.html#getopts-2, we have to specify + % exactly which raw option we want, and the size of the buffer. + {ok, [{raw, IpProtoTcp, TcpKeepIdle, <<KeepAliveTimeSecs:32/native>>}]} = ssl:getopts(LSocket, [{raw, IpProtoTcp, TcpKeepIdle, 4}]). + + +%%-------------------------------------------------------------------- versions() -> [{doc,"Test API function versions/0"}]. @@ -1391,6 +1549,53 @@ upgrade_with_timeout(Config) when is_list(Config) -> ssl_test_lib:close(Client). %%-------------------------------------------------------------------- +downgrade() -> + [{doc,"Test that you can downgarde an ssl connection to an tcp connection"}]. +downgrade(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, tls_downgrade, []}}, + {options, [{active, false} | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, tls_downgrade, []}}, + {options, [{active, false} |ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +close_with_timeout() -> + [{doc,"Test normal (not downgrade) ssl:close/2"}]. +close_with_timeout(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, tls_close, []}}, + {options,[{active, false} | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, tls_close, []}}, + {options, [{active, false} |ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok). + + +%%-------------------------------------------------------------------- tcp_connect() -> [{doc,"Test what happens when a tcp tries to connect, i,e. a bad (ssl) packet is sent first"}]. @@ -1428,6 +1633,7 @@ tcp_connect_big(Config) when is_list(Config) -> {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config), TcpOpts = [binary, {reuseaddr, true}], + Rand = crypto:rand_bytes(?MAX_CIPHER_TEXT_LENGTH+1), Server = ssl_test_lib:start_upgrade_server_error([{node, ServerNode}, {port, 0}, {from, self()}, {timeout, 5000}, @@ -1439,7 +1645,6 @@ tcp_connect_big(Config) when is_list(Config) -> {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {packet, 0}]), ct:log("Testcase ~p connected to Server ~p ~n", [self(), Server]), - Rand = crypto:rand_bytes(?MAX_CIPHER_TEXT_LENGTH+1), gen_tcp:send(Socket, <<?BYTE(0), ?BYTE(3), ?BYTE(1), ?UINT16(?MAX_CIPHER_TEXT_LENGTH), Rand/binary>>), @@ -2751,7 +2956,61 @@ ciphersuite_vs_version(Config) when is_list(Config) -> _ -> ct:fail({unexpected_server_hello, ServerHello}) end. - + +%%-------------------------------------------------------------------- +conf_signature_algs() -> + [{doc,"Test to set the signature_algs option on both client and server"}]. +conf_signature_algs(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result, []}}, + {options, [{active, false}, {signature_algs, [{sha256, rsa}]} | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = + ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result, []}}, + {options, [{active, false}, {signature_algs, [{sha256, rsa}]} | ClientOpts]}]), + + ct:log("Testcase ~p, Client ~p Server ~p ~n", + [self(), Client, Server]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + + +%%-------------------------------------------------------------------- +no_common_signature_algs() -> + [{doc,"Set the signature_algs option so that there client and server does not share any hash sign algorithms"}]. +no_common_signature_algs(Config) when is_list(Config) -> + + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + + Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, + {from, self()}, + {options, [{signature_algs, [{sha256, rsa}]} + | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {options, [{signature_algs, [{sha384, rsa}]} + | ClientOpts]}]), + + ssl_test_lib:check_result(Server, {error, {tls_alert, "insufficient security"}}, + Client, {error, {tls_alert, "insufficient security"}}). + %%-------------------------------------------------------------------- dont_crash_on_handshake_garbage() -> @@ -2831,6 +3090,43 @@ hibernate(Config) -> ssl_test_lib:close(Client). %%-------------------------------------------------------------------- + +hibernate_right_away() -> + [{doc,"Check that an SSL connection that is configured to hibernate " + "after 0 or 1 milliseconds hibernates as soon as possible and not " + "crashes"}]. + +hibernate_right_away(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + StartServerOpts = [{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, + {options, ServerOpts}], + StartClientOpts = [return_socket, + {node, ClientNode}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}], + + Server1 = ssl_test_lib:start_server(StartServerOpts), + Port1 = ssl_test_lib:inet_port(Server1), + {Client1, #sslsocket{}} = ssl_test_lib:start_client(StartClientOpts ++ + [{port, Port1}, {options, [{hibernate_after, 0}|ClientOpts]}]), + ssl_test_lib:close(Server1), + ssl_test_lib:close(Client1), + + Server2 = ssl_test_lib:start_server(StartServerOpts), + Port2 = ssl_test_lib:inet_port(Server2), + {Client2, #sslsocket{}} = ssl_test_lib:start_client(StartClientOpts ++ + [{port, Port2}, {options, [{hibernate_after, 1}|ClientOpts]}]), + ssl_test_lib:close(Server2), + ssl_test_lib:close(Client2). + +%%-------------------------------------------------------------------- listen_socket() -> [{doc,"Check error handling and inet compliance when calling API functions with listen sockets."}]. @@ -3411,8 +3707,84 @@ basic_test(Config) -> ssl_test_lib:close(Server), ssl_test_lib:close(Client). +prf_create_plan(TlsVersions, PRFs, Results) -> + lists:foldl(fun(Ver, Acc) -> + A = prf_ciphers_and_expected(Ver, PRFs, Results), + [A|Acc] + end, [], TlsVersions). +prf_ciphers_and_expected(TlsVer, PRFs, Results) -> + case TlsVer of + TlsVer when TlsVer == sslv3 orelse TlsVer == tlsv1 + orelse TlsVer == 'tlsv1.1' -> + Ciphers = ssl:cipher_suites(), + {_, Expected} = lists:keyfind(md5sha, 1, Results), + [[{tls_ver, TlsVer}, {ciphers, Ciphers}, {expected, Expected}, {prf, md5sha}]]; + 'tlsv1.2' -> + lists:foldl( + fun(PRF, Acc) -> + Ciphers = prf_get_ciphers(TlsVer, PRF), + case Ciphers of + [] -> + ct:log("No ciphers for PRF algorithm ~p. Skipping.", [PRF]), + Acc; + Ciphers -> + {_, Expected} = lists:keyfind(PRF, 1, Results), + [[{tls_ver, TlsVer}, {ciphers, Ciphers}, {expected, Expected}, + {prf, PRF}] | Acc] + end + end, [], PRFs) + end. +prf_get_ciphers(TlsVer, PRF) -> + case TlsVer of + 'tlsv1.2' -> + lists:filter( + fun(C) when tuple_size(C) == 4 andalso + element(4, C) == PRF -> + true; + (_) -> false + end, ssl:cipher_suites()) + end. +prf_run_test(_, TlsVer, [], _, Prf) -> + ct:fail({error, cipher_list_empty, TlsVer, Prf}); +prf_run_test(Config, TlsVer, Ciphers, Expected, Prf) -> + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + BaseOpts = [{active, true}, {versions, [TlsVer]}, {ciphers, Ciphers}], + ServerOpts = BaseOpts ++ ?config(server_opts, Config), + ClientOpts = BaseOpts ++ ?config(client_opts, Config), + Server = ssl_test_lib:start_server( + [{node, ServerNode}, {port, 0}, {from, self()}, + {mfa, {?MODULE, prf_verify_value, [TlsVer, Expected, Prf]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client( + [{node, ClientNode}, {port, Port}, + {host, Hostname}, {from, self()}, + {mfa, {?MODULE, prf_verify_value, [TlsVer, Expected, Prf]}}, + {options, ClientOpts}]), + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). +prf_verify_value(Socket, TlsVer, Expected, Algo) -> + Ret = ssl:prf(Socket, <<>>, <<>>, [<<>>], 16), + case TlsVer of + sslv3 -> + case Ret of + {error, undefined} -> ok; + _ -> + {error, {expected, {error, undefined}, + got, Ret, tls_ver, TlsVer, prf_algorithm, Algo}} + end; + _ -> + case Ret of + {ok, Expected} -> ok; + {ok, Val} -> {error, {expected, Expected, got, Val, tls_ver, TlsVer, + prf_algorithm, Algo}} + end + end. + send_recv_result_timeout_client(Socket) -> {error, timeout} = ssl:recv(Socket, 11, 500), + {error, timeout} = ssl:recv(Socket, 11, 0), ssl:send(Socket, "Hello world"), receive Msg -> @@ -3859,7 +4231,7 @@ run_suites(Ciphers, Version, Config, Type) -> end. erlang_cipher_suite(Suite) when is_list(Suite)-> - ssl:suite_definition(ssl_cipher:openssl_suite(Suite)); + ssl_cipher:erl_suite_definition(ssl_cipher:openssl_suite(Suite)); erlang_cipher_suite(Suite) -> Suite. @@ -3880,11 +4252,11 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) -> Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, - {from, self()}, - {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}}, - {options, - [{ciphers,[CipherSuite]} | - ClientOpts]}]), + {from, self()}, + {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}}, + {options, + [{ciphers,[CipherSuite]} | + ClientOpts]}]), Result = ssl_test_lib:wait_for_result(Server, ok, Client, ok), @@ -3898,6 +4270,17 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) -> [{ErlangCipherSuite, Error}] end. +connection_information_result(Socket) -> + {ok, Info = [_ | _]} = ssl:connection_information(Socket), + case length(Info) > 3 of + true -> + %% Atleast one ssloption() is set + ct:log("Info ~p", [Info]), + ok; + false -> + ct:fail(no_ssl_options_returned) + end. + connection_info_result(Socket) -> {ok, Info} = ssl:connection_information(Socket, [protocol, cipher_suite]), {ok, {proplists:get_value(protocol, Info), proplists:get_value(cipher_suite, Info)}}. @@ -3914,6 +4297,33 @@ connect_dist_c(S) -> {ok, Test} = ssl:recv(S, 0, 10000), ok. +tls_downgrade(Socket) -> + ok = ssl_test_lib:send_recv_result(Socket), + case ssl:close(Socket, {self(), 10000}) of + {ok, TCPSocket} -> + inet:setopts(TCPSocket, [{active, true}]), + gen_tcp:send(TCPSocket, "Downgraded"), + receive + {tcp, TCPSocket, <<"Downgraded">>} -> + ok; + {tcp_closed, TCPSocket} -> + ct:pal("Peer timed out, downgrade aborted"), + ok; + Other -> + {error, Other} + end; + {error, timeout} -> + ct:pal("Timed out, downgrade aborted"), + ok; + Fail -> + {error, Fail} + end. + +tls_close(Socket) -> + ok = ssl_test_lib:send_recv_result(Socket), + ok = ssl:close(Socket, 5000). + + %% First two clauses handles 1/n-1 splitting countermeasure Rizzo/Duong-Beast treashold(N, {3,0}) -> (N div 2) + 1; @@ -3997,6 +4407,12 @@ first_rsa_suite([{dhe_rsa, _, _} = Suite| _]) -> Suite; first_rsa_suite([{rsa, _, _} = Suite| _]) -> Suite; +first_rsa_suite([{ecdhe_rsa, _, _, _} = Suite | _]) -> + Suite; +first_rsa_suite([{dhe_rsa, _, _, _} = Suite| _]) -> + Suite; +first_rsa_suite([{rsa, _, _, _} = Suite| _]) -> + Suite; first_rsa_suite([_ | Rest]) -> first_rsa_suite(Rest). diff --git a/lib/ssl/test/ssl_certificate_verify_SUITE.erl b/lib/ssl/test/ssl_certificate_verify_SUITE.erl index 5940a86a7f..d10506cb69 100644 --- a/lib/ssl/test/ssl_certificate_verify_SUITE.erl +++ b/lib/ssl/test/ssl_certificate_verify_SUITE.erl @@ -66,7 +66,9 @@ tests() -> invalid_signature_client, invalid_signature_server, extended_key_usage_verify_peer, - extended_key_usage_verify_none]. + extended_key_usage_verify_none, + critical_extension_verify_peer, + critical_extension_verify_none]. error_handling_tests()-> [client_with_cert_cipher_suites_handshake, @@ -75,7 +77,8 @@ error_handling_tests()-> unknown_server_ca_accept_verify_none, unknown_server_ca_accept_verify_peer, unknown_server_ca_accept_backwardscompatibility, - no_authority_key_identifier]. + no_authority_key_identifier, + no_authority_key_identifier_and_nonstandard_encoding]. init_per_suite(Config0) -> catch crypto:stop(), @@ -794,6 +797,121 @@ extended_key_usage_verify_none(Config) when is_list(Config) -> ssl_test_lib:close(Client). %%-------------------------------------------------------------------- +critical_extension_verify_peer() -> + [{doc,"Test cert that has a critical unknown extension in verify_peer mode"}]. + +critical_extension_verify_peer(Config) when is_list(Config) -> + ClientOpts = ?config(client_verification_opts, Config), + ServerOpts = ?config(server_verification_opts, Config), + PrivDir = ?config(priv_dir, Config), + Active = ?config(active, Config), + ReceiveFunction = ?config(receive_function, Config), + + KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"), + NewCertName = integer_to_list(erlang:unique_integer()) ++ ".pem", + + ServerCertFile = proplists:get_value(certfile, ServerOpts), + NewServerCertFile = filename:join([PrivDir, "server", NewCertName]), + add_critical_netscape_cert_type(ServerCertFile, NewServerCertFile, KeyFile), + NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)], + + ClientCertFile = proplists:get_value(certfile, ClientOpts), + NewClientCertFile = filename:join([PrivDir, "client", NewCertName]), + add_critical_netscape_cert_type(ClientCertFile, NewClientCertFile, KeyFile), + NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)], + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server_error( + [{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, ReceiveFunction, []}}, + {options, [{verify, verify_peer}, {active, Active} | NewServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client_error( + [{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, ReceiveFunction, []}}, + {options, [{verify, verify_peer}, {active, Active} | NewClientOpts]}]), + + %% This certificate has a critical extension that we don't + %% understand. Therefore, verification should fail. + tcp_delivery_workaround(Server, {error, {tls_alert, "unsupported certificate"}}, + Client, {error, {tls_alert, "unsupported certificate"}}), + + ssl_test_lib:close(Server), + ok. + +%%-------------------------------------------------------------------- +critical_extension_verify_none() -> + [{doc,"Test cert that has a critical unknown extension in verify_none mode"}]. + +critical_extension_verify_none(Config) when is_list(Config) -> + ClientOpts = ?config(client_verification_opts, Config), + ServerOpts = ?config(server_verification_opts, Config), + PrivDir = ?config(priv_dir, Config), + Active = ?config(active, Config), + ReceiveFunction = ?config(receive_function, Config), + + KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"), + NewCertName = integer_to_list(erlang:unique_integer()) ++ ".pem", + + ServerCertFile = proplists:get_value(certfile, ServerOpts), + NewServerCertFile = filename:join([PrivDir, "server", NewCertName]), + add_critical_netscape_cert_type(ServerCertFile, NewServerCertFile, KeyFile), + NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)], + + ClientCertFile = proplists:get_value(certfile, ClientOpts), + NewClientCertFile = filename:join([PrivDir, "client", NewCertName]), + add_critical_netscape_cert_type(ClientCertFile, NewClientCertFile, KeyFile), + NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)], + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server( + [{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, ReceiveFunction, []}}, + {options, [{verify, verify_none}, {active, Active} | NewServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client( + [{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, ReceiveFunction, []}}, + {options, [{verify, verify_none}, {active, Active} | NewClientOpts]}]), + + %% This certificate has a critical extension that we don't + %% understand. But we're using `verify_none', so verification + %% shouldn't fail. + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client), + ok. + +add_critical_netscape_cert_type(CertFile, NewCertFile, KeyFile) -> + [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), + Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)), + + [{'Certificate', DerCert, _}] = ssl_test_lib:pem_to_der(CertFile), + OTPCert = public_key:pkix_decode_cert(DerCert, otp), + %% This is the "Netscape Cert Type" extension, telling us that the + %% certificate can be used for SSL clients and SSL servers. + NetscapeCertTypeExt = #'Extension'{ + extnID = {2,16,840,1,113730,1,1}, + critical = true, + extnValue = <<3,2,6,192>>}, + OTPTbsCert = OTPCert#'OTPCertificate'.tbsCertificate, + Extensions = OTPTbsCert#'OTPTBSCertificate'.extensions, + NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{ + extensions = [NetscapeCertTypeExt] ++ Extensions}, + NewDerCert = public_key:pkix_sign(NewOTPTbsCert, Key), + ssl_test_lib:der_to_pem(NewCertFile, [{'Certificate', NewDerCert, not_encrypted}]), + ok. + +%%-------------------------------------------------------------------- no_authority_key_identifier() -> [{doc, "Test cert that does not have authorityKeyIdentifier extension" " but are present in trusted certs db."}]. @@ -850,6 +968,68 @@ delete_authority_key_extension([Head | Rest], Acc) -> %%-------------------------------------------------------------------- +no_authority_key_identifier_and_nonstandard_encoding() -> + [{doc, "Test cert with nonstandard encoding that does not have" + " authorityKeyIdentifier extension but are present in trusted certs db."}]. + +no_authority_key_identifier_and_nonstandard_encoding(Config) when is_list(Config) -> + ClientOpts = ?config(client_verification_opts, Config), + ServerOpts = ?config(server_verification_opts, Config), + PrivDir = ?config(priv_dir, Config), + + KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"), + [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), + Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)), + + CertFile = proplists:get_value(certfile, ServerOpts), + NewCertFile = filename:join(PrivDir, "server/new_cert.pem"), + [{'Certificate', DerCert, _}] = ssl_test_lib:pem_to_der(CertFile), + ServerCert = public_key:pkix_decode_cert(DerCert, plain), + ServerTbsCert = ServerCert#'Certificate'.tbsCertificate, + Extensions0 = ServerTbsCert#'TBSCertificate'.extensions, + %% need to remove authorityKeyIdentifier extension to cause DB lookup by signature + Extensions = delete_authority_key_extension(Extensions0, []), + NewExtensions = replace_key_usage_extension(Extensions, []), + NewServerTbsCert = ServerTbsCert#'TBSCertificate'{extensions = NewExtensions}, + + ct:log("Extensions ~p~n, NewExtensions: ~p~n", [Extensions, NewExtensions]), + + TbsDer = public_key:pkix_encode('TBSCertificate', NewServerTbsCert, plain), + Sig = public_key:sign(TbsDer, md5, Key), + NewServerCert = ServerCert#'Certificate'{tbsCertificate = NewServerTbsCert, signature = Sig}, + NewDerCert = public_key:pkix_encode('Certificate', NewServerCert, plain), + ssl_test_lib:der_to_pem(NewCertFile, [{'Certificate', NewDerCert, not_encrypted}]), + NewServerOpts = [{certfile, NewCertFile} | proplists:delete(certfile, ServerOpts)], + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, + send_recv_result_active, []}}, + {options, [{active, true} | NewServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, + send_recv_result_active, []}}, + {options, [{verify, verify_peer} | ClientOpts]}]), + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +replace_key_usage_extension([], Acc) -> + lists:reverse(Acc); +replace_key_usage_extension([#'Extension'{extnID = ?'id-ce-keyUsage'} = E | Rest], Acc) -> + %% A nonstandard DER encoding of [digitalSignature, keyEncipherment] + Val = <<3, 2, 0, 16#A0>>, + replace_key_usage_extension(Rest, [E#'Extension'{extnValue = Val} | Acc]); +replace_key_usage_extension([Head | Rest], Acc) -> + replace_key_usage_extension(Rest, [Head | Acc]). + +%%-------------------------------------------------------------------- + invalid_signature_server() -> [{doc,"Test client with invalid signature"}]. diff --git a/lib/ssl/test/ssl_crl_SUITE.erl b/lib/ssl/test/ssl_crl_SUITE.erl index 44580be1ff..5b86027210 100644 --- a/lib/ssl/test/ssl_crl_SUITE.erl +++ b/lib/ssl/test/ssl_crl_SUITE.erl @@ -53,7 +53,7 @@ groups() -> {idp_crl, [], basic_tests()}]. basic_tests() -> - [crl_verify_valid, crl_verify_revoked]. + [crl_verify_valid, crl_verify_revoked, crl_verify_no_crl]. init_per_suite(Config) -> @@ -186,11 +186,6 @@ crl_verify_revoked(Config) when is_list(Config) -> {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, - {from, self()}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - ssl_crl_cache:insert({file, filename:join([PrivDir, "erlangCA", "crl.pem"])}), ssl_crl_cache:insert({file, filename:join([PrivDir, "otpCA", "crl.pem"])}), @@ -206,16 +201,55 @@ crl_verify_revoked(Config) when is_list(Config) -> {verify, verify_peer}] end, - Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {options, ClientOpts}]), - receive - {Server, AlertOrColse} -> - ct:pal("Server Alert or Close ~p", [AlertOrColse]) - end, - ssl_test_lib:check_result(Client, {error, {tls_alert, "certificate revoked"}}). + crl_verify_error(Hostname, ServerNode, ServerOpts, ClientNode, ClientOpts, + "certificate revoked"). +crl_verify_no_crl() -> + [{doc,"Verify a simple CRL chain when the CRL is missing"}]. +crl_verify_no_crl(Config) when is_list(Config) -> + PrivDir = ?config(cert_dir, Config), + Check = ?config(crl_check, Config), + ServerOpts = [{keyfile, filename:join([PrivDir, "server", "key.pem"])}, + {certfile, filename:join([PrivDir, "server", "cert.pem"])}, + {cacertfile, filename:join([PrivDir, "server", "cacerts.pem"])}], + ClientOpts = case ?config(idp_crl, Config) of + true -> + [{cacertfile, filename:join([PrivDir, "server", "cacerts.pem"])}, + {crl_check, Check}, + {crl_cache, {ssl_crl_cache, {internal, [{http, 5000}]}}}, + {verify, verify_peer}]; + false -> + [{cacertfile, filename:join([PrivDir, "server", "cacerts.pem"])}, + {crl_check, Check}, + {verify, verify_peer}] + end, + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + %% In case we're running an HTTP server that serves CRLs, let's + %% rename those files, so the CRL is absent when we try to verify + %% it. + %% + %% If we're not using an HTTP server, we just need to refrain from + %% adding the CRLs to the cache manually. + rename_crl(filename:join([PrivDir, "erlangCA", "crl.pem"])), + rename_crl(filename:join([PrivDir, "otpCA", "crl.pem"])), + + %% The expected outcome when the CRL is missing depends on the + %% crl_check setting. + case Check of + true -> + %% The error "revocation status undetermined" gets turned + %% into "bad certificate". + crl_verify_error(Hostname, ServerNode, ServerOpts, ClientNode, ClientOpts, + "bad certificate"); + peer -> + crl_verify_error(Hostname, ServerNode, ServerOpts, ClientNode, ClientOpts, + "bad certificate"); + best_effort -> + %% In "best effort" mode, we consider the certificate not + %% to be revoked if we can't find the appropriate CRL. + crl_verify_valid(Hostname, ServerNode, ServerOpts, ClientNode, ClientOpts) + end. crl_verify_valid(Hostname, ServerNode, ServerOpts, ClientNode, ClientOpts) -> Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, @@ -236,6 +270,22 @@ crl_verify_valid(Hostname, ServerNode, ServerOpts, ClientNode, ClientOpts) -> ssl_test_lib:close(Server), ssl_test_lib:close(Client). +crl_verify_error(Hostname, ServerNode, ServerOpts, ClientNode, ClientOpts, ExpectedAlert) -> + Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, + {from, self()}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {options, ClientOpts}]), + receive + {Server, AlertOrClose} -> + ct:pal("Server Alert or Close ~p", [AlertOrClose]) + end, + ssl_test_lib:check_result(Client, {error, {tls_alert, ExpectedAlert}}). + %%-------------------------------------------------------------------- %% Internal functions ------------------------------------------------ %%-------------------------------------------------------------------- @@ -259,3 +309,5 @@ make_dir_path(PathComponents) -> "", PathComponents). +rename_crl(Filename) -> + file:rename(Filename, Filename ++ ".notfound"). diff --git a/lib/ssl/test/ssl_dist_SUITE.erl b/lib/ssl/test/ssl_dist_SUITE.erl index 72d62b29a7..00f9ee8e3c 100644 --- a/lib/ssl/test/ssl_dist_SUITE.erl +++ b/lib/ssl/test/ssl_dist_SUITE.erl @@ -40,7 +40,8 @@ %% Common Test interface functions ----------------------------------- %%-------------------------------------------------------------------- all() -> - [basic, payload, plain_options, plain_verify_options]. + [basic, payload, plain_options, plain_verify_options, nodelay_option, + listen_port_options, listen_options, connect_options, use_interface]. groups() -> []. @@ -250,6 +251,173 @@ plain_verify_options(Config) when is_list(Config) -> stop_ssl_node(NH1), stop_ssl_node(NH2), success(Config). +%%-------------------------------------------------------------------- +nodelay_option() -> + [{doc,"Test specifying dist_nodelay option"}]. +nodelay_option(Config) -> + try + %% The default is 'true', so try setting it to 'false'. + application:set_env(kernel, dist_nodelay, false), + basic(Config) + after + application:unset_env(kernel, dist_nodelay) + end. + +listen_port_options() -> + [{doc, "Test specifying listening ports"}]. +listen_port_options(Config) when is_list(Config) -> + %% Start a node, and get the port number it's listening on. + NH1 = start_ssl_node(Config), + Node1 = NH1#node_handle.nodename, + Name1 = lists:takewhile(fun(C) -> C =/= $@ end, atom_to_list(Node1)), + {ok, NodesPorts} = apply_on_ssl_node(NH1, fun net_adm:names/0), + {Name1, Port1} = lists:keyfind(Name1, 1, NodesPorts), + + %% Now start a second node, configuring it to use the same port + %% number. + PortOpt1 = "-kernel inet_dist_listen_min " ++ integer_to_list(Port1) ++ + " inet_dist_listen_max " ++ integer_to_list(Port1), + + try start_ssl_node([{additional_dist_opts, PortOpt1} | Config]) of + #node_handle{} -> + %% If the node was able to start, it didn't take the port + %% option into account. + exit(unexpected_success) + catch + exit:{accept_failed, timeout} -> + %% The node failed to start, as expected. + ok + end, + + %% Try again, now specifying a high max port. + PortOpt2 = "-kernel inet_dist_listen_min " ++ integer_to_list(Port1) ++ + " inet_dist_listen_max 65535", + NH2 = start_ssl_node([{additional_dist_opts, PortOpt2} | Config]), + Node2 = NH2#node_handle.nodename, + Name2 = lists:takewhile(fun(C) -> C =/= $@ end, atom_to_list(Node2)), + {ok, NodesPorts2} = apply_on_ssl_node(NH2, fun net_adm:names/0), + {Name2, Port2} = lists:keyfind(Name2, 1, NodesPorts2), + + %% The new port should be higher: + if Port2 > Port1 -> + ok; + true -> + error({port, Port2, not_higher_than, Port1}) + end, + + stop_ssl_node(NH1), + stop_ssl_node(NH2), + success(Config). +%%-------------------------------------------------------------------- +listen_options() -> + [{doc, "Test inet_dist_listen_options"}]. +listen_options(Config) when is_list(Config) -> + try_setting_priority(fun do_listen_options/2, Config). + +do_listen_options(Prio, Config) -> + PriorityString0 = "[{priority,"++integer_to_list(Prio)++"}]", + PriorityString = + case os:cmd("echo [{a,1}]") of + "[{a,1}]"++_ -> + PriorityString0; + _ -> + %% Some shells need quoting of [{}] + "'"++PriorityString0++"'" + end, + + Options = "-kernel inet_dist_listen_options " ++ PriorityString, + + NH1 = start_ssl_node([{additional_dist_opts, Options} | Config]), + NH2 = start_ssl_node([{additional_dist_opts, Options} | Config]), + Node2 = NH2#node_handle.nodename, + + pong = apply_on_ssl_node(NH1, fun () -> net_adm:ping(Node2) end), + + PrioritiesNode1 = + apply_on_ssl_node(NH1, fun get_socket_priorities/0), + PrioritiesNode2 = + apply_on_ssl_node(NH2, fun get_socket_priorities/0), + + Elevated1 = [P || P <- PrioritiesNode1, P =:= Prio], + ?t:format("Elevated1: ~p~n", [Elevated1]), + Elevated2 = [P || P <- PrioritiesNode2, P =:= Prio], + ?t:format("Elevated2: ~p~n", [Elevated2]), + [_|_] = Elevated1, + [_|_] = Elevated2, + + stop_ssl_node(NH1), + stop_ssl_node(NH2), + success(Config). +%%-------------------------------------------------------------------- +connect_options() -> + [{doc, "Test inet_dist_connect_options"}]. +connect_options(Config) when is_list(Config) -> + try_setting_priority(fun do_connect_options/2, Config). + +do_connect_options(Prio, Config) -> + PriorityString0 = "[{priority,"++integer_to_list(Prio)++"}]", + PriorityString = + case os:cmd("echo [{a,1}]") of + "[{a,1}]"++_ -> + PriorityString0; + _ -> + %% Some shells need quoting of [{}] + "'"++PriorityString0++"'" + end, + + Options = "-kernel inet_dist_connect_options " ++ PriorityString, + + NH1 = start_ssl_node([{additional_dist_opts, Options} | Config]), + NH2 = start_ssl_node([{additional_dist_opts, Options} | Config]), + Node2 = NH2#node_handle.nodename, + + pong = apply_on_ssl_node(NH1, fun () -> net_adm:ping(Node2) end), + + PrioritiesNode1 = + apply_on_ssl_node(NH1, fun get_socket_priorities/0), + PrioritiesNode2 = + apply_on_ssl_node(NH2, fun get_socket_priorities/0), + + Elevated1 = [P || P <- PrioritiesNode1, P =:= Prio], + ?t:format("Elevated1: ~p~n", [Elevated1]), + Elevated2 = [P || P <- PrioritiesNode2, P =:= Prio], + ?t:format("Elevated2: ~p~n", [Elevated2]), + %% Node 1 will have a socket with elevated priority. + [_|_] = Elevated1, + %% Node 2 will not, since it only applies to outbound connections. + [] = Elevated2, + + stop_ssl_node(NH1), + stop_ssl_node(NH2), + success(Config). +%%-------------------------------------------------------------------- +use_interface() -> + [{doc, "Test inet_dist_use_interface"}]. +use_interface(Config) when is_list(Config) -> + %% Force the node to listen only on the loopback interface. + IpString = "'{127,0,0,1}'", + Options = "-kernel inet_dist_use_interface " ++ IpString, + + %% Start a node, and get the port number it's listening on. + NH1 = start_ssl_node([{additional_dist_opts, Options} | Config]), + Node1 = NH1#node_handle.nodename, + Name = lists:takewhile(fun(C) -> C =/= $@ end, atom_to_list(Node1)), + {ok, NodesPorts} = apply_on_ssl_node(NH1, fun net_adm:names/0), + {Name, Port} = lists:keyfind(Name, 1, NodesPorts), + + %% Now find the socket listening on that port, and check its sockname. + Sockets = apply_on_ssl_node( + NH1, + fun() -> + [inet:sockname(P) || + P <- erlang:ports(), + {ok, Port} =:= (catch inet:port(P))] + end), + %% And check that it's actually listening on localhost. + [{ok,{{127,0,0,1},Port}}] = Sockets, + + stop_ssl_node(NH1), + success(Config). %%-------------------------------------------------------------------- %%% Internal functions ----------------------------------------------- @@ -264,6 +432,30 @@ tstsrvr_format(Fmt, ArgList) -> send_to_tstcntrl(Message) -> send_to_tstsrvr({message, Message}). +try_setting_priority(TestFun, Config) -> + Prio = 1, + case gen_udp:open(0, [{priority,Prio}]) of + {ok,Socket} -> + case inet:getopts(Socket, [priority]) of + {ok,[{priority,Prio}]} -> + ok = gen_udp:close(Socket), + TestFun(Prio, Config); + _ -> + ok = gen_udp:close(Socket), + {skip, + "Can not set priority "++integer_to_list(Prio)++ + " on socket"} + end; + {error,_} -> + {skip, "Can not set priority on socket"} + end. + +get_socket_priorities() -> + [Priority || + {ok,[{priority,Priority}]} <- + [inet:getopts(Port, [priority]) || + Port <- erlang:ports(), + element(2, erlang:port_info(Port, name)) =:= "tcp_inet"]]. %% %% test_server side api @@ -346,17 +538,13 @@ host_name() -> Host. mk_node_name(Config) -> - {A, B, C} = erlang:now(), + N = erlang:unique_integer([positive]), Case = ?config(testcase, Config), atom_to_list(?MODULE) ++ "_" ++ atom_to_list(Case) ++ "_" - ++ integer_to_list(A) - ++ "-" - ++ integer_to_list(B) - ++ "-" - ++ integer_to_list(C). + ++ integer_to_list(N). mk_node_cmdline(ListenPort, Name, Args) -> Static = "-detached -noinput", @@ -585,12 +773,10 @@ rand_bin(N) -> rand_bin(0, Acc) -> Acc; rand_bin(N, Acc) -> - rand_bin(N-1, [random:uniform(256)-1|Acc]). + rand_bin(N-1, [rand:uniform(256)-1|Acc]). make_randfile(Dir) -> {ok, IoDev} = file:open(filename:join([Dir, "RAND"]), [write]), - {A, B, C} = erlang:now(), - random:seed(A, B, C), ok = file:write(IoDev, rand_bin(1024)), file:close(IoDev). diff --git a/lib/ssl/test/ssl_handshake_SUITE.erl b/lib/ssl/test/ssl_handshake_SUITE.erl index b0bb77c598..d050812208 100644 --- a/lib/ssl/test/ssl_handshake_SUITE.erl +++ b/lib/ssl/test/ssl_handshake_SUITE.erl @@ -166,10 +166,10 @@ ignore_hassign_extension_pre_tls_1_2(Config) -> CertFile = proplists:get_value(certfile, Opts), [{_, Cert, _}] = ssl_test_lib:pem_to_der(CertFile), HashSigns = #hash_sign_algos{hash_sign_algos = [{sha512, rsa}, {sha, dsa}]}, - {sha512, rsa} = ssl_handshake:select_hashsign(HashSigns, Cert, {3,3}), + {sha512, rsa} = ssl_handshake:select_hashsign(HashSigns, Cert, ecdhe_rsa, tls_v1:default_signature_algs({3,3}), {3,3}), %%% Ignore - {md5sha, rsa} = ssl_handshake:select_hashsign(HashSigns, Cert, {3,2}), - {md5sha, rsa} = ssl_handshake:select_hashsign(HashSigns, Cert, {3,0}). + {md5sha, rsa} = ssl_handshake:select_hashsign(HashSigns, Cert, ecdhe_rsa, tls_v1:default_signature_algs({3,2}), {3,2}), + {md5sha, rsa} = ssl_handshake:select_hashsign(HashSigns, Cert, ecdhe_rsa, tls_v1:default_signature_algs({3,0}), {3,0}). is_supported(Hash) -> Algos = crypto:supports(), diff --git a/lib/ssl/test/ssl_payload_SUITE.erl b/lib/ssl/test/ssl_payload_SUITE.erl index b05f19d756..fb3890a811 100644 --- a/lib/ssl/test/ssl_payload_SUITE.erl +++ b/lib/ssl/test/ssl_payload_SUITE.erl @@ -105,7 +105,16 @@ init_per_testcase(TestCase, Config) when TestCase == server_echos_passive_huge; TestCase == client_echos_passive_huge; TestCase == client_echos_active_once_huge; TestCase == client_echos_active_huge -> - ct:timetrap({seconds, 30}), + ct:timetrap({seconds, 90}), + Config; + +init_per_testcase(TestCase, Config) when TestCase == server_echos_passive_big; + TestCase == server_echos_active_once_big; + TestCase == server_echos_active_big; + TestCase == client_echos_passive_big; + TestCase == client_echos_active_once_big; + TestCase == client_echos_active_big -> + ct:timetrap({seconds, 60}), Config; init_per_testcase(_TestCase, Config) -> diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl index 8ddc5db4b2..85345c814f 100644 --- a/lib/ssl/test/ssl_session_cache_SUITE.erl +++ b/lib/ssl/test/ssl_session_cache_SUITE.erl @@ -31,6 +31,7 @@ -define(SLEEP, 500). -define(TIMEOUT, 60000). -define(LONG_TIMEOUT, 600000). +-define(MAX_TABLE_SIZE, 5). -behaviour(ssl_session_cache_api). @@ -45,7 +46,10 @@ all() -> [session_cleanup, session_cache_process_list, - session_cache_process_mnesia]. + session_cache_process_mnesia, + client_unique_session, + max_table_size + ]. groups() -> []. @@ -90,8 +94,18 @@ init_per_testcase(session_cleanup, Config) -> ct:timetrap({seconds, 20}), Config; -init_per_testcase(_TestCase, Config) -> - ct:timetrap({seconds, 5}), +init_per_testcase(client_unique_session, Config) -> + ct:timetrap({seconds, 40}), + Config; + +init_per_testcase(max_table_size, Config) -> + ssl:stop(), + application:load(ssl), + application:set_env(ssl, session_cache_server_max, ?MAX_TABLE_SIZE), + application:set_env(ssl, session_cache_client_max, ?MAX_TABLE_SIZE), + application:set_env(ssl, session_delay_cleanup_time, ?DELAY), + ssl:start(), + ct:timetrap({seconds, 40}), Config. init_customized_session_cache(Type, Config) -> @@ -121,6 +135,10 @@ end_per_testcase(session_cleanup, Config) -> application:unset_env(ssl, session_delay_cleanup_time), application:unset_env(ssl, session_lifetime), end_per_testcase(default_action, Config); +end_per_testcase(max_table_size, Config) -> + application:unset_env(ssl, session_cach_server_max), + application:unset_env(ssl, session_cach_client_max), + end_per_testcase(default_action, Config); end_per_testcase(Case, Config) when Case == session_cache_process_list; Case == session_cache_process_mnesia -> ets:delete(ssl_test), @@ -131,10 +149,41 @@ end_per_testcase(_, Config) -> %%-------------------------------------------------------------------- %% Test Cases -------------------------------------------------------- %%-------------------------------------------------------------------- +client_unique_session() -> + [{doc, "Test session table does not grow when client " + "sets up many connections"}]. +client_unique_session(Config) when is_list(Config) -> + process_flag(trap_exit, true), + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, no_result, []}}, + {tcp_options, [{active, false}]}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + LastClient = clients_start(Server, + ClientNode, Hostname, Port, ClientOpts, client_unique_session, 20), + receive + {LastClient, {ok, _}} -> + ok + end, + {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)), + [_, _,_, _, Prop] = StatusInfo, + State = ssl_test_lib:state(Prop), + ClientCache = element(2, State), + + 1 = ssl_session_cache:size(ClientCache), + + ssl_test_lib:close(Server, 500), + ssl_test_lib:close(LastClient). + session_cleanup() -> [{doc, "Test that sessions are cleand up eventually, so that the session table " "does not grow and grow ..."}]. -session_cleanup(Config)when is_list(Config) -> +session_cleanup(Config) when is_list(Config) -> process_flag(trap_exit, true), ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), @@ -148,9 +197,9 @@ session_cleanup(Config)when is_list(Config) -> Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, - {port, Port}, {host, Hostname}, + {port, Port}, {host, Hostname}, {mfa, {ssl_test_lib, no_result, []}}, - {from, self()}, {options, ClientOpts}]), + {from, self()}, {options, ClientOpts}]), SessionInfo = receive {Server, Info} -> @@ -192,35 +241,7 @@ session_cleanup(Config)when is_list(Config) -> ssl_test_lib:close(Server), ssl_test_lib:close(Client). -check_timer(Timer) -> - case erlang:read_timer(Timer) of - false -> - {status, _, _, _} = sys:get_status(whereis(ssl_manager)), - timer:sleep(?SLEEP), - {status, _, _, _} = sys:get_status(whereis(ssl_manager)), - ok; - Int -> - ct:sleep(Int), - check_timer(Timer) - end. -get_delay_timers() -> - {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)), - [_, _,_, _, Prop] = StatusInfo, - State = ssl_test_lib:state(Prop), - case element(8, State) of - {undefined, undefined} -> - ct:sleep(?SLEEP), - get_delay_timers(); - {undefined, _} -> - ct:sleep(?SLEEP), - get_delay_timers(); - {_, undefined} -> - ct:sleep(?SLEEP), - get_delay_timers(); - DelayTimers -> - DelayTimers - end. %%-------------------------------------------------------------------- session_cache_process_list() -> [{doc,"Test reuse of sessions (short handshake)"}]. @@ -233,6 +254,42 @@ session_cache_process_mnesia(Config) when is_list(Config) -> session_cache_process(mnesia,Config). %%-------------------------------------------------------------------- + +max_table_size() -> + [{doc,"Test max limit on session table"}]. +max_table_size(Config) when is_list(Config) -> + process_flag(trap_exit, true), + ClientOpts = ?config(client_verification_opts, Config), + ServerOpts = ?config(server_verification_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, no_result, []}}, + {tcp_options, [{active, false}]}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + LastClient = clients_start(Server, + ClientNode, Hostname, Port, ClientOpts, max_table_size, 20), + receive + {LastClient, {ok, _}} -> + ok + end, + ct:sleep(1000), + {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)), + [_, _,_, _, Prop] = StatusInfo, + State = ssl_test_lib:state(Prop), + ClientCache = element(2, State), + ServerCache = element(3, State), + N = ssl_session_cache:size(ServerCache), + M = ssl_session_cache:size(ClientCache), + ct:pal("~p",[{N, M}]), + ssl_test_lib:close(Server, 500), + ssl_test_lib:close(LastClient), + true = N =< ?MAX_TABLE_SIZE, + true = M =< ?MAX_TABLE_SIZE. + +%%-------------------------------------------------------------------- %%% Session cache API callbacks %%-------------------------------------------------------------------- @@ -325,8 +382,8 @@ select_session(Cache, PartialKey) -> mnesia -> Sel = fun() -> mnesia:select(Cache, - [{{Cache,{PartialKey,'$1'}, '$2'}, - [],['$$']}]) + [{{Cache,{PartialKey,'_'}, '$1'}, + [],['$1']}]) end, {atomic, Res} = mnesia:transaction(Sel), Res @@ -354,8 +411,8 @@ session_loop(Sess) -> Pid ! {self(), Res}, session_loop(Sess); {Pid,select_session,PKey} -> - Sel = fun({{PKey0, Id},Session}, Acc) when PKey == PKey0 -> - [[Id, Session]|Acc]; + Sel = fun({{PKey0, _Id},Session}, Acc) when PKey == PKey0 -> + [Session | Acc]; (_,Acc) -> Acc end, @@ -370,3 +427,75 @@ session_loop(Sess) -> session_cache_process(_Type,Config) when is_list(Config) -> ssl_basic_SUITE:reuse_session(Config). + + +clients_start(_Server, ClientNode, Hostname, Port, ClientOpts, Test, 0) -> + %% Make sure session is registered + ct:sleep(?SLEEP * 2), + ssl_test_lib:start_client([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {mfa, {?MODULE, connection_info_result, []}}, + {from, self()}, {options, test_copts(Test, 0, ClientOpts)}]); +clients_start(Server, ClientNode, Hostname, Port, ClientOpts, Test, N) -> + spawn_link(ssl_test_lib, start_client, + [[{node, ClientNode}, + {port, Port}, {host, Hostname}, + {mfa, {ssl_test_lib, no_result, []}}, + {from, self()}, {options, test_copts(Test, N, ClientOpts)}]]), + Server ! listen, + wait_for_server(), + clients_start(Server, ClientNode, Hostname, Port, ClientOpts, Test, N-1). + +connection_info_result(Socket) -> + ssl:connection_information(Socket, [protocol, cipher_suite]). + +check_timer(Timer) -> + case erlang:read_timer(Timer) of + false -> + {status, _, _, _} = sys:get_status(whereis(ssl_manager)), + timer:sleep(?SLEEP), + {status, _, _, _} = sys:get_status(whereis(ssl_manager)), + ok; + Int -> + ct:sleep(Int), + check_timer(Timer) + end. + +get_delay_timers() -> + {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)), + [_, _,_, _, Prop] = StatusInfo, + State = ssl_test_lib:state(Prop), + case element(8, State) of + {undefined, undefined} -> + ct:sleep(?SLEEP), + get_delay_timers(); + {undefined, _} -> + ct:sleep(?SLEEP), + get_delay_timers(); + {_, undefined} -> + ct:sleep(?SLEEP), + get_delay_timers(); + DelayTimers -> + DelayTimers + end. + +wait_for_server() -> + ct:sleep(100). + + +test_copts(_, 0, ClientOpts) -> + ClientOpts; +test_copts(max_table_size, N, ClientOpts) -> + Version = tls_record:highest_protocol_version([]), + CipherSuites = %%lists:map(fun(X) -> ssl_cipher:suite_definition(X) end, ssl_cipher:filter_suites(ssl_cipher:suites(Version))), +[ Y|| Y = {Alg,_, _, _} <- lists:map(fun(X) -> ssl_cipher:suite_definition(X) end, ssl_cipher:filter_suites(ssl_cipher:suites(Version))), Alg =/= ecdhe_ecdsa, Alg =/= ecdh_ecdsa, Alg =/= ecdh_rsa, Alg =/= ecdhe_rsa, Alg =/= dhe_dss, Alg =/= dss], + case length(CipherSuites) of + M when M >= N -> + Cipher = lists:nth(N, CipherSuites), + ct:pal("~p",[Cipher]), + [{ciphers, [Cipher]} | ClientOpts]; + _ -> + ClientOpts + end; +test_copts(_, _, ClientOpts) -> + ClientOpts. diff --git a/lib/ssl/test/ssl_sni_SUITE.erl b/lib/ssl/test/ssl_sni_SUITE.erl index f6ffe91027..90c2a49e61 100644 --- a/lib/ssl/test/ssl_sni_SUITE.erl +++ b/lib/ssl/test/ssl_sni_SUITE.erl @@ -108,8 +108,12 @@ ssl_recv(SSLSocket, CurrentData, ExpectedData) -> send_and_hostname(SSLSocket) -> ssl:send(SSLSocket, "OK"), - {ok, [{sni_hostname, Hostname}]} = ssl:connection_information(SSLSocket, [sni_hostname]), - Hostname. + case ssl:connection_information(SSLSocket, [sni_hostname]) of + {ok, [{sni_hostname, Hostname}]} -> + Hostname; + {ok, []} -> + undefined + end. rdnPart([[#'AttributeTypeAndValue'{type=Type, value=Value} | _] | _], Type) -> Value; diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index da744f7368..ed4bd86665 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -226,6 +226,17 @@ run_client(Opts) -> ct:log("~p:~p~nClient faild several times: connection failed: ~p ~n", [?MODULE,?LINE, Reason]), Pid ! {self(), {error, Reason}} end; + {error, econnreset = Reason} -> + case get(retries) of + N when N < 5 -> + ct:log("~p:~p~neconnreset retries=~p sleep ~p",[?MODULE,?LINE, N,?SLEEP]), + put(retries, N+1), + ct:sleep(?SLEEP), + run_client(Opts); + _ -> + ct:log("~p:~p~nClient faild several times: connection failed: ~p ~n", [?MODULE,?LINE, Reason]), + Pid ! {self(), {error, Reason}} + end; {error, Reason} -> ct:log("~p:~p~nClient: connection failed: ~p ~n", [?MODULE,?LINE, Reason]), Pid ! {connect_failed, Reason}; @@ -241,7 +252,21 @@ close(Pid) -> receive {'DOWN', Monitor, process, Pid, Reason} -> erlang:demonitor(Monitor), - ct:log("~p:~p~nPid: ~p down due to:~p ~n", [?MODULE,?LINE, Pid, Reason]) + ct:log("~p:~p~nPid: ~p down due to:~p ~n", [?MODULE,?LINE, Pid, Reason]) + + end. + +close(Pid, Timeout) -> + ct:log("~p:~p~n Close ~p ~n", [?MODULE,?LINE, Pid]), + Monitor = erlang:monitor(process, Pid), + Pid ! close, + receive + {'DOWN', Monitor, process, Pid, Reason} -> + erlang:demonitor(Monitor), + ct:log("~p:~p~nPid: ~p down due to:~p ~n", [?MODULE,?LINE, Pid, Reason]) + after + Timeout -> + exit(Pid, kill) end. check_result(Server, ServerMsg, Client, ClientMsg) -> @@ -360,7 +385,7 @@ cert_options(Config) -> SNIServerAKeyFile = filename:join([?config(priv_dir, Config), "a.server", "key.pem"]), SNIServerBCertFile = filename:join([?config(priv_dir, Config), "b.server", "cert.pem"]), SNIServerBKeyFile = filename:join([?config(priv_dir, Config), "b.server", "key.pem"]), - [{client_opts, [{ssl_imp, new},{reuseaddr, true}]}, + [{client_opts, []}, {client_verification_opts, [{cacertfile, ClientCaCertFile}, {certfile, ClientCertFile}, {keyfile, ClientKeyFile}, @@ -793,7 +818,17 @@ rsa_suites(CounterPart) -> (_) -> false end, - ssl:cipher_suites()). + common_ciphers(CounterPart)). + +common_ciphers(crypto) -> + ssl:cipher_suites(); +common_ciphers(openssl) -> + OpenSslSuites = + string:tokens(string:strip(os:cmd("openssl ciphers"), right, $\n), ":"), + [ssl_cipher:erl_suite_definition(S) + || S <- ssl_cipher:suites(tls_record:highest_protocol_version([])), + lists:member(ssl_cipher:openssl_suite_name(S), OpenSslSuites) + ]. rsa_non_signed_suites() -> lists:filter(fun({rsa, _, _}) -> @@ -870,8 +905,8 @@ anonymous_suites() -> {dh_anon, '3des_ede_cbc', sha}, {dh_anon, aes_128_cbc, sha}, {dh_anon, aes_256_cbc, sha}, - {dh_anon, aes_128_gcm, null}, - {dh_anon, aes_256_gcm, null}, + {dh_anon, aes_128_gcm, null, sha256}, + {dh_anon, aes_256_gcm, null, sha384}, {ecdh_anon,rc4_128,sha}, {ecdh_anon,'3des_ede_cbc',sha}, {ecdh_anon,aes_128_cbc,sha}, @@ -898,12 +933,12 @@ psk_suites() -> {rsa_psk, aes_256_cbc, sha}, {rsa_psk, aes_128_cbc, sha256}, {rsa_psk, aes_256_cbc, sha384}, - {psk, aes_128_gcm, null}, - {psk, aes_256_gcm, null}, - {dhe_psk, aes_128_gcm, null}, - {dhe_psk, aes_256_gcm, null}, - {rsa_psk, aes_128_gcm, null}, - {rsa_psk, aes_256_gcm, null}], + {psk, aes_128_gcm, null, sha256}, + {psk, aes_256_gcm, null, sha384}, + {dhe_psk, aes_128_gcm, null, sha256}, + {dhe_psk, aes_256_gcm, null, sha384}, + {rsa_psk, aes_128_gcm, null, sha256}, + {rsa_psk, aes_256_gcm, null, sha384}], ssl_cipher:filter_suites(Suites). psk_anon_suites() -> @@ -1076,6 +1111,9 @@ is_sane_ecc(openssl) -> "OpenSSL 1.0.0" ++ _ -> % Known bug in openssl %% manifests as SSL_CHECK_SERVERHELLO_TLSEXT:tls invalid ecpointformat list false; + "OpenSSL 1.0.1l" ++ _ -> + %% Breaks signature verification + false; "OpenSSL 0.9.8" ++ _ -> % Does not support ECC false; "OpenSSL 0.9.7" ++ _ -> % Does not support ECC @@ -1130,23 +1168,27 @@ cipher_restriction(Config0) -> end. check_sane_openssl_version(Version) -> - case {Version, os:cmd("openssl version")} of - {_, "OpenSSL 1.0.2" ++ _} -> - true; - {_, "OpenSSL 1.0.1" ++ _} -> - true; - {'tlsv1.2', "OpenSSL 1.0" ++ _} -> - false; - {'tlsv1.1', "OpenSSL 1.0" ++ _} -> - false; - {'tlsv1.2', "OpenSSL 0" ++ _} -> - false; - {'tlsv1.1', "OpenSSL 0" ++ _} -> - false; - {_, _} -> - true + case supports_ssl_tls_version(Version) of + true -> + case {Version, os:cmd("openssl version")} of + {_, "OpenSSL 1.0.2" ++ _} -> + true; + {_, "OpenSSL 1.0.1" ++ _} -> + true; + {'tlsv1.2', "OpenSSL 1.0" ++ _} -> + false; + {'tlsv1.1', "OpenSSL 1.0" ++ _} -> + false; + {'tlsv1.2', "OpenSSL 0" ++ _} -> + false; + {'tlsv1.1', "OpenSSL 0" ++ _} -> + false; + {_, _} -> + true + end; + false -> + false end. - enough_openssl_crl_support("OpenSSL 0." ++ _) -> false; enough_openssl_crl_support(_) -> true. @@ -1164,13 +1206,15 @@ wait_for_openssl_server(Port, N) -> end. version_flag(tlsv1) -> - " -tls1 "; + "-tls1"; version_flag('tlsv1.1') -> - " -tls1_1 "; + "-tls1_1"; version_flag('tlsv1.2') -> - " -tls1_2 "; + "-tls1_2"; version_flag(sslv3) -> - " -ssl3 ". + "-ssl3"; +version_flag(sslv2) -> + "-ssl2". filter_suites(Ciphers0) -> Version = tls_record:highest_protocol_version([]), @@ -1180,7 +1224,7 @@ filter_suites(Ciphers0) -> ++ ssl_cipher:srp_suites() ++ ssl_cipher:rc4_suites(Version), Supported1 = ssl_cipher:filter_suites(Supported0), - Supported2 = [ssl:suite_definition(S) || S <- Supported1], + Supported2 = [ssl_cipher:erl_suite_definition(S) || S <- Supported1], [Cipher || Cipher <- Ciphers0, lists:member(Cipher, Supported2)]. -define(OPENSSL_QUIT, "Q\n"). @@ -1215,3 +1259,31 @@ close_loop(Port, Time, SentClose) -> ct:log("Timeout~n",[]) end end. + +portable_open_port(Exe, Args) -> + AbsPath = os:find_executable(Exe), + ct:pal("open_port({spawn_executable, ~p}, [{args, ~p}, stderr_to_stdout]).", [AbsPath, Args]), + open_port({spawn_executable, AbsPath}, + [{args, Args}, stderr_to_stdout]). + +supports_ssl_tls_version(Version) -> + VersionFlag = version_flag(Version), + Exe = "openssl", + Args = ["s_client", VersionFlag], + Port = ssl_test_lib:portable_open_port(Exe, Args), + do_supports_ssl_tls_version(Port). + +do_supports_ssl_tls_version(Port) -> + receive + {Port, {data, "unknown option" ++ _}} -> + false; + {Port, {data, Data}} -> + case lists:member("error", string:tokens(Data, ":")) of + true -> + false; + false -> + do_supports_ssl_tls_version(Port) + end + after 500 -> + true + end. diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl index 16b6cb10b9..6934d7f851 100644 --- a/lib/ssl/test/ssl_to_openssl_SUITE.erl +++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl @@ -112,6 +112,7 @@ init_per_suite(Config0) -> false -> {skip, "Openssl not found"}; _ -> + ct:pal("Version: ~p", [os:cmd("openssl version")]), catch crypto:stop(), try crypto:start() of ok -> @@ -174,7 +175,12 @@ special_init(TestCase, Config) check_sane_openssl_renegotaite(Config, Version); special_init(ssl2_erlang_server_openssl_client, Config) -> - check_sane_openssl_sslv2(Config); + case ssl_test_lib:supports_ssl_tls_version(sslv2) of + true -> + Config; + false -> + {skip, "sslv2 not supported by openssl"} + end; special_init(TestCase, Config) when TestCase == erlang_client_alpn_openssl_server_alpn; @@ -262,12 +268,11 @@ basic_erlang_client_openssl_server(Config) when is_list(Config) -> CertFile = proplists:get_value(certfile, ServerOpts), KeyFile = proplists:get_value(keyfile, ServerOpts), - Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ - " -cert " ++ CertFile ++ " -key " ++ KeyFile, - - ct:log("openssl cmd: ~p~n", [Cmd]), + Exe = "openssl", + Args = ["s_server", "-accept", integer_to_list(Port), + "-cert", CertFile, "-key", KeyFile], - OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), ssl_test_lib:wait_for_openssl_server(Port), @@ -302,13 +307,11 @@ basic_erlang_server_openssl_client(Config) when is_list(Config) -> {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), - - Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ - " -host localhost" ++ workaround_openssl_s_clinent(), - - ct:log("openssl cmd: ~p~n", [Cmd]), - OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + Exe = "openssl", + Args = ["s_client", "-connect", "localhost:" ++ integer_to_list(Port) | workaround_openssl_s_clinent()], + + OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), true = port_command(OpenSslPort, Data), ssl_test_lib:check_result(Server, ok), @@ -334,12 +337,12 @@ erlang_client_openssl_server(Config) when is_list(Config) -> CertFile = proplists:get_value(certfile, ServerOpts), KeyFile = proplists:get_value(keyfile, ServerOpts), Version = tls_record:protocol_version(tls_record:highest_protocol_version([])), - Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -cert " ++ CertFile ++ " -key " ++ KeyFile, - - ct:log("openssl cmd: ~p~n", [Cmd]), - - OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + Exe = "openssl", + Args = ["s_server", "-accept", integer_to_list(Port), + ssl_test_lib:version_flag(Version), + "-cert", CertFile, "-key", KeyFile], + + OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), ssl_test_lib:wait_for_openssl_server(Port), @@ -376,12 +379,12 @@ erlang_server_openssl_client(Config) when is_list(Config) -> Port = ssl_test_lib:inet_port(Server), Version = tls_record:protocol_version(tls_record:highest_protocol_version([])), - Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -host localhost", + Exe = "openssl", + Args = ["s_client", "-connect", "localhost: " ++ integer_to_list(Port), + ssl_test_lib:version_flag(Version)], - ct:log("openssl cmd: ~p~n", [Cmd]), + OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), - OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), true = port_command(OpenSslPort, Data), ssl_test_lib:check_result(Server, ok), @@ -407,14 +410,13 @@ erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) -> CertFile = proplists:get_value(certfile, ServerOpts), KeyFile = proplists:get_value(keyfile, ServerOpts), Version = tls_record:protocol_version(tls_record:highest_protocol_version([])), + Exe = "openssl", + Args = ["s_server", "-accept", integer_to_list(Port), + ssl_test_lib:version_flag(Version), + "-cert", CertFile, "-CAfile", CaCertFile, + "-key", KeyFile, "-Verify", "2", "-msg"], - Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile - ++ " -key " ++ KeyFile ++ " -Verify 2 -msg", - - ct:log("openssl cmd: ~p~n", [Cmd]), - - OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), ssl_test_lib:wait_for_openssl_server(Port), @@ -455,13 +457,14 @@ erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) -> {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Version = tls_record:protocol_version(tls_record:highest_protocol_version([])), - Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -host localhost " ++ " -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile - ++ " -key " ++ KeyFile ++ " -msg", - - ct:log("openssl cmd: ~p~n", [Cmd]), - - OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + Exe = "openssl", + Args = ["s_client", "-connect", "localhost: " ++ integer_to_list(Port), + ssl_test_lib:version_flag(Version), + "-cert", CertFile, + "-CAfile", CaCertFile, + "-key", KeyFile, "-msg"], + + OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), true = port_command(OpenSslPort, Data), ssl_test_lib:check_result(Server, ok), @@ -491,12 +494,13 @@ erlang_server_openssl_client_reuse_session(Config) when is_list(Config) -> {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Version = tls_record:protocol_version(tls_record:highest_protocol_version([])), - Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -host localhost -reconnect", - - ct:log("openssl cmd: ~p~n", [Cmd]), - OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + Exe = "openssl", + Args = ["s_client", "-connect", "localhost:" ++ integer_to_list(Port), + ssl_test_lib:version_flag(Version), + "-reconnect"], + + OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), true = port_command(OpenSslPort, Data), @@ -527,12 +531,12 @@ erlang_client_openssl_server_renegotiate(Config) when is_list(Config) -> KeyFile = proplists:get_value(keyfile, ServerOpts), Version = tls_record:protocol_version(tls_record:highest_protocol_version([])), - Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg", + Exe = "openssl", + Args = ["s_server", "-accept", integer_to_list(Port), + ssl_test_lib:version_flag(Version), + "-cert", CertFile, "-key", KeyFile, "-msg"], - ct:log("openssl cmd: ~p~n", [Cmd]), - - OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), ssl_test_lib:wait_for_openssl_server(Port), @@ -576,12 +580,12 @@ erlang_client_openssl_server_nowrap_seqnum(Config) when is_list(Config) -> CertFile = proplists:get_value(certfile, ServerOpts), KeyFile = proplists:get_value(keyfile, ServerOpts), Version = tls_record:protocol_version(tls_record:highest_protocol_version([])), - Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg", + Exe = "openssl", + Args = ["s_server", "-accept", integer_to_list(Port), + ssl_test_lib:version_flag(Version), + "-cert", CertFile, "-key", KeyFile, "-msg"], - ct:log("openssl cmd: ~p~n", [Cmd]), - - OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), ssl_test_lib:wait_for_openssl_server(Port), @@ -622,12 +626,12 @@ erlang_server_openssl_client_nowrap_seqnum(Config) when is_list(Config) -> {options, [{renegotiate_at, N}, {reuse_sessions, false} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), Version = tls_record:protocol_version(tls_record:highest_protocol_version([])), - Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -host localhost -msg", - - ct:log("openssl cmd: ~p~n", [Cmd]), + Exe = "openssl", + Args = ["s_client","-connect", "localhost: " ++ integer_to_list(Port), + ssl_test_lib:version_flag(Version), + "-msg"], - OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), true = port_command(OpenSslPort, Data), @@ -657,13 +661,13 @@ erlang_client_openssl_server_no_server_ca_cert(Config) when is_list(Config) -> CertFile = proplists:get_value(certfile, ServerOpts), KeyFile = proplists:get_value(keyfile, ServerOpts), Version = tls_record:protocol_version(tls_record:highest_protocol_version([])), - Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg", + Exe = "openssl", + Args = ["s_server", "-accept", integer_to_list(Port), + ssl_test_lib:version_flag(Version), + "-cert", CertFile, "-key", KeyFile, "-msg"], - ct:log("openssl cmd: ~p~n", [Cmd]), - - OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), - + OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), + ssl_test_lib:wait_for_openssl_server(Port), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, @@ -699,13 +703,13 @@ erlang_client_openssl_server_client_cert(Config) when is_list(Config) -> CaCertFile = proplists:get_value(cacertfile, ServerOpts), KeyFile = proplists:get_value(keyfile, ServerOpts), Version = tls_record:protocol_version(tls_record:highest_protocol_version([])), - Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile - ++ " -key " ++ KeyFile ++ " -Verify 2", + Exe = "openssl", + Args = ["s_server", "-accept", integer_to_list(Port), + ssl_test_lib:version_flag(Version), + "-cert", CertFile, "-CAfile", CaCertFile, + "-key", KeyFile, "-Verify", "2"], - ct:log("openssl cmd: ~p~n", [Cmd]), - - OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), ssl_test_lib:wait_for_openssl_server(Port), @@ -750,15 +754,14 @@ erlang_server_openssl_client_client_cert(Config) when is_list(Config) -> CertFile = proplists:get_value(certfile, ClientOpts), KeyFile = proplists:get_value(keyfile, ClientOpts), Version = tls_record:protocol_version(tls_record:highest_protocol_version([])), - Cmd = "openssl s_client -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile - ++ " -key " ++ KeyFile ++ " -port " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -host localhost", - - ct:log("openssl cmd: ~p~n", [Cmd]), - - OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), - true = port_command(OpenSslPort, Data), - + Exe = "openssl", + Args = ["s_client", "-cert", CertFile, + "-CAfile", CaCertFile, + "-key", KeyFile,"-connect", "localhost:" ++ integer_to_list(Port), + ssl_test_lib:version_flag(Version)], + OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), + + true = port_command(OpenSslPort, Data), ssl_test_lib:check_result(Server, ok), %% Clean close down! Server needs to be closed first !! @@ -839,12 +842,10 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) -> CertFile = proplists:get_value(certfile, ServerOpts), KeyFile = proplists:get_value(keyfile, ServerOpts), Version = tls_record:protocol_version(tls_record:highest_protocol_version([])), - Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "", - - ct:log("openssl cmd: ~p~n", [Cmd]), - - OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + Exe = "openssl", + Args = ["s_server", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version), + "-cert", CertFile, "-key", KeyFile], + OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), ssl_test_lib:wait_for_openssl_server(Port), @@ -895,12 +896,11 @@ expired_session(Config) when is_list(Config) -> CertFile = proplists:get_value(certfile, ServerOpts), KeyFile = proplists:get_value(keyfile, ServerOpts), - Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ - " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "", + Exe = "openssl", + Args = ["s_server", "-accept", integer_to_list(Port), + "-cert", CertFile,"-key", KeyFile], - ct:log("openssl cmd: ~p~n", [Cmd]), - - OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), ssl_test_lib:wait_for_openssl_server(Port), @@ -953,12 +953,11 @@ ssl2_erlang_server_openssl_client(Config) when is_list(Config) -> {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), - Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ - " -host localhost -ssl2 -msg", - - ct:log("openssl cmd: ~p~n", [Cmd]), + Exe = "openssl", + Args = ["s_client", "-connect", "localhost:" ++ integer_to_list(Port), + "-ssl2", "-msg"], - OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), true = port_command(OpenSslPort, Data), ct:log("Ports ~p~n", [[erlang:port_info(P) || P <- erlang:ports()]]), @@ -1007,7 +1006,7 @@ erlang_client_alpn_openssl_server(Config) when is_list(Config) -> Data = "From openssl to erlang", start_erlang_client_and_openssl_server_with_opts(Config, [{alpn_advertised_protocols, [<<"spdy/2">>]}], - "", + [], Data, fun(Server, OpensslPort) -> true = port_command(OpensslPort, Data), ssl_test_lib:check_result(Server, ok) @@ -1020,7 +1019,7 @@ erlang_client_openssl_server_alpn(Config) when is_list(Config) -> Data = "From openssl to erlang", start_erlang_client_and_openssl_server_with_opts(Config, [], - "-alpn spdy/2", + ["-alpn", "spdy/2"], Data, fun(Server, OpensslPort) -> true = port_command(OpensslPort, Data), ssl_test_lib:check_result(Server, ok) @@ -1033,7 +1032,7 @@ erlang_server_alpn_openssl_client(Config) when is_list(Config) -> Data = "From openssl to erlang", start_erlang_server_and_openssl_client_with_opts(Config, [{alpn_preferred_protocols, [<<"spdy/2">>]}], - "", + [], Data, fun(Server, OpensslPort) -> true = port_command(OpensslPort, Data), ssl_test_lib:check_result(Server, ok) @@ -1046,7 +1045,7 @@ erlang_server_openssl_client_alpn(Config) when is_list(Config) -> Data = "From openssl to erlang", start_erlang_server_and_openssl_client_with_opts(Config, [], - "-alpn spdy/2", + ["-alpn", "spdy/2"], Data, fun(Server, OpensslPort) -> true = port_command(OpensslPort, Data), ssl_test_lib:check_result(Server, ok) @@ -1157,7 +1156,7 @@ erlang_server_openssl_client_npn_renegotiate(Config) when is_list(Config) -> erlang_client_openssl_server_npn_only_server(Config) when is_list(Config) -> Data = "From openssl to erlang", start_erlang_client_and_openssl_server_with_opts(Config, [], - "-nextprotoneg spdy/2", Data, fun(Server, OpensslPort) -> + ["-nextprotoneg", "spdy/2"], Data, fun(Server, OpensslPort) -> true = port_command(OpensslPort, Data), ssl_test_lib:check_result(Server, ok) end), @@ -1169,7 +1168,7 @@ erlang_client_openssl_server_npn_only_client(Config) when is_list(Config) -> Data = "From openssl to erlang", start_erlang_client_and_openssl_server_with_opts(Config, [{client_preferred_next_protocols, - {client, [<<"spdy/2">>], <<"http/1.1">>}}], "", + {client, [<<"spdy/2">>], <<"http/1.1">>}}], [], Data, fun(Server, OpensslPort) -> true = port_command(OpensslPort, Data), ssl_test_lib:check_result(Server, ok) @@ -1179,7 +1178,7 @@ erlang_client_openssl_server_npn_only_client(Config) when is_list(Config) -> %%-------------------------------------------------------------------------- erlang_server_openssl_client_npn_only_server(Config) when is_list(Config) -> Data = "From openssl to erlang", - start_erlang_server_and_openssl_client_with_opts(Config, [{next_protocols_advertised, [<<"spdy/2">>]}], "", + start_erlang_server_and_openssl_client_with_opts(Config, [{next_protocols_advertised, [<<"spdy/2">>]}], [], Data, fun(Server, OpensslPort) -> true = port_command(OpensslPort, Data), ssl_test_lib:check_result(Server, ok) @@ -1188,7 +1187,7 @@ erlang_server_openssl_client_npn_only_server(Config) when is_list(Config) -> erlang_server_openssl_client_npn_only_client(Config) when is_list(Config) -> Data = "From openssl to erlang", - start_erlang_server_and_openssl_client_with_opts(Config, [], "-nextprotoneg spdy/2", + start_erlang_server_and_openssl_client_with_opts(Config, [], ["-nextprotoneg", "spdy/2"], Data, fun(Server, OpensslPort) -> true = port_command(OpensslPort, Data), ssl_test_lib:check_result(Server, ok) @@ -1261,7 +1260,7 @@ client_check_result(Port, DataExpected, DataReceived) -> client_check_result(Port, DataExpected, NewData) end after 3000 -> - ct:fail({"Time out on opensssl Client", {expected, DataExpected}, + ct:fail({"Time out on openSSL Client", {expected, DataExpected}, {got, DataReceived}}) end. client_check_result(Port, DataExpected) -> @@ -1269,8 +1268,12 @@ client_check_result(Port, DataExpected) -> send_and_hostname(SSLSocket) -> ssl:send(SSLSocket, "OK"), - {ok, [{sni_hostname, Hostname}]} = ssl:connection_information(SSLSocket, [sni_hostname]), - Hostname. + case ssl:connection_information(SSLSocket, [sni_hostname]) of + {ok, []} -> + undefined; + {ok, [{sni_hostname, Hostname}]} -> + Hostname + end. erlang_server_openssl_client_sni_test(Config, SNIHostname, ExpectedSNIHostname, ExpectedCN) -> ct:log("Start running handshake, Config: ~p, SNIHostname: ~p, ExpectedSNIHostname: ~p, ExpectedCN: ~p", [Config, SNIHostname, ExpectedSNIHostname, ExpectedCN]), @@ -1280,14 +1283,14 @@ erlang_server_openssl_client_sni_test(Config, SNIHostname, ExpectedSNIHostname, {from, self()}, {mfa, {?MODULE, send_and_hostname, []}}, {options, ServerOptions}]), Port = ssl_test_lib:inet_port(Server), - ClientCommand = case SNIHostname of + Exe = "openssl", + ClientArgs = case SNIHostname of undefined -> - "openssl s_client -connect " ++ Hostname ++ ":" ++ integer_to_list(Port); + ["s_client", "-connect", Hostname ++ ":" ++ integer_to_list(Port)]; _ -> - "openssl s_client -connect " ++ Hostname ++ ":" ++ integer_to_list(Port) ++ " -servername " ++ SNIHostname - end, - ct:log("Options: ~p", [[ServerOptions, ClientCommand]]), - ClientPort = open_port({spawn, ClientCommand}, [stderr_to_stdout]), + ["s_client", "-connect", Hostname ++ ":" ++ integer_to_list(Port), "-servername", SNIHostname] + end, + ClientPort = ssl_test_lib:portable_open_port(Exe, ClientArgs), %% Client check needs to be done befor server check, %% or server check might consume client messages @@ -1309,14 +1312,14 @@ erlang_server_openssl_client_sni_test_sni_fun(Config, SNIHostname, ExpectedSNIHo {from, self()}, {mfa, {?MODULE, send_and_hostname, []}}, {options, ServerOptions}]), Port = ssl_test_lib:inet_port(Server), - ClientCommand = case SNIHostname of + Exe = "openssl", + ClientArgs = case SNIHostname of undefined -> - "openssl s_client -connect " ++ Hostname ++ ":" ++ integer_to_list(Port); + ["s_client", "-connect", Hostname ++ ":" ++ integer_to_list(Port)]; _ -> - "openssl s_client -connect " ++ Hostname ++ ":" ++ integer_to_list(Port) ++ " -servername " ++ SNIHostname + ["s_client", "-connect", Hostname ++ ":" ++ integer_to_list(Port), "-servername", SNIHostname] end, - ct:log("Options: ~p", [[ServerOptions, ClientCommand]]), - ClientPort = open_port({spawn, ClientCommand}, [stderr_to_stdout]), + ClientPort = ssl_test_lib:portable_open_port(Exe, ClientArgs), %% Client check needs to be done befor server check, %% or server check might consume client messages @@ -1336,12 +1339,11 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) -> CertFile = proplists:get_value(certfile, ServerOpts), KeyFile = proplists:get_value(keyfile, ServerOpts), - Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "", + Exe = "openssl", + Args = ["s_server", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version), + "-cert", CertFile, "-key", KeyFile], - ct:log("openssl cmd: ~p~n", [Cmd]), - - OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), ssl_test_lib:wait_for_openssl_server(Port), @@ -1399,13 +1401,19 @@ start_erlang_client_and_openssl_server_with_opts(Config, ErlangClientOpts, Opens KeyFile = proplists:get_value(keyfile, ServerOpts), Version = tls_record:protocol_version(tls_record:highest_protocol_version([])), - Cmd = "openssl s_server " ++ OpensslServerOpts ++ " -accept " ++ - integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -cert " ++ CertFile ++ " -key " ++ KeyFile, - - ct:log("openssl cmd: ~p~n", [Cmd]), - - OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + Exe = "openssl", + Args = case OpensslServerOpts of + [] -> + ["s_server", "-accept", + integer_to_list(Port), ssl_test_lib:version_flag(Version), + "-cert", CertFile,"-key", KeyFile]; + [Opt, Value] -> + ["s_server", Opt, Value, "-accept", + integer_to_list(Port), ssl_test_lib:version_flag(Version), + "-cert", CertFile,"-key", KeyFile] + end, + + OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), ssl_test_lib:wait_for_openssl_server(Port), @@ -1439,13 +1447,10 @@ start_erlang_client_and_openssl_server_for_alpn_negotiation(Config, Data, Callba KeyFile = proplists:get_value(keyfile, ServerOpts), Version = tls_record:protocol_version(tls_record:highest_protocol_version([])), - Cmd = "openssl s_server -msg -alpn http/1.1,spdy/2 -accept " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -cert " ++ CertFile ++ " -key " ++ KeyFile, - - ct:log("openssl cmd: ~p~n", [Cmd]), - - OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), - + Exe = "openssl", + Args = ["s_server", "-msg", "-alpn", "http/1.1,spdy/2", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version), + "-cert", CertFile, "-key", KeyFile], + OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), ssl_test_lib:wait_for_openssl_server(Port), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, @@ -1477,12 +1482,13 @@ start_erlang_server_and_openssl_client_for_alpn_negotiation(Config, Data, Callba {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Version = tls_record:protocol_version(tls_record:highest_protocol_version([])), - Cmd = "openssl s_client -alpn http/1.0,spdy/2 -msg -port " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -host localhost", - ct:log("openssl cmd: ~p~n", [Cmd]), + Exe = "openssl", + Args = ["s_client", "-alpn", "http/1.0,spdy/2", "-msg", "-port", + integer_to_list(Port), ssl_test_lib:version_flag(Version), + "-host", "localhost"], - OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), Callback(Server, OpenSslPort), @@ -1507,12 +1513,12 @@ start_erlang_client_and_openssl_server_for_alpn_npn_negotiation(Config, Data, Ca KeyFile = proplists:get_value(keyfile, ServerOpts), Version = tls_record:protocol_version(tls_record:highest_protocol_version([])), - Cmd = "openssl s_server -msg -alpn http/1.1,spdy/2 -nextprotoneg spdy/3 -accept " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -cert " ++ CertFile ++ " -key " ++ KeyFile, + Exe = "openssl", + Args = ["s_server", "-msg", "-alpn", "http/1.1,spdy/2", "-nextprotoneg", + "spdy/3", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version), + "-cert", CertFile, "-key", KeyFile], - ct:log("openssl cmd: ~p~n", [Cmd]), - - OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), ssl_test_lib:wait_for_openssl_server(Port), @@ -1546,17 +1552,15 @@ start_erlang_server_and_openssl_client_for_alpn_npn_negotiation(Config, Data, Ca {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Version = tls_record:protocol_version(tls_record:highest_protocol_version([])), - Cmd = "openssl s_client -alpn http/1.1,spdy/2 -nextprotoneg spdy/3 -msg -port " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -host localhost", - - ct:log("openssl cmd: ~p~n", [Cmd]), - - OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + Exe = "openssl", + Args = ["s_client", "-alpn", "http/1.1,spdy/2", "-nextprotoneg", "spdy/3", + "-msg", "-port", integer_to_list(Port), ssl_test_lib:version_flag(Version), + "-host", "localhost"], + OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), Callback(Server, OpenSslPort), ssl_test_lib:close(Server), - ssl_test_lib:close_port(OpenSslPort), process_flag(trap_exit, false). @@ -1574,13 +1578,12 @@ start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, Callbac CertFile = proplists:get_value(certfile, ServerOpts), KeyFile = proplists:get_value(keyfile, ServerOpts), Version = tls_record:protocol_version(tls_record:highest_protocol_version([])), - - Cmd = "openssl s_server -msg -nextprotoneg http/1.1,spdy/2 -accept " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -cert " ++ CertFile ++ " -key " ++ KeyFile, - - ct:log("openssl cmd: ~p~n", [Cmd]), - - OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + + Exe = "openssl", + Args = ["s_server", "-msg", "-nextprotoneg", "http/1.1,spdy/2", "-accept", integer_to_list(Port), + ssl_test_lib:version_flag(Version), + "-cert", CertFile, "-key", KeyFile], + OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), ssl_test_lib:wait_for_openssl_server(Port), @@ -1613,12 +1616,12 @@ start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, Callbac {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Version = tls_record:protocol_version(tls_record:highest_protocol_version([])), - Cmd = "openssl s_client -nextprotoneg http/1.0,spdy/2 -msg -port " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -host localhost", - ct:log("openssl cmd: ~p~n", [Cmd]), + Exe = "openssl", + Args = ["s_client", "-nextprotoneg", "http/1.0,spdy/2", "-msg", "-connect", "localhost:" + ++ integer_to_list(Port), ssl_test_lib:version_flag(Version)], - OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), Callback(Server, OpenSslPort), @@ -1642,12 +1645,12 @@ start_erlang_server_and_openssl_client_with_opts(Config, ErlangServerOpts, OpenS {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Version = tls_record:protocol_version(tls_record:highest_protocol_version([])), - Cmd = "openssl s_client " ++ OpenSSLClientOpts ++ " -msg -port " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -host localhost", - - ct:log("openssl cmd: ~p~n", [Cmd]), + + Exe = "openssl", + Args = ["s_client"] ++ OpenSSLClientOpts ++ ["-msg", "-connect", "localhost:" ++ integer_to_list(Port), + ssl_test_lib:version_flag(Version)], - OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), Callback(Server, OpenSslPort), @@ -1679,8 +1682,6 @@ erlang_ssl_receive(Socket, Data) -> erlang_ssl_receive(Socket,Data); Other -> ct:fail({unexpected_message, Other}) - after 4000 -> - ct:fail({did_not_get, Data}) end. connection_info(Socket, Version) -> @@ -1753,7 +1754,9 @@ check_sane_openssl_renegotaite(Config, _) -> check_sane_openssl_renegotaite(Config). check_sane_openssl_renegotaite(Config) -> - case os:cmd("openssl version") of + case os:cmd("openssl version") of + "OpenSSL 1.0.0" ++ _ -> + {skip, "Known renegotiation bug in OpenSSL"}; "OpenSSL 0.9.8" ++ _ -> {skip, "Known renegotiation bug in OpenSSL"}; "OpenSSL 0.9.7" ++ _ -> @@ -1762,30 +1765,6 @@ check_sane_openssl_renegotaite(Config) -> Config end. -check_sane_openssl_sslv2(Config) -> - Port = open_port({spawn, "openssl s_client -ssl2 "}, [stderr_to_stdout]), - case supports_sslv2(Port) of - true -> - Config; - false -> - {skip, "sslv2 not supported by openssl"} - end. - -supports_sslv2(Port) -> - receive - {Port, {data, "unknown option -ssl2" ++ _}} -> - false; - {Port, {data, Data}} -> - case lists:member("error", string:tokens(Data, ":")) of - true -> - false; - false -> - supports_sslv2(Port) - end - after 500 -> - true - end. - workaround_openssl_s_clinent() -> %% http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=683159 %% https://bugs.archlinux.org/task/33919 @@ -1793,13 +1772,13 @@ workaround_openssl_s_clinent() -> %% explicitly specified case os:cmd("openssl version") of "OpenSSL 1.0.1c" ++ _ -> - " -no_tls1_2 "; + ["-no_tls1_2"]; "OpenSSL 1.0.1d" ++ _ -> - " -no_tls1_2 "; + ["-no_tls1_2"]; "OpenSSL 1.0.1e" ++ _ -> - " -no_tls1_2 "; + ["-no_tls1_2"]; "OpenSSL 1.0.1f" ++ _ -> - " -no_tls1_2 "; + ["-no_tls1_2"]; _ -> - "" + [] end. diff --git a/lib/ssl/test/ssl_upgrade_SUITE.erl b/lib/ssl/test/ssl_upgrade_SUITE.erl index 17b0240fe8..d65bdf6983 100644 --- a/lib/ssl/test/ssl_upgrade_SUITE.erl +++ b/lib/ssl/test/ssl_upgrade_SUITE.erl @@ -28,7 +28,8 @@ config, server, client, - soft + soft, + result_proxy }). all() -> @@ -77,45 +78,58 @@ upgrade_init(CTData, #state{config = Config} = State) -> {ok, {_, _, Up, _Down}} = ct_release_test:get_appup(CTData, ssl), ct:pal("Up: ~p", [Up]), Soft = is_soft(Up), %% It is symmetrical, if upgrade is soft so is downgrade + Pid = spawn(?MODULE, result_proxy_init, [[]]), case Soft of true -> - {Server, Client} = soft_start_connection(Config), + {Server, Client} = soft_start_connection(Config, Pid), State#state{server = Server, client = Client, - soft = Soft}; + soft = Soft, + result_proxy = Pid}; false -> - State#state{soft = Soft} + State#state{soft = Soft, result_proxy = Pid} end. -upgrade_upgraded(_, #state{soft = false, config = Config} = State) -> - {Server, Client} = restart_start_connection(Config), - ssl_test_lib:check_result(Server, ok, Client, ok), +upgrade_upgraded(_, #state{soft = false, config = Config, result_proxy = Pid} = State) -> + ct:pal("Restart upgrade ~n", []), + {Server, Client} = restart_start_connection(Config, Pid), + Result = check_result(Pid, Server, Client), ssl_test_lib:close(Server), ssl_test_lib:close(Client), + ok = Result, State; upgrade_upgraded(_, #state{server = Server0, client = Client0, - config = Config, soft = true} = State) -> + config = Config, soft = true, + result_proxy = Pid} = State) -> + ct:pal("Soft upgrade: ~n", []), Server0 ! changed_version, Client0 ! changed_version, - ssl_test_lib:check_result(Server0, ok, Client0, ok), + Result = check_result(Pid, Server0, Client0), ssl_test_lib:close(Server0), ssl_test_lib:close(Client0), - {Server, Client} = soft_start_connection(Config), + ok = Result, + {Server, Client} = soft_start_connection(Config, Pid), State#state{server = Server, client = Client}. -upgrade_downgraded(_, #state{soft = false, config = Config} = State) -> - {Server, Client} = restart_start_connection(Config), - ssl_test_lib:check_result(Server, ok, Client, ok), +upgrade_downgraded(_, #state{soft = false, config = Config, result_proxy = Pid} = State) -> + ct:pal("Restart downgrade: ~n", []), + {Server, Client} = restart_start_connection(Config, Pid), + Result = check_result(Pid, Server, Client), ssl_test_lib:close(Server), ssl_test_lib:close(Client), + Pid ! stop, + ok = Result, State; -upgrade_downgraded(_, #state{server = Server, client = Client, soft = true} = State) -> +upgrade_downgraded(_, #state{server = Server, client = Client, soft = true, result_proxy = Pid} = State) -> + ct:pal("Soft downgrade: ~n", []), Server ! changed_version, Client ! changed_version, - ssl_test_lib:check_result(Server, ok, Client, ok), + Result = check_result(Pid, Server, Client), + Pid ! stop, ssl_test_lib:close(Server), ssl_test_lib:close(Client), + ok = Result, State. use_connection(Socket) -> @@ -125,36 +139,35 @@ use_connection(Socket) -> ssl_test_lib:send_recv_result_active(Socket) end. -soft_start_connection(Config) -> +soft_start_connection(Config, ResulProxy) -> ClientOpts = ?config(client_verification_opts, Config), ServerOpts = ?config(server_verification_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, use_connection, []}}, - {options, ServerOpts}]), + Server = start_server([{node, ServerNode}, {port, 0}, + {from, ResulProxy}, + {mfa, {?MODULE, use_connection, []}}, + {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, use_connection, []}}, - {options, ClientOpts}]), + Port = inet_port(ResulProxy, Server), + Client = start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, ResulProxy}, + {mfa, {?MODULE, use_connection, []}}, + {options, ClientOpts}]), {Server, Client}. -restart_start_connection(Config) -> +restart_start_connection(Config, ResulProxy) -> ClientOpts = ?config(client_verification_opts, Config), ServerOpts = ?config(server_verification_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, + Server = start_server([{node, ServerNode}, {port, 0}, + {from, ResulProxy}, {mfa, {ssl_test_lib, send_recv_result_active, []}}, {options, ServerOpts}]), - - Port = ssl_test_lib:inet_port(Server), - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + Port = inet_port(ResulProxy, Server), + Client = start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, - {from, self()}, + {from, ResulProxy}, {mfa, {ssl_test_lib, send_recv_result_active, []}}, {options, ClientOpts}]), {Server, Client}. @@ -163,3 +176,103 @@ is_soft([{restart_application, ssl}]) -> false; is_soft(_) -> true. + +result_proxy_init(Args) -> + result_proxy_loop(Args). + +result_proxy_loop(Args) -> + receive + {Pid, {check_result, Server, Client}} -> + Result = do_check_result(Server, ok, Client, ok), + Pid ! {self(), Result}, + result_proxy_loop(Args); + {Pid, port, Server} -> + Port = recv_port(Server), + Pid ! Port, + result_proxy_loop(Args); + {Pid, listen} -> + recv_listen(), + Pid ! ok, + result_proxy_loop(Args); + {Pid, connected} -> + Connected = recv_connected(), + Pid ! Connected, + result_proxy_loop(Args) + end. + +check_result(Pid, Server, Client) -> + Pid ! {self(), {check_result, Server, Client}}, + receive + {Pid, Result} -> + Result + end. + +do_check_result(Server, ServerMsg, Client, ClientMsg) -> + receive + {Server, ServerMsg} -> + do_check_result(Client, ClientMsg); + + {Client, ClientMsg} -> + do_check_result(Server, ServerMsg); + Unexpected -> + {{expected, {Client, ClientMsg}}, + {expected, {Server, ServerMsg}}, {got, Unexpected}} + end. + +do_check_result(Pid, Msg) -> + receive + {Pid, Msg} -> + ok; + Unexpected -> + {{expected, {Pid, Msg}}, + {got, Unexpected}} + end. + +inet_port(Pid, Server) -> + Pid ! {self(), port, Server}, + receive + {port, Port} -> + Port + end. + +recv_port(Server) -> + receive + {Server, {port, Port}} -> + {port, Port} + end. + +recv_connected() -> + receive + {connected, _Socket} -> + ok; + {connect_failed, Reason} -> + {connect_failed, Reason} + end. + + +start_server(Args) -> + Pid = proplists:get_value(from, Args), + Result = spawn_link(ssl_test_lib, run_server, [Args]), + Pid ! {self(), listen}, + receive + ok -> + ok + end, + Result. + +start_client(Args) -> + Pid = proplists:get_value(from, Args), + Result = spawn_link(ssl_test_lib, run_client_init, [lists:delete(return_socket, Args)]), + Pid ! {self(), connected}, + receive + ok -> + Result; + Reason -> + exit(Reason) + end. + +recv_listen()-> + receive + {listen, up} -> + ok + end. diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk index 171147adf2..d9391ea543 100644 --- a/lib/ssl/vsn.mk +++ b/lib/ssl/vsn.mk @@ -1 +1 @@ -SSL_VSN = 7.0 +SSL_VSN = 7.3.3.1 diff --git a/lib/stdlib/doc/src/array.xml b/lib/stdlib/doc/src/array.xml index 28b4435938..0f33e2621c 100644 --- a/lib/stdlib/doc/src/array.xml +++ b/lib/stdlib/doc/src/array.xml @@ -164,7 +164,7 @@ the default value cannot be confused with the values of set entries.</p> </fsummary> <desc><marker id="from_list-1"/> -<p>Equivalent to <seealso marker="#from_list-2">from_list(<anno>List</anno>, undefined)</seealso>.</p> +<p>Equivalent to <seealso marker="#from_list-2">from_list(<c><anno>List</anno></c>, undefined)</seealso>.</p> </desc></func> <func> <name name="from_list" arity="2"/> @@ -184,7 +184,7 @@ the default value cannot be confused with the values of set entries.</p> </fsummary> <desc><marker id="from_orddict-1"/> -<p>Equivalent to <seealso marker="#from_orddict-2">from_orddict(<anno>Orddict</anno>, undefined)</seealso>.</p> +<p>Equivalent to <seealso marker="#from_orddict-2">from_orddict(<c><anno>Orddict</anno></c>, undefined)</seealso>.</p> </desc></func> <func> <name name="from_orddict" arity="2"/> diff --git a/lib/stdlib/doc/src/assert_hrl.xml b/lib/stdlib/doc/src/assert_hrl.xml index b85be514d8..ef4f928e57 100644 --- a/lib/stdlib/doc/src/assert_hrl.xml +++ b/lib/stdlib/doc/src/assert_hrl.xml @@ -77,9 +77,6 @@ erlc -DNOASSERT=true *.erl</code> </description> <section> - </section> - - <section> <title>Macros</title> <taglist> <tag><c>assert(BoolExpr)</c></tag> @@ -94,12 +91,12 @@ erlc -DNOASSERT=true *.erl</code> <tag><c>assertMatch(GuardedPattern, Expr)</c></tag> <item><p>Tests that <c>Expr</c> completes normally yielding a value - that matches <c>GuardedPattern</c>. For example: + that matches <c>GuardedPattern</c>. For example:</p> <code type="none"> - ?assertMatch({bork, _}, f())</code></p> - <p>Note that a guard <c>when ...</c> can be included: + ?assertMatch({bork, _}, f())</code> + <p>Note that a guard <c>when ...</c> can be included:</p> <code type="none"> - ?assertMatch({bork, X} when X > 0, f())</code></p> + ?assertMatch({bork, X} when X > 0, f())</code> </item> <tag><c>assertNotMatch(GuardedPattern, Expr)</c></tag> diff --git a/lib/stdlib/doc/src/beam_lib.xml b/lib/stdlib/doc/src/beam_lib.xml index c556180b8b..7c89c8b43e 100644 --- a/lib/stdlib/doc/src/beam_lib.xml +++ b/lib/stdlib/doc/src/beam_lib.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2000</year><year>2013</year> + <year>2000</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -71,6 +71,7 @@ using <seealso marker="#strip/1">strip/1</seealso>, <seealso marker="#strip_files/1">strip_files/1</seealso> and/or <seealso marker="#strip_release/1">strip_release/1</seealso>.</p> + </section> <section> <title>Reconstructing source code</title> <p>Here is an example of how to reconstruct source code from @@ -152,7 +153,6 @@ keys.</p> </note> </section> - </section> <datatypes> <datatype> @@ -224,6 +224,13 @@ <funcs> <func> + <name name="all_chunks" arity="1"/> + <fsummary>Read all chunks from a BEAM file or binary</fsummary> + <desc> + <p>Reads chunk data for all chunks.</p> + </desc> + </func> + <func> <name name="chunks" arity="2"/> <fsummary>Read selected chunks from a BEAM file or binary</fsummary> <desc> @@ -251,6 +258,13 @@ </desc> </func> <func> + <name name="build_module" arity="1"/> + <fsummary>Creates a BEAM module from a list of chunks</fsummary> + <desc> + <p>Builds a BEAM module (as a binary) from a list of chunks.</p> + </desc> + </func> + <func> <name name="version" arity="1"/> <fsummary>Read the BEAM file's module version</fsummary> <desc> diff --git a/lib/stdlib/doc/src/binary.xml b/lib/stdlib/doc/src/binary.xml index 063f3048e0..2682198fe5 100644 --- a/lib/stdlib/doc/src/binary.xml +++ b/lib/stdlib/doc/src/binary.xml @@ -299,8 +299,8 @@ </func> <func> <name name="match" arity="3"/> - <type name="part"/> <fsummary>Searches for the first match of a pattern in a binary</fsummary> + <type name="part"/> <desc> <p>Searches for the first occurrence of <c><anno>Pattern</anno></c> in <c><anno>Subject</anno></c> and @@ -353,8 +353,8 @@ </func> <func> <name name="matches" arity="3"/> - <type name="part"/> <fsummary>Searches for all matches of a pattern in a binary</fsummary> + <type name="part"/> <desc> <p>Works like <c>match/2</c>, but the <c><anno>Subject</anno></c> is searched until diff --git a/lib/stdlib/doc/src/c.xml b/lib/stdlib/doc/src/c.xml index a0f18bd899..e5238fa7db 100644 --- a/lib/stdlib/doc/src/c.xml +++ b/lib/stdlib/doc/src/c.xml @@ -121,12 +121,12 @@ compile:file(<anno>File</anno>, <anno>Options</anno> ++ [report_errors, report_w </func> <func> <name>lc(Files) -> ok</name> + <fsummary>Compile a list of files</fsummary> <type> <v>Files = [File]</v> <v>File = <seealso marker="file#type-filename">file:filename() </seealso></v> </type> - <fsummary>Compile a list of files</fsummary> <desc> <p>Compiles a list of files by calling <c>compile:file(File, [report_errors, report_warnings])</c> for each <c>File</c> in <c>Files</c>.</p> diff --git a/lib/stdlib/doc/src/calendar.xml b/lib/stdlib/doc/src/calendar.xml index a8d933dc83..853184dc0f 100644 --- a/lib/stdlib/doc/src/calendar.xml +++ b/lib/stdlib/doc/src/calendar.xml @@ -130,11 +130,11 @@ <func> <name name="date_to_gregorian_days" arity="1"/> <name name="date_to_gregorian_days" arity="3"/> + <fsummary>Compute the number of days from year 0 up to the given date</fsummary> <type variable="Date" name_i="1"/> <type variable="Year"/> <type variable="Month"/> <type variable="Day"/> - <fsummary>Compute the number of days from year 0 up to the given date</fsummary> <desc> <p>This function computes the number of gregorian days starting with year 0 and ending at the given date.</p> @@ -347,11 +347,11 @@ <func> <name name="valid_date" arity="1"/> <name name="valid_date" arity="3"/> + <fsummary>Check if a date is valid</fsummary> <type variable="Date" name_i="1"/> <type variable="Year"/> <type variable="Month"/> <type variable="Day"/> - <fsummary>Check if a date is valid</fsummary> <desc> <p>This function checks if a date is a valid.</p> </desc> diff --git a/lib/stdlib/doc/src/dets.xml b/lib/stdlib/doc/src/dets.xml index 14237b6f90..48400733d1 100644 --- a/lib/stdlib/doc/src/dets.xml +++ b/lib/stdlib/doc/src/dets.xml @@ -316,20 +316,20 @@ bytes.</p> </item> <item> - <p><c>{filename, <seealso marker="file#type-name">file:name()</seealso>}</c>, + <p><c>{filename, </c><seealso marker="file#type-name">file:name()</seealso><c>}</c>, the name of the file where objects are stored.</p> </item> <item> - <p><c>{keypos, <seealso marker="#type-keypos">keypos()</seealso>} - </c>, the position of the key.</p> + <p><c>{keypos, </c><seealso marker="#type-keypos">keypos()</seealso> + <c>}</c>, the position of the key.</p> </item> <item> <p><c>{size, integer() >= 0}</c>, the number of objects stored in the table.</p> </item> <item> - <p><c>{type, <seealso marker="#type-type">type()</seealso>}</c>, - the type of the table.</p> + <p><c>{type, </c><seealso marker="#type-type">type()</seealso> + <c>}</c>, the type of the table.</p> </item> </list> </desc> @@ -345,12 +345,12 @@ allowed:</p> <list type="bulleted"> <item> - <p><c>{access, <seealso marker="#type-access">access()</seealso>} - </c>, the access mode.</p> + <p><c>{access, </c><seealso marker="#type-access">access()</seealso> + <c>}</c>, the access mode.</p> </item> <item> - <p><c>{auto_save, <seealso marker="#type-auto_save"> - auto_save()</seealso>}</c>, the auto save interval.</p> + <p><c>{auto_save, </c><seealso marker="#type-auto_save"> + auto_save()</seealso><c>}</c>, the auto save interval.</p> </item> <item> <p><c>{bchunk_format, binary()}</c>, an opaque binary @@ -399,15 +399,40 @@ kept in RAM.</p> </item> <item> - <p><c>{safe_fixed,</c> SafeFixed<c>}</c>. If the table - is fixed, SafeFixed is a tuple <c>{FixedAtTime, [{Pid,RefCount}]}</c>. <c>FixedAtTime</c> is the time when + <p><c>{safe_fixed_monotonic_time, SafeFixed}</c>. If the table + is fixed, <c>SafeFixed</c> is a tuple <c>{FixedAtTime, [{Pid,RefCount}]}</c>. + <c>FixedAtTime</c> is the time when the table was first fixed, and <c>Pid</c> is the pid of the process that fixes the table <c>RefCount</c> times. There may be any number of processes in the list. If the table is not fixed, SafeFixed is the atom <c>false</c>.</p> + <p><c>FixedAtTime</c> will correspond to the result + returned by + <seealso marker="erts:erlang#monotonic_time/0">erlang:monotonic_time/0</seealso> + at the time of fixation. The usage of <c>safe_fixed_monotonic_time</c> is + <seealso marker="erts:time_correction#Time_Warp_Safe_Code">time warp + safe</seealso>.</p> </item> <item> - <p><c>{version, integer()</c>, the version of the format of + <p> + <c>{safe_fixed, SafeFixed}</c>. The same as + <c>{safe_fixed_monotonic_time, SafeFixed}</c> with the exception + of the format and value of <c>FixedAtTime</c>. + </p> + <p> + <c>FixedAtTime</c> will correspond to the result returned by + <seealso marker="erts:erlang#timestamp/0">erlang:timestamp/0</seealso> + at the time of fixation. Note that when the system is using + single or multi + <seealso marker="erts:time_correction#Time_Warp_Modes">time warp + modes</seealso> this might produce strange results. This + since the usage of <c>safe_fixed</c> is not + <seealso marker="erts:time_correction#Time_Warp_Safe_Code">time warp + safe</seealso>. Time warp safe code need to use + <c>safe_fixed_monotonic_time</c> instead.</p> + </item> + <item> + <p><c>{version, integer()}</c>, the version of the format of the table.</p> </item> </list> @@ -730,16 +755,16 @@ ok tuples where the following values are allowed:</p> <list type="bulleted"> <item> - <p><c>{access, <seealso marker="#type-access"> - access()</seealso>}</c>. It is possible to open + <p><c>{access, </c><seealso marker="#type-access"> + access()</seealso><c>}</c>. It is possible to open existing tables in read-only mode. A table which is opened in read-only mode is not subjected to the automatic file reparation algorithm if it is later opened after a crash. The default value is <c>read_write</c>.</p> </item> <item> - <p><c>{auto_save, <seealso marker="#type-auto_save"> - auto_save()</seealso>}</c>, the auto save + <p><c>{auto_save, </c><seealso marker="#type-auto_save"> + auto_save()</seealso><c>}</c>, the auto save interval. If the interval is an integer <c>Time</c>, the table is flushed to disk whenever it is not accessed for <c>Time</c> milliseconds. A table that has been flushed @@ -749,18 +774,18 @@ ok is 180000 (3 minutes).</p> </item> <item> - <p><c>{estimated_no_objects, <seealso marker="#type-no_slots"> - no_slots()</seealso>}</c>. Equivalent to the + <p><c>{estimated_no_objects, </c><seealso marker="#type-no_slots"> + no_slots()</seealso><c>}</c>. Equivalent to the <c>min_no_slots</c> option.</p> </item> <item> - <p><c>{file, <seealso marker="file#type-name"> - file:name()</seealso>}</c>, the name of the file to be + <p><c>{file, </c><seealso marker="file#type-name"> + file:name()</seealso><c>}</c>, the name of the file to be opened. The default value is the name of the table.</p> </item> <item> - <p><c>{max_no_slots, <seealso marker="#type-no_slots"> - no_slots()</seealso>}</c>, the maximum number + <p><c>{max_no_slots, </c><seealso marker="#type-no_slots"> + no_slots()</seealso><c>}</c>, the maximum number 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, @@ -769,16 +794,16 @@ ok 9 tables.</p> </item> <item> - <p><c>{min_no_slots, <seealso marker="#type-no_slots"> - no_slots()</seealso>}</c>. Application + <p><c>{min_no_slots, </c><seealso marker="#type-no_slots"> + no_slots()</seealso><c>}</c>. Application performance can be enhanced with this flag by specifying, when the table is created, the estimated number of different keys that will be stored in the table. The default value as well as the minimum value is 256.</p> </item> <item> - <p><c>{keypos, <seealso marker="#type-keypos"> - keypos()</seealso>}</c>, the position of the + <p><c>{keypos, </c><seealso marker="#type-keypos"> + keypos()</seealso><c>}</c>, the position of the element of each object to be used as key. The default value is 1. The ability to explicitly state the key position is most convenient when we want to store Erlang @@ -815,12 +840,12 @@ ok already open.</p> </item> <item> - <p><c>{type, <seealso marker="#type-type">type()</seealso>}</c>, + <p><c>{type, </c><seealso marker="#type-type">type()</seealso><c>}</c>, the type of the table. The default value is <c>set</c>.</p> </item> <item> - <p><c>{version, <seealso marker="#type-version"> - version()</seealso>}</c>, the version of the format + <p><c>{version, </c><seealso marker="#type-version"> + version()</seealso><c>}</c>, the version of the format used for the table. The default value is <c>9</c>. Tables on the format used before OTP R8 can be created by giving the value <c>8</c>. A version 8 table can be converted to @@ -1036,8 +1061,8 @@ ok specification that matches all objects.</p> </item> <item> - <p><c>{select, <seealso marker="#type-match_spec"> - match_spec()}</seealso></c>. As for <c>select</c> + <p><c>{select, </c><seealso marker="#type-match_spec"> + match_spec()</seealso><c>}</c>. As for <c>select</c> the table is traversed by calling <c>dets:select/3</c> and <c>dets:select/1</c>. The difference is that the match specification is explicitly given. This is how to diff --git a/lib/stdlib/doc/src/digraph.xml b/lib/stdlib/doc/src/digraph.xml index 49dc68e103..291be6c08b 100644 --- a/lib/stdlib/doc/src/digraph.xml +++ b/lib/stdlib/doc/src/digraph.xml @@ -103,13 +103,15 @@ <desc><p>A digraph as returned by <c>new/0,1</c>.</p></desc> </datatype> <datatype> - <name><marker id="type-edge">edge()</marker></name> + <name>edge()</name> + <desc><p><marker id="type-edge"/></p></desc> </datatype> <datatype> <name name="label"/> </datatype> <datatype> - <name><marker id="type-vertex">vertex()</marker></name> + <name>vertex()</name> + <desc><p><marker id="type-vertex"/></p></desc> </datatype> </datatypes> <funcs> diff --git a/lib/stdlib/doc/src/digraph_utils.xml b/lib/stdlib/doc/src/digraph_utils.xml index 6a4db2e963..639069543c 100644 --- a/lib/stdlib/doc/src/digraph_utils.xml +++ b/lib/stdlib/doc/src/digraph_utils.xml @@ -122,8 +122,9 @@ <datatypes> <datatype> - <name><marker id="type-digraph">digraph()</marker></name> - <desc><p>A digraph as returned by <c>digraph:new/0,1</c>.</p></desc> + <name>digraph()</name> + <desc><p><marker id="type-digraph"/> + A digraph as returned by <c>digraph:new/0,1</c>.</p></desc> </datatype> </datatypes> <funcs> diff --git a/lib/stdlib/doc/src/epp.xml b/lib/stdlib/doc/src/epp.xml index fe2944bbf7..8c901f57ec 100644 --- a/lib/stdlib/doc/src/epp.xml +++ b/lib/stdlib/doc/src/epp.xml @@ -39,7 +39,7 @@ by <c>compile</c> to preprocess macros and include files before the actual parsing takes place.</p> <p>The Erlang source file <marker - id="encoding"><em>encoding</em></marker> is selected by a + id="encoding"/><em>encoding</em> is selected by a comment in one of the first two lines of the source file. The first string that matches the regular expression <c>coding\s*[:=]\s*([-a-zA-Z0-9])+</c> selects the encoding. If diff --git a/lib/stdlib/doc/src/erl_anno.xml b/lib/stdlib/doc/src/erl_anno.xml index be0ffe6f4d..ddc8b8c765 100644 --- a/lib/stdlib/doc/src/erl_anno.xml +++ b/lib/stdlib/doc/src/erl_anno.xml @@ -44,7 +44,7 @@ <p>This module implements an abstract type that is used by the Erlang Compiler and its helper modules for holding data such as column, line number, and text. The data type is a collection of - <marker id="annotations"><em>annotations</em></marker> as + <marker id="annotations"/><em>annotations</em> as described in the following.</p> <p>The Erlang Token Scanner returns tokens with a subset of the following annotations, depending on the options:</p> @@ -102,8 +102,8 @@ <datatypes> <datatype> - <name><marker id="type-anno">anno()</marker></name> - <desc><p>A collection of annotations.</p> + <name>anno()</name> + <desc><p><marker id="type-anno"/>A collection of annotations.</p> </desc> </datatype> <datatype> @@ -133,8 +133,8 @@ <funcs> <func> <name name="column" arity="1"/> - <type name="column"></type> <fsummary>Return the column</fsummary> + <type name="column"></type> <desc> <p>Returns the column of the annotations <anno>Anno</anno>. </p> @@ -142,8 +142,8 @@ </func> <func> <name name="end_location" arity="1"/> - <type name="location"></type> <fsummary>Return the end location of the text</fsummary> + <type name="location"></type> <desc> <p>Returns the end location of the text of the annotations <anno>Anno</anno>. If there is no text, @@ -153,8 +153,8 @@ </func> <func> <name name="file" arity="1"/> - <type name="filename"></type> <fsummary>Return the filename</fsummary> + <type name="filename"></type> <desc> <p>Returns the filename of the annotations <anno>Anno</anno>. If there is no filename, <c>undefined</c> is returned. @@ -180,8 +180,8 @@ </func> <func> <name name="generated" arity="1"/> - <type name="generated"></type> <fsummary>Return the generated Boolean</fsummary> + <type name="generated"></type> <desc> <p>Returns <c>true</c> if the annotations <anno>Anno</anno> has been marked as generated. The default is to return @@ -199,8 +199,8 @@ </func> <func> <name name="line" arity="1"/> - <type name="line"></type> <fsummary>Return the line</fsummary> + <type name="line"></type> <desc> <p>Returns the line of the annotations <anno>Anno</anno>. </p> @@ -208,8 +208,8 @@ </func> <func> <name name="location" arity="1"/> - <type name="location"></type> <fsummary>Return the location</fsummary> + <type name="location"></type> <desc> <p>Returns the location of the annotations <anno>Anno</anno>. </p> @@ -217,16 +217,16 @@ </func> <func> <name name="new" arity="1"/> - <type name="location"></type> <fsummary>Create a new collection of annotations</fsummary> + <type name="location"></type> <desc> <p>Creates a new collection of annotations given a location.</p> </desc> </func> <func> <name name="set_file" arity="2"/> - <type name="filename"></type> <fsummary>Modify the filename</fsummary> + <type name="filename"></type> <desc> <p>Modifies the filename of the annotations <anno>Anno</anno>. </p> @@ -234,8 +234,8 @@ </func> <func> <name name="set_generated" arity="2"/> - <type name="generated"></type> <fsummary>Modify the generated marker</fsummary> + <type name="generated"></type> <desc> <p>Modifies the generated marker of the annotations <anno>Anno</anno>. @@ -244,8 +244,8 @@ </func> <func> <name name="set_line" arity="2"/> - <type name="line"></type> <fsummary>Modify the line</fsummary> + <type name="line"></type> <desc> <p>Modifies the line of the annotations <anno>Anno</anno>. </p> @@ -253,8 +253,8 @@ </func> <func> <name name="set_location" arity="2"/> - <type name="location"></type> <fsummary>Modify the location</fsummary> + <type name="location"></type> <desc> <p>Modifies the location of the annotations <anno>Anno</anno>. </p> @@ -262,8 +262,8 @@ </func> <func> <name name="set_record" arity="2"/> - <type name="record"></type> <fsummary>Modify the record marker</fsummary> + <type name="record"></type> <desc> <p>Modifies the record marker of the annotations <anno>Anno</anno>. </p> @@ -271,8 +271,8 @@ </func> <func> <name name="set_text" arity="2"/> - <type name="text"></type> <fsummary>Modify the text</fsummary> + <type name="text"></type> <desc> <p>Modifies the text of the annotations <anno>Anno</anno>. </p> @@ -280,8 +280,8 @@ </func> <func> <name name="text" arity="1"/> - <type name="text"></type> <fsummary>Return the text</fsummary> + <type name="text"></type> <desc> <p>Returns the text of the annotations <anno>Anno</anno>. If there is no text, <c>undefined</c> is returned. diff --git a/lib/stdlib/doc/src/erl_parse.xml b/lib/stdlib/doc/src/erl_parse.xml index fdd776b7f1..0938b5dec3 100644 --- a/lib/stdlib/doc/src/erl_parse.xml +++ b/lib/stdlib/doc/src/erl_parse.xml @@ -174,8 +174,8 @@ </func> <func> <name name="abstract" arity="2"/> - <type name="encoding_func"/> <fsummary>Convert an Erlang term into an abstract form</fsummary> + <type name="encoding_func"/> <desc> <p>Converts the Erlang data structure <c><anno>Data</anno></c> into an abstract form of type <c><anno>AbsTerm</anno></c>.</p> diff --git a/lib/stdlib/doc/src/erl_pp.xml b/lib/stdlib/doc/src/erl_pp.xml index c9d9e2723d..4b8a571c81 100644 --- a/lib/stdlib/doc/src/erl_pp.xml +++ b/lib/stdlib/doc/src/erl_pp.xml @@ -48,8 +48,8 @@ <datatype> <name name="hook_function"/> <desc> - <p>The optional argument <marker id="hook_function"> - <c>HookFunction</c></marker>, shown in the functions described below, + <p>The optional argument <marker id="hook_function"/> + <c>HookFunction</c>, shown in the functions described below, defines a function which is called when an unknown form occurs where there should be a valid expression.</p> diff --git a/lib/stdlib/doc/src/erl_scan.xml b/lib/stdlib/doc/src/erl_scan.xml index 18e988e286..342f491dd0 100644 --- a/lib/stdlib/doc/src/erl_scan.xml +++ b/lib/stdlib/doc/src/erl_scan.xml @@ -181,10 +181,10 @@ <func> <name name="tokens" arity="3"/> <name name="tokens" arity="4"/> + <fsummary>Re-entrant scanner</fsummary> <type name="char_spec"/> <type name="return_cont"/> <type_desc name="return_cont">An opaque continuation</type_desc> - <fsummary>Re-entrant scanner</fsummary> <desc> <p>This is the re-entrant scanner which scans characters until a <em>dot</em> ('.' followed by a white space) or @@ -324,9 +324,9 @@ <func> <name name="token_info" arity="2" clause_i="1"/> <name name="token_info" arity="2" clause_i="2"/> + <fsummary>Return information about a token</fsummary> <type name="token_item"/> <type name="attribute_item"/> - <fsummary>Return information about a token</fsummary> <desc> <p>Returns a list containing information about the token <c><anno>Token</anno></c>. If one single @@ -345,28 +345,28 @@ <p>The following <c><anno>TokenInfoTuple</anno></c>s with corresponding <c><anno>TokenItem</anno></c>s are valid:</p> <taglist> - <tag><c>{category, <seealso marker="#type-category"> - category()</seealso>}</c></tag> + <tag><c>{category, </c><seealso marker="#type-category"> + category()</seealso><c>}</c></tag> <item><p>The category of the token.</p> </item> - <tag><c>{column, <seealso marker="#type-column"> - column()</seealso>}</c></tag> + <tag><c>{column, </c><seealso marker="#type-column"> + column()</seealso><c>}</c></tag> <item><p>The column where the token begins.</p> </item> <tag><c>{length, integer() > 0}</c></tag> <item><p>The length of the token's text.</p> </item> - <tag><c>{line, <seealso marker="#type-line"> - line()</seealso>}</c></tag> + <tag><c>{line, </c><seealso marker="#type-line"> + line()</seealso><c>}</c></tag> <item><p>The line where the token begins.</p> </item> - <tag><c>{location, <seealso marker="#type-location"> - location()</seealso>}</c></tag> + <tag><c>{location, </c><seealso marker="#type-location"> + location()</seealso><c>}</c></tag> <item><p>The line and column where the token begins, or just the line if the column unknown.</p> </item> - <tag><c>{symbol, <seealso marker="#type-symbol"> - symbol()</seealso>}</c></tag> + <tag><c>{symbol, </c><seealso marker="#type-symbol"> + symbol()</seealso><c>}</c></tag> <item><p>The token's symbol.</p> </item> <tag><c>{text, string()}</c></tag> @@ -416,19 +416,19 @@ <p>The following <c><anno>AttributeInfoTuple</anno></c>s with corresponding <c><anno>AttributeItem</anno></c>s are valid:</p> <taglist> - <tag><c>{column, <seealso marker="#type-column"> - column()</seealso>}</c></tag> + <tag><c>{column, </c><seealso marker="#type-column"> + column()</seealso><c>}</c></tag> <item><p>The column where the token begins.</p> </item> <tag><c>{length, integer() > 0}</c></tag> <item><p>The length of the token's text.</p> </item> - <tag><c>{line, <seealso marker="#type-line"> - line()</seealso>}</c></tag> + <tag><c>{line, </c><seealso marker="#type-line"> + line()</seealso><c>}</c></tag> <item><p>The line where the token begins.</p> </item> - <tag><c>{location, <seealso marker="#type-location"> - location()</seealso>}</c></tag> + <tag><c>{location, </c><seealso marker="#type-location"> + location()</seealso><c>}</c></tag> <item><p>The line and column where the token begins, or just the line if the column unknown.</p> </item> diff --git a/lib/stdlib/doc/src/erl_tar.xml b/lib/stdlib/doc/src/erl_tar.xml index 0fa5a55c5b..898b55df72 100644 --- a/lib/stdlib/doc/src/erl_tar.xml +++ b/lib/stdlib/doc/src/erl_tar.xml @@ -442,7 +442,7 @@ structure like a file descriptor, a sftp channel id or such. The different <c>Fun</c> clauses operates on that very term. </p> - <p>The fun clauses parameter lists are: + <p>The fun clauses parameter lists are:</p> <taglist> <tag><c>(write, {UserPrivate,DataToWrite})</c></tag> <item>Write the term <c>DataToWrite</c> using <c>UserPrivate</c></item> @@ -457,7 +457,6 @@ <tag><c></c></tag> <item></item> </taglist> - </p> <p>A complete <c>Fun</c> parameter for reading and writing on files using the <seealso marker="kernel:file">file module</seealso> could be: </p> diff --git a/lib/stdlib/doc/src/ets.xml b/lib/stdlib/doc/src/ets.xml index ab1a5900b9..447fe51130 100644 --- a/lib/stdlib/doc/src/ets.xml +++ b/lib/stdlib/doc/src/ets.xml @@ -132,9 +132,10 @@ <name name="access"/> </datatype> <datatype> - <name><marker id="type-continuation">continuation()</marker></name> + <name>continuation()</name> <desc> - <p>Opaque continuation used by <seealso marker="#select/1"> + <p><marker id="type-continuation"/> + Opaque continuation used by <seealso marker="#select/1"> <c>select/1,3</c></seealso>, <seealso marker="#select_reverse/1"> <c>select_reverse/1,3</c></seealso>, <seealso marker="#match/1"> @@ -448,13 +449,13 @@ Error: fun containing local Erlang function calls <item><c>{owner, pid()}</c> <br></br> The pid of the owner of the table.</item> - <item><c>{protection, <seealso marker="#type-access">access()</seealso>}</c> <br></br> + <item><c>{protection, </c><seealso marker="#type-access">access()</seealso><c>}</c> <br></br> The table access rights.</item> <item><c>{size, integer() >= 0</c> <br></br> The number of objects inserted in the table.</item> - <item><c>{type, <seealso marker="#type-type">type()</seealso>}</c> <br></br> + <item><c>{type, </c><seealso marker="#type-type">type()</seealso><c>}</c> <br></br> The table type.</item> <item><c>{read_concurrency, boolean()}</c> <br></br> @@ -487,14 +488,39 @@ Error: fun containing local Erlang function calls <item><c>Item=fixed, Value=boolean()</c> <br></br> Indicates if the table is fixed by any process or not.</item> - <item> - <p><c>Item=safe_fixed, Value={FirstFixed,Info}|false</c> <br></br> + <item><marker id="info_2_safe_fixed_monotonic_time"/> + <p><c>Item=safe_fixed|safe_fixed_monotonic_time, Value={FixationTime,Info}|false</c> <br></br> </p> - <p>If the table has been fixed using <c>safe_fixtable/2</c>, - the call returns a tuple where <c>FirstFixed</c> is the + <p>If the table has been fixed using + <seealso marker="#safe_fixtable/2"><c>safe_fixtable/2</c></seealso>, + the call returns a tuple where <c>FixationTime</c> is the time when the table was first fixed by a process, which may or may not be one of the processes it is fixed by right now.</p> + <p>The format and value of <c>FixationTime</c> depends on + <c>Item</c>:</p> + <taglist> + <tag><c>safe_fixed</c></tag> + <item><p><c>FixationTime</c> will correspond to the result + returned by + <seealso marker="erts:erlang#timestamp/0">erlang:timestamp/0</seealso> + at the time of fixation. Note that when the system is using + single or multi + <seealso marker="erts:time_correction#Time_Warp_Modes">time warp + modes</seealso> this might produce strange results. This + since the usage of <c>safe_fixed</c> is not + <seealso marker="erts:time_correction#Time_Warp_Safe_Code">time warp + safe</seealso>. Time warp safe code need to use + <c>safe_fixed_monotonic_time</c> instead.</p></item> + + <tag><c>safe_fixed_monotonic_time</c></tag> + <item><p><c>FixationTime</c> will correspond to the result + returned by + <seealso marker="erts:erlang#monotonic_time/0">erlang:monotonic_time/0</seealso> + at the time of fixation. The usage of <c>safe_fixed_monotonic_time</c> is + <seealso marker="erts:time_correction#Time_Warp_Safe_Code">time warp + safe</seealso>.</p></item> + </taglist> <p><c>Info</c> is a possibly empty lists of tuples <c>{Pid,RefCount}</c>, one tuple for every process the table is fixed by right now. <c>RefCount</c> is the value @@ -610,7 +636,7 @@ ets:is_compiled_ms(Broken).</code> <p>Returns the last key <c><anno>Key</anno></c> according to Erlang term order in the table <c>Tab</c> of the <c>ordered_set</c> type. If the table is of any other type, the function is synonymous - to <c>first/2</c>. If the table is empty, + to <c>first/1</c>. If the table is empty, <c>'$end_of_table'</c> is returned.</p> <p>Use <c>prev/2</c> to find preceding keys in the table.</p> </desc> @@ -916,7 +942,7 @@ ets:select(Table,MatchSpec),</code> </item> <item> <p><c>{keypos,<anno>Pos</anno>}</c> - Specfies which element in the stored tuples should be + Specifies which element in the stored tuples should be used as key. By default, it is the first element, i.e. <c><anno>Pos</anno>=1</c>. However, this is not always appropriate. In particular, we do not want the first element to be the @@ -1134,9 +1160,11 @@ clean_all_with_value(Tab,X,Key) -> table but never releases it, the memory used by the deleted objects will never be freed. The performance of operations on the table will also degrade significantly.</p> - <p>Use <c>info/2</c> to retrieve information about which - processes have fixed which tables. A system with a lot of - processes fixing tables may need a monitor which sends alarms + <p>Use + <seealso marker="#info_2_safe_fixed_monotonic_time"><c>info(Tab, + safe_fixed_monotonic_time)</c></seealso> to retrieve information + about which processes have fixed which tables. A system with a lot + of processes fixing tables may need a monitor which sends alarms when tables have been fixed for too long.</p> <p>Note that for tables of the <c>ordered_set</c> type, <c>safe_fixtable/2</c> is not necessary as calls to @@ -1626,6 +1654,7 @@ true</pre> <name name="update_counter" arity="4" clause_i="2"/> <name name="update_counter" arity="3" clause_i="3"/> <name name="update_counter" arity="4" clause_i="3"/> + <fsummary>Update a counter object in an ETS table.</fsummary> <type variable="Tab"/> <type variable="Key"/> <type variable="UpdateOp" name_i="1"/> @@ -1633,7 +1662,6 @@ true</pre> <type variable="Threshold" name_i="1"/> <type variable="SetValue" name_i="1"/> <type variable="Default"/> - <fsummary>Update a counter object in an ETS table.</fsummary> <desc> <p>This function provides an efficient way to update one or more counters, without the hassle of having to look up an object, update @@ -1700,11 +1728,11 @@ true</pre> <func> <name name="update_element" arity="3" clause_i="1"/> <name name="update_element" arity="3" clause_i="2"/> + <fsummary>Updates the <c>Pos</c>:th element of the object with a given key in an ETS table.</fsummary> <type variable="Tab"/> <type variable="Key"/> <type variable="Value"/> <type variable="Pos"/> - <fsummary>Updates the <c>Pos</c>:th element of the object with a given key in an ETS table.</fsummary> <desc> <p>This function provides an efficient way to update one or more elements within an object, without the hassle of having to look up, diff --git a/lib/stdlib/doc/src/file_sorter.xml b/lib/stdlib/doc/src/file_sorter.xml index 30e09c17b0..f033eebec7 100644 --- a/lib/stdlib/doc/src/file_sorter.xml +++ b/lib/stdlib/doc/src/file_sorter.xml @@ -223,82 +223,82 @@ output(L) -> <datatypes> <datatype> - <name name="file_name"/><br/> + <name name="file_name"/> </datatype> <datatype> - <name name="file_names"/><br/> + <name name="file_names"/> </datatype> <datatype> - <name name="i_command"/><br/> + <name name="i_command"/> </datatype> <datatype> - <name name="i_reply"/><br/> + <name name="i_reply"/> </datatype> <datatype> - <name name="infun"/><br/> + <name name="infun"/> </datatype> <datatype> - <name name="input"/><br/> + <name name="input"/> </datatype> <datatype> - <name name="input_reply"/><br/> + <name name="input_reply"/> </datatype> <datatype> - <name name="o_command"/><br/> + <name name="o_command"/> </datatype> <datatype> - <name name="o_reply"/><br/> + <name name="o_reply"/> </datatype> <datatype> - <name name="object"/><br/> + <name name="object"/> </datatype> <datatype> - <name name="outfun"/><br/> + <name name="outfun"/> </datatype> <datatype> - <name name="output"/><br/> + <name name="output"/> </datatype> <datatype> - <name name="output_reply"/><br/> + <name name="output_reply"/> </datatype> <datatype> - <name name="value"/><br/> + <name name="value"/> </datatype> <datatype> - <name name="options"/><br/> + <name name="options"/> </datatype> <datatype> - <name name="option"/><br/> + <name name="option"/> </datatype> <datatype> - <name name="format"/><br/> + <name name="format"/> </datatype> <datatype> - <name name="format_fun"/><br/> + <name name="format_fun"/> </datatype> <datatype> - <name name="header_length"/><br/> + <name name="header_length"/> </datatype> <datatype> - <name name="key_pos"/><br/> + <name name="key_pos"/> </datatype> <datatype> - <name name="no_files"/><br/> + <name name="no_files"/> </datatype> <datatype> - <name name="order"/><br/> + <name name="order"/> </datatype> <datatype> - <name name="order_fun"/><br/> + <name name="order_fun"/> </datatype> <datatype> - <name name="size"/><br/> + <name name="size"/> </datatype> <datatype> - <name name="tmp_directory"/><br/> + <name name="tmp_directory"/> </datatype> <datatype> - <name name="reason"/><br/> + <name name="reason"/> </datatype> </datatypes> diff --git a/lib/stdlib/doc/src/filename.xml b/lib/stdlib/doc/src/filename.xml index 77e262dbe6..1d4ffc10f9 100644 --- a/lib/stdlib/doc/src/filename.xml +++ b/lib/stdlib/doc/src/filename.xml @@ -214,7 +214,7 @@ <desc> <p>Converts <c><anno>Path</anno></c> to a form accepted by the command shell and native applications on the current platform. On Windows, - forward slashes is converted to backward slashes. On all + forward slashes are converted to backward slashes. On all platforms, the name is normalized as done by <c>join/1</c>.</p> <pre> 19> <input>filename:nativename("/usr/local/bin/").</input> % Unix diff --git a/lib/stdlib/doc/src/gen_event.xml b/lib/stdlib/doc/src/gen_event.xml index 1efac1535a..c4bab45781 100644 --- a/lib/stdlib/doc/src/gen_event.xml +++ b/lib/stdlib/doc/src/gen_event.xml @@ -716,7 +716,7 @@ gen_event:stop -----> Module:terminate/2 the purposes described below.</p> </note> <p>This function is called by a gen_event process when:</p> - <list typed="bulleted"> + <list type="bulleted"> <item>One of <seealso marker="sys#get_status/1">sys:get_status/1,2</seealso> is invoked to get the gen_event status. <c>Opt</c> is set @@ -740,7 +740,7 @@ gen_event:stop -----> Module:terminate/2 customises the details of the current state of the event handler. Any term is allowed for <c>Status</c>. The gen_event module uses <c>Status</c> as follows:</p> - <list typed="bulleted"> + <list type="bulleted"> <item>When <c>sys:get_status/1,2</c> is called, gen_event ensures that its return value contains <c>Status</c> in place of the event handler's actual state term.</item> diff --git a/lib/stdlib/doc/src/gen_fsm.xml b/lib/stdlib/doc/src/gen_fsm.xml index 5f7b5a3437..4d594b8eb2 100644 --- a/lib/stdlib/doc/src/gen_fsm.xml +++ b/lib/stdlib/doc/src/gen_fsm.xml @@ -339,11 +339,12 @@ gen_fsm:sync_send_all_state_event -----> Module:handle_sync_event/4 </desc> </func> <func> - <name>reply(Caller, Reply) -> true</name> + <name>reply(Caller, Reply) -> Result</name> <fsummary>Send a reply to a caller.</fsummary> <type> <v>Caller - see below</v> <v>Reply = term()</v> + <v>Result = term()</v> </type> <desc> <p>This function can be used by a gen_fsm to explicitly send a @@ -358,6 +359,8 @@ gen_fsm:sync_send_all_state_event -----> Module:handle_sync_event/4 which will be given back to the client as the return value of <c>sync_send_event/2,3</c> or <c>sync_send_all_state_event/2,3</c>.</p> + <p>The return value <c>Result</c> is not further defined, and + should always be ignored.</p> </desc> </func> <func> @@ -802,7 +805,7 @@ gen_fsm:sync_send_all_state_event -----> Module:handle_sync_event/4 module state data.</p> </note> <p>This function is called by a gen_fsm process when:</p> - <list typed="bulleted"> + <list type="bulleted"> <item>One of <seealso marker="sys#get_status/1">sys:get_status/1,2</seealso> is invoked to get the gen_fsm status. <c>Opt</c> is set to diff --git a/lib/stdlib/doc/src/gen_server.xml b/lib/stdlib/doc/src/gen_server.xml index c31e869db8..6d04771cd4 100644 --- a/lib/stdlib/doc/src/gen_server.xml +++ b/lib/stdlib/doc/src/gen_server.xml @@ -673,7 +673,7 @@ gen_server:abcast -----> Module:handle_cast/2 module state.</p> </note> <p>This function is called by a gen_server process when:</p> - <list typed="bulleted"> + <list type="bulleted"> <item>One of <seealso marker="sys#get_status/1">sys:get_status/1,2</seealso> is invoked to get the gen_server status. <c>Opt</c> is set diff --git a/lib/stdlib/doc/src/io.xml b/lib/stdlib/doc/src/io.xml index edf3c51b4c..4655c8662f 100644 --- a/lib/stdlib/doc/src/io.xml +++ b/lib/stdlib/doc/src/io.xml @@ -132,8 +132,8 @@ <func> <name name="get_chars" arity="2"/> <name name="get_chars" arity="3"/> - <type name="server_no_data"/> <fsummary>Read a specified number of characters</fsummary> + <type name="server_no_data"/> <desc> <p>Reads <c><anno>Count</anno></c> characters from standard input (<c><anno>IoDevice</anno></c>), prompting it with <c><anno>Prompt</anno></c>. It @@ -162,8 +162,8 @@ <func> <name name="get_line" arity="1"/> <name name="get_line" arity="2"/> - <type name="server_no_data"/> <fsummary>Read a line</fsummary> + <type name="server_no_data"/> <desc> <p>Reads a line from the standard input (<c><anno>IoDevice</anno></c>), prompting it with <c><anno>Prompt</anno></c>. It returns:</p> @@ -300,8 +300,8 @@ <func> <name name="read" arity="1"/> <name name="read" arity="2"/> - <type name="server_no_data"/> <fsummary>Read a term</fsummary> + <type name="server_no_data"/> <desc> <p>Reads a term <c><anno>Term</anno></c> from the standard input (<c><anno>IoDevice</anno></c>), prompting it with <c><anno>Prompt</anno></c>. It @@ -330,8 +330,8 @@ <func> <name name="read" arity="3"/> <name name="read" arity="4"/> - <type name="server_no_data"/> <fsummary>Read a term</fsummary> + <type name="server_no_data"/> <desc> <p>Reads a term <c><anno>Term</anno></c> from <c><anno>IoDevice</anno></c>, prompting it with <c><anno>Prompt</anno></c>. Reading starts at location @@ -698,8 +698,8 @@ ok <func> <name name="fread" arity="2"/> <name name="fread" arity="3"/> - <type name="server_no_data"/> <fsummary>Read formatted input</fsummary> + <type name="server_no_data"/> <desc> <p>Reads characters from the standard input (<c><anno>IoDevice</anno></c>), prompting it with <c><anno>Prompt</anno></c>. Interprets the characters in @@ -870,8 +870,8 @@ enter><input>:</input> <input>alan</input> <input>:</input> <input>joe</in <name name="scan_erl_exprs" arity="2"/> <name name="scan_erl_exprs" arity="3"/> <name name="scan_erl_exprs" arity="4"/> - <type name="server_no_data"/> <fsummary>Read and tokenize Erlang expressions</fsummary> + <type name="server_no_data"/> <desc> <p>Reads data from the standard input (<c>IoDevice</c>), prompting it with <c>Prompt</c>. Reading starts at location @@ -919,8 +919,8 @@ enter><input>1.0er.</input> <name name="scan_erl_form" arity="2"/> <name name="scan_erl_form" arity="3"/> <name name="scan_erl_form" arity="4"/> - <type name="server_no_data"/> <fsummary>Read and tokenize an Erlang form</fsummary> + <type name="server_no_data"/> <desc> <p>Reads data from the standard input (<c><anno>IoDevice</anno></c>), prompting it with <c><anno>Prompt</anno></c>. Starts reading @@ -939,9 +939,9 @@ enter><input>1.0er.</input> <name name="parse_erl_exprs" arity="2"/> <name name="parse_erl_exprs" arity="3"/> <name name="parse_erl_exprs" arity="4"/> + <fsummary>Read, tokenize and parse Erlang expressions</fsummary> <type name="parse_ret"/> <type name="server_no_data"/> - <fsummary>Read, tokenize and parse Erlang expressions</fsummary> <desc> <p>Reads data from the standard input (<c><anno>IoDevice</anno></c>), prompting it with @@ -990,9 +990,9 @@ enter><input>abc("hey".</input> <name name="parse_erl_form" arity="2"/> <name name="parse_erl_form" arity="3"/> <name name="parse_erl_form" arity="4"/> + <fsummary>Read, tokenize and parse an Erlang form</fsummary> <type name="parse_form_ret"/> <type name="server_no_data"/> - <fsummary>Read, tokenize and parse an Erlang form</fsummary> <desc> <p>Reads data from the standard input (<c><anno>IoDevice</anno></c>), prompting it with <c><anno>Prompt</anno></c>. Starts reading at diff --git a/lib/stdlib/doc/src/lists.xml b/lib/stdlib/doc/src/lists.xml index 46edd9fe16..89ba5238b5 100644 --- a/lib/stdlib/doc/src/lists.xml +++ b/lib/stdlib/doc/src/lists.xml @@ -283,8 +283,8 @@ flatmap(Fun, List1) -> </func> <func> <name name="keyfind" arity="3"/> - <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc> <fsummary>Search for an element in a list of tuples</fsummary> + <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc> <desc> <p>Searches the list of tuples <c><anno>TupleList</anno></c> for a tuple whose <c><anno>N</anno></c>th element compares equal to <c><anno>Key</anno></c>. @@ -311,8 +311,8 @@ flatmap(Fun, List1) -> </func> <func> <name name="keymember" arity="3"/> - <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc> <fsummary>Test for membership of a list of tuples</fsummary> + <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc> <desc> <p>Returns <c>true</c> if there is a tuple in <c><anno>TupleList</anno></c> whose <c><anno>N</anno></c>th element compares equal to <c><anno>Key</anno></c>, otherwise @@ -346,8 +346,8 @@ flatmap(Fun, List1) -> </func> <func> <name name="keysearch" arity="3"/> - <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc> <fsummary>Search for an element in a list of tuples</fsummary> + <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc> <desc> <p>Searches the list of tuples <c><anno>TupleList</anno></c> for a tuple whose <c><anno>N</anno></c>th element compares equal to <c><anno>Key</anno></c>. diff --git a/lib/stdlib/doc/src/math.xml b/lib/stdlib/doc/src/math.xml index 31e838d741..aee6c3f238 100644 --- a/lib/stdlib/doc/src/math.xml +++ b/lib/stdlib/doc/src/math.xml @@ -72,9 +72,9 @@ <name name="log10" arity="1"/> <name name="pow" arity="2"/> <name name="sqrt" arity="1"/> + <fsummary>Diverse math functions</fsummary> <type variable="X" name_i="7"/> <type variable="Y" name_i="7"/> - <fsummary>Diverse math functions</fsummary> <desc> <p>A collection of math functions which return floats. Arguments are numbers. </p> diff --git a/lib/stdlib/doc/src/notes.xml b/lib/stdlib/doc/src/notes.xml index 514ac37d90..5d4f9d912f 100644 --- a/lib/stdlib/doc/src/notes.xml +++ b/lib/stdlib/doc/src/notes.xml @@ -31,6 +31,219 @@ </header> <p>This document describes the changes made to the STDLIB application.</p> +<section><title>STDLIB 2.8</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix evaluation in matching of bound map key variables in + the interpreter.</p> + <p> + Prior to this patch, the following code would not + evaluate: <c>X = key,(fun(#{X := value}) -> true + end)(#{X => value})</c></p> + <p> + Own Id: OTP-13218</p> + </item> + <item> + <p> Fix <c>erl_eval</c> not using non-local function + handler. </p> + <p> + Own Id: OTP-13228 Aux Id: ERL-32 </p> + </item> + <item> + <p> The Erlang Code Linter no longer crashes if there is + a <c>-deprecated()</c> attribute but no <c>-module()</c> + declaration. </p> + <p> + Own Id: OTP-13230 Aux Id: ERL-62 </p> + </item> + <item> + <p> + The timestamp in the result returned by <c>dets:info(Tab, + safe_fixed)</c> was unintentionally broken as a result of + the time API rewrites in OTP 18.0. This has now been + fixed.</p> + <p> + Own Id: OTP-13239 Aux Id: OTP-11997 </p> + </item> + <item> + <p>A rare race condition in <c>beam_lib</c> when using + encrypted abstract format has been eliminated.</p> + <p> + Own Id: OTP-13278</p> + </item> + <item> + <p> + Improved maps:with/2 and maps:without/2 algorithms</p> + <p> + The new implementation speeds up the execution + significantly for all sizes of input.</p> + <p> + Own Id: OTP-13376</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Time warp safety improvements.</p> + <p> + Introduced the options <c>monotonic_timestamp</c>, and + <c>strict_monotonic_timestamp</c> to the trace, + sequential trace, and system profile functionality. This + since the already existing <c>timestamp</c> option is not + time warp safe.</p> + <p> + Introduced the option <c>safe_fixed_monotonic_time</c> to + <c>ets:info/2</c> and <c>dets:info/2</c>. This since the + already existing <c>safe_fixed</c> option is not time + warp safe.</p> + <p> + Own Id: OTP-13222 Aux Id: OTP-11997 </p> + </item> + <item> + <p> + In the shell Ctrl+W (delete word) will no longer consider + "." as being part of a word.</p> + <p> + Own Id: OTP-13281</p> + </item> + </list> + </section> + +</section> + +<section><title>STDLIB 2.7</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>The Erlang Pretty Printer uses <c>::</c> for function + type constraints.</p> <p>A bug concerning pretty printing + of annotated type union elements in map pair types has + been fixed.</p> <p>Some minor issues regarding the + documentation of types and specs have been corrected.</p> + <p> + Own Id: OTP-13084</p> + </item> + <item> + <p> The shell command <c>rp</c> prints strings as lists + of integers if pretty printing of lists is set to + <c>false</c>. </p> + <p> + Own Id: OTP-13145</p> + </item> + <item> + <p> + The shell would crash if a bit syntax expression with + conflicting types were given (e.g. if a field type was + given as '<c>integer-binary</c>'). (Thanks to Aleksei + Magusev for reporting this bug.)</p> + <p> + Own Id: OTP-13157</p> + </item> + <item> + <p>The <c>rand:export_seed/0</c> would never return + '<c>undefined</c>' even if no seed has previously been + created. Fixed to return '<c>undefined</c>' if there is + no seed in the process dictionary.</p> + <p> + Own Id: OTP-13162</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Add support for the Delete, Home and End keys in the + Erlang shell.</p> + <p> + Own Id: OTP-13032</p> + </item> + <item> + <p><c>beam_lib:all_chunks/1</c> and + <c>beam_lib:build_module/1</c> have been documented.</p> + <p> + Own Id: OTP-13063</p> + </item> + </list> + </section> + +</section> + +<section><title>STDLIB 2.6</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> In OTP 18.0, <c>qlc</c> does not handle syntax errors + well. This bug has been fixed. </p> + <p> + Own Id: OTP-12946</p> + </item> + <item> + <p> + Optimize zip:unzip/2 when uncompressing to memory.</p> + <p> + Own Id: OTP-12950</p> + </item> + <item> + <p> + The <c>stdlib</c> reference manual is updated to show + correct information about the return value of + <c>gen_fsm:reply/2</c>.</p> + <p> + Own Id: OTP-12973</p> + </item> + <item> + <p>re:split2,3 and re:replace/3,4 now correctly handles + pre-compiled patterns that have been compiled using the + '<c>unicode</c>' option.</p> + <p> + Own Id: OTP-12977</p> + </item> + <item> + <p> + Export <c>shell:catch_exception/1</c> as documented.</p> + <p> + Own Id: OTP-12990</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>A mechanism for limiting the amount of text that the + built-in error logger events will produce has been + introduced. It is useful for limiting both the size of + log files and the CPU time used to produce them.</p> + <p>This mechanism is experimental in the sense that it + may be changed if it turns out that it does not solve the + problem it is supposed to solve. In that case, there may + be backward incompatible improvements to this + mechanism.</p> + <p>See the documentation for the config parameter + <c>error_logger_format_depth</c> in the Kernel + application for information about how to turn on this + feature.</p> + <p> + Own Id: OTP-12864</p> + </item> + </list> + </section> + +</section> + <section><title>STDLIB 2.5</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -89,8 +302,9 @@ Correct <c>maps</c> module error exceptions </p> <p> Bad input to maps module function will now yield the - following exceptions: <list> <item>{badmap,NotMap} - or,</item> <item>badarg</item> </list></p> + following exceptions:</p> + <list> <item>{badmap, NotMap}, or </item> <item>badarg.</item> + </list> <p> Own Id: OTP-12657</p> </item> @@ -188,12 +402,11 @@ <p> <c>proc_lib:stop/1,3</c> is used by the following functions:</p> - <p> <list> <item><c>gen_server:stop/1,3</c> (new)</item> <item><c>gen_fsm:stop/1,3</c> (new)</item> <item><c>gen_event:stop/1,3</c> (modified to be synchronous)</item> <item><c>wx_object:stop/1,3</c> - (new)</item> </list></p> + (new)</item> </list> <p> Own Id: OTP-11173 Aux Id: seq12353 </p> </item> @@ -800,8 +1013,7 @@ also implemented by the generic behaviours <c>gen_server</c>, <c>gen_event</c> and <c>gen_fsm</c>.</p> <p> - The potential incompatibility refers to</p> - <p> + The potential incompatibility refers to:</p> <list> <item>The previous behaviour of intercepting the system message and passing a tuple of size 2 as the last argument to <c>sys:handle_system_msg/6</c> is no longer @@ -809,7 +1021,7 @@ <c>StateFun</c> in <c>sys:replace_state/2,3</c> fails is changed from being totally silent to possibly (if the callback module does not catch) throw an exception in the - client process.</item> </list></p> + client process.</item> </list> <p> (Thanks to James Fish and Steve Vinoski)</p> <p> @@ -971,22 +1183,28 @@ <p> EEP43: New data type - Maps</p> <p> - With Maps you may for instance: <taglist> <item><c>M0 = - #{ a => 1, b => 2}, % create - associations</c></item> <item><c>M1 = M0#{ a := 10 }, % - update values</c></item> <item><c>M2 = M1#{ "hi" => - "hello"}, % add new associations</c></item> <item><c>#{ - "hi" := V1, a := V2, b := V3} = M2. % match keys with - values</c></item> </taglist></p> + With Maps you may for instance:</p> + <taglist> + <tag/> <item><c>M0 = #{ a => 1, b => 2}, % create + associations</c></item> + <tag/><item><c>M1 = M0#{ a := 10 }, % update values</c></item> + <tag/><item><c>M2 = M1#{ "hi" => + "hello"}, % add new associations</c></item> + <tag/><item><c>#{ "hi" := V1, a := V2, b := V3} = M2. + % match keys with values</c></item> + </taglist> <p> For information on how to use Maps please see Map Expressions in the <seealso marker="doc/reference_manual:expressions#map_expressions"> Reference Manual</seealso>.</p> <p> The current implementation is without the following - features: <taglist> <item>No variable keys</item> - <item>No single value access</item> <item>No map - comprehensions</item> </taglist></p> + features:</p> + <taglist> + <tag/><item>No variable keys</item> + <tag/><item>No single value access</item> + <tag/><item>No map comprehensions</item> + </taglist> <p> Note that Maps is <em>experimental</em> during OTP 17.0.</p> <p> @@ -1737,13 +1955,15 @@ supervisor or for the problematic child.</p> <p> This introduces some incompatibilities in stdlib due to - new return values from supervisor: <list> + new return values from supervisor:</p> + <list> <item>restart_child/2 can now return {error,restarting}</item> <item>delete_child/2 can now return {error,restarting}</item> <item>which_children/1 returns a list of {Id,Child,Type,Mods}, where Child, in addition to the old pid() or 'undefined', now also can be - 'restarting'.</item> </list></p> + 'restarting'.</item> + </list> <p> *** POTENTIAL INCOMPATIBILITY ***</p> <p> @@ -1759,10 +1979,10 @@ Own Id: OTP-9782 Aux Id: seq11964 </p> </item> <item> - <p> Use universal time as base in error logger + <p> Use universal time as base in error logger</p> <p> Previous conversion used the deprecated - calendar:local_time_to_universal_time/1 </p></p> + calendar:local_time_to_universal_time/1 </p> <p> Own Id: OTP-9854</p> </item> @@ -2519,10 +2739,10 @@ Own Id: OTP-8989 Aux Id: seq11741 </p> </item> <item> - <p>Fix exception generation in the io module + <p>Fix exception generation in the io module</p> <p> Some functions did not generate correct badarg exception - on a badarg exception.</p></p> + on a badarg exception.</p> <p> Own Id: OTP-9045</p> </item> diff --git a/lib/stdlib/doc/src/proc_lib.xml b/lib/stdlib/doc/src/proc_lib.xml index 86ade8840f..85f0c0c908 100644 --- a/lib/stdlib/doc/src/proc_lib.xml +++ b/lib/stdlib/doc/src/proc_lib.xml @@ -227,6 +227,17 @@ init(Parent) -> </desc> </func> <func> + <name name="format" arity="3"/> + <fsummary>Format a crash report.</fsummary> + <desc> + <p>This function can be used by a user defined event handler to + format a crash report. When <anno>Depth</anno> is given as an + positive integer, it will be used in the format string to + limit the output as follows: <c>io_lib:format("~P", + [Term,<anno>Depth</anno>])</c>.</p> + </desc> + </func> + <func> <name name="initial_call" arity="1"/> <fsummary>Extract the initial call of a <c>proc_lib</c>spawned process.</fsummary> <desc> diff --git a/lib/stdlib/doc/src/rand.xml b/lib/stdlib/doc/src/rand.xml index e7d4728ef7..50057259c6 100644 --- a/lib/stdlib/doc/src/rand.xml +++ b/lib/stdlib/doc/src/rand.xml @@ -104,7 +104,7 @@ strong. If a strong cryptographic random number generator is needed, use one of functions in the <seealso marker="crypto:crypto">crypto</seealso> - module, for example <c>crypto:rand_bytes/1</c>.</p></note> + module, for example <c>crypto:strong_rand_bytes/1</c>.</p></note> </description> <datatypes> <datatype> diff --git a/lib/stdlib/doc/src/random.xml b/lib/stdlib/doc/src/random.xml index 91a4012ce9..fc4f796863 100644 --- a/lib/stdlib/doc/src/random.xml +++ b/lib/stdlib/doc/src/random.xml @@ -48,7 +48,7 @@ tuple of three integers.</p> <p>It should be noted that this random number generator is not cryptographically strong. If a strong cryptographic random number generator is needed for - example <c>crypto:rand_bytes/1</c> could be used instead.</p> + example <c>crypto:strong_rand_bytes/1</c> could be used instead.</p> <note><p>The new and improved <seealso marker="stdlib:rand">rand</seealso> module should be used instead of this module.</p></note> @@ -76,9 +76,15 @@ dictionary, and returns the old state.</p> <p>One easy way of obtaining a unique value to seed with is to:</p> <code type="none"> - random:seed(<seealso marker="erts:erlang#phash2/1">erlang:phash2</seealso>([<seealso marker="erts:erlang#node/0">node()</seealso>]), - <seealso marker="erts:erlang#monotonic_time/0">erlang:monotonic_time()</seealso>, - <seealso marker="erts:erlang#unique_integer/0">erlang:unique_integer()</seealso>)</code> +random:seed(erlang:phash2([node()]), + erlang:monotonic_time(), + erlang:unique_integer())</code> + <p>See <seealso marker="erts:erlang#phash2/1"> + erlang:phash2/1</seealso>, <seealso marker="erts:erlang#node/0"> + node/0</seealso>, <seealso marker="erts:erlang#monotonic_time/0"> + erlang:monotonic_time/0</seealso>, and + <seealso marker="erts:erlang#unique_integer/0"> + erlang:unique_integer/0</seealso>) for details.</p> </desc> </func> <func> @@ -142,7 +148,7 @@ <p>The implementation changed in R15. Upgrading to R15 will break applications that expect a specific output for a given seed. The output is still deterministic number series, but different compared to releases - older than R15. The seed <c>{0,0,0}</c> will for example no longer + older than R15. The seed <c>{0,0,0}</c> will, for example, no longer produce a flawed series of only zeros.</p> </section> </erlref> diff --git a/lib/stdlib/doc/src/re.xml b/lib/stdlib/doc/src/re.xml index 46b382a6be..8c19926b10 100644 --- a/lib/stdlib/doc/src/re.xml +++ b/lib/stdlib/doc/src/re.xml @@ -205,8 +205,8 @@ This option makes it possible to include comments inside complicated patterns. N </func> <func> <name name="run" arity="3"/> - <type_desc variable="CompileOpt">See <seealso marker="#compile_options">compile/2</seealso> above.</type_desc> <fsummary>Match a subject against regular expression and capture subpatterns</fsummary> + <type_desc variable="CompileOpt">See <seealso marker="#compile_options">compile/2</seealso> above.</type_desc> <desc> <p>Executes a regexp matching, returning <c>match/{match, @@ -881,11 +881,11 @@ nomatch </desc> </func> </funcs> - - <marker id="regexp_syntax"></marker> + <section> <title>PERL LIKE REGULAR EXPRESSIONS SYNTAX</title> - <p>The following sections contain reference material for the + <p><marker id="regexp_syntax"></marker> + The following sections contain reference material for the regular expressions used by this module. The regular expression reference is based on the PCRE documentation, with changes in cases where the re module behaves differently to the PCRE library.</p> @@ -2070,7 +2070,7 @@ supported, and an error is given if they are encountered.</p> <p>By default, in UTF modes, characters with values greater than 255 do not match any of the POSIX character classes. However, if the PCRE_UCP option is passed -to <b>pcre_compile()</b>, some of the classes are changed so that Unicode +to <em>pcre_compile()</em>, some of the classes are changed so that Unicode character properties are used. This is achieved by replacing the POSIX classes by other sequences, as follows:</p> @@ -2078,10 +2078,10 @@ by other sequences, as follows:</p> <tag>[:alnum:]</tag> <item>becomes <em>\p{Xan}</em></item> <tag>[:alpha:]</tag> <item>becomes <em>\p{L}</em></item> <tag>[:blank:]</tag> <item>becomes <em>\h</em></item> - <tag>[:digit:</tag>] <item>becomes <em>\p{Nd}</em></item> + <tag>[:digit:]</tag> <item>becomes <em>\p{Nd}</em></item> <tag>[:lower:]</tag> <item>becomes <em>\p{Ll}</em></item> <tag>[:space:]</tag> <item>becomes <em>\p{Xps}</em></item> - <tag>[:upper:</tag>] <item>becomes <em>\p{Lu}</em></item> + <tag>[:upper:]</tag> <item>becomes <em>\p{Lu}</em></item> <tag>[:word:]</tag> <item>becomes <em>\p{Xwd}</em></item> </taglist> @@ -3059,7 +3059,7 @@ default newline convention is in force:</p> <quote><p> abc #comment \n still comment</p></quote> -<p>On encountering the # character, <b>pcre_compile()</b> skips along, looking for +<p>On encountering the # character, <em>pcre_compile()</em> skips along, looking for a newline in the pattern. The sequence \n is still literal at this stage, so it does not terminate the comment. Only an actual character with the code value 0x0a (the default newline) does so.</p> diff --git a/lib/stdlib/doc/src/sofs.xml b/lib/stdlib/doc/src/sofs.xml index 5d7648d9a1..53f6ca957a 100644 --- a/lib/stdlib/doc/src/sofs.xml +++ b/lib/stdlib/doc/src/sofs.xml @@ -398,8 +398,9 @@ fun(S) -> sofs:partition(1, S) end </datatype> <datatype> <!-- Parameterized opaque types are NYI: --> - <name><marker id="type-tuple_of">tuple_of(T)</marker></name> - <desc><p>A tuple where the elements are of type <c>T</c>.</p></desc> + <name>tuple_of(T)</name> + <desc><p><marker id="type-tuple_of"/> + A tuple where the elements are of type <c>T</c>.</p></desc> </datatype> </datatypes> <funcs> diff --git a/lib/stdlib/doc/src/supervisor.xml b/lib/stdlib/doc/src/supervisor.xml index f08b752998..815bf4a489 100644 --- a/lib/stdlib/doc/src/supervisor.xml +++ b/lib/stdlib/doc/src/supervisor.xml @@ -353,7 +353,7 @@ <desc> <p>Dynamically adds a child specification to the supervisor <c><anno>SupRef</anno></c> which starts the corresponding child process.</p> - <p><marker id="SupRef"><c><anno>SupRef</anno></c></marker> can be:</p> + <p><marker id="SupRef"/><c><anno>SupRef</anno></c> can be:</p> <list type="bulleted"> <item>the pid,</item> <item><c>Name</c>, if the supervisor is locally registered,</item> @@ -543,7 +543,10 @@ </item> <item> <p><c>active</c> - the count of all actively running child processes - managed by this supervisor.</p> + managed by this supervisor. In the case of <c>simple_one_for_one</c> + supervisors, no check is carried out to ensure that each child process + is still alive, though the result provided here is likely to be very + accurate unless the supervisor is heavily overloaded.</p> </item> <item> <p><c>supervisors</c> - the count of all children marked as diff --git a/lib/stdlib/doc/src/sys.xml b/lib/stdlib/doc/src/sys.xml index 6ec515849e..d400f72e1d 100644 --- a/lib/stdlib/doc/src/sys.xml +++ b/lib/stdlib/doc/src/sys.xml @@ -238,8 +238,8 @@ <p>These functions are intended only to help with debugging. They are provided for convenience, allowing developers to avoid having to create their own state extraction functions and also avoid having to interactively extract state from the return values of - <c><seealso marker="#get_status-1">get_status/1</seealso></c> or - <c><seealso marker="#get_status-2">get_status/2</seealso></c> while debugging.</p> + <seealso marker="#get_status-1"><c>get_status/1</c></seealso> or + <seealso marker="#get_status-2"><c>get_status/2</c></seealso> while debugging.</p> </note> <p>The value of <c><anno>State</anno></c> varies for different types of processes. For a <c>gen_server</c> process, the returned <c><anno>State</anno></c> diff --git a/lib/stdlib/doc/src/timer.xml b/lib/stdlib/doc/src/timer.xml index e002f519b9..7609487300 100644 --- a/lib/stdlib/doc/src/timer.xml +++ b/lib/stdlib/doc/src/timer.xml @@ -85,7 +85,6 @@ <name name="send_after" arity="3"/> <fsummary>Send <c>Message</c>to <c>Pid</c>after a specified <c>Time</c>.</fsummary> <desc> - <p> <taglist> <tag><c>send_after/3</c></tag> <item> @@ -99,7 +98,6 @@ <p>Same as <c>send_after(<anno>Time</anno>, self(), <anno>Message</anno>)</c>.</p> </item> </taglist> - </p> </desc> </func> <func> @@ -109,7 +107,6 @@ <name name="exit_after" arity="3"/> <fsummary>Send an exit signal with <c>Reason</c>after a specified <c>Time</c>.</fsummary> <desc> - <p> <taglist> <tag><c>exit_after/3</c></tag> <item> @@ -130,7 +127,6 @@ <p>Same as <c>exit_after(<anno>Time</anno>, self(), kill)</c>. </p> </item> </taglist> - </p> </desc> </func> <func> @@ -147,7 +143,6 @@ <name name="send_interval" arity="3"/> <fsummary>Send <c>Message</c>repeatedly at intervals of <c>Time</c>.</fsummary> <desc> - <p> <taglist> <tag><c>send_interval/3</c></tag> <item> @@ -161,7 +156,6 @@ <p>Same as <c>send_interval(<anno>Time</anno>, self(), <anno>Message</anno>)</c>.</p> </item> </taglist> - </p> </desc> </func> <func> @@ -192,7 +186,6 @@ Function, Arguments)</c> or <c>apply(Fun, Arguments)</c></fsummary> <type_desc variable="Time">In microseconds</type_desc> <desc> - <p> <taglist> <tag><c>tc/3</c></tag> <item> @@ -213,7 +206,6 @@ </item> </taglist> - </p> </desc> </func> <func> diff --git a/lib/stdlib/doc/src/unicode.xml b/lib/stdlib/doc/src/unicode.xml index 19ddf1cbd6..966eec49f5 100644 --- a/lib/stdlib/doc/src/unicode.xml +++ b/lib/stdlib/doc/src/unicode.xml @@ -133,7 +133,7 @@ <c>latin1</c>, or have characters encoded as one of the UTF-encodings, which is given as the <c><anno>InEncoding</anno></c> parameter. Only when the <c><anno>InEncoding</anno></c> is one of the UTF - encodings, integers in the list are allowed to be grater than + encodings, integers in the list are allowed to be greater than 255.</p> <p>If <c><anno>InEncoding</anno></c> is <c>latin1</c>, the <c><anno>Data</anno></c> parameter diff --git a/lib/stdlib/doc/src/zip.xml b/lib/stdlib/doc/src/zip.xml index 4500995c34..186c8ac724 100644 --- a/lib/stdlib/doc/src/zip.xml +++ b/lib/stdlib/doc/src/zip.xml @@ -126,7 +126,7 @@ </datatype> <datatype> <name name="filename"/> - <p>The name of a zip file.</p> + <desc><p>The name of a zip file.</p></desc> </datatype> <datatype><name name="extension"/></datatype> <datatype><name name="extension_spec"/></datatype> diff --git a/lib/stdlib/src/beam_lib.erl b/lib/stdlib/src/beam_lib.erl index b93ce97cd3..503a2b416f 100644 --- a/lib/stdlib/src/beam_lib.erl +++ b/lib/stdlib/src/beam_lib.erl @@ -308,6 +308,17 @@ make_crypto_key(des3_cbc=Type, String) -> <<K3:8/binary,IVec:8/binary>> = erlang:md5([First|reverse(String)]), {Type,[K1,K2,K3],IVec,8}. +-spec build_module(Chunks) -> {'ok', Binary} when + Chunks :: [{chunkid(), dataB()}], + Binary :: binary(). + +build_module(Chunks0) -> + Chunks = list_to_binary(build_chunks(Chunks0)), + Size = byte_size(Chunks), + 0 = Size rem 4, % Assertion: correct padding? + {ok, <<"FOR1", (Size+4):32, "BEAM", Chunks/binary>>}. + + %% %% Local functions %% @@ -419,12 +430,6 @@ strip_file(File) -> end end. -build_module(Chunks0) -> - Chunks = list_to_binary(build_chunks(Chunks0)), - Size = byte_size(Chunks), - 0 = Size rem 4, % Assertion: correct padding? - {ok, <<"FOR1", (Size+4):32, "BEAM", Chunks/binary>>}. - build_chunks([{Id, Data} | Chunks]) -> BId = list_to_binary(Id), Size = byte_size(Data), @@ -926,7 +931,10 @@ call_crypto_server(Req) -> end. call_crypto_server_1(Req) -> - {ok, _} = gen_server:start({local,?CRYPTO_KEY_SERVER}, ?MODULE, [], []), + case gen_server:start({local,?CRYPTO_KEY_SERVER}, ?MODULE, [], []) of + {ok, _} -> ok; + {error, {already_started, _}} -> ok + end, erlang:yield(), call_crypto_server(Req). diff --git a/lib/stdlib/src/dets.erl b/lib/stdlib/src/dets.erl index 6d07f4018a..2d037ff795 100644 --- a/lib/stdlib/src/dets.erl +++ b/lib/stdlib/src/dets.erl @@ -372,7 +372,7 @@ info(Tab) -> Item :: 'access' | 'auto_save' | 'bchunk_format' | 'hash' | 'file_size' | 'filename' | 'keypos' | 'memory' | 'no_keys' | 'no_objects' | 'no_slots' | 'owner' | 'ram_file' - | 'safe_fixed' | 'size' | 'type' | 'version', + | 'safe_fixed' | 'safe_fixed_monotonic_time' | 'size' | 'type' | 'version', Value :: term(). info(Tab, owner) -> @@ -1964,7 +1964,9 @@ do_safe_fixtable(Head, Pid, true) -> case Head#head.fixed of false -> link(Pid), - Fixed = {utime_now(), [{Pid, 1}]}, + MonTime = erlang:monotonic_time(), + TimeOffset = erlang:time_offset(), + Fixed = {{MonTime, TimeOffset}, [{Pid, 1}]}, Ftab = dets_utils:get_freelists(Head), Head#head{fixed = Fixed, freelists = {Ftab, Ftab}}; {TimeStamp, Counters} -> @@ -2091,7 +2093,22 @@ finfo(H, no_keys) -> finfo(H, no_slots) -> {H, (H#head.mod):no_slots(H)}; finfo(H, pid) -> {H, self()}; finfo(H, ram_file) -> {H, H#head.ram_file}; -finfo(H, safe_fixed) -> {H, H#head.fixed}; +finfo(H, safe_fixed) -> + {H, + case H#head.fixed of + false -> + false; + {{FixMonTime, TimeOffset}, RefList} -> + {make_timestamp(FixMonTime, TimeOffset), RefList} + end}; +finfo(H, safe_fixed_monotonic_time) -> + {H, + case H#head.fixed of + false -> + false; + {{FixMonTime, _TimeOffset}, RefList} -> + {FixMonTime, RefList} + end}; finfo(H, size) -> case catch write_cache(H) of {H2, []} -> @@ -3275,11 +3292,14 @@ err(Error) -> time_now() -> erlang:monotonic_time(1000000). --compile({inline, [utime_now/0]}). -utime_now() -> - Time = time_now(), - UniqueCounter = erlang:unique_integer([monotonic]), - {Time, UniqueCounter}. +make_timestamp(MonTime, TimeOffset) -> + ErlangSystemTime = erlang:convert_time_unit(MonTime+TimeOffset, + native, + micro_seconds), + MegaSecs = ErlangSystemTime div 1000000000000, + Secs = ErlangSystemTime div 1000000 - MegaSecs*1000000, + MicroSecs = ErlangSystemTime rem 1000000, + {MegaSecs, Secs, MicroSecs}. %%%%%%%%%%%%%%%%% DEBUG functions %%%%%%%%%%%%%%%% diff --git a/lib/stdlib/src/dets_utils.erl b/lib/stdlib/src/dets_utils.erl index 196158cd48..34a8ddddaa 100644 --- a/lib/stdlib/src/dets_utils.erl +++ b/lib/stdlib/src/dets_utils.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2013. All Rights Reserved. +%% Copyright Ericsson AB 2001-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -747,6 +747,8 @@ all_allocated([{X,Y} | L], _X0, Y0, A) when Y0 < X -> all_allocated_as_list(Head) -> all_allocated_as_list(all(get_freelists(Head)), 0, Head#head.base, []). +-dialyzer({no_improper_lists, all_allocated_as_list/4}). + all_allocated_as_list([], _X0, _Y0, []) -> []; all_allocated_as_list([], _X0, _Y0, A) -> diff --git a/lib/stdlib/src/dets_v8.erl b/lib/stdlib/src/dets_v8.erl index 49126193b8..1bf53d91b1 100644 --- a/lib/stdlib/src/dets_v8.erl +++ b/lib/stdlib/src/dets_v8.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2013. All Rights Reserved. +%% Copyright Ericsson AB 2001-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -36,6 +36,8 @@ %% For backward compatibility. -export([sz2pos/1]). +-dialyzer(no_improper_lists). + -compile({inline, [{sz2pos,1},{scan_skip,7}]}). -compile({inline, [{skip_bytes,5}, {get_segp,1}]}). -compile({inline, [{wl_lookup,5}]}). diff --git a/lib/stdlib/src/dets_v9.erl b/lib/stdlib/src/dets_v9.erl index 361780c776..6c406fc03a 100644 --- a/lib/stdlib/src/dets_v9.erl +++ b/lib/stdlib/src/dets_v9.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2013. All Rights Reserved. +%% Copyright Ericsson AB 2001-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,6 +34,8 @@ -export([cache_segps/3]). +-dialyzer(no_improper_lists). + -compile({inline, [{max_objsize,1},{maxobjsize,1}]}). -compile({inline, [{write_segment_file,6}]}). -compile({inline, [{sz2pos,1},{adjsz,1}]}). diff --git a/lib/stdlib/src/dict.erl b/lib/stdlib/src/dict.erl index 6ce3710f87..f921e28ef6 100644 --- a/lib/stdlib/src/dict.erl +++ b/lib/stdlib/src/dict.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2014. All Rights Reserved. +%% Copyright Ericsson AB 2000-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -333,6 +333,8 @@ update_counter(Key, Incr, D0) when is_number(Incr) -> D0, Slot), maybe_expand(D1, Ic). +-dialyzer({no_improper_lists, counter_bkt/3}). + counter_bkt(Key, I, [?kv(Key,Val)|Bkt]) -> {[?kv(Key,Val+I)|Bkt],0}; counter_bkt(Key, I, [Other|Bkt0]) -> diff --git a/lib/stdlib/src/digraph.erl b/lib/stdlib/src/digraph.erl index e51e560542..8a4df95027 100644 --- a/lib/stdlib/src/digraph.erl +++ b/lib/stdlib/src/digraph.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2014. All Rights Reserved. +%% Copyright Ericsson AB 1996-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -338,6 +338,8 @@ edge(G, E) -> %% -spec new_edge_id(graph()) -> edge(). +-dialyzer({no_improper_lists, new_edge_id/1}). + new_edge_id(G) -> NT = G#digraph.ntab, [{'$eid', K}] = ets:lookup(NT, '$eid'), @@ -350,6 +352,8 @@ new_edge_id(G) -> %% -spec new_vertex_id(graph()) -> vertex(). +-dialyzer({no_improper_lists, new_vertex_id/1}). + new_vertex_id(G) -> NT = G#digraph.ntab, [{'$vid', K}] = ets:lookup(NT, '$vid'), diff --git a/lib/stdlib/src/edlin.erl b/lib/stdlib/src/edlin.erl index 8c7a984f1c..0e9c457de2 100644 --- a/lib/stdlib/src/edlin.erl +++ b/lib/stdlib/src/edlin.erl @@ -227,6 +227,8 @@ key_map($F, meta_o) -> end_of_line; key_map($\177, none) -> backward_delete_char; key_map($\177, meta) -> backward_kill_word; key_map($[, meta) -> meta_left_sq_bracket; +key_map($H, meta_left_sq_bracket) -> beginning_of_line; +key_map($F, meta_left_sq_bracket) -> end_of_line; key_map($D, meta_left_sq_bracket) -> backward_char; key_map($C, meta_left_sq_bracket) -> forward_char; % support a few <CTRL>+<CURSOR LEFT|RIGHT> combinations... @@ -237,8 +239,10 @@ key_map($[, meta_meta) -> meta_csi; key_map($C, meta_csi) -> forward_word; key_map($D, meta_csi) -> backward_word; key_map($1, meta_left_sq_bracket) -> {csi, "1"}; +key_map($3, meta_left_sq_bracket) -> {csi, "3"}; key_map($5, meta_left_sq_bracket) -> {csi, "5"}; key_map($5, {csi, "1;"}) -> {csi, "1;5"}; +key_map($~, {csi, "3"}) -> forward_delete_char; key_map($C, {csi, "5"}) -> forward_word; key_map($C, {csi, "1;5"}) -> forward_word; key_map($D, {csi, "5"}) -> backward_word; @@ -461,7 +465,6 @@ word_char(C) when C >= $a, C =< $z -> true; word_char(C) when C >= $ß, C =< $ÿ, C =/= $÷ -> true; word_char(C) when C >= $0, C =< $9 -> true; word_char(C) when C =:= $_ -> true; -word_char(C) when C =:= $. -> true; % accept dot-separated names word_char(_) -> false. %% over_white(Chars, InitialStack, InitialCount) -> diff --git a/lib/stdlib/src/erl_eval.erl b/lib/stdlib/src/erl_eval.erl index ca3cc43b19..40a34aa30f 100644 --- a/lib/stdlib/src/erl_eval.erl +++ b/lib/stdlib/src/erl_eval.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2015. All Rights Reserved. +%% Copyright Ericsson AB 1996-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -415,7 +415,7 @@ expr({call,_,{atom,_,Func},As0}, Bs0, Lf, Ef, RBs) -> {As,Bs} = expr_list(As0, Bs0, Lf, Ef), bif(Func, As, Bs, Ef, RBs); false -> - local_func(Func, As0, Bs0, Lf, RBs) + local_func(Func, As0, Bs0, Lf, Ef, RBs) end; expr({call,_,Func0,As0}, Bs0, Lf, Ef, RBs) -> % function or {Mod,Fun} {value,Func,Bs1} = expr(Func0, Bs0, Lf, Ef, none), @@ -542,33 +542,34 @@ unhide_calls([E | Es], MaxLine, D) -> unhide_calls(E, _MaxLine, _D) -> E. -%% local_func(Function, Arguments, Bindings, LocalFuncHandler, RBs) -> +%% local_func(Function, Arguments, Bindings, LocalFuncHandler, +%% ExternalFuncHandler, RBs) -> %% {value,Value,Bindings} | Value when %% LocalFuncHandler = {value,F} | {value,F,Eas} | %% {eval,F} | {eval,F,Eas} | none. -local_func(Func, As0, Bs0, {value,F}, value) -> - {As1,_Bs1} = expr_list(As0, Bs0, {value,F}), +local_func(Func, As0, Bs0, {value,F}, Ef, value) -> + {As1,_Bs1} = expr_list(As0, Bs0, {value,F}, Ef), %% Make tail recursive calls when possible. F(Func, As1); -local_func(Func, As0, Bs0, {value,F}, RBs) -> - {As1,Bs1} = expr_list(As0, Bs0, {value,F}), +local_func(Func, As0, Bs0, {value,F}, Ef, RBs) -> + {As1,Bs1} = expr_list(As0, Bs0, {value,F}, Ef), ret_expr(F(Func, As1), Bs1, RBs); -local_func(Func, As0, Bs0, {value,F,Eas}, RBs) -> +local_func(Func, As0, Bs0, {value,F,Eas}, Ef, RBs) -> Fun = fun(Name, Args) -> apply(F, [Name,Args|Eas]) end, - local_func(Func, As0, Bs0, {value, Fun}, RBs); -local_func(Func, As, Bs, {eval,F}, RBs) -> + local_func(Func, As0, Bs0, {value, Fun}, Ef, RBs); +local_func(Func, As, Bs, {eval,F}, _Ef, RBs) -> local_func2(F(Func, As, Bs), RBs); -local_func(Func, As, Bs, {eval,F,Eas}, RBs) -> +local_func(Func, As, Bs, {eval,F,Eas}, _Ef, RBs) -> local_func2(apply(F, [Func,As,Bs|Eas]), RBs); %% These two clauses are for backwards compatibility. -local_func(Func, As0, Bs0, {M,F}, RBs) -> - {As1,Bs1} = expr_list(As0, Bs0, {M,F}), +local_func(Func, As0, Bs0, {M,F}, Ef, RBs) -> + {As1,Bs1} = expr_list(As0, Bs0, {M,F}, Ef), ret_expr(M:F(Func,As1), Bs1, RBs); -local_func(Func, As, _Bs, {M,F,Eas}, RBs) -> +local_func(Func, As, _Bs, {M,F,Eas}, _Ef, RBs) -> local_func2(apply(M, F, [Func,As|Eas]), RBs); %% Default unknown function handler to undefined function. -local_func(Func, As0, _Bs0, none, _RBs) -> +local_func(Func, As0, _Bs0, none, _Ef, _RBs) -> erlang:raise(error, undef, [{erl_eval,Func,length(As0)}|stacktrace()]). local_func2({value,V,Bs}, RBs) -> @@ -1184,7 +1185,7 @@ match_tuple([], _, _, Bs, _BBs) -> match_map([{map_field_exact, _, K, V}|Fs], Map, Bs0, BBs) -> Vm = try - {value, Ke, _} = expr(K, Bs0), + {value, Ke, _} = expr(K, BBs), maps:get(Ke,Map) catch error:_ -> throw(nomatch) diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl index c4cb5fdc80..62b3169a6c 100644 --- a/lib/stdlib/src/erl_lint.erl +++ b/lib/stdlib/src/erl_lint.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2015. All Rights Reserved. +%% Copyright Ericsson AB 1996-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -100,7 +100,7 @@ value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) -> %% 'called' and 'exports' contain {Line, {Function, Arity}}, %% the other function collections contain {Function, Arity}. -record(lint, {state=start :: 'start' | 'attribute' | 'function', - module=[], %Module + module='', %Module behaviour=[], %Behaviour exports=gb_sets:empty() :: gb_sets:set(fa()),%Exports imports=[] :: [fa()], %Imports, an orddict() @@ -293,6 +293,9 @@ format_error({variable_in_record_def,V}) -> %% --- binaries --- format_error({undefined_bittype,Type}) -> io_lib:format("bit type ~w undefined", [Type]); +format_error({bittype_mismatch,Val1,Val2,What}) -> + io_lib:format("conflict in ~s specification for bit field: '~p' and '~p'", + [What,Val1,Val2]); format_error(bittype_unit) -> "a bit unit size must not be specified unless a size is specified too"; format_error(illegal_bitsize) -> @@ -726,7 +729,7 @@ start_state(Form, St) -> %% attribute_state(Form, State) -> %% State' -attribute_state({attribute,_L,module,_M}, #lint{module=[]}=St) -> +attribute_state({attribute,_L,module,_M}, #lint{module=''}=St) -> St; attribute_state({attribute,L,module,_M}, St) -> add_error(L, redefine_module, St); @@ -3529,6 +3532,8 @@ check_qlc_hrl(Line, M, F, As, St) -> %% deprecated_function(Line, ModName, FuncName, [Arg], State) -> State. %% Add warning for calls to deprecated functions. +-dialyzer({no_match, deprecated_function/5}). + deprecated_function(Line, M, F, As, St) -> Arity = length(As), MFA = {M, F, Arity}, @@ -3557,6 +3562,8 @@ deprecated_function(Line, M, F, As, St) -> St end. +-dialyzer({no_match, deprecated_type/5}). + deprecated_type(L, M, N, As, St) -> NAs = length(As), case otp_internal:obsolete_type(M, N, NAs) of diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl index f7a969977a..c5177aca90 100644 --- a/lib/stdlib/src/erl_pp.erl +++ b/lib/stdlib/src/erl_pp.erl @@ -253,6 +253,8 @@ lattribute(import, Name, _Opts, _State) when is_list(Name) -> attr("import", [{var,a0(),pname(Name)}]); lattribute(import, {From,Falist}, _Opts, _State) -> attr("import",[{var,a0(),pname(From)},falist(Falist)]); +lattribute(export_type, Talist, _Opts, _State) -> + call({var,a0(),"-export_type"}, [falist(Talist)], 0, options(none)); lattribute(optional_callbacks, Falist, Opts, _State) -> ArgL = try falist(Falist) catch _:_ -> abstract(Falist, Opts) @@ -321,7 +323,6 @@ ltype({type,_,'fun',[{type,_,any},_]}=FunType, _) -> ltype({type,_Line,'fun',[{type,_,product,_},_]}=FunType, _) -> [fun_type(['fun',$(], FunType),$)]; ltype({type,Line,T,Ts}, _) -> - %% Compatibility. Before 18.0. simple_type({atom,Line,T}, Ts); ltype({user_type,Line,T,Ts}, _) -> simple_type({atom,Line,T}, Ts); @@ -346,16 +347,8 @@ map_type(Fs) -> map_pair_types(Fs) -> tuple_type(Fs, fun map_pair_type/2). -map_pair_type({type,_Line,map_field_assoc,[Ktype,Vtype]}, Prec) -> - map_assoc_typed(ltype(Ktype), Vtype, Prec). - -map_assoc_typed(B, {type,_,union,Ts}, Prec) -> - {first,[B,$\s],{seq,[],[],[],map_assoc_union_type(Ts, Prec)}}; -map_assoc_typed(B, Type, Prec) -> - {list,[{cstep,[B," =>"],ltype(Type, Prec)}]}. - -map_assoc_union_type([T|Ts], Prec) -> - [[leaf("=> "),ltype(T)] | ltypes(Ts, fun union_elem/2, Prec)]. +map_pair_type({type,_Line,map_field_assoc,[KType,VType]}, Prec) -> + {list,[{cstep,[ltype(KType, Prec),leaf(" =>")],ltype(VType, Prec)}]}. record_type(Name, Fields) -> {first,[record_name(Name)],field_types(Fields)}. @@ -370,9 +363,6 @@ typed(B, Type) -> {_L,_P,R} = type_inop_prec('::'), {list,[{cstep,[B,' ::'],ltype(Type, R)}]}. -union_elem(T, Prec) -> - [leaf(" | "),ltype(T, Prec)]. - tuple_type(Ts, F) -> {seq,${,$},[$,],ltypes(Ts, F, 0)}. @@ -399,6 +389,9 @@ guard_type(Before, Gs) -> Gl = {list,[{step,'when',expr_list(Gs, [$,], fun constraint/2, Opts)}]}, {list,[{step,Before,Gl}]}. +constraint({type,_Line,constraint,[{atom,_,is_subtype},[{var,_,_}=V,Type]]}, + _Opts) -> + typed(lexpr(V, options(none)), Type); constraint({type,_Line,constraint,[Tag,As]}, _Opts) -> simple_type(Tag, As). diff --git a/lib/stdlib/src/error_logger_file_h.erl b/lib/stdlib/src/error_logger_file_h.erl index a7f3615972..fea1656051 100644 --- a/lib/stdlib/src/error_logger_file_h.erl +++ b/lib/stdlib/src/error_logger_file_h.erl @@ -24,24 +24,28 @@ %%% %%% A handler that can be connected to the error_logger -%%% event handler. -%%% Writes all events formatted to file. -%%% Handles events tagged error, emulator and info. +%%% event handler. Writes all events formatted to file. %%% %%% It can only be started from error_logger:swap_handler({logfile, File}) -%%% or error_logger:logfile(File) +%%% or error_logger:logfile(File). %%% -export([init/1, handle_event/2, handle_call/2, handle_info/2, terminate/2, code_change/3]). +-record(st, + {fd, + filename, + prev_handler, + depth=unlimited :: 'unlimited' | non_neg_integer()}). + %% This one is used when we takeover from the simple error_logger. init({File, {error_logger, Buf}}) -> case init(File, error_logger) of - {ok, {Fd, File, PrevHandler}} -> - write_events(Fd, Buf), - {ok, {Fd, File, PrevHandler}}; + {ok, State} -> + write_events(State, Buf), + {ok, State}; Error -> Error end; @@ -53,49 +57,45 @@ init(File, PrevHandler) -> process_flag(trap_exit, true), case file:open(File, [write]) of {ok,Fd} -> - {ok, {Fd, File, PrevHandler}}; + Depth = get_depth(), + State = #st{fd=Fd,filename=File,prev_handler=PrevHandler, + depth=Depth}, + {ok, State}; Error -> Error end. - + +get_depth() -> + case application:get_env(kernel, error_logger_format_depth) of + {ok, Depth} when is_integer(Depth) -> + max(10, Depth); + undefined -> + unlimited + end. + handle_event({_Type, GL, _Msg}, State) when node(GL) =/= node() -> {ok, State}; -handle_event(Event, {Fd, File, PrevHandler}) -> - write_event(Fd, tag_event(Event)), - {ok, {Fd, File, PrevHandler}}; -handle_event(_, State) -> +handle_event(Event, State) -> + write_event(State, Event), {ok, State}. -handle_info({'EXIT', Fd, _Reason}, {Fd, _File, PrevHandler}) -> +handle_info({'EXIT', Fd, _Reason}, #st{fd=Fd,prev_handler=PrevHandler}) -> case PrevHandler of [] -> remove_handler; _ -> {swap_handler, install_prev, [], PrevHandler, go_back} end; -handle_info({emulator, GL, Chars}, {Fd, File, PrevHandler}) - when node(GL) == node() -> - write_event(Fd, tag_event({emulator, GL, Chars})), - {ok, {Fd, File, PrevHandler}}; -handle_info({emulator, noproc, Chars}, {Fd, File, PrevHandler}) -> - write_event(Fd, tag_event({emulator, noproc, Chars})), - {ok, {Fd, File, PrevHandler}}; handle_info(_, State) -> {ok, State}. -handle_call(filename, {Fd, File, Prev}) -> - {ok, File, {Fd, File, Prev}}; +handle_call(filename, #st{filename=File}=State) -> + {ok, File, State}; handle_call(_Query, State) -> {ok, {error, bad_query}, State}. -terminate(_Reason, State) -> - case State of - {Fd, _File, _Prev} -> - ok = file:close(Fd); - _ -> - ok - end, - []. +terminate(_Reason, #st{fd=Fd}) -> + file:close(Fd). code_change(_OldVsn, State, _Extra) -> {ok, State}. @@ -104,69 +104,73 @@ code_change(_OldVsn, State, _Extra) -> %%% Misc. functions. %%% ------------------------------------------------------ -tag_event(Event) -> - {erlang:universaltime(), Event}. +write_events(State, [Ev|Es]) -> + %% Write the events in reversed order. + write_events(State, Es), + write_event(State, Ev); +write_events(_State, []) -> + ok. -write_events(Fd, Events) -> write_events1(Fd, lists:reverse(Events)). +write_event(#st{fd=Fd}=State, Event) -> + case parse_event(Event) of + ignore -> + ok; + {Head,Pid,FormatList} -> + Time = maybe_utc(erlang:universaltime()), + Header = write_time(Time, Head), + Body = format_body(State, FormatList), + AtNode = if + node(Pid) =/= node() -> + ["** at node ",atom_to_list(node(Pid))," **\n"]; + true -> + [] + end, + io:put_chars(Fd, [Header,Body,AtNode]) + end. -write_events1(Fd, [Event|Es]) -> - write_event(Fd, Event), - write_events1(Fd, Es); -write_events1(_, []) -> - ok. +format_body(State, [{Format,Args}|T]) -> + S = try format(State, Format, Args) of + S0 -> + S0 + catch + _:_ -> + format(State, "ERROR: ~p - ~p\n", [Format,Args]) + end, + [S|format_body(State, T)]; +format_body(_State, []) -> + []. -write_event(Fd, {Time, {error, _GL, {Pid, Format, Args}}}) -> - T = write_time(maybe_utc(Time)), - case catch io_lib:format(add_node(Format,Pid), Args) of - S when is_list(S) -> - io:format(Fd, T ++ S, []); - _ -> - F = add_node("ERROR: ~p - ~p~n", Pid), - io:format(Fd, T ++ F, [Format,Args]) - end; -write_event(Fd, {Time, {emulator, _GL, Chars}}) -> - T = write_time(maybe_utc(Time)), - case catch io_lib:format(Chars, []) of - S when is_list(S) -> - io:format(Fd, T ++ S, []); - _ -> - io:format(Fd, T ++ "ERROR: ~p ~n", [Chars]) - end; -write_event(Fd, {Time, {info, _GL, {Pid, Info, _}}}) -> - T = write_time(maybe_utc(Time)), - io:format(Fd, T ++ add_node("~p~n",Pid),[Info]); -write_event(Fd, {Time, {error_report, _GL, {Pid, std_error, Rep}}}) -> - T = write_time(maybe_utc(Time)), - S = format_report(Rep), - io:format(Fd, T ++ S ++ add_node("", Pid), []); -write_event(Fd, {Time, {info_report, _GL, {Pid, std_info, Rep}}}) -> - T = write_time(maybe_utc(Time), "INFO REPORT"), - S = format_report(Rep), - io:format(Fd, T ++ S ++ add_node("", Pid), []); -write_event(Fd, {Time, {info_msg, _GL, {Pid, Format, Args}}}) -> - T = write_time(maybe_utc(Time), "INFO REPORT"), - case catch io_lib:format(add_node(Format,Pid), Args) of - S when is_list(S) -> - io:format(Fd, T ++ S, []); - _ -> - F = add_node("ERROR: ~p - ~p~n", Pid), - io:format(Fd, T ++ F, [Format,Args]) - end; -write_event(Fd, {Time, {warning_report, _GL, {Pid, std_warning, Rep}}}) -> - T = write_time(maybe_utc(Time), "WARNING REPORT"), - S = format_report(Rep), - io:format(Fd, T ++ S ++ add_node("", Pid), []); -write_event(Fd, {Time, {warning_msg, _GL, {Pid, Format, Args}}}) -> - T = write_time(maybe_utc(Time), "WARNING REPORT"), - case catch io_lib:format(add_node(Format,Pid), Args) of - S when is_list(S) -> - io:format(Fd, T ++ S, []); - _ -> - F = add_node("ERROR: ~p - ~p~n", Pid), - io:format(Fd, T ++ F, [Format,Args]) - end; -write_event(_, _) -> - ok. +format(#st{depth=unlimited}, Format, Args) -> + io_lib:format(Format, Args); +format(#st{depth=Depth}, Format0, Args) -> + Format1 = io_lib:scan_format(Format0, Args), + Format = limit_format(Format1, Depth), + io_lib:build_text(Format). + +limit_format([#{control_char:=C0}=M0|T], Depth) when C0 =:= $p; + C0 =:= $w -> + C = C0 - ($a - $A), %To uppercase. + #{args:=Args} = M0, + M = M0#{control_char:=C,args:=Args++[Depth]}, + [M|limit_format(T, Depth)]; +limit_format([H|T], Depth) -> + [H|limit_format(T, Depth)]; +limit_format([], _) -> + []. + +parse_event({error, _GL, {Pid, Format, Args}}) -> + {"ERROR REPORT",Pid,[{Format,Args}]}; +parse_event({info_msg, _GL, {Pid, Format, Args}}) -> + {"INFO REPORT",Pid,[{Format, Args}]}; +parse_event({warning_msg, _GL, {Pid, Format, Args}}) -> + {"WARNING REPORT",Pid,[{Format,Args}]}; +parse_event({error_report, _GL, {Pid, std_error, Args}}) -> + {"ERROR REPORT",Pid,format_term(Args)}; +parse_event({info_report, _GL, {Pid, std_info, Args}}) -> + {"INFO REPORT",Pid,format_term(Args)}; +parse_event({warning_report, _GL, {Pid, std_warning, Args}}) -> + {"WARNING REPORT",Pid,format_term(Args)}; +parse_event(_) -> ignore. maybe_utc(Time) -> UTC = case application:get_env(sasl, utc_log) of @@ -183,30 +187,27 @@ maybe_utc(Time) -> maybe_utc(Time, true) -> {utc, Time}; maybe_utc(Time, _) -> {local, calendar:universal_time_to_local_time(Time)}. -format_report(Rep) when is_list(Rep) -> - case string_p(Rep) of +format_term(Term) when is_list(Term) -> + case string_p(Term) of true -> - io_lib:format("~s~n",[Rep]); - _ -> - format_rep(Rep) + [{"~s\n",[Term]}]; + false -> + format_term_list(Term) end; -format_report(Rep) -> - io_lib:format("~p~n",[Rep]). +format_term(Term) -> + [{"~p\n",[Term]}]. -format_rep([{Tag,Data}|Rep]) -> - io_lib:format(" ~p: ~p~n",[Tag,Data]) ++ format_rep(Rep); -format_rep([Other|Rep]) -> - io_lib:format(" ~p~n",[Other]) ++ format_rep(Rep); -format_rep(_) -> +format_term_list([{Tag,Data}|T]) -> + [{" ~p: ~p\n",[Tag,Data]}|format_term_list(T)]; +format_term_list([Data|T]) -> + [{" ~p\n",[Data]}|format_term_list(T)]; +format_term_list([]) -> + []; +format_term_list(_) -> + %% Continue to allow non-proper lists for now. + %% FIXME: Remove this clause in OTP 19. []. -add_node(X, Pid) when is_atom(X) -> - add_node(atom_to_list(X), Pid); -add_node(X, Pid) when node(Pid) =/= node() -> - lists:concat([X,"** at node ",node(Pid)," **~n"]); -add_node(X, _) -> - X. - string_p([]) -> false; string_p(Term) -> @@ -222,15 +223,10 @@ string_p1([$\b|T]) -> string_p1(T); string_p1([$\f|T]) -> string_p1(T); string_p1([$\e|T]) -> string_p1(T); string_p1([H|T]) when is_list(H) -> - case string_p1(H) of - true -> string_p1(T); - _ -> false - end; + string_p1(H) andalso string_p1(T); string_p1([]) -> true; string_p1(_) -> false. -write_time(Time) -> write_time(Time, "ERROR REPORT"). - write_time({utc,{{Y,Mo,D},{H,Mi,S}}}, Type) -> io_lib:format("~n=~s==== ~p-~s-~p::~s:~s:~s UTC ===~n", [Type,D,month(Mo),Y,t(H),t(Mi),t(S)]); diff --git a/lib/stdlib/src/error_logger_tty_h.erl b/lib/stdlib/src/error_logger_tty_h.erl index 65ea645bd9..d2df6681e3 100644 --- a/lib/stdlib/src/error_logger_tty_h.erl +++ b/lib/stdlib/src/error_logger_tty_h.erl @@ -23,145 +23,180 @@ %%% %%% A handler that can be connected to the error_logger -%%% event handler. -%%% Writes all events formatted to stdout. -%%% Handles events tagged error, emulator and info. +%%% event handler. Writes all events formatted to stdout. %%% %%% It can only be started from error_logger:swap_handler(tty) -%%% or error_logger:tty(true) +%%% or error_logger:tty(true). %%% -export([init/1, handle_event/2, handle_call/2, handle_info/2, terminate/2, code_change/3]). --export([write_event/2]). +-export([write_event/2,write_event/3]). + +-record(st, + {user, + prev_handler, + io_mod=io, + depth=unlimited}). %% This one is used when we takeover from the simple error_logger. init({[], {error_logger, Buf}}) -> User = set_group_leader(), - write_events(Buf,io), - {ok, {User, error_logger}}; + Depth = get_depth(), + State = #st{user=User,prev_handler=error_logger,depth=Depth}, + write_events(State, Buf), + {ok, State}; %% This one is used if someone took over from us, and now wants to %% go back. init({[], {error_logger_tty_h, PrevHandler}}) -> User = set_group_leader(), - {ok, {User, PrevHandler}}; + {ok, #st{user=User,prev_handler=PrevHandler}}; %% This one is used when we are started directly. init([]) -> User = set_group_leader(), - {ok, {User, []}}. + Depth = get_depth(), + {ok, #st{user=User,prev_handler=[],depth=Depth}}. + +get_depth() -> + case application:get_env(kernel, error_logger_format_depth) of + {ok, Depth} when is_integer(Depth) -> + max(10, Depth); + undefined -> + unlimited + end. handle_event({_Type, GL, _Msg}, State) when node(GL) =/= node() -> {ok, State}; handle_event(Event, State) -> - ok = write_event(tag_event(Event),io), + ok = do_write_event(State, tag_event(Event)), {ok, State}. -handle_info({'EXIT', User, _Reason}, {User, PrevHandler}) -> +handle_info({'EXIT', User, _Reason}, + #st{user=User,prev_handler=PrevHandler}=State) -> case PrevHandler of [] -> remove_handler; _ -> - {swap_handler, install_prev, {User, PrevHandler}, + {swap_handler, install_prev, State, PrevHandler, go_back} end; -handle_info({emulator, GL, Chars}, State) when node(GL) == node() -> - ok = write_event(tag_event({emulator, GL, Chars}),io), - {ok, State}; -handle_info({emulator, noproc, Chars}, State) -> - ok = write_event(tag_event({emulator, noproc, Chars}),io), - {ok, State}; handle_info(_, State) -> {ok, State}. handle_call(_Query, State) -> {ok, {error, bad_query}, State}. -% unfortunately, we can't unlink from User - links are not counted! -% if pid(User) -> unlink(User); true -> ok end, terminate(install_prev, _State) -> []; -terminate(_Reason, {_User, PrevHandler}) -> +terminate(_Reason, #st{prev_handler=PrevHandler}) -> {error_logger_tty_h, PrevHandler}. code_change(_OldVsn, State, _Extra) -> {ok, State}. +%% Exported (but unoffical) API. +write_event(Event, IoMod) -> + do_write_event(#st{io_mod=IoMod}, Event). + +write_event(Event, IoMod, Depth) -> + do_write_event(#st{io_mod=IoMod,depth=Depth}, Event). + + %%% ------------------------------------------------------ %%% Misc. functions. %%% ------------------------------------------------------ set_group_leader() -> case whereis(user) of - User when is_pid(User) -> link(User), group_leader(User,self()), User; - _ -> false + User when is_pid(User) -> + link(User), + group_leader(User,self()), + User; + _ -> + false end. tag_event(Event) -> {erlang:universaltime(), Event}. -%% IOMOd is always 'io' -write_events(Events,IOMod) -> write_events1(lists:reverse(Events),IOMod). - -write_events1([Event|Es],IOMod) -> - ok = write_event(Event,IOMod), - write_events1(Es,IOMod); -write_events1([],_IOMod) -> +write_events(State, [Ev|Es]) -> + %% Write the events in reverse order. + _ = write_events(State, Es), + _ = do_write_event(State, Ev), + ok; +write_events(_State, []) -> ok. -write_event({Time, {error, _GL, {Pid, Format, Args}}},IOMod) -> - T = write_time(maybe_utc(Time)), - case catch io_lib:format(add_node(Format,Pid), Args) of - S when is_list(S) -> - format(IOMod, T ++ S); - _ -> - F = add_node("ERROR: ~p - ~p~n", Pid), - format(IOMod, T ++ F, [Format,Args]) +do_write_event(State, {Time0, Event}) -> + case parse_event(Event) of + ignore -> + ok; + {Head,Pid,FormatList} -> + Time = maybe_utc(Time0), + Header = write_time(Time, Head), + Body = format_body(State, FormatList), + AtNode = if + node(Pid) =/= node() -> + ["** at node ",atom_to_list(node(Pid))," **\n"]; + true -> + [] + end, + Str = [Header,Body,AtNode], + case State#st.io_mod of + io_lib -> + Str; + io -> + io:put_chars(user, Str) + end end; -write_event({Time, {emulator, _GL, Chars}},IOMod) -> - T = write_time(maybe_utc(Time)), - case catch io_lib:format(Chars, []) of - S when is_list(S) -> - format(IOMod, T ++ S); - _ -> - format(IOMod, T ++ "ERROR: ~p ~n", [Chars]) - end; -write_event({Time, {info, _GL, {Pid, Info, _}}},IOMod) -> - T = write_time(maybe_utc(Time)), - format(IOMod, T ++ add_node("~p~n",Pid),[Info]); -write_event({Time, {error_report, _GL, {Pid, std_error, Rep}}},IOMod) -> - T = write_time(maybe_utc(Time)), - S = format_report(Rep), - format(IOMod, T ++ S ++ add_node("", Pid)); -write_event({Time, {info_report, _GL, {Pid, std_info, Rep}}},IOMod) -> - T = write_time(maybe_utc(Time), "INFO REPORT"), - S = format_report(Rep), - format(IOMod, T ++ S ++ add_node("", Pid)); -write_event({Time, {info_msg, _GL, {Pid, Format, Args}}},IOMod) -> - T = write_time(maybe_utc(Time), "INFO REPORT"), - case catch io_lib:format(add_node(Format,Pid), Args) of - S when is_list(S) -> - format(IOMod, T ++ S); - _ -> - F = add_node("ERROR: ~p - ~p~n", Pid), - format(IOMod, T ++ F, [Format,Args]) - end; -write_event({Time, {warning_report, _GL, {Pid, std_warning, Rep}}},IOMod) -> - T = write_time(maybe_utc(Time), "WARNING REPORT"), - S = format_report(Rep), - format(IOMod, T ++ S ++ add_node("", Pid)); -write_event({Time, {warning_msg, _GL, {Pid, Format, Args}}},IOMod) -> - T = write_time(maybe_utc(Time), "WARNING REPORT"), - case catch io_lib:format(add_node(Format,Pid), Args) of - S when is_list(S) -> - format(IOMod, T ++ S); - _ -> - F = add_node("ERROR: ~p - ~p~n", Pid), - format(IOMod, T ++ F, [Format,Args]) - end; -write_event({_Time, _Error},_IOMod) -> +do_write_event(_, _) -> ok. +format_body(State, [{Format,Args}|T]) -> + S = try format(State, Format, Args) of + S0 -> + S0 + catch + _:_ -> + format(State, "ERROR: ~p - ~p\n", [Format,Args]) + end, + [S|format_body(State, T)]; +format_body(_State, []) -> + []. + +format(#st{depth=unlimited}, Format, Args) -> + io_lib:format(Format, Args); +format(#st{depth=Depth}, Format0, Args) -> + Format1 = io_lib:scan_format(Format0, Args), + Format = limit_format(Format1, Depth), + io_lib:build_text(Format). + +limit_format([#{control_char:=C0}=M0|T], Depth) when C0 =:= $p; + C0 =:= $w -> + C = C0 - ($a - $A), %To uppercase. + #{args:=Args} = M0, + M = M0#{control_char:=C,args:=Args++[Depth]}, + [M|limit_format(T, Depth)]; +limit_format([H|T], Depth) -> + [H|limit_format(T, Depth)]; +limit_format([], _) -> + []. + +parse_event({error, _GL, {Pid, Format, Args}}) -> + {"ERROR REPORT",Pid,[{Format,Args}]}; +parse_event({info_msg, _GL, {Pid, Format, Args}}) -> + {"INFO REPORT",Pid,[{Format, Args}]}; +parse_event({warning_msg, _GL, {Pid, Format, Args}}) -> + {"WARNING REPORT",Pid,[{Format,Args}]}; +parse_event({error_report, _GL, {Pid, std_error, Args}}) -> + {"ERROR REPORT",Pid,format_term(Args)}; +parse_event({info_report, _GL, {Pid, std_info, Args}}) -> + {"INFO REPORT",Pid,format_term(Args)}; +parse_event({warning_report, _GL, {Pid, std_warning, Args}}) -> + {"WARNING REPORT",Pid,format_term(Args)}; +parse_event(_) -> ignore. + maybe_utc(Time) -> UTC = case application:get_env(sasl, utc_log) of {ok, Val} -> Val; @@ -177,33 +212,26 @@ maybe_utc(Time) -> maybe_utc(Time, true) -> {utc, Time}; maybe_utc(Time, _) -> {local, calendar:universal_time_to_local_time(Time)}. -format(IOMod, String) -> format(IOMod, String, []). -format(io_lib, String, Args) -> io_lib:format(String, Args); -format(io, String, Args) -> io:format(user, String, Args). - -format_report(Rep) when is_list(Rep) -> - case string_p(Rep) of +format_term(Term) when is_list(Term) -> + case string_p(Term) of true -> - io_lib:format("~s~n",[Rep]); - _ -> - format_rep(Rep) + [{"~s\n",[Term]}]; + false -> + format_term_list(Term) end; -format_report(Rep) -> - io_lib:format("~p~n",[Rep]). - -format_rep([{Tag,Data}|Rep]) -> - io_lib:format(" ~p: ~p~n",[Tag,Data]) ++ format_rep(Rep); -format_rep([Other|Rep]) -> - io_lib:format(" ~p~n",[Other]) ++ format_rep(Rep); -format_rep(_) -> - []. +format_term(Term) -> + [{"~p\n",[Term]}]. -add_node(X, Pid) when is_atom(X) -> - add_node(atom_to_list(X), Pid); -add_node(X, Pid) when node(Pid) =/= node() -> - lists:concat([X,"** at node ",node(Pid)," **~n"]); -add_node(X, _) -> - X. +format_term_list([{Tag,Data}|T]) -> + [{" ~p: ~p\n",[Tag,Data]}|format_term_list(T)]; +format_term_list([Data|T]) -> + [{" ~p\n",[Data]}|format_term_list(T)]; +format_term_list([]) -> + []; +format_term_list(_) -> + %% Continue to allow non-proper lists for now. + %% FIXME: Remove this clause in OTP 19. + []. string_p([]) -> false; @@ -227,7 +255,6 @@ string_p1([H|T]) when is_list(H) -> string_p1([]) -> true; string_p1(_) -> false. -write_time(Time) -> write_time(Time, "ERROR REPORT"). write_time({utc,{{Y,Mo,D},{H,Mi,S}}},Type) -> io_lib:format("~n=~s==== ~p-~s-~p::~s:~s:~s UTC ===~n", [Type,D,month(Mo),Y,t(H),t(Mi),t(S)]); diff --git a/lib/stdlib/src/ets.erl b/lib/stdlib/src/ets.erl index 847def2fd8..1fca3624dc 100644 --- a/lib/stdlib/src/ets.erl +++ b/lib/stdlib/src/ets.erl @@ -146,7 +146,7 @@ info(_) -> Tab :: tab(), Item :: compressed | fixed | heir | keypos | memory | name | named_table | node | owner | protection - | safe_fixed | size | stats | type + | safe_fixed | safe_fixed_monotonic_time | size | stats | type | write_concurrency | read_concurrency, Value :: term(). diff --git a/lib/stdlib/src/file_sorter.erl b/lib/stdlib/src/file_sorter.erl index 47adb133b0..0d50392b96 100644 --- a/lib/stdlib/src/file_sorter.erl +++ b/lib/stdlib/src/file_sorter.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2013. All Rights Reserved. +%% Copyright Ericsson AB 2001-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -28,6 +28,8 @@ check/1, check/2, keycheck/2, keycheck/3]). +-dialyzer(no_improper_lists). + -include_lib("kernel/include/file.hrl"). -define(CHUNKSIZE, 16384). diff --git a/lib/stdlib/src/lists.erl b/lib/stdlib/src/lists.erl index 62b6ca8a21..2b4472cdf7 100644 --- a/lib/stdlib/src/lists.erl +++ b/lib/stdlib/src/lists.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -2267,6 +2267,8 @@ ukeysplit_2(I, Y, EY, [Z | L], R) -> ukeysplit_2(_I, Y, _EY, [], R) -> [Y | R]. +-dialyzer({no_improper_lists, ukeymergel/3}). + ukeymergel(I, [T1, [H2 | T2], [H3 | T3] | L], Acc) -> %% The fourth argument, [H2 | H3] (=HdM), may confuse type %% checkers. Its purpose is to ensure that the tests H2 == HdM diff --git a/lib/stdlib/src/maps.erl b/lib/stdlib/src/maps.erl index 3c798b7a04..43d10f4800 100644 --- a/lib/stdlib/src/maps.erl +++ b/lib/stdlib/src/maps.erl @@ -205,7 +205,7 @@ size(Val) -> K :: term(). without(Ks,M) when is_list(Ks), is_map(M) -> - maps:from_list([{K,V}||{K,V} <- maps:to_list(M), not lists:member(K, Ks)]); + lists:foldl(fun(K, M1) -> ?MODULE:remove(K, M1) end, M, Ks); without(Ks,M) -> erlang:error(error_type(M),[Ks,M]). @@ -216,8 +216,16 @@ without(Ks,M) -> Map2 :: map(), K :: term(). -with(Ks,M) when is_list(Ks), is_map(M) -> - maps:from_list([{K,V}||{K,V} <- maps:to_list(M), lists:member(K, Ks)]); +with(Ks,Map1) when is_list(Ks), is_map(Map1) -> + Fun = fun(K, List) -> + case ?MODULE:find(K, Map1) of + {ok, V} -> + [{K, V} | List]; + error -> + List + end + end, + ?MODULE:from_list(lists:foldl(Fun, [], Ks)); with(Ks,M) -> erlang:error(error_type(M),[Ks,M]). diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl index 2d77888512..9d394e19d7 100644 --- a/lib/stdlib/src/otp_internal.erl +++ b/lib/stdlib/src/otp_internal.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2015. All Rights Reserved. +%% Copyright Ericsson AB 1999-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -23,6 +23,8 @@ %%---------------------------------------------------------------------- +-dialyzer({no_match, obsolete/3}). + -type tag() :: 'deprecated' | 'removed'. %% | 'experimental'. -type mfas() :: mfa() | {atom(), atom(), [byte()]}. -type release() :: string(). @@ -648,6 +650,9 @@ obsolete_1(httpd_conf, is_file, 1) -> obsolete_1(httpd_conf, make_integer, 1) -> {deprecated, "deprecated; use erlang:list_to_integer/1 instead"}; +obsolete_1(overload, _, _) -> + {deprecated, "deprecated; will be removed in OTP 19"}; + obsolete_1(_, _, _) -> no. @@ -695,17 +700,19 @@ is_snmp_agent_function(del_agent_caps, 1) -> true; is_snmp_agent_function(get_agent_caps, 0) -> true; is_snmp_agent_function(_, _) -> false. +-dialyzer({no_match, obsolete_type/3}). + -spec obsolete_type(module(), atom(), arity()) -> 'no' | {tag(), string()} | {tag(), mfas(), release()}. obsolete_type(Module, Name, NumberOfVariables) -> case obsolete_type_1(Module, Name, NumberOfVariables) of -%% {deprecated=Tag,{_,_,_}=Replacement} -> -%% {Tag,Replacement,"in a future release"}; + {deprecated=Tag,{_,_,_}=Replacement} -> + {Tag,Replacement,"in a future release"}; {_,String}=Ret when is_list(String) -> Ret; -%% {_,_,_}=Ret -> -%% Ret; + {_,_,_}=Ret -> + Ret; no -> no end. diff --git a/lib/stdlib/src/proc_lib.erl b/lib/stdlib/src/proc_lib.erl index bbf4f573f5..10c476a6f5 100644 --- a/lib/stdlib/src/proc_lib.erl +++ b/lib/stdlib/src/proc_lib.erl @@ -30,7 +30,8 @@ start/3, start/4, start/5, start_link/3, start_link/4, start_link/5, hibernate/3, init_ack/1, init_ack/2, - init_p/3,init_p/5,format/1,format/2,initial_call/1, + init_p/3,init_p/5,format/1,format/2,format/3, + initial_call/1, translate_initial_call/1, stop/1, stop/3]). @@ -700,53 +701,71 @@ format(CrashReport) -> CrashReport :: [term()], Encoding :: latin1 | unicode | utf8. -format([OwnReport,LinkReport], Encoding) -> - OwnFormat = format_report(OwnReport, Encoding), - LinkFormat = format_report(LinkReport, Encoding), +format(CrashReport, Encoding) -> + format(CrashReport, Encoding, unlimited). + +-spec format(CrashReport, Encoding, Depth) -> string() when + CrashReport :: [term()], + Encoding :: latin1 | unicode | utf8, + Depth :: unlimited | pos_integer(). + +format([OwnReport,LinkReport], Encoding, Depth) -> + Extra = {Encoding,Depth}, + OwnFormat = format_report(OwnReport, Extra), + LinkFormat = format_report(LinkReport, Extra), Str = io_lib:format(" crasher:~n~ts neighbours:~n~ts", [OwnFormat, LinkFormat]), lists:flatten(Str). -format_report(Rep, Enc) when is_list(Rep) -> - format_rep(Rep,Enc); -format_report(Rep, Enc) -> +format_report(Rep, Extra) when is_list(Rep) -> + format_rep(Rep, Extra); +format_report(Rep, {Enc,_}) -> io_lib:format("~"++modifier(Enc)++"p~n", [Rep]). -format_rep([{initial_call,InitialCall}|Rep], Enc) -> - [format_mfa(InitialCall)|format_rep(Rep, Enc)]; -format_rep([{error_info,{Class,Reason,StackTrace}}|Rep], Enc) -> - [format_exception(Class, Reason, StackTrace, Enc)|format_rep(Rep, Enc)]; -format_rep([{Tag,Data}|Rep], Enc) -> - [format_tag(Tag, Data)|format_rep(Rep, Enc)]; -format_rep(_, _Enc) -> +format_rep([{initial_call,InitialCall}|Rep], {_Enc,Depth}=Extra) -> + [format_mfa(InitialCall, Depth)|format_rep(Rep, Extra)]; +format_rep([{error_info,{Class,Reason,StackTrace}}|Rep], Extra) -> + [format_exception(Class, Reason, StackTrace, Extra)|format_rep(Rep, Extra)]; +format_rep([{Tag,Data}|Rep], Extra) -> + [format_tag(Tag, Data, Extra)|format_rep(Rep, Extra)]; +format_rep(_, _Extra) -> []. -format_exception(Class, Reason, StackTrace, Enc) -> - PF = pp_fun(Enc), +format_exception(Class, Reason, StackTrace, {Enc,_}=Extra) -> + PF = pp_fun(Extra), StackFun = fun(M, _F, _A) -> (M =:= erl_eval) or (M =:= ?MODULE) end, %% EI = " exception: ", EI = " ", [EI, lib:format_exception(1+length(EI), Class, Reason, StackTrace, StackFun, PF, Enc), "\n"]. -format_mfa({M,F,Args}=StartF) -> +format_mfa({M,F,Args}=StartF, Depth) -> try A = length(Args), [" initial call: ",atom_to_list(M),$:,atom_to_list(F),$/, integer_to_list(A),"\n"] catch error:_ -> - format_tag(initial_call, StartF) + format_tag(initial_call, StartF, Depth) end. -pp_fun(Enc) -> - P = modifier(Enc) ++ "p", +pp_fun({Enc,Depth}) -> + {Letter,Tl} = case Depth of + unlimited -> {"p",[]}; + _ -> {"P",[Depth]} + end, + P = modifier(Enc) ++ Letter, fun(Term, I) -> - io_lib:format("~." ++ integer_to_list(I) ++ P, [Term]) + io_lib:format("~." ++ integer_to_list(I) ++ P, [Term|Tl]) end. -format_tag(Tag, Data) -> - io_lib:format(" ~p: ~80.18p~n", [Tag, Data]). +format_tag(Tag, Data, {_Enc,Depth}) -> + case Depth of + unlimited -> + io_lib:format(" ~p: ~80.18p~n", [Tag, Data]); + _ -> + io_lib:format(" ~p: ~80.18P~n", [Tag, Data, Depth]) + end. modifier(latin1) -> ""; modifier(_) -> "t". diff --git a/lib/stdlib/src/qlc.erl b/lib/stdlib/src/qlc.erl index 3ba3a88038..1ae7c6cc25 100644 --- a/lib/stdlib/src/qlc.erl +++ b/lib/stdlib/src/qlc.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2015. All Rights Reserved. +%% Copyright Ericsson AB 2004-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -51,6 +51,8 @@ -export([template_state/0, aux_name/3, name_suffix/2, vars/1, var_ufold/2, var_fold/3, all_selections/1]). +-dialyzer(no_improper_lists). + %% When cache=list lists bigger than ?MAX_LIST_SIZE bytes are put on %% file. Also used when merge join finds big equivalence classes. -define(MAX_LIST_SIZE, 512*1024). diff --git a/lib/stdlib/src/qlc_pt.erl b/lib/stdlib/src/qlc_pt.erl index 4e81e2c2dd..9577d17a85 100644 --- a/lib/stdlib/src/qlc_pt.erl +++ b/lib/stdlib/src/qlc_pt.erl @@ -428,7 +428,13 @@ compile_errors(FormsNoShadows) -> end. compile_forms(Forms0, Options) -> - Forms = [F || F <- Forms0, element(1, F) =/= eof] ++ [{eof,anno0()}], + Exclude = fun(eof) -> true; + (warning) -> true; + (error) -> true; + (_) -> false + end, + Forms = ([F || F <- Forms0, not Exclude(element(1, F))] + ++ [{eof,anno0()}]), try case compile:noenv_forms(Forms, compile_options(Options)) of {ok, _ModName, Ws0} -> diff --git a/lib/stdlib/src/rand.erl b/lib/stdlib/src/rand.erl index 8e8d0bc801..d455abf7b0 100644 --- a/lib/stdlib/src/rand.erl +++ b/lib/stdlib/src/rand.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2015. All Rights Reserved. +%% Copyright Ericsson AB 2015-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -63,7 +63,7 @@ %% Return algorithm and seed so that RNG state can be recreated with seed/1 -spec export_seed() -> undefined | export_state(). export_seed() -> - case seed_get() of + case get(?SEED_DICT) of {#{type:=Alg}, Seed} -> {Alg, Seed}; _ -> undefined end. @@ -256,6 +256,8 @@ exs64_uniform(Max, {Alg, R}) -> %% ===================================================================== -type exsplus_state() :: nonempty_improper_list(uint58(), uint58()). +-dialyzer({no_improper_lists, exsplus_seed/1}). + exsplus_seed({A1, A2, A3}) -> {_, R1} = exsplus_next([(((A1 * 4294967197) + 1) band ?UINT58MASK)| (((A2 * 4294967231) + 1) band ?UINT58MASK)]), @@ -263,6 +265,8 @@ exsplus_seed({A1, A2, A3}) -> tl(R1)]), R2. +-dialyzer({no_improper_lists, exsplus_next/1}). + %% Advance xorshift116+ state for one step and generate 58bit unsigned integer -spec exsplus_next(exsplus_state()) -> {uint58(), exsplus_state()}. exsplus_next([S1|S0]) -> diff --git a/lib/stdlib/src/re.erl b/lib/stdlib/src/re.erl index e5d9fc51d2..80bfe38970 100644 --- a/lib/stdlib/src/re.erl +++ b/lib/stdlib/src/re.erl @@ -132,8 +132,9 @@ split(Subject,RE) -> split(Subject,RE,Options) -> try - {NewOpt,Convert,Unicode,Limit,Strip,Group} = - process_split_params(Options,iodata,false,-1,false,false), + {NewOpt,Convert,Limit,Strip,Group} = + process_split_params(Options,iodata,-1,false,false), + Unicode = check_for_unicode(RE, Options), FlatSubject = to_binary(Subject, Unicode), case compile_split(RE,NewOpt) of {error,_Err} -> @@ -324,8 +325,8 @@ replace(Subject,RE,Replacement) -> replace(Subject,RE,Replacement,Options) -> try - {NewOpt,Convert,Unicode} = - process_repl_params(Options,iodata,false), + {NewOpt,Convert} = process_repl_params(Options,iodata), + Unicode = check_for_unicode(RE, Options), FlatSubject = to_binary(Subject, Unicode), FlatReplacement = to_binary(Replacement, Unicode), IoList = do_replace(FlatSubject,Subject,RE,FlatReplacement,NewOpt), @@ -367,65 +368,59 @@ do_replace(FlatSubject,Subject,RE,Replacement,Options) -> apply_mlist(FlatSubject,Replacement,[Slist]) end. -process_repl_params([],Convert,Unicode) -> - {[],Convert,Unicode}; -process_repl_params([unicode|T],C,_U) -> - {NT,NC,NU} = process_repl_params(T,C,true), - {[unicode|NT],NC,NU}; -process_repl_params([report_errors|_],_,_) -> +process_repl_params([],Convert) -> + {[],Convert}; +process_repl_params([report_errors|_],_) -> throw(badopt); -process_repl_params([{capture,_,_}|_],_,_) -> +process_repl_params([{capture,_,_}|_],_) -> throw(badopt); -process_repl_params([{capture,_}|_],_,_) -> +process_repl_params([{capture,_}|_],_) -> throw(badopt); -process_repl_params([{return,iodata}|T],_C,U) -> - process_repl_params(T,iodata,U); -process_repl_params([{return,list}|T],_C,U) -> - process_repl_params(T,list,U); -process_repl_params([{return,binary}|T],_C,U) -> - process_repl_params(T,binary,U); -process_repl_params([{return,_}|_],_,_) -> +process_repl_params([{return,iodata}|T],_C) -> + process_repl_params(T,iodata); +process_repl_params([{return,list}|T],_C) -> + process_repl_params(T,list); +process_repl_params([{return,binary}|T],_C) -> + process_repl_params(T,binary); +process_repl_params([{return,_}|_],_) -> throw(badopt); -process_repl_params([H|T],C,U) -> - {NT,NC,NU} = process_repl_params(T,C,U), - {[H|NT],NC,NU}. - -process_split_params([],Convert,Unicode,Limit,Strip,Group) -> - {[],Convert,Unicode,Limit,Strip,Group}; -process_split_params([unicode|T],C,_U,L,S,G) -> - {NT,NC,NU,NL,NS,NG} = process_split_params(T,C,true,L,S,G), - {[unicode|NT],NC,NU,NL,NS,NG}; -process_split_params([trim|T],C,U,_L,_S,G) -> - process_split_params(T,C,U,-1,true,G); -process_split_params([{parts,0}|T],C,U,_L,_S,G) -> - process_split_params(T,C,U,-1,true,G); -process_split_params([{parts,N}|T],C,U,_L,_S,G) when is_integer(N), N >= 1 -> - process_split_params(T,C,U,N-1,false,G); -process_split_params([{parts,infinity}|T],C,U,_L,_S,G) -> - process_split_params(T,C,U,-1,false,G); -process_split_params([{parts,_}|_],_,_,_,_,_) -> +process_repl_params([H|T],C) -> + {NT,NC} = process_repl_params(T,C), + {[H|NT],NC}. + +process_split_params([],Convert,Limit,Strip,Group) -> + {[],Convert,Limit,Strip,Group}; +process_split_params([trim|T],C,_L,_S,G) -> + process_split_params(T,C,-1,true,G); +process_split_params([{parts,0}|T],C,_L,_S,G) -> + process_split_params(T,C,-1,true,G); +process_split_params([{parts,N}|T],C,_L,_S,G) when is_integer(N), N >= 1 -> + process_split_params(T,C,N-1,false,G); +process_split_params([{parts,infinity}|T],C,_L,_S,G) -> + process_split_params(T,C,-1,false,G); +process_split_params([{parts,_}|_],_,_,_,_) -> throw(badopt); -process_split_params([group|T],C,U,L,S,_G) -> - process_split_params(T,C,U,L,S,true); -process_split_params([global|_],_,_,_,_,_) -> +process_split_params([group|T],C,L,S,_G) -> + process_split_params(T,C,L,S,true); +process_split_params([global|_],_,_,_,_) -> throw(badopt); -process_split_params([report_errors|_],_,_,_,_,_) -> +process_split_params([report_errors|_],_,_,_,_) -> throw(badopt); -process_split_params([{capture,_,_}|_],_,_,_,_,_) -> +process_split_params([{capture,_,_}|_],_,_,_,_) -> throw(badopt); -process_split_params([{capture,_}|_],_,_,_,_,_) -> +process_split_params([{capture,_}|_],_,_,_,_) -> throw(badopt); -process_split_params([{return,iodata}|T],_C,U,L,S,G) -> - process_split_params(T,iodata,U,L,S,G); -process_split_params([{return,list}|T],_C,U,L,S,G) -> - process_split_params(T,list,U,L,S,G); -process_split_params([{return,binary}|T],_C,U,L,S,G) -> - process_split_params(T,binary,U,L,S,G); -process_split_params([{return,_}|_],_,_,_,_,_) -> +process_split_params([{return,iodata}|T],_C,L,S,G) -> + process_split_params(T,iodata,L,S,G); +process_split_params([{return,list}|T],_C,L,S,G) -> + process_split_params(T,list,L,S,G); +process_split_params([{return,binary}|T],_C,L,S,G) -> + process_split_params(T,binary,L,S,G); +process_split_params([{return,_}|_],_,_,_,_) -> throw(badopt); -process_split_params([H|T],C,U,L,S,G) -> - {NT,NC,NU,NL,NS,NG} = process_split_params(T,C,U,L,S,G), - {[H|NT],NC,NU,NL,NS,NG}. +process_split_params([H|T],C,L,S,G) -> + {NT,NC,NL,NS,NG} = process_split_params(T,C,L,S,G), + {[H|NT],NC,NL,NS,NG}. apply_mlist(Subject,Replacement,Mlist) -> do_mlist(Subject,Subject,0,precomp_repl(Replacement), Mlist). diff --git a/lib/stdlib/src/shell.erl b/lib/stdlib/src/shell.erl index c64123a207..ce1d9eb0ff 100644 --- a/lib/stdlib/src/shell.erl +++ b/lib/stdlib/src/shell.erl @@ -23,7 +23,7 @@ -export([whereis_evaluator/0, whereis_evaluator/1]). -export([start_restricted/1, stop_restricted/0]). -export([local_allowed/3, non_local_allowed/3]). --export([prompt_func/1, strings/1]). +-export([catch_exception/1, prompt_func/1, strings/1]). -define(LINEMAX, 30). -define(CHAR_MAX, 60). @@ -999,12 +999,7 @@ local_func(rl, [A], Bs0, _Shell, RT, Lf, Ef) -> {value,list_records(record_defs(RT, listify(Recs))),Bs}; local_func(rp, [A], Bs0, _Shell, RT, Lf, Ef) -> {[V],Bs} = expr_list([A], Bs0, Lf, Ef), - Cs = io_lib_pretty:print(V, ([{column, 1}, - {line_length, columns()}, - {depth, -1}, - {max_chars, ?CHAR_MAX}, - {record_print_fun, record_print_fun(RT)}] - ++ enc())), + Cs = pp(V, _Column=1, _Depth=-1, RT), io:requests([{put_chars, unicode, Cs}, nl]), {value,ok,Bs}; local_func(rr, [A], Bs0, _Shell, RT, Lf, Ef) -> @@ -1397,9 +1392,9 @@ get_history_and_results() -> {History, erlang:min(Results, History)}. pp(V, I, RT) -> - pp(V, I, RT, enc()). + pp(V, I, _Depth=?LINEMAX, RT). -pp(V, I, RT, Enc) -> +pp(V, I, D, RT) -> Strings = case application:get_env(stdlib, shell_strings) of {ok, false} -> @@ -1408,10 +1403,10 @@ pp(V, I, RT, Enc) -> true end, io_lib_pretty:print(V, ([{column, I}, {line_length, columns()}, - {depth, ?LINEMAX}, {max_chars, ?CHAR_MAX}, + {depth, D}, {max_chars, ?CHAR_MAX}, {strings, Strings}, {record_print_fun, record_print_fun(RT)}] - ++ Enc)). + ++ enc())). columns() -> case io:columns() of diff --git a/lib/stdlib/src/stdlib.app.src b/lib/stdlib/src/stdlib.app.src index 4400956943..b8a7973cf2 100644 --- a/lib/stdlib/src/stdlib.app.src +++ b/lib/stdlib/src/stdlib.app.src @@ -105,7 +105,7 @@ dets]}, {applications, [kernel]}, {env, []}, - {runtime_dependencies, ["sasl-2.4","kernel-4.0","erts-7.0","crypto-3.3", + {runtime_dependencies, ["sasl-2.6","kernel-4.1","erts-7.3","crypto-3.3", "compiler-5.0"]} ]}. diff --git a/lib/stdlib/src/stdlib.appup.src b/lib/stdlib/src/stdlib.appup.src index 828e1d9aa4..8a313591a7 100644 --- a/lib/stdlib/src/stdlib.appup.src +++ b/lib/stdlib/src/stdlib.appup.src @@ -18,7 +18,9 @@ %% %CopyrightEnd% {"%VSN%", %% Up from - max one major revision back - [{<<"2\\.[0-4](\\.[0-9]+)*">>,[restart_new_emulator]}], %% 17.0-17.5 + [{<<"2\\.[5-8](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.* + {<<"2\\.[0-4](\\.[0-9]+)*">>,[restart_new_emulator]}], % 17.0-17.5 %% Down to - max one major revision back - [{<<"2\\.[0-4](\\.[0-9]+)*">>,[restart_new_emulator]}] %% 17.0-17.5 + [{<<"2\\.[5-8](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.* + {<<"2\\.[0-4](\\.[0-9]+)*">>,[restart_new_emulator]}] % 17.0-17.5 }. diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl index 3c77501c0f..cecdebd0c8 100644 --- a/lib/stdlib/src/supervisor.erl +++ b/lib/stdlib/src/supervisor.erl @@ -33,6 +33,9 @@ terminate/2, code_change/3]). -export([try_again_restart/2]). +%% For release_handler only +-export([get_callback_module/1]). + %%-------------------------------------------------------------------------- -export_type([sup_flags/0, child_spec/0, startchild_ret/0, strategy/0]). @@ -113,6 +116,7 @@ intensity :: non_neg_integer(), period :: pos_integer(), restarts = [], + dynamic_restarts = 0 :: non_neg_integer(), module, args}). -type state() :: #state{}. @@ -250,6 +254,17 @@ try_again_restart(Supervisor, Child) -> cast(Supervisor, Req) -> gen_server:cast(Supervisor, Req). +%%%----------------------------------------------------------------- +%%% Called by release_handler during upgrade +-spec get_callback_module(Pid) -> Module when + Pid :: pid(), + Module :: atom(). +get_callback_module(Pid) -> + {status, _Pid, {module, _Mod}, + [_PDict, _SysState, _Parent, _Dbg, Misc]} = sys:get_status(Pid), + [_Header, _Data, {data, [{"State", State}]}] = Misc, + State#state.module. + %%% --------------------------------------------------- %%% %%% Initialize the supervisor. @@ -504,39 +519,26 @@ handle_call(which_children, _From, State) -> handle_call(count_children, _From, #state{children = [#child{restart_type = temporary, child_type = CT}]} = State) when ?is_simple(State) -> - {Active, Count} = - ?SETS:fold(fun(Pid, {Alive, Tot}) -> - case is_pid(Pid) andalso is_process_alive(Pid) of - true ->{Alive+1, Tot +1}; - false -> - {Alive, Tot + 1} - end - end, {0, 0}, dynamics_db(temporary, State#state.dynamics)), + Sz = ?SETS:size(dynamics_db(temporary, State#state.dynamics)), Reply = case CT of - supervisor -> [{specs, 1}, {active, Active}, - {supervisors, Count}, {workers, 0}]; - worker -> [{specs, 1}, {active, Active}, - {supervisors, 0}, {workers, Count}] + supervisor -> [{specs, 1}, {active, Sz}, + {supervisors, Sz}, {workers, 0}]; + worker -> [{specs, 1}, {active, Sz}, + {supervisors, 0}, {workers, Sz}] end, {reply, Reply, State}; -handle_call(count_children, _From, #state{children = [#child{restart_type = RType, +handle_call(count_children, _From, #state{dynamic_restarts = Restarts, + children = [#child{restart_type = RType, child_type = CT}]} = State) when ?is_simple(State) -> - {Active, Count} = - ?DICTS:fold(fun(Pid, _Val, {Alive, Tot}) -> - case is_pid(Pid) andalso is_process_alive(Pid) of - true -> - {Alive+1, Tot +1}; - false -> - {Alive, Tot + 1} - end - end, {0, 0}, dynamics_db(RType, State#state.dynamics)), + Sz = ?DICTS:size(dynamics_db(RType, State#state.dynamics)), + Active = Sz - Restarts, Reply = case CT of supervisor -> [{specs, 1}, {active, Active}, - {supervisors, Count}, {workers, 0}]; + {supervisors, Sz}, {workers, 0}]; worker -> [{specs, 1}, {active, Active}, - {supervisors, 0}, {workers, Count}] + {supervisors, 0}, {workers, Sz}] end, {reply, Reply, State}; @@ -806,8 +808,15 @@ restart(Child, State) -> {shutdown, remove_child(Child, NState)} end. -restart(simple_one_for_one, Child, State) -> +restart(simple_one_for_one, Child, State0) -> #child{pid = OldPid, mfargs = {M, F, A}} = Child, + State = case OldPid of + ?restarting(_) -> + NRes = State0#state.dynamic_restarts - 1, + State0#state{dynamic_restarts = NRes}; + _ -> + State0 + end, Dynamics = ?DICTS:erase(OldPid, dynamics_db(Child#child.restart_type, State#state.dynamics)), case do_start_child_i(M, F, A) of @@ -818,7 +827,9 @@ restart(simple_one_for_one, Child, State) -> NState = State#state{dynamics = ?DICTS:store(Pid, A, Dynamics)}, {ok, NState}; {error, Error} -> - NState = State#state{dynamics = ?DICTS:store(restarting(OldPid), A, + NRestarts = State#state.dynamic_restarts + 1, + NState = State#state{dynamic_restarts = NRestarts, + dynamics = ?DICTS:store(restarting(OldPid), A, Dynamics)}, report_error(start_error, Error, Child, State#state.name), {try_again, NState} @@ -1083,7 +1094,7 @@ wait_dynamic_children(#child{restart_type=RType} = Child, Pids, Sz, {timeout, TRef, kill} -> ?SETS:fold(fun(P, _) -> exit(P, kill) end, ok, Pids), - wait_dynamic_children(Child, Pids, Sz-1, undefined, EStack) + wait_dynamic_children(Child, Pids, Sz, undefined, EStack) end. %%----------------------------------------------------------------- diff --git a/lib/stdlib/src/unicode.erl b/lib/stdlib/src/unicode.erl index 3e8e6f5101..617da11ba8 100644 --- a/lib/stdlib/src/unicode.erl +++ b/lib/stdlib/src/unicode.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -561,6 +561,8 @@ do_o_binary(F,L) -> erlang:iolist_to_binary(List) end. +-dialyzer({no_improper_lists, do_o_binary2/2}). + do_o_binary2(_F,[]) -> <<>>; do_o_binary2(F,[H|T]) -> diff --git a/lib/stdlib/src/zip.erl b/lib/stdlib/src/zip.erl index d6031dabbc..f8ba6f18e9 100644 --- a/lib/stdlib/src/zip.erl +++ b/lib/stdlib/src/zip.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2013. All Rights Reserved. +%% Copyright Ericsson AB 2006-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -1550,57 +1550,35 @@ unix_extra_field_and_var_from_bin(_) -> %% A pwrite-like function for iolists (used by memory-option) -split_iolist(B, Pos) when is_binary(B) -> - split_binary(B, Pos); -split_iolist(L, Pos) when is_list(L) -> - splitter([], L, Pos). +pwrite_binary(B, Pos, Bin) when byte_size(B) =:= Pos -> + append_bins(Bin, B); +pwrite_binary(B, Pos, Bin) -> + erlang:iolist_to_binary(pwrite_iolist(B, Pos, Bin)). -splitter(Left, Right, 0) -> - {Left, Right}; -splitter(Left, [A | Right], RelPos) when is_list(A) or is_binary(A) -> - Sz = erlang:iolist_size(A), - case Sz > RelPos of - true -> - {Leftx, Rightx} = split_iolist(A, RelPos), - {[Left | Leftx], [Rightx, Right]}; - _ -> - splitter([Left | A], Right, RelPos - Sz) - end; -splitter(Left, [A | Right], RelPos) when is_integer(A) -> - splitter([Left, A], Right, RelPos - 1); -splitter(Left, Right, RelPos) when is_binary(Right) -> - splitter(Left, [Right], RelPos). +append_bins([Bin|Bins], B) when is_binary(Bin) -> + append_bins(Bins, <<B/binary, Bin/binary>>); +append_bins([List|Bins], B) when is_list(List) -> + append_bins(Bins, append_bins(List, B)); +append_bins(Bin, B) when is_binary(Bin) -> + <<B/binary, Bin/binary>>; +append_bins([_|_]=List, B) -> + <<B/binary, (iolist_to_binary(List))/binary>>; +append_bins([], B) -> + B. -skip_iolist(B, Pos) when is_binary(B) -> - case B of - <<_:Pos/binary, Bin/binary>> -> Bin; - _ -> <<>> - end; -skip_iolist(L, Pos) when is_list(L) -> - skipper(L, Pos). - -skipper(Right, 0) -> - Right; -skipper([A | Right], RelPos) when is_list(A) or is_binary(A) -> - Sz = erlang:iolist_size(A), - case Sz > RelPos of - true -> - Rightx = skip_iolist(A, RelPos), - [Rightx, Right]; - _ -> - skip_iolist(Right, RelPos - Sz) - end; -skipper([A | Right], RelPos) when is_integer(A) -> - skip_iolist(Right, RelPos - 1). +-dialyzer({no_improper_lists, pwrite_iolist/3}). -pwrite_iolist(Iolist, Pos, Bin) -> - {Left, Right} = split_iolist(Iolist, Pos), +pwrite_iolist(B, Pos, Bin) -> + {Left, Right} = split_binary(B, Pos), Sz = erlang:iolist_size(Bin), - R = skip_iolist(Right, Sz), + R = skip_bin(Right, Sz), [Left, Bin | R]. -pwrite_binary(B, Pos, Bin) -> - erlang:iolist_to_binary(pwrite_iolist(B, Pos, Bin)). +skip_bin(B, Pos) when is_binary(B) -> + case B of + <<_:Pos/binary, Bin/binary>> -> Bin; + _ -> <<>> + end. %% ZIP header manipulations diff --git a/lib/stdlib/test/Makefile b/lib/stdlib/test/Makefile index d4ab674486..e366c2b755 100644 --- a/lib/stdlib/test/Makefile +++ b/lib/stdlib/test/Makefile @@ -30,6 +30,7 @@ MODULES= \ erl_lint_SUITE \ erl_pp_SUITE \ erl_scan_SUITE \ + error_logger_h_SUITE \ escript_SUITE \ ets_SUITE \ ets_tough_SUITE \ diff --git a/lib/stdlib/test/base64_SUITE.erl b/lib/stdlib/test/base64_SUITE.erl index cca9b967d5..75eebba6c6 100644 --- a/lib/stdlib/test/base64_SUITE.erl +++ b/lib/stdlib/test/base64_SUITE.erl @@ -30,7 +30,8 @@ %% Test cases must be exported. -export([base64_encode/1, base64_decode/1, base64_otp_5635/1, base64_otp_6279/1, big/1, illegal/1, mime_decode/1, - mime_decode_to_string/1, roundtrip/1]). + mime_decode_to_string/1, + roundtrip_1/1, roundtrip_2/1, roundtrip_3/1, roundtrip_4/1]). init_per_testcase(_, Config) -> Dog = test_server:timetrap(?t:minutes(4)), @@ -50,10 +51,11 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [base64_encode, base64_decode, base64_otp_5635, base64_otp_6279, big, illegal, mime_decode, mime_decode_to_string, - roundtrip]. + {group, roundtrip}]. groups() -> - []. + [{roundtrip, [parallel], + [roundtrip_1, roundtrip_2, roundtrip_3, roundtrip_4]}]. init_per_suite(Config) -> Config. @@ -242,21 +244,33 @@ mime_decode_to_string(Config) when is_list(Config) -> %%------------------------------------------------------------------------- -roundtrip(Config) when is_list(Config) -> - Sizes = lists:seq(1, 255) ++ lists:seq(2400-5, 2440), - roundtrip_1(Sizes, []). +roundtrip_1(Config) when is_list(Config) -> + do_roundtrip(1). -roundtrip_1([NextSize|Sizes], Current) -> +roundtrip_2(Config) when is_list(Config) -> + do_roundtrip(2). + +roundtrip_3(Config) when is_list(Config) -> + do_roundtrip(3). + +roundtrip_4(Config) when is_list(Config) -> + do_roundtrip(4). + +do_roundtrip(Offset) -> + Sizes = lists:seq(Offset, 255, 4) ++ lists:seq(2400-6+Offset, 2440, 4), + do_roundtrip_1(Sizes, []). + +do_roundtrip_1([NextSize|Sizes], Current) -> Len = length(Current), io:format("~p", [Len]), - do_roundtrip(Current), + do_roundtrip_2(Current), Next = random_byte_list(NextSize - Len, Current), - roundtrip_1(Sizes, Next); -roundtrip_1([], Last) -> + do_roundtrip_1(Sizes, Next); +do_roundtrip_1([], Last) -> io:format("~p", [length(Last)]), - do_roundtrip(Last). + do_roundtrip_2(Last). -do_roundtrip(List) -> +do_roundtrip_2(List) -> Bin = list_to_binary(List), Base64Bin = base64:encode(List), Base64Bin = base64:encode(Bin), diff --git a/lib/stdlib/test/dets_SUITE.erl b/lib/stdlib/test/dets_SUITE.erl index 7f5e06524a..35e587afcc 100644 --- a/lib/stdlib/test/dets_SUITE.erl +++ b/lib/stdlib/test/dets_SUITE.erl @@ -1876,9 +1876,33 @@ fixtable(Config, Version) when is_list(Config) -> {ok, _} = dets:open_file(T, [{type, duplicate_bag} | Args]), %% In a fixed table, delete and re-insert an object. ok = dets:insert(T, {1, a, b}), + SysBefore = erlang:timestamp(), + MonBefore = erlang:monotonic_time(), dets:safe_fixtable(T, true), + MonAfter = erlang:monotonic_time(), + SysAfter = erlang:timestamp(), + Self = self(), + {FixMonTime,[{Self,1}]} = dets:info(T,safe_fixed_monotonic_time), + {FixSysTime,[{Self,1}]} = dets:info(T,safe_fixed), + true = is_integer(FixMonTime), + true = MonBefore =< FixMonTime, + true = FixMonTime =< MonAfter, + {FstMs,FstS,FstUs} = FixSysTime, + true = is_integer(FstMs), + true = is_integer(FstS), + true = is_integer(FstUs), + case erlang:system_info(time_warp_mode) of + no_time_warp -> + true = timer:now_diff(FixSysTime, SysBefore) >= 0, + true = timer:now_diff(SysAfter, FixSysTime) >= 0; + _ -> + %% ets:info(Tab,safe_fixed) not timewarp safe... + ignore + end, ok = dets:match_delete(T, {1, a, b}), ok = dets:insert(T, {1, a, b}), + {FixMonTime,[{Self,1}]} = dets:info(T,safe_fixed_monotonic_time), + {FixSysTime,[{Self,1}]} = dets:info(T,safe_fixed), dets:safe_fixtable(T, false), 1 = length(dets:match_object(T, '_')), diff --git a/lib/stdlib/test/erl_eval_SUITE.erl b/lib/stdlib/test/erl_eval_SUITE.erl index b9c4ad0a46..c21c4e61ee 100644 --- a/lib/stdlib/test/erl_eval_SUITE.erl +++ b/lib/stdlib/test/erl_eval_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2013. All Rights Reserved. +%% Copyright Ericsson AB 1998-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -39,6 +39,7 @@ otp_7550/1, otp_8133/1, otp_10622/1, + otp_13228/1, funs/1, try_catch/1, eval_expr_5/1, @@ -83,7 +84,8 @@ all() -> pattern_expr, match_bin, guard_3, guard_4, guard_5, lc, simple_cases, unary_plus, apply_atom, otp_5269, otp_6539, otp_6543, otp_6787, otp_6977, otp_7550, - otp_8133, otp_10622, funs, try_catch, eval_expr_5, zero_width, + otp_8133, otp_10622, otp_13228, + funs, try_catch, eval_expr_5, zero_width, eep37, eep43]. groups() -> @@ -1042,6 +1044,13 @@ otp_10622(Config) when is_list(Config) -> ok. +otp_13228(doc) -> + ["OTP-13228. ERL-32: non-local function handler bug."]; +otp_13228(_Config) -> + LFH = {value, fun(foo, [io_fwrite]) -> worked end}, + EFH = {value, fun({io, fwrite}, [atom]) -> io_fwrite end}, + {value, worked, []} = parse_and_run("foo(io:fwrite(atom)).", LFH, EFH). + funs(doc) -> ["Simple cases, just to cover some code."]; funs(suite) -> @@ -1483,6 +1492,16 @@ eep43(Config) when is_list(Config) -> " #{ K1 := 1, K2 := 2, K3 := 3, {2,2} := 4} = Map " "end.", #{ 1 => 1, <<42:301>> => 2, {3,<<42:301>>} => 3, {2,2} => 4}), + check(fun () -> + X = key, + (fun(#{X := value}) -> true end)(#{X => value}) + end, + "begin " + " X = key, " + " (fun(#{X := value}) -> true end)(#{X => value}) " + "end.", + true), + error_check("[camembert]#{}.", {badmap,[camembert]}), error_check("[camembert]#{nonexisting:=v}.", {badmap,[camembert]}), error_check("#{} = 1.", {badmatch,1}), diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl index 0424e2b967..375fb6bc93 100644 --- a/lib/stdlib/test/erl_lint_SUITE.erl +++ b/lib/stdlib/test/erl_lint_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2015. All Rights Reserved. +%% Copyright Ericsson AB 1999-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -65,7 +65,7 @@ too_many_arguments/1, basic_errors/1,bin_syntax_errors/1, predef/1, - maps/1,maps_type/1,otp_11851/1,otp_12195/1 + maps/1,maps_type/1,otp_11851/1,otp_12195/1, otp_13230/1 ]). % Default timetrap timeout (set in init_per_testcase). @@ -94,7 +94,7 @@ all() -> bif_clash, behaviour_basic, behaviour_multiple, otp_11861, otp_7550, otp_8051, format_warn, {group, on_load}, too_many_arguments, basic_errors, bin_syntax_errors, predef, - maps, maps_type, otp_11851, otp_12195]. + maps, maps_type, otp_11851, otp_12195, otp_13230]. groups() -> [{unused_vars_warn, [], @@ -3604,7 +3604,10 @@ bin_syntax_errors(Config) -> t(<<X/unit:8>>) -> X; t(<<X:7/float>>) -> X; t(<< <<_:8>> >>) -> ok; - t(<<(x ! y):8/integer>>) -> ok. + t(<<(x ! y):8/integer>>) -> ok; + t(X) -> + {<<X/binary-integer>>,<<X/signed-unsigned-integer>>, + <<X/little-big>>,<<X/unit:4-unit:8>>}. ">>, [], {error,[{1,erl_lint,illegal_bitsize}, @@ -3613,7 +3616,12 @@ bin_syntax_errors(Config) -> {4,erl_lint,{undefined_bittype,bad_type}}, {5,erl_lint,bittype_unit}, {7,erl_lint,illegal_pattern}, - {8,erl_lint,illegal_pattern}], + {8,erl_lint,illegal_pattern}, + {10,erl_lint,{bittype_mismatch,integer,binary,"type"}}, + {10,erl_lint,{bittype_mismatch,unsigned,signed,"sign"}}, + {11,erl_lint,{bittype_mismatch,8,4,"unit"}}, + {11,erl_lint,{bittype_mismatch,big,little,"endianness"}} + ], [{6,erl_lint,{bad_bitsize,"float"}}]}} ], [] = run(Config, Ts), @@ -3869,6 +3877,15 @@ otp_12195(Config) when is_list(Config) -> [] = run(Config, Ts), ok. +otp_13230(doc) -> + "OTP-13230: -deprecated without -module"; +otp_13230(Config) when is_list(Config) -> + Abstr = <<"-deprecated([{frutt,0,next_version}]).">>, + {errors,[{1,erl_lint,undefined_module}, + {1,erl_lint,{bad_deprecated,{frutt,0}}}], + []} = run_test2(Config, Abstr, []), + ok. + run(Config, Tests) -> F = fun({N,P,Ws,E}, BadL) -> case catch run_test(Config, P, Ws) of @@ -3920,22 +3937,35 @@ run_test2(Conf, Test, Warnings0) -> %% is no reason to produce an output file since we are only %% interested in the errors and warnings. - %% Print warnings, call erl_lint:format_error/1. + %% Print warnings, call erl_lint:format_error/1. (But note that + %% the compiler will ignore failing calls to erl_lint:format_error/1.) compile:file(File, [binary,report|Opts]), case compile:file(File, [binary|Opts]) of - {ok, _M, Code, Ws} when is_binary(Code) -> warnings(File, Ws); - {error, [{File,Es}], []} -> {errors, Es, []}; - {error, [{File,Es}], [{File,Ws}]} -> {error, Es, Ws}; - {error, [{File,Es1},{File,Es2}], []} -> {errors2, Es1, Es2} + {ok, _M, Code, Ws} when is_binary(Code) -> + warnings(File, Ws); + {error, [{File,Es}], []} -> + {errors, call_format_error(Es), []}; + {error, [{File,Es}], [{File,Ws}]} -> + {error, call_format_error(Es), call_format_error(Ws)}; + {error, [{File,Es1},{File,Es2}], []} -> + {errors2, Es1, Es2} end. warnings(File, Ws) -> case lists:append([W || {F, W} <- Ws, F =:= File]) of - [] -> []; - L -> {warnings, L} + [] -> + []; + L -> + {warnings, call_format_error(L)} end. +call_format_error(L) -> + %% Smoke test of format_error/1 to make sure that no crashes + %% slip through. + _ = [Mod:format_error(Term) || {_,Mod,Term} <- L], + L. + fail() -> io:format("failed~n"), ?t:fail(). diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl index 389fd059f6..92e2764c65 100644 --- a/lib/stdlib/test/erl_pp_SUITE.erl +++ b/lib/stdlib/test/erl_pp_SUITE.erl @@ -960,6 +960,9 @@ maps_syntax(Config) when is_list(Config) -> "-compile(export_all).\n" "-type t1() :: map().\n" "-type t2() :: #{ atom() => integer(), atom() => float() }.\n" + "-type u() :: #{a => (I :: integer()) | (A :: atom()),\n" + " (X :: atom()) | (Y :: atom()) =>\n" + " (I :: integer()) | (A :: atom())}.\n" "-spec f1(t1()) -> 'true'.\n" "f1(M) when is_map(M) -> true.\n" "-spec f2(t2()) -> integer().\n" diff --git a/lib/stdlib/test/error_logger_h_SUITE.erl b/lib/stdlib/test/error_logger_h_SUITE.erl new file mode 100644 index 0000000000..c82b1b62ef --- /dev/null +++ b/lib/stdlib/test/error_logger_h_SUITE.erl @@ -0,0 +1,406 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2015. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% +-module(error_logger_h_SUITE). +-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, + init_per_group/2,end_per_group/2]). +-export([logfile/1,logfile_truncated/1,tty/1,tty_truncated/1]). + +%% Event handler exports. +-export([init/1,handle_event/2,terminate/2]). + +-include_lib("test_server/include/test_server.hrl"). + +suite() -> [{ct_hooks,[ts_install_cth]}]. + +all() -> + [logfile,logfile_truncated,tty,tty_truncated]. + +groups() -> + []. + +init_per_suite(Config) -> + Config. + +end_per_suite(_Config) -> + ok. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + +logfile(Config) -> + PrivDir = ?config(priv_dir, Config), + LogDir = filename:join(PrivDir, ?MODULE), + Log = filename:join(LogDir, "logfile.log"), + ok = filelib:ensure_dir(Log), + + Ev = event_templates(), + + do_one_logfile(Log, Ev, unlimited), + + Pa = "-pa " ++ filename:dirname(code:which(?MODULE)), + {ok,Node} = start_node(logfile, Pa), + error_logger:logfile({open,Log}), + ok = rpc:call(Node, erlang, apply, [fun gen_events/1,[Ev]]), + AtNode = iolist_to_binary(["** at node ",atom_to_list(Node)," **"]), + error_logger:logfile(close), + analyse_events(Log, Ev, [AtNode], unlimited), + + [] = [{X, file:pid2name(X)} || X <- processes(), Data <- [process_info(X, [current_function])], + Data =/= undefined, + element(1, element(2, lists:keyfind(current_function, 1, Data))) + =:= file_io_server, + file:pid2name(X) =:= {ok, Log}], + + test_server:stop_node(Node), + + cleanup(Log), + ok. + +logfile_truncated(Config) -> + PrivDir = ?config(priv_dir, Config), + LogDir = filename:join(PrivDir, ?MODULE), + Log = filename:join(LogDir, "logfile_truncated.log"), + ok = filelib:ensure_dir(Log), + + Ev = event_templates(), + + Depth = 20, + application:set_env(kernel, error_logger_format_depth, Depth), + try + do_one_logfile(Log, Ev, Depth) + after + application:unset_env(kernel, error_logger_format_depth) + end, + + cleanup(Log), + ok. + +do_one_logfile(Log, Ev, Depth) -> + error_logger:logfile({open,Log}), + gen_events(Ev), + error_logger:logfile(close), + analyse_events(Log, Ev, [], Depth). + +tty(Config) -> + PrivDir = ?config(priv_dir, Config), + LogDir = filename:join(PrivDir, ?MODULE), + Log = filename:join(LogDir, "tty.log"), + ok = filelib:ensure_dir(Log), + + Ev = event_templates(), + + do_one_tty(Log, Ev, unlimited), + + Pa = "-pa " ++ filename:dirname(code:which(?MODULE)), + {ok,Node} = start_node(logfile, Pa), + tty_log_open(Log), + ok = rpc:call(Node, erlang, apply, [fun gen_events/1,[Ev]]), + tty_log_close(), + AtNode = iolist_to_binary(["** at node ",atom_to_list(Node)," **"]), + analyse_events(Log, Ev, [AtNode], unlimited), + + test_server:stop_node(Node), + + cleanup(Log), + ok. + +tty_truncated(Config) -> + PrivDir = ?config(priv_dir, Config), + LogDir = filename:join(PrivDir, ?MODULE), + Log = filename:join(LogDir, "tty_truncated.log"), + ok = filelib:ensure_dir(Log), + + Ev = event_templates(), + + Depth = 20, + application:set_env(kernel, error_logger_format_depth, Depth), + try + do_one_tty(Log, Ev, Depth) + after + application:unset_env(kernel, error_logger_format_depth) + end, + + cleanup(Log), + ok. + +do_one_tty(Log, Ev, Depth) -> + tty_log_open(Log), + gen_events(Ev), + tty_log_close(), + analyse_events(Log, Ev, [], Depth). + +tty_log_open(Log) -> + {ok,Fd} = file:open(Log, [write]), + Depth = case application:get_env(kernel, error_logger_format_depth) of + {ok,D} -> D; + _ -> unlimited + end, + error_logger:add_report_handler(?MODULE, {Fd,Depth}), + Fd. + +tty_log_close() -> + error_logger:delete_report_handler(?MODULE), + ok. + +event_templates() -> + [{error_msg,["Pure error string\n",[]]}, + {error_msg,["Pure error string with error ~p\n",[]]}, + {error_msg,["Error string with ~p\n", [format]]}, + {error_msg,["Error string with bad format ~p\n", []]}, + + {error_report,[error_atom]}, + {error_report,["error string"]}, + {error_report,[[{error_tag,value},error_value]]}, + + {info_msg,["Pure info string\n",[]]}, + {info_msg,["Pure info string with error ~p\n",[]]}, + {info_msg,["Pure string with ~p\n", [format]]}, + {info_msg,["Pure string with bad format ~p\n", []]}, + + {info_report,[info_atom]}, + {info_report,["info string"]}, + {info_report,[[{info_tag,value},info_value]]}, + + {warning_msg,["Pure warning string\n",[]]}, + {warning_msg,["Pure warning string with error ~p\n",[]]}, + {warning_msg,["Warning string with ~p\n", [format]]}, + {warning_msg,["Warning string with bad format ~p\n", []]}, + + {warning_report,[warning_atom]}, + {warning_report,["warning string"]}, + {warning_report,[[{warning_tag,value},warning_value]]}, + + %% Bigger terms. + {error_msg,["fairly big: ~p\n",[lists:seq(1, 128)]]}, + {error_report,[list_to_tuple(lists:seq(1, 100))]}, + {error_report,[lists:seq(32, 126)]}, + {error_report,[[{tag,lists:seq(1, 64)}]]} + ]. + +gen_events(Ev) -> + io:format("node = ~p\n", [node()]), + io:format("group leader = ~p\n", [group_leader()]), + io:format("~p\n", [gen_event:which_handlers(error_logger)]), + call_error_logger(Ev), + + {Pid,Ref} = spawn_monitor(fun() -> error(ouch) end), + receive + {'DOWN',Ref,process,Pid,_} -> + ok + end, + + %% The following calls with a custom type will be ignored. + error_logger:error_report(ignored, value), + error_logger:warning_report(ignored, value), + error_logger:info_report(ignored, value), + receive after 100 -> ok end, + ok. + +analyse_events(Log, Ev, AtNode, Depth) -> + {ok,Bin} = file:read_file(Log), + + io:format("*** Contents of log file ***\n\n~s\n", [Bin]), + + Lines = binary:split(Bin, <<"\n">>, [global,trim_all]), + io:format("~p\n", [Lines]), + + Rest = match_output(Ev, Lines, AtNode, Depth), + io:format("~p\n", [Rest]), + + [] = match_emulator_error(Rest), + ok. + + +call_error_logger([{F,Args}|T]) -> + apply(error_logger, F, Args), + call_error_logger(T); +call_error_logger([]) -> ok. + + +match_emulator_error([Head,Second,Third,_|Lines]) -> + match_head(<<"ERROR">>, Head), + {match,[{0,_}]} = re:run(Second, + "^Error in process <\\d+[.]\\d+[.]\\d+> on " + "node [^ ]* with exit value:"), + {match,[{0,_}]} = re:run(Third, "^[{]ouch,"), + Lines. + +match_output([Item|T], Lines0, AtNode, Depth) -> + try match_item(Item, Lines0, AtNode, Depth) of + Lines -> + match_output(T, Lines, AtNode, Depth) + catch + C:E -> + Stk = erlang:get_stacktrace(), + io:format("ITEM: ~p", [Item]), + io:format("LINES: ~p", [Lines0]), + erlang:raise(C, E, Stk) + end; +match_output([], Lines, _, _) -> Lines. + +match_item(Item, Lines, AtNode, Depth) -> + case item_type(Item) of + {msg,Head,Args} -> + match_format(Head, Args, Lines, AtNode, Depth); + {report,Head,Args} -> + match_term(Head, Args, Lines, AtNode, Depth) + end. + +item_type({error_msg,Args}) -> + {msg,<<"ERROR">>,Args}; +item_type({info_msg,Args}) -> + {msg,<<"INFO">>,Args}; +item_type({warning_msg,Args}) -> + {msg,<<"WARNING">>,Args}; +item_type({error_report,Args}) -> + {report,<<"ERROR">>,Args}; +item_type({info_report,Args}) -> + {report,<<"INFO">>,Args}; +item_type({warning_report,Args}) -> + {report,<<"WARNING">>,Args}. + +match_format(Tag, [Format,Args], [Head|Lines], AtNode, Depth) -> + match_head(Tag, Head), + Bin = try dl_format(Depth, Format, Args) of + Str -> + iolist_to_binary(Str) + catch + _:_ -> + S = dl_format(Depth, "ERROR: ~p - ~p~n", [Format,Args]), + iolist_to_binary(S) + end, + Expected0 = binary:split(Bin, <<"\n">>, [global,trim]), + Expected = Expected0 ++ AtNode, + match_term_lines(Expected, Lines). + +match_term(Tag, [Arg], [Head|Lines], AtNode, Depth) -> + match_head(Tag, Head), + Expected0 = match_term_get_expected(Arg, Depth), + Expected = Expected0 ++ AtNode, + match_term_lines(Expected, Lines). + +match_term_get_expected(List, Depth) when is_list(List) -> + Bin = try iolist_to_binary(dl_format(Depth, "~s\n", [List])) of + Bin0 -> Bin0 + catch + _:_ -> + iolist_to_binary(format_rep(List, Depth)) + end, + binary:split(Bin, <<"\n">>, [global,trim]); +match_term_get_expected(Term, Depth) -> + S = dl_format(Depth, "~p\n", [Term]), + Bin = iolist_to_binary(S), + binary:split(Bin, <<"\n">>, [global,trim]). + +format_rep([{Tag,Data}|Rep], Depth) -> + [dl_format(Depth, " ~p: ~p\n", [Tag,Data])| + format_rep(Rep, Depth)]; +format_rep([Other|Rep], Depth) -> + [dl_format(Depth, " ~p\n", [Other])| + format_rep(Rep, Depth)]; +format_rep([], _Depth) -> []. + +match_term_lines([Line|T], [Line|Lines]) -> + match_term_lines(T, Lines); +match_term_lines([], Lines) -> Lines. + +match_head(Tag, Head) -> + Re = <<"^=",Tag/binary, + " REPORT==== \\d\\d?-[A-Z][a-z][a-z]-\\d{4}::" + "\\d\\d:\\d\\d:\\d\\d ===$">>, + {match,_} = re:run(Head, Re). + +start_node(Name, Args) -> + case test_server:start_node(Name, slave, [{args,Args}]) of + {ok,Node} -> + {ok,Node}; + Error -> + test_server:fail(Error) + end. + +cleanup(File) -> + %% The point of this test case is not to test file operations. + %% Therefore ignore any failures. + case file:delete(File) of + ok -> + ok; + {error,Error1} -> + io:format("file:delete(~s) failed with error ~p", + [File,Error1]) + end, + Dir = filename:dirname(File), + case file:del_dir(Dir) of + ok -> + ok; + {error,Error2} -> + io:format("file:del_dir(~s) failed with error ~p", + [Dir,Error2]) + end, + ok. + + +%% Depth-limited io_lib:format. Intentionally implemented here instead +%% of using io_lib:scan_format/2 to avoid using the same implementation +%% as in the error_logger handlers. + +dl_format(unlimited, Format, Args) -> + io_lib:format(Format, Args); +dl_format(Depth, Format0, Args0) -> + {Format,Args} = dl_format_1(Format0, Args0, Depth, [], []), + io_lib:format(Format, Args). + +dl_format_1("~p"++Fs, [A|As], Depth, Facc, Acc) -> + dl_format_1(Fs, As, Depth, [$P,$~|Facc], [Depth,A|Acc]); +dl_format_1("~w"++Fs, [A|As], Depth, Facc, Acc) -> + dl_format_1(Fs, As, Depth, [$W,$~|Facc], [Depth,A|Acc]); +dl_format_1("~s"++Fs, [A|As], Depth, Facc, Acc) -> + dl_format_1(Fs, As, Depth, [$s,$~|Facc], [A|Acc]); +dl_format_1([F|Fs], As, Depth, Facc, Aacc) -> + dl_format_1(Fs, As, Depth, [F|Facc], Aacc); +dl_format_1([], [], _, Facc, Aacc) -> + {lists:reverse(Facc),lists:reverse(Aacc)}. + +%%% +%%% Our own event handler. There is no way to intercept the output +%%% from error_logger_tty_h, but we can use the same code by +%%% calling error_logger_tty_h:write_event/2. +%%% + +init({_,_}=St) -> + {ok,St}. + +handle_event(Event, {Fd,Depth}=St) -> + case error_logger_tty_h:write_event(tag_event(Event), io_lib, Depth) of + ok -> + ok; + Str when is_list(Str) -> + io:put_chars(Fd, Str) + end, + {ok,St}. + +terminate(_Reason, {Fd,_}) -> + ok = file:close(Fd), + []. + +tag_event(Event) -> + {erlang:universaltime(),Event}. diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl index ae431d66d9..1ddc4e7868 100644 --- a/lib/stdlib/test/ets_SUITE.erl +++ b/lib/stdlib/test/ets_SUITE.erl @@ -49,6 +49,7 @@ fixtable_next/1, fixtable_insert/1, rename/1, rename_unnamed/1, evil_rename/1, update_element/1, update_counter/1, evil_update_counter/1, partly_bound/1, match_heavy/1]). -export([update_counter_with_default/1]). +-export([update_counter_table_growth/1]). -export([member/1]). -export([memory/1]). -export([select_fail/1]). @@ -102,6 +103,7 @@ heavy_lookup_element_do/1, member_do/1, otp_5340_do/1, otp_7665_do/1, meta_wb_do/1, do_heavy_concurrent/1, tab2file2_do/2, exit_large_table_owner_do/2, types_do/1, sleeper/0, memory_do/1, update_counter_with_default_do/1, + update_counter_table_growth_do/1, ms_tracee_dummy/1, ms_tracee_dummy/2, ms_tracee_dummy/3, ms_tracee_dummy/4 ]). @@ -141,6 +143,7 @@ all() -> rename, rename_unnamed, evil_rename, update_element, update_counter, evil_update_counter, update_counter_with_default, partly_bound, + update_counter_table_growth, match_heavy, {group, fold}, member, t_delete_object, t_init_table, t_whitebox, t_delete_all_objects, t_insert_list, t_test_ms, t_select_delete, t_ets_dets, @@ -2063,6 +2066,16 @@ update_counter_with_default_do(Opts) -> ok. +update_counter_table_growth(_Config) -> + repeat_for_opts(update_counter_table_growth_do). + +update_counter_table_growth_do(Opts) -> + Set = ets_new(b, [set | Opts]), + [ets:update_counter(Set, N, {2, 1}, {N, 1}) || N <- lists:seq(1,10000)], + OrderedSet = ets_new(b, [ordered_set | Opts]), + [ets:update_counter(OrderedSet, N, {2, 1}, {N, 1}) || N <- lists:seq(1,10000)], + ok. + fixtable_next(doc) -> ["Check that a first-next sequence always works on a fixed table"]; fixtable_next(suite) -> @@ -3989,15 +4002,37 @@ safe_fixtable_do(Opts) -> ?line true = ets:safe_fixtable(Tab, true), ?line receive after 1 -> ok end, ?line true = ets:safe_fixtable(Tab, false), - ?line false = ets:info(Tab,safe_fixed), - ?line true = ets:safe_fixtable(Tab, true), + false = ets:info(Tab,safe_fixed_monotonic_time), + false = ets:info(Tab,safe_fixed), + SysBefore = erlang:timestamp(), + MonBefore = erlang:monotonic_time(), + true = ets:safe_fixtable(Tab, true), + MonAfter = erlang:monotonic_time(), + SysAfter = erlang:timestamp(), Self = self(), - ?line {{_,_,_},[{Self,1}]} = ets:info(Tab,safe_fixed), + {FixMonTime,[{Self,1}]} = ets:info(Tab,safe_fixed_monotonic_time), + {FixSysTime,[{Self,1}]} = ets:info(Tab,safe_fixed), + true = is_integer(FixMonTime), + true = MonBefore =< FixMonTime, + true = FixMonTime =< MonAfter, + {FstMs,FstS,FstUs} = FixSysTime, + true = is_integer(FstMs), + true = is_integer(FstS), + true = is_integer(FstUs), + case erlang:system_info(time_warp_mode) of + no_time_warp -> + true = timer:now_diff(FixSysTime, SysBefore) >= 0, + true = timer:now_diff(SysAfter, FixSysTime) >= 0; + _ -> + %% ets:info(Tab,safe_fixed) not timewarp safe... + ignore + end, %% Test that an unjustified 'unfix' is a no-op. {Pid,MRef} = my_spawn_monitor(fun() -> true = ets:safe_fixtable(Tab,false) end), {'DOWN', MRef, process, Pid, normal} = receive M -> M end, - ?line true = ets:info(Tab,fixed), - ?line {{_,_,_},[{Self,1}]} = ets:info(Tab,safe_fixed), + true = ets:info(Tab,fixed), + {FixMonTime,[{Self,1}]} = ets:info(Tab,safe_fixed_monotonic_time), + {FixSysTime,[{Self,1}]} = ets:info(Tab,safe_fixed), %% badarg's ?line {'EXIT', {badarg, _}} = (catch ets:safe_fixtable(Tab, foobar)), ?line true = ets:info(Tab,fixed), @@ -4043,6 +4078,7 @@ info_do(Opts) -> ?line undefined = ets:info(non_existing_table_xxyy,type), ?line undefined = ets:info(non_existing_table_xxyy,node), ?line undefined = ets:info(non_existing_table_xxyy,named_table), + ?line undefined = ets:info(non_existing_table_xxyy,safe_fixed_monotonic_time), ?line undefined = ets:info(non_existing_table_xxyy,safe_fixed), ?line verify_etsmem(EtsMem). @@ -5532,7 +5568,7 @@ otp_8166_zombie_creator(T,Deleted) -> [{'=<','$1', Deleted}], [true]}]), Pid ! zombies_created, - repeat_while(fun() -> case ets:info(T,safe_fixed) of + repeat_while(fun() -> case ets:info(T,safe_fixed_monotonic_time) of {_,[_P1,_P2]} -> false; _ -> diff --git a/lib/stdlib/test/gen_event_SUITE.erl b/lib/stdlib/test/gen_event_SUITE.erl index 7a6fcba4e5..b019f98b69 100644 --- a/lib/stdlib/test/gen_event_SUITE.erl +++ b/lib/stdlib/test/gen_event_SUITE.erl @@ -412,7 +412,6 @@ notify(Config) when is_list(Config) -> ok end, ?line ok = gen_event:notify(my_dummy_handler, {swap_event,dummy1_h,swap}), - ?t:sleep(1000), ?line [dummy1_h] = gen_event:which_handlers(my_dummy_handler), ?line ok = gen_event:notify(my_dummy_handler, Event), ?line receive @@ -445,7 +444,6 @@ notify(Config) when is_list(Config) -> end, ?line ok = gen_event:notify(my_dummy_handler, {swap_event, {dummy1_h, 9}, swap}), - ?t:sleep(1000), ?line [{dummy1_h,9}] = gen_event:which_handlers(my_dummy_handler), ?line ok = gen_event:notify(my_dummy_handler, Event), ?line receive @@ -485,7 +483,6 @@ notify(Config) when is_list(Config) -> ?line ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]), ?line ok = gen_event:notify(my_dummy_handler, {swap_event,dummy1_h,swap}), - ?t:sleep(1000), ?line [dummy1_h] = gen_event:which_handlers(my_dummy_handler), ?line ok = gen_event:notify(my_dummy_handler, do_crash), @@ -496,7 +493,6 @@ notify(Config) when is_list(Config) -> ?line ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]), ?line ok = gen_event:notify(my_dummy_handler, {swap_event,dummy1_h,swap}), - ?t:sleep(1000), ?line [dummy1_h] = gen_event:which_handlers(my_dummy_handler), ?line ok = gen_event:notify(my_dummy_handler, delete_event), @@ -529,7 +525,6 @@ sync_notify(Config) when is_list(Config) -> end, ?line ok = gen_event:sync_notify(my_dummy_handler, {swap_event, dummy1_h, swap}), - ?t:sleep(1000), ?line [dummy1_h] = gen_event:which_handlers(my_dummy_handler), ?line ok = gen_event:sync_notify(my_dummy_handler, Event), ?line receive @@ -562,7 +557,6 @@ sync_notify(Config) when is_list(Config) -> end, ?line ok = gen_event:sync_notify(my_dummy_handler, {swap_event, {dummy1_h, 9}, swap}), - ?t:sleep(1000), ?line [{dummy1_h,9}] = gen_event:which_handlers(my_dummy_handler), ?line ok = gen_event:sync_notify(my_dummy_handler, Event), ?line receive @@ -603,7 +597,6 @@ sync_notify(Config) when is_list(Config) -> ?line ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]), ?line ok = gen_event:sync_notify(my_dummy_handler, {swap_event,dummy1_h,swap}), - ?t:sleep(1000), ?line [dummy1_h] = gen_event:which_handlers(my_dummy_handler), ?line ok = gen_event:sync_notify(my_dummy_handler, do_crash), @@ -615,7 +608,6 @@ sync_notify(Config) when is_list(Config) -> ?line ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]), ?line ok = gen_event:sync_notify(my_dummy_handler, {swap_event,dummy1_h,swap}), - ?t:sleep(1000), ?line [dummy1_h] = gen_event:which_handlers(my_dummy_handler), ?line ok = gen_event:sync_notify(my_dummy_handler, delete_event), @@ -789,7 +781,6 @@ info(Config) when is_list(Config) -> ok end, ?line my_dummy_handler ! {swap_info,dummy1_h,swap}, - ?t:sleep(1000), ?line [dummy1_h] = gen_event:which_handlers(my_dummy_handler), ?line my_dummy_handler ! Info, ?line receive @@ -821,7 +812,6 @@ info(Config) when is_list(Config) -> ok end, ?line my_dummy_handler ! {swap_info,{dummy1_h,2},swap}, - ?t:sleep(1000), ?line [{dummy1_h,2}] = gen_event:which_handlers(my_dummy_handler), ?line my_dummy_handler ! Info, ?line receive @@ -853,7 +843,6 @@ info(Config) when is_list(Config) -> ok end, ?line my_dummy_handler ! {swap_info,dummy1_h,swap}, - ?t:sleep(1000), ?line [dummy1_h] = gen_event:which_handlers(my_dummy_handler), ?line my_dummy_handler ! Info, ?line receive diff --git a/lib/stdlib/test/id_transform_SUITE.erl b/lib/stdlib/test/id_transform_SUITE.erl index 41de016f8d..1cff990697 100644 --- a/lib/stdlib/test/id_transform_SUITE.erl +++ b/lib/stdlib/test/id_transform_SUITE.erl @@ -56,47 +56,26 @@ end_per_group(_GroupName, Config) -> id_transform(doc) -> "Test erl_id_trans."; id_transform(Config) when is_list(Config) -> - ?line File=filename:join([code:lib_dir(stdlib),"examples", - "erl_id_trans.erl"]), - ?line {ok,erl_id_trans,Bin}=compile:file(File,[binary]), - ?line {module,erl_id_trans}=code:load_binary(erl_id_trans,File,Bin), - ?line case test_server:purify_is_running() of - false -> - Dog = ct:timetrap(?t:hours(1)), - ?line Res = run_in_test_suite(), - ?t:timetrap_cancel(Dog), - Res; - true -> - {skip,"Purify (too slow)"} - end. + File = filename:join([code:lib_dir(stdlib),"examples", + "erl_id_trans.erl"]), + {ok,erl_id_trans,Bin} = compile:file(File,[binary]), + {module,erl_id_trans} = code:load_binary(erl_id_trans, File, Bin), + case test_server:purify_is_running() of + false -> + Dog = ct:timetrap(?t:hours(1)), + Res = run_in_test_suite(), + ?t:timetrap_cancel(Dog), + Res; + true -> + {skip,"Valgrind (too slow)"} + end. run_in_test_suite() -> - LibDir = code:lib_dir(), SuperDir = filename:dirname(filename:dirname(code:which(?MODULE))), TestDirs = filelib:wildcard(filename:join([SuperDir,"*_test"])), - {All,Res} = case LibDir of - "/clearcase/otp/erts/lib" -> - %% Only test_suites 'cause clearcase is too slow... - {false,run_list(TestDirs)}; - _ -> - {true,run_codepath_and(TestDirs)} - end, - Comment0 = case All of - true -> []; - false -> "Only testsuite directories traversed" - end, - case Res of - {error,Reason} when Comment0 =/= [] -> - {failed,Comment0++"; "++Reason}; - {error,Reason} -> - {failed,Reason}; - ok -> - {comment,Comment0} - end. - -run_codepath_and(DirList) -> AbsDirs = [filename:absname(X) || X <- code:get_path()], - run_list(ordsets:from_list([X || X <- AbsDirs] ++ DirList)). + Dirs = ordsets:from_list(AbsDirs ++ TestDirs), + run_list(Dirs). run_list(PathL) -> io:format("Where to search for beam files:\n~p\n", [PathL]), @@ -123,7 +102,7 @@ run_list(PathL) -> end, case length(SevereFailures) of 0 -> ok; - Len -> {error,integer_to_list(Len)++" failures"} + Len -> {failed,integer_to_list(Len)++" failures"} end. diff --git a/lib/stdlib/test/io_SUITE.erl b/lib/stdlib/test/io_SUITE.erl index 5df09b6a79..cb96f8b575 100644 --- a/lib/stdlib/test/io_SUITE.erl +++ b/lib/stdlib/test/io_SUITE.erl @@ -29,10 +29,11 @@ manpage/1, otp_6708/1, otp_7084/1, otp_7421/1, io_lib_collect_line_3_wb/1, cr_whitespace_in_string/1, io_fread_newlines/1, otp_8989/1, io_lib_fread_literal/1, - printable_range/1, + printable_range/1, bad_printable_range/1, io_lib_print_binary_depth_one/1, otp_10302/1, otp_10755/1, otp_10836/1, io_lib_width_too_small/1, - io_with_huge_message_queue/1, format_string/1]). + io_with_huge_message_queue/1, format_string/1, + maps/1, coverage/1]). -export([pretty/2]). @@ -70,10 +71,10 @@ all() -> manpage, otp_6708, otp_7084, otp_7421, io_lib_collect_line_3_wb, cr_whitespace_in_string, io_fread_newlines, otp_8989, io_lib_fread_literal, - printable_range, + printable_range, bad_printable_range, io_lib_print_binary_depth_one, otp_10302, otp_10755, otp_10836, io_lib_width_too_small, io_with_huge_message_queue, - format_string]. + format_string, maps, coverage]. groups() -> []. @@ -2062,8 +2063,6 @@ printable_range(Suite) when is_list(Suite) -> [{args, " +pclatin1 -pa " ++ Pa}]), unicode = rpc:call(UNode,io,printable_range,[]), latin1 = rpc:call(LNode,io,printable_range,[]), - {error, _} = test_server:start_node(printable_range_unnicode, slave, - [{args, " +pcunnicode -pa " ++ Pa}]), PrettyOptions = [{column,1}, {line_length,109}, {depth,30}, @@ -2071,48 +2070,81 @@ printable_range(Suite) when is_list(Suite) -> {record_print_fun, fun(_,_) -> no end}, {encoding,unicode}], - 1025 = lists:max(lists:flatten(rpc:call(UNode,io_lib_pretty,print, - [{hello, [1024,1025]}, - PrettyOptions]))), - 125 = lists:max(lists:flatten(rpc:call(LNode,io_lib_pretty,print, - [{hello, [1024,1025]}, - PrettyOptions]))), - 125 = lists:max(lists:flatten(rpc:call(DNode,io_lib_pretty,print, - [{hello, [1024,1025]}, - PrettyOptions]))), - 1025 = lists:max(lists:flatten(rpc:call(UNode,io_lib_pretty,print, - [{hello, <<1024/utf8,1025/utf8>>}, - PrettyOptions]))), - 125 = lists:max(lists:flatten(rpc:call(LNode,io_lib_pretty,print, - [{hello, <<1024/utf8,1025/utf8>>}, - PrettyOptions]))), - 125 = lists:max(lists:flatten(rpc:call(DNode,io_lib_pretty,print, - [{hello, <<1024/utf8,1025/utf8>>}, - PrettyOptions]))), + PrintableControls = "\t\v\b\f\e\r\n", + + 1025 = print_max(UNode, [{hello, [1024,1025]}, + PrettyOptions]), + 125 = print_max(LNode, [{hello, [1024,1025]}, + PrettyOptions]), + 125 = print_max(DNode, [{hello, [1024,1025]}, + PrettyOptions]), + 1025 = print_max(UNode, [{hello, <<1024/utf8,1025/utf8>>}, + PrettyOptions]), + 125 = print_max(LNode, [{hello, <<1024/utf8,1025/utf8>>}, + PrettyOptions]), + 125 = print_max(DNode, [{hello, <<1024/utf8,1025/utf8>>}, + PrettyOptions]), + $v = print_max(UNode, [PrintableControls,PrettyOptions]), + $v = print_max(LNode, [PrintableControls,PrettyOptions]), + $v = print_max(DNode, [PrintableControls,PrettyOptions]), + 16#10FFFF = print_max(UNode, + [<<16#10FFFF/utf8,"\t\v\b\f\e\r\n">>, + PrettyOptions]), + $> = print_max(LNode, + [<<16#10FFFF/utf8,"\t\v\b\f\e\r\n">>, + PrettyOptions]), + $> = print_max(DNode, + [<<16#10FFFF/utf8,"\t\v\b\f\e\r\n">>, + PrettyOptions]), - 1025 = lists:max(lists:flatten(rpc:call(UNode,io_lib,format, - ["~tp",[{hello, [1024,1025]}]]))), - 125 = lists:max(lists:flatten(rpc:call(LNode,io_lib,format, - ["~tp",[{hello, [1024,1025]}]]))), - 125 = lists:max(lists:flatten(rpc:call(DNode,io_lib,format, - ["~tp",[{hello, [1024,1025]}]]))), - 1025 = lists:max(lists:flatten(rpc:call(UNode,io_lib,format, - ["~tp", - [{hello, - <<1024/utf8,1025/utf8>>}]]))), - 125 = lists:max(lists:flatten(rpc:call(LNode,io_lib,format, - ["~tp", - [{hello, - <<1024/utf8,1025/utf8>>}]]))), - 125 = lists:max(lists:flatten(rpc:call(DNode,io_lib,format, - ["~tp", - [{hello, - <<1024/utf8,1025/utf8>>}]]))), + 1025 = format_max(UNode, ["~tp", [{hello, [1024,1025]}]]), + 125 = format_max(LNode, ["~tp", [{hello, [1024,1025]}]]), + 125 = format_max(DNode, ["~tp", [{hello, [1024,1025]}]]), + 1025 = format_max(UNode, ["~tp", [{hello, <<1024/utf8,1025/utf8>>}]]), + 125 = format_max(LNode, ["~tp", [{hello, <<1024/utf8,1025/utf8>>}]]), + 125 = format_max(DNode, ["~tp", [{hello, <<1024/utf8,1025/utf8>>}]]), + + $\e = format_max(UNode, ["~ts", [PrintableControls]]), + $\e = format_max(LNode, ["~ts", [PrintableControls]]), + $\e = format_max(DNode, ["~ts", [PrintableControls]]), + test_server:stop_node(UNode), test_server:stop_node(LNode), test_server:stop_node(DNode), ok. +print_max(Node, Args) -> + rpc_call_max(Node, io_lib_pretty, print, Args). + +format_max(Node, Args) -> + rpc_call_max(Node, io_lib, format, Args). + +rpc_call_max(Node, M, F, Args) -> + lists:max(lists:flatten(rpc:call(Node, M, F, Args))). + +%% Make sure that a bad specification for a printable range is rejected. +bad_printable_range(Config) when is_list(Config) -> + Cmd = lists:concat([lib:progname()," +pcunnnnnicode -run erlang halt"]), + P = open_port({spawn, Cmd}, [stderr_to_stdout, {line, 200}]), + ok = receive + {P, {data, {eol , "bad range of printable characters" ++ _}}} -> + ok; + Other -> + Other + after 1000 -> + timeout + end, + catch port_close(P), + flush_from_port(P), + ok. + +flush_from_port(P) -> + receive {P, _} -> + flush_from_port(P) + after 0 -> + ok + end. + io_lib_print_binary_depth_one(doc) -> "Test binaries printed with a depth of one behave correctly"; io_lib_print_binary_depth_one(Suite) when is_list(Suite) -> @@ -2225,7 +2257,7 @@ compile_file(File, Text, Config) -> after ok %file:delete(Fname) end. -io_lib_width_too_small(Config) -> +io_lib_width_too_small(_Config) -> "**" = lists:flatten(io_lib:format("~2.3w", [3.14])), "**" = lists:flatten(io_lib:format("~2.5w", [3.14])), ok. @@ -2233,12 +2265,14 @@ io_lib_width_too_small(Config) -> %% Test that the time for a huge message queue is not %% significantly slower than with an empty message queue. io_with_huge_message_queue(Config) when is_list(Config) -> - case test_server:is_native(gen) of - true -> + case {test_server:is_native(gen),test_server:is_cover()} of + {true,_} -> {skip, "gen is native - huge message queue optimization " "is not implemented"}; - false -> + {_,true} -> + {skip,"Running under cover"}; + {false,false} -> do_io_with_huge_message_queue(Config) end. @@ -2246,19 +2280,23 @@ do_io_with_huge_message_queue(Config) -> PrivDir = ?privdir(Config), File = filename:join(PrivDir, "slask"), {ok, F1} = file:open(File, [write]), - - {Time,ok} = timer:tc(fun() -> writes(1000, F1) end), + Test = fun(Times) -> + {Time,ok} = timer:tc(fun() -> writes(Times, F1) end), + Time + end, + {Times,EmptyTime} = calibrate(100, Test), [self() ! {msg,N} || N <- lists:seq(1, 500000)], erlang:garbage_collect(), - {NewTime,ok} = timer:tc(fun() -> writes(1000, F1) end), + FullTime = Test(Times), file:close(F1), - io:format("Time for empty message queue: ~p", [Time]), - io:format("Time for huge message queue: ~p", [NewTime]), + file:delete(File), + io:format("Number of writes: ~p", [Times]), + io:format("Time for empty message queue: ~p", [EmptyTime]), + io:format("Time for huge message queue: ~p", [FullTime]), - IsCover = test_server:is_cover(), - case (NewTime+1) / (Time+1) of - Q when Q < 10; IsCover -> + case (FullTime+1) / (EmptyTime+1) of + Q when Q < 10 -> ok; Q -> io:format("Q = ~p", [Q]), @@ -2266,13 +2304,130 @@ do_io_with_huge_message_queue(Config) -> end, ok. +%% Make sure that the time is not too short. That could cause the +%% test case to fail. +calibrate(N, Test) when N =< 100000 -> + case Test(N) of + Time when Time < 50000 -> + calibrate(10*N, Test); + Time -> + {N,Time} + end; +calibrate(N, _) -> + N. + writes(0, _) -> ok; writes(N, F1) -> file:write(F1, "hello\n"), writes(N - 1, F1). -format_string(Config) -> +format_string(_Config) -> %% All but padding is tested by fmt/2. "xxxxxxsssx" = fmt("~10.4.xs", ["sss"]), "xxxxxxsssx" = fmt("~10.4.*s", [$x, "sss"]), ok. + +maps(_Config) -> + %% Note that order in which a map is printed is arbitrary. In + %% practice, small maps (non-HAMT) are printed in key order, but + %% the breakpoint for creating big maps (HAMT) is lower in the + %% debug-compiled run-time system than in the optimized run-time + %% system. + %% + %% Therefore, play it completely safe by not assuming any order + %% in a map with more than one element. + + "#{}" = fmt("~w", [#{}]), + "#{a=>b}" = fmt("~w", [#{a=>b}]), + re_fmt(<<"#\\{(a=>b|c=>d),[.][.][.]=>[.][.][.]\\}">>, + "~W", [#{a=>b,c=>d},2]), + re_fmt(<<"#\\{(a=>b|c=>d|e=>f),[.][.][.]=>[.][.][.],[.][.][.]\\}">>, + "~W", [#{a=>b,c=>d,e=>f},2]), + + "#{}" = fmt("~p", [#{}]), + "#{a => b}" = fmt("~p", [#{a=>b}]), + "#{...}" = fmt("~P", [#{a=>b},1]), + re_fmt(<<"#\\{(a => b|c => d),[.][.][.]\\}">>, + "~P", [#{a=>b,c=>d},2]), + re_fmt(<<"#\\{(a => b|c => d|e => f),[.][.][.]\\}">>, + "~P", [#{a=>b,c=>d,e=>f},2]), + + List = [{I,I*I} || I <- lists:seq(1, 20)], + Map = maps:from_list(List), + + "#{...}" = fmt("~P", [Map,1]), + + %% Print a map and parse it back to a map. + S = fmt("~p\n", [Map]), + io:format("~p\n", [S]), + Map = parse_map(S), + + %% Smoke test of a map as key. + MapAsKey = #{Map => "value"}, + io:format("~s\n", [fmt("~p", [MapAsKey])]), + ok. + +re_fmt(Pattern, Format, Args) -> + S = list_to_binary(fmt(Format, Args)), + case re:run(S, Pattern, [{capture,none}]) of + nomatch -> + io:format("Pattern: ~s", [Pattern]), + io:format("Result: ~s", [S]), + ?t:fail(); + match -> + ok + end. + +%% Parse a map consisting of integer keys and values. +parse_map(S0) -> + S1 = parse_expect(S0, "#{"), + {M,S2} = parse_map_1(S1), + S = parse_expect(S2, "}"), + S = "", + M. + +parse_map_1(S0) -> + {Key,S1} = parse_number(S0), + S2 = parse_expect(S1, "=>"), + {Val,S3} = parse_number(S2), + case S3 of + ","++S4 -> + S5 = parse_skip_ws(S4), + {Map,S} = parse_map_1(S5), + {Map#{Key=>Val},S}; + S -> + {#{Key=>Val},S} + end. + +parse_number(S) -> + parse_number(S, none). + +parse_number([C|S], Acc0) when $0 =< C, C =< $9 -> + Acc = case Acc0 of + none -> 0; + _ when is_integer(Acc0) -> Acc0 + end, + parse_number(S, Acc*10+C-$0); +parse_number(S, Acc) -> + {Acc,parse_skip_ws(S)}. + +parse_expect([H|T1], [H|T2]) -> + parse_expect(T1, T2); +parse_expect(S, []) -> + parse_skip_ws(S). + +parse_skip_ws([C|S]) when C =< $\s -> + parse_skip_ws(S); +parse_skip_ws(S) -> + S. + +%% Cover the last uncovered lines for completeness. +coverage(_Config) -> + S1 = io_lib_pretty:print({a,term}, fun(_, _) -> no end), + io:format("~s\n", [S1]), + + %% The tuple of arity three will be ignored. + S2 = io_lib_pretty:print(lists:seq(1, 100), [{depth,1,1}]), + io:format("~s\n", [S2]), + + ok. diff --git a/lib/stdlib/test/io_proto_SUITE.erl b/lib/stdlib/test/io_proto_SUITE.erl index 1337b7dde2..811c7ed7bb 100644 --- a/lib/stdlib/test/io_proto_SUITE.erl +++ b/lib/stdlib/test/io_proto_SUITE.erl @@ -1378,47 +1378,43 @@ rtnode(C,N) -> rtnode(Commands,Nodename,ErlPrefix) -> rtnode(Commands,Nodename,ErlPrefix,[]). rtnode(Commands,Nodename,ErlPrefix,Extra) -> - ?line case get_progs() of - {error,_Reason} -> - ?line {skip,"No runerl present"}; - {RunErl,ToErl,Erl} -> - ?line case create_tempdir() of - {error, Reason2} -> - ?line {skip, Reason2}; - Tempdir -> - ?line SPid = - start_runerl_node(RunErl,ErlPrefix++ - "\\\""++Erl++"\\\"", - Tempdir,Nodename, Extra), - ?line CPid = start_toerl_server(ToErl,Tempdir), - ?line erase(getline_skipped), - ?line Res = - (catch get_and_put(CPid, Commands,1)), - ?line case stop_runerl_node(CPid) of - {error,_} -> - ?line CPid2 = - start_toerl_server - (ToErl,Tempdir), - ?line erase(getline_skipped), - ?line ok = get_and_put - (CPid2, - [{putline,[7]}, - {sleep, - timeout(short)}, - {putline,""}, - {getline," -->"}, - {putline,"s"}, - {putline,"c"}, - {putline,""}],1), - ?line stop_runerl_node(CPid2); - _ -> - ?line ok - end, - ?line wait_for_runerl_server(SPid), - ?line ok = ?RM_RF(Tempdir), - ?line ok = Res - end - end. + case get_progs() of + {error,_Reason} -> + {skip,"No runerl present"}; + {RunErl,ToErl,Erl} -> + case create_tempdir() of + {error, Reason2} -> + {skip, Reason2}; + Tempdir -> + SPid = start_runerl_node(RunErl, ErlPrefix++ + "\\\""++Erl++"\\\"", + Tempdir, Nodename, Extra), + CPid = start_toerl_server(ToErl, Tempdir), + put(getline_skipped, []), + Res = (catch get_and_put(CPid, Commands, 1)), + case stop_runerl_node(CPid) of + {error,_} -> + CPid2 = start_toerl_server(ToErl, Tempdir), + put(getline_skipped, []), + ok = get_and_put + (CPid2, + [{putline,[7]}, + {sleep, + timeout(short)}, + {putline,""}, + {getline," -->"}, + {putline,"s"}, + {putline,"c"}, + {putline,""}], 1), + stop_runerl_node(CPid2); + _ -> + ok + end, + wait_for_runerl_server(SPid), + ok = ?RM_RF(Tempdir), + ok = Res + end + end. timeout(long) -> 2 * timeout(normal); @@ -1462,57 +1458,51 @@ get_and_put(CPid, [{sleep, X}|T],N) -> after X -> get_and_put(CPid,T,N+1) end; -get_and_put(CPid, [{getline, Match}|T],N) -> +get_and_put(CPid, [{getline_pred,Pred,Msg}|T]=T0, N) + when is_function(Pred) -> ?dbg({getline, Match}), CPid ! {self(), {get_line, timeout(normal)}}, receive {get_line, timeout} -> error_logger:error_msg("~p: getline timeout waiting for \"~s\" " "(command number ~p, skipped: ~p)~n", - [?MODULE, Match,N,get(getline_skipped)]), + [?MODULE,Msg,N,get(getline_skipped)]), {error, timeout}; {get_line, Data} -> ?dbg({data,Data}), - case lists:prefix(Match, Data) of - true -> - erase(getline_skipped), + case Pred(Data) of + yes -> + put(getline_skipped, []), get_and_put(CPid, T,N+1); - false -> - case get(getline_skipped) of - undefined -> - put(getline_skipped,[Data]); - List -> - put(getline_skipped,List ++ [Data]) - end, - get_and_put(CPid, [{getline, Match}|T],N) + no -> + error_logger:error_msg("~p: getline match failure " + "\"~s\" " + "(command number ~p)\n", + [?MODULE,Msg,N]), + {error, no_match}; + maybe -> + List = get(getline_skipped), + put(getline_skipped, List ++ [Data]), + get_and_put(CPid, T0, N) end end; +get_and_put(CPid, [{getline, Match}|T],N) -> + ?dbg({getline, Match}), + F = fun(Data) -> + case lists:prefix(Match, Data) of + true -> yes; + false -> maybe + end + end, + get_and_put(CPid, [{getline_pred,F,Match}|T], N); get_and_put(CPid, [{getline_re, Match}|T],N) -> - ?dbg({getline_re, Match}), - CPid ! {self(), {get_line, timeout(normal)}}, - receive - {get_line, timeout} -> - error_logger:error_msg("~p: getline_re timeout waiting for \"~s\" " - "(command number ~p, skipped: ~p)~n", - [?MODULE, Match,N,get(getline_skipped)]), - {error, timeout}; - {get_line, Data} -> - ?dbg({data,Data}), - case re:run(Data, Match,[{capture,none}]) of - match -> - erase(getline_skipped), - get_and_put(CPid, T,N+1); - _ -> - case get(getline_skipped) of - undefined -> - put(getline_skipped,[Data]); - List -> - put(getline_skipped,List ++ [Data]) - end, - get_and_put(CPid, [{getline_re, Match}|T],N) - end - end; - + F = fun(Data) -> + case re:run(Data, Match, [{capture,none}]) of + match -> yes; + _ -> maybe + end + end, + get_and_put(CPid, [{getline_pred,F,Match}|T], N); get_and_put(CPid, [{putline_raw, Line}|T],N) -> ?dbg({putline_raw, Line}), CPid ! {self(), {send_line, Line}}, @@ -1801,10 +1791,22 @@ get_data_within(Port, Timeout, Acc) -> end. get_default_shell() -> + Match = fun(Data) -> + case lists:prefix("undefined", Data) of + true -> + yes; + false -> + case re:run(Data, "<\\d+[.]\\d+[.]\\d+>", + [{capture,none}]) of + match -> no; + _ -> maybe + end + end + end, try rtnode([{putline,""}, {putline, "whereis(user_drv)."}, - {getline, "undefined"}],[]), + {getline_pred, Match, "matching of user_drv pid"}], []), old catch _E:_R -> ?dbg({_E,_R}), diff --git a/lib/stdlib/test/lists_SUITE.erl b/lib/stdlib/test/lists_SUITE.erl index e886a797f0..a0f7fd2744 100644 --- a/lib/stdlib/test/lists_SUITE.erl +++ b/lib/stdlib/test/lists_SUITE.erl @@ -38,13 +38,13 @@ % Test cases must be exported. -export([member/1, reverse/1, keymember/1, keysearch_keyfind/1, - keystore/1, keytake/1, + keystore/1, keytake/1, keyreplace/1, append_1/1, append_2/1, seq_loop/1, seq_2/1, seq_3/1, seq_2_e/1, seq_3_e/1, sublist_2/1, sublist_3/1, sublist_2_e/1, sublist_3_e/1, flatten_1/1, flatten_2/1, flatten_1_e/1, flatten_2_e/1, - dropwhile/1, + dropwhile/1, takewhile/1, sort_1/1, sort_stable/1, merge/1, rmerge/1, sort_rand/1, usort_1/1, usort_stable/1, umerge/1, rumerge/1,usort_rand/1, keymerge/1, rkeymerge/1, @@ -62,7 +62,7 @@ zip_unzip/1, zip_unzip3/1, zipwith/1, zipwith3/1, filter_partition/1, otp_5939/1, otp_6023/1, otp_6606/1, otp_7230/1, - suffix/1, subtract/1, droplast/1]). + suffix/1, subtract/1, droplast/1, hof/1]). %% Sort randomized lists until stopped. %% @@ -81,37 +81,51 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [{group, append}, reverse, member, keymember, - keysearch_keyfind, keystore, keytake, dropwhile, {group,sort}, - {group, usort}, {group, keysort}, {group, ukeysort}, - {group, funsort}, {group, ufunsort}, {group, sublist}, - {group, flatten}, {group, seq}, zip_unzip, zip_unzip3, - zipwith, zipwith3, filter_partition, {group, tickets}, - suffix, subtract]. + [{group, append}, + {group, key}, + {group,sort}, + {group, usort}, + {group, keysort}, + {group, ukeysort}, + {group, funsort}, + {group, ufunsort}, + {group, sublist}, + {group, flatten}, + {group, seq}, + {group, tickets}, + {group, zip}, + {group, misc}]. groups() -> - [{append, [], [append_1, append_2]}, - {usort, [], + [{append, [parallel], [append_1, append_2]}, + {usort, [parallel], [umerge, rumerge, usort_1, usort_rand, usort_stable]}, - {keysort, [], + {keysort, [parallel], [keymerge, rkeymerge, keysort_1, keysort_rand, keysort_i, keysort_stable, keysort_error]}, - {sort,[],[merge, rmerge, sort_1, sort_rand]}, - {ukeysort, [], + {key, [parallel], [keymember, keysearch_keyfind, keystore, + keytake, keyreplace]}, + {sort,[parallel],[merge, rmerge, sort_1, sort_rand]}, + {ukeysort, [parallel], [ukeymerge, rukeymerge, ukeysort_1, ukeysort_rand, ukeysort_i, ukeysort_stable, ukeysort_error]}, - {funsort, [], + {funsort, [parallel], [funmerge, rfunmerge, funsort_1, funsort_stable, funsort_error, funsort_rand]}, - {ufunsort, [], + {ufunsort, [parallel], [ufunmerge, rufunmerge, ufunsort_1, ufunsort_stable, ufunsort_error, ufunsort_rand]}, - {seq, [], [seq_loop, seq_2, seq_3, seq_2_e, seq_3_e]}, - {sublist, [], + {seq, [parallel], [seq_loop, seq_2, seq_3, seq_2_e, seq_3_e]}, + {sublist, [parallel], [sublist_2, sublist_3, sublist_2_e, sublist_3_e]}, - {flatten, [], + {flatten, [parallel], [flatten_1, flatten_2, flatten_1_e, flatten_2_e]}, - {tickets, [], [otp_5939, otp_6023, otp_6606, otp_7230]}]. + {tickets, [parallel], [otp_5939, otp_6023, otp_6606, otp_7230]}, + {zip, [parallel], [zip_unzip, zip_unzip3, zipwith, zipwith3]}, + {misc, [parallel], [reverse, member, dropwhile, takewhile, + filter_partition, suffix, subtract, + hof]} + ]. init_per_suite(Config) -> Config. @@ -345,6 +359,33 @@ dropwhile(Config) when is_list(Config) -> ok. +takewhile(Config) when is_list(Config) -> + F = fun(C) -> C =/= $@ end, + + [] = lists:takewhile(F, []), + [a] = lists:takewhile(F, [a]), + [a,b] = lists:takewhile(F, [a,b]), + [a,b,c] = lists:takewhile(F, [a,b,c]), + + [] = lists:takewhile(F, [$@]), + [] = lists:takewhile(F, [$@,$@]), + [a] = lists:takewhile(F, [a,$@]), + + [$k] = lists:takewhile(F, [$k,$@]), + [$k,$l] = lists:takewhile(F, [$k,$l,$@,$@]), + [a] = lists:takewhile(F, [a,$@,$@,$@]), + + [] = lists:takewhile(F, [$@,a,$@,b]), + [] = lists:takewhile(F, [$@,$@,a,$@,b]), + [] = lists:takewhile(F, [$@,$@,$@,a,$@,b]), + + Long = lists:seq(1, 1024), + Shorter = lists:seq(1, 400), + + Shorter = lists:takewhile(fun(E) -> E =< 400 end, Long), + + ok. + keystore(doc) -> ["OTP-XXX."]; keystore(suite) -> []; @@ -382,6 +423,17 @@ keytake(Config) when is_list(Config) -> ?line false = lists:keytake(4, 2, L), ok. +%% Test lists:keyreplace/4. +keyreplace(Config) when is_list(Config) -> + [{new,42}] = lists:keyreplace(k, 1, [{k,1}], {new,42}), + [atom,{new,a,b}] = lists:keyreplace(k, 1, [atom,{k,1}], {new,a,b}), + [a,{x,y,z}] = lists:keyreplace(a, 5, [a,{x,y,z}], {no,use}), + + %% Error cases. + {'EXIT',_} = (catch lists:keyreplace(k, 1, [], not_tuple)), + {'EXIT',_} = (catch lists:keyreplace(k, 0, [], {a,b})), + ok. + merge(doc) -> ["merge functions"]; merge(suite) -> []; merge(Config) when is_list(Config) -> @@ -2326,19 +2378,25 @@ sublist_3_e(Config) when is_list(Config) -> -define(flatten_error1(X), ?line {'EXIT', _} = (catch lists:flatten(X))). -define(flatten_error2(X,Y), ?line {'EXIT', _} = (catch lists:flatten(X,Y))). -flatten_1(doc) -> ["flatten/1"]; -flatten_1(suite) -> []; +%% Test lists:flatten/1,2 and lists:flatlength/1. flatten_1(Config) when is_list(Config) -> - ?line [] = lists:flatten([]), - ?line [1,2] = lists:flatten([1,2]), - ?line [1,2] = lists:flatten([1,[2]]), - ?line [1,2] = lists:flatten([[1],2]), - ?line [1,2] = lists:flatten([[1],[2]]), - ?line [1,2] = lists:flatten([[1,2]]), - ?line [a,b,c,d] = lists:flatten([[a],[b,c,[d]]]), + [] = lists_flatten([]), + [1,2] = lists_flatten([1,2]), + [1,2] = lists_flatten([1,[2]]), + [1,2] = lists_flatten([[1],2]), + [1,2] = lists_flatten([[1],[2]]), + [1,2] = lists_flatten([[1,2]]), + [a,b,c,d] = lists_flatten([[a],[b,c,[d]]]), ok. +lists_flatten(List) -> + Flat = lists:flatten(List), + Flat = lists:flatten(List, []), + Len = lists:flatlength(List), + Len = length(Flat), + Flat. + flatten_1_e(doc) -> ["flatten/1 error cases"]; flatten_1_e(suite) -> []; flatten_1_e(Config) when is_list(Config) -> @@ -2351,11 +2409,11 @@ flatten_1_e(Config) when is_list(Config) -> %%% clear-cut. Right now, I think that any term should be allowed. %%% But I also wish this function didn't exist at all. -flatten_2(doc) -> ["flatten/2"]; -flatten_2(suite) -> []; +%% Test lists:flatten/2. flatten_2(Config) when is_list(Config) -> - ?line [] = lists:flatten([]), - ?line [a] = lists:flatten([a]), + [] = lists:flatten([], []), + [a] = lists:flatten([a], []), + [a,b,c,[no,flatten]] = lists:flatten([[a,[b,c]]], [[no,flatten]]), ok. flatten_2_e(doc) -> ["flatten/2 error cases"]; @@ -2651,3 +2709,40 @@ droplast(Config) when is_list(Config) -> ?line {'EXIT', {function_clause, _}} = (catch lists:droplast(x)), ok. + +%% Briefly test the common high-order functions to ensure they +%% are covered. +hof(Config) when is_list(Config) -> + L = [1,2,3], + [1,4,9] = lists:map(fun(N) -> N*N end, L), + [1,4,5,6] = lists:flatmap(fun(1) -> [1]; + (2) -> []; + (3) -> [4,5,6] + end, L), + [{1,[a]},{2,[b]},{3,[c]}] = + lists:keymap(fun(A) -> [A] end, 2, [{1,a},{2,b},{3,c}]), + + [1,3] = lists:filter(fun(N) -> N rem 2 =:= 1 end, L), + FilterMapFun = fun(1) -> true; + (2) -> {true,42}; + (3) -> false + end, + [1,42] = lists:filtermap(FilterMapFun, L), + [1,42] = lists:zf(FilterMapFun, L), + + [3,2,1] = lists:foldl(fun(E, A) -> [E|A] end, [], L), + [1,2,3] = lists:foldr(fun(E, A) -> [E|A] end, [], L), + {[1,4,9],[3,2,1]} = lists:mapfoldl(fun(E, A) -> + {E*E,[E|A]} + end, [], L), + {[1,4,9],[1,2,3]} = lists:mapfoldr(fun(E, A) -> + {E*E,[E|A]} + end, [], L), + + true = lists:any(fun(N) -> N =:= 2 end, L), + false = lists:any(fun(N) -> N =:= 42 end, L), + + true = lists:all(fun(N) -> is_integer(N) end, L), + false = lists:all(fun(N) -> N rem 2 =:= 0 end, L), + + ok. diff --git a/lib/stdlib/test/proc_lib_SUITE.erl b/lib/stdlib/test/proc_lib_SUITE.erl index 36f009eec6..f7a6a38138 100644 --- a/lib/stdlib/test/proc_lib_SUITE.erl +++ b/lib/stdlib/test/proc_lib_SUITE.erl @@ -28,7 +28,7 @@ init_per_group/2,end_per_group/2, crash/1, sync_start_nolink/1, sync_start_link/1, spawn_opt/1, sp1/0, sp2/0, sp3/1, sp4/2, sp5/1, - hibernate/1, stop/1]). + hibernate/1, stop/1, t_format/1]). -export([ otp_6345/1, init_dont_hang/1]). -export([hib_loop/1, awaken/1]). @@ -51,7 +51,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [crash, {group, sync_start}, spawn_opt, hibernate, - {group, tickets}, stop]. + {group, tickets}, stop, t_format]. groups() -> [{tickets, [], [otp_6345, init_dont_hang]}, @@ -80,77 +80,123 @@ end_per_group(_GroupName, Config) -> crash(Config) when is_list(Config) -> error_logger:add_report_handler(?MODULE, self()), - Pid = proc_lib:spawn(?MODULE, sp1, []), - Pid ! die, - ?line Report = receive - {crash_report, Pid, Report0} -> Report0 - after 2000 -> test_server:fail(no_crash_report) - end, - ?line proc_lib:format(Report), - ?line [PidRep, []] = Report, - ?line {value, {initial_call,{?MODULE,sp1,[]}}} = - lists:keysearch(initial_call, 1, PidRep), - Self = self(), - ?line {value, {ancestors,[Self]}} = - lists:keysearch(ancestors, 1, PidRep), - ?line {value, {error_info,{exit,die,_StackTrace1}}} = - lists:keysearch(error_info, 1, PidRep), - - F = fun sp1/0, - Pid1 = proc_lib:spawn(node(), F), - Pid1 ! die, - ?line [PidRep1, []] = receive - {crash_report, Pid1, Report1} -> Report1 - after 2000 -> test_server:fail(no_crash_report) - end, - ?line {value, {initial_call,{Fmod,Fname,[]}}} = - lists:keysearch(initial_call, 1, PidRep1), - ?line {module,Fmod} = erlang:fun_info(F, module), - ?line {name,Fname} = erlang:fun_info(F, name), - ?line {value, {ancestors,[Self]}} = - lists:keysearch(ancestors, 1, PidRep1), - ?line {value, {error_info,{exit,die,_StackTrace2}}} = - lists:keysearch(error_info, 1, PidRep1), - - Pid2 = proc_lib:spawn(?MODULE, sp2, []), - test_server:sleep(100), - ?line {?MODULE,sp2,[]} = proc_lib:initial_call(Pid2), - ?line {?MODULE,sp2,0} = proc_lib:translate_initial_call(Pid2), - Pid2 ! die, - ?line [Pid2Rep, [{neighbour, LinkRep}]] = - receive - {crash_report, Pid2, Report2} -> Report2 - after 2000 -> test_server:fail(no_crash_report) - end, - ?line {value, {initial_call,{?MODULE,sp2,[]}}} = - lists:keysearch(initial_call, 1, Pid2Rep), - ?line {value, {ancestors,[Self]}} = - lists:keysearch(ancestors, 1, Pid2Rep), - ?line {value, {error_info,{exit,die,_StackTrace3}}} = - lists:keysearch(error_info, 1, Pid2Rep), - ?line {value, {initial_call,{?MODULE,sp1,[]}}} = - lists:keysearch(initial_call, 1, LinkRep), - %% Make sure that we don't get a crash report if a process %% terminates with reason 'shutdown' or reason {shutdown,Reason}. - ?line process_flag(trap_exit, true), - ?line Pid3 = proc_lib:spawn_link(erlang, apply, - [fun() -> exit(shutdown) end,[]]), + process_flag(trap_exit, true), + Pid0 = proc_lib:spawn_link(erlang, apply, + [fun() -> exit(shutdown) end,[]]), + Pid1 = proc_lib:spawn_link(erlang, apply, + [fun() -> exit({shutdown,{a,b,c}}) end,[]]), + + receive {'EXIT',Pid0,shutdown} -> ok end, + receive {'EXIT',Pid1,{shutdown,{a,b,c}}} -> ok end, + process_flag(trap_exit, false), + %% We expect any unexpected messages to be caught below, + %% so we don't have explicitly wait some time to be sure. + + %% Spawn export function. + Pid2 = proc_lib:spawn(?MODULE, sp1, []), + Pid2 ! die, + Exp2 = [{initial_call,{?MODULE,sp1,[]}}, + {ancestors,[self()]}, + {error_info,{exit,die,{stacktrace}}}], + analyse_crash(Pid2, Exp2, []), - ?line Pid4 = proc_lib:spawn_link(erlang, apply, - [fun() -> exit({shutdown,{a,b,c}}) end,[]]), + %% Spawn fun. + F = fun sp1/0, + Pid3 = proc_lib:spawn(node(), F), + Pid3 ! die, + {module,?MODULE} = erlang:fun_info(F, module), + {name,Fname} = erlang:fun_info(F, name), + Exp3 = [{initial_call,{?MODULE,Fname,[]}}, + {ancestors,[self()]}, + {error_info,{exit,die,{stacktrace}}}], + analyse_crash(Pid3, Exp3, []), - ?line receive {'EXIT',Pid3,shutdown} -> ok end, - ?line receive {'EXIT',Pid4,{shutdown,{a,b,c}}} -> ok end, - ?line process_flag(trap_exit, false), + %% Spawn function with neighbour. + Pid4 = proc_lib:spawn(?MODULE, sp2, []), + test_server:sleep(100), + {?MODULE,sp2,[]} = proc_lib:initial_call(Pid4), + {?MODULE,sp2,0} = proc_lib:translate_initial_call(Pid4), + Pid4 ! die, + Exp4 = [{initial_call,{?MODULE,sp2,[]}}, + {ancestors,[self()]}, + {error_info,{exit,die,{stacktrace}}}], + Links4 = [[{initial_call,{?MODULE,sp1,[]}}, + {ancestors,[Pid4,self()]}]], + analyse_crash(Pid4, Exp4, Links4), + + %% Make sure that we still get a crash report if the + %% process dictionary have been tampered with. + + Pid5 = proc_lib:spawn(erlang, apply, + [fun() -> + erase(), + exit(abnormal) + end,[]]), + Exp5 = [{initial_call,absent}, + {ancestors,[]}, + {error_info,{exit,abnormal,{stacktrace}}}], + analyse_crash(Pid5, Exp5, []), + + error_logger:delete_report_handler(?MODULE), + ok. +analyse_crash(Pid, Expected0, ExpLinks) -> + Expected = [{pid,Pid}|Expected0], receive - Any -> - ?line ?t:fail({unexpected_message,Any}) - after 2000 -> - ok - end. + {crash_report, Pid, Report} -> + _ = proc_lib:format(Report), %Smoke test. + [Crash,Links] = Report, + analyse_crash_1(Expected, Crash), + analyse_links(ExpLinks, Links); + Unexpected -> + io:format("~p\n", [Unexpected]), + test_server:fail(unexpected_message) + after 5000 -> + test_server:fail(no_crash_report) + end. +analyse_links([H|Es], [{neighbour,N}|Links]) -> + analyse_crash_1(H, N), + analyse_links(Es, Links); +analyse_links([], []) -> + ok. + +analyse_crash_1([{Key,absent}|T], Report) -> + false = lists:keymember(Key, 1, Report), + analyse_crash_1(T, Report); +analyse_crash_1([{Key,Pattern}|T], Report) -> + case lists:keyfind(Key, 1, Report) of + false -> + io:format("~p", [Report]), + test_server:fail({missing_key,Key}); + {Key,Info} -> + try + match_info(Pattern, Info) + catch + no_match -> + io:format("key: ~p", [Key]), + io:format("pattern: ~p", [Pattern]), + io:format("actual: ~p", [Report]), + test_server:fail(no_match) + end, + analyse_crash_1(T, Report) + end; +analyse_crash_1([], _Report) -> + []. + +match_info(T, T) -> + ok; +match_info({stacktrace}, Stk) when is_list(Stk) -> + ok; +match_info([H1|T1], [H2|T2]) -> + match_info(H1, H2), + match_info(T1, T2); +match_info(Tuple1, Tuple2) when tuple_size(Tuple1) =:= tuple_size(Tuple2) -> + match_info(tuple_to_list(Tuple1), tuple_to_list(Tuple2)); +match_info(_, _) -> + throw(no_match). sync_start_nolink(Config) when is_list(Config) -> _Pid = spawn_link(?MODULE, sp5, [self()]), @@ -301,6 +347,7 @@ hibernate(Config) when is_list(Config) -> ?line {value,{initial_call,{?MODULE,hib_loop,[_]}}} = lists:keysearch(initial_call, 1, Report), + error_logger:delete_report_handler(?MODULE), ok. hib_loop(LoopData) -> @@ -364,7 +411,7 @@ init_dont_hang(Config) when is_list(Config) -> end. init_dont_hang_init(_Parent) -> - 1 = 2. + error(bad_init). %% Test proc_lib:stop/1,3 stop(_Config) -> @@ -448,10 +495,55 @@ stop(_Config) -> ok. system_terminate(crash,_Parent,_Deb,_State) -> - 1 = 2; + error({badmatch,2}); system_terminate(Reason,_Parent,_Deb,_State) -> exit(Reason). + +t_format(_Config) -> + error_logger:tty(false), + try + t_format() + after + error_logger:tty(true) + end, + ok. + +t_format() -> + error_logger:add_report_handler(?MODULE, self()), + Pid = proc_lib:spawn(fun t_format_looper/0), + HugeData = gb_sets:from_list(lists:seq(1, 100)), + Pid ! {die,HugeData}, + Report = receive + {crash_report, Pid, Report0} -> Report0 + end, + Usz = do_test_format(Report, unlimited), + Tsz = do_test_format(Report, 20), + + if + Tsz >= Usz -> + ?t:fail(); + true -> + ok + end, + + ok. + +do_test_format(Report, Depth) -> + io:format("*** Depth = ~p", [Depth]), + S0 = proc_lib:format(Report, latin1, Depth), + S = lists:flatten(S0), + io:put_chars(S), + length(S). + +t_format_looper() -> + receive + {die,Data} -> + exit(Data); + _ -> + t_format_looper() + end. + %%----------------------------------------------------------------- %% The error_logger handler used. %%----------------------------------------------------------------- diff --git a/lib/stdlib/test/qlc_SUITE.erl b/lib/stdlib/test/qlc_SUITE.erl index 72216bfa0d..52fdb69b73 100644 --- a/lib/stdlib/test/qlc_SUITE.erl +++ b/lib/stdlib/test/qlc_SUITE.erl @@ -74,6 +74,7 @@ otp_5644/1, otp_5195/1, otp_6038_bug/1, otp_6359/1, otp_6562/1, otp_6590/1, otp_6673/1, otp_6964/1, otp_7114/1, otp_7238/1, otp_7232/1, otp_7552/1, otp_6674/1, otp_7714/1, otp_11758/1, + otp_12946/1, manpage/1, @@ -143,7 +144,7 @@ groups() -> {tickets, [], [otp_5644, otp_5195, otp_6038_bug, otp_6359, otp_6562, otp_6590, otp_6673, otp_6964, otp_7114, otp_7232, - otp_7238, otp_7552, otp_6674, otp_7714, otp_11758]}, + otp_7238, otp_7552, otp_6674, otp_7714, otp_11758, otp_12946]}, {compat, [], [backward, forward]}]. init_per_suite(Config) -> @@ -7154,6 +7155,18 @@ otp_6674(Config) when is_list(Config) -> ?line run(Config, Ts). +otp_12946(doc) -> + ["Syntax error."]; +otp_12946(suite) -> []; +otp_12946(Config) when is_list(Config) -> + Text = + <<"-export([init/0]). + init() -> + ok. + y">>, + {errors,[{4,erl_parse,_}],[]} = compile_file(Config, Text, []), + ok. + manpage(doc) -> "Examples from qlc(3)."; manpage(suite) -> []; diff --git a/lib/stdlib/test/rand_SUITE.erl b/lib/stdlib/test/rand_SUITE.erl index b03caebe91..03b5ce1a25 100644 --- a/lib/stdlib/test/rand_SUITE.erl +++ b/lib/stdlib/test/rand_SUITE.erl @@ -25,7 +25,9 @@ ]). -export([interval_int/1, interval_float/1, seed/1, - api_eq/1, reference/1, basic_stats/1, + api_eq/1, reference/1, + basic_stats_uniform_1/1, basic_stats_uniform_2/1, + basic_stats_normal/1, plugin/1, measure/1 ]). @@ -51,11 +53,13 @@ all() -> [seed, interval_int, interval_float, api_eq, reference, - basic_stats, + {group, basic_stats}, plugin, measure ]. -groups() -> []. +groups() -> + [{basic_stats, [parallel], + [basic_stats_uniform_1, basic_stats_uniform_2, basic_stats_normal]}]. init_per_suite(Config) -> Config. end_per_suite(_Config) -> ok. @@ -122,6 +126,9 @@ seed_1(Alg) -> false = (S1 =:= rand:seed_s(Alg)), %% Negative integers works _ = rand:seed_s(Alg, {-1,-1,-1}), + %% Check that export_seed/1 returns 'undefined' if there is no seed + erase(rand_seed), + undefined = rand:export_seed(), %% Other term do not work {'EXIT', _} = (catch rand:seed_s(foobar, os:timestamp())), @@ -291,14 +298,19 @@ gen(_, _, Acc) -> lists:reverse(Acc). %% The algorithms must have good properties to begin with %% -basic_stats(doc) -> ["Check that the algorithms generate sound values."]; -basic_stats(suite) -> []; -basic_stats(Config) when is_list(Config) -> - io:format("Testing uniform~n",[]), +%% Check that the algorithms generate sound values. + +basic_stats_uniform_1(Config) when is_list(Config) -> [basic_uniform_1(?LOOP, rand:seed_s(Alg), 0.0, array:new([{default, 0}])) || Alg <- algs()], + ok. + +basic_stats_uniform_2(Config) when is_list(Config) -> [basic_uniform_2(?LOOP, rand:seed_s(Alg), 0, array:new([{default, 0}])) || Alg <- algs()], + ok. + +basic_stats_normal(Config) when is_list(Config) -> io:format("Testing normal~n",[]), [basic_normal_1(?LOOP, rand:seed_s(Alg), 0, 0) || Alg <- algs()], ok. diff --git a/lib/stdlib/test/re_SUITE.erl b/lib/stdlib/test/re_SUITE.erl index b8c20d9745..d78d6153da 100644 --- a/lib/stdlib/test/re_SUITE.erl +++ b/lib/stdlib/test/re_SUITE.erl @@ -28,7 +28,7 @@ pcre_compile_workspace_overflow/1,re_infinite_loop/1, re_backwards_accented/1,opt_dupnames/1,opt_all_names/1,inspect/1, opt_no_start_optimize/1,opt_never_utf/1,opt_ucp/1, - match_limit/1,sub_binaries/1]). + match_limit/1,sub_binaries/1,copt/1]). -include_lib("test_server/include/test_server.hrl"). -include_lib("kernel/include/file.hrl"). @@ -319,32 +319,26 @@ replace_return(doc) -> ["Tests return options of replace together with global searching"]; replace_return(Config) when is_list(Config) -> Dog = ?t:timetrap(?t:minutes(3)), - ?line {'EXIT',{badarg,_}} = (catch re:replace("na","(a","")), - ?line <<"nasse">> = re:replace(<<"nisse">>,"i","a",[{return,binary}]), - ?line <<"ABCÅXABCXA">> = re:replace("ABC\305abcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,binary}]), - - ?line [<<"ABCÅ">>, - <<"X">>, - <<"ABC">>, - <<"X">> | - <<"A">> ] = - re:replace("ABCÅabcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,iodata}]), - ?line "ABCÅXABCXA" = re:replace("ABCÅabcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,list},unicode]), - ?line <<65,66,67,195,133,88,65,66,67,88,65>> = re:replace("ABCÅabcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,binary},unicode]), - ?line <<65,66,67,195,133,88,65,66,67,97,98,99,100,65>> = re:replace("ABCÅabcdABCabcdA","a(?<FOO>bcd)","X",[{return,binary},unicode]), - ?line <<"iXk">> = re:replace("abcdefghijk","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\9X",[{return,binary}]), - ?line <<"jXk">> = re:replace("abcdefghijk","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\10X",[{return,binary}]), - ?line <<"Xk">> = re:replace("abcdefghijk","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\11X",[{return,binary}]), - ?line <<"9X1">> = re:replace("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g9X",[{return,binary}]), - ?line <<"0X1">> = re:replace("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g10X",[{return,binary}]), - ?line <<"X1">> = re:replace("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g11X",[{return,binary}]), - ?line <<"971">> = re:replace("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g{9}7",[{return,binary}]), - ?line <<"071">> = re:replace("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g{10}7",[{return,binary}]), - ?line <<"71">> = re:replace("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g{11}7",[{return,binary}]), - ?line "a\x{400}bcX" = re:replace("a\x{400}bcd","d","X",[global,{return,list},unicode]), - ?line <<"a",208,128,"bcX">> = re:replace("a\x{400}bcd","d","X",[global,{return,binary},unicode]), - ?line "a\x{400}bcd" = re:replace("a\x{400}bcd","Z","X",[global,{return,list},unicode]), - ?line <<"a",208,128,"bcd">> = re:replace("a\x{400}bcd","Z","X",[global,{return,binary},unicode]), + {'EXIT',{badarg,_}} = (catch re:replace("na","(a","")), + ok = replacetest(<<"nisse">>,"i","a",[{return,binary}],<<"nasse">>), + ok = replacetest("ABC\305abcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,binary}],<<"ABCÅXABCXA">>), + ok = replacetest("ABCÅabcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,iodata}],[<<"ABCÅ">>,<<"X">>,<<"ABC">>,<<"X">>|<<"A">>]), + ok = replacetest("ABCÅabcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,list},unicode],"ABCÅXABCXA"), + ok = replacetest("ABCÅabcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,binary},unicode],<<65,66,67,195,133,88,65,66,67,88,65>>), + ok = replacetest("ABCÅabcdABCabcdA","a(?<FOO>bcd)","X",[{return,binary},unicode],<<65,66,67,195,133,88,65,66,67,97,98,99,100,65>>), + ok = replacetest("abcdefghijk","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\9X",[{return,binary}],<<"iXk">>), + ok = replacetest("abcdefghijk","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\10X",[{return,binary}],<<"jXk">>), + ok = replacetest("abcdefghijk","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\11X",[{return,binary}],<<"Xk">>), + ok = replacetest("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g9X",[{return,binary}],<<"9X1">>), + ok = replacetest("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g10X",[{return,binary}],<<"0X1">>), + ok = replacetest("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g11X",[{return,binary}],<<"X1">>), + ok = replacetest("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g{9}7",[{return,binary}],<<"971">>), + ok = replacetest("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g{10}7",[{return,binary}],<<"071">>), + ok = replacetest("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g{11}7",[{return,binary}],<<"71">>), + ok = replacetest("a\x{400}bcd","d","X",[global,{return,list},unicode],"a\x{400}bcX"), + ok = replacetest("a\x{400}bcd","d","X",[global,{return,binary},unicode],<<"a",208,128,"bcX">>), + ok = replacetest("a\x{400}bcd","Z","X",[global,{return,list},unicode],"a\x{400}bcd"), + ok = replacetest("a\x{400}bcd","Z","X",[global,{return,binary},unicode],<<"a",208,128,"bcd">>), ?t:timetrap_cancel(Dog), ok. @@ -389,6 +383,35 @@ crtest(Subject,RE,Options,true,Result) -> error end. +replacetest(Subject,RE,Replacement,Options,Result) -> + Result = re:replace(Subject,RE,Replacement,Options), + {CompileOptions,ReplaceOptions} = lists:partition(fun copt/1, Options), + {ok,MP} = re:compile(RE,CompileOptions), + Result = re:replace(Subject,MP,Replacement,ReplaceOptions), + ok. + +splittest(Subject,RE,Options,Result) -> + Result = re:split(Subject,RE,Options), + {CompileOptions,SplitOptions} = lists:partition(fun copt/1, Options), + {ok,MP} = re:compile(RE,CompileOptions), + Result = re:split(Subject,MP,SplitOptions), + ok. + +copt(caseless) -> true; +copt(no_start_optimize) -> true; +copt(never_utf) -> true; +copt(ucp) -> true; +copt(dollar_endonly) -> true; +copt(dotall) -> true; +copt(extended) -> true; +copt(firstline) -> true; +copt(multiline) -> true; +copt(no_auto_capture) -> true; +copt(dupnames) -> true; +copt(ungreedy) -> true; +copt(unicode) -> true; +copt(_) -> false. + split_autogen(doc) -> ["Test split with autogenerated erlang module"]; split_autogen(Config) when is_list(Config) -> @@ -401,43 +424,23 @@ split_options(doc) -> ["Test special options to split."]; split_options(Config) when is_list(Config) -> Dog = ?t:timetrap(?t:minutes(1)), - ?line [[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>]] = re:split("a b c ","( )",[group,trim]), - ?line [[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>]] = re:split("a b c ","( )",[group,{parts,0}]), - ?line [[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>],[<<>>]] = - re:split("a b c ","( )",[{parts,infinity},group]), - ?line [[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>],[<<>>]] = - re:split("a b c ","( )",[group]), - ?line [[<<>>,<<" ">>],[<<"a">>,<<" ">>],[<<"b">>,<<" ">>], - [<<"c">>,<<" ">>],[<<"d">>,<<" ">>]] = - re:split(" a b c d ","( +)",[group,trim]), - ?line [[<<>>,<<" ">>],[<<"a">>,<<" ">>],[<<"b">>,<<" ">>], - [<<"c">>,<<" ">>],[<<"d">>,<<" ">>]] = - re:split(" a b c d ","( +)",[{parts,0},group]), - ?line [[<<>>,<<" ">>],[<<"a">>,<<" ">>],[<<"b">>,<<" ">>], - [<<"c">>,<<" ">>],[<<"d">>,<<" ">>],[<<>>]] = - re:split(" a b c d ","( +)",[{parts,infinity},group]), - ?line [[<<"a">>,<<" ">>],[<<"b c d">>]] = - re:split("a b c d","( +)",[{parts,2},group]), - ?line [[[967]," "],["b c d"]] = - re:split([967]++" b c d","( +)", - [{parts,2},group,{return,list},unicode]), - ?line [[<<207,135>>,<<" ">>],[<<"b c d">>]] = - re:split([967]++" b c d","( +)", - [{parts,2},group,{return,binary},unicode]), - ?line {'EXIT',{badarg,_}} = - (catch re:split([967]++" b c d","( +)", - [{parts,2},group,{return,binary}])), - ?line {'EXIT',{badarg,_}} = - (catch re:split("a b c d","( +)",[{parts,-2}])), - ?line {'EXIT',{badarg,_}} = - (catch re:split("a b c d","( +)",[{parts,banan}])), - ?line {'EXIT',{badarg,_}} = - (catch re:split("a b c d","( +)",[{capture,all}])), - ?line {'EXIT',{badarg,_}} = - (catch re:split("a b c d","( +)",[{capture,[],binary}])), + ok = splittest("a b c ","( )",[group,trim],[[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>]]), + ok = splittest("a b c ","( )",[group,{parts,0}],[[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>]]), + ok = splittest("a b c ","( )",[{parts,infinity},group],[[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>],[<<>>]]), + ok = splittest("a b c ","( )",[group],[[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>],[<<>>]]), + ok = splittest(" a b c d ","( +)",[group,trim],[[<<>>,<<" ">>],[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>],[<<"d">>,<<" ">>]]), + ok = splittest(" a b c d ","( +)",[{parts,0},group],[[<<>>,<<" ">>],[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>],[<<"d">>,<<" ">>]]), + ok = splittest(" a b c d ","( +)",[{parts,infinity},group],[[<<>>,<<" ">>],[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>],[<<"d">>,<<" ">>],[<<>>]]), + ok = splittest("a b c d","( +)",[{parts,2},group],[[<<"a">>,<<" ">>],[<<"b c d">>]]), + ok = splittest([967]++" b c d","( +)",[{parts,2},group,{return,list},unicode],[[[967]," "],["b c d"]]), + ok = splittest([967]++" b c d","( +)",[{parts,2},group,{return,binary},unicode],[[<<207,135>>,<<" ">>],[<<"b c d">>]]), + {'EXIT',{badarg,_}} = (catch re:split([967]++" b c d","( +)",[{parts,2},group,{return,binary}])), + {'EXIT',{badarg,_}} = (catch re:split("a b c d","( +)",[{parts,-2}])), + {'EXIT',{badarg,_}} = (catch re:split("a b c d","( +)",[{parts,banan}])), + {'EXIT',{badarg,_}} = (catch re:split("a b c d","( +)",[{capture,all}])), + {'EXIT',{badarg,_}} = (catch re:split("a b c d","( +)",[{capture,[],binary}])), % Parts 0 is equal to no parts specification (implicit strip) - ?line ["a"," ","b"," ","c"," ","d"] = - re:split("a b c d","( *)",[{parts,0},{return,list}]), + ok = splittest("a b c d","( *)",[{parts,0},{return,list}],["a"," ","b"," ","c"," ","d"]), ?t:timetrap_cancel(Dog), ok. diff --git a/lib/stdlib/test/stdlib_SUITE.erl b/lib/stdlib/test/stdlib_SUITE.erl index a586729b30..fa9d0f6b55 100644 --- a/lib/stdlib/test/stdlib_SUITE.erl +++ b/lib/stdlib/test/stdlib_SUITE.erl @@ -31,10 +31,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [app_test, appup_test, assert_test, {group,upgrade}]. - -groups() -> - [{upgrade,[minor_upgrade,major_upgrade]}]. + [app_test, appup_test, assert_test]. init_per_suite(Config) -> Config. @@ -42,13 +39,9 @@ init_per_suite(Config) -> end_per_suite(_Config) -> ok. -init_per_group(upgrade, Config) -> - ct_release_test:init(Config); init_per_group(_GroupName, Config) -> Config. -end_per_group(upgrade, Config) -> - ct_release_test:cleanup(Config); end_per_group(_GroupName, Config) -> Config. @@ -165,29 +158,6 @@ check_appup([],_,_) -> ok. -minor_upgrade(Config) -> - ct_release_test:upgrade(stdlib,minor,{?MODULE,[]},Config). - -major_upgrade(Config) -> - ct_release_test:upgrade(stdlib,major,{?MODULE,[]},Config). - -%% Version numbers are checked by ct_release_test, so there is nothing -%% more to check here... -upgrade_init(CtData,State) -> - {ok,{FromVsn,ToVsn}} = ct_release_test:get_app_vsns(CtData,stdlib), - case ct_release_test:get_appup(CtData,stdlib) of - {ok,{FromVsn,ToVsn,[restart_new_emulator],[restart_new_emulator]}} -> - io:format("Upgrade/downgrade ~p <--> ~p",[FromVsn,ToVsn]); - {error,{vsn_not_found,_}} when FromVsn==ToVsn -> - io:format("No upgrade test for stdlib, same version") - end, - State. -upgrade_upgraded(_CtData,State) -> - State. -upgrade_downgraded(_CtData,State) -> - State. - - -include_lib("stdlib/include/assert.hrl"). -include_lib("stdlib/include/assert.hrl"). % test repeated inclusion assert_test(suite) -> diff --git a/lib/stdlib/test/supervisor_SUITE.erl b/lib/stdlib/test/supervisor_SUITE.erl index 8cb2a5194a..903ca76575 100644 --- a/lib/stdlib/test/supervisor_SUITE.erl +++ b/lib/stdlib/test/supervisor_SUITE.erl @@ -67,6 +67,7 @@ %% Misc tests -export([child_unlink/1, tree/1, count_children/1, + count_restarting_children/1, do_not_save_start_parameters_for_temporary_children/1, do_not_save_child_specs_for_temporary_children/1, simple_one_for_one_scale_many_temporary_children/1, @@ -90,7 +91,8 @@ all() -> {group, normal_termination}, {group, shutdown_termination}, {group, abnormal_termination}, child_unlink, tree, - count_children, do_not_save_start_parameters_for_temporary_children, + count_children, count_restarting_children, + do_not_save_start_parameters_for_temporary_children, do_not_save_child_specs_for_temporary_children, simple_one_for_one_scale_many_temporary_children, temporary_bystander, simple_global_supervisor, hanging_restart_loop, hanging_restart_loop_simple, @@ -1459,6 +1461,54 @@ count_children(Config) when is_list(Config) -> [1,0,0,0] = get_child_counts(sup_test). %%------------------------------------------------------------------------- +%% Test count_children when some children are restarting +count_restarting_children(Config) when is_list(Config) -> + process_flag(trap_exit, true), + Child = {child, {supervisor_deadlock, start_child_noreg, []}, + permanent, brutal_kill, worker, []}, + %% 2 sek delay on failing restart (see supervisor_deadlock.erl) -> + %% MaxR=20, MaxT=10 should ensure a restart loop when starting and + %% restarting 3 instances of the child (as below) + {ok, SupPid} = start_link({ok, {{simple_one_for_one, 20, 10}, [Child]}}), + + %% Ets table with state read by supervisor_deadlock.erl + ets:new(supervisor_deadlock,[set,named_table,public]), + ets:insert(supervisor_deadlock,{fail_start,false}), + + [1,0,0,0] = get_child_counts(SupPid), + {ok, Ch1_1} = supervisor:start_child(SupPid, []), + [1,1,0,1] = get_child_counts(SupPid), + {ok, Ch1_2} = supervisor:start_child(SupPid, []), + [1,2,0,2] = get_child_counts(SupPid), + {ok, Ch1_3} = supervisor:start_child(SupPid, []), + [1,3,0,3] = get_child_counts(SupPid), + + supervisor_deadlock:restart_child(Ch1_1), + supervisor_deadlock:restart_child(Ch1_2), + supervisor_deadlock:restart_child(Ch1_3), + test_server:sleep(400), + [1,3,0,3] = get_child_counts(SupPid), + [Ch2_1, Ch2_2, Ch2_3] = [C || {_,C,_,_} <- supervisor:which_children(SupPid)], + + ets:insert(supervisor_deadlock,{fail_start,true}), + supervisor_deadlock:restart_child(Ch2_1), + supervisor_deadlock:restart_child(Ch2_2), + test_server:sleep(4000), % allow restart to happen before proceeding + [1,1,0,3] = get_child_counts(SupPid), + + ets:insert(supervisor_deadlock,{fail_start,false}), + test_server:sleep(4000), % allow restart to happen before proceeding + [1,3,0,3] = get_child_counts(SupPid), + + ok = supervisor:terminate_child(SupPid, Ch2_3), + [1,2,0,2] = get_child_counts(SupPid), + [Ch3_1, Ch3_2] = [C || {_,C,_,_} <- supervisor:which_children(SupPid)], + ok = supervisor:terminate_child(SupPid, Ch3_1), + [1,1,0,1] = get_child_counts(SupPid), + ok = supervisor:terminate_child(SupPid, Ch3_2), + [1,0,0,0] = get_child_counts(SupPid). + +%%------------------------------------------------------------------------- %% Temporary children shall not be restarted so they should not save %% start parameters, as it potentially can take up a huge amount of %% memory for no purpose. diff --git a/lib/stdlib/test/supervisor_deadlock.erl b/lib/stdlib/test/supervisor_deadlock.erl index 288547a972..8d3d1c6f30 100644 --- a/lib/stdlib/test/supervisor_deadlock.erl +++ b/lib/stdlib/test/supervisor_deadlock.erl @@ -11,9 +11,11 @@ init([child]) -> %% terminates immediately {ok, []}; [{fail_start, true}] -> - %% Restart frequency is MaxR=8, MaxT=10, so this will - %% ensure that restart intensity is not reached -> restart - %% loop + %% A restart frequency of MaxR=8, MaxT=10 should ensure + %% that restart intensity is not reached -> restart loop. + %% (Note that if we use simple_one_for_one, and start + %% 'many' child instances, the restart frequency must be + %% ajusted accordingly.) timer:sleep(2000), % NOTE: this could be a gen_server call timeout {stop, error} @@ -41,5 +43,11 @@ code_change(_OldVsn, State, _Extra) -> start_child() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [child], []). +start_child_noreg() -> + gen_server:start_link(?MODULE, [child], []). + restart_child() -> gen_server:cast(supervisor_deadlock, restart). + +restart_child(Pid) -> + gen_server:cast(Pid, restart). diff --git a/lib/stdlib/test/win32reg_SUITE.erl b/lib/stdlib/test/win32reg_SUITE.erl index 82baa43318..6d27ac6387 100644 --- a/lib/stdlib/test/win32reg_SUITE.erl +++ b/lib/stdlib/test/win32reg_SUITE.erl @@ -49,48 +49,53 @@ init_per_suite(Config) when is_list(Config) -> end_per_suite(Config) when is_list(Config) -> Config. + long(doc) -> "Test long keys and entries (OTP-3446)."; long(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(10)), + Dog = test_server:timetrap(test_server:seconds(10)), - ?line LongKey = "software\\" ++ + LongKey = "software\\" ++ lists:flatten(lists:duplicate(10, "..\\software\\")) ++ "Ericsson\\Erlang", - ?line {ok,Reg} = win32reg:open([read,write]), - ?line ok = win32reg:change_key(Reg, "\\hklm"), - ?line ok = win32reg:change_key(Reg, LongKey), - ?line {ok,ErlangKey} = win32reg:current_key(Reg), - io:format("Erlang key: ~s", [ErlangKey]), + {ok,Read} = win32reg:open([read]), + ok = win32reg:change_key(Read, "\\hklm"), + + ok = win32reg:change_key(Read, LongKey), + {ok,ErlangKey} = win32reg:current_key(Read), + io:format("Erlang key: ~s~n", [ErlangKey]), + ok = win32reg:close(Read), + {ok,Reg} = win32reg:open([read, write]), %% Write a long value and read it back. - ?line TestKey = "test_key", - ?line LongValue = lists:concat(["This is a long value generated by the test case ",?MODULE,":long/1. "|lists:duplicate(128, "a")]), - ?line ok = win32reg:set_value(Reg, TestKey, LongValue), - ?line {ok,LongValue} = win32reg:value(Reg, TestKey), + TestKey = "test_key", + LongValue = lists:concat(["This is a long value generated by the test case ",?MODULE,":long/1. "|lists:duplicate(128, "a")]), + ok = win32reg:set_value(Reg, TestKey, LongValue), + {ok,LongValue} = win32reg:value(Reg, TestKey), + io:format("Where ~p Key ~s Value ~s ~n", [win32reg:current_key(Reg), TestKey, LongValue]), %% Done. - ?line ok = win32reg:close(Reg), - ?line test_server:timetrap_cancel(Dog), + ok = win32reg:close(Reg), + test_server:timetrap_cancel(Dog), ok. evil_write(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(10)), + Dog = test_server:timetrap(test_server:seconds(10)), - ?line Key = "Software\\Ericsson\\Erlang", - ?line {ok,Reg} = win32reg:open([read,write]), - ?line ok = win32reg:change_key(Reg, "\\hklm"), - ?line ok = win32reg:change_key(Reg, Key), - ?line {ok,ErlangKey} = win32reg:current_key(Reg), + Key = "Software\\Ericsson\\Erlang", + {ok,Reg} = win32reg:open([read,write]), + ok = win32reg:change_key(Reg, "\\hkcu"), + ok = win32reg:change_key_create(Reg, Key), + {ok,ErlangKey} = win32reg:current_key(Reg), io:format("Erlang key: ~s", [ErlangKey]), %% Write keys with different length and read it back. - ?line TestKey = "test_key " ++ lists:duplicate(128, $a), + TestKey = "test_key " ++ lists:duplicate(128, $a), evil_write_1(Reg, TestKey), %% Done. - ?line ok = win32reg:close(Reg), - ?line test_server:timetrap_cancel(Dog), + ok = win32reg:close(Reg), + test_server:timetrap_cancel(Dog), ok. evil_write_1(Reg, [_|[_|_]=Key]=Key0) -> diff --git a/lib/stdlib/test/zip_SUITE.erl b/lib/stdlib/test/zip_SUITE.erl index 9d48d092cf..c275053691 100644 --- a/lib/stdlib/test/zip_SUITE.erl +++ b/lib/stdlib/test/zip_SUITE.erl @@ -556,9 +556,10 @@ unzip_to_binary(doc) -> unzip_to_binary(Config) when is_list(Config) -> DataDir = ?config(data_dir, Config), PrivDir = ?config(priv_dir, Config), + WorkDir = filename:join(PrivDir, "unzip_to_binary"), + _ = file:make_dir(WorkDir), - delete_all_in(PrivDir), - file:set_cwd(PrivDir), + ok = file:set_cwd(WorkDir), Long = filename:join(DataDir, "abc.zip"), %% Unzip a zip file into a binary @@ -569,7 +570,7 @@ unzip_to_binary(Config) when is_list(Config) -> end, FBList), %% Make sure no files created in cwd - {ok,[]} = file:list_dir(PrivDir), + {ok,[]} = file:list_dir(WorkDir), ok. @@ -578,8 +579,10 @@ zip_to_binary(doc) -> zip_to_binary(Config) when is_list(Config) -> DataDir = ?config(data_dir, Config), PrivDir = ?config(priv_dir, Config), - delete_all_in(PrivDir), - file:set_cwd(PrivDir), + WorkDir = filename:join(PrivDir, "zip_to_binary"), + _ = file:make_dir(WorkDir), + + file:set_cwd(WorkDir), FileName = "abc.txt", ZipName = "t.zip", FilePath = filename:join(DataDir, FileName), @@ -589,7 +592,7 @@ zip_to_binary(Config) when is_list(Config) -> {ok, {ZipName, ZipB}} = zip:zip(ZipName, [FileName], [memory]), %% Make sure no files created in cwd - {ok,[FileName]} = file:list_dir(PrivDir), + {ok,[FileName]} = file:list_dir(WorkDir), %% Zip to a file {ok, ZipName} = zip:zip(ZipName, [FileName]), @@ -696,11 +699,6 @@ do_delete_files([Item|Rest], Cnt) -> end, do_delete_files(Rest, Cnt + DelCnt). -delete_all_in(Dir) -> - {ok, Files} = file:list_dir(Dir), - delete_files(lists:map(fun(F) -> filename:join(Dir,F) end, - Files)). - compress_control(doc) -> ["Test control of which files that should be compressed"]; compress_control(suite) -> []; diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk index a1f2a946b1..5bac4be9d7 100644 --- a/lib/stdlib/vsn.mk +++ b/lib/stdlib/vsn.mk @@ -1 +1 @@ -STDLIB_VSN = 2.5 +STDLIB_VSN = 2.8 diff --git a/lib/test_server/doc/src/notes.xml b/lib/test_server/doc/src/notes.xml index 939a07dcef..9b5df6271a 100644 --- a/lib/test_server/doc/src/notes.xml +++ b/lib/test_server/doc/src/notes.xml @@ -33,6 +33,56 @@ <file>notes.xml</file> </header> +<section><title>Test_Server 3.10</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Two new CT hook functions have been added: + <c>post_init_per_testcase/4</c> and + <c>pre_end_per_testcase/3</c>. With these hook functions, + it is possible to perform arbitrary actions (including + modifications of test execution, test state and results) + immediately before and after the execution of the test + case.</p> + <p> + Own Id: OTP-13242 Aux Id: seq12991 </p> + </item> + </list> + </section> + +</section> + +<section><title>Test_Server 3.9.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + When generating Makefile from Makefile.src, + ts_lib:get_arg/4 earlier removed all spaces in the + extracted argument. The code was probably meant for + removing leading and trailing spaces only, and is now + corrected to do so.</p> + <p> + Own Id: OTP-13015</p> + </item> + <item> + <p> + With the Common Test 'create_priv_dir' start option set + to 'auto_per_tc', the name of the priv directory for a + configuration function could clash with the name of the + priv directory for a test case, which would cause Test + Server failure. This error has been corrected.</p> + <p> + Own Id: OTP-13181</p> + </item> + </list> + </section> + +</section> + <section><title>Test_Server 3.9</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -298,7 +348,7 @@ configuration function or test specification term), the affected test cases get the status <c>user_skipped</c> instead.</p> <p>This update has meant a few changes that - may affect Common Test users in various ways: <list> + may affect Common Test users in various ways:</p> <list> <item>The test results and statistics will be affected, which is important to know when running regression tests and comparing results to previous test runs.</item> @@ -318,7 +368,7 @@ <c>auto_skipped</c> rather than <c>user_skipped</c> as before.</item> <item>The event messages that Common Test generates during test runs have been affected by this - update. For details see OTP-11524.</item> </list> </p> + update. For details see OTP-11524.</item> </list> <p> Own Id: OTP-11305 Aux Id: OTP-11524 </p> </item> @@ -445,7 +495,7 @@ that were not opened with the {encoding,utf8} option. If then the argument contained unicode characters above 255, the file descriptor would crash. This has been corrected - by the following modifications: <list> <item> Since the + by the following modifications:</p> <list> <item> Since the 'unexpected_io' log file is used only when the test case HTML file is not available (e.g. between test cases), this file is now also a HTML file and as other @@ -467,7 +517,7 @@ path to the last run.<timestamp> directory, is now dependent on the file name mode of the VM. If file names are expected to be unicode, then the 'last_name' file is - UTF-8 encoded, else it is latin1 encoded. </item> </list></p> + UTF-8 encoded, else it is latin1 encoded. </item> </list> <p> Also, ~tp has been changed back to ~p unless it is somehow likely that the argument includes strings. It is @@ -615,7 +665,7 @@ </item> <item> <p> - Update common test modules to handle unicode <list> + Update common test modules to handle Unicode:</p> <list> <item> Use UTF-8 encoding for all HTML files, except the HTML version of the test suite generated with erl2html2:convert, which will have the same encoding as @@ -626,7 +676,7 @@ unicode:characters_to_list and unicode:characters_to_binary for conversion between binaries and strings instead of binary_to_list and - list_to_binary. </item> </list></p> + list_to_binary. </item> </list> </item> </list> </section> diff --git a/lib/test_server/src/erl2html2.erl b/lib/test_server/src/erl2html2.erl index 2c63103264..e69383acea 100644 --- a/lib/test_server/src/erl2html2.erl +++ b/lib/test_server/src/erl2html2.erl @@ -44,7 +44,7 @@ convert(File, Dest, InclPath) -> "<html>\n" "<head>\n" "<meta http-equiv=\"Content-Type\" content=\"text/html;" - "charset=",html_encoding(Encoding),"\"/>\n" + "charset=",html_encoding(Encoding),"\"/></meta>\n" "<title>", to_raw_list(File,Encoding), "</title>\n" "</head>\n\n" "<body bgcolor=\"white\" text=\"black\"" diff --git a/lib/test_server/src/test_server.erl b/lib/test_server/src/test_server.erl index da6bf491ac..919526c5d7 100644 --- a/lib/test_server/src/test_server.erl +++ b/lib/test_server/src/test_server.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2015. All Rights Reserved. +%% Copyright Ericsson AB 1996-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -63,13 +63,11 @@ init_target_info() -> [$.|Emu] = code:objfile_extension(), {_, OTPRel} = init:script_id(), - TestServerDir = filename:absname(filename:dirname(code:which(?MODULE))), #target_info{os_family=test_server_sup:get_os_family(), os_type=os:type(), version=erlang:system_info(version), system_version=erlang:system_info(system_version), root_dir=code:root_dir(), - test_server_dir=TestServerDir, emulator=Emu, otp_release=OTPRel, username=test_server_sup:get_username(), @@ -411,11 +409,9 @@ run_test_case_apply(Mod, Func, Args, Name, RunInit, TimetrapData) -> Ref = make_ref(), Pid = spawn_link( - fun() -> - run_test_case_eval(Mod, Func, Args, Name, Ref, - RunInit, TimetrapData, - LogOpts, TCCallback) - end), + run_test_case_eval_fun(Mod, Func, Args, Name, Ref, + RunInit, TimetrapData, + LogOpts, TCCallback)), put(test_server_detected_fail, []), St = #st{ref=Ref,pid=Pid,mf={Mod,Func},last_known_loc=unknown, status=starting,ret_val=[],comment="",timeout=infinity, @@ -718,10 +714,10 @@ call_end_conf(Mod,Func,TCPid,TCExitReason,Loc,Conf,TVal) -> Starter ! {self(),{call_end_conf,Data,ok}} end); true -> - do_call_end_conf(Starter,Mod,Func,Data,Conf,TVal) + do_call_end_conf(Starter,Mod,Func,Data,TCExitReason,Conf,TVal) end. -do_call_end_conf(Starter,Mod,Func,Data,Conf,TVal) -> +do_call_end_conf(Starter,Mod,Func,Data,TCExitReason,Conf,TVal) -> EndConfProc = fun() -> process_flag(trap_exit,true), % to catch timetraps @@ -729,16 +725,25 @@ do_call_end_conf(Starter,Mod,Func,Data,Conf,TVal) -> EndConfApply = fun() -> timetrap(TVal), - try apply(Mod,end_per_testcase,[Func,Conf]) of + %% We can't handle fails or skips here + %% (neither input nor output). The error can + %% be read from Conf though (tc_status). + EndConf = + case do_init_tc_call(Mod,{end_per_testcase,Func}, + [Conf], + {TCExitReason,[Conf]}) of + {_,[EPTCInit]} when is_list(EPTCInit) -> + EPTCInit; + _ -> + Conf + end, + try apply(Mod,end_per_testcase,[Func,EndConf]) of _ -> ok catch - _:Why -> + _:Error -> timer:sleep(1), - group_leader() ! {printout,12, - "WARNING! " - "~w:end_per_testcase(~w, ~p)" - " crashed!\n\tReason: ~p\n", - [Mod,Func,Conf,Why]} + print_end_conf_result(Mod,Func,Conf, + "crashed",Error) end, Supervisor ! {self(),end_conf} end, @@ -747,10 +752,7 @@ do_call_end_conf(Starter,Mod,Func,Data,Conf,TVal) -> {Pid,end_conf} -> Starter ! {self(),{call_end_conf,Data,ok}}; {'EXIT',Pid,Reason} -> - group_leader() ! {printout,12, - "WARNING! ~w:end_per_testcase(~w, ~p)" - " failed!\n\tReason: ~p\n", - [Mod,Func,Conf,Reason]}, + print_end_conf_result(Mod,Func,Conf,"failed",Reason), Starter ! {self(),{call_end_conf,Data,{error,Reason}}}; {'EXIT',_OtherPid,Reason} -> %% Probably the parent - not much to do about that @@ -759,28 +761,55 @@ do_call_end_conf(Starter,Mod,Func,Data,Conf,TVal) -> end, spawn_link(EndConfProc). -spawn_fw_call(Mod,{init_per_testcase,Func},CurrConf,Pid, - {timetrap_timeout,TVal}=Why, - Loc,SendTo) -> +print_end_conf_result(Mod,Func,Conf,Cause,Error) -> + Str2Print = + fun(NoHTML) when NoHTML == stdout; NoHTML == major -> + io_lib:format("WARNING! " + "~w:end_per_testcase(~w, ~tp)" + " ~s!\n\tReason: ~tp\n", + [Mod,Func,Conf,Cause,Error]); + (minor) -> + ErrorStr = test_server_ctrl:escape_chars(Error), + io_lib:format("WARNING! " + "~w:end_per_testcase(~w, ~tp)" + " ~s!\n\tReason: ~ts\n", + [Mod,Func,Conf,Cause,ErrorStr]) + end, + group_leader() ! {printout,12,Str2Print}. + + +spawn_fw_call(Mod,IPTC={init_per_testcase,Func},CurrConf,Pid, + Why,Loc,SendTo) -> FwCall = fun() -> Skip = {skip,{failed,{Mod,init_per_testcase,Why}}}, %% if init_per_testcase fails, the test case %% should be skipped - try do_end_tc_call(Mod,Func, {Pid,Skip,[CurrConf]}, Why) of + try begin do_end_tc_call(Mod,IPTC, {Pid,Skip,[CurrConf]}, Why), + do_init_tc_call(Mod,{end_per_testcase,Func}, + [CurrConf],{ok,[CurrConf]}), + do_end_tc_call(Mod,{end_per_testcase,Func}, + {Pid,Skip,[CurrConf]}, Why) end of _ -> ok catch _:FwEndTCErr -> exit({fw_notify_done,end_tc,FwEndTCErr}) end, + Time = case Why of + {timetrap_timeout,TVal} -> TVal/1000; + _ -> died + end, + group_leader() ! {printout,12, + "ERROR! ~w:init_per_testcase(~w, ~p)" + " failed!\n\tReason: ~tp\n", + [Mod,Func,CurrConf,Why]}, %% finished, report back - SendTo ! {self(),fw_notify_done, - {TVal/1000,Skip,Loc,[],undefined}} + SendTo ! {self(),fw_notify_done,{Time,Skip,Loc,[],undefined}} end, spawn_link(FwCall); -spawn_fw_call(Mod,{end_per_testcase,Func},EndConf,Pid, - {timetrap_timeout,TVal}=Why,_Loc,SendTo) -> +spawn_fw_call(Mod,EPTC={end_per_testcase,Func},EndConf,Pid, + Why,_Loc,SendTo) -> FwCall = fun() -> {RetVal,Report} = @@ -794,24 +823,38 @@ spawn_fw_call(Mod,{end_per_testcase,Func},EndConf,Pid, E = {failed,{Mod,end_per_testcase,Why}}, {Result,E} end, - group_leader() ! {printout,12, - "WARNING! ~w:end_per_testcase(~w, ~p)" - " failed!\n\tReason: timetrap timeout" - " after ~w ms!\n", [Mod,Func,EndConf,TVal]}, - FailLoc = proplists:get_value(tc_fail_loc, EndConf), - try do_end_tc_call(Mod,Func, - {Pid,Report,[EndConf]}, Why) of + {Time,Warn} = + case Why of + {timetrap_timeout,TVal} -> + group_leader() ! + {printout,12, + "WARNING! ~w:end_per_testcase(~w, ~p)" + " failed!\n\tReason: timetrap timeout" + " after ~w ms!\n", [Mod,Func,EndConf,TVal]}, + W = "<font color=\"red\">" + "WARNING: end_per_testcase timed out!</font>", + {TVal/1000,W}; + _ -> + group_leader() ! + {printout,12, + "WARNING! ~w:end_per_testcase(~w, ~p)" + " failed!\n\tReason: ~tp\n", + [Mod,Func,EndConf,Why]}, + W = "<font color=\"red\">" + "WARNING: end_per_testcase failed!</font>", + {died,W} + end, + try do_end_tc_call(Mod,EPTC,{Pid,Report,[EndConf]}, Why) of _ -> ok catch _:FwEndTCErr -> exit({fw_notify_done,end_tc,FwEndTCErr}) end, - Warn = "<font color=\"red\">" - "WARNING: end_per_testcase timed out!</font>", + FailLoc = proplists:get_value(tc_fail_loc, EndConf), %% finished, report back (if end_per_testcase fails, a warning %% should be printed as part of the comment) SendTo ! {self(),fw_notify_done, - {TVal/1000,RetVal,FailLoc,[],Warn}} + {Time,RetVal,FailLoc,[],Warn}} end, spawn_link(FwCall); @@ -834,10 +877,12 @@ spawn_fw_call(FwMod,FwFunc,_,_Pid,{framework_error,FwError},_,SendTo) -> spawn_link(FwCall); spawn_fw_call(Mod,Func,CurrConf,Pid,Error,Loc,SendTo) -> - Func1 = case Func of - {_InitOrEndPerTC,F} -> F; - F -> F - end, + {Func1,EndTCFunc} = case Func of + CF when CF == init_per_suite; CF == end_per_suite; + CF == init_per_group; CF == end_per_group -> + {CF,CF}; + TC -> {TC,{end_per_testcase,TC}} + end, FwCall = fun() -> try fw_error_notify(Mod,Func1,[], @@ -849,8 +894,7 @@ spawn_fw_call(Mod,Func,CurrConf,Pid,Error,Loc,SendTo) -> FwErrorNotifyErr}) end, Conf = [{tc_status,{failed,Error}}|CurrConf], - try do_end_tc_call(Mod,Func1, - {Pid,Error,[Conf]},Error) of + try do_end_tc_call(Mod,EndTCFunc,{Pid,Error,[Conf]},Error) of _ -> ok catch _:FwEndTCErr -> @@ -907,6 +951,16 @@ job_proxy_msgloop() -> end, job_proxy_msgloop(). +-spec run_test_case_eval_fun(_, _, _, _, _, _, _, _, _) -> + fun(() -> no_return()). +run_test_case_eval_fun(Mod, Func, Args, Name, Ref, RunInit, + TimetrapData, LogOpts, TCCallback) -> + fun () -> + run_test_case_eval(Mod, Func, Args, Name, Ref, + RunInit, TimetrapData, + LogOpts, TCCallback) + end. + %% A test case is known to have failed if it returns {'EXIT', _} tuple, %% or sends a message {failed, File, Line} to it's group_leader @@ -917,32 +971,38 @@ run_test_case_eval(Mod, Func, Args0, Name, Ref, RunInit, Where = [{Mod,Func}], put(test_server_loc, Where), - FWInitResult = test_server_sup:framework_call(init_tc,[Mod,Func,Args0], - {ok,Args0}), + FWInitFunc = case RunInit of + run_init -> {init_per_testcase,Func}; + _ -> Func + end, + + FWInitResult0 = do_init_tc_call(Mod,FWInitFunc,Args0,{ok,Args0}), + set_tc_state(running), {{Time,Value},Loc,Opts} = - case FWInitResult of + case FWInitResult0 of {ok,Args} -> run_test_case_eval1(Mod, Func, Args, Name, RunInit, TCCallback); Error = {error,_Reason} -> - NewResult = do_end_tc_call(Mod,Func, {Error,Args0}, + NewResult = do_end_tc_call(Mod,FWInitFunc, {Error,Args0}, {auto_skip,{failed,Error}}), {{0,NewResult},Where,[]}; {fail,Reason} -> - Conf = [{tc_status,{failed,Reason}} | hd(Args0)], + Conf = [{tc_status,{failed,Reason}} | hd(Args0)], fw_error_notify(Mod, Func, Conf, Reason), - NewResult = do_end_tc_call(Mod,Func, {{error,Reason},[Conf]}, + NewResult = do_end_tc_call(Mod,FWInitFunc, + {{error,Reason},[Conf]}, {fail,Reason}), {{0,NewResult},Where,[]}; Skip = {SkipType,_Reason} when SkipType == skip; SkipType == skipped -> - NewResult = do_end_tc_call(Mod,Func, + NewResult = do_end_tc_call(Mod,FWInitFunc, {Skip,Args0}, Skip), {{0,NewResult},Where,[]}; AutoSkip = {auto_skip,_Reason} -> %% special case where a conf case "pretends" to be skipped NewResult = - do_end_tc_call(Mod,Func, {AutoSkip,Args0}, AutoSkip), + do_end_tc_call(Mod,FWInitFunc, {AutoSkip,Args0}, AutoSkip), {{0,NewResult},Where,[]} end, exit({Ref,Time,Value,Loc,Opts}). @@ -957,31 +1017,41 @@ run_test_case_eval1(Mod, Func, Args, Name, RunInit, TCCallback) -> SkipType == skipped -> Line = get_loc(), Conf = [{tc_status,{skipped,Reason}}|hd(Args)], - NewRes = do_end_tc_call(Mod,Func, + NewRes = do_end_tc_call(Mod,{init_per_testcase,Func}, {Skip,[Conf]}, Skip), {{0,NewRes},Line,[]}; {skip_and_save,Reason,SaveCfg} -> Line = get_loc(), Conf = [{tc_status,{skipped,Reason}}, {save_config,SaveCfg}|hd(Args)], - NewRes = do_end_tc_call(Mod,Func, {{skip,Reason},[Conf]}, + NewRes = do_end_tc_call(Mod,{init_per_testcase,Func}, + {{skip,Reason},[Conf]}, {skip,Reason}), {{0,NewRes},Line,[]}; FailTC = {fail,Reason} -> % user fails the testcase EndConf = [{tc_status,{failed,Reason}} | hd(Args)], fw_error_notify(Mod, Func, EndConf, Reason), - NewRes = do_end_tc_call(Mod,Func, + NewRes = do_end_tc_call(Mod,{init_per_testcase,Func}, {{error,Reason},[EndConf]}, FailTC), {{0,NewRes},[{Mod,Func}],[]}; {ok,NewConf} -> - %% call user callback function if defined - NewConf1 = - user_callback(TCCallback, Mod, Func, init, NewConf), - %% save current state in controller loop - set_tc_state(tc, NewConf1), - %% execute the test case - {{T,Return},Loc} = {ts_tc(Mod,Func,[NewConf1]), get_loc()}, + IPTCEndRes = do_end_tc_call(Mod,{init_per_testcase,Func}, + {ok,[NewConf]}, NewConf), + {{T,Return},Loc,NewConf1} = + if not is_list(IPTCEndRes) -> + %% received skip or fail, not config + {{0,IPTCEndRes},undefined,NewConf}; + true -> + %% call user callback function if defined + NewConfUC = + user_callback(TCCallback, Mod, Func, + init, IPTCEndRes), + %% save current state in controller loop + set_tc_state(tc, NewConfUC), + %% execute the test case + {ts_tc(Mod,Func,[NewConfUC]),get_loc(),NewConfUC} + end, {EndConf,TSReturn,FWReturn} = case Return of {E,TCError} when E=='EXIT' ; E==failed -> @@ -1007,36 +1077,47 @@ run_test_case_eval1(Mod, Func, Args, Name, RunInit, TCCallback) -> %% call user callback function if defined EndConf1 = user_callback(TCCallback, Mod, Func, 'end', EndConf), + + %% We can't handle fails or skips here + EndConf2 = + case do_init_tc_call(Mod,{end_per_testcase,Func}, + [EndConf1],{ok,[EndConf1]}) of + {ok,[EPTCInitRes]} when is_list(EPTCInitRes) -> + EPTCInitRes; + _ -> + EndConf1 + end, + %% update current state in controller loop - {FWReturn1,TSReturn1,EndConf2} = - case end_per_testcase(Mod, Func, EndConf1) of + {FWReturn1,TSReturn1,EndConf3} = + case end_per_testcase(Mod, Func, EndConf2) of SaveCfg1={save_config,_} -> {FWReturn,TSReturn, [SaveCfg1|lists:keydelete(save_config,1, - EndConf1)]}; + EndConf2)]}; {fail,ReasonToFail} -> %% user has failed the testcase - fw_error_notify(Mod, Func, EndConf1, + fw_error_notify(Mod, Func, EndConf2, ReasonToFail), {{error,ReasonToFail}, {failed,ReasonToFail}, - EndConf1}; + EndConf2}; {failed,{_,end_per_testcase,_}} = Failure when FWReturn == ok -> %% unexpected termination in end_per_testcase %% report this as the result to the framework - {Failure,TSReturn,EndConf1}; + {Failure,TSReturn,EndConf2}; _ -> %% test case result should be reported to %% framework no matter the status of %% end_per_testcase - {FWReturn,TSReturn,EndConf1} + {FWReturn,TSReturn,EndConf2} end, %% clear current state in controller loop - case do_end_tc_call(Mod,Func, - {FWReturn1,[EndConf2]}, TSReturn1) of + case do_end_tc_call(Mod,{end_per_testcase,Func}, + {FWReturn1,[EndConf3]}, TSReturn1) of {failed,Reason} = NewReturn -> - fw_error_notify(Mod,Func,EndConf2, Reason), + fw_error_notify(Mod,Func,EndConf3, Reason), {{T,NewReturn},[{Mod,Func}],[]}; NewReturn -> {{T,NewReturn},Loc,[]} @@ -1062,7 +1143,38 @@ run_test_case_eval1(Mod, Func, Args, Name, RunInit, TCCallback) -> {{T,Return2},Loc,Opts} end. +do_init_tc_call(Mod, Func, Res, Return) -> + test_server_sup:framework_call(init_tc,[Mod,Func,Res],Return). + +do_end_tc_call(Mod, IPTC={init_per_testcase,Func}, Res, Return) -> + case Return of + {NOk,_} when NOk == auto_skip; NOk == fail; + NOk == skip ; NOk == skipped -> + {_,Args} = Res, + IPTCEndRes = + case do_end_tc_call1(Mod, IPTC, Res, Return) of + IPTCEndConfig when is_list(IPTCEndConfig) -> + IPTCEndConfig; + _ -> + Args + end, + EPTCInitRes = + case do_init_tc_call(Mod,{end_per_testcase,Func}, + IPTCEndRes,Return) of + {ok,EPTCInitConfig} when is_list(EPTCInitConfig) -> + {Return,EPTCInitConfig}; + _ -> + Return + end, + do_end_tc_call1(Mod, {end_per_testcase,Func}, + EPTCInitRes, Return); + _Ok -> + do_end_tc_call1(Mod, IPTC, Res, Return) + end; do_end_tc_call(Mod, Func, Res, Return) -> + do_end_tc_call1(Mod, Func, Res, Return). + +do_end_tc_call1(Mod, Func, Res, Return) -> FwMod = os:getenv("TEST_SERVER_FRAMEWORK"), Ref = make_ref(), if FwMod == "ct_framework" ; FwMod == "undefined"; FwMod == false -> @@ -1201,7 +1313,7 @@ do_init_per_testcase(Mod, Args) -> Bad -> group_leader() ! {printout,12, "ERROR! init_per_testcase has returned " - "bad elements in Config: ~p\n",[Bad]}, + "bad elements in Config: ~tp\n",[Bad]}, {skip,{failed,{Mod,init_per_testcase,bad_return}}} end; {fail,_Reason}=Res -> @@ -1219,25 +1331,33 @@ do_init_per_testcase(Mod, Args) -> throw:Other -> set_loc(erlang:get_stacktrace()), Line = get_loc(), - FormattedLoc = test_server_sup:format_loc(Line), - group_leader() ! {printout,12, - "ERROR! init_per_testcase thrown!\n" - "\tLocation: ~ts\n\tReason: ~p\n", - [FormattedLoc, Other]}, + print_init_conf_result(Line,"thrown",Other), {skip,{failed,{Mod,init_per_testcase,Other}}}; _:Reason0 -> Stk = erlang:get_stacktrace(), Reason = {Reason0,Stk}, set_loc(Stk), Line = get_loc(), - FormattedLoc = test_server_sup:format_loc(Line), - group_leader() ! {printout,12, - "ERROR! init_per_testcase crashed!\n" - "\tLocation: ~ts\n\tReason: ~p\n", - [FormattedLoc,Reason]}, + print_init_conf_result(Line,"crashed",Reason), {skip,{failed,{Mod,init_per_testcase,Reason}}} end. +print_init_conf_result(Line,Cause,Reason) -> + FormattedLoc = test_server_sup:format_loc(Line), + Str2Print = + fun(NoHTML) when NoHTML == stdout; NoHTML == major -> + io_lib:format("ERROR! init_per_testcase ~s!\n" + "\tLocation: ~p\n\tReason: ~tp\n", + [Cause,Line,Reason]); + (minor) -> + ReasonStr = test_server_ctrl:escape_chars(Reason), + io_lib:format("ERROR! init_per_testcase ~s!\n" + "\tLocation: ~ts\n\tReason: ~ts\n", + [Cause,FormattedLoc,ReasonStr]) + end, + group_leader() ! {printout,12,Str2Print}. + + end_per_testcase(Mod, Func, Conf) -> case erlang:function_exported(Mod,end_per_testcase,2) of true -> @@ -1272,12 +1392,7 @@ do_end_per_testcase(Mod,EndFunc,Func,Conf) -> comment(io_lib:format("~ts<font color=\"red\">" "WARNING: ~w thrown!" "</font>\n",[Comment0,EndFunc])), - group_leader() ! {printout,12, - "WARNING: ~w thrown!\n" - "Reason: ~p\n" - "Line: ~ts\n", - [EndFunc, Other, - test_server_sup:format_loc(get_loc())]}, + print_end_tc_warning(EndFunc,Other,"thrown",get_loc()), {failed,{Mod,end_per_testcase,Other}}; Class:Reason -> Stk = erlang:get_stacktrace(), @@ -1294,15 +1409,25 @@ do_end_per_testcase(Mod,EndFunc,Func,Conf) -> comment(io_lib:format("~ts<font color=\"red\">" "WARNING: ~w crashed!" "</font>\n",[Comment0,EndFunc])), - group_leader() ! {printout,12, - "WARNING: ~w crashed!\n" - "Reason: ~p\n" - "Line: ~ts\n", - [EndFunc, Reason, - test_server_sup:format_loc(get_loc())]}, + print_end_tc_warning(EndFunc,Reason,"crashed",get_loc()), {failed,{Mod,end_per_testcase,Why}} end. +print_end_tc_warning(EndFunc,Reason,Cause,Loc) -> + FormattedLoc = test_server_sup:format_loc(Loc), + Str2Print = + fun(NoHTML) when NoHTML == stdout; NoHTML == major -> + io_lib:format("WARNING: ~w ~s!\n" + "Reason: ~tp\nLine: ~p\n", + [EndFunc,Cause,Reason,Loc]); + (minor) -> + ReasonStr = test_server_ctrl:escape_chars(Reason), + io_lib:format("WARNING: ~w ~s!\n" + "Reason: ~ts\nLine: ~ts\n", + [EndFunc,Cause,ReasonStr,FormattedLoc]) + end, + group_leader() ! {printout,12,Str2Print}. + get_loc() -> get(test_server_loc). @@ -2040,10 +2165,19 @@ get_timetrap_info(TCPid, SendToServer) -> Timers -> case [Info || {Handle,Pid,Info} <- Timers, Pid == TCPid, Handle /= infinity] of - [I|_] -> - I; + [{TVal,true}|_] -> + {TVal,{true,test_server:timetrap_scale_factor()}}; + [{TVal,false}|_] -> + {TVal,{false,1}}; [] when SendToServer == true -> - tc_supervisor_req({get_timetrap_info,TCPid}); + case tc_supervisor_req({get_timetrap_info,TCPid}) of + {TVal,true} -> + {TVal,{true,test_server:timetrap_scale_factor()}}; + {TVal,false} -> + {TVal,{false,1}}; + Error -> + Error + end; [] -> undefined end @@ -2408,15 +2542,7 @@ run_on_shielded_node(Fun, CArgs) when is_function(Fun), is_list(CArgs) -> end, Master = self(), Ref = make_ref(), - Slave = spawn(Node, - fun () -> - start_job_proxy(), - receive - Ref -> - Master ! {Ref, Fun()} - end, - receive after infinity -> infinity end - end), + Slave = spawn(Node, start_job_proxy_fun(Master, Fun)), MRef = erlang:monitor(process, Slave), Slave ! Ref, receive @@ -2431,6 +2557,17 @@ run_on_shielded_node(Fun, CArgs) when is_function(Fun), is_list(CArgs) -> end end. +-spec start_job_proxy_fun(_, _) -> fun(() -> no_return()). +start_job_proxy_fun(Master, Fun) -> + fun () -> + start_job_proxy(), + receive + Ref -> + Master ! {Ref, Fun()} + end, + receive after infinity -> infinity end + end. + %% Return true if Name or node() is a shielded node is_shielded(Name) -> case {cast_to_list(Name),atom_to_list(node())} of diff --git a/lib/test_server/src/test_server_ctrl.erl b/lib/test_server/src/test_server_ctrl.erl index 0be6e0b4e4..e0975ab744 100644 --- a/lib/test_server/src/test_server_ctrl.erl +++ b/lib/test_server/src/test_server_ctrl.erl @@ -77,7 +77,7 @@ -export([handle_call/3, handle_cast/2, handle_info/2]). -export([do_test_cases/4]). -export([do_spec/2, do_spec_list/2]). --export([xhtml/2]). +-export([xhtml/2, escape_chars/1]). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1825,13 +1825,14 @@ start_minor_log_file1(Mod, Func, LogDir, AbsName, MFA) -> case {filelib:is_file(filename:join(LogDir, SrcListing)), lists:member(no_src, get(test_server_logopts))} of {true,false} -> - print(Lev, Info ++ "<a href=\"~ts#~ts\">~w:~w/~w</a> " - "(click for source code)\n", + print(Lev, ["$tc_html", + Info ++ "<a href=\"~ts#~ts\">~w:~w/~w</a> " + "(click for source code)\n"], [uri_encode(SrcListing), uri_encode(atom_to_list(Func)++"-1",utf8), Mod,Func,Arity]); _ -> - print(Lev, Info ++ "~w:~w/~w\n", [Mod,Func,Arity]) + print(Lev, ["$tc_html",Info ++ "~w:~w/~w\n"], [Mod,Func,Arity]) end end, @@ -3711,8 +3712,8 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit, RunDir = filename:dirname(MinorName), Ext = if Num == 0 -> - Nr = erlang:unique_integer([positive]), - lists:flatten(io_lib:format(".~w", [Nr])); + Int = erlang:unique_integer([positive,monotonic]), + lists:flatten(io_lib:format(".cfg.~w", [Int])); true -> lists:flatten(io_lib:format(".~w", [Num])) end, @@ -3741,7 +3742,10 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit, true -> ok end, - print(minor, "Config value:\n\n ~tp\n", [Args2Print]), + + print(minor, + escape_chars(io_lib:format("Config value:\n\n ~tp\n", [Args2Print])), + []), print(minor, "Current directory is ~tp\n", [Cwd]), GrNameStr = case GrName of @@ -3756,7 +3760,7 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit, "<td>" ++ Col0 ++ "~w" ++ Col1 ++ "</td>" "<td>" ++ Col0 ++ "~ts" ++ Col1 ++ "</td>" "<td><a href=\"~ts\">~w</a></td>" - "<td><a href=\"~ts#top\"><</a> <a href=\"~ts#end\">></a></td>", + "<td><a href=\"~ts#top\"><</a> <a href=\"~ts#end\">></a></td>", [num2str(Num),fw_name(Mod),GrNameStr,EncMinorBase,Func, EncMinorBase,EncMinorBase]), @@ -3933,7 +3937,7 @@ progress(skip, CaseNum, Mod, Func, GrName, Loc, Reason, Time, [get_info_str(Mod,Func, CaseNum, get(test_server_cases))]), test_server_sup:framework_call(report, [tc_done,{Mod,{Func,GrName}, {ReportTag,Reason1}}]), - ReasonStr = reason_to_string(Reason1), + ReasonStr = escape_chars(reason_to_string(Reason1)), ReasonStr1 = lists:flatten([string:strip(S,left) || S <- string:tokens(ReasonStr,[$\n])]), ReasonStr2 = @@ -4005,7 +4009,10 @@ progress(failed, CaseNum, Mod, Func, GrName, Loc, {testcase_aborted,Reason}, _T, [Comment]), FormatLoc = test_server_sup:format_loc(Loc), print(minor, "=== Location: ~ts", [FormatLoc]), - print(minor, "=== Reason: {testcase_aborted,~p}", [Reason]), + print(minor, + escape_chars(io_lib:format("=== Reason: {testcase_aborted,~p}", + [Reason])), + []), failed; progress(failed, CaseNum, Mod, Func, GrName, unknown, Reason, Time, @@ -4018,7 +4025,7 @@ progress(failed, CaseNum, Mod, Func, GrName, unknown, Reason, Time, TimeStr = io_lib:format(if is_float(Time) -> "~.3fs"; true -> "~w" end, [Time]), - ErrorReason = lists:flatten(io_lib:format("~p", [Reason])), + ErrorReason = escape_chars(lists:flatten(io_lib:format("~p", [Reason]))), ErrorReason1 = lists:flatten([string:strip(S,left) || S <- string:tokens(ErrorReason,[$\n])]), ErrorReason2 = @@ -4041,7 +4048,9 @@ progress(failed, CaseNum, Mod, Func, GrName, unknown, Reason, Time, [TimeStr,Comment]), print(minor, "=== Location: ~w", [unknown]), {FStr,FormattedReason} = format_exception(Reason), - print(minor, "=== Reason: " ++ FStr, [FormattedReason]), + print(minor, + escape_chars(io_lib:format("=== Reason: " ++ FStr, [FormattedReason])), + []), failed; progress(failed, CaseNum, Mod, Func, GrName, Loc, Reason, Time, @@ -4075,7 +4084,8 @@ progress(failed, CaseNum, Mod, Func, GrName, Loc, Reason, Time, FormatLoc = test_server_sup:format_loc(LocMin), print(minor, "=== Location: ~ts", [FormatLoc]), {FStr,FormattedReason} = format_exception(Reason), - print(minor, "=== Reason: " ++ FStr, [FormattedReason]), + print(minor, "=== Reason: " ++ + escape_chars(io_lib:format(FStr, [FormattedReason])), []), failed; progress(ok, _CaseNum, Mod, Func, GrName, _Loc, RetVal, Time, @@ -4104,11 +4114,36 @@ progress(ok, _CaseNum, Mod, Func, GrName, _Loc, RetVal, Time, "<td><font color=\"green\">Ok</font></td>" "~ts</tr>\n", [Time,Comment]), - print(minor, "=== Returned value: ~p", [RetVal]), + print(minor, + escape_chars(io_lib:format("=== Returned value: ~tp", [RetVal])), + []), ok. %%-------------------------------------------------------------------- %% various help functions +escape_chars(Term) when not is_list(Term), not is_binary(Term) -> + esc_chars_in_list(io_lib:format("~tp", [Term])); +escape_chars(List = [Term | _]) when not is_list(Term), not is_integer(Term) -> + esc_chars_in_list(io_lib:format("~tp", [List])); +escape_chars(List) -> + esc_chars_in_list(List). + +esc_chars_in_list([Bin | Io]) when is_binary(Bin) -> + [Bin | esc_chars_in_list(Io)]; +esc_chars_in_list([List | Io]) when is_list(List) -> + [esc_chars_in_list(List) | esc_chars_in_list(Io)]; +esc_chars_in_list([$< | Io]) -> + ["<" | esc_chars_in_list(Io)]; +esc_chars_in_list([$> | Io]) -> + [">" | esc_chars_in_list(Io)]; +esc_chars_in_list([$& | Io]) -> + ["&" | esc_chars_in_list(Io)]; +esc_chars_in_list([Char | Io]) when is_integer(Char) -> + [Char | esc_chars_in_list(Io)]; +esc_chars_in_list([]) -> + []; +esc_chars_in_list(Bin) -> + Bin. get_fw_mod(Mod) -> case get(test_server_framework) of @@ -4322,6 +4357,10 @@ print(Detail, Format) -> print(Detail, Format, Args) -> print(Detail, Format, Args, internal). +print(Detail, ["$tc_html",Format], Args, Printer) -> + Msg = io_lib:format(Format, Args), + print_or_buffer(Detail, ["$tc_html",Msg], Printer); + print(Detail, Format, Args, Printer) -> Msg = io_lib:format(Format, Args), print_or_buffer(Detail, Msg, Printer). @@ -5564,8 +5603,9 @@ html_header(Title) -> "<html>\n" "<head>\n" "<title>", Title, "</title>\n" - "<meta http-equiv=\"cache-control\" content=\"no-cache\">\n" - "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">\n" + "<meta http-equiv=\"cache-control\" content=\"no-cache\"></meta>\n" + "<meta http-equiv=\"content-type\" content=\"text/html; " + "charset=utf-8\"></meta>\n" "</head>\n" "<body bgcolor=\"white\" text=\"black\" " "link=\"blue\" vlink=\"purple\" alink=\"red\">\n"]. diff --git a/lib/test_server/src/test_server_gl.erl b/lib/test_server/src/test_server_gl.erl index c5ec3ccbe6..444cfa595f 100644 --- a/lib/test_server/src/test_server_gl.erl +++ b/lib/test_server/src/test_server_gl.erl @@ -37,7 +37,8 @@ reject_io :: boolean(), %Reject I/O requests... permit_io, %... and exceptions auto_nl=true :: boolean(), %Automatically add NL - levels %{Stdout,Major,Minor} + levels, %{Stdout,Major,Minor} + escape_chars=true %Switch escaping HTML on/off }). %% start_link() @@ -130,6 +131,10 @@ set_props(GL, PropList) -> %%% Internal functions. init([]) -> + EscChars = case application:get_env(test_server, esc_chars) of + {ok,ECBool} -> ECBool; + _ -> true + end, {ok,#st{tc_supervisor=none, minor=none, minor_monitor=none, @@ -137,7 +142,8 @@ init([]) -> reject_io=false, permit_io=gb_sets:empty(), auto_nl=true, - levels={1,19,10} + levels={1,19,10}, + escape_chars=EscChars }}. req(GL, Req) -> @@ -182,7 +188,7 @@ handle_info({io_request,From,ReplyAs,Req}=IoReq, St) -> try io_req(Req, From, St) of passthrough -> group_leader() ! IoReq; - Data -> + {EscapeHtml,Data} -> case is_io_permitted(From, St) of false -> ok; @@ -193,7 +199,13 @@ handle_info({io_request,From,ReplyAs,Req}=IoReq, St) -> #st{capture=CapturePid} -> CapturePid ! {captured,Data} end, - output(minor, Data, From, From, St) + case EscapeHtml andalso St#st.escape_chars of + true -> + output(minor, test_server_ctrl:escape_chars(Data), + From, From, St); + false -> + output(minor, Data, From, From, St) + end end, From ! {io_reply,ReplyAs,ok} catch @@ -204,9 +216,20 @@ handle_info({io_request,From,ReplyAs,Req}=IoReq, St) -> handle_info({structured_io,ClientPid,{Detail,Str}}, St) -> output(Detail, Str, ClientPid, ClientPid, St), {noreply,St}; +handle_info({printout,Detail,["$tc_html",Format],Args}, St) -> + Str = io_lib:format(Format, Args), + output(Detail, ["$tc_html",Str], internal, none, St), + {noreply,St}; +handle_info({printout,Detail,Fun}, St) when is_function(Fun)-> + output(Detail, Fun, internal, none, St), + {noreply,St}; handle_info({printout,Detail,Format,Args}, St) -> Str = io_lib:format(Format, Args), - output(Detail, Str, internal, none, St), + if not St#st.escape_chars -> + output(Detail, ["$tc_html",Str], internal, none, St); + true -> + output(Detail, Str, internal, none, St) + end, {noreply,St}; handle_info(Msg, #st{tc_supervisor=Pid}=St) when is_pid(Pid) -> %% The process overseeing the testcase process also used to be @@ -231,25 +254,55 @@ do_set_props([{reject_io_reqs,Bool}|Ps], St) -> do_set_props(Ps, St#st{reject_io=Bool}); do_set_props([], St) -> St. -io_req({put_chars,Enc,Bytes}, _, _) when Enc =:= latin1; Enc =:= unicode -> - unicode:characters_to_list(Bytes, Enc); +io_req({put_chars,Enc,Str}, _, _) when Enc =:= latin1; Enc =:= unicode -> + case Str of + ["$tc_html",Str0] -> + {false,unicode:characters_to_list(Str0, Enc)}; + _ -> + {true,unicode:characters_to_list(Str, Enc)} + end; io_req({put_chars,Encoding,Mod,Func,[Format,Args]}, _, _) -> - Str = Mod:Func(Format, Args), - unicode:characters_to_list(Str, Encoding); + case Format of + ["$tc_html",Format0] -> + Str = Mod:Func(Format0, Args), + {false,unicode:characters_to_list(Str, Encoding)}; + _ -> + Str = Mod:Func(Format, Args), + {true,unicode:characters_to_list(Str, Encoding)} + end; io_req(_, _, _) -> passthrough. -output(Level, Str, Sender, From, St) when is_integer(Level) -> +output(Level, StrOrFun, Sender, From, St) when is_integer(Level) -> case selected_by_level(Level, stdout, St) of - true -> output(stdout, Str, Sender, From, St); - false -> ok + true when hd(StrOrFun) == "$tc_html" -> + output(stdout, tl(StrOrFun), Sender, From, St); + true when is_function(StrOrFun) -> + output(stdout, StrOrFun(stdout), Sender, From, St); + true -> + output(stdout, StrOrFun, Sender, From, St); + false -> + ok end, case selected_by_level(Level, major, St) of - true -> output(major, Str, Sender, From, St); - false -> ok + true when hd(StrOrFun) == "$tc_html" -> + output(major, tl(StrOrFun), Sender, From, St); + true when is_function(StrOrFun) -> + output(major, StrOrFun(major), Sender, From, St); + true -> + output(major, StrOrFun, Sender, From, St); + false -> + ok end, case selected_by_level(Level, minor, St) of - true -> output(minor, Str, Sender, From, St); - false -> ok + true when hd(StrOrFun) == "$tc_html" -> + output(minor, tl(StrOrFun), Sender, From, St); + true when is_function(StrOrFun) -> + output(minor, StrOrFun(minor), Sender, From, St); + true -> + output(minor, test_server_ctrl:escape_chars(StrOrFun), + Sender, From, St); + false -> + ok end; output(stdout, Str, _Sender, From, St) -> output_to_file(stdout, Str, From, St); diff --git a/lib/test_server/src/test_server_internal.hrl b/lib/test_server/src/test_server_internal.hrl index 578f359010..1ec2d83417 100644 --- a/lib/test_server/src/test_server_internal.hrl +++ b/lib/test_server/src/test_server_internal.hrl @@ -30,7 +30,6 @@ version, % string() system_version, % string() root_dir, % string() - test_server_dir, % string() emulator, % string() otp_release, % string() username, % string() diff --git a/lib/test_server/src/test_server_node.erl b/lib/test_server/src/test_server_node.erl index 4e6839fc6b..37f8941d24 100644 --- a/lib/test_server/src/test_server_node.erl +++ b/lib/test_server/src/test_server_node.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2014. All Rights Reserved. +%% Copyright Ericsson AB 2002-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -121,7 +121,7 @@ start_tracer_node(TraceFile,TI) -> %%% trace_nodes(Sock,Nodes) -> Bin = term_to_binary({add_nodes,Nodes}), - ok = gen_tcp:send(Sock, [1|Bin]), + ok = gen_tcp:send(Sock, tag_trace_message(Bin)), receive_ack(Sock). @@ -142,7 +142,7 @@ receive_ack(Sock) -> %%% stop_tracer_node(Sock) -> Bin = term_to_binary(id(stop)), - ok = gen_tcp:send(Sock, [1|Bin]), + ok = gen_tcp:send(Sock, tag_trace_message(Bin)), receive {tcp_closed,Sock} -> gen_tcp:close(Sock) end, ok. @@ -171,7 +171,7 @@ trc([TraceFile, PortAtom, Type]) -> {packet,2}]) of {ok,Sock} -> BinResult = term_to_binary(Result), - ok = gen_tcp:send(Sock,[1|BinResult]), + ok = gen_tcp:send(Sock,tag_trace_message(BinResult)), trc_loop(Sock,Patterns,Type); _else -> ok @@ -187,7 +187,7 @@ trc_loop(Sock,Patterns,Type) -> {ok,{add_nodes,Nodes}} -> add_nodes(Nodes,Patterns,Type), Bin = term_to_binary(id(ok)), - ok = gen_tcp:send(Sock, [1|Bin]), + ok = gen_tcp:send(Sock, tag_trace_message(Bin)), trc_loop(Sock,Patterns,Type); {ok,stop} -> ttb:stop(), @@ -307,11 +307,11 @@ start_node_peer(SlaveName, OptList, From, TI) -> HostStr, " ", WaitPort]), % Support for erl_crash_dump files.. - CrashFile = filename:join([TI#target_info.test_server_dir, + CrashDir = test_server_sup:crash_dump_dir(), + CrashFile = filename:join([CrashDir, "erl_crash_dump."++cast_to_list(SlaveName)]), CrashArgs = lists:concat([" -env ERL_CRASH_DUMP \"",CrashFile,"\" "]), FailOnError = start_node_get_option_value(fail_on_error, OptList, true), - Pa = TI#target_info.test_server_dir, Prog0 = start_node_get_option_value(erl, OptList, default), Prog = quote_progname(pick_erl_program(Prog0)), Args = @@ -322,7 +322,6 @@ start_node_peer(SlaveName, OptList, From, TI) -> Cmd = lists:concat([Prog, " -detached ", TI#target_info.naming, " ", SlaveName, - " -pa \"", Pa,"\"", NodeStarted, CrashArgs, " ", Args]), @@ -354,28 +353,31 @@ start_node_peer(SlaveName, OptList, From, TI) -> I = "=== Not waiting for node", gen_server:reply(From,{{ok, Nodename}, HostStr, Cmd, I, []}), Self = self(), - spawn_link( - fun() -> - wait_for_node_started(LSock,Tmo,undefined, - Cleanup,TI,Self), - receive after infinity -> ok end - end), + spawn_link(wait_for_node_started_fun(LSock,Tmo,Cleanup,TI,Self)), ok end. +-spec wait_for_node_started_fun(_, _, _, _, _) -> fun(() -> no_return()). +wait_for_node_started_fun(LSock, Tmo, Cleanup, TI, Self) -> + fun() -> + wait_for_node_started(LSock,Tmo,undefined, + Cleanup,TI,Self), + receive after infinity -> ok end + end. + %% %% Slave nodes are started on a remote host if %% - the option remote is given when calling test_server:start_node/3 %% -start_node_slave(SlaveName, OptList, From, TI) -> +start_node_slave(SlaveName, OptList, From, _TI) -> SuppliedArgs = start_node_get_option_value(args, OptList, []), Cleanup = start_node_get_option_value(cleanup, OptList, true), - CrashFile = filename:join([TI#target_info.test_server_dir, + CrashDir = test_server_sup:crash_dump_dir(), + CrashFile = filename:join([CrashDir, "erl_crash_dump."++cast_to_list(SlaveName)]), CrashArgs = lists:concat([" -env ERL_CRASH_DUMP \"",CrashFile,"\" "]), - Pa = TI#target_info.test_server_dir, - Args = lists:concat([" -pa \"", Pa, "\" ", SuppliedArgs, CrashArgs]), + Args = lists:concat([" ", SuppliedArgs, CrashArgs]), Prog0 = start_node_get_option_value(erl, OptList, default), Prog = pick_erl_program(Prog0), @@ -468,7 +470,11 @@ handle_start_node_return(Version,VsnStr,{started, Node, OVersion, OVsnStr}) -> node_started([Host,PortAtom]) -> %% Must spawn a new process because the boot process should not %% hang forever!! - spawn(fun() -> node_started(Host,PortAtom) end). + spawn(node_started_fun(Host,PortAtom)). + +-spec node_started_fun(_, _) -> fun(() -> no_return()). +node_started_fun(Host,PortAtom) -> + fun() -> node_started(Host,PortAtom) end. %% This process hangs forever, just waiting for the socket to be %% closed and terminating the node @@ -482,7 +488,7 @@ node_started(Host,PortAtom) -> {ok,Sock} -> Started = term_to_binary({started, node(), Version, VsnStr}), - ok = gen_tcp:send(Sock, [1|Started]), + ok = gen_tcp:send(Sock, tag_trace_message(Started)), receive _Anyting -> gen_tcp:close(Sock), erlang:halt() @@ -492,8 +498,10 @@ node_started(Host,PortAtom) -> end. - - +-compile({inline, [tag_trace_message/1]}). +-dialyzer({no_improper_lists, tag_trace_message/1}). +tag_trace_message(M) -> + [1|M]. % start_which_node(Optlist) -> hostname start_which_node(Optlist) -> diff --git a/lib/test_server/src/test_server_sup.erl b/lib/test_server/src/test_server_sup.erl index fc2cfd57bd..c4530ba62f 100644 --- a/lib/test_server/src/test_server_sup.erl +++ b/lib/test_server/src/test_server_sup.erl @@ -594,7 +594,11 @@ cleanup_crash_dumps() -> delete_files(Dumps). crash_dump_dir() -> - filename:dirname(code:which(?MODULE)). + %% If no framework is known, then we use current working directory + %% - in most cases that will be the same as the default log + %% directory. + {ok,Dir} = test_server_sup:framework_call(get_log_dir,[],file:get_cwd()), + Dir. tar_crash_dumps() -> Dir = crash_dump_dir(), diff --git a/lib/test_server/src/ts_install_cth.erl b/lib/test_server/src/ts_install_cth.erl index ec0d54ccde..0462e62611 100644 --- a/lib/test_server/src/ts_install_cth.erl +++ b/lib/test_server/src/ts_install_cth.erl @@ -41,6 +41,8 @@ -export([post_end_per_group/4]). -export([pre_init_per_testcase/3]). +-export([post_init_per_testcase/4]). +-export([pre_end_per_testcase/3]). -export([post_end_per_testcase/4]). -export([on_tc_fail/3]). @@ -181,7 +183,22 @@ post_end_per_group(_Group,_Config,Return,State) -> pre_init_per_testcase(_TC,Config,State) -> {add_node_name(Config, State), State}. +-spec post_init_per_testcase(TC :: atom(), + Config :: config(), + Return :: term(), + State :: #state{}) -> + {ok | skip_or_fail(), NewState :: #state{}}. +post_init_per_testcase(_TC,_Config,Return,State) -> + {Return, State}. + %% @doc Called after each test case. +-spec pre_end_per_testcase(TC :: atom(), + Config :: config(), + State :: #state{}) -> + {config() | skip_or_fail(), NewState :: #state{}}. +pre_end_per_testcase(_TC,Config,State) -> + {Config, State}. + -spec post_end_per_testcase(TC :: atom(), Config :: config(), Return :: term(), diff --git a/lib/test_server/src/ts_lib.erl b/lib/test_server/src/ts_lib.erl index 61bd55a654..7c3f450194 100644 --- a/lib/test_server/src/ts_lib.erl +++ b/lib/test_server/src/ts_lib.erl @@ -250,12 +250,10 @@ do_test(Rest, Vars, Test) -> {Result,Comment,Rest2}. %% extract an argument -get_arg([$ |Rest], Vars, Stop, Acc) -> - get_arg(Rest, Vars, Stop, Acc); get_arg([$(|Rest], Vars, Stop, _) -> get_arg(Rest, Vars, Stop, []); get_arg([Stop|Rest], Vars, Stop, Acc) -> - Arg = lists:reverse(Acc), + Arg = string:strip(lists:reverse(Acc)), Subst = subst(Arg, Vars), {Subst,Rest}; get_arg([C|Rest], Vars, Stop, Acc) -> diff --git a/lib/test_server/test/erl2html2_SUITE.erl b/lib/test_server/test/erl2html2_SUITE.erl index 9e6389109b..8e9f6e773a 100644 --- a/lib/test_server/test/erl2html2_SUITE.erl +++ b/lib/test_server/test/erl2html2_SUITE.erl @@ -31,7 +31,7 @@ "<html>\n", "<head><title>Module ", Src, "</title>\n", "<meta http-equiv=\"cache-control\" ", - "content=\"no-cache\">\n", + "content=\"no-cache\"></meta>\n", "</head>\n", "<body bgcolor=\"white\" text=\"black\" ", "link=\"blue\" vlink=\"purple\" alink=\"red\">\n"]). diff --git a/lib/test_server/vsn.mk b/lib/test_server/vsn.mk index fd9e4e6d74..8c5fc97383 100644 --- a/lib/test_server/vsn.mk +++ b/lib/test_server/vsn.mk @@ -1 +1 @@ -TEST_SERVER_VSN = 3.9 +TEST_SERVER_VSN = 3.10 diff --git a/lib/tools/doc/src/eprof.xml b/lib/tools/doc/src/eprof.xml index 7dccd927ca..8e37d49c99 100644 --- a/lib/tools/doc/src/eprof.xml +++ b/lib/tools/doc/src/eprof.xml @@ -131,13 +131,13 @@ <name>analyze() -> ok</name> <name>analyze(Type) -> ok</name> <name>analyze(Type,Options) -> ok</name> + <fsummary>Display profiling results per process.</fsummary> <type> <v>Type = procs | total</v> <v>Options = [{filter, Filter} | {sort, Sort}</v> <v>Filter = [{calls, integer()} | {time, float()}]</v> <v>Sort = time | calls | mfa</v> </type> - <fsummary>Display profiling results per process.</fsummary> <desc> <p>Call this function when profiling has been stopped to display the results per process, that is:</p> diff --git a/lib/tools/doc/src/make.xml b/lib/tools/doc/src/make.xml index e63163d689..5c2e5e5d62 100644 --- a/lib/tools/doc/src/make.xml +++ b/lib/tools/doc/src/make.xml @@ -76,7 +76,7 @@ Load mode. Loads all recompiled modules.</item> <item><c>netload</c> <br></br> - Net load mode. Loads all recompiled modules an all known nodes.</item> + Net load mode. Loads all recompiled modules on all known nodes.</item> </list> <p>All items in <c>Options</c> that are not make options are assumed to be compiler options and are passed as-is to diff --git a/lib/tools/doc/src/notes.xml b/lib/tools/doc/src/notes.xml index e788814564..c62b0607ee 100644 --- a/lib/tools/doc/src/notes.xml +++ b/lib/tools/doc/src/notes.xml @@ -31,6 +31,67 @@ </header> <p>This document describes the changes made to the Tools application.</p> +<section><title>Tools 2.8.3</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + <c>cover:compile_beam/1</c> and + <c>cover:compile_beam_directory/1,2</c> crashed when + trying to compile a beam file without a <c>'file'</c> + attribute. This has been corrected and an error is + returned instead.</p> + <p> + Thanks to Louis-Philippe Gauthier for reporting this bug.</p> + <p> + Own Id: OTP-13200</p> + </item> + <item> + <p>Fix a bit string comprehension bug in Cover. </p> + <p> + Own Id: OTP-13277 Aux Id: PR 856 </p> + </item> + </list> + </section> + +</section> + +<section><title>Tools 2.8.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The emacs mode does not add a newline after the arrow on + -callback lines anymore.</p> + <p> + Own Id: OTP-13042</p> + </item> + </list> + </section> + +</section> + +<section><title>Tools 2.8.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + If a module includes eunit.hrl, a parse transform adds + the function test/0 on line 0 in the module. A bug in + OTP-18.0 caused cover:analyse_to_file/1 to fail to insert + cover data in the output file when line 0 existed in the + cover data table. This is now corrected.</p> + <p> + Own Id: OTP-12981</p> + </item> + </list> + </section> + +</section> + <section><title>Tools 2.8</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/tools/emacs/erlang.el b/lib/tools/emacs/erlang.el index 4aa1ab7d38..466bf139b9 100644 --- a/lib/tools/emacs/erlang.el +++ b/lib/tools/emacs/erlang.el @@ -4236,7 +4236,7 @@ This function is designed to be a member of a criteria list." This function is designed to be a member of a criteria list." (save-excursion (beginning-of-line) - (when (save-match-data (looking-at "-\\(spec\\|type\\)")) + (when (save-match-data (looking-at "-\\(spec\\|type\\|callback\\)")) 'stop))) diff --git a/lib/tools/src/cover.erl b/lib/tools/src/cover.erl index 8d1cb96504..d16ca7f406 100644 --- a/lib/tools/src/cover.erl +++ b/lib/tools/src/cover.erl @@ -1474,7 +1474,7 @@ do_compile_beam(Module,BeamFile0,State) -> {ok,Module,BeamFile}; error -> {error, BeamFile}; - {error,Reason} -> % no abstract code + {error,Reason} -> % no abstract code or no 'file' attribute {error, {Reason, BeamFile}} end; {error,no_beam} -> @@ -1537,32 +1537,11 @@ do_compile_beam1(Module,Beam,UserOptions) -> {error,E}; {raw_abstract_v1,Code} -> Forms0 = epp:interpret_file_attribute(Code), - {Forms,Vars} = transform(Forms0, Module), - - %% We need to recover the source from the compilation - %% info otherwise the newly compiled module will have - %% source pointing to the current directory - SourceInfo = get_source_info(Module, Beam), - - %% Compile and load the result - %% It's necessary to check the result of loading since it may - %% fail, for example if Module resides in a sticky directory - {ok, Module, Binary} = compile:forms(Forms, SourceInfo ++ UserOptions), - case code:load_binary(Module, ?TAG, Binary) of - {module, Module} -> - - %% Store info about all function clauses in database - InitInfo = lists:reverse(Vars#vars.init_info), - ets:insert(?COVER_CLAUSE_TABLE, {Module, InitInfo}), - - %% Store binary code so it can be loaded on remote nodes - ets:insert(?BINARY_TABLE, {Module, Binary}), - - {ok, Module}; - - _Error -> - do_clear(Module), - error + case find_main_filename(Forms0) of + {ok,MainFile} -> + do_compile_beam2(Module,Beam,UserOptions,Forms0,MainFile); + Error -> + Error end; {_VSN,_Code} -> %% Wrong version of abstract code. Just report that there @@ -1579,6 +1558,35 @@ get_abstract_code(Module, Beam) -> Error -> Error end. +do_compile_beam2(Module,Beam,UserOptions,Forms0,MainFile) -> + {Forms,Vars} = transform(Forms0, Module, MainFile), + + %% We need to recover the source from the compilation + %% info otherwise the newly compiled module will have + %% source pointing to the current directory + SourceInfo = get_source_info(Module, Beam), + + %% Compile and load the result + %% It's necessary to check the result of loading since it may + %% fail, for example if Module resides in a sticky directory + {ok, Module, Binary} = compile:forms(Forms, SourceInfo ++ UserOptions), + case code:load_binary(Module, ?TAG, Binary) of + {module, Module} -> + + %% Store info about all function clauses in database + InitInfo = lists:reverse(Vars#vars.init_info), + ets:insert(?COVER_CLAUSE_TABLE, {Module, InitInfo}), + + %% Store binary code so it can be loaded on remote nodes + ets:insert(?BINARY_TABLE, {Module, Binary}), + + {ok, Module}; + + _Error -> + do_clear(Module), + error + end. + get_source_info(Module, Beam) -> Compile = get_compile_info(Module, Beam), case lists:keyfind(source, 1, Compile) of @@ -1601,8 +1609,7 @@ get_compile_info(Module, Beam) -> [] end. -transform(Code, Module) -> - MainFile=find_main_filename(Code), +transform(Code, Module, MainFile) -> Vars0 = #vars{module=Module}, {ok,MungedForms,Vars} = transform_2(Code,[],Vars0,MainFile,on), {MungedForms,Vars}. @@ -1610,9 +1617,12 @@ transform(Code, Module) -> %% Helpfunction which returns the first found file-attribute, which can %% be interpreted as the name of the main erlang source file. find_main_filename([{attribute,_,file,{MainFile,_}}|_]) -> - MainFile; + {ok,MainFile}; find_main_filename([_|Rest]) -> - find_main_filename(Rest). + find_main_filename(Rest); +find_main_filename([]) -> + {error, no_file_attribute}. + transform_2([Form0|Forms],MungedForms,Vars,MainFile,Switch) -> Form = expand(Form0), @@ -1995,7 +2005,7 @@ munge_expr({lc,Line,Expr,Qs}, Vars) -> {{lc,Line,MungedExpr,MungedQs}, Vars3}; munge_expr({bc,Line,Expr,Qs}, Vars) -> {bin,BLine,[{bin_element,EL,Val,Sz,TSL}|Es]} = Expr, - Expr2 = {bin,BLine,[{bin_element,EL,?BLOCK1(Val),Sz,TSL}|Es]}, + Expr2 = {bin,BLine,[{bin_element,EL,Val,Sz,TSL}|Es]}, {MungedExpr,Vars2} = munge_expr(Expr2, Vars), {MungedQs, Vars3} = munge_qualifiers(Qs, Vars2), {{bc,Line,MungedExpr,MungedQs}, Vars3}; @@ -2437,7 +2447,7 @@ do_analyse_to_file1(Module, OutFile, ErlFile, HTML) -> "\n\n"]), Pattern = {#bump{module=Module,line='$1',_='_'},'$2'}, - MS = [{Pattern,[],[{{'$1','$2'}}]}], + MS = [{Pattern,[{is_integer,'$1'},{'>','$1',0}],[{{'$1','$2'}}]}], CovLines = lists:keysort(1,ets:select(?COLLECTION_TABLE, MS)), print_lines(Module, CovLines, InFd, OutFd, 1, HTML), diff --git a/lib/tools/src/cprof.erl b/lib/tools/src/cprof.erl index 0240f876bc..f6d68f0bf8 100644 --- a/lib/tools/src/cprof.erl +++ b/lib/tools/src/cprof.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2009. All Rights Reserved. +%% Copyright Ericsson AB 2002-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -114,6 +114,7 @@ analyse(Limit) when is_integer(Limit) -> analyse(M) when is_atom(M) -> analyse(M, 1). +-dialyzer({no_improper_lists, analyse/2}). analyse(M, Limit) when is_atom(M), is_integer(Limit) -> L0 = [begin MFA = {M,F,A}, diff --git a/lib/tools/src/fprof.erl b/lib/tools/src/fprof.erl index 7c6fab0b75..c5c24c8eb3 100644 --- a/lib/tools/src/fprof.erl +++ b/lib/tools/src/fprof.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2013. All Rights Reserved. +%% Copyright Ericsson AB 2001-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -2251,6 +2251,8 @@ do_analyse(Table, Analyse) -> ?dbg(5, "do_analyse_1(_, _) ->~p~n", [Result]), Result. +-dialyzer({no_improper_lists, do_analyse_1/2}). + do_analyse_1(Table, #analyse{group_leader = GroupLeader, dest = Io, @@ -2624,6 +2626,8 @@ funcstat_pd(Pid, Func1, Func0, Clocks) -> funcstat_sort_r(FuncstatList, Element) -> funcstat_sort_r_1(FuncstatList, Element, []). +-dialyzer({no_improper_lists, funcstat_sort_r_1/3}). + funcstat_sort_r_1([], _, R) -> postsort_r(lists:sort(R)); funcstat_sort_r_1([#funcstat{callers_sum = #clocks{} = Clocks, @@ -2646,6 +2650,8 @@ funcstat_sort_r_1([#funcstat{callers_sum = #clocks{} = Clocks, clocks_sort_r(L, E) -> clocks_sort_r_1(L, E, []). +-dialyzer({no_improper_lists, clocks_sort_r_1/3}). + clocks_sort_r_1([], _, R) -> postsort_r(lists:sort(R)); clocks_sort_r_1([#clocks{} = C | L], E, R) -> diff --git a/lib/tools/src/lcnt.erl b/lib/tools/src/lcnt.erl index e8b3d242e4..3a3cebf3ed 100644 --- a/lib/tools/src/lcnt.erl +++ b/lib/tools/src/lcnt.erl @@ -933,7 +933,6 @@ strings(Strings) -> strings(Strings, []). strings([], Out) -> Out; strings([{space, N, S} | Ss], Out) -> strings(Ss, Out ++ term2string(term2string("~~~ws", [N]), [S])); strings([{left, N, S} | Ss], Out) -> strings(Ss, Out ++ term2string(term2string(" ~~s~~~ws", [N]), [S,""])); -strings([{format, Format, S} | Ss], Out) -> strings(Ss, Out ++ term2string(Format, [S])); strings([S|Ss], Out) -> strings(Ss, Out ++ term2string("~ts", [S])). diff --git a/lib/tools/src/make.erl b/lib/tools/src/make.erl index 96c3e0e506..5d5a1ef2bd 100644 --- a/lib/tools/src/make.erl +++ b/lib/tools/src/make.erl @@ -25,12 +25,20 @@ %% If Emakefile is missing the current directory is used. -module(make). --export([all/0,all/1,files/1,files/2]). +-export([all_or_nothing/0,all/0,all/1,files/1,files/2]). -include_lib("kernel/include/file.hrl"). -define(MakeOpts,[noexec,load,netload,noload]). +all_or_nothing() -> + case all() of + up_to_date -> + up_to_date; + error -> + halt(1) + end. + all() -> all([]). diff --git a/lib/tools/src/xref_utils.erl b/lib/tools/src/xref_utils.erl index 438ec93962..f69aa70244 100644 --- a/lib/tools/src/xref_utils.erl +++ b/lib/tools/src/xref_utils.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2014. All Rights Reserved. +%% Copyright Ericsson AB 2000-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -245,6 +245,8 @@ select_last_application_version(AppVs) -> TL = to_external(partition(1, relation(AppVs))), [last(keysort(2, L)) || L <- TL]. +-record(scan, {collected = [], errors = [], seen = [], unreadable = []}). + %% scan_directory(Directory, Recurse, Collect, Watch) -> %% {Collected, Errors, Seen, Unreadable} %% @@ -261,8 +263,9 @@ select_last_application_version(AppVs) -> %% Unreadable. %% scan_directory(File, Recurse, Collect, Watch) -> - Init = [[] | {[],[],[]}], - [L | {E,J,U}] = find_files_dir(File, Recurse, Collect, Watch, Init), + Init = #scan{}, + S = find_files_dir(File, Recurse, Collect, Watch, Init), + #scan{collected = L, errors = E, seen = J, unreadable = U} = S, {reverse(L), reverse(E), reverse(J), reverse(U)}. %% {Dir, Basename} | false @@ -576,8 +579,7 @@ find_files_dir(Dir, Recurse, Collect, Watch, L) -> {ok, Files} -> find_files(sort(Files), Dir, Recurse, Collect, Watch, L); {error, Error} -> - [B | {E,J,U}] = L, - [B | {[file_error(Dir, Error)|E],J,U}] + L#scan{errors = [file_error(Dir, Error)|L#scan.errors]} end. find_files([F | Fs], Dir, Recurse, Collect, Watch, L) -> @@ -588,22 +590,23 @@ find_files([F | Fs], Dir, Recurse, Collect, Watch, L) -> {ok, {_, directory, _, _}} -> L; Info -> - [B | EJU = {E,J,U}] = L, + #scan{collected = B, errors = E, + seen = J, unreadable = U} = L, Ext = filename:extension(File), C = member(Ext, Collect), case C of true -> case Info of {ok, {_, file, readable, _}} -> - [[{Dir,F} | B] | EJU]; + L#scan{collected = [{Dir,F} | B]}; {ok, {_, file, unreadable, _}} -> - [B | {E,J,[File|U]}]; + L#scan{unreadable = [File|U]}; Error -> - [B | {[Error|E],J,U}] + L#scan{errors = [Error|E]} end; false -> case member(Ext, Watch) of - true -> [B | {E,[File|J],U}]; + true -> L#scan{seen = [File|J]}; false -> L end end diff --git a/lib/tools/test/cover_SUITE.erl b/lib/tools/test/cover_SUITE.erl index 931e3e2cfa..71570a55fa 100644 --- a/lib/tools/test/cover_SUITE.erl +++ b/lib/tools/test/cover_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2015. All Rights Reserved. +%% Copyright Ericsson AB 2001-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -19,43 +19,17 @@ %% -module(cover_SUITE). --export([all/0, init_per_testcase/2, end_per_testcase/2, - suite/0,groups/0,init_per_suite/1, end_per_suite/1, - init_per_group/2,end_per_group/2]). - --export([coverage/1, coverage_analysis/1, - start/1, compile/1, analyse/1, misc/1, stop/1, - distribution/1, reconnect/1, die_and_reconnect/1, - dont_reconnect_after_stop/1, stop_node_after_disconnect/1, - export_import/1, - otp_5031/1, eif/1, otp_5305/1, otp_5418/1, otp_6115/1, otp_7095/1, - otp_8188/1, otp_8270/1, otp_8273/1, otp_8340/1, - otp_10979_hanging_node/1, compile_beam_opts/1, eep37/1, - analyse_no_beam/1]). - --export([do_coverage/1]). - --export([distribution_performance/1]). +-compile(export_all). -include_lib("test_server/include/test_server.hrl"). -%%---------------------------------------------------------------------- -%% The following directory structure is assumed: -%% cwd __________________________________________ -%% | \ \ \ \ \ \ \ -%% a b cc d f d1 compile_beam_____ otp_6115 -%% | \ \ \ \ \ \ \ -%% e crypt v w x d f1 f2 -%% | -%% y -%%---------------------------------------------------------------------- - suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> NoStartStop = [eif,otp_5305,otp_5418,otp_7095,otp_8273, otp_8340,otp_8188,compile_beam_opts,eep37, - analyse_no_beam], + analyse_no_beam, line_0, compile_beam_no_file, + otp_13277], StartStop = [start, compile, analyse, misc, stop, distribution, reconnect, die_and_reconnect, dont_reconnect_after_stop, stop_node_after_disconnect, @@ -778,8 +752,8 @@ distribution_performance(Config) -> %% [{ok,_} = cover:compile_beam(Mod) || Mod <- Mods] %% end, CFun = fun() -> cover:compile_beam(Mods) end, - {CT,CA} = timer:tc(CFun), -% erlang:display(CA), + {CT,_CA} = timer:tc(CFun), +% erlang:display(_CA), erlang:display({compile,CT}), {SNT,_} = timer:tc(fun() -> {ok,[N1]} = cover:start(nodes()) end), @@ -799,7 +773,7 @@ distribution_performance(Config) -> % Fun = fun() -> cover:reset() end, - {AT,A} = timer:tc(Fun), + {AT,_A} = timer:tc(Fun), erlang:display({analyse,AT}), % erlang:display(lists:sort([X || X={_MFA,N} <- lists:append([L || {ok,L}<-A]), N=/=0])), @@ -1279,7 +1253,7 @@ otp_8340(doc) -> ["OTP-8340. Bug."]; otp_8340(suite) -> []; otp_8340(Config) when is_list(Config) -> - ?line [{{t,1},1},{{t,2},1},{{t,4},1}] = + ?line [{{t,1},1},{{t,4},1}] = analyse_expr(<<"<< \n" " <<3:2, \n" " SeqId:62>> \n" @@ -1573,8 +1547,10 @@ comprehension_8188(Cf) -> " true]. \n" % 2 " two() -> 2">>, Cf), % 1 + %% The template cannot have a counter since it is not allowed to + %% be a block. ?line [{{t,1},1}, - {{t,2},2}, + %% {{t,2},2}, {{t,3},1}, {{t,4},1}, {{t,5},0}, @@ -1584,7 +1560,7 @@ comprehension_8188(Cf) -> {{t,13},2}, {{t,14},2}] = analyse_expr(<<"<< \n" % 1 - " << (X*2) >> || \n" % 2 + " << (X*2) >> || \n" % 2 (now: 0) " <<X>> <= << (case two() of\n" " 2 -> 1;\n" % 1 " _ -> 2\n" % 0 @@ -1599,7 +1575,7 @@ comprehension_8188(Cf) -> "two() -> 2">>, Cf), ?line [{{t,1},1}, - {{t,2},4}, + %% {{t,2},4}, {{t,4},1}, {{t,6},1}, {{t,7},0}, @@ -1608,7 +1584,7 @@ comprehension_8188(Cf) -> {{t,12},4}, {{t,13},1}] = analyse_expr(<<"<< \n" % 1 - " << (2)\n" % 4 + " << (2)\n" % 4 (now: 0) " :(8) >> || \n" " <<X>> <= << 1,\n" % 1 " (case two() of \n" @@ -1727,6 +1703,69 @@ analyse_no_beam(Config) when is_list(Config) -> ok = file:set_cwd(Cwd), ok. +%% When including eunit.hrl, a parse transform adds the function +%% test/0 to line 0 in your module. A bug in OTP-18.0 caused +%% cover:analyse_to_file/1 to fail to insert cover data in the output +%% file in this situation. The test below tests that this bug is +%% corrected. +line_0(Config) -> + ok = file:set_cwd(filename:join(?config(data_dir, Config), + "include_eunit_hrl")), + {ok, cover_inc_eunit} = compile:file(cover_inc_eunit,[debug_info]), + {ok, cover_inc_eunit} = cover:compile_beam(cover_inc_eunit), + {ok, CovOut} = cover:analyse_to_file(cover_inc_eunit), + + {ok,Bin} = file:read_file(CovOut), + Match = <<"0..| ok.\n">>, % "0.." is missing when bug is there + S = byte_size(Bin)-byte_size(Match), + <<_:S/binary,Match/binary>> = Bin, + ok. + + +%% OTP-13200: Return error instead of crashing when trying to compile +%% a beam which has no 'file' attribute. +compile_beam_no_file(Config) -> + PrivDir = ?config(priv_dir,Config), + Dir = filename:join(PrivDir,"compile_beam_no_file"), + ok = filelib:ensure_dir(filename:join(Dir,"*")), + code:add_patha(Dir), + Str = lists:concat( + ["-module(nofile).\n" + "-compile(export_all).\n" + "foo() -> ok.\n"]), + TT = do_scan(Str), + Forms = [ begin {ok,Y} = erl_parse:parse_form(X),Y end || X <- TT ], + {ok,_,Bin} = compile:forms(Forms,[debug_info]), + BeamFile = filename:join(Dir,"nofile.beam"), + ok = file:write_file(BeamFile,Bin), + {error,{no_file_attribute,BeamFile}} = cover:compile_beam(nofile), + [{error,{no_file_attribute,BeamFile}}] = cover:compile_beam_directory(Dir), + ok. + +do_scan([]) -> + []; +do_scan(Str) -> + {done,{ok,T,_},C} = erl_scan:tokens([],Str,0), + [ T | do_scan(C) ]. + +otp_13277(doc) -> + ["PR 856. Fix a bc bug."]; +otp_13277(Config) -> + Test = <<"-module(t). + -export([t/0]). + + pad(A, L) -> + P = << <<\"#\">> || _ <- lists:seq(1, L) >>, + <<A/binary, P/binary>>. + + t() -> + pad(<<\"hi\">>, 2). + ">>, + ?line File = cc_mod(t, Test, Config), + ?line <<"hi##">> = t:t(), + ?line ok = file:delete(File), + ok. + %%--Auxiliary------------------------------------------------------------ analyse_expr(Expr, Config) -> diff --git a/lib/tools/test/cover_SUITE_data/cc.erl b/lib/tools/test/cover_SUITE_data/cc.erl index 587bdbe493..7eb165ef8a 100644 --- a/lib/tools/test/cover_SUITE_data/cc.erl +++ b/lib/tools/test/cover_SUITE_data/cc.erl @@ -1,88 +1,17 @@ -module(cc). --export([epp/1, epp/2, dbg/1, dbg/2, cvr/1, cvr/2]). --export([p/2, pp/2]). +-compile(export_all). -%% epp(Module) - Creates Module.epp which contains all forms of Module -%% as obtained by using epp. -%% -%% dbg(Module) - Creates Module.dbg which contains all forms of Module -%% as obtained by using beam_lib:chunks/2. -%% -%% cvr(Module) - Creates Module.cvr which contains all forms of Module -%% as obtained by using cover:transform/3. -%% +%% This is a dummy module used only for cover compiling. The content +%% of this module has no meaning for the test. -epp(Module) -> - epp(Module, p). -epp(Module, P) -> - File = atom_to_list(Module)++".erl", - {ok,Cwd} = file:get_cwd(), - {ok, Fd1} = epp:open(File, [Cwd], []), - {ok, Fd2} = file:open(atom_to_list(Module)++".epp", write), +foo() -> + T = erlang:time(), + spawn(fun() -> bar(T) end). - epp(Fd1, Fd2, P), - - epp:close(Fd1), - file:close(Fd2), - ok. - -epp(Fd1, Fd2, P) -> - case epp:parse_erl_form(Fd1) of - {ok, {attribute,Line,Attr,Data}} -> - epp(Fd1, Fd2, P); - {ok, Form} when P==p -> - io:format(Fd2, "~p.~n", [Form]), - epp(Fd1, Fd2, P); - {ok, Form} when P==pp -> - io:format(Fd2, "~p.~n", [erl_pp:form(Form)]), - epp(Fd1, Fd2, P); - {eof, Line} -> - ok - end. - -cvr(Module) -> - cvr(Module, p). -cvr(Module, P) -> - case beam_lib:chunks(Module, [abstract_code]) of - {ok, {Module, [{abstract_code, no_abstract_code}]}} -> - {error, {no_debug_info,Module}}; - {ok, {Module, [{abstract_code, {Vsn, Forms}}]}} -> - Vars = {vars,Module,Vsn, [], - undefined, undefined, undefined, undefined, undefined, - undefined, - false}, - {ok, TForms, _Vars2} = cover:transform(Forms, [], Vars), - File = atom_to_list(Module)++".cvr", - apply(?MODULE, P, [File, TForms]); - Error -> - Error +bar(T) -> + receive + X -> + T1 = erlang:time(), + io:format("received ~p at ~p. Last time: ~p~n",[X,T1,T]), + bar(T1) end. - -dbg(Module) -> - dbg(Module, p). -dbg(Module, P) -> - case beam_lib:chunks(Module, [abstract_code]) of - {ok, {Module, [{abstract_code, no_abstract_code}]}} -> - {error, {no_debug_info,Module}}; - {ok, {Module, [{abstract_code, {Vsn, Forms}}]}} -> - File = atom_to_list(Module)++".dbg", - apply(?MODULE, P, [File, Forms]); - Error -> - Error - end. - -p(File, Forms) -> - {ok, Fd} = file:open(File, write), - lists:foreach(fun(Form) -> - io:format(Fd, "~p.~n", [Form]) - end, - Forms), - file:close(Fd). - -pp(File, Forms) -> - {ok, Fd} = file:open(File, write), - lists:foreach(fun(Form) -> - io:format(Fd, "~s", [erl_pp:form(Form)]) - end, - Forms), - file:close(Fd). diff --git a/lib/tools/test/cover_SUITE_data/include_eunit_hrl/cover_inc_eunit.erl b/lib/tools/test/cover_SUITE_data/include_eunit_hrl/cover_inc_eunit.erl new file mode 100644 index 0000000000..c1fe7939d2 --- /dev/null +++ b/lib/tools/test/cover_SUITE_data/include_eunit_hrl/cover_inc_eunit.erl @@ -0,0 +1,6 @@ +-module(cover_inc_eunit). +-compile(export_all). +-include_lib("eunit/include/eunit.hrl"). + +func() -> + ok. diff --git a/lib/tools/vsn.mk b/lib/tools/vsn.mk index 68c3f6e29c..70564f05c6 100644 --- a/lib/tools/vsn.mk +++ b/lib/tools/vsn.mk @@ -1 +1 @@ -TOOLS_VSN = 2.8 +TOOLS_VSN = 2.8.3 diff --git a/lib/typer/doc/src/notes.xml b/lib/typer/doc/src/notes.xml index 044873ec94..21a2a6d597 100644 --- a/lib/typer/doc/src/notes.xml +++ b/lib/typer/doc/src/notes.xml @@ -31,6 +31,21 @@ </header> <p>This document describes the changes made to TypEr.</p> +<section><title>TypEr 0.9.10</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>Fix a bug that could result in a crash when printing + warnings onto standard error. </p> + <p> + Own Id: OTP-13010</p> + </item> + </list> + </section> + +</section> + <section><title>TypEr 0.9.9</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/typer/src/typer.erl b/lib/typer/src/typer.erl index ec00bfaba0..562530c868 100644 --- a/lib/typer/src/typer.erl +++ b/lib/typer/src/typer.erl @@ -1012,15 +1012,7 @@ compile_error(Reason) -> -spec msg(string()) -> 'ok'. msg(Msg) -> - case os:type() of - {unix, _} -> % Output a message on 'stderr', if possible - P = open_port({fd, 0, 2}, [out]), - port_command(P, Msg), - true = port_close(P), - ok; - _ -> % win32 - io:format("~s", [Msg]) - end. + io:format(standard_error, "~s", [Msg]). %%-------------------------------------------------------------------- %% Version and help messages. diff --git a/lib/typer/vsn.mk b/lib/typer/vsn.mk index 74c0ccfc59..507593ef56 100644 --- a/lib/typer/vsn.mk +++ b/lib/typer/vsn.mk @@ -1 +1 @@ -TYPER_VSN = 0.9.9 +TYPER_VSN = 0.9.10 diff --git a/lib/webtool/doc/src/notes.xml b/lib/webtool/doc/src/notes.xml index 21309261a8..0ebb66ae3c 100644 --- a/lib/webtool/doc/src/notes.xml +++ b/lib/webtool/doc/src/notes.xml @@ -32,6 +32,22 @@ <p>This document describes the changes made to the Webtool application.</p> +<section><title>WebTool 0.9.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Remove dependency to inets <c>mod_include</c> in + configuration.</p> + <p> + Own Id: OTP-13406</p> + </item> + </list> + </section> + +</section> + <section><title>WebTool 0.9</title> <section><title>Improvements and New Features</title> diff --git a/lib/webtool/src/webtool.erl b/lib/webtool/src/webtool.erl index 80dad53f8f..a0f2b5aab0 100644 --- a/lib/webtool/src/webtool.erl +++ b/lib/webtool/src/webtool.erl @@ -583,7 +583,6 @@ rest_of_standard_data() -> mod_esi, mod_actions, mod_cgi, - mod_include, mod_dir, mod_get, mod_head, diff --git a/lib/webtool/vsn.mk b/lib/webtool/vsn.mk index 4a701ae6e0..92201282c0 100644 --- a/lib/webtool/vsn.mk +++ b/lib/webtool/vsn.mk @@ -1 +1 @@ -WEBTOOL_VSN=0.9 +WEBTOOL_VSN=0.9.1 diff --git a/lib/wx/api_gen/Makefile b/lib/wx/api_gen/Makefile index d605f3d8d8..3fa8f1feee 100644 --- a/lib/wx/api_gen/Makefile +++ b/lib/wx/api_gen/Makefile @@ -49,7 +49,7 @@ opt: $(WX) $(GL) $(WX): wxxml_generated $(COMPILER_T) wxapi.conf $(wildcard wx_extra/wx*.c_src) $(wildcard wx_extra/wx*.erl) erl -noshell -run wx_gen code && touch wx_code_generated -wxxml_generated: wx_doxygen.conf wx_extra/bugs.h wx_extra/wxe_evth.h +wxxml_generated: wx_doxygen.conf wx_extra/bugs.h wx_extra/wxe_evth.h wx_extra/added_func.h sed -e 's|@WXGTK_DIR@|$(WXGTK_DIR)|g' wx_doxygen.conf > wx_doxygen doxygen wx_doxygen && touch wxxml_generated diff --git a/lib/wx/api_gen/gen_util.erl b/lib/wx/api_gen/gen_util.erl index 6bdbb4ca96..ff245a6359 100644 --- a/lib/wx/api_gen/gen_util.erl +++ b/lib/wx/api_gen/gen_util.erl @@ -230,7 +230,7 @@ erl_copyright() -> w("%% Copyright Ericsson AB ~p-~p. All Rights Reserved.~n", [StartYear, CurrentYear]), w("%%~n",[]), - w("%% Licensed under the Apache License, Version 2.0 (the \"License\");,~n",[]), + w("%% Licensed under the Apache License, Version 2.0 (the \"License\");~n",[]), w("%% you may not use this file except in compliance with the License.~n",[]), w("%% You may obtain a copy of the License at~n",[]), w("%%~n",[]), @@ -251,7 +251,7 @@ c_copyright() -> w(" *~n",[]), w(" * Copyright Ericsson AB 2008-~p. All Rights Reserved.~n",[CurrentYear]), w(" *~n",[]), - w(" * Licensed under the Apache License, Version 2.0 (the \"License\");,~n",[]), + w(" * Licensed under the Apache License, Version 2.0 (the \"License\");~n",[]), w(" * you may not use this file except in compliance with the License.~n",[]), w(" * You may obtain a copy of the License at~n",[]), w(" *~n",[]), diff --git a/lib/wx/api_gen/gl_gen.erl b/lib/wx/api_gen/gl_gen.erl index 8b24e38cc0..ab8f842d31 100644 --- a/lib/wx/api_gen/gl_gen.erl +++ b/lib/wx/api_gen/gl_gen.erl @@ -191,7 +191,7 @@ parse_define([#xmlElement{name=initializer,content=Contents}|_R],Def,_Os) -> try case Val0 of "0x" ++ Val1 -> - _ = http_util:hexlist_to_integer(Val1), + _ = list_to_integer(Val1, 16), Def#def{val=Val1, type=hex}; _ -> Val = list_to_integer(Val0), diff --git a/lib/wx/api_gen/gl_gen_erl.erl b/lib/wx/api_gen/gl_gen_erl.erl index 20406a8d05..84e9600bc0 100644 --- a/lib/wx/api_gen/gl_gen_erl.erl +++ b/lib/wx/api_gen/gl_gen_erl.erl @@ -226,10 +226,14 @@ gen_types(Where) -> w("-type clamp() :: float(). %% 0.0..1.0~n", []), w("-type offset() :: non_neg_integer(). %% Offset in memory block~n", []) end, - w("-type matrix() :: {float(),float(),float(),float(),~n", []), + w("-type matrix12() :: {float(),float(),float(),float(),~n", []), + w(" float(),float(),float(),float(),~n", []), + w(" float(),float(),float(),float()}.~n", []), + w("-type matrix16() :: {float(),float(),float(),float(),~n", []), w(" float(),float(),float(),float(),~n", []), w(" float(),float(),float(),float(),~n", []), w(" float(),float(),float(),float()}.~n", []), + w("-type matrix() :: matrix12() | matrix16().~n", []), w("-type mem() :: binary() | tuple(). %% Memory block~n", []), ok. @@ -480,10 +484,12 @@ doc_arg_type2(T=#type{single=true}) -> doc_arg_type3(T); doc_arg_type2(T=#type{single=undefined}) -> doc_arg_type3(T); -doc_arg_type2(T=#type{single={tuple,undefined}}) -> - "{" ++ doc_arg_type3(T) ++ "}"; +doc_arg_type2(_T=#type{single={tuple,undefined}}) -> + "tuple()"; doc_arg_type2(#type{base=float, single={tuple,16}}) -> "matrix()"; +doc_arg_type2(#type{base=string, single=list}) -> + "iolist()"; doc_arg_type2(T=#type{single={tuple,Sz}}) -> "{" ++ args(fun doc_arg_type3/1, ",", lists:duplicate(Sz,T)) ++ "}"; doc_arg_type2(T=#type{single=list}) -> diff --git a/lib/wx/api_gen/wx_extra/added_func.h b/lib/wx/api_gen/wx_extra/added_func.h new file mode 100644 index 0000000000..417188cc8a --- /dev/null +++ b/lib/wx/api_gen/wx_extra/added_func.h @@ -0,0 +1,41 @@ +// Added 3.0 functionality + +class WXDLLIMPEXP_AUI wxAuiTabArt +{ +public: + virtual void SetColour(const wxColour& colour) = 0; + virtual void SetActiveColour(const wxColour& colour) = 0; +}; + +// Api to get data out of paneinfo +class WXDLLIMPEXP_AUI wxAuiPaneInfo +{ + public: + wxString GetName(); + wxString GetCaption(); + wxIcon GetIcon(); + + wxWindow* GetWindow(); + wxFrame* GetFrame(); + + int GetDirection(); + int GetLayer(); + int GetRow(); + int GetPosition(); + + wxPoint GetFloatingPosition(); + wxSize GetFloatingSize(); +}; + +class wxToolBar { + public: + wxToolBarToolBase * AddStretchableSpace(); + wxToolBarToolBase * InsertStretchableSpace(size_t pos); +}; + + +class wxWindow { + public: + bool IsDoubleBuffered(); + void SetDoubleBuffered(bool on); +}; diff --git a/lib/wx/api_gen/wx_extra/wxEvtHandler.c_src b/lib/wx/api_gen/wx_extra/wxEvtHandler.c_src index 5d20019d8f..08fef1c2ff 100644 --- a/lib/wx/api_gen/wx_extra/wxEvtHandler.c_src +++ b/lib/wx/api_gen/wx_extra/wxEvtHandler.c_src @@ -11,7 +11,7 @@ case 100: { // wxEvtHandler::Connect int * class_nameLen = (int *) bp; bp += 4; if(*haveUserData) { - userData = new wxeErlTerm(Ecmd.bin[0]); + userData = new wxeErlTerm(&Ecmd.bin[0]); } int eventType = wxeEventTypeFromAtom(bp); bp += *eventTypeLen; @@ -42,11 +42,15 @@ case 101: { // wxEvtHandler::Disconnect int eventType = wxeEventTypeFromAtom(bp); bp += *eventTypeLen; if(eventType > 0) { + if(recurse_level > 1) { + delayed_delete->Append(Ecmd.Save()); + } else { bool Result = This->Disconnect((int) *winid,(int) *lastId,eventType, (wxObjectEventFunction)(wxEventFunction) &wxeEvtListener::forward, NULL, Listener); rt.addBool(Result); + } } else { rt.addAtom("badarg"); rt.addAtom("event_type"); diff --git a/lib/wx/api_gen/wx_extra/wxEvtHandler.erl b/lib/wx/api_gen/wx_extra/wxEvtHandler.erl index c9726fd475..85ebc093f5 100644 --- a/lib/wx/api_gen/wx_extra/wxEvtHandler.erl +++ b/lib/wx/api_gen/wx_extra/wxEvtHandler.erl @@ -70,6 +70,8 @@ connect(This=#wx_ref{type=ThisT}, EventType, Options) -> parse_opts([{callback,Fun}|R], Opts) when is_function(Fun) -> %% Check Fun Arity? parse_opts(R, Opts#evh{cb=Fun}); +parse_opts([{callback,CB={nospawn, Fun}}|R], Opts) when is_function(Fun) -> + parse_opts(R, Opts#evh{cb=CB}); parse_opts([callback|R], Opts) -> parse_opts(R, Opts#evh{cb=self()}); parse_opts([{userData, UserData}|R],Opts) -> diff --git a/lib/wx/api_gen/wx_gen.erl b/lib/wx/api_gen/wx_gen.erl index 212574ede3..ec2c35cc0e 100644 --- a/lib/wx/api_gen/wx_gen.erl +++ b/lib/wx/api_gen/wx_gen.erl @@ -705,6 +705,8 @@ parse_type2(["unsigned"|R],Info,Opts,T=#type{mod=Mod}) -> parse_type2(R,Info,Opts,T#type{mod=[unsigned|Mod]}); parse_type2(["int"|R],Info,Opts, T) -> parse_type2(R,Info,Opts,T#type{name=int,base=int}); +parse_type2(["wxByte"|R],Info,Opts, T) -> + parse_type2(R,Info,Opts,T#type{name=int,base=int}); parse_type2(["char"|R],Info,Opts, T) -> parse_type2(R,Info,Opts,T#type{name="char",base=int}); parse_type2([N="size_t"|R], Info, Opts, T) -> @@ -771,14 +773,19 @@ parse_type2([N="wxGridCellCoordsArray"|R],Info,Opts,T) -> parse_type2(R,Info,Opts,T#type{name=N,base={comp,"wxGridCellCoords", [{int,"R"},{int,"C"}]}, single=array}); +parse_type2([N="wxAuiPaneInfoArray"|R],Info,Opts,T) -> + parse_type2(R,Info,Opts,T#type{name=N,base={class,"wxAuiPaneInfo"}, + single=array}); + parse_type2([N="wxRect"|R],Info,Opts,T) -> parse_type2(R,Info,Opts,T#type{name=N,base={comp,N,[{int,"X"},{int,"Y"}, {int,"W"},{int,"H"}]}}); parse_type2([N="wxColour"|R],Info,Opts,T) -> parse_type2(R,Info,Opts,T#type{name=N, base={comp,N,[{int,"R"},{int,"G"},{int,"B"},{int,"A"}]}}); -parse_type2([N="wxColor"|R],Info,Opts,T) -> - parse_type2(R,Info,Opts,T#type{name="wxColour", +parse_type2(["wxColor"|R],Info,Opts,T) -> + N = "wxColour", + parse_type2(R,Info,Opts,T#type{name=N, base={comp,N,[{int,"R"},{int,"G"},{int,"B"},{int,"A"}]}}); parse_type2([N="wxPoint2DDouble"|R],Info,Opts,T) -> @@ -1196,7 +1203,7 @@ translate_constants(Enums, NotConsts0, Skip0) -> create_consts([{{enum, Name},Enum = #enum{vals=Vals}}|R], Skip, NotConsts, Acc0) -> CC = fun(What, Acc) -> - create_const(What, Skip, NotConsts, Acc) + create_const(What, Name, Skip, NotConsts, Acc) end, Acc = case Vals of undefined -> @@ -1210,17 +1217,17 @@ create_consts([{{enum, Name},Enum = #enum{vals=Vals}}|R], Skip, NotConsts, Acc0) create_consts(R, Skip, NotConsts, Acc); create_consts([],_,_,Acc) -> Acc. -create_const({Name, Val}, Skip, NotConsts, Acc) -> +create_const({Name, Val}, EnumName, Skip, NotConsts, Acc) -> case gb_sets:is_member(Name, Skip) of true -> Acc; false -> - case gb_sets:is_member(Name, NotConsts) of + case gb_sets:is_member(Name, NotConsts) orelse + gb_sets:is_member(EnumName, NotConsts) + of true -> [#const{name=Name,val=next_id(const),is_const=false}|Acc]; false -> [#const{name=Name,val=Val,is_const=true}|Acc] -%% false -> -%% [#const{name=Name,val=Val}|Acc] end end. @@ -1368,7 +1375,7 @@ extract_enum3([#xmlElement{name=initializer,content=Cs}|_],_Id,[{Name,_}|Acc]) - try case Val0 of ["0x" ++ Val1] -> - Val = http_util:hexlist_to_integer(Val1), + Val = list_to_integer(Val1, 16), {[{Name, Val}|Acc], Val+1}; ["1", "<<", Shift] -> Val = 1 bsl list_to_integer(Shift), @@ -1424,7 +1431,7 @@ extract_def([#xmlElement{name=param}|_],Name,_) -> extract_def([#xmlElement{name=initializer,content=Cs}|_R],N,Skip) -> Val0 = extract_def2(Cs), case Val0 of - "0x" ++ Val1 -> {N, http_util:hexlist_to_integer(Val1)}; + "0x" ++ Val1 -> {N, list_to_integer(Val1, 16)}; _ -> try Val = list_to_integer(Val0), @@ -1446,7 +1453,7 @@ extract_def(_,N,_) -> throw(N). extract_def2([#xmlText{value=Val}|R]) -> - strip_comment(string:strip(Val)) ++ extract_def2(R); + string:strip(strip_comment(Val)) ++ extract_def2(R); extract_def2([#xmlElement{content=Cs}|R]) -> extract_def2(Cs) ++ extract_def2(R); extract_def2([]) -> []. diff --git a/lib/wx/api_gen/wx_gen_cpp.erl b/lib/wx/api_gen/wx_gen_cpp.erl index 3120d491b1..71b2038c56 100644 --- a/lib/wx/api_gen/wx_gen_cpp.erl +++ b/lib/wx/api_gen/wx_gen_cpp.erl @@ -116,8 +116,13 @@ taylormade_class(#class{name=CName, methods=Ms}) -> gen_constructors(#class{name=Class, methods=Ms0}) -> Ms = lists:append(Ms0), Cs = lists:filter(fun(#method{method_type=MT}) -> MT =:= constructor end, Ms), - [gen_constructor(Class, Const) || Const <- Cs]. - + [gen_constructor(Class, Const) || Const <- Cs], + case need_copy_constr(Class) of + true -> + w(" E~s(~s copy) : ~s(copy) {};~n", [Class, Class, Class]); + false -> + ignore + end. gen_constructor(_Class, #method{where=merged_c}) -> ok; gen_constructor(_Class, #method{where=erl_no_opt}) -> ok; gen_constructor(Class, _M=#method{params=Ps, opts=FOpts}) -> @@ -145,6 +150,14 @@ gen_constructor(Class, _M=#method{params=Ps, opts=FOpts}) -> Endif andalso w("#endif~n", []), ok. + +need_copy_constr("wxFont") -> true; +need_copy_constr("wxIcon") -> true; +need_copy_constr("wxImage") -> true; +need_copy_constr("wxBitmap") -> true; +%%need_copy_constr("wxGraphics" ++ _) -> true; +need_copy_constr(_) -> false. + gen_type(#type{name=Type, ref={pointer,1}, mod=Mod},_) -> mods(Mod) ++ to_string(Type) ++ " * "; gen_type(#type{name=Type, ref={pointer,2}, mod=Mod},_) -> @@ -206,8 +219,8 @@ gen_funcs(Defs) -> " rt.addAtom(\"ok\");~n" " break;~n" " }~n"), - w(" case WXE_BIN_INCR:~n driver_binary_inc_refc(Ecmd.bin[0]->bin);~n break;~n",[]), - w(" case WXE_BIN_DECR:~n driver_binary_dec_refc(Ecmd.bin[0]->bin);~n break;~n",[]), + w(" case WXE_BIN_INCR:~n driver_binary_inc_refc(Ecmd.bin[0].bin);~n break;~n",[]), + w(" case WXE_BIN_DECR:~n driver_binary_dec_refc(Ecmd.bin[0].bin);~n break;~n",[]), w(" case WXE_INIT_OPENGL:~n wxe_initOpenGL(&rt, bp);~n break;~n",[]), Res = [gen_class(Class) || Class <- Defs], @@ -235,7 +248,8 @@ gen_funcs(Defs) -> w("}} /* The End */~n~n~n"), UglySkipList = ["wxCaret", "wxCalendarDateAttr", - "wxFileDataObject", "wxTextDataObject", "wxBitmapDataObject" + "wxFileDataObject", "wxTextDataObject", "wxBitmapDataObject", + "wxAuiSimpleTabArt" ], w("bool WxeApp::delete_object(void *ptr, wxeRefData *refd) {~n", []), @@ -323,12 +337,8 @@ gen_method(CName, M=#method{name=N,params=Ps0,type=T,method_type=MT,id=MethodId put(current_func, N), put(bin_count,-1), ?WTC("gen_method"), - Endif = case lists:keysearch(deprecated, 1, FOpts) of - {value, {deprecated, IfDef}} -> - w("#if ~s~n", [IfDef]), - true; - _ -> false - end, + Endif1 = gen_if(deprecated, FOpts), + Endif2 = gen_if(test_if, FOpts), w("case ~s: { // ~s::~s~n", [wx_gen_erl:get_unique_name(MethodId),CName,N]), Ps1 = declare_variables(void, Ps0), {Ps2,Align} = decode_arguments(Ps1), @@ -347,10 +357,19 @@ gen_method(CName, M=#method{name=N,params=Ps0,type=T,method_type=MT,id=MethodId free_args(), build_return_vals(T,Ps3), w(" break;~n}~n", []), - Endif andalso w("#endif~n", []), + Endif1 andalso w("#endif~n", []), + Endif2 andalso w("#endif~n", []), erase(current_func), M. +gen_if(What, Opts) -> + case lists:keysearch(What, 1, Opts) of + {value, {What, IfDef}} -> + w("#if ~s~n", [IfDef]), + true; + _ -> false + end. + declare_variables(void,Ps) -> [declare_var(P) || P <- Ps]; declare_variables(T, Ps) -> @@ -631,10 +650,10 @@ decode_arg(N,#type{name=Type,base=binary,mod=Mod0},Arg,A0) -> Mod = mods([M || M <- Mod0]), case Arg of arg -> - w(" ~s~s * ~s = (~s~s*) Ecmd.bin[~p]->base;~n", + w(" ~s~s * ~s = (~s~s*) Ecmd.bin[~p].base;~n", [Mod,Type,N,Mod,Type, next_id(bin_count)]); opt -> - w(" ~s = (~s~s*) Ecmd.bin[~p]->base;~n", + w(" ~s = (~s~s*) Ecmd.bin[~p].base;~n", [N,Mod,Type,next_id(bin_count)]) end, A0; @@ -644,10 +663,10 @@ decode_arg(N,#type{base={term,"wxTreeItemData"},mod=Mod0},Arg,A0) -> BinCnt = next_id(bin_count), case Arg of arg -> - w(" ~s~s * ~s = new ~s(Ecmd.bin[~p]->size, Ecmd.bin[~p]->base);~n", + w(" ~s~s * ~s = new ~s(Ecmd.bin[~p].size, Ecmd.bin[~p].base);~n", [Mod,Type,N,Type,BinCnt,BinCnt]); opt -> - w(" ~s = new ~s(Ecmd.bin[~p]->size, Ecmd.bin[~p]->base);~n", + w(" ~s = new ~s(Ecmd.bin[~p].size, Ecmd.bin[~p].base);~n", [N,Type,BinCnt,BinCnt]) end, A0; @@ -656,10 +675,10 @@ decode_arg(N,#type{name=Type,base={term,_},mod=Mod0},Arg,A0) -> BinCnt = next_id(bin_count), case Arg of arg -> - w(" ~s~s * ~s = new ~s(Ecmd.bin[~p]);~n", + w(" ~s~s * ~s = new ~s(&Ecmd.bin[~p]);~n", [Mod,Type,N,Type,BinCnt]); opt -> - w(" ~s = new ~s(Ecmd.bin[~p]);~n", + w(" ~s = new ~s(&Ecmd.bin[~p]);~n", [N,Type,BinCnt]) end, A0; @@ -799,18 +818,21 @@ return_res1(#type{name=Type,base={comp,_,_},single=array,by_val=true}) -> {Type ++ " Result = ", ""}; return_res1(#type{name=Type,single=true,by_val=true, base={class, _}}) -> %% Temporary memory leak !!!!!! - case Type of - "wxImage" -> ok; - "wxFont" -> ok; - "wxBitmap" -> ok; - "wxIcon" -> ok; - "wxGraphics" ++ _ -> ok; + case {need_copy_constr(Type),Type} of + {true, _} -> ok; + {_, "wxGraphics" ++ _} -> ok; _ -> io:format("~s::~s Building return value of temp ~s~n", [get(current_class),get(current_func),Type]) end, - {Type ++ " * Result = new " ++ Type ++ "(", "); newPtr((void *) Result," - ++ "3, memenv);"}; + case need_copy_constr(Type) of + true -> + {Type ++ " * Result = new E" ++ Type ++ "(", "); newPtr((void *) Result," + ++ "3, memenv);"}; + false -> + {Type ++ " * Result = new " ++ Type ++ "(", "); newPtr((void *) Result," + ++ "3, memenv);"} + end; return_res1(#type{base={enum,_Type},single=true,by_val=true}) -> {"int Result = " , ""}; return_res1(#type{name="wxCharBuffer", base={binary,_},single=true,by_val=true}) -> @@ -832,7 +854,7 @@ call_arg(#param{where=c, alt={length,Alt}}) when is_list(Alt) -> "*" ++ Alt ++ "Len"; call_arg(#param{where=c, alt={size,Id}}) when is_integer(Id) -> %% It's a binary - "Ecmd.bin["++ integer_to_list(Id) ++ "]->size"; + "Ecmd.bin["++ integer_to_list(Id) ++ "].size"; call_arg(#param{name=N,def=Def,type=#type{by_val=true,single=true,base=Base}}) when Base =:= int; Base =:= long; Base =:= float; Base =:= double; Base =:= bool -> case Def of @@ -1014,6 +1036,10 @@ build_ret(Name,_,#type{base={comp,_,_},single=array}) -> w(" for(unsigned int i=0; i < ~s.GetCount(); i++) {~n", [Name]), w(" rt.add(~s[i]);~n }~n",[Name]), w(" rt.endList(~s.GetCount());~n",[Name]); +build_ret(Name,_,#type{base={class,Class},single=array}) -> + w(" for(unsigned int i=0; i < ~s.GetCount(); i++) {~n", [Name]), + w(" rt.addRef(getRef((void *) &~s.Item(i), memenv), \"~s\");~n }~n",[Name, Class]), + w(" rt.endList(~s.GetCount());~n",[Name]); build_ret(Name,_,#type{name=List,single=list,base={class,Class}}) -> w(" int i=0;~n"), w(" for(~s::const_iterator it = ~s.begin(); it != ~s.end(); ++it) {~n", @@ -1131,6 +1157,7 @@ gen_macros() -> w("#include <wx/html/htmlcell.h>~n"), w("#include <wx/filename.h>~n"), w("#include <wx/sysopt.h>~n"), + w("#include <wx/overlay.h>~n"), w("~n~n", []), w("#ifndef wxICON_DEFAULT_BITMAP_TYPE~n",[]), @@ -1266,6 +1293,11 @@ encode_events(Evs) -> w(" } else {~n"), w(" send_res = rt.send();~n"), w(" if(cb->skip) event->Skip();~n"), + w(" if(app->recurse_level < 1) {~n"), + w(" app->recurse_level++;~n"), + w(" app->dispatch_cmds();~n"), + w(" app->recurse_level--;~n"), + w(" }~n"), w(" };~n"), w(" return send_res;~n"), w(" }~n"). diff --git a/lib/wx/api_gen/wx_gen_erl.erl b/lib/wx/api_gen/wx_gen_erl.erl index 9df5cb853e..c28b9238dc 100644 --- a/lib/wx/api_gen/wx_gen_erl.erl +++ b/lib/wx/api_gen/wx_gen_erl.erl @@ -1169,7 +1169,7 @@ build_enum_ints(#enum{from=From, vals=Vals},Done) -> const_value(V,_,_) when is_integer(V) -> integer_to_list(V); const_value(V = "16#" ++ IntList,_,_) -> - _ = http_util:hexlist_to_integer(IntList), %% ASSERT + _ = list_to_integer(IntList, 16), %% ASSERT V; const_value(V0, EnumClass, Ignore) -> try diff --git a/lib/wx/api_gen/wxapi.conf b/lib/wx/api_gen/wxapi.conf index 09877f0f5a..b8458e901b 100644 --- a/lib/wx/api_gen/wxapi.conf +++ b/lib/wx/api_gen/wxapi.conf @@ -36,7 +36,8 @@ wxSL_LABELS, wxCURSOR_DEFAULT, wxCURSOR_ARROWWAIT, - wxCURSOR_MAX + wxCURSOR_MAX, + wxLanguage ]}. {gvars, @@ -149,7 +150,12 @@ 'ShouldInheritColours','Show','Thaw','TransferDataFromWindow', 'TransferDataToWindow',%'UnregisterHotKey', 'Update','UpdateWindowUI','Validate', - 'WarpPointer']}. + 'WarpPointer', + {'SetTransparent', [{test_if, "wxCHECK_VERSION(2,8,12)"}]}, + {'CanSetTransparent', [{test_if, "wxCHECK_VERSION(2,8,12)"}]}, + {'IsDoubleBuffered', [{test_if, "wxCHECK_VERSION(3,0,0)"}]}, + {'SetDoubleBuffered', [{test_if, "wxCHECK_VERSION(3,0,0) && !defined(__WXMAC__)"}]} +]}. {class, wxTopLevelWindowGTK, wxWindow, [{alias, [{wxTopLevelWindowGTK, wxTopLevelWindow}]}], @@ -366,7 +372,7 @@ {class,wxMirrorDC, wxDC, [], ['wxMirrorDC', '~wxMirrorDC']}. {class,wxScreenDC, wxDC, [], ['wxScreenDC', '~wxScreenDC']}. -{class,wxPostScriptDC,wxDC,[], +{class,wxPostScriptDC,wxDC,[{ifdef, wxUSE_POSTSCRIPT}], ['wxPostScriptDC','~wxPostScriptDC', {'SetResolution', [{deprecated, "!wxCHECK_VERSION(2,9,0)"}]}, {'GetResolution', [{deprecated, "!wxCHECK_VERSION(2,9,0)"}]}]}. @@ -492,6 +498,8 @@ {class, wxToolBar, wxControl, [], ['AddControl','AddSeparator','AddTool','AddCheckTool','AddRadioTool', + {'AddStretchableSpace', [{test_if, "wxCHECK_VERSION(3,0,0)"}]}, + {'InsertStretchableSpace', [{test_if, "wxCHECK_VERSION(3,0,0)"}]}, 'DeleteTool','DeleteToolByPos','EnableTool','FindById','FindControl', 'FindToolForPosition','GetToolSize','GetToolBitmapSize','GetMargins', %%'GetToolClientData' , %%'SetToolClientData', @@ -556,14 +564,14 @@ {"alpha",[in,{base,binary}]}, {{4,pre_hook}, [{c, "if(!static_data) {" - "data = (unsigned char *) malloc(Ecmd.bin[0]->size);" - "memcpy(data,Ecmd.bin[0]->base,Ecmd.bin[0]->size);}"}]}, + "data = (unsigned char *) malloc(Ecmd.bin[0].size);" + "memcpy(data,Ecmd.bin[0].base,Ecmd.bin[0].size);}"}]}, {{5,pre_hook}, [{c, "if(!static_data) {" - " data = (unsigned char *) malloc(Ecmd.bin[0]->size);" - " alpha = (unsigned char *) malloc(Ecmd.bin[1]->size);" - " memcpy(data,Ecmd.bin[0]->base,Ecmd.bin[0]->size);" - " memcpy(alpha,Ecmd.bin[1]->base,Ecmd.bin[1]->size);}"}]} + " data = (unsigned char *) malloc(Ecmd.bin[0].size);" + " alpha = (unsigned char *) malloc(Ecmd.bin[1].size);" + " memcpy(data,Ecmd.bin[0].base,Ecmd.bin[0].size);" + " memcpy(alpha,Ecmd.bin[1].base,Ecmd.bin[1].size);}"}]} ]}, '~wxImage',%'AddHandler', 'Blur','BlurHorizontal','BlurVertical', @@ -575,14 +583,14 @@ {"alpha",[in,{base,binary}]}, {{4,pre_hook}, [{c, "if(!static_data) {" - "data = (unsigned char *) malloc(Ecmd.bin[0]->size);" - "memcpy(data,Ecmd.bin[0]->base,Ecmd.bin[0]->size);}"}]}, + "data = (unsigned char *) malloc(Ecmd.bin[0].size);" + "memcpy(data,Ecmd.bin[0].base,Ecmd.bin[0].size);}"}]}, {{5,pre_hook}, [{c, "if(!static_data) {" - " data = (unsigned char *) malloc(Ecmd.bin[0]->size);" - " alpha = (unsigned char *) malloc(Ecmd.bin[1]->size);" - " memcpy(data,Ecmd.bin[0]->base,Ecmd.bin[0]->size);" - " memcpy(alpha,Ecmd.bin[1]->base,Ecmd.bin[1]->size);}"}]} + " data = (unsigned char *) malloc(Ecmd.bin[0].size);" + " alpha = (unsigned char *) malloc(Ecmd.bin[1].size);" + " memcpy(data,Ecmd.bin[0].base,Ecmd.bin[0].size);" + " memcpy(alpha,Ecmd.bin[1].base,Ecmd.bin[1].size);}"}]} ]}, 'Destroy','FindFirstUnusedColour', % 'FindHandler', 'GetImageExtWildcard', @@ -608,14 +616,14 @@ {'SetAlpha', [{{2,"alpha"},[in,{base,binary}, {def, none}]}, {{2,pre_hook}, [{c, "if(!static_data) {" - "alpha = (unsigned char *) malloc(Ecmd.bin[0]->size);" - "memcpy(alpha,Ecmd.bin[0]->base,Ecmd.bin[0]->size);}"}]} + "alpha = (unsigned char *) malloc(Ecmd.bin[0].size);" + "memcpy(alpha,Ecmd.bin[0].base,Ecmd.bin[0].size);}"}]} ]}, {'SetData', [{"data",[in,{base,binary}]}, {pre_hook, [{c, "if(!static_data) {" - "data = (unsigned char *) malloc(Ecmd.bin[0]->size);" - "memcpy(data,Ecmd.bin[0]->base,Ecmd.bin[0]->size);}"}]} + "data = (unsigned char *) malloc(Ecmd.bin[0].size);" + "memcpy(data,Ecmd.bin[0].base,Ecmd.bin[0].size);}"}]} ]}, 'SetMask','SetMaskColour','SetMaskFromImage','SetOption', 'SetPalette', @@ -1245,7 +1253,8 @@ 'SetArtProvider','SetDockSizeConstraint','SetFlags','SetManagedWindow', 'ShowHint','UnInit','Update']}. -{class, wxAuiPaneInfo, root, [{ifdef, wxUSE_AUI}], +{class, wxAuiPaneInfo, root, + [{ifdef, wxUSE_AUI}], [ wxAuiPaneInfo,'~wxAuiPaneInfo', 'BestSize','Bottom','BottomDockable','Caption','CaptionVisible', @@ -1262,7 +1271,44 @@ 'MinSize','MinimizeButton','Movable','Name', 'PaneBorder','PinButton','Position','Resizable','Right', 'RightDockable','Row','SafeSet','SetFlag','Show','ToolbarPane', - 'Top','TopDockable','Window']}. + 'Top','TopDockable','Window', + %% Extended func + %% These are not initilized by default and thus cause crashes + %% {'GetName', + %% [{pre_hook, [{c, "#if 0\n"}]}, + %% {post_hook, [{c, "#endif\n if(!This) throw wxe_badarg(0);\n wxString Result = This->name"}]}]}, + %% {'GetCaption', + %% [{pre_hook, [{c, "#if 0\n"}]}, + %% {post_hook, [{c, "#endif\n if(!This) throw wxe_badarg(0);\n wxString Result = This->caption"}]}]}, + %% {'GetIcon', + %% [{pre_hook, [{c, "#if 0\n"}]}, + %% {post_hook, [{c, "#endif\n if(!This) throw wxe_badarg(0);\n wxIcon Result = This->icon"}]}]}, + {'GetWindow', + [{pre_hook, [{c, "#if 0\n"}]}, + {post_hook, [{c, "#endif\n if(!This) throw wxe_badarg(0);\n wxWindow* Result = This->window"}]}]}, + {'GetFrame', + [{pre_hook, [{c, "#if 0\n"}]}, + {post_hook, [{c, "#endif\n if(!This) throw wxe_badarg(0);\n wxFrame* Result = This->frame"}]}]}, + {'GetDirection', + [{pre_hook, [{c, "#if 0\n"}]}, + {post_hook, [{c, "#endif\n if(!This) throw wxe_badarg(0);\n int Result = This->dock_direction"}]}]}, + {'GetLayer', + [{pre_hook, [{c, "#if 0\n"}]}, + {post_hook, [{c, "#endif\n if(!This) throw wxe_badarg(0);\n int Result = This->dock_layer"}]}]}, + {'GetRow', + [{pre_hook, [{c, "#if 0\n"}]}, + {post_hook, [{c, "#endif\n if(!This) throw wxe_badarg(0);\n int Result = This->dock_row"}]}]}, + {'GetPosition', + [{pre_hook, [{c, "#if 0\n"}]}, + {post_hook, [{c, "#endif\n if(!This) throw wxe_badarg(0);\n int Result = This->dock_pos"}]}]}, + {'GetFloatingPosition', + [{pre_hook, [{c, "#if 0\n"}]}, + {post_hook, [{c, "#endif\n if(!This) throw wxe_badarg(0);\n wxPoint Result = This->floating_pos"}]}]}, + {'GetFloatingSize', + [{pre_hook, [{c, "#if 0\n"}]}, + {post_hook, [{c, "#endif\n if(!This) throw wxe_badarg(0);\n wxSize Result = This->floating_size"}]}]} + +]}. {class, wxAuiNotebook, wxControl, [{ifdef, wxUSE_AUI}], ['wxAuiNotebook','AddPage',%'AdvanceSelection', @@ -1281,15 +1327,22 @@ %'Clone','DrawBackground','DrawButton','DrawTab','GetBestTabCtrlSize', %'GetIndentSize','GetTabSize','SetFlags','SetMeasuringFont', %'SetNormalFont','SetSelectedFont','SetSizingInfo'%,'ShowWindowList' + 'SetFlags', 'SetMeasuringFont', 'SetNormalFont', 'SetSelectedFont', + {'SetColour', [{test_if, "wxCHECK_VERSION(3,0,0)"}]}, + {'SetActiveColour', [{test_if, "wxCHECK_VERSION(3,0,0)"}]} ]}. {class,wxAuiDockArt, root, [{ifdef, wxUSE_AUI}], [%% 'wxAuiDockArt','~wxAuiDockArt' %, %%'DrawBackground','DrawBorder','DrawCaption', %% Pure virtual funcs %%'DrawGripper','DrawPaneButton','DrawSash', - %%'GetColor','GetColour','GetFont','GetMetric','SetColor','SetColour','SetFont','SetMetric' + 'GetColour','GetFont','GetMetric','SetColour','SetFont','SetMetric' ]}. +{class,wxAuiSimpleTabArt, wxAuiTabArt, [{ifdef, wxUSE_AUI}], + [wxAuiSimpleTabArt]}. + + {class, wxMDIParentFrame, wxFrame, [], [ 'wxMDIParentFrame', @@ -1869,7 +1922,7 @@ ]}. -{class, wxAuiManagerEvent, wxEvent, +{class, wxAuiManagerEvent, wxEvent, [{acc, [{button, "GetButton()"}, {dc, "GetDC()"}, {pane, "GetPane()"}, @@ -1879,6 +1932,7 @@ wxEVT_AUI_PANE_CLOSE, wxEVT_AUI_PANE_MAXIMIZE, wxEVT_AUI_PANE_RESTORE, + {wxEVT_AUI_PANE_ACTIVATED, {test_if, "wxCHECK_VERSION(2,9,5)"}}, wxEVT_AUI_RENDER, wxEVT_AUI_FIND_MANAGER ]}], @@ -1925,3 +1979,12 @@ {class, wxPopupTransientWindow, wxPopupWindow, [{ifdef, wxUSE_POPUPWIN}], ['wxPopupTransientWindow', '~wxPopupTransientWindow', 'Popup', 'Dismiss']}. + +{class, wxMouseCaptureLostEvent, wxEvent, + [{event,[wxEVT_MOUSE_CAPTURE_LOST]}],[]}. + +{class, wxOverlay, root, [], + ['wxOverlay', '~wxOverlay', 'Reset']}. + +{class, wxDCOverlay, root, [], + ['wxDCOverlay', '~wxDCOverlay', 'Clear']}. diff --git a/lib/wx/c_src/gen/wxe_derived_dest.h b/lib/wx/c_src/gen/wxe_derived_dest.h index 03d1502c2a..fc0ae0d9fc 100644 --- a/lib/wx/c_src/gen/wxe_derived_dest.h +++ b/lib/wx/c_src/gen/wxe_derived_dest.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2008-2014. All Rights Reserved. + * Copyright Ericsson AB 2008-2016. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -86,11 +86,13 @@ class EwxScreenDC : public wxScreenDC { EwxScreenDC() : wxScreenDC() {}; }; +#if wxUSE_POSTSCRIPT class EwxPostScriptDC : public wxPostScriptDC { public: ~EwxPostScriptDC() {((WxeApp *)wxTheApp)->clearPtr(this);}; EwxPostScriptDC(const wxPrintData& printData) : wxPostScriptDC(printData) {}; EwxPostScriptDC() : wxPostScriptDC() {}; }; +#endif // wxUSE_POSTSCRIPT class EwxWindowDC : public wxWindowDC { public: ~EwxWindowDC() {((WxeApp *)wxTheApp)->clearPtr(this);}; @@ -178,6 +180,7 @@ class EwxBitmap : public wxBitmap { EwxBitmap(const wxString& filename,wxBitmapType type) : wxBitmap(filename,type) {}; EwxBitmap(const wxImage& image,int depth) : wxBitmap(image,depth) {}; EwxBitmap() : wxBitmap() {}; + EwxBitmap(wxBitmap copy) : wxBitmap(copy) {}; }; class EwxIcon : public wxIcon { @@ -185,6 +188,7 @@ class EwxIcon : public wxIcon { EwxIcon(const wxString& filename,wxBitmapType type,int desiredWidth,int desiredHeight) : wxIcon(filename,type,desiredWidth,desiredHeight) {}; EwxIcon(const wxIconLocation& loc) : wxIcon(loc) {}; EwxIcon() : wxIcon() {}; + EwxIcon(wxIcon copy) : wxIcon(copy) {}; }; class EwxCursor : public wxCursor { @@ -213,6 +217,7 @@ class EwxImage : public wxImage { EwxImage(const wxString& name,const wxString& mimetype,int index) : wxImage(name,mimetype,index) {}; EwxImage(const wxString& name,long type,int index) : wxImage(name,type,index) {}; EwxImage() : wxImage() {}; + EwxImage(wxImage copy) : wxImage(copy) {}; }; class EwxBrush : public wxBrush { @@ -298,6 +303,7 @@ class EwxFont : public wxFont { EwxFont(int size,wxFontFamily family,wxFontStyle style,int weight,bool underlined,const wxString& face,wxFontEncoding encoding) : wxFont(size,family,style,weight,underlined,face,encoding) {}; EwxFont(const wxString& fontname) : wxFont(fontname) {}; EwxFont() : wxFont() {}; + EwxFont(wxFont copy) : wxFont(copy) {}; }; class EwxToolTip : public wxToolTip { @@ -787,3 +793,9 @@ class EwxPopupTransientWindow : public wxPopupTransientWindow { }; #endif // wxUSE_POPUPWIN +class EwxDCOverlay : public wxDCOverlay { + public: ~EwxDCOverlay() {((WxeApp *)wxTheApp)->clearPtr(this);}; + EwxDCOverlay(wxOverlay& overlay,wxWindowDC * dc,int x,int y,int width,int height) : wxDCOverlay(overlay,dc,x,y,width,height) {}; + EwxDCOverlay(wxOverlay& overlay,wxWindowDC * dc) : wxDCOverlay(overlay,dc) {}; +}; + diff --git a/lib/wx/c_src/gen/wxe_events.cpp b/lib/wx/c_src/gen/wxe_events.cpp index 88a147cf90..4affe2ba53 100644 --- a/lib/wx/c_src/gen/wxe_events.cpp +++ b/lib/wx/c_src/gen/wxe_events.cpp @@ -54,254 +54,258 @@ void initEventTable() struct { int ev_type; int class_id; const char * ev_name;} event_types[] = { {wxEVT_NULL, 0, "null"}, - {wxEVT_COMMAND_BUTTON_CLICKED, 164, "command_button_clicked"}, - {wxEVT_COMMAND_CHECKBOX_CLICKED, 164, "command_checkbox_clicked"}, - {wxEVT_COMMAND_CHOICE_SELECTED, 164, "command_choice_selected"}, - {wxEVT_COMMAND_LISTBOX_SELECTED, 164, "command_listbox_selected"}, - {wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, 164, "command_listbox_doubleclicked"}, - {wxEVT_COMMAND_TEXT_UPDATED, 164, "command_text_updated"}, - {wxEVT_COMMAND_TEXT_ENTER, 164, "command_text_enter"}, - {wxEVT_COMMAND_MENU_SELECTED, 164, "command_menu_selected"}, - {wxEVT_COMMAND_SLIDER_UPDATED, 164, "command_slider_updated"}, - {wxEVT_COMMAND_RADIOBOX_SELECTED, 164, "command_radiobox_selected"}, - {wxEVT_COMMAND_RADIOBUTTON_SELECTED, 164, "command_radiobutton_selected"}, - {wxEVT_COMMAND_SCROLLBAR_UPDATED, 164, "command_scrollbar_updated"}, - {wxEVT_COMMAND_VLBOX_SELECTED, 164, "command_vlbox_selected"}, - {wxEVT_COMMAND_COMBOBOX_SELECTED, 164, "command_combobox_selected"}, - {wxEVT_COMMAND_TOOL_RCLICKED, 164, "command_tool_rclicked"}, - {wxEVT_COMMAND_TOOL_ENTER, 164, "command_tool_enter"}, - {wxEVT_COMMAND_CHECKLISTBOX_TOGGLED, 164, "command_checklistbox_toggled"}, - {wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, 164, "command_togglebutton_clicked"}, - {wxEVT_COMMAND_LEFT_CLICK, 164, "command_left_click"}, - {wxEVT_COMMAND_LEFT_DCLICK, 164, "command_left_dclick"}, - {wxEVT_COMMAND_RIGHT_CLICK, 164, "command_right_click"}, - {wxEVT_COMMAND_SET_FOCUS, 164, "command_set_focus"}, - {wxEVT_COMMAND_KILL_FOCUS, 164, "command_kill_focus"}, - {wxEVT_COMMAND_ENTER, 164, "command_enter"}, - {wxEVT_SCROLL_TOP, 165, "scroll_top"}, - {wxEVT_SCROLL_BOTTOM, 165, "scroll_bottom"}, - {wxEVT_SCROLL_LINEUP, 165, "scroll_lineup"}, - {wxEVT_SCROLL_LINEDOWN, 165, "scroll_linedown"}, - {wxEVT_SCROLL_PAGEUP, 165, "scroll_pageup"}, - {wxEVT_SCROLL_PAGEDOWN, 165, "scroll_pagedown"}, - {wxEVT_SCROLL_THUMBTRACK, 165, "scroll_thumbtrack"}, - {wxEVT_SCROLL_THUMBRELEASE, 165, "scroll_thumbrelease"}, - {wxEVT_SCROLL_CHANGED, 165, "scroll_changed"}, - {wxEVT_SCROLLWIN_TOP, 166, "scrollwin_top"}, - {wxEVT_SCROLLWIN_BOTTOM, 166, "scrollwin_bottom"}, - {wxEVT_SCROLLWIN_LINEUP, 166, "scrollwin_lineup"}, - {wxEVT_SCROLLWIN_LINEDOWN, 166, "scrollwin_linedown"}, - {wxEVT_SCROLLWIN_PAGEUP, 166, "scrollwin_pageup"}, - {wxEVT_SCROLLWIN_PAGEDOWN, 166, "scrollwin_pagedown"}, - {wxEVT_SCROLLWIN_THUMBTRACK, 166, "scrollwin_thumbtrack"}, - {wxEVT_SCROLLWIN_THUMBRELEASE, 166, "scrollwin_thumbrelease"}, - {wxEVT_LEFT_DOWN, 167, "left_down"}, - {wxEVT_LEFT_UP, 167, "left_up"}, - {wxEVT_MIDDLE_DOWN, 167, "middle_down"}, - {wxEVT_MIDDLE_UP, 167, "middle_up"}, - {wxEVT_RIGHT_DOWN, 167, "right_down"}, - {wxEVT_RIGHT_UP, 167, "right_up"}, - {wxEVT_MOTION, 167, "motion"}, - {wxEVT_ENTER_WINDOW, 167, "enter_window"}, - {wxEVT_LEAVE_WINDOW, 167, "leave_window"}, - {wxEVT_LEFT_DCLICK, 167, "left_dclick"}, - {wxEVT_MIDDLE_DCLICK, 167, "middle_dclick"}, - {wxEVT_RIGHT_DCLICK, 167, "right_dclick"}, - {wxEVT_MOUSEWHEEL, 167, "mousewheel"}, - {wxEVT_SET_CURSOR, 168, "set_cursor"}, - {wxEVT_CHAR, 169, "char"}, - {wxEVT_CHAR_HOOK, 169, "char_hook"}, - {wxEVT_KEY_DOWN, 169, "key_down"}, - {wxEVT_KEY_UP, 169, "key_up"}, - {wxEVT_SIZE, 170, "size"}, - {wxEVT_MOVE, 171, "move"}, - {wxEVT_PAINT, 172, "paint"}, - {wxEVT_ERASE_BACKGROUND, 173, "erase_background"}, - {wxEVT_SET_FOCUS, 174, "set_focus"}, - {wxEVT_KILL_FOCUS, 174, "kill_focus"}, - {wxEVT_CHILD_FOCUS, 175, "child_focus"}, - {wxEVT_MENU_OPEN, 176, "menu_open"}, - {wxEVT_MENU_CLOSE, 176, "menu_close"}, - {wxEVT_MENU_HIGHLIGHT, 176, "menu_highlight"}, - {wxEVT_CLOSE_WINDOW, 177, "close_window"}, - {wxEVT_END_SESSION, 177, "end_session"}, - {wxEVT_QUERY_END_SESSION, 177, "query_end_session"}, - {wxEVT_SHOW, 178, "show"}, - {wxEVT_ICONIZE, 179, "iconize"}, - {wxEVT_MAXIMIZE, 180, "maximize"}, - {wxEVT_JOY_BUTTON_DOWN, 181, "joy_button_down"}, - {wxEVT_JOY_BUTTON_UP, 181, "joy_button_up"}, - {wxEVT_JOY_MOVE, 181, "joy_move"}, - {wxEVT_JOY_ZMOVE, 181, "joy_zmove"}, - {wxEVT_UPDATE_UI, 182, "update_ui"}, - {wxEVT_SYS_COLOUR_CHANGED, 183, "sys_colour_changed"}, - {wxEVT_MOUSE_CAPTURE_CHANGED, 184, "mouse_capture_changed"}, - {wxEVT_DISPLAY_CHANGED, 185, "display_changed"}, - {wxEVT_PALETTE_CHANGED, 186, "palette_changed"}, - {wxEVT_QUERY_NEW_PALETTE, 187, "query_new_palette"}, - {wxEVT_NAVIGATION_KEY, 188, "navigation_key"}, - {wxEVT_CREATE, 189, "create"}, - {wxEVT_DESTROY, 190, "destroy"}, - {wxEVT_HELP, 191, "help"}, - {wxEVT_DETAILED_HELP, 191, "detailed_help"}, - {wxEVT_CONTEXT_MENU, 192, "context_menu"}, - {wxEVT_IDLE, 193, "idle"}, - {wxEVT_GRID_CELL_LEFT_CLICK, 194, "grid_cell_left_click"}, - {wxEVT_GRID_CELL_RIGHT_CLICK, 194, "grid_cell_right_click"}, - {wxEVT_GRID_CELL_LEFT_DCLICK, 194, "grid_cell_left_dclick"}, - {wxEVT_GRID_CELL_RIGHT_DCLICK, 194, "grid_cell_right_dclick"}, - {wxEVT_GRID_LABEL_LEFT_CLICK, 194, "grid_label_left_click"}, - {wxEVT_GRID_LABEL_RIGHT_CLICK, 194, "grid_label_right_click"}, - {wxEVT_GRID_LABEL_LEFT_DCLICK, 194, "grid_label_left_dclick"}, - {wxEVT_GRID_LABEL_RIGHT_DCLICK, 194, "grid_label_right_dclick"}, - {wxEVT_GRID_ROW_SIZE, 194, "grid_row_size"}, - {wxEVT_GRID_COL_SIZE, 194, "grid_col_size"}, - {wxEVT_GRID_RANGE_SELECT, 194, "grid_range_select"}, - {wxEVT_GRID_CELL_CHANGE, 194, "grid_cell_change"}, - {wxEVT_GRID_SELECT_CELL, 194, "grid_select_cell"}, - {wxEVT_GRID_EDITOR_SHOWN, 194, "grid_editor_shown"}, - {wxEVT_GRID_EDITOR_HIDDEN, 194, "grid_editor_hidden"}, - {wxEVT_GRID_EDITOR_CREATED, 194, "grid_editor_created"}, - {wxEVT_GRID_CELL_BEGIN_DRAG, 194, "grid_cell_begin_drag"}, - {wxEVT_SASH_DRAGGED, 196, "sash_dragged"}, - {wxEVT_COMMAND_LIST_BEGIN_DRAG, 197, "command_list_begin_drag"}, - {wxEVT_COMMAND_LIST_BEGIN_RDRAG, 197, "command_list_begin_rdrag"}, - {wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT, 197, "command_list_begin_label_edit"}, - {wxEVT_COMMAND_LIST_END_LABEL_EDIT, 197, "command_list_end_label_edit"}, - {wxEVT_COMMAND_LIST_DELETE_ITEM, 197, "command_list_delete_item"}, - {wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS, 197, "command_list_delete_all_items"}, - {wxEVT_COMMAND_LIST_KEY_DOWN, 197, "command_list_key_down"}, - {wxEVT_COMMAND_LIST_INSERT_ITEM, 197, "command_list_insert_item"}, - {wxEVT_COMMAND_LIST_COL_CLICK, 197, "command_list_col_click"}, - {wxEVT_COMMAND_LIST_COL_RIGHT_CLICK, 197, "command_list_col_right_click"}, - {wxEVT_COMMAND_LIST_COL_BEGIN_DRAG, 197, "command_list_col_begin_drag"}, - {wxEVT_COMMAND_LIST_COL_DRAGGING, 197, "command_list_col_dragging"}, - {wxEVT_COMMAND_LIST_COL_END_DRAG, 197, "command_list_col_end_drag"}, - {wxEVT_COMMAND_LIST_ITEM_SELECTED, 197, "command_list_item_selected"}, - {wxEVT_COMMAND_LIST_ITEM_DESELECTED, 197, "command_list_item_deselected"}, - {wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, 197, "command_list_item_right_click"}, - {wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK, 197, "command_list_item_middle_click"}, - {wxEVT_COMMAND_LIST_ITEM_ACTIVATED, 197, "command_list_item_activated"}, - {wxEVT_COMMAND_LIST_ITEM_FOCUSED, 197, "command_list_item_focused"}, - {wxEVT_COMMAND_LIST_CACHE_HINT, 197, "command_list_cache_hint"}, - {wxEVT_DATE_CHANGED, 198, "date_changed"}, - {wxEVT_CALENDAR_SEL_CHANGED, 199, "calendar_sel_changed"}, - {wxEVT_CALENDAR_DAY_CHANGED, 199, "calendar_day_changed"}, - {wxEVT_CALENDAR_MONTH_CHANGED, 199, "calendar_month_changed"}, - {wxEVT_CALENDAR_YEAR_CHANGED, 199, "calendar_year_changed"}, - {wxEVT_CALENDAR_DOUBLECLICKED, 199, "calendar_doubleclicked"}, - {wxEVT_CALENDAR_WEEKDAY_CLICKED, 199, "calendar_weekday_clicked"}, - {wxEVT_COMMAND_FILEPICKER_CHANGED, 200, "command_filepicker_changed"}, - {wxEVT_COMMAND_DIRPICKER_CHANGED, 200, "command_dirpicker_changed"}, - {wxEVT_COMMAND_COLOURPICKER_CHANGED, 201, "command_colourpicker_changed"}, - {wxEVT_COMMAND_FONTPICKER_CHANGED, 202, "command_fontpicker_changed"}, - {wxEVT_STC_CHANGE, 203, "stc_change"}, - {wxEVT_STC_STYLENEEDED, 203, "stc_styleneeded"}, - {wxEVT_STC_CHARADDED, 203, "stc_charadded"}, - {wxEVT_STC_SAVEPOINTREACHED, 203, "stc_savepointreached"}, - {wxEVT_STC_SAVEPOINTLEFT, 203, "stc_savepointleft"}, - {wxEVT_STC_ROMODIFYATTEMPT, 203, "stc_romodifyattempt"}, - {wxEVT_STC_KEY, 203, "stc_key"}, - {wxEVT_STC_DOUBLECLICK, 203, "stc_doubleclick"}, - {wxEVT_STC_UPDATEUI, 203, "stc_updateui"}, - {wxEVT_STC_MODIFIED, 203, "stc_modified"}, - {wxEVT_STC_MACRORECORD, 203, "stc_macrorecord"}, - {wxEVT_STC_MARGINCLICK, 203, "stc_marginclick"}, - {wxEVT_STC_NEEDSHOWN, 203, "stc_needshown"}, - {wxEVT_STC_PAINTED, 203, "stc_painted"}, - {wxEVT_STC_USERLISTSELECTION, 203, "stc_userlistselection"}, - {wxEVT_STC_URIDROPPED, 203, "stc_uridropped"}, - {wxEVT_STC_DWELLSTART, 203, "stc_dwellstart"}, - {wxEVT_STC_DWELLEND, 203, "stc_dwellend"}, - {wxEVT_STC_START_DRAG, 203, "stc_start_drag"}, - {wxEVT_STC_DRAG_OVER, 203, "stc_drag_over"}, - {wxEVT_STC_DO_DROP, 203, "stc_do_drop"}, - {wxEVT_STC_ZOOM, 203, "stc_zoom"}, - {wxEVT_STC_HOTSPOT_CLICK, 203, "stc_hotspot_click"}, - {wxEVT_STC_HOTSPOT_DCLICK, 203, "stc_hotspot_dclick"}, - {wxEVT_STC_CALLTIP_CLICK, 203, "stc_calltip_click"}, - {wxEVT_STC_AUTOCOMP_SELECTION, 203, "stc_autocomp_selection"}, - {wxEVT_COMMAND_TREE_BEGIN_DRAG, 209, "command_tree_begin_drag"}, - {wxEVT_COMMAND_TREE_BEGIN_RDRAG, 209, "command_tree_begin_rdrag"}, - {wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, 209, "command_tree_begin_label_edit"}, - {wxEVT_COMMAND_TREE_END_LABEL_EDIT, 209, "command_tree_end_label_edit"}, - {wxEVT_COMMAND_TREE_DELETE_ITEM, 209, "command_tree_delete_item"}, - {wxEVT_COMMAND_TREE_GET_INFO, 209, "command_tree_get_info"}, - {wxEVT_COMMAND_TREE_SET_INFO, 209, "command_tree_set_info"}, - {wxEVT_COMMAND_TREE_ITEM_EXPANDED, 209, "command_tree_item_expanded"}, - {wxEVT_COMMAND_TREE_ITEM_EXPANDING, 209, "command_tree_item_expanding"}, - {wxEVT_COMMAND_TREE_ITEM_COLLAPSED, 209, "command_tree_item_collapsed"}, - {wxEVT_COMMAND_TREE_ITEM_COLLAPSING, 209, "command_tree_item_collapsing"}, - {wxEVT_COMMAND_TREE_SEL_CHANGED, 209, "command_tree_sel_changed"}, - {wxEVT_COMMAND_TREE_SEL_CHANGING, 209, "command_tree_sel_changing"}, - {wxEVT_COMMAND_TREE_KEY_DOWN, 209, "command_tree_key_down"}, - {wxEVT_COMMAND_TREE_ITEM_ACTIVATED, 209, "command_tree_item_activated"}, - {wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, 209, "command_tree_item_right_click"}, - {wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK, 209, "command_tree_item_middle_click"}, - {wxEVT_COMMAND_TREE_END_DRAG, 209, "command_tree_end_drag"}, - {wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK, 209, "command_tree_state_image_click"}, - {wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP, 209, "command_tree_item_gettooltip"}, - {wxEVT_COMMAND_TREE_ITEM_MENU, 209, "command_tree_item_menu"}, - {wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, 210, "command_notebook_page_changed"}, - {wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING, 210, "command_notebook_page_changing"}, - {wxEVT_COMMAND_TEXT_COPY, 216, "command_text_copy"}, - {wxEVT_COMMAND_TEXT_CUT, 216, "command_text_cut"}, - {wxEVT_COMMAND_TEXT_PASTE, 216, "command_text_paste"}, - {wxEVT_COMMAND_SPINCTRL_UPDATED, 217, "command_spinctrl_updated"}, - {wxEVT_SCROLL_LINEUP + wxEVT_USER_FIRST, 165, "spin_up"}, - {wxEVT_SCROLL_LINEDOWN + wxEVT_USER_FIRST, 165, "spin_down"}, - {wxEVT_SCROLL_THUMBTRACK + wxEVT_USER_FIRST, 165, "spin"}, - {wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGED, 219, "command_splitter_sash_pos_changed"}, - {wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGING, 219, "command_splitter_sash_pos_changing"}, - {wxEVT_COMMAND_SPLITTER_DOUBLECLICKED, 219, "command_splitter_doubleclicked"}, - {wxEVT_COMMAND_SPLITTER_UNSPLIT, 219, "command_splitter_unsplit"}, - {wxEVT_COMMAND_HTML_LINK_CLICKED, 221, "command_html_link_clicked"}, - {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, 224, "command_auinotebook_page_close"}, - {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, 224, "command_auinotebook_page_changed"}, - {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, 224, "command_auinotebook_page_changing"}, - {wxEVT_COMMAND_AUINOTEBOOK_BUTTON, 224, "command_auinotebook_button"}, - {wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, 224, "command_auinotebook_begin_drag"}, - {wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, 224, "command_auinotebook_end_drag"}, - {wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION, 224, "command_auinotebook_drag_motion"}, - {wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, 224, "command_auinotebook_allow_dnd"}, + {wxEVT_COMMAND_BUTTON_CLICKED, 165, "command_button_clicked"}, + {wxEVT_COMMAND_CHECKBOX_CLICKED, 165, "command_checkbox_clicked"}, + {wxEVT_COMMAND_CHOICE_SELECTED, 165, "command_choice_selected"}, + {wxEVT_COMMAND_LISTBOX_SELECTED, 165, "command_listbox_selected"}, + {wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, 165, "command_listbox_doubleclicked"}, + {wxEVT_COMMAND_TEXT_UPDATED, 165, "command_text_updated"}, + {wxEVT_COMMAND_TEXT_ENTER, 165, "command_text_enter"}, + {wxEVT_COMMAND_MENU_SELECTED, 165, "command_menu_selected"}, + {wxEVT_COMMAND_SLIDER_UPDATED, 165, "command_slider_updated"}, + {wxEVT_COMMAND_RADIOBOX_SELECTED, 165, "command_radiobox_selected"}, + {wxEVT_COMMAND_RADIOBUTTON_SELECTED, 165, "command_radiobutton_selected"}, + {wxEVT_COMMAND_SCROLLBAR_UPDATED, 165, "command_scrollbar_updated"}, + {wxEVT_COMMAND_VLBOX_SELECTED, 165, "command_vlbox_selected"}, + {wxEVT_COMMAND_COMBOBOX_SELECTED, 165, "command_combobox_selected"}, + {wxEVT_COMMAND_TOOL_RCLICKED, 165, "command_tool_rclicked"}, + {wxEVT_COMMAND_TOOL_ENTER, 165, "command_tool_enter"}, + {wxEVT_COMMAND_CHECKLISTBOX_TOGGLED, 165, "command_checklistbox_toggled"}, + {wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, 165, "command_togglebutton_clicked"}, + {wxEVT_COMMAND_LEFT_CLICK, 165, "command_left_click"}, + {wxEVT_COMMAND_LEFT_DCLICK, 165, "command_left_dclick"}, + {wxEVT_COMMAND_RIGHT_CLICK, 165, "command_right_click"}, + {wxEVT_COMMAND_SET_FOCUS, 165, "command_set_focus"}, + {wxEVT_COMMAND_KILL_FOCUS, 165, "command_kill_focus"}, + {wxEVT_COMMAND_ENTER, 165, "command_enter"}, + {wxEVT_SCROLL_TOP, 166, "scroll_top"}, + {wxEVT_SCROLL_BOTTOM, 166, "scroll_bottom"}, + {wxEVT_SCROLL_LINEUP, 166, "scroll_lineup"}, + {wxEVT_SCROLL_LINEDOWN, 166, "scroll_linedown"}, + {wxEVT_SCROLL_PAGEUP, 166, "scroll_pageup"}, + {wxEVT_SCROLL_PAGEDOWN, 166, "scroll_pagedown"}, + {wxEVT_SCROLL_THUMBTRACK, 166, "scroll_thumbtrack"}, + {wxEVT_SCROLL_THUMBRELEASE, 166, "scroll_thumbrelease"}, + {wxEVT_SCROLL_CHANGED, 166, "scroll_changed"}, + {wxEVT_SCROLLWIN_TOP, 167, "scrollwin_top"}, + {wxEVT_SCROLLWIN_BOTTOM, 167, "scrollwin_bottom"}, + {wxEVT_SCROLLWIN_LINEUP, 167, "scrollwin_lineup"}, + {wxEVT_SCROLLWIN_LINEDOWN, 167, "scrollwin_linedown"}, + {wxEVT_SCROLLWIN_PAGEUP, 167, "scrollwin_pageup"}, + {wxEVT_SCROLLWIN_PAGEDOWN, 167, "scrollwin_pagedown"}, + {wxEVT_SCROLLWIN_THUMBTRACK, 167, "scrollwin_thumbtrack"}, + {wxEVT_SCROLLWIN_THUMBRELEASE, 167, "scrollwin_thumbrelease"}, + {wxEVT_LEFT_DOWN, 168, "left_down"}, + {wxEVT_LEFT_UP, 168, "left_up"}, + {wxEVT_MIDDLE_DOWN, 168, "middle_down"}, + {wxEVT_MIDDLE_UP, 168, "middle_up"}, + {wxEVT_RIGHT_DOWN, 168, "right_down"}, + {wxEVT_RIGHT_UP, 168, "right_up"}, + {wxEVT_MOTION, 168, "motion"}, + {wxEVT_ENTER_WINDOW, 168, "enter_window"}, + {wxEVT_LEAVE_WINDOW, 168, "leave_window"}, + {wxEVT_LEFT_DCLICK, 168, "left_dclick"}, + {wxEVT_MIDDLE_DCLICK, 168, "middle_dclick"}, + {wxEVT_RIGHT_DCLICK, 168, "right_dclick"}, + {wxEVT_MOUSEWHEEL, 168, "mousewheel"}, + {wxEVT_SET_CURSOR, 169, "set_cursor"}, + {wxEVT_CHAR, 170, "char"}, + {wxEVT_CHAR_HOOK, 170, "char_hook"}, + {wxEVT_KEY_DOWN, 170, "key_down"}, + {wxEVT_KEY_UP, 170, "key_up"}, + {wxEVT_SIZE, 171, "size"}, + {wxEVT_MOVE, 172, "move"}, + {wxEVT_PAINT, 173, "paint"}, + {wxEVT_ERASE_BACKGROUND, 174, "erase_background"}, + {wxEVT_SET_FOCUS, 175, "set_focus"}, + {wxEVT_KILL_FOCUS, 175, "kill_focus"}, + {wxEVT_CHILD_FOCUS, 176, "child_focus"}, + {wxEVT_MENU_OPEN, 177, "menu_open"}, + {wxEVT_MENU_CLOSE, 177, "menu_close"}, + {wxEVT_MENU_HIGHLIGHT, 177, "menu_highlight"}, + {wxEVT_CLOSE_WINDOW, 178, "close_window"}, + {wxEVT_END_SESSION, 178, "end_session"}, + {wxEVT_QUERY_END_SESSION, 178, "query_end_session"}, + {wxEVT_SHOW, 179, "show"}, + {wxEVT_ICONIZE, 180, "iconize"}, + {wxEVT_MAXIMIZE, 181, "maximize"}, + {wxEVT_JOY_BUTTON_DOWN, 182, "joy_button_down"}, + {wxEVT_JOY_BUTTON_UP, 182, "joy_button_up"}, + {wxEVT_JOY_MOVE, 182, "joy_move"}, + {wxEVT_JOY_ZMOVE, 182, "joy_zmove"}, + {wxEVT_UPDATE_UI, 183, "update_ui"}, + {wxEVT_SYS_COLOUR_CHANGED, 184, "sys_colour_changed"}, + {wxEVT_MOUSE_CAPTURE_CHANGED, 185, "mouse_capture_changed"}, + {wxEVT_DISPLAY_CHANGED, 186, "display_changed"}, + {wxEVT_PALETTE_CHANGED, 187, "palette_changed"}, + {wxEVT_QUERY_NEW_PALETTE, 188, "query_new_palette"}, + {wxEVT_NAVIGATION_KEY, 189, "navigation_key"}, + {wxEVT_CREATE, 190, "create"}, + {wxEVT_DESTROY, 191, "destroy"}, + {wxEVT_HELP, 192, "help"}, + {wxEVT_DETAILED_HELP, 192, "detailed_help"}, + {wxEVT_CONTEXT_MENU, 193, "context_menu"}, + {wxEVT_IDLE, 194, "idle"}, + {wxEVT_GRID_CELL_LEFT_CLICK, 195, "grid_cell_left_click"}, + {wxEVT_GRID_CELL_RIGHT_CLICK, 195, "grid_cell_right_click"}, + {wxEVT_GRID_CELL_LEFT_DCLICK, 195, "grid_cell_left_dclick"}, + {wxEVT_GRID_CELL_RIGHT_DCLICK, 195, "grid_cell_right_dclick"}, + {wxEVT_GRID_LABEL_LEFT_CLICK, 195, "grid_label_left_click"}, + {wxEVT_GRID_LABEL_RIGHT_CLICK, 195, "grid_label_right_click"}, + {wxEVT_GRID_LABEL_LEFT_DCLICK, 195, "grid_label_left_dclick"}, + {wxEVT_GRID_LABEL_RIGHT_DCLICK, 195, "grid_label_right_dclick"}, + {wxEVT_GRID_ROW_SIZE, 195, "grid_row_size"}, + {wxEVT_GRID_COL_SIZE, 195, "grid_col_size"}, + {wxEVT_GRID_RANGE_SELECT, 195, "grid_range_select"}, + {wxEVT_GRID_CELL_CHANGE, 195, "grid_cell_change"}, + {wxEVT_GRID_SELECT_CELL, 195, "grid_select_cell"}, + {wxEVT_GRID_EDITOR_SHOWN, 195, "grid_editor_shown"}, + {wxEVT_GRID_EDITOR_HIDDEN, 195, "grid_editor_hidden"}, + {wxEVT_GRID_EDITOR_CREATED, 195, "grid_editor_created"}, + {wxEVT_GRID_CELL_BEGIN_DRAG, 195, "grid_cell_begin_drag"}, + {wxEVT_SASH_DRAGGED, 197, "sash_dragged"}, + {wxEVT_COMMAND_LIST_BEGIN_DRAG, 198, "command_list_begin_drag"}, + {wxEVT_COMMAND_LIST_BEGIN_RDRAG, 198, "command_list_begin_rdrag"}, + {wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT, 198, "command_list_begin_label_edit"}, + {wxEVT_COMMAND_LIST_END_LABEL_EDIT, 198, "command_list_end_label_edit"}, + {wxEVT_COMMAND_LIST_DELETE_ITEM, 198, "command_list_delete_item"}, + {wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS, 198, "command_list_delete_all_items"}, + {wxEVT_COMMAND_LIST_KEY_DOWN, 198, "command_list_key_down"}, + {wxEVT_COMMAND_LIST_INSERT_ITEM, 198, "command_list_insert_item"}, + {wxEVT_COMMAND_LIST_COL_CLICK, 198, "command_list_col_click"}, + {wxEVT_COMMAND_LIST_COL_RIGHT_CLICK, 198, "command_list_col_right_click"}, + {wxEVT_COMMAND_LIST_COL_BEGIN_DRAG, 198, "command_list_col_begin_drag"}, + {wxEVT_COMMAND_LIST_COL_DRAGGING, 198, "command_list_col_dragging"}, + {wxEVT_COMMAND_LIST_COL_END_DRAG, 198, "command_list_col_end_drag"}, + {wxEVT_COMMAND_LIST_ITEM_SELECTED, 198, "command_list_item_selected"}, + {wxEVT_COMMAND_LIST_ITEM_DESELECTED, 198, "command_list_item_deselected"}, + {wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, 198, "command_list_item_right_click"}, + {wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK, 198, "command_list_item_middle_click"}, + {wxEVT_COMMAND_LIST_ITEM_ACTIVATED, 198, "command_list_item_activated"}, + {wxEVT_COMMAND_LIST_ITEM_FOCUSED, 198, "command_list_item_focused"}, + {wxEVT_COMMAND_LIST_CACHE_HINT, 198, "command_list_cache_hint"}, + {wxEVT_DATE_CHANGED, 199, "date_changed"}, + {wxEVT_CALENDAR_SEL_CHANGED, 200, "calendar_sel_changed"}, + {wxEVT_CALENDAR_DAY_CHANGED, 200, "calendar_day_changed"}, + {wxEVT_CALENDAR_MONTH_CHANGED, 200, "calendar_month_changed"}, + {wxEVT_CALENDAR_YEAR_CHANGED, 200, "calendar_year_changed"}, + {wxEVT_CALENDAR_DOUBLECLICKED, 200, "calendar_doubleclicked"}, + {wxEVT_CALENDAR_WEEKDAY_CLICKED, 200, "calendar_weekday_clicked"}, + {wxEVT_COMMAND_FILEPICKER_CHANGED, 201, "command_filepicker_changed"}, + {wxEVT_COMMAND_DIRPICKER_CHANGED, 201, "command_dirpicker_changed"}, + {wxEVT_COMMAND_COLOURPICKER_CHANGED, 202, "command_colourpicker_changed"}, + {wxEVT_COMMAND_FONTPICKER_CHANGED, 203, "command_fontpicker_changed"}, + {wxEVT_STC_CHANGE, 204, "stc_change"}, + {wxEVT_STC_STYLENEEDED, 204, "stc_styleneeded"}, + {wxEVT_STC_CHARADDED, 204, "stc_charadded"}, + {wxEVT_STC_SAVEPOINTREACHED, 204, "stc_savepointreached"}, + {wxEVT_STC_SAVEPOINTLEFT, 204, "stc_savepointleft"}, + {wxEVT_STC_ROMODIFYATTEMPT, 204, "stc_romodifyattempt"}, + {wxEVT_STC_KEY, 204, "stc_key"}, + {wxEVT_STC_DOUBLECLICK, 204, "stc_doubleclick"}, + {wxEVT_STC_UPDATEUI, 204, "stc_updateui"}, + {wxEVT_STC_MODIFIED, 204, "stc_modified"}, + {wxEVT_STC_MACRORECORD, 204, "stc_macrorecord"}, + {wxEVT_STC_MARGINCLICK, 204, "stc_marginclick"}, + {wxEVT_STC_NEEDSHOWN, 204, "stc_needshown"}, + {wxEVT_STC_PAINTED, 204, "stc_painted"}, + {wxEVT_STC_USERLISTSELECTION, 204, "stc_userlistselection"}, + {wxEVT_STC_URIDROPPED, 204, "stc_uridropped"}, + {wxEVT_STC_DWELLSTART, 204, "stc_dwellstart"}, + {wxEVT_STC_DWELLEND, 204, "stc_dwellend"}, + {wxEVT_STC_START_DRAG, 204, "stc_start_drag"}, + {wxEVT_STC_DRAG_OVER, 204, "stc_drag_over"}, + {wxEVT_STC_DO_DROP, 204, "stc_do_drop"}, + {wxEVT_STC_ZOOM, 204, "stc_zoom"}, + {wxEVT_STC_HOTSPOT_CLICK, 204, "stc_hotspot_click"}, + {wxEVT_STC_HOTSPOT_DCLICK, 204, "stc_hotspot_dclick"}, + {wxEVT_STC_CALLTIP_CLICK, 204, "stc_calltip_click"}, + {wxEVT_STC_AUTOCOMP_SELECTION, 204, "stc_autocomp_selection"}, + {wxEVT_COMMAND_TREE_BEGIN_DRAG, 210, "command_tree_begin_drag"}, + {wxEVT_COMMAND_TREE_BEGIN_RDRAG, 210, "command_tree_begin_rdrag"}, + {wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, 210, "command_tree_begin_label_edit"}, + {wxEVT_COMMAND_TREE_END_LABEL_EDIT, 210, "command_tree_end_label_edit"}, + {wxEVT_COMMAND_TREE_DELETE_ITEM, 210, "command_tree_delete_item"}, + {wxEVT_COMMAND_TREE_GET_INFO, 210, "command_tree_get_info"}, + {wxEVT_COMMAND_TREE_SET_INFO, 210, "command_tree_set_info"}, + {wxEVT_COMMAND_TREE_ITEM_EXPANDED, 210, "command_tree_item_expanded"}, + {wxEVT_COMMAND_TREE_ITEM_EXPANDING, 210, "command_tree_item_expanding"}, + {wxEVT_COMMAND_TREE_ITEM_COLLAPSED, 210, "command_tree_item_collapsed"}, + {wxEVT_COMMAND_TREE_ITEM_COLLAPSING, 210, "command_tree_item_collapsing"}, + {wxEVT_COMMAND_TREE_SEL_CHANGED, 210, "command_tree_sel_changed"}, + {wxEVT_COMMAND_TREE_SEL_CHANGING, 210, "command_tree_sel_changing"}, + {wxEVT_COMMAND_TREE_KEY_DOWN, 210, "command_tree_key_down"}, + {wxEVT_COMMAND_TREE_ITEM_ACTIVATED, 210, "command_tree_item_activated"}, + {wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, 210, "command_tree_item_right_click"}, + {wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK, 210, "command_tree_item_middle_click"}, + {wxEVT_COMMAND_TREE_END_DRAG, 210, "command_tree_end_drag"}, + {wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK, 210, "command_tree_state_image_click"}, + {wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP, 210, "command_tree_item_gettooltip"}, + {wxEVT_COMMAND_TREE_ITEM_MENU, 210, "command_tree_item_menu"}, + {wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, 211, "command_notebook_page_changed"}, + {wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING, 211, "command_notebook_page_changing"}, + {wxEVT_COMMAND_TEXT_COPY, 217, "command_text_copy"}, + {wxEVT_COMMAND_TEXT_CUT, 217, "command_text_cut"}, + {wxEVT_COMMAND_TEXT_PASTE, 217, "command_text_paste"}, + {wxEVT_COMMAND_SPINCTRL_UPDATED, 218, "command_spinctrl_updated"}, + {wxEVT_SCROLL_LINEUP + wxEVT_USER_FIRST, 166, "spin_up"}, + {wxEVT_SCROLL_LINEDOWN + wxEVT_USER_FIRST, 166, "spin_down"}, + {wxEVT_SCROLL_THUMBTRACK + wxEVT_USER_FIRST, 166, "spin"}, + {wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGED, 220, "command_splitter_sash_pos_changed"}, + {wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGING, 220, "command_splitter_sash_pos_changing"}, + {wxEVT_COMMAND_SPLITTER_DOUBLECLICKED, 220, "command_splitter_doubleclicked"}, + {wxEVT_COMMAND_SPLITTER_UNSPLIT, 220, "command_splitter_unsplit"}, + {wxEVT_COMMAND_HTML_LINK_CLICKED, 222, "command_html_link_clicked"}, + {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, 225, "command_auinotebook_page_close"}, + {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, 225, "command_auinotebook_page_changed"}, + {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, 225, "command_auinotebook_page_changing"}, + {wxEVT_COMMAND_AUINOTEBOOK_BUTTON, 225, "command_auinotebook_button"}, + {wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, 225, "command_auinotebook_begin_drag"}, + {wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, 225, "command_auinotebook_end_drag"}, + {wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION, 225, "command_auinotebook_drag_motion"}, + {wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, 225, "command_auinotebook_allow_dnd"}, #if wxCHECK_VERSION(2,8,5) - {wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN, 224, "command_auinotebook_tab_middle_down"}, + {wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN, 225, "command_auinotebook_tab_middle_down"}, #endif #if wxCHECK_VERSION(2,8,5) - {wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP, 224, "command_auinotebook_tab_middle_up"}, + {wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP, 225, "command_auinotebook_tab_middle_up"}, #endif #if wxCHECK_VERSION(2,8,5) - {wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN, 224, "command_auinotebook_tab_right_down"}, + {wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN, 225, "command_auinotebook_tab_right_down"}, #endif #if wxCHECK_VERSION(2,8,5) - {wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, 224, "command_auinotebook_tab_right_up"}, + {wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, 225, "command_auinotebook_tab_right_up"}, #endif #if wxCHECK_VERSION(2,8,5) - {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, 224, "command_auinotebook_page_closed"}, + {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, 225, "command_auinotebook_page_closed"}, #endif #if wxCHECK_VERSION(2,8,5) - {wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE, 224, "command_auinotebook_drag_done"}, + {wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE, 225, "command_auinotebook_drag_done"}, #endif #if wxCHECK_VERSION(2,8,5) - {wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK, 224, "command_auinotebook_bg_dclick"}, + {wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK, 225, "command_auinotebook_bg_dclick"}, #endif - {wxEVT_AUI_PANE_BUTTON, 225, "aui_pane_button"}, - {wxEVT_AUI_PANE_CLOSE, 225, "aui_pane_close"}, - {wxEVT_AUI_PANE_MAXIMIZE, 225, "aui_pane_maximize"}, - {wxEVT_AUI_PANE_RESTORE, 225, "aui_pane_restore"}, - {wxEVT_AUI_RENDER, 225, "aui_render"}, - {wxEVT_AUI_FIND_MANAGER, 225, "aui_find_manager"}, - {wxEVT_TASKBAR_MOVE, 228, "taskbar_move"}, - {wxEVT_TASKBAR_LEFT_DOWN, 228, "taskbar_left_down"}, - {wxEVT_TASKBAR_LEFT_UP, 228, "taskbar_left_up"}, - {wxEVT_TASKBAR_RIGHT_DOWN, 228, "taskbar_right_down"}, - {wxEVT_TASKBAR_RIGHT_UP, 228, "taskbar_right_up"}, - {wxEVT_TASKBAR_LEFT_DCLICK, 228, "taskbar_left_dclick"}, - {wxEVT_TASKBAR_RIGHT_DCLICK, 228, "taskbar_right_dclick"}, - {wxEVT_INIT_DIALOG, 229, "init_dialog"}, - {wxEVT_ACTIVATE, 231, "activate"}, - {wxEVT_ACTIVATE_APP, 231, "activate_app"}, - {wxEVT_HIBERNATE, 231, "hibernate"}, + {wxEVT_AUI_PANE_BUTTON, 226, "aui_pane_button"}, + {wxEVT_AUI_PANE_CLOSE, 226, "aui_pane_close"}, + {wxEVT_AUI_PANE_MAXIMIZE, 226, "aui_pane_maximize"}, + {wxEVT_AUI_PANE_RESTORE, 226, "aui_pane_restore"}, +#if wxCHECK_VERSION(2,9,5) + {wxEVT_AUI_PANE_ACTIVATED, 226, "aui_pane_activated"}, +#endif + {wxEVT_AUI_RENDER, 226, "aui_render"}, + {wxEVT_AUI_FIND_MANAGER, 226, "aui_find_manager"}, + {wxEVT_TASKBAR_MOVE, 229, "taskbar_move"}, + {wxEVT_TASKBAR_LEFT_DOWN, 229, "taskbar_left_down"}, + {wxEVT_TASKBAR_LEFT_UP, 229, "taskbar_left_up"}, + {wxEVT_TASKBAR_RIGHT_DOWN, 229, "taskbar_right_down"}, + {wxEVT_TASKBAR_RIGHT_UP, 229, "taskbar_right_up"}, + {wxEVT_TASKBAR_LEFT_DCLICK, 229, "taskbar_left_dclick"}, + {wxEVT_TASKBAR_RIGHT_DCLICK, 229, "taskbar_right_dclick"}, + {wxEVT_INIT_DIALOG, 230, "init_dialog"}, + {wxEVT_ACTIVATE, 232, "activate"}, + {wxEVT_ACTIVATE_APP, 232, "activate_app"}, + {wxEVT_HIBERNATE, 232, "hibernate"}, + {wxEVT_MOUSE_CAPTURE_LOST, 235, "mouse_capture_lost"}, {-1, 0, } }; for(int i=0; event_types[i].ev_type != -1; i++) { @@ -344,7 +348,7 @@ bool sendevent(wxEvent *event, ErlDrvTermData port) rt.addRef(cb->obj, cb->class_name); rt.addExt2Term(cb->user_data); switch(Etype->cID) { -case 164: {// wxCommandEvent +case 165: {// wxCommandEvent wxCommandEvent * ev = (wxCommandEvent *) event; evClass = (char*)"wxCommandEvent"; rt.addAtom((char*)"wxCommand"); @@ -355,7 +359,7 @@ case 164: {// wxCommandEvent rt.addTupleCount(5); break; } -case 165: {// wxScrollEvent or wxSpinEvent +case 166: {// wxScrollEvent or wxSpinEvent if(event->IsKindOf(CLASSINFO(wxScrollEvent))) { wxScrollEvent * ev = (wxScrollEvent *) event; evClass = (char*)"wxScrollEvent"; @@ -375,7 +379,7 @@ case 165: {// wxScrollEvent or wxSpinEvent } break; } -case 166: {// wxScrollWinEvent +case 167: {// wxScrollWinEvent wxScrollWinEvent * ev = (wxScrollWinEvent *) event; evClass = (char*)"wxScrollWinEvent"; rt.addAtom((char*)"wxScrollWin"); @@ -385,7 +389,7 @@ case 166: {// wxScrollWinEvent rt.addTupleCount(4); break; } -case 167: {// wxMouseEvent +case 168: {// wxMouseEvent wxMouseEvent * ev = (wxMouseEvent *) event; evClass = (char*)"wxMouseEvent"; rt.addAtom((char*)"wxMouse"); @@ -409,7 +413,7 @@ case 167: {// wxMouseEvent rt.addTupleCount(14); break; } -case 168: {// wxSetCursorEvent +case 169: {// wxSetCursorEvent wxSetCursorEvent * ev = (wxSetCursorEvent *) event; wxCursor * GetCursor = new wxCursor(ev->GetCursor()); app->newPtr((void *) GetCursor,3, memenv); @@ -422,7 +426,7 @@ case 168: {// wxSetCursorEvent rt.addTupleCount(5); break; } -case 169: {// wxKeyEvent +case 170: {// wxKeyEvent wxKeyEvent * ev = (wxKeyEvent *) event; evClass = (char*)"wxKeyEvent"; rt.addAtom((char*)"wxKey"); @@ -449,7 +453,7 @@ case 169: {// wxKeyEvent rt.addTupleCount(13); break; } -case 170: {// wxSizeEvent +case 171: {// wxSizeEvent wxSizeEvent * ev = (wxSizeEvent *) event; evClass = (char*)"wxSizeEvent"; rt.addAtom((char*)"wxSize"); @@ -459,7 +463,7 @@ case 170: {// wxSizeEvent rt.addTupleCount(4); break; } -case 171: {// wxMoveEvent +case 172: {// wxMoveEvent wxMoveEvent * ev = (wxMoveEvent *) event; evClass = (char*)"wxMoveEvent"; rt.addAtom((char*)"wxMove"); @@ -469,14 +473,14 @@ case 171: {// wxMoveEvent rt.addTupleCount(4); break; } -case 172: {// wxPaintEvent +case 173: {// wxPaintEvent evClass = (char*)"wxPaintEvent"; rt.addAtom((char*)"wxPaint"); rt.addAtom(Etype->eName); rt.addTupleCount(2); break; } -case 173: {// wxEraseEvent +case 174: {// wxEraseEvent wxEraseEvent * ev = (wxEraseEvent *) event; wxDC * GetDC = ev->GetDC(); evClass = (char*)"wxEraseEvent"; @@ -486,7 +490,7 @@ case 173: {// wxEraseEvent rt.addTupleCount(3); break; } -case 174: {// wxFocusEvent +case 175: {// wxFocusEvent wxFocusEvent * ev = (wxFocusEvent *) event; wxWindow * GetWindow = ev->GetWindow(); evClass = (char*)"wxFocusEvent"; @@ -496,14 +500,14 @@ case 174: {// wxFocusEvent rt.addTupleCount(3); break; } -case 175: {// wxChildFocusEvent +case 176: {// wxChildFocusEvent evClass = (char*)"wxChildFocusEvent"; rt.addAtom((char*)"wxChildFocus"); rt.addAtom(Etype->eName); rt.addTupleCount(2); break; } -case 176: {// wxMenuEvent +case 177: {// wxMenuEvent wxMenuEvent * ev = (wxMenuEvent *) event; wxMenu * GetMenu = ev->GetMenu(); evClass = (char*)"wxMenuEvent"; @@ -514,14 +518,14 @@ case 176: {// wxMenuEvent rt.addTupleCount(4); break; } -case 177: {// wxCloseEvent +case 178: {// wxCloseEvent evClass = (char*)"wxCloseEvent"; rt.addAtom((char*)"wxClose"); rt.addAtom(Etype->eName); rt.addTupleCount(2); break; } -case 178: {// wxShowEvent +case 179: {// wxShowEvent wxShowEvent * ev = (wxShowEvent *) event; evClass = (char*)"wxShowEvent"; rt.addAtom((char*)"wxShow"); @@ -530,7 +534,7 @@ case 178: {// wxShowEvent rt.addTupleCount(3); break; } -case 179: {// wxIconizeEvent +case 180: {// wxIconizeEvent wxIconizeEvent * ev = (wxIconizeEvent *) event; evClass = (char*)"wxIconizeEvent"; rt.addAtom((char*)"wxIconize"); @@ -539,14 +543,14 @@ case 179: {// wxIconizeEvent rt.addTupleCount(3); break; } -case 180: {// wxMaximizeEvent +case 181: {// wxMaximizeEvent evClass = (char*)"wxMaximizeEvent"; rt.addAtom((char*)"wxMaximize"); rt.addAtom(Etype->eName); rt.addTupleCount(2); break; } -case 181: {// wxJoystickEvent +case 182: {// wxJoystickEvent wxJoystickEvent * ev = (wxJoystickEvent *) event; evClass = (char*)"wxJoystickEvent"; rt.addAtom((char*)"wxJoystick"); @@ -559,49 +563,49 @@ case 181: {// wxJoystickEvent rt.addTupleCount(7); break; } -case 182: {// wxUpdateUIEvent +case 183: {// wxUpdateUIEvent evClass = (char*)"wxUpdateUIEvent"; rt.addAtom((char*)"wxUpdateUI"); rt.addAtom(Etype->eName); rt.addTupleCount(2); break; } -case 183: {// wxSysColourChangedEvent +case 184: {// wxSysColourChangedEvent evClass = (char*)"wxSysColourChangedEvent"; rt.addAtom((char*)"wxSysColourChanged"); rt.addAtom(Etype->eName); rt.addTupleCount(2); break; } -case 184: {// wxMouseCaptureChangedEvent +case 185: {// wxMouseCaptureChangedEvent evClass = (char*)"wxMouseCaptureChangedEvent"; rt.addAtom((char*)"wxMouseCaptureChanged"); rt.addAtom(Etype->eName); rt.addTupleCount(2); break; } -case 185: {// wxDisplayChangedEvent +case 186: {// wxDisplayChangedEvent evClass = (char*)"wxDisplayChangedEvent"; rt.addAtom((char*)"wxDisplayChanged"); rt.addAtom(Etype->eName); rt.addTupleCount(2); break; } -case 186: {// wxPaletteChangedEvent +case 187: {// wxPaletteChangedEvent evClass = (char*)"wxPaletteChangedEvent"; rt.addAtom((char*)"wxPaletteChanged"); rt.addAtom(Etype->eName); rt.addTupleCount(2); break; } -case 187: {// wxQueryNewPaletteEvent +case 188: {// wxQueryNewPaletteEvent evClass = (char*)"wxQueryNewPaletteEvent"; rt.addAtom((char*)"wxQueryNewPalette"); rt.addAtom(Etype->eName); rt.addTupleCount(2); break; } -case 188: {// wxNavigationKeyEvent +case 189: {// wxNavigationKeyEvent wxNavigationKeyEvent * ev = (wxNavigationKeyEvent *) event; evClass = (char*)"wxNavigationKeyEvent"; rt.addAtom((char*)"wxNavigationKey"); @@ -611,28 +615,28 @@ case 188: {// wxNavigationKeyEvent rt.addTupleCount(4); break; } -case 189: {// wxWindowCreateEvent +case 190: {// wxWindowCreateEvent evClass = (char*)"wxWindowCreateEvent"; rt.addAtom((char*)"wxWindowCreate"); rt.addAtom(Etype->eName); rt.addTupleCount(2); break; } -case 190: {// wxWindowDestroyEvent +case 191: {// wxWindowDestroyEvent evClass = (char*)"wxWindowDestroyEvent"; rt.addAtom((char*)"wxWindowDestroy"); rt.addAtom(Etype->eName); rt.addTupleCount(2); break; } -case 191: {// wxHelpEvent +case 192: {// wxHelpEvent evClass = (char*)"wxHelpEvent"; rt.addAtom((char*)"wxHelp"); rt.addAtom(Etype->eName); rt.addTupleCount(2); break; } -case 192: {// wxContextMenuEvent +case 193: {// wxContextMenuEvent wxContextMenuEvent * ev = (wxContextMenuEvent *) event; evClass = (char*)"wxContextMenuEvent"; rt.addAtom((char*)"wxContextMenu"); @@ -641,14 +645,14 @@ case 192: {// wxContextMenuEvent rt.addTupleCount(3); break; } -case 193: {// wxIdleEvent +case 194: {// wxIdleEvent evClass = (char*)"wxIdleEvent"; rt.addAtom((char*)"wxIdle"); rt.addAtom(Etype->eName); rt.addTupleCount(2); break; } -case 194: {// wxGridEvent +case 195: {// wxGridEvent wxGridEvent * ev = (wxGridEvent *) event; evClass = (char*)"wxGridEvent"; rt.addAtom((char*)"wxGrid"); @@ -665,7 +669,7 @@ case 194: {// wxGridEvent rt.addTupleCount(11); break; } -case 196: {// wxSashEvent +case 197: {// wxSashEvent wxSashEvent * ev = (wxSashEvent *) event; evClass = (char*)"wxSashEvent"; rt.addAtom((char*)"wxSash"); @@ -676,7 +680,7 @@ case 196: {// wxSashEvent rt.addTupleCount(5); break; } -case 197: {// wxListEvent +case 198: {// wxListEvent wxListEvent * ev = (wxListEvent *) event; evClass = (char*)"wxListEvent"; rt.addAtom((char*)"wxList"); @@ -689,7 +693,7 @@ case 197: {// wxListEvent rt.addTupleCount(7); break; } -case 198: {// wxDateEvent +case 199: {// wxDateEvent wxDateEvent * ev = (wxDateEvent *) event; evClass = (char*)"wxDateEvent"; rt.addAtom((char*)"wxDate"); @@ -698,7 +702,7 @@ case 198: {// wxDateEvent rt.addTupleCount(3); break; } -case 199: {// wxCalendarEvent +case 200: {// wxCalendarEvent wxCalendarEvent * ev = (wxCalendarEvent *) event; evClass = (char*)"wxCalendarEvent"; rt.addAtom((char*)"wxCalendar"); @@ -708,7 +712,7 @@ case 199: {// wxCalendarEvent rt.addTupleCount(4); break; } -case 200: {// wxFileDirPickerEvent +case 201: {// wxFileDirPickerEvent wxFileDirPickerEvent * ev = (wxFileDirPickerEvent *) event; evClass = (char*)"wxFileDirPickerEvent"; rt.addAtom((char*)"wxFileDirPicker"); @@ -717,7 +721,7 @@ case 200: {// wxFileDirPickerEvent rt.addTupleCount(3); break; } -case 201: {// wxColourPickerEvent +case 202: {// wxColourPickerEvent wxColourPickerEvent * ev = (wxColourPickerEvent *) event; evClass = (char*)"wxColourPickerEvent"; rt.addAtom((char*)"wxColourPicker"); @@ -726,7 +730,7 @@ case 201: {// wxColourPickerEvent rt.addTupleCount(3); break; } -case 202: {// wxFontPickerEvent +case 203: {// wxFontPickerEvent wxFontPickerEvent * ev = (wxFontPickerEvent *) event; wxFont * GetFont = new wxFont(ev->GetFont()); app->newPtr((void *) GetFont,3, memenv); @@ -737,7 +741,7 @@ case 202: {// wxFontPickerEvent rt.addTupleCount(3); break; } -case 203: {// wxStyledTextEvent +case 204: {// wxStyledTextEvent wxStyledTextEvent * ev = (wxStyledTextEvent *) event; evClass = (char*)"wxStyledTextEvent"; rt.addAtom((char*)"wxStyledText"); @@ -765,7 +769,7 @@ case 203: {// wxStyledTextEvent rt.addTupleCount(22); break; } -case 209: {// wxTreeEvent +case 210: {// wxTreeEvent wxTreeEvent * ev = (wxTreeEvent *) event; evClass = (char*)"wxTreeEvent"; rt.addAtom((char*)"wxTree"); @@ -776,7 +780,7 @@ case 209: {// wxTreeEvent rt.addTupleCount(5); break; } -case 210: {// wxNotebookEvent +case 211: {// wxNotebookEvent wxNotebookEvent * ev = (wxNotebookEvent *) event; evClass = (char*)"wxNotebookEvent"; rt.addAtom((char*)"wxNotebook"); @@ -786,14 +790,14 @@ case 210: {// wxNotebookEvent rt.addTupleCount(4); break; } -case 216: {// wxClipboardTextEvent +case 217: {// wxClipboardTextEvent evClass = (char*)"wxClipboardTextEvent"; rt.addAtom((char*)"wxClipboardText"); rt.addAtom(Etype->eName); rt.addTupleCount(2); break; } -case 217: {// wxSpinEvent +case 218: {// wxSpinEvent wxSpinEvent * ev = (wxSpinEvent *) event; evClass = (char*)"wxSpinEvent"; rt.addAtom((char*)"wxSpin"); @@ -802,14 +806,14 @@ case 217: {// wxSpinEvent rt.addTupleCount(3); break; } -case 219: {// wxSplitterEvent +case 220: {// wxSplitterEvent evClass = (char*)"wxSplitterEvent"; rt.addAtom((char*)"wxSplitter"); rt.addAtom(Etype->eName); rt.addTupleCount(2); break; } -case 221: {// wxHtmlLinkEvent +case 222: {// wxHtmlLinkEvent wxHtmlLinkEvent * ev = (wxHtmlLinkEvent *) event; evClass = (char*)"wxHtmlLinkEvent"; rt.addAtom((char*)"wxHtmlLink"); @@ -818,7 +822,7 @@ case 221: {// wxHtmlLinkEvent rt.addTupleCount(3); break; } -case 224: {// wxAuiNotebookEvent +case 225: {// wxAuiNotebookEvent wxAuiNotebookEvent * ev = (wxAuiNotebookEvent *) event; wxAuiNotebook * GetDragSource = ev->GetDragSource(); evClass = (char*)"wxAuiNotebookEvent"; @@ -830,7 +834,7 @@ case 224: {// wxAuiNotebookEvent rt.addTupleCount(5); break; } -case 225: {// wxAuiManagerEvent +case 226: {// wxAuiManagerEvent wxAuiManagerEvent * ev = (wxAuiManagerEvent *) event; wxAuiManager * GetManager = ev->GetManager(); wxAuiPaneInfo * GetPane = ev->GetPane(); @@ -847,21 +851,21 @@ case 225: {// wxAuiManagerEvent rt.addTupleCount(8); break; } -case 228: {// wxTaskBarIconEvent +case 229: {// wxTaskBarIconEvent evClass = (char*)"wxTaskBarIconEvent"; rt.addAtom((char*)"wxTaskBarIcon"); rt.addAtom(Etype->eName); rt.addTupleCount(2); break; } -case 229: {// wxInitDialogEvent +case 230: {// wxInitDialogEvent evClass = (char*)"wxInitDialogEvent"; rt.addAtom((char*)"wxInitDialog"); rt.addAtom(Etype->eName); rt.addTupleCount(2); break; } -case 231: {// wxActivateEvent +case 232: {// wxActivateEvent wxActivateEvent * ev = (wxActivateEvent *) event; evClass = (char*)"wxActivateEvent"; rt.addAtom((char*)"wxActivate"); @@ -870,6 +874,13 @@ case 231: {// wxActivateEvent rt.addTupleCount(3); break; } +case 235: {// wxMouseCaptureLostEvent + evClass = (char*)"wxMouseCaptureLostEvent"; + rt.addAtom((char*)"wxMouseCaptureLost"); + rt.addAtom(Etype->eName); + rt.addTupleCount(2); + break; +} } rt.addTupleCount(5); @@ -886,6 +897,11 @@ case 231: {// wxActivateEvent } else { send_res = rt.send(); if(cb->skip) event->Skip(); + if(app->recurse_level < 1) { + app->recurse_level++; + app->dispatch_cmds(); + app->recurse_level--; + } }; return send_res; } diff --git a/lib/wx/c_src/gen/wxe_funcs.cpp b/lib/wx/c_src/gen/wxe_funcs.cpp index b440de6cae..03b0baf875 100644 --- a/lib/wx/c_src/gen/wxe_funcs.cpp +++ b/lib/wx/c_src/gen/wxe_funcs.cpp @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2008-2015. All Rights Reserved. + * Copyright Ericsson AB 2008-2016. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -113,11 +113,15 @@ case 101: { // wxEvtHandler::Disconnect int eventType = wxeEventTypeFromAtom(bp); bp += *eventTypeLen; if(eventType > 0) { + if(recurse_level > 1) { + delayed_delete->Append(Ecmd.Save()); + } else { bool Result = This->Disconnect((int) *winid,(int) *lastId,eventType, (wxObjectEventFunction)(wxEventFunction) &wxeEvtListener::forward, NULL, Listener); rt.addBool(Result); + } } else { rt.addAtom("badarg"); rt.addAtom("event_type"); @@ -515,7 +519,7 @@ case wxWindow_GetExtraStyle: { // wxWindow::GetExtraStyle case wxWindow_GetFont: { // wxWindow::GetFont wxWindow *This = (wxWindow *) getPtr(bp,memenv); bp += 4; if(!This) throw wxe_badarg(0); - wxFont * Result = new wxFont(This->GetFont()); newPtr((void *) Result,3, memenv);; + wxFont * Result = new EwxFont(This->GetFont()); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxFont"); break; } @@ -1664,10 +1668,47 @@ case wxWindow_WarpPointer: { // wxWindow::WarpPointer This->WarpPointer(*x,*y); break; } +#if wxCHECK_VERSION(2,8,12) +case wxWindow_SetTransparent: { // wxWindow::SetTransparent + wxWindow *This = (wxWindow *) getPtr(bp,memenv); bp += 4; + int * alpha = (int *) bp; bp += 4; + if(!This) throw wxe_badarg(0); + bool Result = This->SetTransparent(*alpha); + rt.addBool(Result); + break; +} +#endif +#if wxCHECK_VERSION(2,8,12) +case wxWindow_CanSetTransparent: { // wxWindow::CanSetTransparent + wxWindow *This = (wxWindow *) getPtr(bp,memenv); bp += 4; + if(!This) throw wxe_badarg(0); + bool Result = This->CanSetTransparent(); + rt.addBool(Result); + break; +} +#endif +#if wxCHECK_VERSION(3,0,0) +case wxWindow_IsDoubleBuffered: { // wxWindow::IsDoubleBuffered + wxWindow *This = (wxWindow *) getPtr(bp,memenv); bp += 4; + if(!This) throw wxe_badarg(0); + bool Result = This->IsDoubleBuffered(); + rt.addBool(Result); + break; +} +#endif +#if wxCHECK_VERSION(3,0,0) && !defined(__WXMAC__) +case wxWindow_SetDoubleBuffered: { // wxWindow::SetDoubleBuffered + wxWindow *This = (wxWindow *) getPtr(bp,memenv); bp += 4; + bool * on = (bool *) bp; bp += 4; + if(!This) throw wxe_badarg(0); + This->SetDoubleBuffered(*on); + break; +} +#endif case wxTopLevelWindow_GetIcon: { // wxTopLevelWindow::GetIcon wxTopLevelWindow *This = (wxTopLevelWindow *) getPtr(bp,memenv); bp += 4; if(!This) throw wxe_badarg(0); - const wxIcon * Result = new wxIcon(This->GetIcon()); newPtr((void *) Result,3, memenv);; + const wxIcon * Result = new EwxIcon(This->GetIcon()); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxIcon"); break; } @@ -3061,7 +3102,7 @@ case wxGrid_GetCellFont: { // wxGrid::GetCellFont int * row = (int *) bp; bp += 4; int * col = (int *) bp; bp += 4; if(!This) throw wxe_badarg(0); - wxFont * Result = new wxFont(This->GetCellFont(*row,*col)); newPtr((void *) Result,3, memenv);; + wxFont * Result = new EwxFont(This->GetCellFont(*row,*col)); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxFont"); break; } @@ -3156,7 +3197,7 @@ case wxGrid_GetDefaultCellBackgroundColour: { // wxGrid::GetDefaultCellBackgroun case wxGrid_GetDefaultCellFont: { // wxGrid::GetDefaultCellFont wxGrid *This = (wxGrid *) getPtr(bp,memenv); bp += 4; if(!This) throw wxe_badarg(0); - wxFont * Result = new wxFont(This->GetDefaultCellFont()); newPtr((void *) Result,3, memenv);; + wxFont * Result = new EwxFont(This->GetDefaultCellFont()); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxFont"); break; } @@ -3295,7 +3336,7 @@ case wxGrid_GetLabelBackgroundColour: { // wxGrid::GetLabelBackgroundColour case wxGrid_GetLabelFont: { // wxGrid::GetLabelFont wxGrid *This = (wxGrid *) getPtr(bp,memenv); bp += 4; if(!This) throw wxe_badarg(0); - wxFont * Result = new wxFont(This->GetLabelFont()); newPtr((void *) Result,3, memenv);; + wxFont * Result = new EwxFont(This->GetLabelFont()); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxFont"); break; } @@ -5856,6 +5897,7 @@ case wxScreenDC_new: { // wxScreenDC::wxScreenDC rt.addRef(getRef((void *)Result,memenv), "wxScreenDC"); break; } +#if wxUSE_POSTSCRIPT case wxPostScriptDC_new_0: { // wxPostScriptDC::wxPostScriptDC wxPostScriptDC * Result = new EwxPostScriptDC(); newPtr((void *) Result, 4, memenv); @@ -5883,6 +5925,7 @@ case wxPostScriptDC_GetResolution: { // wxPostScriptDC::GetResolution break; } #endif +#endif // wxUSE_POSTSCRIPT #if !wxCHECK_VERSION(2,9,0) case wxWindowDC_new_0: { // wxWindowDC::wxWindowDC wxWindowDC * Result = new EwxWindowDC(); @@ -8514,6 +8557,25 @@ data = (wxObject *) getPtr(bp,memenv); bp += 4; rt.addRef(getRef((void *)Result,memenv), "wx"); break; } +#if wxCHECK_VERSION(3,0,0) +case wxToolBar_AddStretchableSpace: { // wxToolBar::AddStretchableSpace + wxToolBar *This = (wxToolBar *) getPtr(bp,memenv); bp += 4; + if(!This) throw wxe_badarg(0); + wxToolBarToolBase * Result = (wxToolBarToolBase*)This->AddStretchableSpace(); + rt.addRef(getRef((void *)Result,memenv), "wx"); + break; +} +#endif +#if wxCHECK_VERSION(3,0,0) +case wxToolBar_InsertStretchableSpace: { // wxToolBar::InsertStretchableSpace + wxToolBar *This = (wxToolBar *) getPtr(bp,memenv); bp += 4; + int * pos = (int *) bp; bp += 4; + if(!This) throw wxe_badarg(0); + wxToolBarToolBase * Result = (wxToolBarToolBase*)This->InsertStretchableSpace(*pos); + rt.addRef(getRef((void *)Result,memenv), "wx"); + break; +} +#endif case wxToolBar_DeleteTool: { // wxToolBar::DeleteTool wxToolBar *This = (wxToolBar *) getPtr(bp,memenv); bp += 4; int * toolid = (int *) bp; bp += 4; @@ -9036,7 +9098,7 @@ case wxBitmap_new_2_1: { // wxBitmap::wxBitmap case wxBitmap_ConvertToImage: { // wxBitmap::ConvertToImage wxBitmap *This = (wxBitmap *) getPtr(bp,memenv); bp += 4; if(!This) throw wxe_badarg(0); - wxImage * Result = new wxImage(This->ConvertToImage()); newPtr((void *) Result,3, memenv);; + wxImage * Result = new EwxImage(This->ConvertToImage()); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxImage"); break; } @@ -9107,7 +9169,7 @@ case wxBitmap_GetSubBitmap: { // wxBitmap::GetSubBitmap int * rectH = (int *) bp; bp += 4; wxRect rect = wxRect(*rectX,*rectY,*rectW,*rectH); if(!This) throw wxe_badarg(0); - wxBitmap * Result = new wxBitmap(This->GetSubBitmap(rect)); newPtr((void *) Result,3, memenv);; + wxBitmap * Result = new EwxBitmap(This->GetSubBitmap(rect)); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxBitmap"); break; } @@ -9289,7 +9351,7 @@ case wxIconBundle_GetIcon_1_1: { // wxIconBundle::GetIcon int * sizeH = (int *) bp; bp += 4; wxSize size = wxSize(*sizeW,*sizeH); if(!This) throw wxe_badarg(0); - const wxIcon * Result = new wxIcon(This->GetIcon(size)); newPtr((void *) Result,3, memenv);; + const wxIcon * Result = new EwxIcon(This->GetIcon(size)); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxIcon"); break; } @@ -9303,7 +9365,7 @@ case wxIconBundle_GetIcon_1_0: { // wxIconBundle::GetIcon } break; }}; if(!This) throw wxe_badarg(0); - const wxIcon * Result = new wxIcon(This->GetIcon(size)); newPtr((void *) Result,3, memenv);; + const wxIcon * Result = new EwxIcon(This->GetIcon(size)); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxIcon"); break; } @@ -9512,7 +9574,7 @@ case wxImage_Blur: { // wxImage::Blur wxImage *This = (wxImage *) getPtr(bp,memenv); bp += 4; int * radius = (int *) bp; bp += 4; if(!This) throw wxe_badarg(0); - wxImage * Result = new wxImage(This->Blur(*radius)); newPtr((void *) Result,3, memenv);; + wxImage * Result = new EwxImage(This->Blur(*radius)); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxImage"); break; } @@ -9520,7 +9582,7 @@ case wxImage_BlurHorizontal: { // wxImage::BlurHorizontal wxImage *This = (wxImage *) getPtr(bp,memenv); bp += 4; int * radius = (int *) bp; bp += 4; if(!This) throw wxe_badarg(0); - wxImage * Result = new wxImage(This->BlurHorizontal(*radius)); newPtr((void *) Result,3, memenv);; + wxImage * Result = new EwxImage(This->BlurHorizontal(*radius)); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxImage"); break; } @@ -9528,7 +9590,7 @@ case wxImage_BlurVertical: { // wxImage::BlurVertical wxImage *This = (wxImage *) getPtr(bp,memenv); bp += 4; int * radius = (int *) bp; bp += 4; if(!This) throw wxe_badarg(0); - wxImage * Result = new wxImage(This->BlurVertical(*radius)); newPtr((void *) Result,3, memenv);; + wxImage * Result = new EwxImage(This->BlurVertical(*radius)); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxImage"); break; } @@ -9567,7 +9629,7 @@ case wxImage_ConvertToGreyscale: { // wxImage::ConvertToGreyscale } break; }}; if(!This) throw wxe_badarg(0); - wxImage * Result = new wxImage(This->ConvertToGreyscale(lr,lg,lb)); newPtr((void *) Result,3, memenv);; + wxImage * Result = new EwxImage(This->ConvertToGreyscale(lr,lg,lb)); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxImage"); break; } @@ -9577,14 +9639,14 @@ case wxImage_ConvertToMono: { // wxImage::ConvertToMono unsigned int * g = (unsigned int *) bp; bp += 4; unsigned int * b = (unsigned int *) bp; bp += 4; if(!This) throw wxe_badarg(0); - wxImage * Result = new wxImage(This->ConvertToMono(*r,*g,*b)); newPtr((void *) Result,3, memenv);; + wxImage * Result = new EwxImage(This->ConvertToMono(*r,*g,*b)); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxImage"); break; } case wxImage_Copy: { // wxImage::Copy wxImage *This = (wxImage *) getPtr(bp,memenv); bp += 4; if(!This) throw wxe_badarg(0); - wxImage * Result = new wxImage(This->Copy()); newPtr((void *) Result,3, memenv);; + wxImage * Result = new EwxImage(This->Copy()); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxImage"); break; } @@ -9806,7 +9868,7 @@ case wxImage_GetSubImage: { // wxImage::GetSubImage int * rectH = (int *) bp; bp += 4; wxRect rect = wxRect(*rectX,*rectY,*rectW,*rectH); if(!This) throw wxe_badarg(0); - wxImage * Result = new wxImage(This->GetSubImage(rect)); newPtr((void *) Result,3, memenv);; + wxImage * Result = new EwxImage(This->GetSubImage(rect)); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxImage"); break; } @@ -9951,7 +10013,7 @@ case wxImage_Mirror: { // wxImage::Mirror } break; }}; if(!This) throw wxe_badarg(0); - wxImage * Result = new wxImage(This->Mirror(horizontally)); newPtr((void *) Result,3, memenv);; + wxImage * Result = new EwxImage(This->Mirror(horizontally)); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxImage"); break; } @@ -10032,7 +10094,7 @@ case wxImage_Rotate: { // wxImage::Rotate } break; }}; if(!This) throw wxe_badarg(0); - wxImage * Result = new wxImage(This->Rotate(*angle,centre_of_rotation,interpolating,offset_after_rotation)); newPtr((void *) Result,3, memenv);; + wxImage * Result = new EwxImage(This->Rotate(*angle,centre_of_rotation,interpolating,offset_after_rotation)); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxImage"); break; } @@ -10054,7 +10116,7 @@ case wxImage_Rotate90: { // wxImage::Rotate90 } break; }}; if(!This) throw wxe_badarg(0); - wxImage * Result = new wxImage(This->Rotate90(clockwise)); newPtr((void *) Result,3, memenv);; + wxImage * Result = new EwxImage(This->Rotate90(clockwise)); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxImage"); break; } @@ -10104,7 +10166,7 @@ quality = *(wxImageResizeQuality *) bp; bp += 4;; } break; }}; if(!This) throw wxe_badarg(0); - wxImage * Result = new wxImage(This->Scale(*width,*height,quality)); newPtr((void *) Result,3, memenv);; + wxImage * Result = new EwxImage(This->Scale(*width,*height,quality)); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxImage"); break; } @@ -10132,7 +10194,7 @@ case wxImage_Size: { // wxImage::Size } break; }}; if(!This) throw wxe_badarg(0); - wxImage * Result = new wxImage(This->Size(size,pos,r,g,b)); newPtr((void *) Result,3, memenv);; + wxImage * Result = new EwxImage(This->Size(size,pos,r,g,b)); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxImage"); break; } @@ -10592,7 +10654,7 @@ case wxRegion_Contains_1_1: { // wxRegion::Contains case wxRegion_ConvertToBitmap: { // wxRegion::ConvertToBitmap wxRegion *This = (wxRegion *) getPtr(bp,memenv); bp += 4; if(!This) throw wxe_badarg(0); - wxBitmap * Result = new wxBitmap(This->ConvertToBitmap()); newPtr((void *) Result,3, memenv);; + wxBitmap * Result = new EwxBitmap(This->ConvertToBitmap()); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxBitmap"); break; } @@ -13319,28 +13381,28 @@ validator = (wxValidator *) getPtr(bp,memenv); bp += 4; case wxBitmapButton_GetBitmapDisabled: { // wxBitmapButton::GetBitmapDisabled wxBitmapButton *This = (wxBitmapButton *) getPtr(bp,memenv); bp += 4; if(!This) throw wxe_badarg(0); - const wxBitmap * Result = new wxBitmap(This->GetBitmapDisabled()); newPtr((void *) Result,3, memenv);; + const wxBitmap * Result = new EwxBitmap(This->GetBitmapDisabled()); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxBitmap"); break; } case wxBitmapButton_GetBitmapFocus: { // wxBitmapButton::GetBitmapFocus wxBitmapButton *This = (wxBitmapButton *) getPtr(bp,memenv); bp += 4; if(!This) throw wxe_badarg(0); - const wxBitmap * Result = new wxBitmap(This->GetBitmapFocus()); newPtr((void *) Result,3, memenv);; + const wxBitmap * Result = new EwxBitmap(This->GetBitmapFocus()); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxBitmap"); break; } case wxBitmapButton_GetBitmapLabel: { // wxBitmapButton::GetBitmapLabel wxBitmapButton *This = (wxBitmapButton *) getPtr(bp,memenv); bp += 4; if(!This) throw wxe_badarg(0); - const wxBitmap * Result = new wxBitmap(This->GetBitmapLabel()); newPtr((void *) Result,3, memenv);; + const wxBitmap * Result = new EwxBitmap(This->GetBitmapLabel()); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxBitmap"); break; } case wxBitmapButton_GetBitmapSelected: { // wxBitmapButton::GetBitmapSelected wxBitmapButton *This = (wxBitmapButton *) getPtr(bp,memenv); bp += 4; if(!This) throw wxe_badarg(0); - const wxBitmap * Result = new wxBitmap(This->GetBitmapSelected()); newPtr((void *) Result,3, memenv);; + const wxBitmap * Result = new EwxBitmap(This->GetBitmapSelected()); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxBitmap"); break; } @@ -15458,7 +15520,7 @@ case wxListCtrl_GetItemFont: { // wxListCtrl::GetItemFont wxListCtrl *This = (wxListCtrl *) getPtr(bp,memenv); bp += 4; int * item = (int *) bp; bp += 4; if(!This) throw wxe_badarg(0); - wxFont * Result = new wxFont(This->GetItemFont(*item)); newPtr((void *) Result,3, memenv);; + wxFont * Result = new EwxFont(This->GetItemFont(*item)); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxFont"); break; } @@ -16004,7 +16066,7 @@ case wxListItem_GetColumn: { // wxListItem::GetColumn case wxListItem_GetFont: { // wxListItem::GetFont wxListItem *This = (wxListItem *) getPtr(bp,memenv); bp += 4; if(!This) throw wxe_badarg(0); - wxFont * Result = new wxFont(This->GetFont()); newPtr((void *) Result,3, memenv);; + wxFont * Result = new EwxFont(This->GetFont()); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxFont"); break; } @@ -16351,7 +16413,7 @@ case wxImageList_GetBitmap: { // wxImageList::GetBitmap wxImageList *This = (wxImageList *) getPtr(bp,memenv); bp += 4; int * index = (int *) bp; bp += 4; if(!This) throw wxe_badarg(0); - wxBitmap * Result = new wxBitmap(This->GetBitmap(*index)); newPtr((void *) Result,3, memenv);; + wxBitmap * Result = new EwxBitmap(This->GetBitmap(*index)); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxBitmap"); break; } @@ -16359,7 +16421,7 @@ case wxImageList_GetIcon: { // wxImageList::GetIcon wxImageList *This = (wxImageList *) getPtr(bp,memenv); bp += 4; int * index = (int *) bp; bp += 4; if(!This) throw wxe_badarg(0); - wxIcon * Result = new wxIcon(This->GetIcon(*index)); newPtr((void *) Result,3, memenv);; + wxIcon * Result = new EwxIcon(This->GetIcon(*index)); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxIcon"); break; } @@ -16470,7 +16532,7 @@ case wxTextAttr_GetBackgroundColour: { // wxTextAttr::GetBackgroundColour case wxTextAttr_GetFont: { // wxTextAttr::GetFont wxTextAttr *This = (wxTextAttr *) getPtr(bp,memenv); bp += 4; if(!This) throw wxe_badarg(0); - const wxFont * Result = new wxFont(This->GetFont()); newPtr((void *) Result,3, memenv);; + const wxFont * Result = new EwxFont(This->GetFont()); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxFont"); break; } @@ -18816,7 +18878,7 @@ case wxTreeCtrl_GetItemFont: { // wxTreeCtrl::GetItemFont bp += 4; /* Align */ wxTreeItemId item = wxTreeItemId((void *) *(wxUint64 *) bp); bp += 8; if(!This) throw wxe_badarg(0); - wxFont * Result = new wxFont(This->GetItemFont(item)); newPtr((void *) Result,3, memenv);; + wxFont * Result = new EwxFont(This->GetItemFont(item)); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxFont"); break; } @@ -19843,7 +19905,7 @@ case wxStaticBitmap_Create: { // wxStaticBitmap::Create case wxStaticBitmap_GetBitmap: { // wxStaticBitmap::GetBitmap wxStaticBitmap *This = (wxStaticBitmap *) getPtr(bp,memenv); bp += 4; if(!This) throw wxe_badarg(0); - wxBitmap * Result = new wxBitmap(This->GetBitmap()); newPtr((void *) Result,3, memenv);; + wxBitmap * Result = new EwxBitmap(This->GetBitmap()); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxBitmap"); break; } @@ -21533,7 +21595,7 @@ validator = (wxValidator *) getPtr(bp,memenv); bp += 4; case wxFontPickerCtrl_GetSelectedFont: { // wxFontPickerCtrl::GetSelectedFont wxFontPickerCtrl *This = (wxFontPickerCtrl *) getPtr(bp,memenv); bp += 4; if(!This) throw wxe_badarg(0); - wxFont * Result = new wxFont(This->GetSelectedFont()); newPtr((void *) Result,3, memenv);; + wxFont * Result = new EwxFont(This->GetSelectedFont()); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxFont"); break; } @@ -21911,7 +21973,7 @@ case wxFontData_GetColour: { // wxFontData::GetColour case wxFontData_GetChosenFont: { // wxFontData::GetChosenFont wxFontData *This = (wxFontData *) getPtr(bp,memenv); bp += 4; if(!This) throw wxe_badarg(0); - wxFont * Result = new wxFont(This->GetChosenFont()); newPtr((void *) Result,3, memenv);; + wxFont * Result = new EwxFont(This->GetChosenFont()); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxFont"); break; } @@ -21925,7 +21987,7 @@ case wxFontData_GetEnableEffects: { // wxFontData::GetEnableEffects case wxFontData_GetInitialFont: { // wxFontData::GetInitialFont wxFontData *This = (wxFontData *) getPtr(bp,memenv); bp += 4; if(!This) throw wxe_badarg(0); - wxFont * Result = new wxFont(This->GetInitialFont()); newPtr((void *) Result,3, memenv);; + wxFont * Result = new EwxFont(This->GetInitialFont()); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxFont"); break; } @@ -23208,7 +23270,7 @@ case wxXmlResource_LoadBitmap: { // wxXmlResource::LoadBitmap wxString name = wxString(bp, wxConvUTF8); bp += *nameLen+((8-((0+ *nameLen) & 7)) & 7); if(!This) throw wxe_badarg(0); - wxBitmap * Result = new wxBitmap(This->LoadBitmap(name)); newPtr((void *) Result,3, memenv);; + wxBitmap * Result = new EwxBitmap(This->LoadBitmap(name)); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxBitmap"); break; } @@ -23264,7 +23326,7 @@ case wxXmlResource_LoadIcon: { // wxXmlResource::LoadIcon wxString name = wxString(bp, wxConvUTF8); bp += *nameLen+((8-((0+ *nameLen) & 7)) & 7); if(!This) throw wxe_badarg(0); - wxIcon * Result = new wxIcon(This->LoadIcon(name)); newPtr((void *) Result,3, memenv);; + wxIcon * Result = new EwxIcon(This->LoadIcon(name)); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxIcon"); break; } @@ -23735,8 +23797,11 @@ case wxAuiManager_DetachPane: { // wxAuiManager::DetachPane case wxAuiManager_GetAllPanes: { // wxAuiManager::GetAllPanes wxAuiManager *This = (wxAuiManager *) getPtr(bp,memenv); bp += 4; if(!This) throw wxe_badarg(0); - wxAuiPaneInfoArray * Result = &This->GetAllPanes(); - rt.addRef(getRef((void *)Result,memenv), "wxAuiPaneInfoArray"); + wxAuiPaneInfoArray Result = This->GetAllPanes(); + for(unsigned int i=0; i < Result.GetCount(); i++) { + rt.addRef(getRef((void *) &Result.Item(i), memenv), "wxAuiPaneInfo"); + } + rt.endList(Result.GetCount()); break; } case wxAuiManager_GetArtProvider: { // wxAuiManager::GetArtProvider @@ -24595,6 +24660,102 @@ case wxAuiPaneInfo_Window: { // wxAuiPaneInfo::Window rt.addRef(getRef((void *)Result,memenv), "wxAuiPaneInfo"); break; } +case wxAuiPaneInfo_GetWindow: { // wxAuiPaneInfo::GetWindow + wxAuiPaneInfo *This = (wxAuiPaneInfo *) getPtr(bp,memenv); bp += 4; + #if 0 +; + if(!This) throw wxe_badarg(0); + wxWindow * Result = (wxWindow*)This->GetWindow(); + #endif + if(!This) throw wxe_badarg(0); + wxWindow* Result = This->window; + rt.addRef(getRef((void *)Result,memenv), "wxWindow"); + break; +} +case wxAuiPaneInfo_GetFrame: { // wxAuiPaneInfo::GetFrame + wxAuiPaneInfo *This = (wxAuiPaneInfo *) getPtr(bp,memenv); bp += 4; + #if 0 +; + if(!This) throw wxe_badarg(0); + wxFrame * Result = (wxFrame*)This->GetFrame(); + #endif + if(!This) throw wxe_badarg(0); + wxFrame* Result = This->frame; + rt.addRef(getRef((void *)Result,memenv), "wxFrame"); + break; +} +case wxAuiPaneInfo_GetDirection: { // wxAuiPaneInfo::GetDirection + wxAuiPaneInfo *This = (wxAuiPaneInfo *) getPtr(bp,memenv); bp += 4; + #if 0 +; + if(!This) throw wxe_badarg(0); + int Result = This->GetDirection(); + #endif + if(!This) throw wxe_badarg(0); + int Result = This->dock_direction; + rt.addInt(Result); + break; +} +case wxAuiPaneInfo_GetLayer: { // wxAuiPaneInfo::GetLayer + wxAuiPaneInfo *This = (wxAuiPaneInfo *) getPtr(bp,memenv); bp += 4; + #if 0 +; + if(!This) throw wxe_badarg(0); + int Result = This->GetLayer(); + #endif + if(!This) throw wxe_badarg(0); + int Result = This->dock_layer; + rt.addInt(Result); + break; +} +case wxAuiPaneInfo_GetRow: { // wxAuiPaneInfo::GetRow + wxAuiPaneInfo *This = (wxAuiPaneInfo *) getPtr(bp,memenv); bp += 4; + #if 0 +; + if(!This) throw wxe_badarg(0); + int Result = This->GetRow(); + #endif + if(!This) throw wxe_badarg(0); + int Result = This->dock_row; + rt.addInt(Result); + break; +} +case wxAuiPaneInfo_GetPosition: { // wxAuiPaneInfo::GetPosition + wxAuiPaneInfo *This = (wxAuiPaneInfo *) getPtr(bp,memenv); bp += 4; + #if 0 +; + if(!This) throw wxe_badarg(0); + int Result = This->GetPosition(); + #endif + if(!This) throw wxe_badarg(0); + int Result = This->dock_pos; + rt.addInt(Result); + break; +} +case wxAuiPaneInfo_GetFloatingPosition: { // wxAuiPaneInfo::GetFloatingPosition + wxAuiPaneInfo *This = (wxAuiPaneInfo *) getPtr(bp,memenv); bp += 4; + #if 0 +; + if(!This) throw wxe_badarg(0); + wxPoint Result = This->GetFloatingPosition(); + #endif + if(!This) throw wxe_badarg(0); + wxPoint Result = This->floating_pos; + rt.add(Result); + break; +} +case wxAuiPaneInfo_GetFloatingSize: { // wxAuiPaneInfo::GetFloatingSize + wxAuiPaneInfo *This = (wxAuiPaneInfo *) getPtr(bp,memenv); bp += 4; + #if 0 +; + if(!This) throw wxe_badarg(0); + wxSize Result = This->GetFloatingSize(); + #endif + if(!This) throw wxe_badarg(0); + wxSize Result = This->floating_size; + rt.add(Result); + break; +} #endif // wxUSE_AUI #if wxUSE_AUI case wxAuiNotebook_new_0: { // wxAuiNotebook::wxAuiNotebook @@ -24715,7 +24876,7 @@ case wxAuiNotebook_GetPageBitmap: { // wxAuiNotebook::GetPageBitmap wxAuiNotebook *This = (wxAuiNotebook *) getPtr(bp,memenv); bp += 4; int * page_idx = (int *) bp; bp += 4; if(!This) throw wxe_badarg(0); - wxBitmap * Result = new wxBitmap(This->GetPageBitmap(*page_idx)); newPtr((void *) Result,3, memenv);; + wxBitmap * Result = new EwxBitmap(This->GetPageBitmap(*page_idx)); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxBitmap"); break; } @@ -24840,8 +25001,128 @@ case wxAuiNotebook_SetUniformBitmapSize: { // wxAuiNotebook::SetUniformBitmapSiz } #endif // wxUSE_AUI #if wxUSE_AUI +case wxAuiTabArt_SetFlags: { // wxAuiTabArt::SetFlags + wxAuiTabArt *This = (wxAuiTabArt *) getPtr(bp,memenv); bp += 4; + unsigned int * flags = (unsigned int *) bp; bp += 4; + if(!This) throw wxe_badarg(0); + This->SetFlags(*flags); + break; +} +case wxAuiTabArt_SetMeasuringFont: { // wxAuiTabArt::SetMeasuringFont + wxAuiTabArt *This = (wxAuiTabArt *) getPtr(bp,memenv); bp += 4; + wxFont *font = (wxFont *) getPtr(bp,memenv); bp += 4; + if(!This) throw wxe_badarg(0); + This->SetMeasuringFont(*font); + break; +} +case wxAuiTabArt_SetNormalFont: { // wxAuiTabArt::SetNormalFont + wxAuiTabArt *This = (wxAuiTabArt *) getPtr(bp,memenv); bp += 4; + wxFont *font = (wxFont *) getPtr(bp,memenv); bp += 4; + if(!This) throw wxe_badarg(0); + This->SetNormalFont(*font); + break; +} +case wxAuiTabArt_SetSelectedFont: { // wxAuiTabArt::SetSelectedFont + wxAuiTabArt *This = (wxAuiTabArt *) getPtr(bp,memenv); bp += 4; + wxFont *font = (wxFont *) getPtr(bp,memenv); bp += 4; + if(!This) throw wxe_badarg(0); + This->SetSelectedFont(*font); + break; +} +#if wxCHECK_VERSION(3,0,0) +case wxAuiTabArt_SetColour: { // wxAuiTabArt::SetColour + wxAuiTabArt *This = (wxAuiTabArt *) getPtr(bp,memenv); bp += 4; + int * colourR = (int *) bp; bp += 4; + int * colourG = (int *) bp; bp += 4; + int * colourB = (int *) bp; bp += 4; + int * colourA = (int *) bp; bp += 4; + wxColour colour = wxColour(*colourR,*colourG,*colourB,*colourA); + if(!This) throw wxe_badarg(0); + This->SetColour(colour); + break; +} +#endif +#if wxCHECK_VERSION(3,0,0) +case wxAuiTabArt_SetActiveColour: { // wxAuiTabArt::SetActiveColour + wxAuiTabArt *This = (wxAuiTabArt *) getPtr(bp,memenv); bp += 4; + int * colourR = (int *) bp; bp += 4; + int * colourG = (int *) bp; bp += 4; + int * colourB = (int *) bp; bp += 4; + int * colourA = (int *) bp; bp += 4; + wxColour colour = wxColour(*colourR,*colourG,*colourB,*colourA); + if(!This) throw wxe_badarg(0); + This->SetActiveColour(colour); + break; +} +#endif +#endif // wxUSE_AUI +#if wxUSE_AUI +case wxAuiDockArt_GetColour: { // wxAuiDockArt::GetColour + wxAuiDockArt *This = (wxAuiDockArt *) getPtr(bp,memenv); bp += 4; + int * id = (int *) bp; bp += 4; + if(!This) throw wxe_badarg(0); + wxColour Result = This->GetColour(*id); + rt.add(Result); + break; +} +case wxAuiDockArt_GetFont: { // wxAuiDockArt::GetFont + wxAuiDockArt *This = (wxAuiDockArt *) getPtr(bp,memenv); bp += 4; + int * id = (int *) bp; bp += 4; + if(!This) throw wxe_badarg(0); + wxFont * Result = new EwxFont(This->GetFont(*id)); newPtr((void *) Result,3, memenv);; + rt.addRef(getRef((void *)Result,memenv), "wxFont"); + break; +} +case wxAuiDockArt_GetMetric: { // wxAuiDockArt::GetMetric + wxAuiDockArt *This = (wxAuiDockArt *) getPtr(bp,memenv); bp += 4; + int * id = (int *) bp; bp += 4; + if(!This) throw wxe_badarg(0); + int Result = This->GetMetric(*id); + rt.addInt(Result); + break; +} +case wxAuiDockArt_SetColour: { // wxAuiDockArt::SetColour + wxAuiDockArt *This = (wxAuiDockArt *) getPtr(bp,memenv); bp += 4; + int * id = (int *) bp; bp += 4; + int * colourR = (int *) bp; bp += 4; + int * colourG = (int *) bp; bp += 4; + int * colourB = (int *) bp; bp += 4; + int * colourA = (int *) bp; bp += 4; + wxColour colour = wxColour(*colourR,*colourG,*colourB,*colourA); + if(!This) throw wxe_badarg(0); + This->SetColour(*id,colour); + break; +} +case wxAuiDockArt_SetFont: { // wxAuiDockArt::SetFont + wxAuiDockArt *This = (wxAuiDockArt *) getPtr(bp,memenv); bp += 4; + int * id = (int *) bp; bp += 4; + wxFont *font = (wxFont *) getPtr(bp,memenv); bp += 4; + if(!This) throw wxe_badarg(0); + This->SetFont(*id,*font); + break; +} +case wxAuiDockArt_SetMetric: { // wxAuiDockArt::SetMetric + wxAuiDockArt *This = (wxAuiDockArt *) getPtr(bp,memenv); bp += 4; + int * id = (int *) bp; bp += 4; + int * new_val = (int *) bp; bp += 4; + if(!This) throw wxe_badarg(0); + This->SetMetric(*id,*new_val); + break; +} #endif // wxUSE_AUI #if wxUSE_AUI +case wxAuiSimpleTabArt_new: { // wxAuiSimpleTabArt::wxAuiSimpleTabArt + wxAuiSimpleTabArt * Result = new wxAuiSimpleTabArt(); + newPtr((void *) Result, 159, memenv); + rt.addRef(getRef((void *)Result,memenv), "wxAuiSimpleTabArt"); + break; +} +case wxAuiSimpleTabArt_destroy: { // wxAuiSimpleTabArt::destroy + wxAuiSimpleTabArt *This = (wxAuiSimpleTabArt *) getPtr(bp,memenv); bp += 4; + if(This) { ((WxeApp *) wxTheApp)->clearPtr((void *) This); + delete This;} + break; +} #endif // wxUSE_AUI case wxMDIParentFrame_new_0: { // wxMDIParentFrame::wxMDIParentFrame wxMDIParentFrame * Result = new EwxMDIParentFrame(); @@ -26427,7 +26708,7 @@ case wxColourPickerEvent_GetColour: { // wxColourPickerEvent::GetColour case wxFontPickerEvent_GetFont: { // wxFontPickerEvent::GetFont wxFontPickerEvent *This = (wxFontPickerEvent *) getPtr(bp,memenv); bp += 4; if(!This) throw wxe_badarg(0); - wxFont * Result = new wxFont(This->GetFont()); newPtr((void *) Result,3, memenv);; + wxFont * Result = new EwxFont(This->GetFont()); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxFont"); break; } @@ -30358,7 +30639,7 @@ case wxArtProvider_GetBitmap: { // wxArtProvider::GetBitmap bp += 4; /* Align */ } break; }}; - wxBitmap * Result = new wxBitmap(wxArtProvider::GetBitmap(id,client,size)); newPtr((void *) Result,3, memenv);; + wxBitmap * Result = new EwxBitmap(wxArtProvider::GetBitmap(id,client,size)); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxBitmap"); break; } @@ -30381,7 +30662,7 @@ case wxArtProvider_GetIcon: { // wxArtProvider::GetIcon bp += 4; /* Align */ } break; }}; - wxIcon * Result = new wxIcon(wxArtProvider::GetIcon(id,client,size)); newPtr((void *) Result,3, memenv);; + wxIcon * Result = new EwxIcon(wxArtProvider::GetIcon(id,client,size)); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxIcon"); break; } @@ -30473,7 +30754,7 @@ case wxNotebookEvent_SetSelection: { // wxNotebookEvent::SetSelection } case wxFileDataObject_new: { // wxFileDataObject::wxFileDataObject wxFileDataObject * Result = new wxFileDataObject(); - newPtr((void *) Result, 212, memenv); + newPtr((void *) Result, 213, memenv); rt.addRef(getRef((void *)Result,memenv), "wxFileDataObject"); break; } @@ -30509,7 +30790,7 @@ case wxTextDataObject_new: { // wxTextDataObject::wxTextDataObject } break; }}; wxTextDataObject * Result = new wxTextDataObject(text); - newPtr((void *) Result, 213, memenv); + newPtr((void *) Result, 214, memenv); rt.addRef(getRef((void *)Result,memenv), "wxTextDataObject"); break; } @@ -30545,7 +30826,7 @@ case wxTextDataObject_destroy: { // wxTextDataObject::destroy case wxBitmapDataObject_new_1_1: { // wxBitmapDataObject::wxBitmapDataObject wxBitmap *bitmap = (wxBitmap *) getPtr(bp,memenv); bp += 4; wxBitmapDataObject * Result = new wxBitmapDataObject(*bitmap); - newPtr((void *) Result, 214, memenv); + newPtr((void *) Result, 215, memenv); rt.addRef(getRef((void *)Result,memenv), "wxBitmapDataObject"); break; } @@ -30557,14 +30838,14 @@ bitmap = (wxBitmap *) getPtr(bp,memenv); bp += 4; } break; }}; wxBitmapDataObject * Result = new wxBitmapDataObject(*bitmap); - newPtr((void *) Result, 214, memenv); + newPtr((void *) Result, 215, memenv); rt.addRef(getRef((void *)Result,memenv), "wxBitmapDataObject"); break; } case wxBitmapDataObject_GetBitmap: { // wxBitmapDataObject::GetBitmap wxBitmapDataObject *This = (wxBitmapDataObject *) getPtr(bp,memenv); bp += 4; if(!This) throw wxe_badarg(0); - wxBitmap * Result = new wxBitmap(This->GetBitmap()); newPtr((void *) Result,3, memenv);; + wxBitmap * Result = new EwxBitmap(This->GetBitmap()); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxBitmap"); break; } @@ -31184,7 +31465,7 @@ case wxSystemSettings_GetColour: { // wxSystemSettings::GetColour } case wxSystemSettings_GetFont: { // wxSystemSettings::GetFont wxSystemFont index = *(wxSystemFont *) bp; bp += 4;; - wxFont * Result = new wxFont(wxSystemSettings::GetFont(index)); newPtr((void *) Result,3, memenv);; + wxFont * Result = new EwxFont(wxSystemSettings::GetFont(index)); newPtr((void *) Result,3, memenv);; rt.addRef(getRef((void *)Result,memenv), "wxFont"); break; } @@ -31390,7 +31671,7 @@ case wxAuiManagerEvent_CanVeto: { // wxAuiManagerEvent::CanVeto } case wxLogNull_new: { // wxLogNull::wxLogNull wxLogNull * Result = new wxLogNull(); - newPtr((void *) Result, 226, memenv); + newPtr((void *) Result, 227, memenv); rt.addRef(getRef((void *)Result,memenv), "wxLogNull"); break; } @@ -31439,7 +31720,7 @@ case wxTaskBarIcon_SetIcon: { // wxTaskBarIcon::SetIcon } case wxLocale_new_0: { // wxLocale::wxLocale wxLocale * Result = new EwxLocale(); - newPtr((void *) Result, 230, memenv); + newPtr((void *) Result, 231, memenv); rt.addRef(getRef((void *)Result,memenv), "wxLocale"); break; } @@ -31453,7 +31734,7 @@ case wxLocale_new_2: { // wxLocale::wxLocale } break; }}; wxLocale * Result = new EwxLocale(*language,flags); - newPtr((void *) Result, 230, memenv); + newPtr((void *) Result, 231, memenv); rt.addRef(getRef((void *)Result,memenv), "wxLocale"); break; } @@ -31740,6 +32021,56 @@ case wxPopupTransientWindow_Dismiss: { // wxPopupTransientWindow::Dismiss break; } #endif // wxUSE_POPUPWIN +case wxOverlay_new: { // wxOverlay::wxOverlay + wxOverlay * Result = new wxOverlay(); + newPtr((void *) Result, 236, memenv); + rt.addRef(getRef((void *)Result,memenv), "wxOverlay"); + break; +} +case wxOverlay_destruct: { // wxOverlay::~wxOverlay + wxOverlay *This = (wxOverlay *) getPtr(bp,memenv); bp += 4; + if(This) { ((WxeApp *) wxTheApp)->clearPtr((void *) This); + delete This;} + break; +} +case wxOverlay_Reset: { // wxOverlay::Reset + wxOverlay *This = (wxOverlay *) getPtr(bp,memenv); bp += 4; + if(!This) throw wxe_badarg(0); + This->Reset(); + break; +} +case wxDCOverlay_new_6: { // wxDCOverlay::wxDCOverlay + wxOverlay *overlay = (wxOverlay *) getPtr(bp,memenv); bp += 4; + wxWindowDC *dc = (wxWindowDC *) getPtr(bp,memenv); bp += 4; + int * x = (int *) bp; bp += 4; + int * y = (int *) bp; bp += 4; + int * width = (int *) bp; bp += 4; + int * height = (int *) bp; bp += 4; + wxDCOverlay * Result = new EwxDCOverlay(*overlay,dc,*x,*y,*width,*height); + newPtr((void *) Result, 237, memenv); + rt.addRef(getRef((void *)Result,memenv), "wxDCOverlay"); + break; +} +case wxDCOverlay_new_2: { // wxDCOverlay::wxDCOverlay + wxOverlay *overlay = (wxOverlay *) getPtr(bp,memenv); bp += 4; + wxWindowDC *dc = (wxWindowDC *) getPtr(bp,memenv); bp += 4; + wxDCOverlay * Result = new EwxDCOverlay(*overlay,dc); + newPtr((void *) Result, 237, memenv); + rt.addRef(getRef((void *)Result,memenv), "wxDCOverlay"); + break; +} +case wxDCOverlay_destruct: { // wxDCOverlay::~wxDCOverlay + wxDCOverlay *This = (wxDCOverlay *) getPtr(bp,memenv); bp += 4; + if(This) { ((WxeApp *) wxTheApp)->clearPtr((void *) This); + delete This;} + break; +} +case wxDCOverlay_Clear: { // wxDCOverlay::Clear + wxDCOverlay *This = (wxDCOverlay *) getPtr(bp,memenv); bp += 4; + if(!This) throw wxe_badarg(0); + This->Clear(); + break; +} default: { wxeReturn error = wxeReturn(WXE_DRV_PORT, Ecmd.caller, false); error.addAtom("_wxe_error_"); error.addInt((int) Ecmd.op); @@ -31780,11 +32111,14 @@ bool WxeApp::delete_object(void *ptr, wxeRefData *refd) { case 101: delete (wxListItemAttr *) ptr; break; case 103: delete (wxTextAttr *) ptr; break; case 155: delete (wxAuiPaneInfo *) ptr; break; - case 212: /* delete (wxFileDataObject *) ptr;These objects must be deleted by owner object */ break; - case 213: /* delete (wxTextDataObject *) ptr;These objects must be deleted by owner object */ break; - case 214: /* delete (wxBitmapDataObject *) ptr;These objects must be deleted by owner object */ break; - case 226: delete (wxLogNull *) ptr; break; - case 230: delete (EwxLocale *) ptr; return false; + case 159: /* delete (wxAuiSimpleTabArt *) ptr;These objects must be deleted by owner object */ break; + case 213: /* delete (wxFileDataObject *) ptr;These objects must be deleted by owner object */ break; + case 214: /* delete (wxTextDataObject *) ptr;These objects must be deleted by owner object */ break; + case 215: /* delete (wxBitmapDataObject *) ptr;These objects must be deleted by owner object */ break; + case 227: delete (wxLogNull *) ptr; break; + case 231: delete (EwxLocale *) ptr; return false; + case 236: delete (wxOverlay *) ptr; break; + case 237: delete (EwxDCOverlay *) ptr; return false; default: delete (wxObject *) ptr; return false; } return true; diff --git a/lib/wx/c_src/gen/wxe_init.cpp b/lib/wx/c_src/gen/wxe_init.cpp index fd729accc9..1e432e34ce 100644 --- a/lib/wx/c_src/gen/wxe_init.cpp +++ b/lib/wx/c_src/gen/wxe_init.cpp @@ -57,6 +57,472 @@ void WxeApp::init_nonconsts(wxeMemEnv *memenv, ErlDrvTermData caller) { rt.addTupleCount(2); rt.addAtom("wxMOD_CMD"); rt.addInt(wxMOD_CMD); rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ABKHAZIAN"); rt.addInt(wxLANGUAGE_ABKHAZIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_AFAR"); rt.addInt(wxLANGUAGE_AFAR); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_AFRIKAANS"); rt.addInt(wxLANGUAGE_AFRIKAANS); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ALBANIAN"); rt.addInt(wxLANGUAGE_ALBANIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_AMHARIC"); rt.addInt(wxLANGUAGE_AMHARIC); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ARABIC"); rt.addInt(wxLANGUAGE_ARABIC); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ARABIC_ALGERIA"); rt.addInt(wxLANGUAGE_ARABIC_ALGERIA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ARABIC_BAHRAIN"); rt.addInt(wxLANGUAGE_ARABIC_BAHRAIN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ARABIC_EGYPT"); rt.addInt(wxLANGUAGE_ARABIC_EGYPT); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ARABIC_IRAQ"); rt.addInt(wxLANGUAGE_ARABIC_IRAQ); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ARABIC_JORDAN"); rt.addInt(wxLANGUAGE_ARABIC_JORDAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ARABIC_KUWAIT"); rt.addInt(wxLANGUAGE_ARABIC_KUWAIT); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ARABIC_LEBANON"); rt.addInt(wxLANGUAGE_ARABIC_LEBANON); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ARABIC_LIBYA"); rt.addInt(wxLANGUAGE_ARABIC_LIBYA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ARABIC_MOROCCO"); rt.addInt(wxLANGUAGE_ARABIC_MOROCCO); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ARABIC_OMAN"); rt.addInt(wxLANGUAGE_ARABIC_OMAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ARABIC_QATAR"); rt.addInt(wxLANGUAGE_ARABIC_QATAR); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ARABIC_SAUDI_ARABIA"); rt.addInt(wxLANGUAGE_ARABIC_SAUDI_ARABIA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ARABIC_SUDAN"); rt.addInt(wxLANGUAGE_ARABIC_SUDAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ARABIC_SYRIA"); rt.addInt(wxLANGUAGE_ARABIC_SYRIA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ARABIC_TUNISIA"); rt.addInt(wxLANGUAGE_ARABIC_TUNISIA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ARABIC_UAE"); rt.addInt(wxLANGUAGE_ARABIC_UAE); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ARABIC_YEMEN"); rt.addInt(wxLANGUAGE_ARABIC_YEMEN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ARMENIAN"); rt.addInt(wxLANGUAGE_ARMENIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ASSAMESE"); rt.addInt(wxLANGUAGE_ASSAMESE); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_AYMARA"); rt.addInt(wxLANGUAGE_AYMARA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_AZERI"); rt.addInt(wxLANGUAGE_AZERI); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_AZERI_CYRILLIC"); rt.addInt(wxLANGUAGE_AZERI_CYRILLIC); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_AZERI_LATIN"); rt.addInt(wxLANGUAGE_AZERI_LATIN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_BASHKIR"); rt.addInt(wxLANGUAGE_BASHKIR); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_BASQUE"); rt.addInt(wxLANGUAGE_BASQUE); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_BELARUSIAN"); rt.addInt(wxLANGUAGE_BELARUSIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_BENGALI"); rt.addInt(wxLANGUAGE_BENGALI); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_BHUTANI"); rt.addInt(wxLANGUAGE_BHUTANI); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_BIHARI"); rt.addInt(wxLANGUAGE_BIHARI); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_BISLAMA"); rt.addInt(wxLANGUAGE_BISLAMA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_BRETON"); rt.addInt(wxLANGUAGE_BRETON); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_BULGARIAN"); rt.addInt(wxLANGUAGE_BULGARIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_BURMESE"); rt.addInt(wxLANGUAGE_BURMESE); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_CAMBODIAN"); rt.addInt(wxLANGUAGE_CAMBODIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_CATALAN"); rt.addInt(wxLANGUAGE_CATALAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_CHINESE"); rt.addInt(wxLANGUAGE_CHINESE); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_CHINESE_HONGKONG"); rt.addInt(wxLANGUAGE_CHINESE_HONGKONG); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_CHINESE_MACAU"); rt.addInt(wxLANGUAGE_CHINESE_MACAU); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_CHINESE_SIMPLIFIED"); rt.addInt(wxLANGUAGE_CHINESE_SIMPLIFIED); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_CHINESE_SINGAPORE"); rt.addInt(wxLANGUAGE_CHINESE_SINGAPORE); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_CHINESE_TAIWAN"); rt.addInt(wxLANGUAGE_CHINESE_TAIWAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_CHINESE_TRADITIONAL"); rt.addInt(wxLANGUAGE_CHINESE_TRADITIONAL); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_CORSICAN"); rt.addInt(wxLANGUAGE_CORSICAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_CROATIAN"); rt.addInt(wxLANGUAGE_CROATIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_CZECH"); rt.addInt(wxLANGUAGE_CZECH); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_DANISH"); rt.addInt(wxLANGUAGE_DANISH); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_DEFAULT"); rt.addInt(wxLANGUAGE_DEFAULT); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_DUTCH"); rt.addInt(wxLANGUAGE_DUTCH); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_DUTCH_BELGIAN"); rt.addInt(wxLANGUAGE_DUTCH_BELGIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ENGLISH"); rt.addInt(wxLANGUAGE_ENGLISH); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ENGLISH_AUSTRALIA"); rt.addInt(wxLANGUAGE_ENGLISH_AUSTRALIA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ENGLISH_BELIZE"); rt.addInt(wxLANGUAGE_ENGLISH_BELIZE); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ENGLISH_BOTSWANA"); rt.addInt(wxLANGUAGE_ENGLISH_BOTSWANA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ENGLISH_CANADA"); rt.addInt(wxLANGUAGE_ENGLISH_CANADA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ENGLISH_CARIBBEAN"); rt.addInt(wxLANGUAGE_ENGLISH_CARIBBEAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ENGLISH_DENMARK"); rt.addInt(wxLANGUAGE_ENGLISH_DENMARK); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ENGLISH_EIRE"); rt.addInt(wxLANGUAGE_ENGLISH_EIRE); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ENGLISH_JAMAICA"); rt.addInt(wxLANGUAGE_ENGLISH_JAMAICA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ENGLISH_NEW_ZEALAND"); rt.addInt(wxLANGUAGE_ENGLISH_NEW_ZEALAND); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ENGLISH_PHILIPPINES"); rt.addInt(wxLANGUAGE_ENGLISH_PHILIPPINES); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ENGLISH_SOUTH_AFRICA"); rt.addInt(wxLANGUAGE_ENGLISH_SOUTH_AFRICA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ENGLISH_TRINIDAD"); rt.addInt(wxLANGUAGE_ENGLISH_TRINIDAD); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ENGLISH_UK"); rt.addInt(wxLANGUAGE_ENGLISH_UK); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ENGLISH_US"); rt.addInt(wxLANGUAGE_ENGLISH_US); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ENGLISH_ZIMBABWE"); rt.addInt(wxLANGUAGE_ENGLISH_ZIMBABWE); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ESPERANTO"); rt.addInt(wxLANGUAGE_ESPERANTO); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ESTONIAN"); rt.addInt(wxLANGUAGE_ESTONIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_FAEROESE"); rt.addInt(wxLANGUAGE_FAEROESE); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_FARSI"); rt.addInt(wxLANGUAGE_FARSI); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_FIJI"); rt.addInt(wxLANGUAGE_FIJI); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_FINNISH"); rt.addInt(wxLANGUAGE_FINNISH); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_FRENCH"); rt.addInt(wxLANGUAGE_FRENCH); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_FRENCH_BELGIAN"); rt.addInt(wxLANGUAGE_FRENCH_BELGIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_FRENCH_CANADIAN"); rt.addInt(wxLANGUAGE_FRENCH_CANADIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_FRENCH_LUXEMBOURG"); rt.addInt(wxLANGUAGE_FRENCH_LUXEMBOURG); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_FRENCH_MONACO"); rt.addInt(wxLANGUAGE_FRENCH_MONACO); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_FRENCH_SWISS"); rt.addInt(wxLANGUAGE_FRENCH_SWISS); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_FRISIAN"); rt.addInt(wxLANGUAGE_FRISIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_GALICIAN"); rt.addInt(wxLANGUAGE_GALICIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_GEORGIAN"); rt.addInt(wxLANGUAGE_GEORGIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_GERMAN"); rt.addInt(wxLANGUAGE_GERMAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_GERMAN_AUSTRIAN"); rt.addInt(wxLANGUAGE_GERMAN_AUSTRIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_GERMAN_BELGIUM"); rt.addInt(wxLANGUAGE_GERMAN_BELGIUM); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_GERMAN_LIECHTENSTEIN"); rt.addInt(wxLANGUAGE_GERMAN_LIECHTENSTEIN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_GERMAN_LUXEMBOURG"); rt.addInt(wxLANGUAGE_GERMAN_LUXEMBOURG); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_GERMAN_SWISS"); rt.addInt(wxLANGUAGE_GERMAN_SWISS); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_GREEK"); rt.addInt(wxLANGUAGE_GREEK); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_GREENLANDIC"); rt.addInt(wxLANGUAGE_GREENLANDIC); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_GUARANI"); rt.addInt(wxLANGUAGE_GUARANI); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_GUJARATI"); rt.addInt(wxLANGUAGE_GUJARATI); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_HAUSA"); rt.addInt(wxLANGUAGE_HAUSA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_HEBREW"); rt.addInt(wxLANGUAGE_HEBREW); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_HINDI"); rt.addInt(wxLANGUAGE_HINDI); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_HUNGARIAN"); rt.addInt(wxLANGUAGE_HUNGARIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ICELANDIC"); rt.addInt(wxLANGUAGE_ICELANDIC); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_INDONESIAN"); rt.addInt(wxLANGUAGE_INDONESIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_INTERLINGUA"); rt.addInt(wxLANGUAGE_INTERLINGUA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_INTERLINGUE"); rt.addInt(wxLANGUAGE_INTERLINGUE); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_INUKTITUT"); rt.addInt(wxLANGUAGE_INUKTITUT); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_INUPIAK"); rt.addInt(wxLANGUAGE_INUPIAK); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_IRISH"); rt.addInt(wxLANGUAGE_IRISH); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ITALIAN"); rt.addInt(wxLANGUAGE_ITALIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ITALIAN_SWISS"); rt.addInt(wxLANGUAGE_ITALIAN_SWISS); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_JAPANESE"); rt.addInt(wxLANGUAGE_JAPANESE); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_JAVANESE"); rt.addInt(wxLANGUAGE_JAVANESE); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_KANNADA"); rt.addInt(wxLANGUAGE_KANNADA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_KASHMIRI"); rt.addInt(wxLANGUAGE_KASHMIRI); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_KASHMIRI_INDIA"); rt.addInt(wxLANGUAGE_KASHMIRI_INDIA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_KAZAKH"); rt.addInt(wxLANGUAGE_KAZAKH); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_KERNEWEK"); rt.addInt(wxLANGUAGE_KERNEWEK); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_KINYARWANDA"); rt.addInt(wxLANGUAGE_KINYARWANDA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_KIRGHIZ"); rt.addInt(wxLANGUAGE_KIRGHIZ); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_KIRUNDI"); rt.addInt(wxLANGUAGE_KIRUNDI); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_KONKANI"); rt.addInt(wxLANGUAGE_KONKANI); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_KOREAN"); rt.addInt(wxLANGUAGE_KOREAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_KURDISH"); rt.addInt(wxLANGUAGE_KURDISH); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_LAOTHIAN"); rt.addInt(wxLANGUAGE_LAOTHIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_LATIN"); rt.addInt(wxLANGUAGE_LATIN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_LATVIAN"); rt.addInt(wxLANGUAGE_LATVIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_LINGALA"); rt.addInt(wxLANGUAGE_LINGALA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_LITHUANIAN"); rt.addInt(wxLANGUAGE_LITHUANIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_MACEDONIAN"); rt.addInt(wxLANGUAGE_MACEDONIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_MALAGASY"); rt.addInt(wxLANGUAGE_MALAGASY); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_MALAY"); rt.addInt(wxLANGUAGE_MALAY); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_MALAYALAM"); rt.addInt(wxLANGUAGE_MALAYALAM); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_MALAY_BRUNEI_DARUSSALAM"); rt.addInt(wxLANGUAGE_MALAY_BRUNEI_DARUSSALAM); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_MALAY_MALAYSIA"); rt.addInt(wxLANGUAGE_MALAY_MALAYSIA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_MALTESE"); rt.addInt(wxLANGUAGE_MALTESE); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_MANIPURI"); rt.addInt(wxLANGUAGE_MANIPURI); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_MAORI"); rt.addInt(wxLANGUAGE_MAORI); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_MARATHI"); rt.addInt(wxLANGUAGE_MARATHI); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_MOLDAVIAN"); rt.addInt(wxLANGUAGE_MOLDAVIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_MONGOLIAN"); rt.addInt(wxLANGUAGE_MONGOLIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_NAURU"); rt.addInt(wxLANGUAGE_NAURU); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_NEPALI"); rt.addInt(wxLANGUAGE_NEPALI); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_NEPALI_INDIA"); rt.addInt(wxLANGUAGE_NEPALI_INDIA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_NORWEGIAN_BOKMAL"); rt.addInt(wxLANGUAGE_NORWEGIAN_BOKMAL); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_NORWEGIAN_NYNORSK"); rt.addInt(wxLANGUAGE_NORWEGIAN_NYNORSK); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_OCCITAN"); rt.addInt(wxLANGUAGE_OCCITAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ORIYA"); rt.addInt(wxLANGUAGE_ORIYA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_OROMO"); rt.addInt(wxLANGUAGE_OROMO); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_PASHTO"); rt.addInt(wxLANGUAGE_PASHTO); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_POLISH"); rt.addInt(wxLANGUAGE_POLISH); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_PORTUGUESE"); rt.addInt(wxLANGUAGE_PORTUGUESE); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_PORTUGUESE_BRAZILIAN"); rt.addInt(wxLANGUAGE_PORTUGUESE_BRAZILIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_PUNJABI"); rt.addInt(wxLANGUAGE_PUNJABI); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_QUECHUA"); rt.addInt(wxLANGUAGE_QUECHUA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_RHAETO_ROMANCE"); rt.addInt(wxLANGUAGE_RHAETO_ROMANCE); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ROMANIAN"); rt.addInt(wxLANGUAGE_ROMANIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_RUSSIAN"); rt.addInt(wxLANGUAGE_RUSSIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_RUSSIAN_UKRAINE"); rt.addInt(wxLANGUAGE_RUSSIAN_UKRAINE); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SAMI"); rt.addInt(wxLANGUAGE_SAMI); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SAMOAN"); rt.addInt(wxLANGUAGE_SAMOAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SANGHO"); rt.addInt(wxLANGUAGE_SANGHO); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SANSKRIT"); rt.addInt(wxLANGUAGE_SANSKRIT); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SCOTS_GAELIC"); rt.addInt(wxLANGUAGE_SCOTS_GAELIC); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SERBIAN"); rt.addInt(wxLANGUAGE_SERBIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SERBIAN_CYRILLIC"); rt.addInt(wxLANGUAGE_SERBIAN_CYRILLIC); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SERBIAN_LATIN"); rt.addInt(wxLANGUAGE_SERBIAN_LATIN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SERBO_CROATIAN"); rt.addInt(wxLANGUAGE_SERBO_CROATIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SESOTHO"); rt.addInt(wxLANGUAGE_SESOTHO); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SETSWANA"); rt.addInt(wxLANGUAGE_SETSWANA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SHONA"); rt.addInt(wxLANGUAGE_SHONA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SINDHI"); rt.addInt(wxLANGUAGE_SINDHI); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SINHALESE"); rt.addInt(wxLANGUAGE_SINHALESE); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SISWATI"); rt.addInt(wxLANGUAGE_SISWATI); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SLOVAK"); rt.addInt(wxLANGUAGE_SLOVAK); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SLOVENIAN"); rt.addInt(wxLANGUAGE_SLOVENIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SOMALI"); rt.addInt(wxLANGUAGE_SOMALI); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SPANISH"); rt.addInt(wxLANGUAGE_SPANISH); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SPANISH_ARGENTINA"); rt.addInt(wxLANGUAGE_SPANISH_ARGENTINA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SPANISH_BOLIVIA"); rt.addInt(wxLANGUAGE_SPANISH_BOLIVIA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SPANISH_CHILE"); rt.addInt(wxLANGUAGE_SPANISH_CHILE); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SPANISH_COLOMBIA"); rt.addInt(wxLANGUAGE_SPANISH_COLOMBIA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SPANISH_COSTA_RICA"); rt.addInt(wxLANGUAGE_SPANISH_COSTA_RICA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SPANISH_DOMINICAN_REPUBLIC"); rt.addInt(wxLANGUAGE_SPANISH_DOMINICAN_REPUBLIC); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SPANISH_ECUADOR"); rt.addInt(wxLANGUAGE_SPANISH_ECUADOR); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SPANISH_EL_SALVADOR"); rt.addInt(wxLANGUAGE_SPANISH_EL_SALVADOR); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SPANISH_GUATEMALA"); rt.addInt(wxLANGUAGE_SPANISH_GUATEMALA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SPANISH_HONDURAS"); rt.addInt(wxLANGUAGE_SPANISH_HONDURAS); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SPANISH_MEXICAN"); rt.addInt(wxLANGUAGE_SPANISH_MEXICAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SPANISH_MODERN"); rt.addInt(wxLANGUAGE_SPANISH_MODERN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SPANISH_NICARAGUA"); rt.addInt(wxLANGUAGE_SPANISH_NICARAGUA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SPANISH_PANAMA"); rt.addInt(wxLANGUAGE_SPANISH_PANAMA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SPANISH_PARAGUAY"); rt.addInt(wxLANGUAGE_SPANISH_PARAGUAY); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SPANISH_PERU"); rt.addInt(wxLANGUAGE_SPANISH_PERU); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SPANISH_PUERTO_RICO"); rt.addInt(wxLANGUAGE_SPANISH_PUERTO_RICO); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SPANISH_URUGUAY"); rt.addInt(wxLANGUAGE_SPANISH_URUGUAY); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SPANISH_US"); rt.addInt(wxLANGUAGE_SPANISH_US); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SPANISH_VENEZUELA"); rt.addInt(wxLANGUAGE_SPANISH_VENEZUELA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SUNDANESE"); rt.addInt(wxLANGUAGE_SUNDANESE); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SWAHILI"); rt.addInt(wxLANGUAGE_SWAHILI); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SWEDISH"); rt.addInt(wxLANGUAGE_SWEDISH); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_SWEDISH_FINLAND"); rt.addInt(wxLANGUAGE_SWEDISH_FINLAND); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_TAGALOG"); rt.addInt(wxLANGUAGE_TAGALOG); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_TAJIK"); rt.addInt(wxLANGUAGE_TAJIK); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_TAMIL"); rt.addInt(wxLANGUAGE_TAMIL); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_TATAR"); rt.addInt(wxLANGUAGE_TATAR); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_TELUGU"); rt.addInt(wxLANGUAGE_TELUGU); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_THAI"); rt.addInt(wxLANGUAGE_THAI); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_TIBETAN"); rt.addInt(wxLANGUAGE_TIBETAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_TIGRINYA"); rt.addInt(wxLANGUAGE_TIGRINYA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_TONGA"); rt.addInt(wxLANGUAGE_TONGA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_TSONGA"); rt.addInt(wxLANGUAGE_TSONGA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_TURKISH"); rt.addInt(wxLANGUAGE_TURKISH); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_TURKMEN"); rt.addInt(wxLANGUAGE_TURKMEN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_TWI"); rt.addInt(wxLANGUAGE_TWI); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_UIGHUR"); rt.addInt(wxLANGUAGE_UIGHUR); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_UKRAINIAN"); rt.addInt(wxLANGUAGE_UKRAINIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_UNKNOWN"); rt.addInt(wxLANGUAGE_UNKNOWN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_URDU"); rt.addInt(wxLANGUAGE_URDU); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_URDU_INDIA"); rt.addInt(wxLANGUAGE_URDU_INDIA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_URDU_PAKISTAN"); rt.addInt(wxLANGUAGE_URDU_PAKISTAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_USER_DEFINED"); rt.addInt(wxLANGUAGE_USER_DEFINED); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_UZBEK"); rt.addInt(wxLANGUAGE_UZBEK); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_UZBEK_CYRILLIC"); rt.addInt(wxLANGUAGE_UZBEK_CYRILLIC); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_UZBEK_LATIN"); rt.addInt(wxLANGUAGE_UZBEK_LATIN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_VALENCIAN"); rt.addInt(wxLANGUAGE_VALENCIAN); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_VIETNAMESE"); rt.addInt(wxLANGUAGE_VIETNAMESE); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_VOLAPUK"); rt.addInt(wxLANGUAGE_VOLAPUK); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_WELSH"); rt.addInt(wxLANGUAGE_WELSH); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_WOLOF"); rt.addInt(wxLANGUAGE_WOLOF); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_XHOSA"); rt.addInt(wxLANGUAGE_XHOSA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_YIDDISH"); rt.addInt(wxLANGUAGE_YIDDISH); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_YORUBA"); rt.addInt(wxLANGUAGE_YORUBA); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ZHUANG"); rt.addInt(wxLANGUAGE_ZHUANG); + rt.addTupleCount(2); + rt.addAtom("wxLANGUAGE_ZULU"); rt.addInt(wxLANGUAGE_ZULU); + rt.addTupleCount(2); rt.addAtom("wxCURSOR_ARROWWAIT"); rt.addInt(wxCURSOR_ARROWWAIT); rt.addTupleCount(2); rt.addAtom("wxCURSOR_DEFAULT"); rt.addInt(wxCURSOR_DEFAULT); @@ -145,7 +611,7 @@ void WxeApp::init_nonconsts(wxeMemEnv *memenv, ErlDrvTermData caller) { rt.addTupleCount(2); rt.addAtom("wxWHITE_PEN"); rt.addRef(getRef((void *)wxWHITE_PEN,memenv),"wxPen"); rt.addTupleCount(2); - rt.endList(60); + rt.endList(293); rt.addTupleCount(2); rt.send(); } diff --git a/lib/wx/c_src/gen/wxe_macros.h b/lib/wx/c_src/gen/wxe_macros.h index 50ceb01623..0d3b79b7f9 100644 --- a/lib/wx/c_src/gen/wxe_macros.h +++ b/lib/wx/c_src/gen/wxe_macros.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2008-2014. All Rights Reserved. + * Copyright Ericsson AB 2008-2016. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -64,6 +64,7 @@ #include <wx/html/htmlcell.h> #include <wx/filename.h> #include <wx/sysopt.h> +#include <wx/overlay.h> #ifndef wxICON_DEFAULT_BITMAP_TYPE @@ -240,3154 +241,3189 @@ #define wxWindow_UpdateWindowUI 281 #define wxWindow_Validate 282 #define wxWindow_WarpPointer 283 -#define wxTopLevelWindow_GetIcon 284 -#define wxTopLevelWindow_GetIcons 285 -#define wxTopLevelWindow_GetTitle 286 -#define wxTopLevelWindow_IsActive 287 -#define wxTopLevelWindow_Iconize 288 -#define wxTopLevelWindow_IsFullScreen 289 -#define wxTopLevelWindow_IsIconized 290 -#define wxTopLevelWindow_IsMaximized 291 -#define wxTopLevelWindow_Maximize 292 -#define wxTopLevelWindow_RequestUserAttention 293 -#define wxTopLevelWindow_SetIcon 294 -#define wxTopLevelWindow_SetIcons 295 -#define wxTopLevelWindow_CenterOnScreen 296 -#define wxTopLevelWindow_CentreOnScreen 297 -#define wxTopLevelWindow_SetShape 299 -#define wxTopLevelWindow_SetTitle 300 -#define wxTopLevelWindow_ShowFullScreen 301 -#define wxFrame_new_4 303 -#define wxFrame_new_0 304 -#define wxFrame_destruct 306 -#define wxFrame_Create 307 -#define wxFrame_CreateStatusBar 308 -#define wxFrame_CreateToolBar 309 -#define wxFrame_GetClientAreaOrigin 310 -#define wxFrame_GetMenuBar 311 -#define wxFrame_GetStatusBar 312 -#define wxFrame_GetStatusBarPane 313 -#define wxFrame_GetToolBar 314 -#define wxFrame_ProcessCommand 315 -#define wxFrame_SendSizeEvent 316 -#define wxFrame_SetMenuBar 317 -#define wxFrame_SetStatusBar 318 -#define wxFrame_SetStatusBarPane 319 -#define wxFrame_SetStatusText 320 -#define wxFrame_SetStatusWidths 321 -#define wxFrame_SetToolBar 322 -#define wxMiniFrame_new_0 323 -#define wxMiniFrame_new_4 324 -#define wxMiniFrame_Create 325 -#define wxMiniFrame_destroy 326 -#define wxSplashScreen_new_0 327 -#define wxSplashScreen_new_6 328 -#define wxSplashScreen_destruct 329 -#define wxSplashScreen_GetSplashStyle 330 -#define wxSplashScreen_GetTimeout 331 -#define wxPanel_new_0 332 -#define wxPanel_new_6 333 -#define wxPanel_new_2 334 -#define wxPanel_destruct 335 -#define wxPanel_InitDialog 336 -#define wxPanel_SetFocusIgnoringChildren 337 -#define wxScrolledWindow_new_0 338 -#define wxScrolledWindow_new_2 339 -#define wxScrolledWindow_destruct 340 -#define wxScrolledWindow_CalcScrolledPosition_4 341 -#define wxScrolledWindow_CalcScrolledPosition_1 342 -#define wxScrolledWindow_CalcUnscrolledPosition_4 343 -#define wxScrolledWindow_CalcUnscrolledPosition_1 344 -#define wxScrolledWindow_EnableScrolling 345 -#define wxScrolledWindow_GetScrollPixelsPerUnit 346 -#define wxScrolledWindow_GetViewStart 347 -#define wxScrolledWindow_DoPrepareDC 348 -#define wxScrolledWindow_PrepareDC 349 -#define wxScrolledWindow_Scroll 350 -#define wxScrolledWindow_SetScrollbars 351 -#define wxScrolledWindow_SetScrollRate 352 -#define wxScrolledWindow_SetTargetWindow 353 -#define wxSashWindow_new_0 354 -#define wxSashWindow_new_2 355 -#define wxSashWindow_destruct 356 -#define wxSashWindow_GetSashVisible 357 -#define wxSashWindow_GetMaximumSizeX 358 -#define wxSashWindow_GetMaximumSizeY 359 -#define wxSashWindow_GetMinimumSizeX 360 -#define wxSashWindow_GetMinimumSizeY 361 -#define wxSashWindow_SetMaximumSizeX 362 -#define wxSashWindow_SetMaximumSizeY 363 -#define wxSashWindow_SetMinimumSizeX 364 -#define wxSashWindow_SetMinimumSizeY 365 -#define wxSashWindow_SetSashVisible 366 -#define wxSashLayoutWindow_new_0 367 -#define wxSashLayoutWindow_new_2 368 -#define wxSashLayoutWindow_Create 369 -#define wxSashLayoutWindow_GetAlignment 370 -#define wxSashLayoutWindow_GetOrientation 371 -#define wxSashLayoutWindow_SetAlignment 372 -#define wxSashLayoutWindow_SetDefaultSize 373 -#define wxSashLayoutWindow_SetOrientation 374 -#define wxSashLayoutWindow_destroy 375 -#define wxGrid_new_0 376 -#define wxGrid_new_3 377 -#define wxGrid_new_4 378 -#define wxGrid_destruct 379 -#define wxGrid_AppendCols 380 -#define wxGrid_AppendRows 381 -#define wxGrid_AutoSize 382 -#define wxGrid_AutoSizeColumn 383 -#define wxGrid_AutoSizeColumns 384 -#define wxGrid_AutoSizeRow 385 -#define wxGrid_AutoSizeRows 386 -#define wxGrid_BeginBatch 387 -#define wxGrid_BlockToDeviceRect 388 -#define wxGrid_CanDragColSize 389 -#define wxGrid_CanDragRowSize 390 -#define wxGrid_CanDragGridSize 391 -#define wxGrid_CanEnableCellControl 392 -#define wxGrid_CellToRect_2 393 -#define wxGrid_CellToRect_1 394 -#define wxGrid_ClearGrid 395 -#define wxGrid_ClearSelection 396 -#define wxGrid_CreateGrid 397 -#define wxGrid_DeleteCols 398 -#define wxGrid_DeleteRows 399 -#define wxGrid_DisableCellEditControl 400 -#define wxGrid_DisableDragColSize 401 -#define wxGrid_DisableDragGridSize 402 -#define wxGrid_DisableDragRowSize 403 -#define wxGrid_EnableCellEditControl 404 -#define wxGrid_EnableDragColSize 405 -#define wxGrid_EnableDragGridSize 406 -#define wxGrid_EnableDragRowSize 407 -#define wxGrid_EnableEditing 408 -#define wxGrid_EnableGridLines 409 -#define wxGrid_EndBatch 410 -#define wxGrid_Fit 411 -#define wxGrid_ForceRefresh 412 -#define wxGrid_GetBatchCount 413 -#define wxGrid_GetCellAlignment 414 -#define wxGrid_GetCellBackgroundColour 415 -#define wxGrid_GetCellEditor 416 -#define wxGrid_GetCellFont 417 -#define wxGrid_GetCellRenderer 418 -#define wxGrid_GetCellTextColour 419 -#define wxGrid_GetCellValue_2 420 -#define wxGrid_GetCellValue_1 421 -#define wxGrid_GetColLabelAlignment 422 -#define wxGrid_GetColLabelSize 423 -#define wxGrid_GetColLabelValue 424 -#define wxGrid_GetColMinimalAcceptableWidth 425 -#define wxGrid_GetDefaultCellAlignment 426 -#define wxGrid_GetDefaultCellBackgroundColour 427 -#define wxGrid_GetDefaultCellFont 428 -#define wxGrid_GetDefaultCellTextColour 429 -#define wxGrid_GetDefaultColLabelSize 430 -#define wxGrid_GetDefaultColSize 431 -#define wxGrid_GetDefaultEditor 432 -#define wxGrid_GetDefaultEditorForCell_2 433 -#define wxGrid_GetDefaultEditorForCell_1 434 -#define wxGrid_GetDefaultEditorForType 435 -#define wxGrid_GetDefaultRenderer 436 -#define wxGrid_GetDefaultRendererForCell 437 -#define wxGrid_GetDefaultRendererForType 438 -#define wxGrid_GetDefaultRowLabelSize 439 -#define wxGrid_GetDefaultRowSize 440 -#define wxGrid_GetGridCursorCol 441 -#define wxGrid_GetGridCursorRow 442 -#define wxGrid_GetGridLineColour 443 -#define wxGrid_GridLinesEnabled 444 -#define wxGrid_GetLabelBackgroundColour 445 -#define wxGrid_GetLabelFont 446 -#define wxGrid_GetLabelTextColour 447 -#define wxGrid_GetNumberCols 448 -#define wxGrid_GetNumberRows 449 -#define wxGrid_GetOrCreateCellAttr 450 -#define wxGrid_GetRowMinimalAcceptableHeight 451 -#define wxGrid_GetRowLabelAlignment 452 -#define wxGrid_GetRowLabelSize 453 -#define wxGrid_GetRowLabelValue 454 -#define wxGrid_GetRowSize 455 -#define wxGrid_GetScrollLineX 456 -#define wxGrid_GetScrollLineY 457 -#define wxGrid_GetSelectedCells 458 -#define wxGrid_GetSelectedCols 459 -#define wxGrid_GetSelectedRows 460 -#define wxGrid_GetSelectionBackground 461 -#define wxGrid_GetSelectionBlockTopLeft 462 -#define wxGrid_GetSelectionBlockBottomRight 463 -#define wxGrid_GetSelectionForeground 464 -#define wxGrid_GetViewWidth 465 -#define wxGrid_GetGridWindow 466 -#define wxGrid_GetGridRowLabelWindow 467 -#define wxGrid_GetGridColLabelWindow 468 -#define wxGrid_GetGridCornerLabelWindow 469 -#define wxGrid_HideCellEditControl 470 -#define wxGrid_InsertCols 471 -#define wxGrid_InsertRows 472 -#define wxGrid_IsCellEditControlEnabled 473 -#define wxGrid_IsCurrentCellReadOnly 474 -#define wxGrid_IsEditable 475 -#define wxGrid_IsInSelection_2 476 -#define wxGrid_IsInSelection_1 477 -#define wxGrid_IsReadOnly 478 -#define wxGrid_IsSelection 479 -#define wxGrid_IsVisible_3 480 -#define wxGrid_IsVisible_2 481 -#define wxGrid_MakeCellVisible_2 482 -#define wxGrid_MakeCellVisible_1 483 -#define wxGrid_MoveCursorDown 484 -#define wxGrid_MoveCursorLeft 485 -#define wxGrid_MoveCursorRight 486 -#define wxGrid_MoveCursorUp 487 -#define wxGrid_MoveCursorDownBlock 488 -#define wxGrid_MoveCursorLeftBlock 489 -#define wxGrid_MoveCursorRightBlock 490 -#define wxGrid_MoveCursorUpBlock 491 -#define wxGrid_MovePageDown 492 -#define wxGrid_MovePageUp 493 -#define wxGrid_RegisterDataType 494 -#define wxGrid_SaveEditControlValue 495 -#define wxGrid_SelectAll 496 -#define wxGrid_SelectBlock_5 497 -#define wxGrid_SelectBlock_3 498 -#define wxGrid_SelectCol 499 -#define wxGrid_SelectRow 500 -#define wxGrid_SetCellAlignment_4 501 -#define wxGrid_SetCellAlignment_3 502 -#define wxGrid_SetCellAlignment_1 503 -#define wxGrid_SetCellBackgroundColour_3_0 504 -#define wxGrid_SetCellBackgroundColour_1 505 -#define wxGrid_SetCellBackgroundColour_3_1 506 -#define wxGrid_SetCellEditor 507 -#define wxGrid_SetCellFont 508 -#define wxGrid_SetCellRenderer 509 -#define wxGrid_SetCellTextColour_3_0 510 -#define wxGrid_SetCellTextColour_3_1 511 -#define wxGrid_SetCellTextColour_1 512 -#define wxGrid_SetCellValue_3_0 513 -#define wxGrid_SetCellValue_2 514 -#define wxGrid_SetCellValue_3_1 515 -#define wxGrid_SetColAttr 516 -#define wxGrid_SetColFormatBool 517 -#define wxGrid_SetColFormatNumber 518 -#define wxGrid_SetColFormatFloat 519 -#define wxGrid_SetColFormatCustom 520 -#define wxGrid_SetColLabelAlignment 521 -#define wxGrid_SetColLabelSize 522 -#define wxGrid_SetColLabelValue 523 -#define wxGrid_SetColMinimalWidth 524 -#define wxGrid_SetColMinimalAcceptableWidth 525 -#define wxGrid_SetColSize 526 -#define wxGrid_SetDefaultCellAlignment 527 -#define wxGrid_SetDefaultCellBackgroundColour 528 -#define wxGrid_SetDefaultCellFont 529 -#define wxGrid_SetDefaultCellTextColour 530 -#define wxGrid_SetDefaultEditor 531 -#define wxGrid_SetDefaultRenderer 532 -#define wxGrid_SetDefaultColSize 533 -#define wxGrid_SetDefaultRowSize 534 -#define wxGrid_SetGridCursor 535 -#define wxGrid_SetGridLineColour 536 -#define wxGrid_SetLabelBackgroundColour 537 -#define wxGrid_SetLabelFont 538 -#define wxGrid_SetLabelTextColour 539 -#define wxGrid_SetMargins 540 -#define wxGrid_SetReadOnly 541 -#define wxGrid_SetRowAttr 542 -#define wxGrid_SetRowLabelAlignment 543 -#define wxGrid_SetRowLabelSize 544 -#define wxGrid_SetRowLabelValue 545 -#define wxGrid_SetRowMinimalHeight 546 -#define wxGrid_SetRowMinimalAcceptableHeight 547 -#define wxGrid_SetRowSize 548 -#define wxGrid_SetScrollLineX 549 -#define wxGrid_SetScrollLineY 550 -#define wxGrid_SetSelectionBackground 551 -#define wxGrid_SetSelectionForeground 552 -#define wxGrid_SetSelectionMode 553 -#define wxGrid_ShowCellEditControl 554 -#define wxGrid_XToCol 555 -#define wxGrid_XToEdgeOfCol 556 -#define wxGrid_YToEdgeOfRow 557 -#define wxGrid_YToRow 558 -#define wxGridCellRenderer_Draw 559 -#define wxGridCellRenderer_GetBestSize 560 -#define wxGridCellEditor_Create 561 -#define wxGridCellEditor_IsCreated 562 -#define wxGridCellEditor_SetSize 563 -#define wxGridCellEditor_Show 564 -#define wxGridCellEditor_PaintBackground 565 -#define wxGridCellEditor_BeginEdit 566 -#define wxGridCellEditor_EndEdit 567 -#define wxGridCellEditor_Reset 568 -#define wxGridCellEditor_StartingKey 569 -#define wxGridCellEditor_StartingClick 570 -#define wxGridCellEditor_HandleReturn 571 -#define wxGridCellBoolRenderer_new 572 -#define wxGridCellBoolRenderer_destroy 573 -#define wxGridCellBoolEditor_new 574 -#define wxGridCellBoolEditor_IsTrueValue 575 -#define wxGridCellBoolEditor_UseStringValues 576 -#define wxGridCellBoolEditor_destroy 577 -#define wxGridCellFloatRenderer_new 578 -#define wxGridCellFloatRenderer_GetPrecision 579 -#define wxGridCellFloatRenderer_GetWidth 580 -#define wxGridCellFloatRenderer_SetParameters 581 -#define wxGridCellFloatRenderer_SetPrecision 582 -#define wxGridCellFloatRenderer_SetWidth 583 -#define wxGridCellFloatRenderer_destroy 584 -#define wxGridCellFloatEditor_new 585 -#define wxGridCellFloatEditor_SetParameters 586 -#define wxGridCellFloatEditor_destroy 587 -#define wxGridCellStringRenderer_new 588 -#define wxGridCellStringRenderer_destroy 589 -#define wxGridCellTextEditor_new 590 -#define wxGridCellTextEditor_SetParameters 591 -#define wxGridCellTextEditor_destroy 592 -#define wxGridCellChoiceEditor_new 594 -#define wxGridCellChoiceEditor_SetParameters 595 -#define wxGridCellChoiceEditor_destroy 596 -#define wxGridCellNumberRenderer_new 597 -#define wxGridCellNumberRenderer_destroy 598 -#define wxGridCellNumberEditor_new 599 -#define wxGridCellNumberEditor_GetValue 600 -#define wxGridCellNumberEditor_SetParameters 601 -#define wxGridCellNumberEditor_destroy 602 -#define wxGridCellAttr_SetTextColour 603 -#define wxGridCellAttr_SetBackgroundColour 604 -#define wxGridCellAttr_SetFont 605 -#define wxGridCellAttr_SetAlignment 606 -#define wxGridCellAttr_SetReadOnly 607 -#define wxGridCellAttr_SetRenderer 608 -#define wxGridCellAttr_SetEditor 609 -#define wxGridCellAttr_HasTextColour 610 -#define wxGridCellAttr_HasBackgroundColour 611 -#define wxGridCellAttr_HasFont 612 -#define wxGridCellAttr_HasAlignment 613 -#define wxGridCellAttr_HasRenderer 614 -#define wxGridCellAttr_HasEditor 615 -#define wxGridCellAttr_GetTextColour 616 -#define wxGridCellAttr_GetBackgroundColour 617 -#define wxGridCellAttr_GetFont 618 -#define wxGridCellAttr_GetAlignment 619 -#define wxGridCellAttr_GetRenderer 620 -#define wxGridCellAttr_GetEditor 621 -#define wxGridCellAttr_IsReadOnly 622 -#define wxGridCellAttr_SetDefAttr 623 -#define wxDC_Blit 624 -#define wxDC_CalcBoundingBox 625 -#define wxDC_Clear 626 -#define wxDC_ComputeScaleAndOrigin 627 -#define wxDC_CrossHair 628 -#define wxDC_DestroyClippingRegion 629 -#define wxDC_DeviceToLogicalX 630 -#define wxDC_DeviceToLogicalXRel 631 -#define wxDC_DeviceToLogicalY 632 -#define wxDC_DeviceToLogicalYRel 633 -#define wxDC_DrawArc 634 -#define wxDC_DrawBitmap 635 -#define wxDC_DrawCheckMark 636 -#define wxDC_DrawCircle 637 -#define wxDC_DrawEllipse_2 639 -#define wxDC_DrawEllipse_1 640 -#define wxDC_DrawEllipticArc 641 -#define wxDC_DrawIcon 642 -#define wxDC_DrawLabel 643 -#define wxDC_DrawLine 644 -#define wxDC_DrawLines 645 -#define wxDC_DrawPolygon 647 -#define wxDC_DrawPoint 649 -#define wxDC_DrawRectangle_2 651 -#define wxDC_DrawRectangle_1 652 -#define wxDC_DrawRotatedText 653 -#define wxDC_DrawRoundedRectangle_3 655 -#define wxDC_DrawRoundedRectangle_2 656 -#define wxDC_DrawText 657 -#define wxDC_EndDoc 658 -#define wxDC_EndPage 659 -#define wxDC_FloodFill 660 -#define wxDC_GetBackground 661 -#define wxDC_GetBackgroundMode 662 -#define wxDC_GetBrush 663 -#define wxDC_GetCharHeight 664 -#define wxDC_GetCharWidth 665 -#define wxDC_GetClippingBox 666 -#define wxDC_GetFont 668 -#define wxDC_GetLayoutDirection 669 -#define wxDC_GetLogicalFunction 670 -#define wxDC_GetMapMode 671 -#define wxDC_GetMultiLineTextExtent_4 672 -#define wxDC_GetMultiLineTextExtent_1 673 -#define wxDC_GetPartialTextExtents 674 -#define wxDC_GetPen 675 -#define wxDC_GetPixel 676 -#define wxDC_GetPPI 677 -#define wxDC_GetSize 679 -#define wxDC_GetSizeMM 681 -#define wxDC_GetTextBackground 682 -#define wxDC_GetTextExtent_4 683 -#define wxDC_GetTextExtent_1 684 -#define wxDC_GetTextForeground 686 -#define wxDC_GetUserScale 687 -#define wxDC_GradientFillConcentric_3 688 -#define wxDC_GradientFillConcentric_4 689 -#define wxDC_GradientFillLinear 690 -#define wxDC_LogicalToDeviceX 691 -#define wxDC_LogicalToDeviceXRel 692 -#define wxDC_LogicalToDeviceY 693 -#define wxDC_LogicalToDeviceYRel 694 -#define wxDC_MaxX 695 -#define wxDC_MaxY 696 -#define wxDC_MinX 697 -#define wxDC_MinY 698 -#define wxDC_IsOk 699 -#define wxDC_ResetBoundingBox 700 -#define wxDC_SetAxisOrientation 701 -#define wxDC_SetBackground 702 -#define wxDC_SetBackgroundMode 703 -#define wxDC_SetBrush 704 -#define wxDC_SetClippingRegion_2 706 -#define wxDC_SetClippingRegion_1_1 707 -#define wxDC_SetClippingRegion_1_0 708 -#define wxDC_SetDeviceOrigin 709 -#define wxDC_SetFont 710 -#define wxDC_SetLayoutDirection 711 -#define wxDC_SetLogicalFunction 712 -#define wxDC_SetMapMode 713 -#define wxDC_SetPalette 714 -#define wxDC_SetPen 715 -#define wxDC_SetTextBackground 716 -#define wxDC_SetTextForeground 717 -#define wxDC_SetUserScale 718 -#define wxDC_StartDoc 719 -#define wxDC_StartPage 720 -#define wxMirrorDC_new 721 -#define wxMirrorDC_destroy 722 -#define wxScreenDC_new 723 -#define wxScreenDC_destruct 724 -#define wxPostScriptDC_new_0 725 -#define wxPostScriptDC_new_1 726 -#define wxPostScriptDC_destruct 727 -#define wxPostScriptDC_SetResolution 728 -#define wxPostScriptDC_GetResolution 729 -#define wxWindowDC_new_0 730 -#define wxWindowDC_new_1 731 -#define wxWindowDC_destruct 732 -#define wxClientDC_new_0 733 -#define wxClientDC_new_1 734 -#define wxClientDC_destroy 735 -#define wxPaintDC_new_0 736 -#define wxPaintDC_new_1 737 -#define wxPaintDC_destroy 738 -#define wxMemoryDC_new_1_0 740 -#define wxMemoryDC_new_1_1 741 -#define wxMemoryDC_new_0 742 -#define wxMemoryDC_destruct 744 -#define wxMemoryDC_SelectObject 745 -#define wxMemoryDC_SelectObjectAsSource 746 -#define wxBufferedDC_new_0 747 -#define wxBufferedDC_new_2 748 -#define wxBufferedDC_new_3 749 -#define wxBufferedDC_destruct 750 -#define wxBufferedDC_Init_2 751 -#define wxBufferedDC_Init_3 752 -#define wxBufferedPaintDC_new_3 753 -#define wxBufferedPaintDC_new_2 754 -#define wxBufferedPaintDC_destruct 755 -#define wxGraphicsObject_destruct 756 -#define wxGraphicsObject_GetRenderer 757 -#define wxGraphicsObject_IsNull 758 -#define wxGraphicsContext_destruct 759 -#define wxGraphicsContext_Create_1_1 760 -#define wxGraphicsContext_Create_1_0 761 -#define wxGraphicsContext_Create_0 762 -#define wxGraphicsContext_CreatePen 763 -#define wxGraphicsContext_CreateBrush 764 -#define wxGraphicsContext_CreateRadialGradientBrush 765 -#define wxGraphicsContext_CreateLinearGradientBrush 766 -#define wxGraphicsContext_CreateFont 767 -#define wxGraphicsContext_CreateMatrix 768 -#define wxGraphicsContext_CreatePath 769 -#define wxGraphicsContext_Clip_1 770 -#define wxGraphicsContext_Clip_4 771 -#define wxGraphicsContext_ResetClip 772 -#define wxGraphicsContext_DrawBitmap 773 -#define wxGraphicsContext_DrawEllipse 774 -#define wxGraphicsContext_DrawIcon 775 -#define wxGraphicsContext_DrawLines 776 -#define wxGraphicsContext_DrawPath 777 -#define wxGraphicsContext_DrawRectangle 778 -#define wxGraphicsContext_DrawRoundedRectangle 779 -#define wxGraphicsContext_DrawText_3 780 -#define wxGraphicsContext_DrawText_4_0 781 -#define wxGraphicsContext_DrawText_4_1 782 -#define wxGraphicsContext_DrawText_5 783 -#define wxGraphicsContext_FillPath 784 -#define wxGraphicsContext_StrokePath 785 -#define wxGraphicsContext_GetPartialTextExtents 786 -#define wxGraphicsContext_GetTextExtent 787 -#define wxGraphicsContext_Rotate 788 -#define wxGraphicsContext_Scale 789 -#define wxGraphicsContext_Translate 790 -#define wxGraphicsContext_GetTransform 791 -#define wxGraphicsContext_SetTransform 792 -#define wxGraphicsContext_ConcatTransform 793 -#define wxGraphicsContext_SetBrush_1_1 794 -#define wxGraphicsContext_SetBrush_1_0 795 -#define wxGraphicsContext_SetFont_1 796 -#define wxGraphicsContext_SetFont_2 797 -#define wxGraphicsContext_SetPen_1_0 798 -#define wxGraphicsContext_SetPen_1_1 799 -#define wxGraphicsContext_StrokeLine 800 -#define wxGraphicsContext_StrokeLines 801 -#define wxGraphicsMatrix_Concat 803 -#define wxGraphicsMatrix_Get 805 -#define wxGraphicsMatrix_Invert 806 -#define wxGraphicsMatrix_IsEqual 807 -#define wxGraphicsMatrix_IsIdentity 809 -#define wxGraphicsMatrix_Rotate 810 -#define wxGraphicsMatrix_Scale 811 -#define wxGraphicsMatrix_Translate 812 -#define wxGraphicsMatrix_Set 813 -#define wxGraphicsMatrix_TransformPoint 814 -#define wxGraphicsMatrix_TransformDistance 815 -#define wxGraphicsPath_MoveToPoint_2 816 -#define wxGraphicsPath_MoveToPoint_1 817 -#define wxGraphicsPath_AddArc_6 818 -#define wxGraphicsPath_AddArc_5 819 -#define wxGraphicsPath_AddArcToPoint 820 -#define wxGraphicsPath_AddCircle 821 -#define wxGraphicsPath_AddCurveToPoint_6 822 -#define wxGraphicsPath_AddCurveToPoint_3 823 -#define wxGraphicsPath_AddEllipse 824 -#define wxGraphicsPath_AddLineToPoint_2 825 -#define wxGraphicsPath_AddLineToPoint_1 826 -#define wxGraphicsPath_AddPath 827 -#define wxGraphicsPath_AddQuadCurveToPoint 828 -#define wxGraphicsPath_AddRectangle 829 -#define wxGraphicsPath_AddRoundedRectangle 830 -#define wxGraphicsPath_CloseSubpath 831 -#define wxGraphicsPath_Contains_3 832 -#define wxGraphicsPath_Contains_2 833 -#define wxGraphicsPath_GetBox 835 -#define wxGraphicsPath_GetCurrentPoint 837 -#define wxGraphicsPath_Transform 838 -#define wxGraphicsRenderer_GetDefaultRenderer 839 -#define wxGraphicsRenderer_CreateContext_1_1 840 -#define wxGraphicsRenderer_CreateContext_1_0 841 -#define wxGraphicsRenderer_CreatePen 842 -#define wxGraphicsRenderer_CreateBrush 843 -#define wxGraphicsRenderer_CreateLinearGradientBrush 844 -#define wxGraphicsRenderer_CreateRadialGradientBrush 845 -#define wxGraphicsRenderer_CreateFont 846 -#define wxGraphicsRenderer_CreateMatrix 847 -#define wxGraphicsRenderer_CreatePath 848 -#define wxMenuBar_new_1 850 -#define wxMenuBar_new_0 852 -#define wxMenuBar_destruct 854 -#define wxMenuBar_Append 855 -#define wxMenuBar_Check 856 -#define wxMenuBar_Enable_2 857 -#define wxMenuBar_Enable_1 858 -#define wxMenuBar_EnableTop 859 -#define wxMenuBar_FindMenu 860 -#define wxMenuBar_FindMenuItem 861 -#define wxMenuBar_FindItem 862 -#define wxMenuBar_GetHelpString 863 -#define wxMenuBar_GetLabel_1 864 -#define wxMenuBar_GetLabel_0 865 -#define wxMenuBar_GetLabelTop 866 -#define wxMenuBar_GetMenu 867 -#define wxMenuBar_GetMenuCount 868 -#define wxMenuBar_Insert 869 -#define wxMenuBar_IsChecked 870 -#define wxMenuBar_IsEnabled_1 871 -#define wxMenuBar_IsEnabled_0 872 -#define wxMenuBar_Remove 873 -#define wxMenuBar_Replace 874 -#define wxMenuBar_SetHelpString 875 -#define wxMenuBar_SetLabel_2 876 -#define wxMenuBar_SetLabel_1 877 -#define wxMenuBar_SetLabelTop 878 -#define wxControl_GetLabel 879 -#define wxControl_SetLabel 880 -#define wxControlWithItems_Append_1 881 -#define wxControlWithItems_Append_2 882 -#define wxControlWithItems_appendStrings_1 883 -#define wxControlWithItems_Clear 884 -#define wxControlWithItems_Delete 885 -#define wxControlWithItems_FindString 886 -#define wxControlWithItems_getClientData 887 -#define wxControlWithItems_setClientData 888 -#define wxControlWithItems_GetCount 889 -#define wxControlWithItems_GetSelection 890 -#define wxControlWithItems_GetString 891 -#define wxControlWithItems_GetStringSelection 892 -#define wxControlWithItems_Insert_2 893 -#define wxControlWithItems_Insert_3 894 -#define wxControlWithItems_IsEmpty 895 -#define wxControlWithItems_Select 896 -#define wxControlWithItems_SetSelection 897 -#define wxControlWithItems_SetString 898 -#define wxControlWithItems_SetStringSelection 899 -#define wxMenu_new_2 902 -#define wxMenu_new_1 903 -#define wxMenu_destruct 905 -#define wxMenu_Append_3 906 -#define wxMenu_Append_1 907 -#define wxMenu_Append_4_0 908 -#define wxMenu_Append_4_1 909 -#define wxMenu_AppendCheckItem 910 -#define wxMenu_AppendRadioItem 911 -#define wxMenu_AppendSeparator 912 -#define wxMenu_Break 913 -#define wxMenu_Check 914 -#define wxMenu_Delete_1_0 915 -#define wxMenu_Delete_1_1 916 -#define wxMenu_Destroy_1_0 917 -#define wxMenu_Destroy_1_1 918 -#define wxMenu_Enable 919 -#define wxMenu_FindItem_1 920 -#define wxMenu_FindItem_2 921 -#define wxMenu_FindItemByPosition 922 -#define wxMenu_GetHelpString 923 -#define wxMenu_GetLabel 924 -#define wxMenu_GetMenuItemCount 925 -#define wxMenu_GetMenuItems 926 -#define wxMenu_GetTitle 928 -#define wxMenu_Insert_2 929 -#define wxMenu_Insert_3 930 -#define wxMenu_Insert_5_1 931 -#define wxMenu_Insert_5_0 932 -#define wxMenu_InsertCheckItem 933 -#define wxMenu_InsertRadioItem 934 -#define wxMenu_InsertSeparator 935 -#define wxMenu_IsChecked 936 -#define wxMenu_IsEnabled 937 -#define wxMenu_Prepend_1 938 -#define wxMenu_Prepend_2 939 -#define wxMenu_Prepend_4_1 940 -#define wxMenu_Prepend_4_0 941 -#define wxMenu_PrependCheckItem 942 -#define wxMenu_PrependRadioItem 943 -#define wxMenu_PrependSeparator 944 -#define wxMenu_Remove_1_0 945 -#define wxMenu_Remove_1_1 946 -#define wxMenu_SetHelpString 947 -#define wxMenu_SetLabel 948 -#define wxMenu_SetTitle 949 -#define wxMenuItem_new 950 -#define wxMenuItem_destruct 952 -#define wxMenuItem_Check 953 -#define wxMenuItem_Enable 954 -#define wxMenuItem_GetBitmap 955 -#define wxMenuItem_GetHelp 956 -#define wxMenuItem_GetId 957 -#define wxMenuItem_GetKind 958 -#define wxMenuItem_GetLabel 959 -#define wxMenuItem_GetLabelFromText 960 -#define wxMenuItem_GetMenu 961 -#define wxMenuItem_GetText 962 -#define wxMenuItem_GetSubMenu 963 -#define wxMenuItem_IsCheckable 964 -#define wxMenuItem_IsChecked 965 -#define wxMenuItem_IsEnabled 966 -#define wxMenuItem_IsSeparator 967 -#define wxMenuItem_IsSubMenu 968 -#define wxMenuItem_SetBitmap 969 -#define wxMenuItem_SetHelp 970 -#define wxMenuItem_SetMenu 971 -#define wxMenuItem_SetSubMenu 972 -#define wxMenuItem_SetText 973 -#define wxToolBar_AddControl 974 -#define wxToolBar_AddSeparator 975 -#define wxToolBar_AddTool_5 976 -#define wxToolBar_AddTool_4_0 977 -#define wxToolBar_AddTool_1 978 -#define wxToolBar_AddTool_4_1 979 -#define wxToolBar_AddTool_3 980 -#define wxToolBar_AddTool_6 981 -#define wxToolBar_AddCheckTool 982 -#define wxToolBar_AddRadioTool 983 -#define wxToolBar_DeleteTool 984 -#define wxToolBar_DeleteToolByPos 985 -#define wxToolBar_EnableTool 986 -#define wxToolBar_FindById 987 -#define wxToolBar_FindControl 988 -#define wxToolBar_FindToolForPosition 989 -#define wxToolBar_GetToolSize 990 -#define wxToolBar_GetToolBitmapSize 991 -#define wxToolBar_GetMargins 992 -#define wxToolBar_GetToolEnabled 993 -#define wxToolBar_GetToolLongHelp 994 -#define wxToolBar_GetToolPacking 995 -#define wxToolBar_GetToolPos 996 -#define wxToolBar_GetToolSeparation 997 -#define wxToolBar_GetToolShortHelp 998 -#define wxToolBar_GetToolState 999 -#define wxToolBar_InsertControl 1000 -#define wxToolBar_InsertSeparator 1001 -#define wxToolBar_InsertTool_5 1002 -#define wxToolBar_InsertTool_2 1003 -#define wxToolBar_InsertTool_4 1004 -#define wxToolBar_Realize 1005 -#define wxToolBar_RemoveTool 1006 -#define wxToolBar_SetMargins 1007 -#define wxToolBar_SetToolBitmapSize 1008 -#define wxToolBar_SetToolLongHelp 1009 -#define wxToolBar_SetToolPacking 1010 -#define wxToolBar_SetToolShortHelp 1011 -#define wxToolBar_SetToolSeparation 1012 -#define wxToolBar_ToggleTool 1013 -#define wxStatusBar_new_0 1015 -#define wxStatusBar_new_2 1016 -#define wxStatusBar_destruct 1018 -#define wxStatusBar_Create 1019 -#define wxStatusBar_GetFieldRect 1020 -#define wxStatusBar_GetFieldsCount 1021 -#define wxStatusBar_GetStatusText 1022 -#define wxStatusBar_PopStatusText 1023 -#define wxStatusBar_PushStatusText 1024 -#define wxStatusBar_SetFieldsCount 1025 -#define wxStatusBar_SetMinHeight 1026 -#define wxStatusBar_SetStatusText 1027 -#define wxStatusBar_SetStatusWidths 1028 -#define wxStatusBar_SetStatusStyles 1029 -#define wxBitmap_new_0 1030 -#define wxBitmap_new_3 1031 -#define wxBitmap_new_4 1032 -#define wxBitmap_new_2_0 1033 -#define wxBitmap_new_2_1 1034 -#define wxBitmap_destruct 1035 -#define wxBitmap_ConvertToImage 1036 -#define wxBitmap_CopyFromIcon 1037 -#define wxBitmap_Create 1038 -#define wxBitmap_GetDepth 1039 -#define wxBitmap_GetHeight 1040 -#define wxBitmap_GetPalette 1041 -#define wxBitmap_GetMask 1042 -#define wxBitmap_GetWidth 1043 -#define wxBitmap_GetSubBitmap 1044 -#define wxBitmap_LoadFile 1045 -#define wxBitmap_Ok 1046 -#define wxBitmap_SaveFile 1047 -#define wxBitmap_SetDepth 1048 -#define wxBitmap_SetHeight 1049 -#define wxBitmap_SetMask 1050 -#define wxBitmap_SetPalette 1051 -#define wxBitmap_SetWidth 1052 -#define wxIcon_new_0 1053 -#define wxIcon_new_2 1054 -#define wxIcon_new_1 1055 -#define wxIcon_CopyFromBitmap 1056 -#define wxIcon_destroy 1057 -#define wxIconBundle_new_0 1058 -#define wxIconBundle_new_2 1059 -#define wxIconBundle_new_1_0 1060 -#define wxIconBundle_new_1_1 1061 -#define wxIconBundle_destruct 1062 -#define wxIconBundle_AddIcon_2 1063 -#define wxIconBundle_AddIcon_1 1064 -#define wxIconBundle_GetIcon_1_1 1065 -#define wxIconBundle_GetIcon_1_0 1066 -#define wxCursor_new_0 1067 -#define wxCursor_new_1_0 1068 -#define wxCursor_new_1_1 1069 -#define wxCursor_new_4 1070 -#define wxCursor_destruct 1071 -#define wxCursor_Ok 1072 -#define wxMask_new_0 1073 -#define wxMask_new_2_1 1074 -#define wxMask_new_2_0 1075 -#define wxMask_new_1 1076 -#define wxMask_destruct 1077 -#define wxMask_Create_2_1 1078 -#define wxMask_Create_2_0 1079 -#define wxMask_Create_1 1080 -#define wxImage_new_0 1081 -#define wxImage_new_3_0 1082 -#define wxImage_new_4 1083 -#define wxImage_new_5 1084 -#define wxImage_new_2 1085 -#define wxImage_new_3_1 1086 -#define wxImage_Blur 1087 -#define wxImage_BlurHorizontal 1088 -#define wxImage_BlurVertical 1089 -#define wxImage_ConvertAlphaToMask 1090 -#define wxImage_ConvertToGreyscale 1091 -#define wxImage_ConvertToMono 1092 -#define wxImage_Copy 1093 -#define wxImage_Create_3 1094 -#define wxImage_Create_4 1095 -#define wxImage_Create_5 1096 -#define wxImage_Destroy 1097 -#define wxImage_FindFirstUnusedColour 1098 -#define wxImage_GetImageExtWildcard 1099 -#define wxImage_GetAlpha_2 1100 -#define wxImage_GetAlpha_0 1101 -#define wxImage_GetBlue 1102 -#define wxImage_GetData 1103 -#define wxImage_GetGreen 1104 -#define wxImage_GetImageCount 1105 -#define wxImage_GetHeight 1106 -#define wxImage_GetMaskBlue 1107 -#define wxImage_GetMaskGreen 1108 -#define wxImage_GetMaskRed 1109 -#define wxImage_GetOrFindMaskColour 1110 -#define wxImage_GetPalette 1111 -#define wxImage_GetRed 1112 -#define wxImage_GetSubImage 1113 -#define wxImage_GetWidth 1114 -#define wxImage_HasAlpha 1115 -#define wxImage_HasMask 1116 -#define wxImage_GetOption 1117 -#define wxImage_GetOptionInt 1118 -#define wxImage_HasOption 1119 -#define wxImage_InitAlpha 1120 -#define wxImage_InitStandardHandlers 1121 -#define wxImage_IsTransparent 1122 -#define wxImage_LoadFile_2 1123 -#define wxImage_LoadFile_3 1124 -#define wxImage_Ok 1125 -#define wxImage_RemoveHandler 1126 -#define wxImage_Mirror 1127 -#define wxImage_Replace 1128 -#define wxImage_Rescale 1129 -#define wxImage_Resize 1130 -#define wxImage_Rotate 1131 -#define wxImage_RotateHue 1132 -#define wxImage_Rotate90 1133 -#define wxImage_SaveFile_1 1134 -#define wxImage_SaveFile_2_0 1135 -#define wxImage_SaveFile_2_1 1136 -#define wxImage_Scale 1137 -#define wxImage_Size 1138 -#define wxImage_SetAlpha_3 1139 -#define wxImage_SetAlpha_2 1140 -#define wxImage_SetData_2 1141 -#define wxImage_SetData_4 1142 -#define wxImage_SetMask 1143 -#define wxImage_SetMaskColour 1144 -#define wxImage_SetMaskFromImage 1145 -#define wxImage_SetOption_2_1 1146 -#define wxImage_SetOption_2_0 1147 -#define wxImage_SetPalette 1148 -#define wxImage_SetRGB_5 1149 -#define wxImage_SetRGB_4 1150 -#define wxImage_destroy 1151 -#define wxBrush_new_0 1152 -#define wxBrush_new_2 1153 -#define wxBrush_new_1 1154 -#define wxBrush_destruct 1156 -#define wxBrush_GetColour 1157 -#define wxBrush_GetStipple 1158 -#define wxBrush_GetStyle 1159 -#define wxBrush_IsHatch 1160 -#define wxBrush_IsOk 1161 -#define wxBrush_SetColour_1 1162 -#define wxBrush_SetColour_3 1163 -#define wxBrush_SetStipple 1164 -#define wxBrush_SetStyle 1165 -#define wxPen_new_0 1166 -#define wxPen_new_2 1167 -#define wxPen_destruct 1168 -#define wxPen_GetCap 1169 -#define wxPen_GetColour 1170 -#define wxPen_GetJoin 1171 -#define wxPen_GetStyle 1172 -#define wxPen_GetWidth 1173 -#define wxPen_IsOk 1174 -#define wxPen_SetCap 1175 -#define wxPen_SetColour_1 1176 -#define wxPen_SetColour_3 1177 -#define wxPen_SetJoin 1178 -#define wxPen_SetStyle 1179 -#define wxPen_SetWidth 1180 -#define wxRegion_new_0 1181 -#define wxRegion_new_4 1182 -#define wxRegion_new_2 1183 -#define wxRegion_new_1_1 1184 -#define wxRegion_new_1_0 1186 -#define wxRegion_destruct 1188 -#define wxRegion_Clear 1189 -#define wxRegion_Contains_2 1190 -#define wxRegion_Contains_1_0 1191 -#define wxRegion_Contains_4 1192 -#define wxRegion_Contains_1_1 1193 -#define wxRegion_ConvertToBitmap 1194 -#define wxRegion_GetBox 1195 -#define wxRegion_Intersect_4 1196 -#define wxRegion_Intersect_1_1 1197 -#define wxRegion_Intersect_1_0 1198 -#define wxRegion_IsEmpty 1199 -#define wxRegion_Subtract_4 1200 -#define wxRegion_Subtract_1_1 1201 -#define wxRegion_Subtract_1_0 1202 -#define wxRegion_Offset_2 1203 -#define wxRegion_Offset_1 1204 -#define wxRegion_Union_4 1205 -#define wxRegion_Union_1_2 1206 -#define wxRegion_Union_1_1 1207 -#define wxRegion_Union_1_0 1208 -#define wxRegion_Union_3 1209 -#define wxRegion_Xor_4 1210 -#define wxRegion_Xor_1_1 1211 -#define wxRegion_Xor_1_0 1212 -#define wxAcceleratorTable_new_0 1213 -#define wxAcceleratorTable_new_2 1214 -#define wxAcceleratorTable_destruct 1215 -#define wxAcceleratorTable_Ok 1216 -#define wxAcceleratorEntry_new_1_0 1217 -#define wxAcceleratorEntry_new_1_1 1218 -#define wxAcceleratorEntry_GetCommand 1219 -#define wxAcceleratorEntry_GetFlags 1220 -#define wxAcceleratorEntry_GetKeyCode 1221 -#define wxAcceleratorEntry_Set 1222 -#define wxAcceleratorEntry_destroy 1223 -#define wxCaret_new_3 1228 -#define wxCaret_new_2 1229 -#define wxCaret_destruct 1231 -#define wxCaret_Create_3 1232 -#define wxCaret_Create_2 1233 -#define wxCaret_GetBlinkTime 1234 -#define wxCaret_GetPosition 1236 -#define wxCaret_GetSize 1238 -#define wxCaret_GetWindow 1239 -#define wxCaret_Hide 1240 -#define wxCaret_IsOk 1241 -#define wxCaret_IsVisible 1242 -#define wxCaret_Move_2 1243 -#define wxCaret_Move_1 1244 -#define wxCaret_SetBlinkTime 1245 -#define wxCaret_SetSize_2 1246 -#define wxCaret_SetSize_1 1247 -#define wxCaret_Show 1248 -#define wxSizer_Add_2_1 1249 -#define wxSizer_Add_2_0 1250 -#define wxSizer_Add_3 1251 -#define wxSizer_Add_2_3 1252 -#define wxSizer_Add_2_2 1253 -#define wxSizer_AddSpacer 1254 -#define wxSizer_AddStretchSpacer 1255 -#define wxSizer_CalcMin 1256 -#define wxSizer_Clear 1257 -#define wxSizer_Detach_1_2 1258 -#define wxSizer_Detach_1_1 1259 -#define wxSizer_Detach_1_0 1260 -#define wxSizer_Fit 1261 -#define wxSizer_FitInside 1262 -#define wxSizer_GetChildren 1263 -#define wxSizer_GetItem_2_1 1264 -#define wxSizer_GetItem_2_0 1265 -#define wxSizer_GetItem_1 1266 -#define wxSizer_GetSize 1267 -#define wxSizer_GetPosition 1268 -#define wxSizer_GetMinSize 1269 -#define wxSizer_Hide_2_0 1270 -#define wxSizer_Hide_2_1 1271 -#define wxSizer_Hide_1 1272 -#define wxSizer_Insert_3_1 1273 -#define wxSizer_Insert_3_0 1274 -#define wxSizer_Insert_4 1275 -#define wxSizer_Insert_3_3 1276 -#define wxSizer_Insert_3_2 1277 -#define wxSizer_Insert_2 1278 -#define wxSizer_InsertSpacer 1279 -#define wxSizer_InsertStretchSpacer 1280 -#define wxSizer_IsShown_1_2 1281 -#define wxSizer_IsShown_1_1 1282 -#define wxSizer_IsShown_1_0 1283 -#define wxSizer_Layout 1284 -#define wxSizer_Prepend_2_1 1285 -#define wxSizer_Prepend_2_0 1286 -#define wxSizer_Prepend_3 1287 -#define wxSizer_Prepend_2_3 1288 -#define wxSizer_Prepend_2_2 1289 -#define wxSizer_Prepend_1 1290 -#define wxSizer_PrependSpacer 1291 -#define wxSizer_PrependStretchSpacer 1292 -#define wxSizer_RecalcSizes 1293 -#define wxSizer_Remove_1_1 1294 -#define wxSizer_Remove_1_0 1295 -#define wxSizer_Replace_3_1 1296 -#define wxSizer_Replace_3_0 1297 -#define wxSizer_Replace_2 1298 -#define wxSizer_SetDimension 1299 -#define wxSizer_SetMinSize_2 1300 -#define wxSizer_SetMinSize_1 1301 -#define wxSizer_SetItemMinSize_3_2 1302 -#define wxSizer_SetItemMinSize_2_2 1303 -#define wxSizer_SetItemMinSize_3_1 1304 -#define wxSizer_SetItemMinSize_2_1 1305 -#define wxSizer_SetItemMinSize_3_0 1306 -#define wxSizer_SetItemMinSize_2_0 1307 -#define wxSizer_SetSizeHints 1308 -#define wxSizer_SetVirtualSizeHints 1309 -#define wxSizer_Show_2_2 1310 -#define wxSizer_Show_2_1 1311 -#define wxSizer_Show_2_0 1312 -#define wxSizer_Show_1 1313 -#define wxSizerFlags_new 1314 -#define wxSizerFlags_Align 1315 -#define wxSizerFlags_Border_2 1316 -#define wxSizerFlags_Border_1 1317 -#define wxSizerFlags_Center 1318 -#define wxSizerFlags_Centre 1319 -#define wxSizerFlags_Expand 1320 -#define wxSizerFlags_Left 1321 -#define wxSizerFlags_Proportion 1322 -#define wxSizerFlags_Right 1323 -#define wxSizerFlags_destroy 1324 -#define wxSizerItem_new_5_1 1325 -#define wxSizerItem_new_2_1 1326 -#define wxSizerItem_new_5_0 1327 -#define wxSizerItem_new_2_0 1328 -#define wxSizerItem_new_6 1329 -#define wxSizerItem_new_3 1330 -#define wxSizerItem_new_0 1331 -#define wxSizerItem_destruct 1332 -#define wxSizerItem_CalcMin 1333 -#define wxSizerItem_DeleteWindows 1334 -#define wxSizerItem_DetachSizer 1335 -#define wxSizerItem_GetBorder 1336 -#define wxSizerItem_GetFlag 1337 -#define wxSizerItem_GetMinSize 1338 -#define wxSizerItem_GetPosition 1339 -#define wxSizerItem_GetProportion 1340 -#define wxSizerItem_GetRatio 1341 -#define wxSizerItem_GetRect 1342 -#define wxSizerItem_GetSize 1343 -#define wxSizerItem_GetSizer 1344 -#define wxSizerItem_GetSpacer 1345 -#define wxSizerItem_GetUserData 1346 -#define wxSizerItem_GetWindow 1347 -#define wxSizerItem_IsSizer 1348 -#define wxSizerItem_IsShown 1349 -#define wxSizerItem_IsSpacer 1350 -#define wxSizerItem_IsWindow 1351 -#define wxSizerItem_SetBorder 1352 -#define wxSizerItem_SetDimension 1353 -#define wxSizerItem_SetFlag 1354 -#define wxSizerItem_SetInitSize 1355 -#define wxSizerItem_SetMinSize_1 1356 -#define wxSizerItem_SetMinSize_2 1357 -#define wxSizerItem_SetProportion 1358 -#define wxSizerItem_SetRatio_2 1359 -#define wxSizerItem_SetRatio_1_1 1360 -#define wxSizerItem_SetRatio_1_0 1361 -#define wxSizerItem_SetSizer 1362 -#define wxSizerItem_SetSpacer_1 1363 -#define wxSizerItem_SetSpacer_2 1364 -#define wxSizerItem_SetWindow 1365 -#define wxSizerItem_Show 1366 -#define wxBoxSizer_new 1367 -#define wxBoxSizer_GetOrientation 1368 -#define wxBoxSizer_destroy 1369 -#define wxStaticBoxSizer_new_2 1370 -#define wxStaticBoxSizer_new_3 1371 -#define wxStaticBoxSizer_GetStaticBox 1372 -#define wxStaticBoxSizer_destroy 1373 -#define wxGridSizer_new_4 1374 -#define wxGridSizer_new_2 1375 -#define wxGridSizer_GetCols 1376 -#define wxGridSizer_GetHGap 1377 -#define wxGridSizer_GetRows 1378 -#define wxGridSizer_GetVGap 1379 -#define wxGridSizer_SetCols 1380 -#define wxGridSizer_SetHGap 1381 -#define wxGridSizer_SetRows 1382 -#define wxGridSizer_SetVGap 1383 -#define wxGridSizer_destroy 1384 -#define wxFlexGridSizer_new_4 1385 -#define wxFlexGridSizer_new_2 1386 -#define wxFlexGridSizer_AddGrowableCol 1387 -#define wxFlexGridSizer_AddGrowableRow 1388 -#define wxFlexGridSizer_GetFlexibleDirection 1389 -#define wxFlexGridSizer_GetNonFlexibleGrowMode 1390 -#define wxFlexGridSizer_RemoveGrowableCol 1391 -#define wxFlexGridSizer_RemoveGrowableRow 1392 -#define wxFlexGridSizer_SetFlexibleDirection 1393 -#define wxFlexGridSizer_SetNonFlexibleGrowMode 1394 -#define wxFlexGridSizer_destroy 1395 -#define wxGridBagSizer_new 1396 -#define wxGridBagSizer_Add_3_2 1397 -#define wxGridBagSizer_Add_3_1 1398 -#define wxGridBagSizer_Add_4 1399 -#define wxGridBagSizer_Add_1_0 1400 -#define wxGridBagSizer_Add_2_1 1401 -#define wxGridBagSizer_Add_2_0 1402 -#define wxGridBagSizer_Add_3_0 1403 -#define wxGridBagSizer_Add_1_1 1404 -#define wxGridBagSizer_CalcMin 1405 -#define wxGridBagSizer_CheckForIntersection_2 1406 -#define wxGridBagSizer_CheckForIntersection_3 1407 -#define wxGridBagSizer_FindItem_1_1 1408 -#define wxGridBagSizer_FindItem_1_0 1409 -#define wxGridBagSizer_FindItemAtPoint 1410 -#define wxGridBagSizer_FindItemAtPosition 1411 -#define wxGridBagSizer_FindItemWithData 1412 -#define wxGridBagSizer_GetCellSize 1413 -#define wxGridBagSizer_GetEmptyCellSize 1414 -#define wxGridBagSizer_GetItemPosition_1_2 1415 -#define wxGridBagSizer_GetItemPosition_1_1 1416 -#define wxGridBagSizer_GetItemPosition_1_0 1417 -#define wxGridBagSizer_GetItemSpan_1_2 1418 -#define wxGridBagSizer_GetItemSpan_1_1 1419 -#define wxGridBagSizer_GetItemSpan_1_0 1420 -#define wxGridBagSizer_SetEmptyCellSize 1421 -#define wxGridBagSizer_SetItemPosition_2_2 1422 -#define wxGridBagSizer_SetItemPosition_2_1 1423 -#define wxGridBagSizer_SetItemPosition_2_0 1424 -#define wxGridBagSizer_SetItemSpan_2_2 1425 -#define wxGridBagSizer_SetItemSpan_2_1 1426 -#define wxGridBagSizer_SetItemSpan_2_0 1427 -#define wxGridBagSizer_destroy 1428 -#define wxStdDialogButtonSizer_new 1429 -#define wxStdDialogButtonSizer_AddButton 1430 -#define wxStdDialogButtonSizer_Realize 1431 -#define wxStdDialogButtonSizer_SetAffirmativeButton 1432 -#define wxStdDialogButtonSizer_SetCancelButton 1433 -#define wxStdDialogButtonSizer_SetNegativeButton 1434 -#define wxStdDialogButtonSizer_destroy 1435 -#define wxFont_new_0 1436 -#define wxFont_new_1 1437 -#define wxFont_new_5 1438 -#define wxFont_destruct 1440 -#define wxFont_IsFixedWidth 1441 -#define wxFont_GetDefaultEncoding 1442 -#define wxFont_GetFaceName 1443 -#define wxFont_GetFamily 1444 -#define wxFont_GetNativeFontInfoDesc 1445 -#define wxFont_GetNativeFontInfoUserDesc 1446 -#define wxFont_GetPointSize 1447 -#define wxFont_GetStyle 1448 -#define wxFont_GetUnderlined 1449 -#define wxFont_GetWeight 1450 -#define wxFont_Ok 1451 -#define wxFont_SetDefaultEncoding 1452 -#define wxFont_SetFaceName 1453 -#define wxFont_SetFamily 1454 -#define wxFont_SetPointSize 1455 -#define wxFont_SetStyle 1456 -#define wxFont_SetUnderlined 1457 -#define wxFont_SetWeight 1458 -#define wxToolTip_Enable 1459 -#define wxToolTip_SetDelay 1460 -#define wxToolTip_new 1461 -#define wxToolTip_SetTip 1462 -#define wxToolTip_GetTip 1463 -#define wxToolTip_GetWindow 1464 -#define wxToolTip_destroy 1465 -#define wxButton_new_3 1467 -#define wxButton_new_0 1468 -#define wxButton_destruct 1469 -#define wxButton_Create 1470 -#define wxButton_GetDefaultSize 1471 -#define wxButton_SetDefault 1472 -#define wxButton_SetLabel 1473 -#define wxBitmapButton_new_4 1475 -#define wxBitmapButton_new_0 1476 -#define wxBitmapButton_Create 1477 -#define wxBitmapButton_GetBitmapDisabled 1478 -#define wxBitmapButton_GetBitmapFocus 1480 -#define wxBitmapButton_GetBitmapLabel 1482 -#define wxBitmapButton_GetBitmapSelected 1484 -#define wxBitmapButton_SetBitmapDisabled 1486 -#define wxBitmapButton_SetBitmapFocus 1487 -#define wxBitmapButton_SetBitmapLabel 1488 -#define wxBitmapButton_SetBitmapSelected 1489 -#define wxBitmapButton_destroy 1490 -#define wxToggleButton_new_0 1491 -#define wxToggleButton_new_4 1492 -#define wxToggleButton_Create 1493 -#define wxToggleButton_GetValue 1494 -#define wxToggleButton_SetValue 1495 -#define wxToggleButton_destroy 1496 -#define wxCalendarCtrl_new_0 1497 -#define wxCalendarCtrl_new_3 1498 -#define wxCalendarCtrl_Create 1499 -#define wxCalendarCtrl_destruct 1500 -#define wxCalendarCtrl_SetDate 1501 -#define wxCalendarCtrl_GetDate 1502 -#define wxCalendarCtrl_EnableYearChange 1503 -#define wxCalendarCtrl_EnableMonthChange 1504 -#define wxCalendarCtrl_EnableHolidayDisplay 1505 -#define wxCalendarCtrl_SetHeaderColours 1506 -#define wxCalendarCtrl_GetHeaderColourFg 1507 -#define wxCalendarCtrl_GetHeaderColourBg 1508 -#define wxCalendarCtrl_SetHighlightColours 1509 -#define wxCalendarCtrl_GetHighlightColourFg 1510 -#define wxCalendarCtrl_GetHighlightColourBg 1511 -#define wxCalendarCtrl_SetHolidayColours 1512 -#define wxCalendarCtrl_GetHolidayColourFg 1513 -#define wxCalendarCtrl_GetHolidayColourBg 1514 -#define wxCalendarCtrl_GetAttr 1515 -#define wxCalendarCtrl_SetAttr 1516 -#define wxCalendarCtrl_SetHoliday 1517 -#define wxCalendarCtrl_ResetAttr 1518 -#define wxCalendarCtrl_HitTest 1519 -#define wxCalendarDateAttr_new_0 1520 -#define wxCalendarDateAttr_new_2_1 1521 -#define wxCalendarDateAttr_new_2_0 1522 -#define wxCalendarDateAttr_SetTextColour 1523 -#define wxCalendarDateAttr_SetBackgroundColour 1524 -#define wxCalendarDateAttr_SetBorderColour 1525 -#define wxCalendarDateAttr_SetFont 1526 -#define wxCalendarDateAttr_SetBorder 1527 -#define wxCalendarDateAttr_SetHoliday 1528 -#define wxCalendarDateAttr_HasTextColour 1529 -#define wxCalendarDateAttr_HasBackgroundColour 1530 -#define wxCalendarDateAttr_HasBorderColour 1531 -#define wxCalendarDateAttr_HasFont 1532 -#define wxCalendarDateAttr_HasBorder 1533 -#define wxCalendarDateAttr_IsHoliday 1534 -#define wxCalendarDateAttr_GetTextColour 1535 -#define wxCalendarDateAttr_GetBackgroundColour 1536 -#define wxCalendarDateAttr_GetBorderColour 1537 -#define wxCalendarDateAttr_GetFont 1538 -#define wxCalendarDateAttr_GetBorder 1539 -#define wxCalendarDateAttr_destroy 1540 -#define wxCheckBox_new_4 1542 -#define wxCheckBox_new_0 1543 -#define wxCheckBox_Create 1544 -#define wxCheckBox_GetValue 1545 -#define wxCheckBox_Get3StateValue 1546 -#define wxCheckBox_Is3rdStateAllowedForUser 1547 -#define wxCheckBox_Is3State 1548 -#define wxCheckBox_IsChecked 1549 -#define wxCheckBox_SetValue 1550 -#define wxCheckBox_Set3StateValue 1551 -#define wxCheckBox_destroy 1552 -#define wxCheckListBox_new_0 1553 -#define wxCheckListBox_new_3 1555 -#define wxCheckListBox_Check 1556 -#define wxCheckListBox_IsChecked 1557 -#define wxCheckListBox_destroy 1558 -#define wxChoice_new_3 1561 -#define wxChoice_new_0 1562 -#define wxChoice_destruct 1564 -#define wxChoice_Create 1566 -#define wxChoice_Delete 1567 -#define wxChoice_GetColumns 1568 -#define wxChoice_SetColumns 1569 -#define wxComboBox_new_0 1570 -#define wxComboBox_new_3 1572 -#define wxComboBox_destruct 1573 -#define wxComboBox_Create 1575 -#define wxComboBox_CanCopy 1576 -#define wxComboBox_CanCut 1577 -#define wxComboBox_CanPaste 1578 -#define wxComboBox_CanRedo 1579 -#define wxComboBox_CanUndo 1580 -#define wxComboBox_Copy 1581 -#define wxComboBox_Cut 1582 -#define wxComboBox_GetInsertionPoint 1583 -#define wxComboBox_GetLastPosition 1584 -#define wxComboBox_GetValue 1585 -#define wxComboBox_Paste 1586 -#define wxComboBox_Redo 1587 -#define wxComboBox_Replace 1588 -#define wxComboBox_Remove 1589 -#define wxComboBox_SetInsertionPoint 1590 -#define wxComboBox_SetInsertionPointEnd 1591 -#define wxComboBox_SetSelection_1 1592 -#define wxComboBox_SetSelection_2 1593 -#define wxComboBox_SetValue 1594 -#define wxComboBox_Undo 1595 -#define wxGauge_new_0 1596 -#define wxGauge_new_4 1597 -#define wxGauge_Create 1598 -#define wxGauge_GetBezelFace 1599 -#define wxGauge_GetRange 1600 -#define wxGauge_GetShadowWidth 1601 -#define wxGauge_GetValue 1602 -#define wxGauge_IsVertical 1603 -#define wxGauge_SetBezelFace 1604 -#define wxGauge_SetRange 1605 -#define wxGauge_SetShadowWidth 1606 -#define wxGauge_SetValue 1607 -#define wxGauge_Pulse 1608 -#define wxGauge_destroy 1609 -#define wxGenericDirCtrl_new_0 1610 -#define wxGenericDirCtrl_new_2 1611 -#define wxGenericDirCtrl_destruct 1612 -#define wxGenericDirCtrl_Create 1613 -#define wxGenericDirCtrl_Init 1614 -#define wxGenericDirCtrl_CollapseTree 1615 -#define wxGenericDirCtrl_ExpandPath 1616 -#define wxGenericDirCtrl_GetDefaultPath 1617 -#define wxGenericDirCtrl_GetPath 1618 -#define wxGenericDirCtrl_GetFilePath 1619 -#define wxGenericDirCtrl_GetFilter 1620 -#define wxGenericDirCtrl_GetFilterIndex 1621 -#define wxGenericDirCtrl_GetRootId 1622 -#define wxGenericDirCtrl_GetTreeCtrl 1623 -#define wxGenericDirCtrl_ReCreateTree 1624 -#define wxGenericDirCtrl_SetDefaultPath 1625 -#define wxGenericDirCtrl_SetFilter 1626 -#define wxGenericDirCtrl_SetFilterIndex 1627 -#define wxGenericDirCtrl_SetPath 1628 -#define wxStaticBox_new_4 1630 -#define wxStaticBox_new_0 1631 -#define wxStaticBox_Create 1632 -#define wxStaticBox_destroy 1633 -#define wxStaticLine_new_2 1635 -#define wxStaticLine_new_0 1636 -#define wxStaticLine_Create 1637 -#define wxStaticLine_IsVertical 1638 -#define wxStaticLine_GetDefaultSize 1639 -#define wxStaticLine_destroy 1640 -#define wxListBox_new_3 1643 -#define wxListBox_new_0 1644 -#define wxListBox_destruct 1646 -#define wxListBox_Create 1648 -#define wxListBox_Deselect 1649 -#define wxListBox_GetSelections 1650 -#define wxListBox_InsertItems 1651 -#define wxListBox_IsSelected 1652 -#define wxListBox_Set 1653 -#define wxListBox_HitTest 1654 -#define wxListBox_SetFirstItem_1_0 1655 -#define wxListBox_SetFirstItem_1_1 1656 -#define wxListCtrl_new_0 1657 -#define wxListCtrl_new_2 1658 -#define wxListCtrl_Arrange 1659 -#define wxListCtrl_AssignImageList 1660 -#define wxListCtrl_ClearAll 1661 -#define wxListCtrl_Create 1662 -#define wxListCtrl_DeleteAllItems 1663 -#define wxListCtrl_DeleteColumn 1664 -#define wxListCtrl_DeleteItem 1665 -#define wxListCtrl_EditLabel 1666 -#define wxListCtrl_EnsureVisible 1667 -#define wxListCtrl_FindItem_3_0 1668 -#define wxListCtrl_FindItem_3_1 1669 -#define wxListCtrl_GetColumn 1670 -#define wxListCtrl_GetColumnCount 1671 -#define wxListCtrl_GetColumnWidth 1672 -#define wxListCtrl_GetCountPerPage 1673 -#define wxListCtrl_GetEditControl 1674 -#define wxListCtrl_GetImageList 1675 -#define wxListCtrl_GetItem 1676 -#define wxListCtrl_GetItemBackgroundColour 1677 -#define wxListCtrl_GetItemCount 1678 -#define wxListCtrl_GetItemData 1679 -#define wxListCtrl_GetItemFont 1680 -#define wxListCtrl_GetItemPosition 1681 -#define wxListCtrl_GetItemRect 1682 -#define wxListCtrl_GetItemSpacing 1683 -#define wxListCtrl_GetItemState 1684 -#define wxListCtrl_GetItemText 1685 -#define wxListCtrl_GetItemTextColour 1686 -#define wxListCtrl_GetNextItem 1687 -#define wxListCtrl_GetSelectedItemCount 1688 -#define wxListCtrl_GetTextColour 1689 -#define wxListCtrl_GetTopItem 1690 -#define wxListCtrl_GetViewRect 1691 -#define wxListCtrl_HitTest 1692 -#define wxListCtrl_InsertColumn_2 1693 -#define wxListCtrl_InsertColumn_3 1694 -#define wxListCtrl_InsertItem_1 1695 -#define wxListCtrl_InsertItem_2_1 1696 -#define wxListCtrl_InsertItem_2_0 1697 -#define wxListCtrl_InsertItem_3 1698 -#define wxListCtrl_RefreshItem 1699 -#define wxListCtrl_RefreshItems 1700 -#define wxListCtrl_ScrollList 1701 -#define wxListCtrl_SetBackgroundColour 1702 -#define wxListCtrl_SetColumn 1703 -#define wxListCtrl_SetColumnWidth 1704 -#define wxListCtrl_SetImageList 1705 -#define wxListCtrl_SetItem_1 1706 -#define wxListCtrl_SetItem_4 1707 -#define wxListCtrl_SetItemBackgroundColour 1708 -#define wxListCtrl_SetItemCount 1709 -#define wxListCtrl_SetItemData 1710 -#define wxListCtrl_SetItemFont 1711 -#define wxListCtrl_SetItemImage 1712 -#define wxListCtrl_SetItemColumnImage 1713 -#define wxListCtrl_SetItemPosition 1714 -#define wxListCtrl_SetItemState 1715 -#define wxListCtrl_SetItemText 1716 -#define wxListCtrl_SetItemTextColour 1717 -#define wxListCtrl_SetSingleStyle 1718 -#define wxListCtrl_SetTextColour 1719 -#define wxListCtrl_SetWindowStyleFlag 1720 -#define wxListCtrl_SortItems 1721 -#define wxListCtrl_destroy 1722 -#define wxListView_ClearColumnImage 1723 -#define wxListView_Focus 1724 -#define wxListView_GetFirstSelected 1725 -#define wxListView_GetFocusedItem 1726 -#define wxListView_GetNextSelected 1727 -#define wxListView_IsSelected 1728 -#define wxListView_Select 1729 -#define wxListView_SetColumnImage 1730 -#define wxListItem_new_0 1731 -#define wxListItem_new_1 1732 -#define wxListItem_destruct 1733 -#define wxListItem_Clear 1734 -#define wxListItem_GetAlign 1735 -#define wxListItem_GetBackgroundColour 1736 -#define wxListItem_GetColumn 1737 -#define wxListItem_GetFont 1738 -#define wxListItem_GetId 1739 -#define wxListItem_GetImage 1740 -#define wxListItem_GetMask 1741 -#define wxListItem_GetState 1742 -#define wxListItem_GetText 1743 -#define wxListItem_GetTextColour 1744 -#define wxListItem_GetWidth 1745 -#define wxListItem_SetAlign 1746 -#define wxListItem_SetBackgroundColour 1747 -#define wxListItem_SetColumn 1748 -#define wxListItem_SetFont 1749 -#define wxListItem_SetId 1750 -#define wxListItem_SetImage 1751 -#define wxListItem_SetMask 1752 -#define wxListItem_SetState 1753 -#define wxListItem_SetStateMask 1754 -#define wxListItem_SetText 1755 -#define wxListItem_SetTextColour 1756 -#define wxListItem_SetWidth 1757 -#define wxListItemAttr_new_0 1758 -#define wxListItemAttr_new_3 1759 -#define wxListItemAttr_GetBackgroundColour 1760 -#define wxListItemAttr_GetFont 1761 -#define wxListItemAttr_GetTextColour 1762 -#define wxListItemAttr_HasBackgroundColour 1763 -#define wxListItemAttr_HasFont 1764 -#define wxListItemAttr_HasTextColour 1765 -#define wxListItemAttr_SetBackgroundColour 1766 -#define wxListItemAttr_SetFont 1767 -#define wxListItemAttr_SetTextColour 1768 -#define wxListItemAttr_destroy 1769 -#define wxImageList_new_0 1770 -#define wxImageList_new_3 1771 -#define wxImageList_Add_1 1772 -#define wxImageList_Add_2_0 1773 -#define wxImageList_Add_2_1 1774 -#define wxImageList_Create 1775 -#define wxImageList_Draw 1777 -#define wxImageList_GetBitmap 1778 -#define wxImageList_GetIcon 1779 -#define wxImageList_GetImageCount 1780 -#define wxImageList_GetSize 1781 -#define wxImageList_Remove 1782 -#define wxImageList_RemoveAll 1783 -#define wxImageList_Replace_2 1784 -#define wxImageList_Replace_3 1785 -#define wxImageList_destroy 1786 -#define wxTextAttr_new_0 1787 -#define wxTextAttr_new_2 1788 -#define wxTextAttr_GetAlignment 1789 -#define wxTextAttr_GetBackgroundColour 1790 -#define wxTextAttr_GetFont 1791 -#define wxTextAttr_GetLeftIndent 1792 -#define wxTextAttr_GetLeftSubIndent 1793 -#define wxTextAttr_GetRightIndent 1794 -#define wxTextAttr_GetTabs 1795 -#define wxTextAttr_GetTextColour 1796 -#define wxTextAttr_HasBackgroundColour 1797 -#define wxTextAttr_HasFont 1798 -#define wxTextAttr_HasTextColour 1799 -#define wxTextAttr_GetFlags 1800 -#define wxTextAttr_IsDefault 1801 -#define wxTextAttr_SetAlignment 1802 -#define wxTextAttr_SetBackgroundColour 1803 -#define wxTextAttr_SetFlags 1804 -#define wxTextAttr_SetFont 1805 -#define wxTextAttr_SetLeftIndent 1806 -#define wxTextAttr_SetRightIndent 1807 -#define wxTextAttr_SetTabs 1808 -#define wxTextAttr_SetTextColour 1809 -#define wxTextAttr_destroy 1810 -#define wxTextCtrl_new_3 1812 -#define wxTextCtrl_new_0 1813 -#define wxTextCtrl_destruct 1815 -#define wxTextCtrl_AppendText 1816 -#define wxTextCtrl_CanCopy 1817 -#define wxTextCtrl_CanCut 1818 -#define wxTextCtrl_CanPaste 1819 -#define wxTextCtrl_CanRedo 1820 -#define wxTextCtrl_CanUndo 1821 -#define wxTextCtrl_Clear 1822 -#define wxTextCtrl_Copy 1823 -#define wxTextCtrl_Create 1824 -#define wxTextCtrl_Cut 1825 -#define wxTextCtrl_DiscardEdits 1826 -#define wxTextCtrl_ChangeValue 1827 -#define wxTextCtrl_EmulateKeyPress 1828 -#define wxTextCtrl_GetDefaultStyle 1829 -#define wxTextCtrl_GetInsertionPoint 1830 -#define wxTextCtrl_GetLastPosition 1831 -#define wxTextCtrl_GetLineLength 1832 -#define wxTextCtrl_GetLineText 1833 -#define wxTextCtrl_GetNumberOfLines 1834 -#define wxTextCtrl_GetRange 1835 -#define wxTextCtrl_GetSelection 1836 -#define wxTextCtrl_GetStringSelection 1837 -#define wxTextCtrl_GetStyle 1838 -#define wxTextCtrl_GetValue 1839 -#define wxTextCtrl_IsEditable 1840 -#define wxTextCtrl_IsModified 1841 -#define wxTextCtrl_IsMultiLine 1842 -#define wxTextCtrl_IsSingleLine 1843 -#define wxTextCtrl_LoadFile 1844 -#define wxTextCtrl_MarkDirty 1845 -#define wxTextCtrl_Paste 1846 -#define wxTextCtrl_PositionToXY 1847 -#define wxTextCtrl_Redo 1848 -#define wxTextCtrl_Remove 1849 -#define wxTextCtrl_Replace 1850 -#define wxTextCtrl_SaveFile 1851 -#define wxTextCtrl_SetDefaultStyle 1852 -#define wxTextCtrl_SetEditable 1853 -#define wxTextCtrl_SetInsertionPoint 1854 -#define wxTextCtrl_SetInsertionPointEnd 1855 -#define wxTextCtrl_SetMaxLength 1857 -#define wxTextCtrl_SetSelection 1858 -#define wxTextCtrl_SetStyle 1859 -#define wxTextCtrl_SetValue 1860 -#define wxTextCtrl_ShowPosition 1861 -#define wxTextCtrl_Undo 1862 -#define wxTextCtrl_WriteText 1863 -#define wxTextCtrl_XYToPosition 1864 -#define wxNotebook_new_0 1867 -#define wxNotebook_new_3 1868 -#define wxNotebook_destruct 1869 -#define wxNotebook_AddPage 1870 -#define wxNotebook_AdvanceSelection 1871 -#define wxNotebook_AssignImageList 1872 -#define wxNotebook_Create 1873 -#define wxNotebook_DeleteAllPages 1874 -#define wxNotebook_DeletePage 1875 -#define wxNotebook_RemovePage 1876 -#define wxNotebook_GetCurrentPage 1877 -#define wxNotebook_GetImageList 1878 -#define wxNotebook_GetPage 1880 -#define wxNotebook_GetPageCount 1881 -#define wxNotebook_GetPageImage 1882 -#define wxNotebook_GetPageText 1883 -#define wxNotebook_GetRowCount 1884 -#define wxNotebook_GetSelection 1885 -#define wxNotebook_GetThemeBackgroundColour 1886 -#define wxNotebook_HitTest 1888 -#define wxNotebook_InsertPage 1890 -#define wxNotebook_SetImageList 1891 -#define wxNotebook_SetPadding 1892 -#define wxNotebook_SetPageSize 1893 -#define wxNotebook_SetPageImage 1894 -#define wxNotebook_SetPageText 1895 -#define wxNotebook_SetSelection 1896 -#define wxNotebook_ChangeSelection 1897 -#define wxChoicebook_new_0 1898 -#define wxChoicebook_new_3 1899 -#define wxChoicebook_AddPage 1900 -#define wxChoicebook_AdvanceSelection 1901 -#define wxChoicebook_AssignImageList 1902 -#define wxChoicebook_Create 1903 -#define wxChoicebook_DeleteAllPages 1904 -#define wxChoicebook_DeletePage 1905 -#define wxChoicebook_RemovePage 1906 -#define wxChoicebook_GetCurrentPage 1907 -#define wxChoicebook_GetImageList 1908 -#define wxChoicebook_GetPage 1910 -#define wxChoicebook_GetPageCount 1911 -#define wxChoicebook_GetPageImage 1912 -#define wxChoicebook_GetPageText 1913 -#define wxChoicebook_GetSelection 1914 -#define wxChoicebook_HitTest 1915 -#define wxChoicebook_InsertPage 1916 -#define wxChoicebook_SetImageList 1917 -#define wxChoicebook_SetPageSize 1918 -#define wxChoicebook_SetPageImage 1919 -#define wxChoicebook_SetPageText 1920 -#define wxChoicebook_SetSelection 1921 -#define wxChoicebook_ChangeSelection 1922 -#define wxChoicebook_destroy 1923 -#define wxToolbook_new_0 1924 -#define wxToolbook_new_3 1925 -#define wxToolbook_AddPage 1926 -#define wxToolbook_AdvanceSelection 1927 -#define wxToolbook_AssignImageList 1928 -#define wxToolbook_Create 1929 -#define wxToolbook_DeleteAllPages 1930 -#define wxToolbook_DeletePage 1931 -#define wxToolbook_RemovePage 1932 -#define wxToolbook_GetCurrentPage 1933 -#define wxToolbook_GetImageList 1934 -#define wxToolbook_GetPage 1936 -#define wxToolbook_GetPageCount 1937 -#define wxToolbook_GetPageImage 1938 -#define wxToolbook_GetPageText 1939 -#define wxToolbook_GetSelection 1940 -#define wxToolbook_HitTest 1942 -#define wxToolbook_InsertPage 1943 -#define wxToolbook_SetImageList 1944 -#define wxToolbook_SetPageSize 1945 -#define wxToolbook_SetPageImage 1946 -#define wxToolbook_SetPageText 1947 -#define wxToolbook_SetSelection 1948 -#define wxToolbook_ChangeSelection 1949 -#define wxToolbook_destroy 1950 -#define wxListbook_new_0 1951 -#define wxListbook_new_3 1952 -#define wxListbook_AddPage 1953 -#define wxListbook_AdvanceSelection 1954 -#define wxListbook_AssignImageList 1955 -#define wxListbook_Create 1956 -#define wxListbook_DeleteAllPages 1957 -#define wxListbook_DeletePage 1958 -#define wxListbook_RemovePage 1959 -#define wxListbook_GetCurrentPage 1960 -#define wxListbook_GetImageList 1961 -#define wxListbook_GetPage 1963 -#define wxListbook_GetPageCount 1964 -#define wxListbook_GetPageImage 1965 -#define wxListbook_GetPageText 1966 -#define wxListbook_GetSelection 1967 -#define wxListbook_HitTest 1969 -#define wxListbook_InsertPage 1970 -#define wxListbook_SetImageList 1971 -#define wxListbook_SetPageSize 1972 -#define wxListbook_SetPageImage 1973 -#define wxListbook_SetPageText 1974 -#define wxListbook_SetSelection 1975 -#define wxListbook_ChangeSelection 1976 -#define wxListbook_destroy 1977 -#define wxTreebook_new_0 1978 -#define wxTreebook_new_3 1979 -#define wxTreebook_AddPage 1980 -#define wxTreebook_AdvanceSelection 1981 -#define wxTreebook_AssignImageList 1982 -#define wxTreebook_Create 1983 -#define wxTreebook_DeleteAllPages 1984 -#define wxTreebook_DeletePage 1985 -#define wxTreebook_RemovePage 1986 -#define wxTreebook_GetCurrentPage 1987 -#define wxTreebook_GetImageList 1988 -#define wxTreebook_GetPage 1990 -#define wxTreebook_GetPageCount 1991 -#define wxTreebook_GetPageImage 1992 -#define wxTreebook_GetPageText 1993 -#define wxTreebook_GetSelection 1994 -#define wxTreebook_ExpandNode 1995 -#define wxTreebook_IsNodeExpanded 1996 -#define wxTreebook_HitTest 1998 -#define wxTreebook_InsertPage 1999 -#define wxTreebook_InsertSubPage 2000 -#define wxTreebook_SetImageList 2001 -#define wxTreebook_SetPageSize 2002 -#define wxTreebook_SetPageImage 2003 -#define wxTreebook_SetPageText 2004 -#define wxTreebook_SetSelection 2005 -#define wxTreebook_ChangeSelection 2006 -#define wxTreebook_destroy 2007 -#define wxTreeCtrl_new_2 2010 -#define wxTreeCtrl_new_0 2011 -#define wxTreeCtrl_destruct 2013 -#define wxTreeCtrl_AddRoot 2014 -#define wxTreeCtrl_AppendItem 2015 -#define wxTreeCtrl_AssignImageList 2016 -#define wxTreeCtrl_AssignStateImageList 2017 -#define wxTreeCtrl_Collapse 2018 -#define wxTreeCtrl_CollapseAndReset 2019 -#define wxTreeCtrl_Create 2020 -#define wxTreeCtrl_Delete 2021 -#define wxTreeCtrl_DeleteAllItems 2022 -#define wxTreeCtrl_DeleteChildren 2023 -#define wxTreeCtrl_EditLabel 2024 -#define wxTreeCtrl_EnsureVisible 2025 -#define wxTreeCtrl_Expand 2026 -#define wxTreeCtrl_GetBoundingRect 2027 -#define wxTreeCtrl_GetChildrenCount 2029 -#define wxTreeCtrl_GetCount 2030 -#define wxTreeCtrl_GetEditControl 2031 -#define wxTreeCtrl_GetFirstChild 2032 -#define wxTreeCtrl_GetNextChild 2033 -#define wxTreeCtrl_GetFirstVisibleItem 2034 -#define wxTreeCtrl_GetImageList 2035 -#define wxTreeCtrl_GetIndent 2036 -#define wxTreeCtrl_GetItemBackgroundColour 2037 -#define wxTreeCtrl_GetItemData 2038 -#define wxTreeCtrl_GetItemFont 2039 -#define wxTreeCtrl_GetItemImage_1 2040 -#define wxTreeCtrl_GetItemImage_2 2041 -#define wxTreeCtrl_GetItemText 2042 -#define wxTreeCtrl_GetItemTextColour 2043 -#define wxTreeCtrl_GetLastChild 2044 -#define wxTreeCtrl_GetNextSibling 2045 -#define wxTreeCtrl_GetNextVisible 2046 -#define wxTreeCtrl_GetItemParent 2047 -#define wxTreeCtrl_GetPrevSibling 2048 -#define wxTreeCtrl_GetPrevVisible 2049 -#define wxTreeCtrl_GetRootItem 2050 -#define wxTreeCtrl_GetSelection 2051 -#define wxTreeCtrl_GetSelections 2052 -#define wxTreeCtrl_GetStateImageList 2053 -#define wxTreeCtrl_HitTest 2054 -#define wxTreeCtrl_InsertItem 2056 -#define wxTreeCtrl_IsBold 2057 -#define wxTreeCtrl_IsExpanded 2058 -#define wxTreeCtrl_IsSelected 2059 -#define wxTreeCtrl_IsVisible 2060 -#define wxTreeCtrl_ItemHasChildren 2061 -#define wxTreeCtrl_IsTreeItemIdOk 2062 -#define wxTreeCtrl_PrependItem 2063 -#define wxTreeCtrl_ScrollTo 2064 -#define wxTreeCtrl_SelectItem_1 2065 -#define wxTreeCtrl_SelectItem_2 2066 -#define wxTreeCtrl_SetIndent 2067 -#define wxTreeCtrl_SetImageList 2068 -#define wxTreeCtrl_SetItemBackgroundColour 2069 -#define wxTreeCtrl_SetItemBold 2070 -#define wxTreeCtrl_SetItemData 2071 -#define wxTreeCtrl_SetItemDropHighlight 2072 -#define wxTreeCtrl_SetItemFont 2073 -#define wxTreeCtrl_SetItemHasChildren 2074 -#define wxTreeCtrl_SetItemImage_2 2075 -#define wxTreeCtrl_SetItemImage_3 2076 -#define wxTreeCtrl_SetItemText 2077 -#define wxTreeCtrl_SetItemTextColour 2078 -#define wxTreeCtrl_SetStateImageList 2079 -#define wxTreeCtrl_SetWindowStyle 2080 -#define wxTreeCtrl_SortChildren 2081 -#define wxTreeCtrl_Toggle 2082 -#define wxTreeCtrl_ToggleItemSelection 2083 -#define wxTreeCtrl_Unselect 2084 -#define wxTreeCtrl_UnselectAll 2085 -#define wxTreeCtrl_UnselectItem 2086 -#define wxScrollBar_new_0 2087 -#define wxScrollBar_new_3 2088 -#define wxScrollBar_destruct 2089 -#define wxScrollBar_Create 2090 -#define wxScrollBar_GetRange 2091 -#define wxScrollBar_GetPageSize 2092 -#define wxScrollBar_GetThumbPosition 2093 -#define wxScrollBar_GetThumbSize 2094 -#define wxScrollBar_SetThumbPosition 2095 -#define wxScrollBar_SetScrollbar 2096 -#define wxSpinButton_new_2 2098 -#define wxSpinButton_new_0 2099 -#define wxSpinButton_Create 2100 -#define wxSpinButton_GetMax 2101 -#define wxSpinButton_GetMin 2102 -#define wxSpinButton_GetValue 2103 -#define wxSpinButton_SetRange 2104 -#define wxSpinButton_SetValue 2105 -#define wxSpinButton_destroy 2106 -#define wxSpinCtrl_new_0 2107 -#define wxSpinCtrl_new_2 2108 -#define wxSpinCtrl_Create 2110 -#define wxSpinCtrl_SetValue_1_1 2113 -#define wxSpinCtrl_SetValue_1_0 2114 -#define wxSpinCtrl_GetValue 2116 -#define wxSpinCtrl_SetRange 2118 -#define wxSpinCtrl_SetSelection 2119 -#define wxSpinCtrl_GetMin 2121 -#define wxSpinCtrl_GetMax 2123 -#define wxSpinCtrl_destroy 2124 -#define wxStaticText_new_0 2125 -#define wxStaticText_new_4 2126 -#define wxStaticText_Create 2127 -#define wxStaticText_GetLabel 2128 -#define wxStaticText_SetLabel 2129 -#define wxStaticText_Wrap 2130 -#define wxStaticText_destroy 2131 -#define wxStaticBitmap_new_0 2132 -#define wxStaticBitmap_new_4 2133 -#define wxStaticBitmap_Create 2134 -#define wxStaticBitmap_GetBitmap 2135 -#define wxStaticBitmap_SetBitmap 2136 -#define wxStaticBitmap_destroy 2137 -#define wxRadioBox_new 2138 -#define wxRadioBox_destruct 2140 -#define wxRadioBox_Create 2141 -#define wxRadioBox_Enable_2 2142 -#define wxRadioBox_Enable_1 2143 -#define wxRadioBox_GetSelection 2144 -#define wxRadioBox_GetString 2145 -#define wxRadioBox_SetSelection 2146 -#define wxRadioBox_Show_2 2147 -#define wxRadioBox_Show_1 2148 -#define wxRadioBox_GetColumnCount 2149 -#define wxRadioBox_GetItemHelpText 2150 -#define wxRadioBox_GetItemToolTip 2151 -#define wxRadioBox_GetItemFromPoint 2153 -#define wxRadioBox_GetRowCount 2154 -#define wxRadioBox_IsItemEnabled 2155 -#define wxRadioBox_IsItemShown 2156 -#define wxRadioBox_SetItemHelpText 2157 -#define wxRadioBox_SetItemToolTip 2158 -#define wxRadioButton_new_0 2159 -#define wxRadioButton_new_4 2160 -#define wxRadioButton_Create 2161 -#define wxRadioButton_GetValue 2162 -#define wxRadioButton_SetValue 2163 -#define wxRadioButton_destroy 2164 -#define wxSlider_new_6 2166 -#define wxSlider_new_0 2167 -#define wxSlider_Create 2168 -#define wxSlider_GetLineSize 2169 -#define wxSlider_GetMax 2170 -#define wxSlider_GetMin 2171 -#define wxSlider_GetPageSize 2172 -#define wxSlider_GetThumbLength 2173 -#define wxSlider_GetValue 2174 -#define wxSlider_SetLineSize 2175 -#define wxSlider_SetPageSize 2176 -#define wxSlider_SetRange 2177 -#define wxSlider_SetThumbLength 2178 -#define wxSlider_SetValue 2179 -#define wxSlider_destroy 2180 -#define wxDialog_new_4 2182 -#define wxDialog_new_0 2183 -#define wxDialog_destruct 2185 -#define wxDialog_Create 2186 -#define wxDialog_CreateButtonSizer 2187 -#define wxDialog_CreateStdDialogButtonSizer 2188 -#define wxDialog_EndModal 2189 -#define wxDialog_GetAffirmativeId 2190 -#define wxDialog_GetReturnCode 2191 -#define wxDialog_IsModal 2192 -#define wxDialog_SetAffirmativeId 2193 -#define wxDialog_SetReturnCode 2194 -#define wxDialog_Show 2195 -#define wxDialog_ShowModal 2196 -#define wxColourDialog_new_0 2197 -#define wxColourDialog_new_2 2198 -#define wxColourDialog_destruct 2199 -#define wxColourDialog_Create 2200 -#define wxColourDialog_GetColourData 2201 -#define wxColourData_new_0 2202 -#define wxColourData_new_1 2203 -#define wxColourData_destruct 2204 -#define wxColourData_GetChooseFull 2205 -#define wxColourData_GetColour 2206 -#define wxColourData_GetCustomColour 2208 -#define wxColourData_SetChooseFull 2209 -#define wxColourData_SetColour 2210 -#define wxColourData_SetCustomColour 2211 -#define wxPalette_new_0 2212 -#define wxPalette_new_4 2213 -#define wxPalette_destruct 2215 -#define wxPalette_Create 2216 -#define wxPalette_GetColoursCount 2217 -#define wxPalette_GetPixel 2218 -#define wxPalette_GetRGB 2219 -#define wxPalette_IsOk 2220 -#define wxDirDialog_new 2224 -#define wxDirDialog_destruct 2225 -#define wxDirDialog_GetPath 2226 -#define wxDirDialog_GetMessage 2227 -#define wxDirDialog_SetMessage 2228 -#define wxDirDialog_SetPath 2229 -#define wxFileDialog_new 2233 -#define wxFileDialog_destruct 2234 -#define wxFileDialog_GetDirectory 2235 -#define wxFileDialog_GetFilename 2236 -#define wxFileDialog_GetFilenames 2237 -#define wxFileDialog_GetFilterIndex 2238 -#define wxFileDialog_GetMessage 2239 -#define wxFileDialog_GetPath 2240 -#define wxFileDialog_GetPaths 2241 -#define wxFileDialog_GetWildcard 2242 -#define wxFileDialog_SetDirectory 2243 -#define wxFileDialog_SetFilename 2244 -#define wxFileDialog_SetFilterIndex 2245 -#define wxFileDialog_SetMessage 2246 -#define wxFileDialog_SetPath 2247 -#define wxFileDialog_SetWildcard 2248 -#define wxPickerBase_SetInternalMargin 2249 -#define wxPickerBase_GetInternalMargin 2250 -#define wxPickerBase_SetTextCtrlProportion 2251 -#define wxPickerBase_SetPickerCtrlProportion 2252 -#define wxPickerBase_GetTextCtrlProportion 2253 -#define wxPickerBase_GetPickerCtrlProportion 2254 -#define wxPickerBase_HasTextCtrl 2255 -#define wxPickerBase_GetTextCtrl 2256 -#define wxPickerBase_IsTextCtrlGrowable 2257 -#define wxPickerBase_SetPickerCtrlGrowable 2258 -#define wxPickerBase_SetTextCtrlGrowable 2259 -#define wxPickerBase_IsPickerCtrlGrowable 2260 -#define wxFilePickerCtrl_new_0 2261 -#define wxFilePickerCtrl_new_3 2262 -#define wxFilePickerCtrl_Create 2263 -#define wxFilePickerCtrl_GetPath 2264 -#define wxFilePickerCtrl_SetPath 2265 -#define wxFilePickerCtrl_destroy 2266 -#define wxDirPickerCtrl_new_0 2267 -#define wxDirPickerCtrl_new_3 2268 -#define wxDirPickerCtrl_Create 2269 -#define wxDirPickerCtrl_GetPath 2270 -#define wxDirPickerCtrl_SetPath 2271 -#define wxDirPickerCtrl_destroy 2272 -#define wxColourPickerCtrl_new_0 2273 -#define wxColourPickerCtrl_new_3 2274 -#define wxColourPickerCtrl_Create 2275 -#define wxColourPickerCtrl_GetColour 2276 -#define wxColourPickerCtrl_SetColour_1_1 2277 -#define wxColourPickerCtrl_SetColour_1_0 2278 -#define wxColourPickerCtrl_destroy 2279 -#define wxDatePickerCtrl_new_0 2280 -#define wxDatePickerCtrl_new_3 2281 -#define wxDatePickerCtrl_GetRange 2282 -#define wxDatePickerCtrl_GetValue 2283 -#define wxDatePickerCtrl_SetRange 2284 -#define wxDatePickerCtrl_SetValue 2285 -#define wxDatePickerCtrl_destroy 2286 -#define wxFontPickerCtrl_new_0 2287 -#define wxFontPickerCtrl_new_3 2288 -#define wxFontPickerCtrl_Create 2289 -#define wxFontPickerCtrl_GetSelectedFont 2290 -#define wxFontPickerCtrl_SetSelectedFont 2291 -#define wxFontPickerCtrl_GetMaxPointSize 2292 -#define wxFontPickerCtrl_SetMaxPointSize 2293 -#define wxFontPickerCtrl_destroy 2294 -#define wxFindReplaceDialog_new_0 2297 -#define wxFindReplaceDialog_new_4 2298 -#define wxFindReplaceDialog_destruct 2299 -#define wxFindReplaceDialog_Create 2300 -#define wxFindReplaceDialog_GetData 2301 -#define wxFindReplaceData_new_0 2302 -#define wxFindReplaceData_new_1 2303 -#define wxFindReplaceData_GetFindString 2304 -#define wxFindReplaceData_GetReplaceString 2305 -#define wxFindReplaceData_GetFlags 2306 -#define wxFindReplaceData_SetFlags 2307 -#define wxFindReplaceData_SetFindString 2308 -#define wxFindReplaceData_SetReplaceString 2309 -#define wxFindReplaceData_destroy 2310 -#define wxMultiChoiceDialog_new_0 2311 -#define wxMultiChoiceDialog_new_5 2313 -#define wxMultiChoiceDialog_GetSelections 2314 -#define wxMultiChoiceDialog_SetSelections 2315 -#define wxMultiChoiceDialog_destroy 2316 -#define wxSingleChoiceDialog_new_0 2317 -#define wxSingleChoiceDialog_new_5 2319 -#define wxSingleChoiceDialog_GetSelection 2320 -#define wxSingleChoiceDialog_GetStringSelection 2321 -#define wxSingleChoiceDialog_SetSelection 2322 -#define wxSingleChoiceDialog_destroy 2323 -#define wxTextEntryDialog_new 2324 -#define wxTextEntryDialog_GetValue 2325 -#define wxTextEntryDialog_SetValue 2326 -#define wxTextEntryDialog_destroy 2327 -#define wxPasswordEntryDialog_new 2328 -#define wxPasswordEntryDialog_destroy 2329 -#define wxFontData_new_0 2330 -#define wxFontData_new_1 2331 -#define wxFontData_destruct 2332 -#define wxFontData_EnableEffects 2333 -#define wxFontData_GetAllowSymbols 2334 -#define wxFontData_GetColour 2335 -#define wxFontData_GetChosenFont 2336 -#define wxFontData_GetEnableEffects 2337 -#define wxFontData_GetInitialFont 2338 -#define wxFontData_GetShowHelp 2339 -#define wxFontData_SetAllowSymbols 2340 -#define wxFontData_SetChosenFont 2341 -#define wxFontData_SetColour 2342 -#define wxFontData_SetInitialFont 2343 -#define wxFontData_SetRange 2344 -#define wxFontData_SetShowHelp 2345 -#define wxFontDialog_new_0 2349 -#define wxFontDialog_new_2 2351 -#define wxFontDialog_Create 2353 -#define wxFontDialog_GetFontData 2354 -#define wxFontDialog_destroy 2356 -#define wxProgressDialog_new 2357 -#define wxProgressDialog_destruct 2358 -#define wxProgressDialog_Resume 2359 -#define wxProgressDialog_Update_2 2360 -#define wxProgressDialog_Update_0 2361 -#define wxMessageDialog_new 2362 -#define wxMessageDialog_destruct 2363 -#define wxPageSetupDialog_new 2364 -#define wxPageSetupDialog_destruct 2365 -#define wxPageSetupDialog_GetPageSetupData 2366 -#define wxPageSetupDialog_ShowModal 2367 -#define wxPageSetupDialogData_new_0 2368 -#define wxPageSetupDialogData_new_1_0 2369 -#define wxPageSetupDialogData_new_1_1 2370 -#define wxPageSetupDialogData_destruct 2371 -#define wxPageSetupDialogData_EnableHelp 2372 -#define wxPageSetupDialogData_EnableMargins 2373 -#define wxPageSetupDialogData_EnableOrientation 2374 -#define wxPageSetupDialogData_EnablePaper 2375 -#define wxPageSetupDialogData_EnablePrinter 2376 -#define wxPageSetupDialogData_GetDefaultMinMargins 2377 -#define wxPageSetupDialogData_GetEnableMargins 2378 -#define wxPageSetupDialogData_GetEnableOrientation 2379 -#define wxPageSetupDialogData_GetEnablePaper 2380 -#define wxPageSetupDialogData_GetEnablePrinter 2381 -#define wxPageSetupDialogData_GetEnableHelp 2382 -#define wxPageSetupDialogData_GetDefaultInfo 2383 -#define wxPageSetupDialogData_GetMarginTopLeft 2384 -#define wxPageSetupDialogData_GetMarginBottomRight 2385 -#define wxPageSetupDialogData_GetMinMarginTopLeft 2386 -#define wxPageSetupDialogData_GetMinMarginBottomRight 2387 -#define wxPageSetupDialogData_GetPaperId 2388 -#define wxPageSetupDialogData_GetPaperSize 2389 -#define wxPageSetupDialogData_GetPrintData 2391 -#define wxPageSetupDialogData_IsOk 2392 -#define wxPageSetupDialogData_SetDefaultInfo 2393 -#define wxPageSetupDialogData_SetDefaultMinMargins 2394 -#define wxPageSetupDialogData_SetMarginTopLeft 2395 -#define wxPageSetupDialogData_SetMarginBottomRight 2396 -#define wxPageSetupDialogData_SetMinMarginTopLeft 2397 -#define wxPageSetupDialogData_SetMinMarginBottomRight 2398 -#define wxPageSetupDialogData_SetPaperId 2399 -#define wxPageSetupDialogData_SetPaperSize_1_1 2400 -#define wxPageSetupDialogData_SetPaperSize_1_0 2401 -#define wxPageSetupDialogData_SetPrintData 2402 -#define wxPrintDialog_new_2_0 2403 -#define wxPrintDialog_new_2_1 2404 -#define wxPrintDialog_destruct 2405 -#define wxPrintDialog_GetPrintDialogData 2406 -#define wxPrintDialog_GetPrintDC 2407 -#define wxPrintDialogData_new_0 2408 -#define wxPrintDialogData_new_1_1 2409 -#define wxPrintDialogData_new_1_0 2410 -#define wxPrintDialogData_destruct 2411 -#define wxPrintDialogData_EnableHelp 2412 -#define wxPrintDialogData_EnablePageNumbers 2413 -#define wxPrintDialogData_EnablePrintToFile 2414 -#define wxPrintDialogData_EnableSelection 2415 -#define wxPrintDialogData_GetAllPages 2416 -#define wxPrintDialogData_GetCollate 2417 -#define wxPrintDialogData_GetFromPage 2418 -#define wxPrintDialogData_GetMaxPage 2419 -#define wxPrintDialogData_GetMinPage 2420 -#define wxPrintDialogData_GetNoCopies 2421 -#define wxPrintDialogData_GetPrintData 2422 -#define wxPrintDialogData_GetPrintToFile 2423 -#define wxPrintDialogData_GetSelection 2424 -#define wxPrintDialogData_GetToPage 2425 -#define wxPrintDialogData_IsOk 2426 -#define wxPrintDialogData_SetCollate 2427 -#define wxPrintDialogData_SetFromPage 2428 -#define wxPrintDialogData_SetMaxPage 2429 -#define wxPrintDialogData_SetMinPage 2430 -#define wxPrintDialogData_SetNoCopies 2431 -#define wxPrintDialogData_SetPrintData 2432 -#define wxPrintDialogData_SetPrintToFile 2433 -#define wxPrintDialogData_SetSelection 2434 -#define wxPrintDialogData_SetToPage 2435 -#define wxPrintData_new_0 2436 -#define wxPrintData_new_1 2437 -#define wxPrintData_destruct 2438 -#define wxPrintData_GetCollate 2439 -#define wxPrintData_GetBin 2440 -#define wxPrintData_GetColour 2441 -#define wxPrintData_GetDuplex 2442 -#define wxPrintData_GetNoCopies 2443 -#define wxPrintData_GetOrientation 2444 -#define wxPrintData_GetPaperId 2445 -#define wxPrintData_GetPrinterName 2446 -#define wxPrintData_GetQuality 2447 -#define wxPrintData_IsOk 2448 -#define wxPrintData_SetBin 2449 -#define wxPrintData_SetCollate 2450 -#define wxPrintData_SetColour 2451 -#define wxPrintData_SetDuplex 2452 -#define wxPrintData_SetNoCopies 2453 -#define wxPrintData_SetOrientation 2454 -#define wxPrintData_SetPaperId 2455 -#define wxPrintData_SetPrinterName 2456 -#define wxPrintData_SetQuality 2457 -#define wxPrintPreview_new_2 2460 -#define wxPrintPreview_new_3 2461 -#define wxPrintPreview_destruct 2463 -#define wxPrintPreview_GetCanvas 2464 -#define wxPrintPreview_GetCurrentPage 2465 -#define wxPrintPreview_GetFrame 2466 -#define wxPrintPreview_GetMaxPage 2467 -#define wxPrintPreview_GetMinPage 2468 -#define wxPrintPreview_GetPrintout 2469 -#define wxPrintPreview_GetPrintoutForPrinting 2470 -#define wxPrintPreview_IsOk 2471 -#define wxPrintPreview_PaintPage 2472 -#define wxPrintPreview_Print 2473 -#define wxPrintPreview_RenderPage 2474 -#define wxPrintPreview_SetCanvas 2475 -#define wxPrintPreview_SetCurrentPage 2476 -#define wxPrintPreview_SetFrame 2477 -#define wxPrintPreview_SetPrintout 2478 -#define wxPrintPreview_SetZoom 2479 -#define wxPreviewFrame_new 2480 -#define wxPreviewFrame_destruct 2481 -#define wxPreviewFrame_CreateControlBar 2482 -#define wxPreviewFrame_CreateCanvas 2483 -#define wxPreviewFrame_Initialize 2484 -#define wxPreviewFrame_OnCloseWindow 2485 -#define wxPreviewControlBar_new 2486 -#define wxPreviewControlBar_destruct 2487 -#define wxPreviewControlBar_CreateButtons 2488 -#define wxPreviewControlBar_GetPrintPreview 2489 -#define wxPreviewControlBar_GetZoomControl 2490 -#define wxPreviewControlBar_SetZoomControl 2491 -#define wxPrinter_new 2493 -#define wxPrinter_CreateAbortWindow 2494 -#define wxPrinter_GetAbort 2495 -#define wxPrinter_GetLastError 2496 -#define wxPrinter_GetPrintDialogData 2497 -#define wxPrinter_Print 2498 -#define wxPrinter_PrintDialog 2499 -#define wxPrinter_ReportError 2500 -#define wxPrinter_Setup 2501 -#define wxPrinter_destroy 2502 -#define wxXmlResource_new_1 2503 -#define wxXmlResource_new_2 2504 -#define wxXmlResource_destruct 2505 -#define wxXmlResource_AttachUnknownControl 2506 -#define wxXmlResource_ClearHandlers 2507 -#define wxXmlResource_CompareVersion 2508 -#define wxXmlResource_Get 2509 -#define wxXmlResource_GetFlags 2510 -#define wxXmlResource_GetVersion 2511 -#define wxXmlResource_GetXRCID 2512 -#define wxXmlResource_InitAllHandlers 2513 -#define wxXmlResource_Load 2514 -#define wxXmlResource_LoadBitmap 2515 -#define wxXmlResource_LoadDialog_2 2516 -#define wxXmlResource_LoadDialog_3 2517 -#define wxXmlResource_LoadFrame_2 2518 -#define wxXmlResource_LoadFrame_3 2519 -#define wxXmlResource_LoadIcon 2520 -#define wxXmlResource_LoadMenu 2521 -#define wxXmlResource_LoadMenuBar_2 2522 -#define wxXmlResource_LoadMenuBar_1 2523 -#define wxXmlResource_LoadPanel_2 2524 -#define wxXmlResource_LoadPanel_3 2525 -#define wxXmlResource_LoadToolBar 2526 -#define wxXmlResource_Set 2527 -#define wxXmlResource_SetFlags 2528 -#define wxXmlResource_Unload 2529 -#define wxXmlResource_xrcctrl 2530 -#define wxHtmlEasyPrinting_new 2531 -#define wxHtmlEasyPrinting_destruct 2532 -#define wxHtmlEasyPrinting_GetPrintData 2533 -#define wxHtmlEasyPrinting_GetPageSetupData 2534 -#define wxHtmlEasyPrinting_PreviewFile 2535 -#define wxHtmlEasyPrinting_PreviewText 2536 -#define wxHtmlEasyPrinting_PrintFile 2537 -#define wxHtmlEasyPrinting_PrintText 2538 -#define wxHtmlEasyPrinting_PageSetup 2539 -#define wxHtmlEasyPrinting_SetFonts 2540 -#define wxHtmlEasyPrinting_SetHeader 2541 -#define wxHtmlEasyPrinting_SetFooter 2542 -#define wxGLCanvas_new_2 2544 -#define wxGLCanvas_new_3_1 2545 -#define wxGLCanvas_new_3_0 2546 -#define wxGLCanvas_GetContext 2547 -#define wxGLCanvas_SetCurrent 2549 -#define wxGLCanvas_SwapBuffers 2550 -#define wxGLCanvas_destroy 2551 -#define wxAuiManager_new 2552 -#define wxAuiManager_destruct 2553 -#define wxAuiManager_AddPane_2_1 2554 -#define wxAuiManager_AddPane_3 2555 -#define wxAuiManager_AddPane_2_0 2556 -#define wxAuiManager_DetachPane 2557 -#define wxAuiManager_GetAllPanes 2558 -#define wxAuiManager_GetArtProvider 2559 -#define wxAuiManager_GetDockSizeConstraint 2560 -#define wxAuiManager_GetFlags 2561 -#define wxAuiManager_GetManagedWindow 2562 -#define wxAuiManager_GetManager 2563 -#define wxAuiManager_GetPane_1_1 2564 -#define wxAuiManager_GetPane_1_0 2565 -#define wxAuiManager_HideHint 2566 -#define wxAuiManager_InsertPane 2567 -#define wxAuiManager_LoadPaneInfo 2568 -#define wxAuiManager_LoadPerspective 2569 -#define wxAuiManager_SavePaneInfo 2570 -#define wxAuiManager_SavePerspective 2571 -#define wxAuiManager_SetArtProvider 2572 -#define wxAuiManager_SetDockSizeConstraint 2573 -#define wxAuiManager_SetFlags 2574 -#define wxAuiManager_SetManagedWindow 2575 -#define wxAuiManager_ShowHint 2576 -#define wxAuiManager_UnInit 2577 -#define wxAuiManager_Update 2578 -#define wxAuiPaneInfo_new_0 2579 -#define wxAuiPaneInfo_new_1 2580 -#define wxAuiPaneInfo_destruct 2581 -#define wxAuiPaneInfo_BestSize_1 2582 -#define wxAuiPaneInfo_BestSize_2 2583 -#define wxAuiPaneInfo_Bottom 2584 -#define wxAuiPaneInfo_BottomDockable 2585 -#define wxAuiPaneInfo_Caption 2586 -#define wxAuiPaneInfo_CaptionVisible 2587 -#define wxAuiPaneInfo_Centre 2588 -#define wxAuiPaneInfo_CentrePane 2589 -#define wxAuiPaneInfo_CloseButton 2590 -#define wxAuiPaneInfo_DefaultPane 2591 -#define wxAuiPaneInfo_DestroyOnClose 2592 -#define wxAuiPaneInfo_Direction 2593 -#define wxAuiPaneInfo_Dock 2594 -#define wxAuiPaneInfo_Dockable 2595 -#define wxAuiPaneInfo_Fixed 2596 -#define wxAuiPaneInfo_Float 2597 -#define wxAuiPaneInfo_Floatable 2598 -#define wxAuiPaneInfo_FloatingPosition_1 2599 -#define wxAuiPaneInfo_FloatingPosition_2 2600 -#define wxAuiPaneInfo_FloatingSize_1 2601 -#define wxAuiPaneInfo_FloatingSize_2 2602 -#define wxAuiPaneInfo_Gripper 2603 -#define wxAuiPaneInfo_GripperTop 2604 -#define wxAuiPaneInfo_HasBorder 2605 -#define wxAuiPaneInfo_HasCaption 2606 -#define wxAuiPaneInfo_HasCloseButton 2607 -#define wxAuiPaneInfo_HasFlag 2608 -#define wxAuiPaneInfo_HasGripper 2609 -#define wxAuiPaneInfo_HasGripperTop 2610 -#define wxAuiPaneInfo_HasMaximizeButton 2611 -#define wxAuiPaneInfo_HasMinimizeButton 2612 -#define wxAuiPaneInfo_HasPinButton 2613 -#define wxAuiPaneInfo_Hide 2614 -#define wxAuiPaneInfo_IsBottomDockable 2615 -#define wxAuiPaneInfo_IsDocked 2616 -#define wxAuiPaneInfo_IsFixed 2617 -#define wxAuiPaneInfo_IsFloatable 2618 -#define wxAuiPaneInfo_IsFloating 2619 -#define wxAuiPaneInfo_IsLeftDockable 2620 -#define wxAuiPaneInfo_IsMovable 2621 -#define wxAuiPaneInfo_IsOk 2622 -#define wxAuiPaneInfo_IsResizable 2623 -#define wxAuiPaneInfo_IsRightDockable 2624 -#define wxAuiPaneInfo_IsShown 2625 -#define wxAuiPaneInfo_IsToolbar 2626 -#define wxAuiPaneInfo_IsTopDockable 2627 -#define wxAuiPaneInfo_Layer 2628 -#define wxAuiPaneInfo_Left 2629 -#define wxAuiPaneInfo_LeftDockable 2630 -#define wxAuiPaneInfo_MaxSize_1 2631 -#define wxAuiPaneInfo_MaxSize_2 2632 -#define wxAuiPaneInfo_MaximizeButton 2633 -#define wxAuiPaneInfo_MinSize_1 2634 -#define wxAuiPaneInfo_MinSize_2 2635 -#define wxAuiPaneInfo_MinimizeButton 2636 -#define wxAuiPaneInfo_Movable 2637 -#define wxAuiPaneInfo_Name 2638 -#define wxAuiPaneInfo_PaneBorder 2639 -#define wxAuiPaneInfo_PinButton 2640 -#define wxAuiPaneInfo_Position 2641 -#define wxAuiPaneInfo_Resizable 2642 -#define wxAuiPaneInfo_Right 2643 -#define wxAuiPaneInfo_RightDockable 2644 -#define wxAuiPaneInfo_Row 2645 -#define wxAuiPaneInfo_SafeSet 2646 -#define wxAuiPaneInfo_SetFlag 2647 -#define wxAuiPaneInfo_Show 2648 -#define wxAuiPaneInfo_ToolbarPane 2649 -#define wxAuiPaneInfo_Top 2650 -#define wxAuiPaneInfo_TopDockable 2651 -#define wxAuiPaneInfo_Window 2652 -#define wxAuiNotebook_new_0 2653 -#define wxAuiNotebook_new_2 2654 -#define wxAuiNotebook_AddPage 2655 -#define wxAuiNotebook_Create 2656 -#define wxAuiNotebook_DeletePage 2657 -#define wxAuiNotebook_GetArtProvider 2658 -#define wxAuiNotebook_GetPage 2659 -#define wxAuiNotebook_GetPageBitmap 2660 -#define wxAuiNotebook_GetPageCount 2661 -#define wxAuiNotebook_GetPageIndex 2662 -#define wxAuiNotebook_GetPageText 2663 -#define wxAuiNotebook_GetSelection 2664 -#define wxAuiNotebook_InsertPage 2665 -#define wxAuiNotebook_RemovePage 2666 -#define wxAuiNotebook_SetArtProvider 2667 -#define wxAuiNotebook_SetFont 2668 -#define wxAuiNotebook_SetPageBitmap 2669 -#define wxAuiNotebook_SetPageText 2670 -#define wxAuiNotebook_SetSelection 2671 -#define wxAuiNotebook_SetTabCtrlHeight 2672 -#define wxAuiNotebook_SetUniformBitmapSize 2673 -#define wxAuiNotebook_destroy 2674 -#define wxMDIParentFrame_new_0 2675 -#define wxMDIParentFrame_new_4 2676 -#define wxMDIParentFrame_destruct 2677 -#define wxMDIParentFrame_ActivateNext 2678 -#define wxMDIParentFrame_ActivatePrevious 2679 -#define wxMDIParentFrame_ArrangeIcons 2680 -#define wxMDIParentFrame_Cascade 2681 -#define wxMDIParentFrame_Create 2682 -#define wxMDIParentFrame_GetActiveChild 2683 -#define wxMDIParentFrame_GetClientWindow 2684 -#define wxMDIParentFrame_Tile 2685 -#define wxMDIChildFrame_new_0 2686 -#define wxMDIChildFrame_new_4 2687 -#define wxMDIChildFrame_destruct 2688 -#define wxMDIChildFrame_Activate 2689 -#define wxMDIChildFrame_Create 2690 -#define wxMDIChildFrame_Maximize 2691 -#define wxMDIChildFrame_Restore 2692 -#define wxMDIClientWindow_new_0 2693 -#define wxMDIClientWindow_new_2 2694 -#define wxMDIClientWindow_destruct 2695 -#define wxMDIClientWindow_CreateClient 2696 -#define wxLayoutAlgorithm_new 2697 -#define wxLayoutAlgorithm_LayoutFrame 2698 -#define wxLayoutAlgorithm_LayoutMDIFrame 2699 -#define wxLayoutAlgorithm_LayoutWindow 2700 -#define wxLayoutAlgorithm_destroy 2701 -#define wxEvent_GetId 2702 -#define wxEvent_GetSkipped 2703 -#define wxEvent_GetTimestamp 2704 -#define wxEvent_IsCommandEvent 2705 -#define wxEvent_ResumePropagation 2706 -#define wxEvent_ShouldPropagate 2707 -#define wxEvent_Skip 2708 -#define wxEvent_StopPropagation 2709 -#define wxCommandEvent_getClientData 2710 -#define wxCommandEvent_GetExtraLong 2711 -#define wxCommandEvent_GetInt 2712 -#define wxCommandEvent_GetSelection 2713 -#define wxCommandEvent_GetString 2714 -#define wxCommandEvent_IsChecked 2715 -#define wxCommandEvent_IsSelection 2716 -#define wxCommandEvent_SetInt 2717 -#define wxCommandEvent_SetString 2718 -#define wxScrollEvent_GetOrientation 2719 -#define wxScrollEvent_GetPosition 2720 -#define wxScrollWinEvent_GetOrientation 2721 -#define wxScrollWinEvent_GetPosition 2722 -#define wxMouseEvent_AltDown 2723 -#define wxMouseEvent_Button 2724 -#define wxMouseEvent_ButtonDClick 2725 -#define wxMouseEvent_ButtonDown 2726 -#define wxMouseEvent_ButtonUp 2727 -#define wxMouseEvent_CmdDown 2728 -#define wxMouseEvent_ControlDown 2729 -#define wxMouseEvent_Dragging 2730 -#define wxMouseEvent_Entering 2731 -#define wxMouseEvent_GetButton 2732 -#define wxMouseEvent_GetPosition 2735 -#define wxMouseEvent_GetLogicalPosition 2736 -#define wxMouseEvent_GetLinesPerAction 2737 -#define wxMouseEvent_GetWheelRotation 2738 -#define wxMouseEvent_GetWheelDelta 2739 -#define wxMouseEvent_GetX 2740 -#define wxMouseEvent_GetY 2741 -#define wxMouseEvent_IsButton 2742 -#define wxMouseEvent_IsPageScroll 2743 -#define wxMouseEvent_Leaving 2744 -#define wxMouseEvent_LeftDClick 2745 -#define wxMouseEvent_LeftDown 2746 -#define wxMouseEvent_LeftIsDown 2747 -#define wxMouseEvent_LeftUp 2748 -#define wxMouseEvent_MetaDown 2749 -#define wxMouseEvent_MiddleDClick 2750 -#define wxMouseEvent_MiddleDown 2751 -#define wxMouseEvent_MiddleIsDown 2752 -#define wxMouseEvent_MiddleUp 2753 -#define wxMouseEvent_Moving 2754 -#define wxMouseEvent_RightDClick 2755 -#define wxMouseEvent_RightDown 2756 -#define wxMouseEvent_RightIsDown 2757 -#define wxMouseEvent_RightUp 2758 -#define wxMouseEvent_ShiftDown 2759 -#define wxSetCursorEvent_GetCursor 2760 -#define wxSetCursorEvent_GetX 2761 -#define wxSetCursorEvent_GetY 2762 -#define wxSetCursorEvent_HasCursor 2763 -#define wxSetCursorEvent_SetCursor 2764 -#define wxKeyEvent_AltDown 2765 -#define wxKeyEvent_CmdDown 2766 -#define wxKeyEvent_ControlDown 2767 -#define wxKeyEvent_GetKeyCode 2768 -#define wxKeyEvent_GetModifiers 2769 -#define wxKeyEvent_GetPosition 2772 -#define wxKeyEvent_GetRawKeyCode 2773 -#define wxKeyEvent_GetRawKeyFlags 2774 -#define wxKeyEvent_GetUnicodeKey 2775 -#define wxKeyEvent_GetX 2776 -#define wxKeyEvent_GetY 2777 -#define wxKeyEvent_HasModifiers 2778 -#define wxKeyEvent_MetaDown 2779 -#define wxKeyEvent_ShiftDown 2780 -#define wxSizeEvent_GetSize 2781 -#define wxMoveEvent_GetPosition 2782 -#define wxEraseEvent_GetDC 2783 -#define wxFocusEvent_GetWindow 2784 -#define wxChildFocusEvent_GetWindow 2785 -#define wxMenuEvent_GetMenu 2786 -#define wxMenuEvent_GetMenuId 2787 -#define wxMenuEvent_IsPopup 2788 -#define wxCloseEvent_CanVeto 2789 -#define wxCloseEvent_GetLoggingOff 2790 -#define wxCloseEvent_SetCanVeto 2791 -#define wxCloseEvent_SetLoggingOff 2792 -#define wxCloseEvent_Veto 2793 -#define wxShowEvent_SetShow 2794 -#define wxShowEvent_GetShow 2795 -#define wxIconizeEvent_Iconized 2796 -#define wxJoystickEvent_ButtonDown 2797 -#define wxJoystickEvent_ButtonIsDown 2798 -#define wxJoystickEvent_ButtonUp 2799 -#define wxJoystickEvent_GetButtonChange 2800 -#define wxJoystickEvent_GetButtonState 2801 -#define wxJoystickEvent_GetJoystick 2802 -#define wxJoystickEvent_GetPosition 2803 -#define wxJoystickEvent_GetZPosition 2804 -#define wxJoystickEvent_IsButton 2805 -#define wxJoystickEvent_IsMove 2806 -#define wxJoystickEvent_IsZMove 2807 -#define wxUpdateUIEvent_CanUpdate 2808 -#define wxUpdateUIEvent_Check 2809 -#define wxUpdateUIEvent_Enable 2810 -#define wxUpdateUIEvent_Show 2811 -#define wxUpdateUIEvent_GetChecked 2812 -#define wxUpdateUIEvent_GetEnabled 2813 -#define wxUpdateUIEvent_GetShown 2814 -#define wxUpdateUIEvent_GetSetChecked 2815 -#define wxUpdateUIEvent_GetSetEnabled 2816 -#define wxUpdateUIEvent_GetSetShown 2817 -#define wxUpdateUIEvent_GetSetText 2818 -#define wxUpdateUIEvent_GetText 2819 -#define wxUpdateUIEvent_GetMode 2820 -#define wxUpdateUIEvent_GetUpdateInterval 2821 -#define wxUpdateUIEvent_ResetUpdateTime 2822 -#define wxUpdateUIEvent_SetMode 2823 -#define wxUpdateUIEvent_SetText 2824 -#define wxUpdateUIEvent_SetUpdateInterval 2825 -#define wxMouseCaptureChangedEvent_GetCapturedWindow 2826 -#define wxPaletteChangedEvent_SetChangedWindow 2827 -#define wxPaletteChangedEvent_GetChangedWindow 2828 -#define wxQueryNewPaletteEvent_SetPaletteRealized 2829 -#define wxQueryNewPaletteEvent_GetPaletteRealized 2830 -#define wxNavigationKeyEvent_GetDirection 2831 -#define wxNavigationKeyEvent_SetDirection 2832 -#define wxNavigationKeyEvent_IsWindowChange 2833 -#define wxNavigationKeyEvent_SetWindowChange 2834 -#define wxNavigationKeyEvent_IsFromTab 2835 -#define wxNavigationKeyEvent_SetFromTab 2836 -#define wxNavigationKeyEvent_GetCurrentFocus 2837 -#define wxNavigationKeyEvent_SetCurrentFocus 2838 -#define wxHelpEvent_GetOrigin 2839 -#define wxHelpEvent_GetPosition 2840 -#define wxHelpEvent_SetOrigin 2841 -#define wxHelpEvent_SetPosition 2842 -#define wxContextMenuEvent_GetPosition 2843 -#define wxContextMenuEvent_SetPosition 2844 -#define wxIdleEvent_CanSend 2845 -#define wxIdleEvent_GetMode 2846 -#define wxIdleEvent_RequestMore 2847 -#define wxIdleEvent_MoreRequested 2848 -#define wxIdleEvent_SetMode 2849 -#define wxGridEvent_AltDown 2850 -#define wxGridEvent_ControlDown 2851 -#define wxGridEvent_GetCol 2852 -#define wxGridEvent_GetPosition 2853 -#define wxGridEvent_GetRow 2854 -#define wxGridEvent_MetaDown 2855 -#define wxGridEvent_Selecting 2856 -#define wxGridEvent_ShiftDown 2857 -#define wxNotifyEvent_Allow 2858 -#define wxNotifyEvent_IsAllowed 2859 -#define wxNotifyEvent_Veto 2860 -#define wxSashEvent_GetEdge 2861 -#define wxSashEvent_GetDragRect 2862 -#define wxSashEvent_GetDragStatus 2863 -#define wxListEvent_GetCacheFrom 2864 -#define wxListEvent_GetCacheTo 2865 -#define wxListEvent_GetKeyCode 2866 -#define wxListEvent_GetIndex 2867 -#define wxListEvent_GetColumn 2868 -#define wxListEvent_GetPoint 2869 -#define wxListEvent_GetLabel 2870 -#define wxListEvent_GetText 2871 -#define wxListEvent_GetImage 2872 -#define wxListEvent_GetData 2873 -#define wxListEvent_GetMask 2874 -#define wxListEvent_GetItem 2875 -#define wxListEvent_IsEditCancelled 2876 -#define wxDateEvent_GetDate 2877 -#define wxCalendarEvent_GetWeekDay 2878 -#define wxFileDirPickerEvent_GetPath 2879 -#define wxColourPickerEvent_GetColour 2880 -#define wxFontPickerEvent_GetFont 2881 -#define wxStyledTextEvent_GetPosition 2882 -#define wxStyledTextEvent_GetKey 2883 -#define wxStyledTextEvent_GetModifiers 2884 -#define wxStyledTextEvent_GetModificationType 2885 -#define wxStyledTextEvent_GetText 2886 -#define wxStyledTextEvent_GetLength 2887 -#define wxStyledTextEvent_GetLinesAdded 2888 -#define wxStyledTextEvent_GetLine 2889 -#define wxStyledTextEvent_GetFoldLevelNow 2890 -#define wxStyledTextEvent_GetFoldLevelPrev 2891 -#define wxStyledTextEvent_GetMargin 2892 -#define wxStyledTextEvent_GetMessage 2893 -#define wxStyledTextEvent_GetWParam 2894 -#define wxStyledTextEvent_GetLParam 2895 -#define wxStyledTextEvent_GetListType 2896 -#define wxStyledTextEvent_GetX 2897 -#define wxStyledTextEvent_GetY 2898 -#define wxStyledTextEvent_GetDragText 2899 -#define wxStyledTextEvent_GetDragAllowMove 2900 -#define wxStyledTextEvent_GetDragResult 2901 -#define wxStyledTextEvent_GetShift 2902 -#define wxStyledTextEvent_GetControl 2903 -#define wxStyledTextEvent_GetAlt 2904 -#define utils_wxGetKeyState 2905 -#define utils_wxGetMousePosition 2906 -#define utils_wxGetMouseState 2907 -#define utils_wxSetDetectableAutoRepeat 2908 -#define utils_wxBell 2909 -#define utils_wxFindMenuItemId 2910 -#define utils_wxGenericFindWindowAtPoint 2911 -#define utils_wxFindWindowAtPoint 2912 -#define utils_wxBeginBusyCursor 2913 -#define utils_wxEndBusyCursor 2914 -#define utils_wxIsBusy 2915 -#define utils_wxShutdown 2916 -#define utils_wxShell 2917 -#define utils_wxLaunchDefaultBrowser 2918 -#define utils_wxGetEmailAddress 2919 -#define utils_wxGetUserId 2920 -#define utils_wxGetHomeDir 2921 -#define utils_wxNewId 2922 -#define utils_wxRegisterId 2923 -#define utils_wxGetCurrentId 2924 -#define utils_wxGetOsDescription 2925 -#define utils_wxIsPlatformLittleEndian 2926 -#define utils_wxIsPlatform64Bit 2927 -#define gdicmn_wxDisplaySize 2928 -#define gdicmn_wxSetCursor 2929 -#define wxPrintout_new 2930 -#define wxPrintout_destruct 2931 -#define wxPrintout_GetDC 2932 -#define wxPrintout_GetPageSizeMM 2933 -#define wxPrintout_GetPageSizePixels 2934 -#define wxPrintout_GetPaperRectPixels 2935 -#define wxPrintout_GetPPIPrinter 2936 -#define wxPrintout_GetPPIScreen 2937 -#define wxPrintout_GetTitle 2938 -#define wxPrintout_IsPreview 2939 -#define wxPrintout_FitThisSizeToPaper 2940 -#define wxPrintout_FitThisSizeToPage 2941 -#define wxPrintout_FitThisSizeToPageMargins 2942 -#define wxPrintout_MapScreenSizeToPaper 2943 -#define wxPrintout_MapScreenSizeToPage 2944 -#define wxPrintout_MapScreenSizeToPageMargins 2945 -#define wxPrintout_MapScreenSizeToDevice 2946 -#define wxPrintout_GetLogicalPaperRect 2947 -#define wxPrintout_GetLogicalPageRect 2948 -#define wxPrintout_GetLogicalPageMarginsRect 2949 -#define wxPrintout_SetLogicalOrigin 2950 -#define wxPrintout_OffsetLogicalOrigin 2951 -#define wxStyledTextCtrl_new_2 2952 -#define wxStyledTextCtrl_new_0 2953 -#define wxStyledTextCtrl_destruct 2954 -#define wxStyledTextCtrl_Create 2955 -#define wxStyledTextCtrl_AddText 2956 -#define wxStyledTextCtrl_AddStyledText 2957 -#define wxStyledTextCtrl_InsertText 2958 -#define wxStyledTextCtrl_ClearAll 2959 -#define wxStyledTextCtrl_ClearDocumentStyle 2960 -#define wxStyledTextCtrl_GetLength 2961 -#define wxStyledTextCtrl_GetCharAt 2962 -#define wxStyledTextCtrl_GetCurrentPos 2963 -#define wxStyledTextCtrl_GetAnchor 2964 -#define wxStyledTextCtrl_GetStyleAt 2965 -#define wxStyledTextCtrl_Redo 2966 -#define wxStyledTextCtrl_SetUndoCollection 2967 -#define wxStyledTextCtrl_SelectAll 2968 -#define wxStyledTextCtrl_SetSavePoint 2969 -#define wxStyledTextCtrl_GetStyledText 2970 -#define wxStyledTextCtrl_CanRedo 2971 -#define wxStyledTextCtrl_MarkerLineFromHandle 2972 -#define wxStyledTextCtrl_MarkerDeleteHandle 2973 -#define wxStyledTextCtrl_GetUndoCollection 2974 -#define wxStyledTextCtrl_GetViewWhiteSpace 2975 -#define wxStyledTextCtrl_SetViewWhiteSpace 2976 -#define wxStyledTextCtrl_PositionFromPoint 2977 -#define wxStyledTextCtrl_PositionFromPointClose 2978 -#define wxStyledTextCtrl_GotoLine 2979 -#define wxStyledTextCtrl_GotoPos 2980 -#define wxStyledTextCtrl_SetAnchor 2981 -#define wxStyledTextCtrl_GetCurLine 2982 -#define wxStyledTextCtrl_GetEndStyled 2983 -#define wxStyledTextCtrl_ConvertEOLs 2984 -#define wxStyledTextCtrl_GetEOLMode 2985 -#define wxStyledTextCtrl_SetEOLMode 2986 -#define wxStyledTextCtrl_StartStyling 2987 -#define wxStyledTextCtrl_SetStyling 2988 -#define wxStyledTextCtrl_GetBufferedDraw 2989 -#define wxStyledTextCtrl_SetBufferedDraw 2990 -#define wxStyledTextCtrl_SetTabWidth 2991 -#define wxStyledTextCtrl_GetTabWidth 2992 -#define wxStyledTextCtrl_SetCodePage 2993 -#define wxStyledTextCtrl_MarkerDefine 2994 -#define wxStyledTextCtrl_MarkerSetForeground 2995 -#define wxStyledTextCtrl_MarkerSetBackground 2996 -#define wxStyledTextCtrl_MarkerAdd 2997 -#define wxStyledTextCtrl_MarkerDelete 2998 -#define wxStyledTextCtrl_MarkerDeleteAll 2999 -#define wxStyledTextCtrl_MarkerGet 3000 -#define wxStyledTextCtrl_MarkerNext 3001 -#define wxStyledTextCtrl_MarkerPrevious 3002 -#define wxStyledTextCtrl_MarkerDefineBitmap 3003 -#define wxStyledTextCtrl_MarkerAddSet 3004 -#define wxStyledTextCtrl_MarkerSetAlpha 3005 -#define wxStyledTextCtrl_SetMarginType 3006 -#define wxStyledTextCtrl_GetMarginType 3007 -#define wxStyledTextCtrl_SetMarginWidth 3008 -#define wxStyledTextCtrl_GetMarginWidth 3009 -#define wxStyledTextCtrl_SetMarginMask 3010 -#define wxStyledTextCtrl_GetMarginMask 3011 -#define wxStyledTextCtrl_SetMarginSensitive 3012 -#define wxStyledTextCtrl_GetMarginSensitive 3013 -#define wxStyledTextCtrl_StyleClearAll 3014 -#define wxStyledTextCtrl_StyleSetForeground 3015 -#define wxStyledTextCtrl_StyleSetBackground 3016 -#define wxStyledTextCtrl_StyleSetBold 3017 -#define wxStyledTextCtrl_StyleSetItalic 3018 -#define wxStyledTextCtrl_StyleSetSize 3019 -#define wxStyledTextCtrl_StyleSetFaceName 3020 -#define wxStyledTextCtrl_StyleSetEOLFilled 3021 -#define wxStyledTextCtrl_StyleResetDefault 3022 -#define wxStyledTextCtrl_StyleSetUnderline 3023 -#define wxStyledTextCtrl_StyleSetCase 3024 -#define wxStyledTextCtrl_StyleSetHotSpot 3025 -#define wxStyledTextCtrl_SetSelForeground 3026 -#define wxStyledTextCtrl_SetSelBackground 3027 -#define wxStyledTextCtrl_GetSelAlpha 3028 -#define wxStyledTextCtrl_SetSelAlpha 3029 -#define wxStyledTextCtrl_SetCaretForeground 3030 -#define wxStyledTextCtrl_CmdKeyAssign 3031 -#define wxStyledTextCtrl_CmdKeyClear 3032 -#define wxStyledTextCtrl_CmdKeyClearAll 3033 -#define wxStyledTextCtrl_SetStyleBytes 3034 -#define wxStyledTextCtrl_StyleSetVisible 3035 -#define wxStyledTextCtrl_GetCaretPeriod 3036 -#define wxStyledTextCtrl_SetCaretPeriod 3037 -#define wxStyledTextCtrl_SetWordChars 3038 -#define wxStyledTextCtrl_BeginUndoAction 3039 -#define wxStyledTextCtrl_EndUndoAction 3040 -#define wxStyledTextCtrl_IndicatorSetStyle 3041 -#define wxStyledTextCtrl_IndicatorGetStyle 3042 -#define wxStyledTextCtrl_IndicatorSetForeground 3043 -#define wxStyledTextCtrl_IndicatorGetForeground 3044 -#define wxStyledTextCtrl_SetWhitespaceForeground 3045 -#define wxStyledTextCtrl_SetWhitespaceBackground 3046 -#define wxStyledTextCtrl_GetStyleBits 3047 -#define wxStyledTextCtrl_SetLineState 3048 -#define wxStyledTextCtrl_GetLineState 3049 -#define wxStyledTextCtrl_GetMaxLineState 3050 -#define wxStyledTextCtrl_GetCaretLineVisible 3051 -#define wxStyledTextCtrl_SetCaretLineVisible 3052 -#define wxStyledTextCtrl_GetCaretLineBackground 3053 -#define wxStyledTextCtrl_SetCaretLineBackground 3054 -#define wxStyledTextCtrl_AutoCompShow 3055 -#define wxStyledTextCtrl_AutoCompCancel 3056 -#define wxStyledTextCtrl_AutoCompActive 3057 -#define wxStyledTextCtrl_AutoCompPosStart 3058 -#define wxStyledTextCtrl_AutoCompComplete 3059 -#define wxStyledTextCtrl_AutoCompStops 3060 -#define wxStyledTextCtrl_AutoCompSetSeparator 3061 -#define wxStyledTextCtrl_AutoCompGetSeparator 3062 -#define wxStyledTextCtrl_AutoCompSelect 3063 -#define wxStyledTextCtrl_AutoCompSetCancelAtStart 3064 -#define wxStyledTextCtrl_AutoCompGetCancelAtStart 3065 -#define wxStyledTextCtrl_AutoCompSetFillUps 3066 -#define wxStyledTextCtrl_AutoCompSetChooseSingle 3067 -#define wxStyledTextCtrl_AutoCompGetChooseSingle 3068 -#define wxStyledTextCtrl_AutoCompSetIgnoreCase 3069 -#define wxStyledTextCtrl_AutoCompGetIgnoreCase 3070 -#define wxStyledTextCtrl_UserListShow 3071 -#define wxStyledTextCtrl_AutoCompSetAutoHide 3072 -#define wxStyledTextCtrl_AutoCompGetAutoHide 3073 -#define wxStyledTextCtrl_AutoCompSetDropRestOfWord 3074 -#define wxStyledTextCtrl_AutoCompGetDropRestOfWord 3075 -#define wxStyledTextCtrl_RegisterImage 3076 -#define wxStyledTextCtrl_ClearRegisteredImages 3077 -#define wxStyledTextCtrl_AutoCompGetTypeSeparator 3078 -#define wxStyledTextCtrl_AutoCompSetTypeSeparator 3079 -#define wxStyledTextCtrl_AutoCompSetMaxWidth 3080 -#define wxStyledTextCtrl_AutoCompGetMaxWidth 3081 -#define wxStyledTextCtrl_AutoCompSetMaxHeight 3082 -#define wxStyledTextCtrl_AutoCompGetMaxHeight 3083 -#define wxStyledTextCtrl_SetIndent 3084 -#define wxStyledTextCtrl_GetIndent 3085 -#define wxStyledTextCtrl_SetUseTabs 3086 -#define wxStyledTextCtrl_GetUseTabs 3087 -#define wxStyledTextCtrl_SetLineIndentation 3088 -#define wxStyledTextCtrl_GetLineIndentation 3089 -#define wxStyledTextCtrl_GetLineIndentPosition 3090 -#define wxStyledTextCtrl_GetColumn 3091 -#define wxStyledTextCtrl_SetUseHorizontalScrollBar 3092 -#define wxStyledTextCtrl_GetUseHorizontalScrollBar 3093 -#define wxStyledTextCtrl_SetIndentationGuides 3094 -#define wxStyledTextCtrl_GetIndentationGuides 3095 -#define wxStyledTextCtrl_SetHighlightGuide 3096 -#define wxStyledTextCtrl_GetHighlightGuide 3097 -#define wxStyledTextCtrl_GetLineEndPosition 3098 -#define wxStyledTextCtrl_GetCodePage 3099 -#define wxStyledTextCtrl_GetCaretForeground 3100 -#define wxStyledTextCtrl_GetReadOnly 3101 -#define wxStyledTextCtrl_SetCurrentPos 3102 -#define wxStyledTextCtrl_SetSelectionStart 3103 -#define wxStyledTextCtrl_GetSelectionStart 3104 -#define wxStyledTextCtrl_SetSelectionEnd 3105 -#define wxStyledTextCtrl_GetSelectionEnd 3106 -#define wxStyledTextCtrl_SetPrintMagnification 3107 -#define wxStyledTextCtrl_GetPrintMagnification 3108 -#define wxStyledTextCtrl_SetPrintColourMode 3109 -#define wxStyledTextCtrl_GetPrintColourMode 3110 -#define wxStyledTextCtrl_FindText 3111 -#define wxStyledTextCtrl_FormatRange 3112 -#define wxStyledTextCtrl_GetFirstVisibleLine 3113 -#define wxStyledTextCtrl_GetLine 3114 -#define wxStyledTextCtrl_GetLineCount 3115 -#define wxStyledTextCtrl_SetMarginLeft 3116 -#define wxStyledTextCtrl_GetMarginLeft 3117 -#define wxStyledTextCtrl_SetMarginRight 3118 -#define wxStyledTextCtrl_GetMarginRight 3119 -#define wxStyledTextCtrl_GetModify 3120 -#define wxStyledTextCtrl_SetSelection 3121 -#define wxStyledTextCtrl_GetSelectedText 3122 -#define wxStyledTextCtrl_GetTextRange 3123 -#define wxStyledTextCtrl_HideSelection 3124 -#define wxStyledTextCtrl_LineFromPosition 3125 -#define wxStyledTextCtrl_PositionFromLine 3126 -#define wxStyledTextCtrl_LineScroll 3127 -#define wxStyledTextCtrl_EnsureCaretVisible 3128 -#define wxStyledTextCtrl_ReplaceSelection 3129 -#define wxStyledTextCtrl_SetReadOnly 3130 -#define wxStyledTextCtrl_CanPaste 3131 -#define wxStyledTextCtrl_CanUndo 3132 -#define wxStyledTextCtrl_EmptyUndoBuffer 3133 -#define wxStyledTextCtrl_Undo 3134 -#define wxStyledTextCtrl_Cut 3135 -#define wxStyledTextCtrl_Copy 3136 -#define wxStyledTextCtrl_Paste 3137 -#define wxStyledTextCtrl_Clear 3138 -#define wxStyledTextCtrl_SetText 3139 -#define wxStyledTextCtrl_GetText 3140 -#define wxStyledTextCtrl_GetTextLength 3141 -#define wxStyledTextCtrl_GetOvertype 3142 -#define wxStyledTextCtrl_SetCaretWidth 3143 -#define wxStyledTextCtrl_GetCaretWidth 3144 -#define wxStyledTextCtrl_SetTargetStart 3145 -#define wxStyledTextCtrl_GetTargetStart 3146 -#define wxStyledTextCtrl_SetTargetEnd 3147 -#define wxStyledTextCtrl_GetTargetEnd 3148 -#define wxStyledTextCtrl_ReplaceTarget 3149 -#define wxStyledTextCtrl_SearchInTarget 3150 -#define wxStyledTextCtrl_SetSearchFlags 3151 -#define wxStyledTextCtrl_GetSearchFlags 3152 -#define wxStyledTextCtrl_CallTipShow 3153 -#define wxStyledTextCtrl_CallTipCancel 3154 -#define wxStyledTextCtrl_CallTipActive 3155 -#define wxStyledTextCtrl_CallTipPosAtStart 3156 -#define wxStyledTextCtrl_CallTipSetHighlight 3157 -#define wxStyledTextCtrl_CallTipSetBackground 3158 -#define wxStyledTextCtrl_CallTipSetForeground 3159 -#define wxStyledTextCtrl_CallTipSetForegroundHighlight 3160 -#define wxStyledTextCtrl_CallTipUseStyle 3161 -#define wxStyledTextCtrl_VisibleFromDocLine 3162 -#define wxStyledTextCtrl_DocLineFromVisible 3163 -#define wxStyledTextCtrl_WrapCount 3164 -#define wxStyledTextCtrl_SetFoldLevel 3165 -#define wxStyledTextCtrl_GetFoldLevel 3166 -#define wxStyledTextCtrl_GetLastChild 3167 -#define wxStyledTextCtrl_GetFoldParent 3168 -#define wxStyledTextCtrl_ShowLines 3169 -#define wxStyledTextCtrl_HideLines 3170 -#define wxStyledTextCtrl_GetLineVisible 3171 -#define wxStyledTextCtrl_SetFoldExpanded 3172 -#define wxStyledTextCtrl_GetFoldExpanded 3173 -#define wxStyledTextCtrl_ToggleFold 3174 -#define wxStyledTextCtrl_EnsureVisible 3175 -#define wxStyledTextCtrl_SetFoldFlags 3176 -#define wxStyledTextCtrl_EnsureVisibleEnforcePolicy 3177 -#define wxStyledTextCtrl_SetTabIndents 3178 -#define wxStyledTextCtrl_GetTabIndents 3179 -#define wxStyledTextCtrl_SetBackSpaceUnIndents 3180 -#define wxStyledTextCtrl_GetBackSpaceUnIndents 3181 -#define wxStyledTextCtrl_SetMouseDwellTime 3182 -#define wxStyledTextCtrl_GetMouseDwellTime 3183 -#define wxStyledTextCtrl_WordStartPosition 3184 -#define wxStyledTextCtrl_WordEndPosition 3185 -#define wxStyledTextCtrl_SetWrapMode 3186 -#define wxStyledTextCtrl_GetWrapMode 3187 -#define wxStyledTextCtrl_SetWrapVisualFlags 3188 -#define wxStyledTextCtrl_GetWrapVisualFlags 3189 -#define wxStyledTextCtrl_SetWrapVisualFlagsLocation 3190 -#define wxStyledTextCtrl_GetWrapVisualFlagsLocation 3191 -#define wxStyledTextCtrl_SetWrapStartIndent 3192 -#define wxStyledTextCtrl_GetWrapStartIndent 3193 -#define wxStyledTextCtrl_SetLayoutCache 3194 -#define wxStyledTextCtrl_GetLayoutCache 3195 -#define wxStyledTextCtrl_SetScrollWidth 3196 -#define wxStyledTextCtrl_GetScrollWidth 3197 -#define wxStyledTextCtrl_TextWidth 3198 -#define wxStyledTextCtrl_GetEndAtLastLine 3199 -#define wxStyledTextCtrl_TextHeight 3200 -#define wxStyledTextCtrl_SetUseVerticalScrollBar 3201 -#define wxStyledTextCtrl_GetUseVerticalScrollBar 3202 -#define wxStyledTextCtrl_AppendText 3203 -#define wxStyledTextCtrl_GetTwoPhaseDraw 3204 -#define wxStyledTextCtrl_SetTwoPhaseDraw 3205 -#define wxStyledTextCtrl_TargetFromSelection 3206 -#define wxStyledTextCtrl_LinesJoin 3207 -#define wxStyledTextCtrl_LinesSplit 3208 -#define wxStyledTextCtrl_SetFoldMarginColour 3209 -#define wxStyledTextCtrl_SetFoldMarginHiColour 3210 -#define wxStyledTextCtrl_LineDown 3211 -#define wxStyledTextCtrl_LineDownExtend 3212 -#define wxStyledTextCtrl_LineUp 3213 -#define wxStyledTextCtrl_LineUpExtend 3214 -#define wxStyledTextCtrl_CharLeft 3215 -#define wxStyledTextCtrl_CharLeftExtend 3216 -#define wxStyledTextCtrl_CharRight 3217 -#define wxStyledTextCtrl_CharRightExtend 3218 -#define wxStyledTextCtrl_WordLeft 3219 -#define wxStyledTextCtrl_WordLeftExtend 3220 -#define wxStyledTextCtrl_WordRight 3221 -#define wxStyledTextCtrl_WordRightExtend 3222 -#define wxStyledTextCtrl_Home 3223 -#define wxStyledTextCtrl_HomeExtend 3224 -#define wxStyledTextCtrl_LineEnd 3225 -#define wxStyledTextCtrl_LineEndExtend 3226 -#define wxStyledTextCtrl_DocumentStart 3227 -#define wxStyledTextCtrl_DocumentStartExtend 3228 -#define wxStyledTextCtrl_DocumentEnd 3229 -#define wxStyledTextCtrl_DocumentEndExtend 3230 -#define wxStyledTextCtrl_PageUp 3231 -#define wxStyledTextCtrl_PageUpExtend 3232 -#define wxStyledTextCtrl_PageDown 3233 -#define wxStyledTextCtrl_PageDownExtend 3234 -#define wxStyledTextCtrl_EditToggleOvertype 3235 -#define wxStyledTextCtrl_Cancel 3236 -#define wxStyledTextCtrl_DeleteBack 3237 -#define wxStyledTextCtrl_Tab 3238 -#define wxStyledTextCtrl_BackTab 3239 -#define wxStyledTextCtrl_NewLine 3240 -#define wxStyledTextCtrl_FormFeed 3241 -#define wxStyledTextCtrl_VCHome 3242 -#define wxStyledTextCtrl_VCHomeExtend 3243 -#define wxStyledTextCtrl_ZoomIn 3244 -#define wxStyledTextCtrl_ZoomOut 3245 -#define wxStyledTextCtrl_DelWordLeft 3246 -#define wxStyledTextCtrl_DelWordRight 3247 -#define wxStyledTextCtrl_LineCut 3248 -#define wxStyledTextCtrl_LineDelete 3249 -#define wxStyledTextCtrl_LineTranspose 3250 -#define wxStyledTextCtrl_LineDuplicate 3251 -#define wxStyledTextCtrl_LowerCase 3252 -#define wxStyledTextCtrl_UpperCase 3253 -#define wxStyledTextCtrl_LineScrollDown 3254 -#define wxStyledTextCtrl_LineScrollUp 3255 -#define wxStyledTextCtrl_DeleteBackNotLine 3256 -#define wxStyledTextCtrl_HomeDisplay 3257 -#define wxStyledTextCtrl_HomeDisplayExtend 3258 -#define wxStyledTextCtrl_LineEndDisplay 3259 -#define wxStyledTextCtrl_LineEndDisplayExtend 3260 -#define wxStyledTextCtrl_HomeWrapExtend 3261 -#define wxStyledTextCtrl_LineEndWrap 3262 -#define wxStyledTextCtrl_LineEndWrapExtend 3263 -#define wxStyledTextCtrl_VCHomeWrap 3264 -#define wxStyledTextCtrl_VCHomeWrapExtend 3265 -#define wxStyledTextCtrl_LineCopy 3266 -#define wxStyledTextCtrl_MoveCaretInsideView 3267 -#define wxStyledTextCtrl_LineLength 3268 -#define wxStyledTextCtrl_BraceHighlight 3269 -#define wxStyledTextCtrl_BraceBadLight 3270 -#define wxStyledTextCtrl_BraceMatch 3271 -#define wxStyledTextCtrl_GetViewEOL 3272 -#define wxStyledTextCtrl_SetViewEOL 3273 -#define wxStyledTextCtrl_SetModEventMask 3274 -#define wxStyledTextCtrl_GetEdgeColumn 3275 -#define wxStyledTextCtrl_SetEdgeColumn 3276 -#define wxStyledTextCtrl_SetEdgeMode 3277 -#define wxStyledTextCtrl_GetEdgeMode 3278 -#define wxStyledTextCtrl_GetEdgeColour 3279 -#define wxStyledTextCtrl_SetEdgeColour 3280 -#define wxStyledTextCtrl_SearchAnchor 3281 -#define wxStyledTextCtrl_SearchNext 3282 -#define wxStyledTextCtrl_SearchPrev 3283 -#define wxStyledTextCtrl_LinesOnScreen 3284 -#define wxStyledTextCtrl_UsePopUp 3285 -#define wxStyledTextCtrl_SelectionIsRectangle 3286 -#define wxStyledTextCtrl_SetZoom 3287 -#define wxStyledTextCtrl_GetZoom 3288 -#define wxStyledTextCtrl_GetModEventMask 3289 -#define wxStyledTextCtrl_SetSTCFocus 3290 -#define wxStyledTextCtrl_GetSTCFocus 3291 -#define wxStyledTextCtrl_SetStatus 3292 -#define wxStyledTextCtrl_GetStatus 3293 -#define wxStyledTextCtrl_SetMouseDownCaptures 3294 -#define wxStyledTextCtrl_GetMouseDownCaptures 3295 -#define wxStyledTextCtrl_SetSTCCursor 3296 -#define wxStyledTextCtrl_GetSTCCursor 3297 -#define wxStyledTextCtrl_SetControlCharSymbol 3298 -#define wxStyledTextCtrl_GetControlCharSymbol 3299 -#define wxStyledTextCtrl_WordPartLeft 3300 -#define wxStyledTextCtrl_WordPartLeftExtend 3301 -#define wxStyledTextCtrl_WordPartRight 3302 -#define wxStyledTextCtrl_WordPartRightExtend 3303 -#define wxStyledTextCtrl_SetVisiblePolicy 3304 -#define wxStyledTextCtrl_DelLineLeft 3305 -#define wxStyledTextCtrl_DelLineRight 3306 -#define wxStyledTextCtrl_GetXOffset 3307 -#define wxStyledTextCtrl_ChooseCaretX 3308 -#define wxStyledTextCtrl_SetXCaretPolicy 3309 -#define wxStyledTextCtrl_SetYCaretPolicy 3310 -#define wxStyledTextCtrl_GetPrintWrapMode 3311 -#define wxStyledTextCtrl_SetHotspotActiveForeground 3312 -#define wxStyledTextCtrl_SetHotspotActiveBackground 3313 -#define wxStyledTextCtrl_SetHotspotActiveUnderline 3314 -#define wxStyledTextCtrl_SetHotspotSingleLine 3315 -#define wxStyledTextCtrl_ParaDownExtend 3316 -#define wxStyledTextCtrl_ParaUp 3317 -#define wxStyledTextCtrl_ParaUpExtend 3318 -#define wxStyledTextCtrl_PositionBefore 3319 -#define wxStyledTextCtrl_PositionAfter 3320 -#define wxStyledTextCtrl_CopyRange 3321 -#define wxStyledTextCtrl_CopyText 3322 -#define wxStyledTextCtrl_SetSelectionMode 3323 -#define wxStyledTextCtrl_GetSelectionMode 3324 -#define wxStyledTextCtrl_LineDownRectExtend 3325 -#define wxStyledTextCtrl_LineUpRectExtend 3326 -#define wxStyledTextCtrl_CharLeftRectExtend 3327 -#define wxStyledTextCtrl_CharRightRectExtend 3328 -#define wxStyledTextCtrl_HomeRectExtend 3329 -#define wxStyledTextCtrl_VCHomeRectExtend 3330 -#define wxStyledTextCtrl_LineEndRectExtend 3331 -#define wxStyledTextCtrl_PageUpRectExtend 3332 -#define wxStyledTextCtrl_PageDownRectExtend 3333 -#define wxStyledTextCtrl_StutteredPageUp 3334 -#define wxStyledTextCtrl_StutteredPageUpExtend 3335 -#define wxStyledTextCtrl_StutteredPageDown 3336 -#define wxStyledTextCtrl_StutteredPageDownExtend 3337 -#define wxStyledTextCtrl_WordLeftEnd 3338 -#define wxStyledTextCtrl_WordLeftEndExtend 3339 -#define wxStyledTextCtrl_WordRightEnd 3340 -#define wxStyledTextCtrl_WordRightEndExtend 3341 -#define wxStyledTextCtrl_SetWhitespaceChars 3342 -#define wxStyledTextCtrl_SetCharsDefault 3343 -#define wxStyledTextCtrl_AutoCompGetCurrent 3344 -#define wxStyledTextCtrl_Allocate 3345 -#define wxStyledTextCtrl_FindColumn 3346 -#define wxStyledTextCtrl_GetCaretSticky 3347 -#define wxStyledTextCtrl_SetCaretSticky 3348 -#define wxStyledTextCtrl_ToggleCaretSticky 3349 -#define wxStyledTextCtrl_SetPasteConvertEndings 3350 -#define wxStyledTextCtrl_GetPasteConvertEndings 3351 -#define wxStyledTextCtrl_SelectionDuplicate 3352 -#define wxStyledTextCtrl_SetCaretLineBackAlpha 3353 -#define wxStyledTextCtrl_GetCaretLineBackAlpha 3354 -#define wxStyledTextCtrl_StartRecord 3355 -#define wxStyledTextCtrl_StopRecord 3356 -#define wxStyledTextCtrl_SetLexer 3357 -#define wxStyledTextCtrl_GetLexer 3358 -#define wxStyledTextCtrl_Colourise 3359 -#define wxStyledTextCtrl_SetProperty 3360 -#define wxStyledTextCtrl_SetKeyWords 3361 -#define wxStyledTextCtrl_SetLexerLanguage 3362 -#define wxStyledTextCtrl_GetProperty 3363 -#define wxStyledTextCtrl_GetStyleBitsNeeded 3364 -#define wxStyledTextCtrl_GetCurrentLine 3365 -#define wxStyledTextCtrl_StyleSetSpec 3366 -#define wxStyledTextCtrl_StyleSetFont 3367 -#define wxStyledTextCtrl_StyleSetFontAttr 3368 -#define wxStyledTextCtrl_StyleSetCharacterSet 3369 -#define wxStyledTextCtrl_StyleSetFontEncoding 3370 -#define wxStyledTextCtrl_CmdKeyExecute 3371 -#define wxStyledTextCtrl_SetMargins 3372 -#define wxStyledTextCtrl_GetSelection 3373 -#define wxStyledTextCtrl_PointFromPosition 3374 -#define wxStyledTextCtrl_ScrollToLine 3375 -#define wxStyledTextCtrl_ScrollToColumn 3376 -#define wxStyledTextCtrl_SetVScrollBar 3377 -#define wxStyledTextCtrl_SetHScrollBar 3378 -#define wxStyledTextCtrl_GetLastKeydownProcessed 3379 -#define wxStyledTextCtrl_SetLastKeydownProcessed 3380 -#define wxStyledTextCtrl_SaveFile 3381 -#define wxStyledTextCtrl_LoadFile 3382 -#define wxStyledTextCtrl_DoDragOver 3383 -#define wxStyledTextCtrl_DoDropText 3384 -#define wxStyledTextCtrl_GetUseAntiAliasing 3385 -#define wxStyledTextCtrl_AddTextRaw 3386 -#define wxStyledTextCtrl_InsertTextRaw 3387 -#define wxStyledTextCtrl_GetCurLineRaw 3388 -#define wxStyledTextCtrl_GetLineRaw 3389 -#define wxStyledTextCtrl_GetSelectedTextRaw 3390 -#define wxStyledTextCtrl_GetTextRangeRaw 3391 -#define wxStyledTextCtrl_SetTextRaw 3392 -#define wxStyledTextCtrl_GetTextRaw 3393 -#define wxStyledTextCtrl_AppendTextRaw 3394 -#define wxArtProvider_GetBitmap 3395 -#define wxArtProvider_GetIcon 3396 -#define wxTreeEvent_GetKeyCode 3397 -#define wxTreeEvent_GetItem 3398 -#define wxTreeEvent_GetKeyEvent 3399 -#define wxTreeEvent_GetLabel 3400 -#define wxTreeEvent_GetOldItem 3401 -#define wxTreeEvent_GetPoint 3402 -#define wxTreeEvent_IsEditCancelled 3403 -#define wxTreeEvent_SetToolTip 3404 -#define wxNotebookEvent_GetOldSelection 3405 -#define wxNotebookEvent_GetSelection 3406 -#define wxNotebookEvent_SetOldSelection 3407 -#define wxNotebookEvent_SetSelection 3408 -#define wxFileDataObject_new 3409 -#define wxFileDataObject_AddFile 3410 -#define wxFileDataObject_GetFilenames 3411 -#define wxFileDataObject_destroy 3412 -#define wxTextDataObject_new 3413 -#define wxTextDataObject_GetTextLength 3414 -#define wxTextDataObject_GetText 3415 -#define wxTextDataObject_SetText 3416 -#define wxTextDataObject_destroy 3417 -#define wxBitmapDataObject_new_1_1 3418 -#define wxBitmapDataObject_new_1_0 3419 -#define wxBitmapDataObject_GetBitmap 3420 -#define wxBitmapDataObject_SetBitmap 3421 -#define wxBitmapDataObject_destroy 3422 -#define wxClipboard_new 3424 -#define wxClipboard_destruct 3425 -#define wxClipboard_AddData 3426 -#define wxClipboard_Clear 3427 -#define wxClipboard_Close 3428 -#define wxClipboard_Flush 3429 -#define wxClipboard_GetData 3430 -#define wxClipboard_IsOpened 3431 -#define wxClipboard_Open 3432 -#define wxClipboard_SetData 3433 -#define wxClipboard_UsePrimarySelection 3435 -#define wxClipboard_IsSupported 3436 -#define wxClipboard_Get 3437 -#define wxSpinEvent_GetPosition 3438 -#define wxSpinEvent_SetPosition 3439 -#define wxSplitterWindow_new_0 3440 -#define wxSplitterWindow_new_2 3441 -#define wxSplitterWindow_destruct 3442 -#define wxSplitterWindow_Create 3443 -#define wxSplitterWindow_GetMinimumPaneSize 3444 -#define wxSplitterWindow_GetSashGravity 3445 -#define wxSplitterWindow_GetSashPosition 3446 -#define wxSplitterWindow_GetSplitMode 3447 -#define wxSplitterWindow_GetWindow1 3448 -#define wxSplitterWindow_GetWindow2 3449 -#define wxSplitterWindow_Initialize 3450 -#define wxSplitterWindow_IsSplit 3451 -#define wxSplitterWindow_ReplaceWindow 3452 -#define wxSplitterWindow_SetSashGravity 3453 -#define wxSplitterWindow_SetSashPosition 3454 -#define wxSplitterWindow_SetSashSize 3455 -#define wxSplitterWindow_SetMinimumPaneSize 3456 -#define wxSplitterWindow_SetSplitMode 3457 -#define wxSplitterWindow_SplitHorizontally 3458 -#define wxSplitterWindow_SplitVertically 3459 -#define wxSplitterWindow_Unsplit 3460 -#define wxSplitterWindow_UpdateSize 3461 -#define wxSplitterEvent_GetSashPosition 3462 -#define wxSplitterEvent_GetX 3463 -#define wxSplitterEvent_GetY 3464 -#define wxSplitterEvent_GetWindowBeingRemoved 3465 -#define wxSplitterEvent_SetSashPosition 3466 -#define wxHtmlWindow_new_0 3467 -#define wxHtmlWindow_new_2 3468 -#define wxHtmlWindow_AppendToPage 3469 -#define wxHtmlWindow_GetOpenedAnchor 3470 -#define wxHtmlWindow_GetOpenedPage 3471 -#define wxHtmlWindow_GetOpenedPageTitle 3472 -#define wxHtmlWindow_GetRelatedFrame 3473 -#define wxHtmlWindow_HistoryBack 3474 -#define wxHtmlWindow_HistoryCanBack 3475 -#define wxHtmlWindow_HistoryCanForward 3476 -#define wxHtmlWindow_HistoryClear 3477 -#define wxHtmlWindow_HistoryForward 3478 -#define wxHtmlWindow_LoadFile 3479 -#define wxHtmlWindow_LoadPage 3480 -#define wxHtmlWindow_SelectAll 3481 -#define wxHtmlWindow_SelectionToText 3482 -#define wxHtmlWindow_SelectLine 3483 -#define wxHtmlWindow_SelectWord 3484 -#define wxHtmlWindow_SetBorders 3485 -#define wxHtmlWindow_SetFonts 3486 -#define wxHtmlWindow_SetPage 3487 -#define wxHtmlWindow_SetRelatedFrame 3488 -#define wxHtmlWindow_SetRelatedStatusBar 3489 -#define wxHtmlWindow_ToText 3490 -#define wxHtmlWindow_destroy 3491 -#define wxHtmlLinkEvent_GetLinkInfo 3492 -#define wxSystemSettings_GetColour 3493 -#define wxSystemSettings_GetFont 3494 -#define wxSystemSettings_GetMetric 3495 -#define wxSystemSettings_GetScreenType 3496 -#define wxSystemOptions_GetOption 3497 -#define wxSystemOptions_GetOptionInt 3498 -#define wxSystemOptions_HasOption 3499 -#define wxSystemOptions_IsFalse 3500 -#define wxSystemOptions_SetOption_2_1 3501 -#define wxSystemOptions_SetOption_2_0 3502 -#define wxAuiNotebookEvent_SetSelection 3503 -#define wxAuiNotebookEvent_GetSelection 3504 -#define wxAuiNotebookEvent_SetOldSelection 3505 -#define wxAuiNotebookEvent_GetOldSelection 3506 -#define wxAuiNotebookEvent_SetDragSource 3507 -#define wxAuiNotebookEvent_GetDragSource 3508 -#define wxAuiManagerEvent_SetManager 3509 -#define wxAuiManagerEvent_GetManager 3510 -#define wxAuiManagerEvent_SetPane 3511 -#define wxAuiManagerEvent_GetPane 3512 -#define wxAuiManagerEvent_SetButton 3513 -#define wxAuiManagerEvent_GetButton 3514 -#define wxAuiManagerEvent_SetDC 3515 -#define wxAuiManagerEvent_GetDC 3516 -#define wxAuiManagerEvent_Veto 3517 -#define wxAuiManagerEvent_GetVeto 3518 -#define wxAuiManagerEvent_SetCanVeto 3519 -#define wxAuiManagerEvent_CanVeto 3520 -#define wxLogNull_new 3521 -#define wxLogNull_destroy 3522 -#define wxTaskBarIcon_new 3523 -#define wxTaskBarIcon_destruct 3524 -#define wxTaskBarIcon_PopupMenu 3525 -#define wxTaskBarIcon_RemoveIcon 3526 -#define wxTaskBarIcon_SetIcon 3527 -#define wxLocale_new_0 3528 -#define wxLocale_new_2 3530 -#define wxLocale_destruct 3531 -#define wxLocale_Init 3533 -#define wxLocale_AddCatalog_1 3534 -#define wxLocale_AddCatalog_3 3535 -#define wxLocale_AddCatalogLookupPathPrefix 3536 -#define wxLocale_GetCanonicalName 3537 -#define wxLocale_GetLanguage 3538 -#define wxLocale_GetLanguageName 3539 -#define wxLocale_GetLocale 3540 -#define wxLocale_GetName 3541 -#define wxLocale_GetString_2 3542 -#define wxLocale_GetString_4 3543 -#define wxLocale_GetHeaderValue 3544 -#define wxLocale_GetSysName 3545 -#define wxLocale_GetSystemEncoding 3546 -#define wxLocale_GetSystemEncodingName 3547 -#define wxLocale_GetSystemLanguage 3548 -#define wxLocale_IsLoaded 3549 -#define wxLocale_IsOk 3550 -#define wxActivateEvent_GetActive 3551 -#define wxPopupWindow_new_2 3553 -#define wxPopupWindow_new_0 3554 -#define wxPopupWindow_destruct 3556 -#define wxPopupWindow_Create 3557 -#define wxPopupWindow_Position 3558 -#define wxPopupTransientWindow_new_0 3559 -#define wxPopupTransientWindow_new_2 3560 -#define wxPopupTransientWindow_destruct 3561 -#define wxPopupTransientWindow_Popup 3562 -#define wxPopupTransientWindow_Dismiss 3563 +#define wxWindow_SetTransparent 284 +#define wxWindow_CanSetTransparent 285 +#define wxWindow_IsDoubleBuffered 286 +#define wxWindow_SetDoubleBuffered 287 +#define wxTopLevelWindow_GetIcon 288 +#define wxTopLevelWindow_GetIcons 289 +#define wxTopLevelWindow_GetTitle 290 +#define wxTopLevelWindow_IsActive 291 +#define wxTopLevelWindow_Iconize 292 +#define wxTopLevelWindow_IsFullScreen 293 +#define wxTopLevelWindow_IsIconized 294 +#define wxTopLevelWindow_IsMaximized 295 +#define wxTopLevelWindow_Maximize 296 +#define wxTopLevelWindow_RequestUserAttention 297 +#define wxTopLevelWindow_SetIcon 298 +#define wxTopLevelWindow_SetIcons 299 +#define wxTopLevelWindow_CenterOnScreen 300 +#define wxTopLevelWindow_CentreOnScreen 301 +#define wxTopLevelWindow_SetShape 303 +#define wxTopLevelWindow_SetTitle 304 +#define wxTopLevelWindow_ShowFullScreen 305 +#define wxFrame_new_4 307 +#define wxFrame_new_0 308 +#define wxFrame_destruct 310 +#define wxFrame_Create 311 +#define wxFrame_CreateStatusBar 312 +#define wxFrame_CreateToolBar 313 +#define wxFrame_GetClientAreaOrigin 314 +#define wxFrame_GetMenuBar 315 +#define wxFrame_GetStatusBar 316 +#define wxFrame_GetStatusBarPane 317 +#define wxFrame_GetToolBar 318 +#define wxFrame_ProcessCommand 319 +#define wxFrame_SendSizeEvent 320 +#define wxFrame_SetMenuBar 321 +#define wxFrame_SetStatusBar 322 +#define wxFrame_SetStatusBarPane 323 +#define wxFrame_SetStatusText 324 +#define wxFrame_SetStatusWidths 325 +#define wxFrame_SetToolBar 326 +#define wxMiniFrame_new_0 327 +#define wxMiniFrame_new_4 328 +#define wxMiniFrame_Create 329 +#define wxMiniFrame_destroy 330 +#define wxSplashScreen_new_0 331 +#define wxSplashScreen_new_6 332 +#define wxSplashScreen_destruct 333 +#define wxSplashScreen_GetSplashStyle 334 +#define wxSplashScreen_GetTimeout 335 +#define wxPanel_new_0 336 +#define wxPanel_new_6 337 +#define wxPanel_new_2 338 +#define wxPanel_destruct 339 +#define wxPanel_InitDialog 340 +#define wxPanel_SetFocusIgnoringChildren 341 +#define wxScrolledWindow_new_0 342 +#define wxScrolledWindow_new_2 343 +#define wxScrolledWindow_destruct 344 +#define wxScrolledWindow_CalcScrolledPosition_4 345 +#define wxScrolledWindow_CalcScrolledPosition_1 346 +#define wxScrolledWindow_CalcUnscrolledPosition_4 347 +#define wxScrolledWindow_CalcUnscrolledPosition_1 348 +#define wxScrolledWindow_EnableScrolling 349 +#define wxScrolledWindow_GetScrollPixelsPerUnit 350 +#define wxScrolledWindow_GetViewStart 351 +#define wxScrolledWindow_DoPrepareDC 352 +#define wxScrolledWindow_PrepareDC 353 +#define wxScrolledWindow_Scroll 354 +#define wxScrolledWindow_SetScrollbars 355 +#define wxScrolledWindow_SetScrollRate 356 +#define wxScrolledWindow_SetTargetWindow 357 +#define wxSashWindow_new_0 358 +#define wxSashWindow_new_2 359 +#define wxSashWindow_destruct 360 +#define wxSashWindow_GetSashVisible 361 +#define wxSashWindow_GetMaximumSizeX 362 +#define wxSashWindow_GetMaximumSizeY 363 +#define wxSashWindow_GetMinimumSizeX 364 +#define wxSashWindow_GetMinimumSizeY 365 +#define wxSashWindow_SetMaximumSizeX 366 +#define wxSashWindow_SetMaximumSizeY 367 +#define wxSashWindow_SetMinimumSizeX 368 +#define wxSashWindow_SetMinimumSizeY 369 +#define wxSashWindow_SetSashVisible 370 +#define wxSashLayoutWindow_new_0 371 +#define wxSashLayoutWindow_new_2 372 +#define wxSashLayoutWindow_Create 373 +#define wxSashLayoutWindow_GetAlignment 374 +#define wxSashLayoutWindow_GetOrientation 375 +#define wxSashLayoutWindow_SetAlignment 376 +#define wxSashLayoutWindow_SetDefaultSize 377 +#define wxSashLayoutWindow_SetOrientation 378 +#define wxSashLayoutWindow_destroy 379 +#define wxGrid_new_0 380 +#define wxGrid_new_3 381 +#define wxGrid_new_4 382 +#define wxGrid_destruct 383 +#define wxGrid_AppendCols 384 +#define wxGrid_AppendRows 385 +#define wxGrid_AutoSize 386 +#define wxGrid_AutoSizeColumn 387 +#define wxGrid_AutoSizeColumns 388 +#define wxGrid_AutoSizeRow 389 +#define wxGrid_AutoSizeRows 390 +#define wxGrid_BeginBatch 391 +#define wxGrid_BlockToDeviceRect 392 +#define wxGrid_CanDragColSize 393 +#define wxGrid_CanDragRowSize 394 +#define wxGrid_CanDragGridSize 395 +#define wxGrid_CanEnableCellControl 396 +#define wxGrid_CellToRect_2 397 +#define wxGrid_CellToRect_1 398 +#define wxGrid_ClearGrid 399 +#define wxGrid_ClearSelection 400 +#define wxGrid_CreateGrid 401 +#define wxGrid_DeleteCols 402 +#define wxGrid_DeleteRows 403 +#define wxGrid_DisableCellEditControl 404 +#define wxGrid_DisableDragColSize 405 +#define wxGrid_DisableDragGridSize 406 +#define wxGrid_DisableDragRowSize 407 +#define wxGrid_EnableCellEditControl 408 +#define wxGrid_EnableDragColSize 409 +#define wxGrid_EnableDragGridSize 410 +#define wxGrid_EnableDragRowSize 411 +#define wxGrid_EnableEditing 412 +#define wxGrid_EnableGridLines 413 +#define wxGrid_EndBatch 414 +#define wxGrid_Fit 415 +#define wxGrid_ForceRefresh 416 +#define wxGrid_GetBatchCount 417 +#define wxGrid_GetCellAlignment 418 +#define wxGrid_GetCellBackgroundColour 419 +#define wxGrid_GetCellEditor 420 +#define wxGrid_GetCellFont 421 +#define wxGrid_GetCellRenderer 422 +#define wxGrid_GetCellTextColour 423 +#define wxGrid_GetCellValue_2 424 +#define wxGrid_GetCellValue_1 425 +#define wxGrid_GetColLabelAlignment 426 +#define wxGrid_GetColLabelSize 427 +#define wxGrid_GetColLabelValue 428 +#define wxGrid_GetColMinimalAcceptableWidth 429 +#define wxGrid_GetDefaultCellAlignment 430 +#define wxGrid_GetDefaultCellBackgroundColour 431 +#define wxGrid_GetDefaultCellFont 432 +#define wxGrid_GetDefaultCellTextColour 433 +#define wxGrid_GetDefaultColLabelSize 434 +#define wxGrid_GetDefaultColSize 435 +#define wxGrid_GetDefaultEditor 436 +#define wxGrid_GetDefaultEditorForCell_2 437 +#define wxGrid_GetDefaultEditorForCell_1 438 +#define wxGrid_GetDefaultEditorForType 439 +#define wxGrid_GetDefaultRenderer 440 +#define wxGrid_GetDefaultRendererForCell 441 +#define wxGrid_GetDefaultRendererForType 442 +#define wxGrid_GetDefaultRowLabelSize 443 +#define wxGrid_GetDefaultRowSize 444 +#define wxGrid_GetGridCursorCol 445 +#define wxGrid_GetGridCursorRow 446 +#define wxGrid_GetGridLineColour 447 +#define wxGrid_GridLinesEnabled 448 +#define wxGrid_GetLabelBackgroundColour 449 +#define wxGrid_GetLabelFont 450 +#define wxGrid_GetLabelTextColour 451 +#define wxGrid_GetNumberCols 452 +#define wxGrid_GetNumberRows 453 +#define wxGrid_GetOrCreateCellAttr 454 +#define wxGrid_GetRowMinimalAcceptableHeight 455 +#define wxGrid_GetRowLabelAlignment 456 +#define wxGrid_GetRowLabelSize 457 +#define wxGrid_GetRowLabelValue 458 +#define wxGrid_GetRowSize 459 +#define wxGrid_GetScrollLineX 460 +#define wxGrid_GetScrollLineY 461 +#define wxGrid_GetSelectedCells 462 +#define wxGrid_GetSelectedCols 463 +#define wxGrid_GetSelectedRows 464 +#define wxGrid_GetSelectionBackground 465 +#define wxGrid_GetSelectionBlockTopLeft 466 +#define wxGrid_GetSelectionBlockBottomRight 467 +#define wxGrid_GetSelectionForeground 468 +#define wxGrid_GetViewWidth 469 +#define wxGrid_GetGridWindow 470 +#define wxGrid_GetGridRowLabelWindow 471 +#define wxGrid_GetGridColLabelWindow 472 +#define wxGrid_GetGridCornerLabelWindow 473 +#define wxGrid_HideCellEditControl 474 +#define wxGrid_InsertCols 475 +#define wxGrid_InsertRows 476 +#define wxGrid_IsCellEditControlEnabled 477 +#define wxGrid_IsCurrentCellReadOnly 478 +#define wxGrid_IsEditable 479 +#define wxGrid_IsInSelection_2 480 +#define wxGrid_IsInSelection_1 481 +#define wxGrid_IsReadOnly 482 +#define wxGrid_IsSelection 483 +#define wxGrid_IsVisible_3 484 +#define wxGrid_IsVisible_2 485 +#define wxGrid_MakeCellVisible_2 486 +#define wxGrid_MakeCellVisible_1 487 +#define wxGrid_MoveCursorDown 488 +#define wxGrid_MoveCursorLeft 489 +#define wxGrid_MoveCursorRight 490 +#define wxGrid_MoveCursorUp 491 +#define wxGrid_MoveCursorDownBlock 492 +#define wxGrid_MoveCursorLeftBlock 493 +#define wxGrid_MoveCursorRightBlock 494 +#define wxGrid_MoveCursorUpBlock 495 +#define wxGrid_MovePageDown 496 +#define wxGrid_MovePageUp 497 +#define wxGrid_RegisterDataType 498 +#define wxGrid_SaveEditControlValue 499 +#define wxGrid_SelectAll 500 +#define wxGrid_SelectBlock_5 501 +#define wxGrid_SelectBlock_3 502 +#define wxGrid_SelectCol 503 +#define wxGrid_SelectRow 504 +#define wxGrid_SetCellAlignment_4 505 +#define wxGrid_SetCellAlignment_3 506 +#define wxGrid_SetCellAlignment_1 507 +#define wxGrid_SetCellBackgroundColour_3_0 508 +#define wxGrid_SetCellBackgroundColour_1 509 +#define wxGrid_SetCellBackgroundColour_3_1 510 +#define wxGrid_SetCellEditor 511 +#define wxGrid_SetCellFont 512 +#define wxGrid_SetCellRenderer 513 +#define wxGrid_SetCellTextColour_3_0 514 +#define wxGrid_SetCellTextColour_3_1 515 +#define wxGrid_SetCellTextColour_1 516 +#define wxGrid_SetCellValue_3_0 517 +#define wxGrid_SetCellValue_2 518 +#define wxGrid_SetCellValue_3_1 519 +#define wxGrid_SetColAttr 520 +#define wxGrid_SetColFormatBool 521 +#define wxGrid_SetColFormatNumber 522 +#define wxGrid_SetColFormatFloat 523 +#define wxGrid_SetColFormatCustom 524 +#define wxGrid_SetColLabelAlignment 525 +#define wxGrid_SetColLabelSize 526 +#define wxGrid_SetColLabelValue 527 +#define wxGrid_SetColMinimalWidth 528 +#define wxGrid_SetColMinimalAcceptableWidth 529 +#define wxGrid_SetColSize 530 +#define wxGrid_SetDefaultCellAlignment 531 +#define wxGrid_SetDefaultCellBackgroundColour 532 +#define wxGrid_SetDefaultCellFont 533 +#define wxGrid_SetDefaultCellTextColour 534 +#define wxGrid_SetDefaultEditor 535 +#define wxGrid_SetDefaultRenderer 536 +#define wxGrid_SetDefaultColSize 537 +#define wxGrid_SetDefaultRowSize 538 +#define wxGrid_SetGridCursor 539 +#define wxGrid_SetGridLineColour 540 +#define wxGrid_SetLabelBackgroundColour 541 +#define wxGrid_SetLabelFont 542 +#define wxGrid_SetLabelTextColour 543 +#define wxGrid_SetMargins 544 +#define wxGrid_SetReadOnly 545 +#define wxGrid_SetRowAttr 546 +#define wxGrid_SetRowLabelAlignment 547 +#define wxGrid_SetRowLabelSize 548 +#define wxGrid_SetRowLabelValue 549 +#define wxGrid_SetRowMinimalHeight 550 +#define wxGrid_SetRowMinimalAcceptableHeight 551 +#define wxGrid_SetRowSize 552 +#define wxGrid_SetScrollLineX 553 +#define wxGrid_SetScrollLineY 554 +#define wxGrid_SetSelectionBackground 555 +#define wxGrid_SetSelectionForeground 556 +#define wxGrid_SetSelectionMode 557 +#define wxGrid_ShowCellEditControl 558 +#define wxGrid_XToCol 559 +#define wxGrid_XToEdgeOfCol 560 +#define wxGrid_YToEdgeOfRow 561 +#define wxGrid_YToRow 562 +#define wxGridCellRenderer_Draw 563 +#define wxGridCellRenderer_GetBestSize 564 +#define wxGridCellEditor_Create 565 +#define wxGridCellEditor_IsCreated 566 +#define wxGridCellEditor_SetSize 567 +#define wxGridCellEditor_Show 568 +#define wxGridCellEditor_PaintBackground 569 +#define wxGridCellEditor_BeginEdit 570 +#define wxGridCellEditor_EndEdit 571 +#define wxGridCellEditor_Reset 572 +#define wxGridCellEditor_StartingKey 573 +#define wxGridCellEditor_StartingClick 574 +#define wxGridCellEditor_HandleReturn 575 +#define wxGridCellBoolRenderer_new 576 +#define wxGridCellBoolRenderer_destroy 577 +#define wxGridCellBoolEditor_new 578 +#define wxGridCellBoolEditor_IsTrueValue 579 +#define wxGridCellBoolEditor_UseStringValues 580 +#define wxGridCellBoolEditor_destroy 581 +#define wxGridCellFloatRenderer_new 582 +#define wxGridCellFloatRenderer_GetPrecision 583 +#define wxGridCellFloatRenderer_GetWidth 584 +#define wxGridCellFloatRenderer_SetParameters 585 +#define wxGridCellFloatRenderer_SetPrecision 586 +#define wxGridCellFloatRenderer_SetWidth 587 +#define wxGridCellFloatRenderer_destroy 588 +#define wxGridCellFloatEditor_new 589 +#define wxGridCellFloatEditor_SetParameters 590 +#define wxGridCellFloatEditor_destroy 591 +#define wxGridCellStringRenderer_new 592 +#define wxGridCellStringRenderer_destroy 593 +#define wxGridCellTextEditor_new 594 +#define wxGridCellTextEditor_SetParameters 595 +#define wxGridCellTextEditor_destroy 596 +#define wxGridCellChoiceEditor_new 598 +#define wxGridCellChoiceEditor_SetParameters 599 +#define wxGridCellChoiceEditor_destroy 600 +#define wxGridCellNumberRenderer_new 601 +#define wxGridCellNumberRenderer_destroy 602 +#define wxGridCellNumberEditor_new 603 +#define wxGridCellNumberEditor_GetValue 604 +#define wxGridCellNumberEditor_SetParameters 605 +#define wxGridCellNumberEditor_destroy 606 +#define wxGridCellAttr_SetTextColour 607 +#define wxGridCellAttr_SetBackgroundColour 608 +#define wxGridCellAttr_SetFont 609 +#define wxGridCellAttr_SetAlignment 610 +#define wxGridCellAttr_SetReadOnly 611 +#define wxGridCellAttr_SetRenderer 612 +#define wxGridCellAttr_SetEditor 613 +#define wxGridCellAttr_HasTextColour 614 +#define wxGridCellAttr_HasBackgroundColour 615 +#define wxGridCellAttr_HasFont 616 +#define wxGridCellAttr_HasAlignment 617 +#define wxGridCellAttr_HasRenderer 618 +#define wxGridCellAttr_HasEditor 619 +#define wxGridCellAttr_GetTextColour 620 +#define wxGridCellAttr_GetBackgroundColour 621 +#define wxGridCellAttr_GetFont 622 +#define wxGridCellAttr_GetAlignment 623 +#define wxGridCellAttr_GetRenderer 624 +#define wxGridCellAttr_GetEditor 625 +#define wxGridCellAttr_IsReadOnly 626 +#define wxGridCellAttr_SetDefAttr 627 +#define wxDC_Blit 628 +#define wxDC_CalcBoundingBox 629 +#define wxDC_Clear 630 +#define wxDC_ComputeScaleAndOrigin 631 +#define wxDC_CrossHair 632 +#define wxDC_DestroyClippingRegion 633 +#define wxDC_DeviceToLogicalX 634 +#define wxDC_DeviceToLogicalXRel 635 +#define wxDC_DeviceToLogicalY 636 +#define wxDC_DeviceToLogicalYRel 637 +#define wxDC_DrawArc 638 +#define wxDC_DrawBitmap 639 +#define wxDC_DrawCheckMark 640 +#define wxDC_DrawCircle 641 +#define wxDC_DrawEllipse_2 643 +#define wxDC_DrawEllipse_1 644 +#define wxDC_DrawEllipticArc 645 +#define wxDC_DrawIcon 646 +#define wxDC_DrawLabel 647 +#define wxDC_DrawLine 648 +#define wxDC_DrawLines 649 +#define wxDC_DrawPolygon 651 +#define wxDC_DrawPoint 653 +#define wxDC_DrawRectangle_2 655 +#define wxDC_DrawRectangle_1 656 +#define wxDC_DrawRotatedText 657 +#define wxDC_DrawRoundedRectangle_3 659 +#define wxDC_DrawRoundedRectangle_2 660 +#define wxDC_DrawText 661 +#define wxDC_EndDoc 662 +#define wxDC_EndPage 663 +#define wxDC_FloodFill 664 +#define wxDC_GetBackground 665 +#define wxDC_GetBackgroundMode 666 +#define wxDC_GetBrush 667 +#define wxDC_GetCharHeight 668 +#define wxDC_GetCharWidth 669 +#define wxDC_GetClippingBox 670 +#define wxDC_GetFont 672 +#define wxDC_GetLayoutDirection 673 +#define wxDC_GetLogicalFunction 674 +#define wxDC_GetMapMode 675 +#define wxDC_GetMultiLineTextExtent_4 676 +#define wxDC_GetMultiLineTextExtent_1 677 +#define wxDC_GetPartialTextExtents 678 +#define wxDC_GetPen 679 +#define wxDC_GetPixel 680 +#define wxDC_GetPPI 681 +#define wxDC_GetSize 683 +#define wxDC_GetSizeMM 685 +#define wxDC_GetTextBackground 686 +#define wxDC_GetTextExtent_4 687 +#define wxDC_GetTextExtent_1 688 +#define wxDC_GetTextForeground 690 +#define wxDC_GetUserScale 691 +#define wxDC_GradientFillConcentric_3 692 +#define wxDC_GradientFillConcentric_4 693 +#define wxDC_GradientFillLinear 694 +#define wxDC_LogicalToDeviceX 695 +#define wxDC_LogicalToDeviceXRel 696 +#define wxDC_LogicalToDeviceY 697 +#define wxDC_LogicalToDeviceYRel 698 +#define wxDC_MaxX 699 +#define wxDC_MaxY 700 +#define wxDC_MinX 701 +#define wxDC_MinY 702 +#define wxDC_IsOk 703 +#define wxDC_ResetBoundingBox 704 +#define wxDC_SetAxisOrientation 705 +#define wxDC_SetBackground 706 +#define wxDC_SetBackgroundMode 707 +#define wxDC_SetBrush 708 +#define wxDC_SetClippingRegion_2 710 +#define wxDC_SetClippingRegion_1_1 711 +#define wxDC_SetClippingRegion_1_0 712 +#define wxDC_SetDeviceOrigin 713 +#define wxDC_SetFont 714 +#define wxDC_SetLayoutDirection 715 +#define wxDC_SetLogicalFunction 716 +#define wxDC_SetMapMode 717 +#define wxDC_SetPalette 718 +#define wxDC_SetPen 719 +#define wxDC_SetTextBackground 720 +#define wxDC_SetTextForeground 721 +#define wxDC_SetUserScale 722 +#define wxDC_StartDoc 723 +#define wxDC_StartPage 724 +#define wxMirrorDC_new 725 +#define wxMirrorDC_destroy 726 +#define wxScreenDC_new 727 +#define wxScreenDC_destruct 728 +#define wxPostScriptDC_new_0 729 +#define wxPostScriptDC_new_1 730 +#define wxPostScriptDC_destruct 731 +#define wxPostScriptDC_SetResolution 732 +#define wxPostScriptDC_GetResolution 733 +#define wxWindowDC_new_0 734 +#define wxWindowDC_new_1 735 +#define wxWindowDC_destruct 736 +#define wxClientDC_new_0 737 +#define wxClientDC_new_1 738 +#define wxClientDC_destroy 739 +#define wxPaintDC_new_0 740 +#define wxPaintDC_new_1 741 +#define wxPaintDC_destroy 742 +#define wxMemoryDC_new_1_0 744 +#define wxMemoryDC_new_1_1 745 +#define wxMemoryDC_new_0 746 +#define wxMemoryDC_destruct 748 +#define wxMemoryDC_SelectObject 749 +#define wxMemoryDC_SelectObjectAsSource 750 +#define wxBufferedDC_new_0 751 +#define wxBufferedDC_new_2 752 +#define wxBufferedDC_new_3 753 +#define wxBufferedDC_destruct 754 +#define wxBufferedDC_Init_2 755 +#define wxBufferedDC_Init_3 756 +#define wxBufferedPaintDC_new_3 757 +#define wxBufferedPaintDC_new_2 758 +#define wxBufferedPaintDC_destruct 759 +#define wxGraphicsObject_destruct 760 +#define wxGraphicsObject_GetRenderer 761 +#define wxGraphicsObject_IsNull 762 +#define wxGraphicsContext_destruct 763 +#define wxGraphicsContext_Create_1_1 764 +#define wxGraphicsContext_Create_1_0 765 +#define wxGraphicsContext_Create_0 766 +#define wxGraphicsContext_CreatePen 767 +#define wxGraphicsContext_CreateBrush 768 +#define wxGraphicsContext_CreateRadialGradientBrush 769 +#define wxGraphicsContext_CreateLinearGradientBrush 770 +#define wxGraphicsContext_CreateFont 771 +#define wxGraphicsContext_CreateMatrix 772 +#define wxGraphicsContext_CreatePath 773 +#define wxGraphicsContext_Clip_1 774 +#define wxGraphicsContext_Clip_4 775 +#define wxGraphicsContext_ResetClip 776 +#define wxGraphicsContext_DrawBitmap 777 +#define wxGraphicsContext_DrawEllipse 778 +#define wxGraphicsContext_DrawIcon 779 +#define wxGraphicsContext_DrawLines 780 +#define wxGraphicsContext_DrawPath 781 +#define wxGraphicsContext_DrawRectangle 782 +#define wxGraphicsContext_DrawRoundedRectangle 783 +#define wxGraphicsContext_DrawText_3 784 +#define wxGraphicsContext_DrawText_4_0 785 +#define wxGraphicsContext_DrawText_4_1 786 +#define wxGraphicsContext_DrawText_5 787 +#define wxGraphicsContext_FillPath 788 +#define wxGraphicsContext_StrokePath 789 +#define wxGraphicsContext_GetPartialTextExtents 790 +#define wxGraphicsContext_GetTextExtent 791 +#define wxGraphicsContext_Rotate 792 +#define wxGraphicsContext_Scale 793 +#define wxGraphicsContext_Translate 794 +#define wxGraphicsContext_GetTransform 795 +#define wxGraphicsContext_SetTransform 796 +#define wxGraphicsContext_ConcatTransform 797 +#define wxGraphicsContext_SetBrush_1_1 798 +#define wxGraphicsContext_SetBrush_1_0 799 +#define wxGraphicsContext_SetFont_1 800 +#define wxGraphicsContext_SetFont_2 801 +#define wxGraphicsContext_SetPen_1_0 802 +#define wxGraphicsContext_SetPen_1_1 803 +#define wxGraphicsContext_StrokeLine 804 +#define wxGraphicsContext_StrokeLines 805 +#define wxGraphicsMatrix_Concat 807 +#define wxGraphicsMatrix_Get 809 +#define wxGraphicsMatrix_Invert 810 +#define wxGraphicsMatrix_IsEqual 811 +#define wxGraphicsMatrix_IsIdentity 813 +#define wxGraphicsMatrix_Rotate 814 +#define wxGraphicsMatrix_Scale 815 +#define wxGraphicsMatrix_Translate 816 +#define wxGraphicsMatrix_Set 817 +#define wxGraphicsMatrix_TransformPoint 818 +#define wxGraphicsMatrix_TransformDistance 819 +#define wxGraphicsPath_MoveToPoint_2 820 +#define wxGraphicsPath_MoveToPoint_1 821 +#define wxGraphicsPath_AddArc_6 822 +#define wxGraphicsPath_AddArc_5 823 +#define wxGraphicsPath_AddArcToPoint 824 +#define wxGraphicsPath_AddCircle 825 +#define wxGraphicsPath_AddCurveToPoint_6 826 +#define wxGraphicsPath_AddCurveToPoint_3 827 +#define wxGraphicsPath_AddEllipse 828 +#define wxGraphicsPath_AddLineToPoint_2 829 +#define wxGraphicsPath_AddLineToPoint_1 830 +#define wxGraphicsPath_AddPath 831 +#define wxGraphicsPath_AddQuadCurveToPoint 832 +#define wxGraphicsPath_AddRectangle 833 +#define wxGraphicsPath_AddRoundedRectangle 834 +#define wxGraphicsPath_CloseSubpath 835 +#define wxGraphicsPath_Contains_3 836 +#define wxGraphicsPath_Contains_2 837 +#define wxGraphicsPath_GetBox 839 +#define wxGraphicsPath_GetCurrentPoint 841 +#define wxGraphicsPath_Transform 842 +#define wxGraphicsRenderer_GetDefaultRenderer 843 +#define wxGraphicsRenderer_CreateContext_1_1 844 +#define wxGraphicsRenderer_CreateContext_1_0 845 +#define wxGraphicsRenderer_CreatePen 846 +#define wxGraphicsRenderer_CreateBrush 847 +#define wxGraphicsRenderer_CreateLinearGradientBrush 848 +#define wxGraphicsRenderer_CreateRadialGradientBrush 849 +#define wxGraphicsRenderer_CreateFont 850 +#define wxGraphicsRenderer_CreateMatrix 851 +#define wxGraphicsRenderer_CreatePath 852 +#define wxMenuBar_new_1 854 +#define wxMenuBar_new_0 856 +#define wxMenuBar_destruct 858 +#define wxMenuBar_Append 859 +#define wxMenuBar_Check 860 +#define wxMenuBar_Enable_2 861 +#define wxMenuBar_Enable_1 862 +#define wxMenuBar_EnableTop 863 +#define wxMenuBar_FindMenu 864 +#define wxMenuBar_FindMenuItem 865 +#define wxMenuBar_FindItem 866 +#define wxMenuBar_GetHelpString 867 +#define wxMenuBar_GetLabel_1 868 +#define wxMenuBar_GetLabel_0 869 +#define wxMenuBar_GetLabelTop 870 +#define wxMenuBar_GetMenu 871 +#define wxMenuBar_GetMenuCount 872 +#define wxMenuBar_Insert 873 +#define wxMenuBar_IsChecked 874 +#define wxMenuBar_IsEnabled_1 875 +#define wxMenuBar_IsEnabled_0 876 +#define wxMenuBar_Remove 877 +#define wxMenuBar_Replace 878 +#define wxMenuBar_SetHelpString 879 +#define wxMenuBar_SetLabel_2 880 +#define wxMenuBar_SetLabel_1 881 +#define wxMenuBar_SetLabelTop 882 +#define wxControl_GetLabel 883 +#define wxControl_SetLabel 884 +#define wxControlWithItems_Append_1 885 +#define wxControlWithItems_Append_2 886 +#define wxControlWithItems_appendStrings_1 887 +#define wxControlWithItems_Clear 888 +#define wxControlWithItems_Delete 889 +#define wxControlWithItems_FindString 890 +#define wxControlWithItems_getClientData 891 +#define wxControlWithItems_setClientData 892 +#define wxControlWithItems_GetCount 893 +#define wxControlWithItems_GetSelection 894 +#define wxControlWithItems_GetString 895 +#define wxControlWithItems_GetStringSelection 896 +#define wxControlWithItems_Insert_2 897 +#define wxControlWithItems_Insert_3 898 +#define wxControlWithItems_IsEmpty 899 +#define wxControlWithItems_Select 900 +#define wxControlWithItems_SetSelection 901 +#define wxControlWithItems_SetString 902 +#define wxControlWithItems_SetStringSelection 903 +#define wxMenu_new_2 906 +#define wxMenu_new_1 907 +#define wxMenu_destruct 909 +#define wxMenu_Append_3 910 +#define wxMenu_Append_1 911 +#define wxMenu_Append_4_0 912 +#define wxMenu_Append_4_1 913 +#define wxMenu_AppendCheckItem 914 +#define wxMenu_AppendRadioItem 915 +#define wxMenu_AppendSeparator 916 +#define wxMenu_Break 917 +#define wxMenu_Check 918 +#define wxMenu_Delete_1_0 919 +#define wxMenu_Delete_1_1 920 +#define wxMenu_Destroy_1_0 921 +#define wxMenu_Destroy_1_1 922 +#define wxMenu_Enable 923 +#define wxMenu_FindItem_1 924 +#define wxMenu_FindItem_2 925 +#define wxMenu_FindItemByPosition 926 +#define wxMenu_GetHelpString 927 +#define wxMenu_GetLabel 928 +#define wxMenu_GetMenuItemCount 929 +#define wxMenu_GetMenuItems 930 +#define wxMenu_GetTitle 932 +#define wxMenu_Insert_2 933 +#define wxMenu_Insert_3 934 +#define wxMenu_Insert_5_1 935 +#define wxMenu_Insert_5_0 936 +#define wxMenu_InsertCheckItem 937 +#define wxMenu_InsertRadioItem 938 +#define wxMenu_InsertSeparator 939 +#define wxMenu_IsChecked 940 +#define wxMenu_IsEnabled 941 +#define wxMenu_Prepend_1 942 +#define wxMenu_Prepend_2 943 +#define wxMenu_Prepend_4_1 944 +#define wxMenu_Prepend_4_0 945 +#define wxMenu_PrependCheckItem 946 +#define wxMenu_PrependRadioItem 947 +#define wxMenu_PrependSeparator 948 +#define wxMenu_Remove_1_0 949 +#define wxMenu_Remove_1_1 950 +#define wxMenu_SetHelpString 951 +#define wxMenu_SetLabel 952 +#define wxMenu_SetTitle 953 +#define wxMenuItem_new 954 +#define wxMenuItem_destruct 956 +#define wxMenuItem_Check 957 +#define wxMenuItem_Enable 958 +#define wxMenuItem_GetBitmap 959 +#define wxMenuItem_GetHelp 960 +#define wxMenuItem_GetId 961 +#define wxMenuItem_GetKind 962 +#define wxMenuItem_GetLabel 963 +#define wxMenuItem_GetLabelFromText 964 +#define wxMenuItem_GetMenu 965 +#define wxMenuItem_GetText 966 +#define wxMenuItem_GetSubMenu 967 +#define wxMenuItem_IsCheckable 968 +#define wxMenuItem_IsChecked 969 +#define wxMenuItem_IsEnabled 970 +#define wxMenuItem_IsSeparator 971 +#define wxMenuItem_IsSubMenu 972 +#define wxMenuItem_SetBitmap 973 +#define wxMenuItem_SetHelp 974 +#define wxMenuItem_SetMenu 975 +#define wxMenuItem_SetSubMenu 976 +#define wxMenuItem_SetText 977 +#define wxToolBar_AddControl 978 +#define wxToolBar_AddSeparator 979 +#define wxToolBar_AddTool_5 980 +#define wxToolBar_AddTool_4_0 981 +#define wxToolBar_AddTool_1 982 +#define wxToolBar_AddTool_4_1 983 +#define wxToolBar_AddTool_3 984 +#define wxToolBar_AddTool_6 985 +#define wxToolBar_AddCheckTool 986 +#define wxToolBar_AddRadioTool 987 +#define wxToolBar_AddStretchableSpace 988 +#define wxToolBar_InsertStretchableSpace 989 +#define wxToolBar_DeleteTool 990 +#define wxToolBar_DeleteToolByPos 991 +#define wxToolBar_EnableTool 992 +#define wxToolBar_FindById 993 +#define wxToolBar_FindControl 994 +#define wxToolBar_FindToolForPosition 995 +#define wxToolBar_GetToolSize 996 +#define wxToolBar_GetToolBitmapSize 997 +#define wxToolBar_GetMargins 998 +#define wxToolBar_GetToolEnabled 999 +#define wxToolBar_GetToolLongHelp 1000 +#define wxToolBar_GetToolPacking 1001 +#define wxToolBar_GetToolPos 1002 +#define wxToolBar_GetToolSeparation 1003 +#define wxToolBar_GetToolShortHelp 1004 +#define wxToolBar_GetToolState 1005 +#define wxToolBar_InsertControl 1006 +#define wxToolBar_InsertSeparator 1007 +#define wxToolBar_InsertTool_5 1008 +#define wxToolBar_InsertTool_2 1009 +#define wxToolBar_InsertTool_4 1010 +#define wxToolBar_Realize 1011 +#define wxToolBar_RemoveTool 1012 +#define wxToolBar_SetMargins 1013 +#define wxToolBar_SetToolBitmapSize 1014 +#define wxToolBar_SetToolLongHelp 1015 +#define wxToolBar_SetToolPacking 1016 +#define wxToolBar_SetToolShortHelp 1017 +#define wxToolBar_SetToolSeparation 1018 +#define wxToolBar_ToggleTool 1019 +#define wxStatusBar_new_0 1021 +#define wxStatusBar_new_2 1022 +#define wxStatusBar_destruct 1024 +#define wxStatusBar_Create 1025 +#define wxStatusBar_GetFieldRect 1026 +#define wxStatusBar_GetFieldsCount 1027 +#define wxStatusBar_GetStatusText 1028 +#define wxStatusBar_PopStatusText 1029 +#define wxStatusBar_PushStatusText 1030 +#define wxStatusBar_SetFieldsCount 1031 +#define wxStatusBar_SetMinHeight 1032 +#define wxStatusBar_SetStatusText 1033 +#define wxStatusBar_SetStatusWidths 1034 +#define wxStatusBar_SetStatusStyles 1035 +#define wxBitmap_new_0 1036 +#define wxBitmap_new_3 1037 +#define wxBitmap_new_4 1038 +#define wxBitmap_new_2_0 1039 +#define wxBitmap_new_2_1 1040 +#define wxBitmap_destruct 1041 +#define wxBitmap_ConvertToImage 1042 +#define wxBitmap_CopyFromIcon 1043 +#define wxBitmap_Create 1044 +#define wxBitmap_GetDepth 1045 +#define wxBitmap_GetHeight 1046 +#define wxBitmap_GetPalette 1047 +#define wxBitmap_GetMask 1048 +#define wxBitmap_GetWidth 1049 +#define wxBitmap_GetSubBitmap 1050 +#define wxBitmap_LoadFile 1051 +#define wxBitmap_Ok 1052 +#define wxBitmap_SaveFile 1053 +#define wxBitmap_SetDepth 1054 +#define wxBitmap_SetHeight 1055 +#define wxBitmap_SetMask 1056 +#define wxBitmap_SetPalette 1057 +#define wxBitmap_SetWidth 1058 +#define wxIcon_new_0 1059 +#define wxIcon_new_2 1060 +#define wxIcon_new_1 1061 +#define wxIcon_CopyFromBitmap 1062 +#define wxIcon_destroy 1063 +#define wxIconBundle_new_0 1064 +#define wxIconBundle_new_2 1065 +#define wxIconBundle_new_1_0 1066 +#define wxIconBundle_new_1_1 1067 +#define wxIconBundle_destruct 1068 +#define wxIconBundle_AddIcon_2 1069 +#define wxIconBundle_AddIcon_1 1070 +#define wxIconBundle_GetIcon_1_1 1071 +#define wxIconBundle_GetIcon_1_0 1072 +#define wxCursor_new_0 1073 +#define wxCursor_new_1_0 1074 +#define wxCursor_new_1_1 1075 +#define wxCursor_new_4 1076 +#define wxCursor_destruct 1077 +#define wxCursor_Ok 1078 +#define wxMask_new_0 1079 +#define wxMask_new_2_1 1080 +#define wxMask_new_2_0 1081 +#define wxMask_new_1 1082 +#define wxMask_destruct 1083 +#define wxMask_Create_2_1 1084 +#define wxMask_Create_2_0 1085 +#define wxMask_Create_1 1086 +#define wxImage_new_0 1087 +#define wxImage_new_3_0 1088 +#define wxImage_new_4 1089 +#define wxImage_new_5 1090 +#define wxImage_new_2 1091 +#define wxImage_new_3_1 1092 +#define wxImage_Blur 1093 +#define wxImage_BlurHorizontal 1094 +#define wxImage_BlurVertical 1095 +#define wxImage_ConvertAlphaToMask 1096 +#define wxImage_ConvertToGreyscale 1097 +#define wxImage_ConvertToMono 1098 +#define wxImage_Copy 1099 +#define wxImage_Create_3 1100 +#define wxImage_Create_4 1101 +#define wxImage_Create_5 1102 +#define wxImage_Destroy 1103 +#define wxImage_FindFirstUnusedColour 1104 +#define wxImage_GetImageExtWildcard 1105 +#define wxImage_GetAlpha_2 1106 +#define wxImage_GetAlpha_0 1107 +#define wxImage_GetBlue 1108 +#define wxImage_GetData 1109 +#define wxImage_GetGreen 1110 +#define wxImage_GetImageCount 1111 +#define wxImage_GetHeight 1112 +#define wxImage_GetMaskBlue 1113 +#define wxImage_GetMaskGreen 1114 +#define wxImage_GetMaskRed 1115 +#define wxImage_GetOrFindMaskColour 1116 +#define wxImage_GetPalette 1117 +#define wxImage_GetRed 1118 +#define wxImage_GetSubImage 1119 +#define wxImage_GetWidth 1120 +#define wxImage_HasAlpha 1121 +#define wxImage_HasMask 1122 +#define wxImage_GetOption 1123 +#define wxImage_GetOptionInt 1124 +#define wxImage_HasOption 1125 +#define wxImage_InitAlpha 1126 +#define wxImage_InitStandardHandlers 1127 +#define wxImage_IsTransparent 1128 +#define wxImage_LoadFile_2 1129 +#define wxImage_LoadFile_3 1130 +#define wxImage_Ok 1131 +#define wxImage_RemoveHandler 1132 +#define wxImage_Mirror 1133 +#define wxImage_Replace 1134 +#define wxImage_Rescale 1135 +#define wxImage_Resize 1136 +#define wxImage_Rotate 1137 +#define wxImage_RotateHue 1138 +#define wxImage_Rotate90 1139 +#define wxImage_SaveFile_1 1140 +#define wxImage_SaveFile_2_0 1141 +#define wxImage_SaveFile_2_1 1142 +#define wxImage_Scale 1143 +#define wxImage_Size 1144 +#define wxImage_SetAlpha_3 1145 +#define wxImage_SetAlpha_2 1146 +#define wxImage_SetData_2 1147 +#define wxImage_SetData_4 1148 +#define wxImage_SetMask 1149 +#define wxImage_SetMaskColour 1150 +#define wxImage_SetMaskFromImage 1151 +#define wxImage_SetOption_2_1 1152 +#define wxImage_SetOption_2_0 1153 +#define wxImage_SetPalette 1154 +#define wxImage_SetRGB_5 1155 +#define wxImage_SetRGB_4 1156 +#define wxImage_destroy 1157 +#define wxBrush_new_0 1158 +#define wxBrush_new_2 1159 +#define wxBrush_new_1 1160 +#define wxBrush_destruct 1162 +#define wxBrush_GetColour 1163 +#define wxBrush_GetStipple 1164 +#define wxBrush_GetStyle 1165 +#define wxBrush_IsHatch 1166 +#define wxBrush_IsOk 1167 +#define wxBrush_SetColour_1 1168 +#define wxBrush_SetColour_3 1169 +#define wxBrush_SetStipple 1170 +#define wxBrush_SetStyle 1171 +#define wxPen_new_0 1172 +#define wxPen_new_2 1173 +#define wxPen_destruct 1174 +#define wxPen_GetCap 1175 +#define wxPen_GetColour 1176 +#define wxPen_GetJoin 1177 +#define wxPen_GetStyle 1178 +#define wxPen_GetWidth 1179 +#define wxPen_IsOk 1180 +#define wxPen_SetCap 1181 +#define wxPen_SetColour_1 1182 +#define wxPen_SetColour_3 1183 +#define wxPen_SetJoin 1184 +#define wxPen_SetStyle 1185 +#define wxPen_SetWidth 1186 +#define wxRegion_new_0 1187 +#define wxRegion_new_4 1188 +#define wxRegion_new_2 1189 +#define wxRegion_new_1_1 1190 +#define wxRegion_new_1_0 1192 +#define wxRegion_destruct 1194 +#define wxRegion_Clear 1195 +#define wxRegion_Contains_2 1196 +#define wxRegion_Contains_1_0 1197 +#define wxRegion_Contains_4 1198 +#define wxRegion_Contains_1_1 1199 +#define wxRegion_ConvertToBitmap 1200 +#define wxRegion_GetBox 1201 +#define wxRegion_Intersect_4 1202 +#define wxRegion_Intersect_1_1 1203 +#define wxRegion_Intersect_1_0 1204 +#define wxRegion_IsEmpty 1205 +#define wxRegion_Subtract_4 1206 +#define wxRegion_Subtract_1_1 1207 +#define wxRegion_Subtract_1_0 1208 +#define wxRegion_Offset_2 1209 +#define wxRegion_Offset_1 1210 +#define wxRegion_Union_4 1211 +#define wxRegion_Union_1_2 1212 +#define wxRegion_Union_1_1 1213 +#define wxRegion_Union_1_0 1214 +#define wxRegion_Union_3 1215 +#define wxRegion_Xor_4 1216 +#define wxRegion_Xor_1_1 1217 +#define wxRegion_Xor_1_0 1218 +#define wxAcceleratorTable_new_0 1219 +#define wxAcceleratorTable_new_2 1220 +#define wxAcceleratorTable_destruct 1221 +#define wxAcceleratorTable_Ok 1222 +#define wxAcceleratorEntry_new_1_0 1223 +#define wxAcceleratorEntry_new_1_1 1224 +#define wxAcceleratorEntry_GetCommand 1225 +#define wxAcceleratorEntry_GetFlags 1226 +#define wxAcceleratorEntry_GetKeyCode 1227 +#define wxAcceleratorEntry_Set 1228 +#define wxAcceleratorEntry_destroy 1229 +#define wxCaret_new_3 1234 +#define wxCaret_new_2 1235 +#define wxCaret_destruct 1237 +#define wxCaret_Create_3 1238 +#define wxCaret_Create_2 1239 +#define wxCaret_GetBlinkTime 1240 +#define wxCaret_GetPosition 1242 +#define wxCaret_GetSize 1244 +#define wxCaret_GetWindow 1245 +#define wxCaret_Hide 1246 +#define wxCaret_IsOk 1247 +#define wxCaret_IsVisible 1248 +#define wxCaret_Move_2 1249 +#define wxCaret_Move_1 1250 +#define wxCaret_SetBlinkTime 1251 +#define wxCaret_SetSize_2 1252 +#define wxCaret_SetSize_1 1253 +#define wxCaret_Show 1254 +#define wxSizer_Add_2_1 1255 +#define wxSizer_Add_2_0 1256 +#define wxSizer_Add_3 1257 +#define wxSizer_Add_2_3 1258 +#define wxSizer_Add_2_2 1259 +#define wxSizer_AddSpacer 1260 +#define wxSizer_AddStretchSpacer 1261 +#define wxSizer_CalcMin 1262 +#define wxSizer_Clear 1263 +#define wxSizer_Detach_1_2 1264 +#define wxSizer_Detach_1_1 1265 +#define wxSizer_Detach_1_0 1266 +#define wxSizer_Fit 1267 +#define wxSizer_FitInside 1268 +#define wxSizer_GetChildren 1269 +#define wxSizer_GetItem_2_1 1270 +#define wxSizer_GetItem_2_0 1271 +#define wxSizer_GetItem_1 1272 +#define wxSizer_GetSize 1273 +#define wxSizer_GetPosition 1274 +#define wxSizer_GetMinSize 1275 +#define wxSizer_Hide_2_0 1276 +#define wxSizer_Hide_2_1 1277 +#define wxSizer_Hide_1 1278 +#define wxSizer_Insert_3_1 1279 +#define wxSizer_Insert_3_0 1280 +#define wxSizer_Insert_4 1281 +#define wxSizer_Insert_3_3 1282 +#define wxSizer_Insert_3_2 1283 +#define wxSizer_Insert_2 1284 +#define wxSizer_InsertSpacer 1285 +#define wxSizer_InsertStretchSpacer 1286 +#define wxSizer_IsShown_1_2 1287 +#define wxSizer_IsShown_1_1 1288 +#define wxSizer_IsShown_1_0 1289 +#define wxSizer_Layout 1290 +#define wxSizer_Prepend_2_1 1291 +#define wxSizer_Prepend_2_0 1292 +#define wxSizer_Prepend_3 1293 +#define wxSizer_Prepend_2_3 1294 +#define wxSizer_Prepend_2_2 1295 +#define wxSizer_Prepend_1 1296 +#define wxSizer_PrependSpacer 1297 +#define wxSizer_PrependStretchSpacer 1298 +#define wxSizer_RecalcSizes 1299 +#define wxSizer_Remove_1_1 1300 +#define wxSizer_Remove_1_0 1301 +#define wxSizer_Replace_3_1 1302 +#define wxSizer_Replace_3_0 1303 +#define wxSizer_Replace_2 1304 +#define wxSizer_SetDimension 1305 +#define wxSizer_SetMinSize_2 1306 +#define wxSizer_SetMinSize_1 1307 +#define wxSizer_SetItemMinSize_3_2 1308 +#define wxSizer_SetItemMinSize_2_2 1309 +#define wxSizer_SetItemMinSize_3_1 1310 +#define wxSizer_SetItemMinSize_2_1 1311 +#define wxSizer_SetItemMinSize_3_0 1312 +#define wxSizer_SetItemMinSize_2_0 1313 +#define wxSizer_SetSizeHints 1314 +#define wxSizer_SetVirtualSizeHints 1315 +#define wxSizer_Show_2_2 1316 +#define wxSizer_Show_2_1 1317 +#define wxSizer_Show_2_0 1318 +#define wxSizer_Show_1 1319 +#define wxSizerFlags_new 1320 +#define wxSizerFlags_Align 1321 +#define wxSizerFlags_Border_2 1322 +#define wxSizerFlags_Border_1 1323 +#define wxSizerFlags_Center 1324 +#define wxSizerFlags_Centre 1325 +#define wxSizerFlags_Expand 1326 +#define wxSizerFlags_Left 1327 +#define wxSizerFlags_Proportion 1328 +#define wxSizerFlags_Right 1329 +#define wxSizerFlags_destroy 1330 +#define wxSizerItem_new_5_1 1331 +#define wxSizerItem_new_2_1 1332 +#define wxSizerItem_new_5_0 1333 +#define wxSizerItem_new_2_0 1334 +#define wxSizerItem_new_6 1335 +#define wxSizerItem_new_3 1336 +#define wxSizerItem_new_0 1337 +#define wxSizerItem_destruct 1338 +#define wxSizerItem_CalcMin 1339 +#define wxSizerItem_DeleteWindows 1340 +#define wxSizerItem_DetachSizer 1341 +#define wxSizerItem_GetBorder 1342 +#define wxSizerItem_GetFlag 1343 +#define wxSizerItem_GetMinSize 1344 +#define wxSizerItem_GetPosition 1345 +#define wxSizerItem_GetProportion 1346 +#define wxSizerItem_GetRatio 1347 +#define wxSizerItem_GetRect 1348 +#define wxSizerItem_GetSize 1349 +#define wxSizerItem_GetSizer 1350 +#define wxSizerItem_GetSpacer 1351 +#define wxSizerItem_GetUserData 1352 +#define wxSizerItem_GetWindow 1353 +#define wxSizerItem_IsSizer 1354 +#define wxSizerItem_IsShown 1355 +#define wxSizerItem_IsSpacer 1356 +#define wxSizerItem_IsWindow 1357 +#define wxSizerItem_SetBorder 1358 +#define wxSizerItem_SetDimension 1359 +#define wxSizerItem_SetFlag 1360 +#define wxSizerItem_SetInitSize 1361 +#define wxSizerItem_SetMinSize_1 1362 +#define wxSizerItem_SetMinSize_2 1363 +#define wxSizerItem_SetProportion 1364 +#define wxSizerItem_SetRatio_2 1365 +#define wxSizerItem_SetRatio_1_1 1366 +#define wxSizerItem_SetRatio_1_0 1367 +#define wxSizerItem_SetSizer 1368 +#define wxSizerItem_SetSpacer_1 1369 +#define wxSizerItem_SetSpacer_2 1370 +#define wxSizerItem_SetWindow 1371 +#define wxSizerItem_Show 1372 +#define wxBoxSizer_new 1373 +#define wxBoxSizer_GetOrientation 1374 +#define wxBoxSizer_destroy 1375 +#define wxStaticBoxSizer_new_2 1376 +#define wxStaticBoxSizer_new_3 1377 +#define wxStaticBoxSizer_GetStaticBox 1378 +#define wxStaticBoxSizer_destroy 1379 +#define wxGridSizer_new_4 1380 +#define wxGridSizer_new_2 1381 +#define wxGridSizer_GetCols 1382 +#define wxGridSizer_GetHGap 1383 +#define wxGridSizer_GetRows 1384 +#define wxGridSizer_GetVGap 1385 +#define wxGridSizer_SetCols 1386 +#define wxGridSizer_SetHGap 1387 +#define wxGridSizer_SetRows 1388 +#define wxGridSizer_SetVGap 1389 +#define wxGridSizer_destroy 1390 +#define wxFlexGridSizer_new_4 1391 +#define wxFlexGridSizer_new_2 1392 +#define wxFlexGridSizer_AddGrowableCol 1393 +#define wxFlexGridSizer_AddGrowableRow 1394 +#define wxFlexGridSizer_GetFlexibleDirection 1395 +#define wxFlexGridSizer_GetNonFlexibleGrowMode 1396 +#define wxFlexGridSizer_RemoveGrowableCol 1397 +#define wxFlexGridSizer_RemoveGrowableRow 1398 +#define wxFlexGridSizer_SetFlexibleDirection 1399 +#define wxFlexGridSizer_SetNonFlexibleGrowMode 1400 +#define wxFlexGridSizer_destroy 1401 +#define wxGridBagSizer_new 1402 +#define wxGridBagSizer_Add_3_2 1403 +#define wxGridBagSizer_Add_3_1 1404 +#define wxGridBagSizer_Add_4 1405 +#define wxGridBagSizer_Add_1_0 1406 +#define wxGridBagSizer_Add_2_1 1407 +#define wxGridBagSizer_Add_2_0 1408 +#define wxGridBagSizer_Add_3_0 1409 +#define wxGridBagSizer_Add_1_1 1410 +#define wxGridBagSizer_CalcMin 1411 +#define wxGridBagSizer_CheckForIntersection_2 1412 +#define wxGridBagSizer_CheckForIntersection_3 1413 +#define wxGridBagSizer_FindItem_1_1 1414 +#define wxGridBagSizer_FindItem_1_0 1415 +#define wxGridBagSizer_FindItemAtPoint 1416 +#define wxGridBagSizer_FindItemAtPosition 1417 +#define wxGridBagSizer_FindItemWithData 1418 +#define wxGridBagSizer_GetCellSize 1419 +#define wxGridBagSizer_GetEmptyCellSize 1420 +#define wxGridBagSizer_GetItemPosition_1_2 1421 +#define wxGridBagSizer_GetItemPosition_1_1 1422 +#define wxGridBagSizer_GetItemPosition_1_0 1423 +#define wxGridBagSizer_GetItemSpan_1_2 1424 +#define wxGridBagSizer_GetItemSpan_1_1 1425 +#define wxGridBagSizer_GetItemSpan_1_0 1426 +#define wxGridBagSizer_SetEmptyCellSize 1427 +#define wxGridBagSizer_SetItemPosition_2_2 1428 +#define wxGridBagSizer_SetItemPosition_2_1 1429 +#define wxGridBagSizer_SetItemPosition_2_0 1430 +#define wxGridBagSizer_SetItemSpan_2_2 1431 +#define wxGridBagSizer_SetItemSpan_2_1 1432 +#define wxGridBagSizer_SetItemSpan_2_0 1433 +#define wxGridBagSizer_destroy 1434 +#define wxStdDialogButtonSizer_new 1435 +#define wxStdDialogButtonSizer_AddButton 1436 +#define wxStdDialogButtonSizer_Realize 1437 +#define wxStdDialogButtonSizer_SetAffirmativeButton 1438 +#define wxStdDialogButtonSizer_SetCancelButton 1439 +#define wxStdDialogButtonSizer_SetNegativeButton 1440 +#define wxStdDialogButtonSizer_destroy 1441 +#define wxFont_new_0 1442 +#define wxFont_new_1 1443 +#define wxFont_new_5 1444 +#define wxFont_destruct 1446 +#define wxFont_IsFixedWidth 1447 +#define wxFont_GetDefaultEncoding 1448 +#define wxFont_GetFaceName 1449 +#define wxFont_GetFamily 1450 +#define wxFont_GetNativeFontInfoDesc 1451 +#define wxFont_GetNativeFontInfoUserDesc 1452 +#define wxFont_GetPointSize 1453 +#define wxFont_GetStyle 1454 +#define wxFont_GetUnderlined 1455 +#define wxFont_GetWeight 1456 +#define wxFont_Ok 1457 +#define wxFont_SetDefaultEncoding 1458 +#define wxFont_SetFaceName 1459 +#define wxFont_SetFamily 1460 +#define wxFont_SetPointSize 1461 +#define wxFont_SetStyle 1462 +#define wxFont_SetUnderlined 1463 +#define wxFont_SetWeight 1464 +#define wxToolTip_Enable 1465 +#define wxToolTip_SetDelay 1466 +#define wxToolTip_new 1467 +#define wxToolTip_SetTip 1468 +#define wxToolTip_GetTip 1469 +#define wxToolTip_GetWindow 1470 +#define wxToolTip_destroy 1471 +#define wxButton_new_3 1473 +#define wxButton_new_0 1474 +#define wxButton_destruct 1475 +#define wxButton_Create 1476 +#define wxButton_GetDefaultSize 1477 +#define wxButton_SetDefault 1478 +#define wxButton_SetLabel 1479 +#define wxBitmapButton_new_4 1481 +#define wxBitmapButton_new_0 1482 +#define wxBitmapButton_Create 1483 +#define wxBitmapButton_GetBitmapDisabled 1484 +#define wxBitmapButton_GetBitmapFocus 1486 +#define wxBitmapButton_GetBitmapLabel 1488 +#define wxBitmapButton_GetBitmapSelected 1490 +#define wxBitmapButton_SetBitmapDisabled 1492 +#define wxBitmapButton_SetBitmapFocus 1493 +#define wxBitmapButton_SetBitmapLabel 1494 +#define wxBitmapButton_SetBitmapSelected 1495 +#define wxBitmapButton_destroy 1496 +#define wxToggleButton_new_0 1497 +#define wxToggleButton_new_4 1498 +#define wxToggleButton_Create 1499 +#define wxToggleButton_GetValue 1500 +#define wxToggleButton_SetValue 1501 +#define wxToggleButton_destroy 1502 +#define wxCalendarCtrl_new_0 1503 +#define wxCalendarCtrl_new_3 1504 +#define wxCalendarCtrl_Create 1505 +#define wxCalendarCtrl_destruct 1506 +#define wxCalendarCtrl_SetDate 1507 +#define wxCalendarCtrl_GetDate 1508 +#define wxCalendarCtrl_EnableYearChange 1509 +#define wxCalendarCtrl_EnableMonthChange 1510 +#define wxCalendarCtrl_EnableHolidayDisplay 1511 +#define wxCalendarCtrl_SetHeaderColours 1512 +#define wxCalendarCtrl_GetHeaderColourFg 1513 +#define wxCalendarCtrl_GetHeaderColourBg 1514 +#define wxCalendarCtrl_SetHighlightColours 1515 +#define wxCalendarCtrl_GetHighlightColourFg 1516 +#define wxCalendarCtrl_GetHighlightColourBg 1517 +#define wxCalendarCtrl_SetHolidayColours 1518 +#define wxCalendarCtrl_GetHolidayColourFg 1519 +#define wxCalendarCtrl_GetHolidayColourBg 1520 +#define wxCalendarCtrl_GetAttr 1521 +#define wxCalendarCtrl_SetAttr 1522 +#define wxCalendarCtrl_SetHoliday 1523 +#define wxCalendarCtrl_ResetAttr 1524 +#define wxCalendarCtrl_HitTest 1525 +#define wxCalendarDateAttr_new_0 1526 +#define wxCalendarDateAttr_new_2_1 1527 +#define wxCalendarDateAttr_new_2_0 1528 +#define wxCalendarDateAttr_SetTextColour 1529 +#define wxCalendarDateAttr_SetBackgroundColour 1530 +#define wxCalendarDateAttr_SetBorderColour 1531 +#define wxCalendarDateAttr_SetFont 1532 +#define wxCalendarDateAttr_SetBorder 1533 +#define wxCalendarDateAttr_SetHoliday 1534 +#define wxCalendarDateAttr_HasTextColour 1535 +#define wxCalendarDateAttr_HasBackgroundColour 1536 +#define wxCalendarDateAttr_HasBorderColour 1537 +#define wxCalendarDateAttr_HasFont 1538 +#define wxCalendarDateAttr_HasBorder 1539 +#define wxCalendarDateAttr_IsHoliday 1540 +#define wxCalendarDateAttr_GetTextColour 1541 +#define wxCalendarDateAttr_GetBackgroundColour 1542 +#define wxCalendarDateAttr_GetBorderColour 1543 +#define wxCalendarDateAttr_GetFont 1544 +#define wxCalendarDateAttr_GetBorder 1545 +#define wxCalendarDateAttr_destroy 1546 +#define wxCheckBox_new_4 1548 +#define wxCheckBox_new_0 1549 +#define wxCheckBox_Create 1550 +#define wxCheckBox_GetValue 1551 +#define wxCheckBox_Get3StateValue 1552 +#define wxCheckBox_Is3rdStateAllowedForUser 1553 +#define wxCheckBox_Is3State 1554 +#define wxCheckBox_IsChecked 1555 +#define wxCheckBox_SetValue 1556 +#define wxCheckBox_Set3StateValue 1557 +#define wxCheckBox_destroy 1558 +#define wxCheckListBox_new_0 1559 +#define wxCheckListBox_new_3 1561 +#define wxCheckListBox_Check 1562 +#define wxCheckListBox_IsChecked 1563 +#define wxCheckListBox_destroy 1564 +#define wxChoice_new_3 1567 +#define wxChoice_new_0 1568 +#define wxChoice_destruct 1570 +#define wxChoice_Create 1572 +#define wxChoice_Delete 1573 +#define wxChoice_GetColumns 1574 +#define wxChoice_SetColumns 1575 +#define wxComboBox_new_0 1576 +#define wxComboBox_new_3 1578 +#define wxComboBox_destruct 1579 +#define wxComboBox_Create 1581 +#define wxComboBox_CanCopy 1582 +#define wxComboBox_CanCut 1583 +#define wxComboBox_CanPaste 1584 +#define wxComboBox_CanRedo 1585 +#define wxComboBox_CanUndo 1586 +#define wxComboBox_Copy 1587 +#define wxComboBox_Cut 1588 +#define wxComboBox_GetInsertionPoint 1589 +#define wxComboBox_GetLastPosition 1590 +#define wxComboBox_GetValue 1591 +#define wxComboBox_Paste 1592 +#define wxComboBox_Redo 1593 +#define wxComboBox_Replace 1594 +#define wxComboBox_Remove 1595 +#define wxComboBox_SetInsertionPoint 1596 +#define wxComboBox_SetInsertionPointEnd 1597 +#define wxComboBox_SetSelection_1 1598 +#define wxComboBox_SetSelection_2 1599 +#define wxComboBox_SetValue 1600 +#define wxComboBox_Undo 1601 +#define wxGauge_new_0 1602 +#define wxGauge_new_4 1603 +#define wxGauge_Create 1604 +#define wxGauge_GetBezelFace 1605 +#define wxGauge_GetRange 1606 +#define wxGauge_GetShadowWidth 1607 +#define wxGauge_GetValue 1608 +#define wxGauge_IsVertical 1609 +#define wxGauge_SetBezelFace 1610 +#define wxGauge_SetRange 1611 +#define wxGauge_SetShadowWidth 1612 +#define wxGauge_SetValue 1613 +#define wxGauge_Pulse 1614 +#define wxGauge_destroy 1615 +#define wxGenericDirCtrl_new_0 1616 +#define wxGenericDirCtrl_new_2 1617 +#define wxGenericDirCtrl_destruct 1618 +#define wxGenericDirCtrl_Create 1619 +#define wxGenericDirCtrl_Init 1620 +#define wxGenericDirCtrl_CollapseTree 1621 +#define wxGenericDirCtrl_ExpandPath 1622 +#define wxGenericDirCtrl_GetDefaultPath 1623 +#define wxGenericDirCtrl_GetPath 1624 +#define wxGenericDirCtrl_GetFilePath 1625 +#define wxGenericDirCtrl_GetFilter 1626 +#define wxGenericDirCtrl_GetFilterIndex 1627 +#define wxGenericDirCtrl_GetRootId 1628 +#define wxGenericDirCtrl_GetTreeCtrl 1629 +#define wxGenericDirCtrl_ReCreateTree 1630 +#define wxGenericDirCtrl_SetDefaultPath 1631 +#define wxGenericDirCtrl_SetFilter 1632 +#define wxGenericDirCtrl_SetFilterIndex 1633 +#define wxGenericDirCtrl_SetPath 1634 +#define wxStaticBox_new_4 1636 +#define wxStaticBox_new_0 1637 +#define wxStaticBox_Create 1638 +#define wxStaticBox_destroy 1639 +#define wxStaticLine_new_2 1641 +#define wxStaticLine_new_0 1642 +#define wxStaticLine_Create 1643 +#define wxStaticLine_IsVertical 1644 +#define wxStaticLine_GetDefaultSize 1645 +#define wxStaticLine_destroy 1646 +#define wxListBox_new_3 1649 +#define wxListBox_new_0 1650 +#define wxListBox_destruct 1652 +#define wxListBox_Create 1654 +#define wxListBox_Deselect 1655 +#define wxListBox_GetSelections 1656 +#define wxListBox_InsertItems 1657 +#define wxListBox_IsSelected 1658 +#define wxListBox_Set 1659 +#define wxListBox_HitTest 1660 +#define wxListBox_SetFirstItem_1_0 1661 +#define wxListBox_SetFirstItem_1_1 1662 +#define wxListCtrl_new_0 1663 +#define wxListCtrl_new_2 1664 +#define wxListCtrl_Arrange 1665 +#define wxListCtrl_AssignImageList 1666 +#define wxListCtrl_ClearAll 1667 +#define wxListCtrl_Create 1668 +#define wxListCtrl_DeleteAllItems 1669 +#define wxListCtrl_DeleteColumn 1670 +#define wxListCtrl_DeleteItem 1671 +#define wxListCtrl_EditLabel 1672 +#define wxListCtrl_EnsureVisible 1673 +#define wxListCtrl_FindItem_3_0 1674 +#define wxListCtrl_FindItem_3_1 1675 +#define wxListCtrl_GetColumn 1676 +#define wxListCtrl_GetColumnCount 1677 +#define wxListCtrl_GetColumnWidth 1678 +#define wxListCtrl_GetCountPerPage 1679 +#define wxListCtrl_GetEditControl 1680 +#define wxListCtrl_GetImageList 1681 +#define wxListCtrl_GetItem 1682 +#define wxListCtrl_GetItemBackgroundColour 1683 +#define wxListCtrl_GetItemCount 1684 +#define wxListCtrl_GetItemData 1685 +#define wxListCtrl_GetItemFont 1686 +#define wxListCtrl_GetItemPosition 1687 +#define wxListCtrl_GetItemRect 1688 +#define wxListCtrl_GetItemSpacing 1689 +#define wxListCtrl_GetItemState 1690 +#define wxListCtrl_GetItemText 1691 +#define wxListCtrl_GetItemTextColour 1692 +#define wxListCtrl_GetNextItem 1693 +#define wxListCtrl_GetSelectedItemCount 1694 +#define wxListCtrl_GetTextColour 1695 +#define wxListCtrl_GetTopItem 1696 +#define wxListCtrl_GetViewRect 1697 +#define wxListCtrl_HitTest 1698 +#define wxListCtrl_InsertColumn_2 1699 +#define wxListCtrl_InsertColumn_3 1700 +#define wxListCtrl_InsertItem_1 1701 +#define wxListCtrl_InsertItem_2_1 1702 +#define wxListCtrl_InsertItem_2_0 1703 +#define wxListCtrl_InsertItem_3 1704 +#define wxListCtrl_RefreshItem 1705 +#define wxListCtrl_RefreshItems 1706 +#define wxListCtrl_ScrollList 1707 +#define wxListCtrl_SetBackgroundColour 1708 +#define wxListCtrl_SetColumn 1709 +#define wxListCtrl_SetColumnWidth 1710 +#define wxListCtrl_SetImageList 1711 +#define wxListCtrl_SetItem_1 1712 +#define wxListCtrl_SetItem_4 1713 +#define wxListCtrl_SetItemBackgroundColour 1714 +#define wxListCtrl_SetItemCount 1715 +#define wxListCtrl_SetItemData 1716 +#define wxListCtrl_SetItemFont 1717 +#define wxListCtrl_SetItemImage 1718 +#define wxListCtrl_SetItemColumnImage 1719 +#define wxListCtrl_SetItemPosition 1720 +#define wxListCtrl_SetItemState 1721 +#define wxListCtrl_SetItemText 1722 +#define wxListCtrl_SetItemTextColour 1723 +#define wxListCtrl_SetSingleStyle 1724 +#define wxListCtrl_SetTextColour 1725 +#define wxListCtrl_SetWindowStyleFlag 1726 +#define wxListCtrl_SortItems 1727 +#define wxListCtrl_destroy 1728 +#define wxListView_ClearColumnImage 1729 +#define wxListView_Focus 1730 +#define wxListView_GetFirstSelected 1731 +#define wxListView_GetFocusedItem 1732 +#define wxListView_GetNextSelected 1733 +#define wxListView_IsSelected 1734 +#define wxListView_Select 1735 +#define wxListView_SetColumnImage 1736 +#define wxListItem_new_0 1737 +#define wxListItem_new_1 1738 +#define wxListItem_destruct 1739 +#define wxListItem_Clear 1740 +#define wxListItem_GetAlign 1741 +#define wxListItem_GetBackgroundColour 1742 +#define wxListItem_GetColumn 1743 +#define wxListItem_GetFont 1744 +#define wxListItem_GetId 1745 +#define wxListItem_GetImage 1746 +#define wxListItem_GetMask 1747 +#define wxListItem_GetState 1748 +#define wxListItem_GetText 1749 +#define wxListItem_GetTextColour 1750 +#define wxListItem_GetWidth 1751 +#define wxListItem_SetAlign 1752 +#define wxListItem_SetBackgroundColour 1753 +#define wxListItem_SetColumn 1754 +#define wxListItem_SetFont 1755 +#define wxListItem_SetId 1756 +#define wxListItem_SetImage 1757 +#define wxListItem_SetMask 1758 +#define wxListItem_SetState 1759 +#define wxListItem_SetStateMask 1760 +#define wxListItem_SetText 1761 +#define wxListItem_SetTextColour 1762 +#define wxListItem_SetWidth 1763 +#define wxListItemAttr_new_0 1764 +#define wxListItemAttr_new_3 1765 +#define wxListItemAttr_GetBackgroundColour 1766 +#define wxListItemAttr_GetFont 1767 +#define wxListItemAttr_GetTextColour 1768 +#define wxListItemAttr_HasBackgroundColour 1769 +#define wxListItemAttr_HasFont 1770 +#define wxListItemAttr_HasTextColour 1771 +#define wxListItemAttr_SetBackgroundColour 1772 +#define wxListItemAttr_SetFont 1773 +#define wxListItemAttr_SetTextColour 1774 +#define wxListItemAttr_destroy 1775 +#define wxImageList_new_0 1776 +#define wxImageList_new_3 1777 +#define wxImageList_Add_1 1778 +#define wxImageList_Add_2_0 1779 +#define wxImageList_Add_2_1 1780 +#define wxImageList_Create 1781 +#define wxImageList_Draw 1783 +#define wxImageList_GetBitmap 1784 +#define wxImageList_GetIcon 1785 +#define wxImageList_GetImageCount 1786 +#define wxImageList_GetSize 1787 +#define wxImageList_Remove 1788 +#define wxImageList_RemoveAll 1789 +#define wxImageList_Replace_2 1790 +#define wxImageList_Replace_3 1791 +#define wxImageList_destroy 1792 +#define wxTextAttr_new_0 1793 +#define wxTextAttr_new_2 1794 +#define wxTextAttr_GetAlignment 1795 +#define wxTextAttr_GetBackgroundColour 1796 +#define wxTextAttr_GetFont 1797 +#define wxTextAttr_GetLeftIndent 1798 +#define wxTextAttr_GetLeftSubIndent 1799 +#define wxTextAttr_GetRightIndent 1800 +#define wxTextAttr_GetTabs 1801 +#define wxTextAttr_GetTextColour 1802 +#define wxTextAttr_HasBackgroundColour 1803 +#define wxTextAttr_HasFont 1804 +#define wxTextAttr_HasTextColour 1805 +#define wxTextAttr_GetFlags 1806 +#define wxTextAttr_IsDefault 1807 +#define wxTextAttr_SetAlignment 1808 +#define wxTextAttr_SetBackgroundColour 1809 +#define wxTextAttr_SetFlags 1810 +#define wxTextAttr_SetFont 1811 +#define wxTextAttr_SetLeftIndent 1812 +#define wxTextAttr_SetRightIndent 1813 +#define wxTextAttr_SetTabs 1814 +#define wxTextAttr_SetTextColour 1815 +#define wxTextAttr_destroy 1816 +#define wxTextCtrl_new_3 1818 +#define wxTextCtrl_new_0 1819 +#define wxTextCtrl_destruct 1821 +#define wxTextCtrl_AppendText 1822 +#define wxTextCtrl_CanCopy 1823 +#define wxTextCtrl_CanCut 1824 +#define wxTextCtrl_CanPaste 1825 +#define wxTextCtrl_CanRedo 1826 +#define wxTextCtrl_CanUndo 1827 +#define wxTextCtrl_Clear 1828 +#define wxTextCtrl_Copy 1829 +#define wxTextCtrl_Create 1830 +#define wxTextCtrl_Cut 1831 +#define wxTextCtrl_DiscardEdits 1832 +#define wxTextCtrl_ChangeValue 1833 +#define wxTextCtrl_EmulateKeyPress 1834 +#define wxTextCtrl_GetDefaultStyle 1835 +#define wxTextCtrl_GetInsertionPoint 1836 +#define wxTextCtrl_GetLastPosition 1837 +#define wxTextCtrl_GetLineLength 1838 +#define wxTextCtrl_GetLineText 1839 +#define wxTextCtrl_GetNumberOfLines 1840 +#define wxTextCtrl_GetRange 1841 +#define wxTextCtrl_GetSelection 1842 +#define wxTextCtrl_GetStringSelection 1843 +#define wxTextCtrl_GetStyle 1844 +#define wxTextCtrl_GetValue 1845 +#define wxTextCtrl_IsEditable 1846 +#define wxTextCtrl_IsModified 1847 +#define wxTextCtrl_IsMultiLine 1848 +#define wxTextCtrl_IsSingleLine 1849 +#define wxTextCtrl_LoadFile 1850 +#define wxTextCtrl_MarkDirty 1851 +#define wxTextCtrl_Paste 1852 +#define wxTextCtrl_PositionToXY 1853 +#define wxTextCtrl_Redo 1854 +#define wxTextCtrl_Remove 1855 +#define wxTextCtrl_Replace 1856 +#define wxTextCtrl_SaveFile 1857 +#define wxTextCtrl_SetDefaultStyle 1858 +#define wxTextCtrl_SetEditable 1859 +#define wxTextCtrl_SetInsertionPoint 1860 +#define wxTextCtrl_SetInsertionPointEnd 1861 +#define wxTextCtrl_SetMaxLength 1863 +#define wxTextCtrl_SetSelection 1864 +#define wxTextCtrl_SetStyle 1865 +#define wxTextCtrl_SetValue 1866 +#define wxTextCtrl_ShowPosition 1867 +#define wxTextCtrl_Undo 1868 +#define wxTextCtrl_WriteText 1869 +#define wxTextCtrl_XYToPosition 1870 +#define wxNotebook_new_0 1873 +#define wxNotebook_new_3 1874 +#define wxNotebook_destruct 1875 +#define wxNotebook_AddPage 1876 +#define wxNotebook_AdvanceSelection 1877 +#define wxNotebook_AssignImageList 1878 +#define wxNotebook_Create 1879 +#define wxNotebook_DeleteAllPages 1880 +#define wxNotebook_DeletePage 1881 +#define wxNotebook_RemovePage 1882 +#define wxNotebook_GetCurrentPage 1883 +#define wxNotebook_GetImageList 1884 +#define wxNotebook_GetPage 1886 +#define wxNotebook_GetPageCount 1887 +#define wxNotebook_GetPageImage 1888 +#define wxNotebook_GetPageText 1889 +#define wxNotebook_GetRowCount 1890 +#define wxNotebook_GetSelection 1891 +#define wxNotebook_GetThemeBackgroundColour 1892 +#define wxNotebook_HitTest 1894 +#define wxNotebook_InsertPage 1896 +#define wxNotebook_SetImageList 1897 +#define wxNotebook_SetPadding 1898 +#define wxNotebook_SetPageSize 1899 +#define wxNotebook_SetPageImage 1900 +#define wxNotebook_SetPageText 1901 +#define wxNotebook_SetSelection 1902 +#define wxNotebook_ChangeSelection 1903 +#define wxChoicebook_new_0 1904 +#define wxChoicebook_new_3 1905 +#define wxChoicebook_AddPage 1906 +#define wxChoicebook_AdvanceSelection 1907 +#define wxChoicebook_AssignImageList 1908 +#define wxChoicebook_Create 1909 +#define wxChoicebook_DeleteAllPages 1910 +#define wxChoicebook_DeletePage 1911 +#define wxChoicebook_RemovePage 1912 +#define wxChoicebook_GetCurrentPage 1913 +#define wxChoicebook_GetImageList 1914 +#define wxChoicebook_GetPage 1916 +#define wxChoicebook_GetPageCount 1917 +#define wxChoicebook_GetPageImage 1918 +#define wxChoicebook_GetPageText 1919 +#define wxChoicebook_GetSelection 1920 +#define wxChoicebook_HitTest 1921 +#define wxChoicebook_InsertPage 1922 +#define wxChoicebook_SetImageList 1923 +#define wxChoicebook_SetPageSize 1924 +#define wxChoicebook_SetPageImage 1925 +#define wxChoicebook_SetPageText 1926 +#define wxChoicebook_SetSelection 1927 +#define wxChoicebook_ChangeSelection 1928 +#define wxChoicebook_destroy 1929 +#define wxToolbook_new_0 1930 +#define wxToolbook_new_3 1931 +#define wxToolbook_AddPage 1932 +#define wxToolbook_AdvanceSelection 1933 +#define wxToolbook_AssignImageList 1934 +#define wxToolbook_Create 1935 +#define wxToolbook_DeleteAllPages 1936 +#define wxToolbook_DeletePage 1937 +#define wxToolbook_RemovePage 1938 +#define wxToolbook_GetCurrentPage 1939 +#define wxToolbook_GetImageList 1940 +#define wxToolbook_GetPage 1942 +#define wxToolbook_GetPageCount 1943 +#define wxToolbook_GetPageImage 1944 +#define wxToolbook_GetPageText 1945 +#define wxToolbook_GetSelection 1946 +#define wxToolbook_HitTest 1948 +#define wxToolbook_InsertPage 1949 +#define wxToolbook_SetImageList 1950 +#define wxToolbook_SetPageSize 1951 +#define wxToolbook_SetPageImage 1952 +#define wxToolbook_SetPageText 1953 +#define wxToolbook_SetSelection 1954 +#define wxToolbook_ChangeSelection 1955 +#define wxToolbook_destroy 1956 +#define wxListbook_new_0 1957 +#define wxListbook_new_3 1958 +#define wxListbook_AddPage 1959 +#define wxListbook_AdvanceSelection 1960 +#define wxListbook_AssignImageList 1961 +#define wxListbook_Create 1962 +#define wxListbook_DeleteAllPages 1963 +#define wxListbook_DeletePage 1964 +#define wxListbook_RemovePage 1965 +#define wxListbook_GetCurrentPage 1966 +#define wxListbook_GetImageList 1967 +#define wxListbook_GetPage 1969 +#define wxListbook_GetPageCount 1970 +#define wxListbook_GetPageImage 1971 +#define wxListbook_GetPageText 1972 +#define wxListbook_GetSelection 1973 +#define wxListbook_HitTest 1975 +#define wxListbook_InsertPage 1976 +#define wxListbook_SetImageList 1977 +#define wxListbook_SetPageSize 1978 +#define wxListbook_SetPageImage 1979 +#define wxListbook_SetPageText 1980 +#define wxListbook_SetSelection 1981 +#define wxListbook_ChangeSelection 1982 +#define wxListbook_destroy 1983 +#define wxTreebook_new_0 1984 +#define wxTreebook_new_3 1985 +#define wxTreebook_AddPage 1986 +#define wxTreebook_AdvanceSelection 1987 +#define wxTreebook_AssignImageList 1988 +#define wxTreebook_Create 1989 +#define wxTreebook_DeleteAllPages 1990 +#define wxTreebook_DeletePage 1991 +#define wxTreebook_RemovePage 1992 +#define wxTreebook_GetCurrentPage 1993 +#define wxTreebook_GetImageList 1994 +#define wxTreebook_GetPage 1996 +#define wxTreebook_GetPageCount 1997 +#define wxTreebook_GetPageImage 1998 +#define wxTreebook_GetPageText 1999 +#define wxTreebook_GetSelection 2000 +#define wxTreebook_ExpandNode 2001 +#define wxTreebook_IsNodeExpanded 2002 +#define wxTreebook_HitTest 2004 +#define wxTreebook_InsertPage 2005 +#define wxTreebook_InsertSubPage 2006 +#define wxTreebook_SetImageList 2007 +#define wxTreebook_SetPageSize 2008 +#define wxTreebook_SetPageImage 2009 +#define wxTreebook_SetPageText 2010 +#define wxTreebook_SetSelection 2011 +#define wxTreebook_ChangeSelection 2012 +#define wxTreebook_destroy 2013 +#define wxTreeCtrl_new_2 2016 +#define wxTreeCtrl_new_0 2017 +#define wxTreeCtrl_destruct 2019 +#define wxTreeCtrl_AddRoot 2020 +#define wxTreeCtrl_AppendItem 2021 +#define wxTreeCtrl_AssignImageList 2022 +#define wxTreeCtrl_AssignStateImageList 2023 +#define wxTreeCtrl_Collapse 2024 +#define wxTreeCtrl_CollapseAndReset 2025 +#define wxTreeCtrl_Create 2026 +#define wxTreeCtrl_Delete 2027 +#define wxTreeCtrl_DeleteAllItems 2028 +#define wxTreeCtrl_DeleteChildren 2029 +#define wxTreeCtrl_EditLabel 2030 +#define wxTreeCtrl_EnsureVisible 2031 +#define wxTreeCtrl_Expand 2032 +#define wxTreeCtrl_GetBoundingRect 2033 +#define wxTreeCtrl_GetChildrenCount 2035 +#define wxTreeCtrl_GetCount 2036 +#define wxTreeCtrl_GetEditControl 2037 +#define wxTreeCtrl_GetFirstChild 2038 +#define wxTreeCtrl_GetNextChild 2039 +#define wxTreeCtrl_GetFirstVisibleItem 2040 +#define wxTreeCtrl_GetImageList 2041 +#define wxTreeCtrl_GetIndent 2042 +#define wxTreeCtrl_GetItemBackgroundColour 2043 +#define wxTreeCtrl_GetItemData 2044 +#define wxTreeCtrl_GetItemFont 2045 +#define wxTreeCtrl_GetItemImage_1 2046 +#define wxTreeCtrl_GetItemImage_2 2047 +#define wxTreeCtrl_GetItemText 2048 +#define wxTreeCtrl_GetItemTextColour 2049 +#define wxTreeCtrl_GetLastChild 2050 +#define wxTreeCtrl_GetNextSibling 2051 +#define wxTreeCtrl_GetNextVisible 2052 +#define wxTreeCtrl_GetItemParent 2053 +#define wxTreeCtrl_GetPrevSibling 2054 +#define wxTreeCtrl_GetPrevVisible 2055 +#define wxTreeCtrl_GetRootItem 2056 +#define wxTreeCtrl_GetSelection 2057 +#define wxTreeCtrl_GetSelections 2058 +#define wxTreeCtrl_GetStateImageList 2059 +#define wxTreeCtrl_HitTest 2060 +#define wxTreeCtrl_InsertItem 2062 +#define wxTreeCtrl_IsBold 2063 +#define wxTreeCtrl_IsExpanded 2064 +#define wxTreeCtrl_IsSelected 2065 +#define wxTreeCtrl_IsVisible 2066 +#define wxTreeCtrl_ItemHasChildren 2067 +#define wxTreeCtrl_IsTreeItemIdOk 2068 +#define wxTreeCtrl_PrependItem 2069 +#define wxTreeCtrl_ScrollTo 2070 +#define wxTreeCtrl_SelectItem_1 2071 +#define wxTreeCtrl_SelectItem_2 2072 +#define wxTreeCtrl_SetIndent 2073 +#define wxTreeCtrl_SetImageList 2074 +#define wxTreeCtrl_SetItemBackgroundColour 2075 +#define wxTreeCtrl_SetItemBold 2076 +#define wxTreeCtrl_SetItemData 2077 +#define wxTreeCtrl_SetItemDropHighlight 2078 +#define wxTreeCtrl_SetItemFont 2079 +#define wxTreeCtrl_SetItemHasChildren 2080 +#define wxTreeCtrl_SetItemImage_2 2081 +#define wxTreeCtrl_SetItemImage_3 2082 +#define wxTreeCtrl_SetItemText 2083 +#define wxTreeCtrl_SetItemTextColour 2084 +#define wxTreeCtrl_SetStateImageList 2085 +#define wxTreeCtrl_SetWindowStyle 2086 +#define wxTreeCtrl_SortChildren 2087 +#define wxTreeCtrl_Toggle 2088 +#define wxTreeCtrl_ToggleItemSelection 2089 +#define wxTreeCtrl_Unselect 2090 +#define wxTreeCtrl_UnselectAll 2091 +#define wxTreeCtrl_UnselectItem 2092 +#define wxScrollBar_new_0 2093 +#define wxScrollBar_new_3 2094 +#define wxScrollBar_destruct 2095 +#define wxScrollBar_Create 2096 +#define wxScrollBar_GetRange 2097 +#define wxScrollBar_GetPageSize 2098 +#define wxScrollBar_GetThumbPosition 2099 +#define wxScrollBar_GetThumbSize 2100 +#define wxScrollBar_SetThumbPosition 2101 +#define wxScrollBar_SetScrollbar 2102 +#define wxSpinButton_new_2 2104 +#define wxSpinButton_new_0 2105 +#define wxSpinButton_Create 2106 +#define wxSpinButton_GetMax 2107 +#define wxSpinButton_GetMin 2108 +#define wxSpinButton_GetValue 2109 +#define wxSpinButton_SetRange 2110 +#define wxSpinButton_SetValue 2111 +#define wxSpinButton_destroy 2112 +#define wxSpinCtrl_new_0 2113 +#define wxSpinCtrl_new_2 2114 +#define wxSpinCtrl_Create 2116 +#define wxSpinCtrl_SetValue_1_1 2119 +#define wxSpinCtrl_SetValue_1_0 2120 +#define wxSpinCtrl_GetValue 2122 +#define wxSpinCtrl_SetRange 2124 +#define wxSpinCtrl_SetSelection 2125 +#define wxSpinCtrl_GetMin 2127 +#define wxSpinCtrl_GetMax 2129 +#define wxSpinCtrl_destroy 2130 +#define wxStaticText_new_0 2131 +#define wxStaticText_new_4 2132 +#define wxStaticText_Create 2133 +#define wxStaticText_GetLabel 2134 +#define wxStaticText_SetLabel 2135 +#define wxStaticText_Wrap 2136 +#define wxStaticText_destroy 2137 +#define wxStaticBitmap_new_0 2138 +#define wxStaticBitmap_new_4 2139 +#define wxStaticBitmap_Create 2140 +#define wxStaticBitmap_GetBitmap 2141 +#define wxStaticBitmap_SetBitmap 2142 +#define wxStaticBitmap_destroy 2143 +#define wxRadioBox_new 2144 +#define wxRadioBox_destruct 2146 +#define wxRadioBox_Create 2147 +#define wxRadioBox_Enable_2 2148 +#define wxRadioBox_Enable_1 2149 +#define wxRadioBox_GetSelection 2150 +#define wxRadioBox_GetString 2151 +#define wxRadioBox_SetSelection 2152 +#define wxRadioBox_Show_2 2153 +#define wxRadioBox_Show_1 2154 +#define wxRadioBox_GetColumnCount 2155 +#define wxRadioBox_GetItemHelpText 2156 +#define wxRadioBox_GetItemToolTip 2157 +#define wxRadioBox_GetItemFromPoint 2159 +#define wxRadioBox_GetRowCount 2160 +#define wxRadioBox_IsItemEnabled 2161 +#define wxRadioBox_IsItemShown 2162 +#define wxRadioBox_SetItemHelpText 2163 +#define wxRadioBox_SetItemToolTip 2164 +#define wxRadioButton_new_0 2165 +#define wxRadioButton_new_4 2166 +#define wxRadioButton_Create 2167 +#define wxRadioButton_GetValue 2168 +#define wxRadioButton_SetValue 2169 +#define wxRadioButton_destroy 2170 +#define wxSlider_new_6 2172 +#define wxSlider_new_0 2173 +#define wxSlider_Create 2174 +#define wxSlider_GetLineSize 2175 +#define wxSlider_GetMax 2176 +#define wxSlider_GetMin 2177 +#define wxSlider_GetPageSize 2178 +#define wxSlider_GetThumbLength 2179 +#define wxSlider_GetValue 2180 +#define wxSlider_SetLineSize 2181 +#define wxSlider_SetPageSize 2182 +#define wxSlider_SetRange 2183 +#define wxSlider_SetThumbLength 2184 +#define wxSlider_SetValue 2185 +#define wxSlider_destroy 2186 +#define wxDialog_new_4 2188 +#define wxDialog_new_0 2189 +#define wxDialog_destruct 2191 +#define wxDialog_Create 2192 +#define wxDialog_CreateButtonSizer 2193 +#define wxDialog_CreateStdDialogButtonSizer 2194 +#define wxDialog_EndModal 2195 +#define wxDialog_GetAffirmativeId 2196 +#define wxDialog_GetReturnCode 2197 +#define wxDialog_IsModal 2198 +#define wxDialog_SetAffirmativeId 2199 +#define wxDialog_SetReturnCode 2200 +#define wxDialog_Show 2201 +#define wxDialog_ShowModal 2202 +#define wxColourDialog_new_0 2203 +#define wxColourDialog_new_2 2204 +#define wxColourDialog_destruct 2205 +#define wxColourDialog_Create 2206 +#define wxColourDialog_GetColourData 2207 +#define wxColourData_new_0 2208 +#define wxColourData_new_1 2209 +#define wxColourData_destruct 2210 +#define wxColourData_GetChooseFull 2211 +#define wxColourData_GetColour 2212 +#define wxColourData_GetCustomColour 2214 +#define wxColourData_SetChooseFull 2215 +#define wxColourData_SetColour 2216 +#define wxColourData_SetCustomColour 2217 +#define wxPalette_new_0 2218 +#define wxPalette_new_4 2219 +#define wxPalette_destruct 2221 +#define wxPalette_Create 2222 +#define wxPalette_GetColoursCount 2223 +#define wxPalette_GetPixel 2224 +#define wxPalette_GetRGB 2225 +#define wxPalette_IsOk 2226 +#define wxDirDialog_new 2230 +#define wxDirDialog_destruct 2231 +#define wxDirDialog_GetPath 2232 +#define wxDirDialog_GetMessage 2233 +#define wxDirDialog_SetMessage 2234 +#define wxDirDialog_SetPath 2235 +#define wxFileDialog_new 2239 +#define wxFileDialog_destruct 2240 +#define wxFileDialog_GetDirectory 2241 +#define wxFileDialog_GetFilename 2242 +#define wxFileDialog_GetFilenames 2243 +#define wxFileDialog_GetFilterIndex 2244 +#define wxFileDialog_GetMessage 2245 +#define wxFileDialog_GetPath 2246 +#define wxFileDialog_GetPaths 2247 +#define wxFileDialog_GetWildcard 2248 +#define wxFileDialog_SetDirectory 2249 +#define wxFileDialog_SetFilename 2250 +#define wxFileDialog_SetFilterIndex 2251 +#define wxFileDialog_SetMessage 2252 +#define wxFileDialog_SetPath 2253 +#define wxFileDialog_SetWildcard 2254 +#define wxPickerBase_SetInternalMargin 2255 +#define wxPickerBase_GetInternalMargin 2256 +#define wxPickerBase_SetTextCtrlProportion 2257 +#define wxPickerBase_SetPickerCtrlProportion 2258 +#define wxPickerBase_GetTextCtrlProportion 2259 +#define wxPickerBase_GetPickerCtrlProportion 2260 +#define wxPickerBase_HasTextCtrl 2261 +#define wxPickerBase_GetTextCtrl 2262 +#define wxPickerBase_IsTextCtrlGrowable 2263 +#define wxPickerBase_SetPickerCtrlGrowable 2264 +#define wxPickerBase_SetTextCtrlGrowable 2265 +#define wxPickerBase_IsPickerCtrlGrowable 2266 +#define wxFilePickerCtrl_new_0 2267 +#define wxFilePickerCtrl_new_3 2268 +#define wxFilePickerCtrl_Create 2269 +#define wxFilePickerCtrl_GetPath 2270 +#define wxFilePickerCtrl_SetPath 2271 +#define wxFilePickerCtrl_destroy 2272 +#define wxDirPickerCtrl_new_0 2273 +#define wxDirPickerCtrl_new_3 2274 +#define wxDirPickerCtrl_Create 2275 +#define wxDirPickerCtrl_GetPath 2276 +#define wxDirPickerCtrl_SetPath 2277 +#define wxDirPickerCtrl_destroy 2278 +#define wxColourPickerCtrl_new_0 2279 +#define wxColourPickerCtrl_new_3 2280 +#define wxColourPickerCtrl_Create 2281 +#define wxColourPickerCtrl_GetColour 2282 +#define wxColourPickerCtrl_SetColour_1_1 2283 +#define wxColourPickerCtrl_SetColour_1_0 2284 +#define wxColourPickerCtrl_destroy 2285 +#define wxDatePickerCtrl_new_0 2286 +#define wxDatePickerCtrl_new_3 2287 +#define wxDatePickerCtrl_GetRange 2288 +#define wxDatePickerCtrl_GetValue 2289 +#define wxDatePickerCtrl_SetRange 2290 +#define wxDatePickerCtrl_SetValue 2291 +#define wxDatePickerCtrl_destroy 2292 +#define wxFontPickerCtrl_new_0 2293 +#define wxFontPickerCtrl_new_3 2294 +#define wxFontPickerCtrl_Create 2295 +#define wxFontPickerCtrl_GetSelectedFont 2296 +#define wxFontPickerCtrl_SetSelectedFont 2297 +#define wxFontPickerCtrl_GetMaxPointSize 2298 +#define wxFontPickerCtrl_SetMaxPointSize 2299 +#define wxFontPickerCtrl_destroy 2300 +#define wxFindReplaceDialog_new_0 2303 +#define wxFindReplaceDialog_new_4 2304 +#define wxFindReplaceDialog_destruct 2305 +#define wxFindReplaceDialog_Create 2306 +#define wxFindReplaceDialog_GetData 2307 +#define wxFindReplaceData_new_0 2308 +#define wxFindReplaceData_new_1 2309 +#define wxFindReplaceData_GetFindString 2310 +#define wxFindReplaceData_GetReplaceString 2311 +#define wxFindReplaceData_GetFlags 2312 +#define wxFindReplaceData_SetFlags 2313 +#define wxFindReplaceData_SetFindString 2314 +#define wxFindReplaceData_SetReplaceString 2315 +#define wxFindReplaceData_destroy 2316 +#define wxMultiChoiceDialog_new_0 2317 +#define wxMultiChoiceDialog_new_5 2319 +#define wxMultiChoiceDialog_GetSelections 2320 +#define wxMultiChoiceDialog_SetSelections 2321 +#define wxMultiChoiceDialog_destroy 2322 +#define wxSingleChoiceDialog_new_0 2323 +#define wxSingleChoiceDialog_new_5 2325 +#define wxSingleChoiceDialog_GetSelection 2326 +#define wxSingleChoiceDialog_GetStringSelection 2327 +#define wxSingleChoiceDialog_SetSelection 2328 +#define wxSingleChoiceDialog_destroy 2329 +#define wxTextEntryDialog_new 2330 +#define wxTextEntryDialog_GetValue 2331 +#define wxTextEntryDialog_SetValue 2332 +#define wxTextEntryDialog_destroy 2333 +#define wxPasswordEntryDialog_new 2334 +#define wxPasswordEntryDialog_destroy 2335 +#define wxFontData_new_0 2336 +#define wxFontData_new_1 2337 +#define wxFontData_destruct 2338 +#define wxFontData_EnableEffects 2339 +#define wxFontData_GetAllowSymbols 2340 +#define wxFontData_GetColour 2341 +#define wxFontData_GetChosenFont 2342 +#define wxFontData_GetEnableEffects 2343 +#define wxFontData_GetInitialFont 2344 +#define wxFontData_GetShowHelp 2345 +#define wxFontData_SetAllowSymbols 2346 +#define wxFontData_SetChosenFont 2347 +#define wxFontData_SetColour 2348 +#define wxFontData_SetInitialFont 2349 +#define wxFontData_SetRange 2350 +#define wxFontData_SetShowHelp 2351 +#define wxFontDialog_new_0 2355 +#define wxFontDialog_new_2 2357 +#define wxFontDialog_Create 2359 +#define wxFontDialog_GetFontData 2360 +#define wxFontDialog_destroy 2362 +#define wxProgressDialog_new 2363 +#define wxProgressDialog_destruct 2364 +#define wxProgressDialog_Resume 2365 +#define wxProgressDialog_Update_2 2366 +#define wxProgressDialog_Update_0 2367 +#define wxMessageDialog_new 2368 +#define wxMessageDialog_destruct 2369 +#define wxPageSetupDialog_new 2370 +#define wxPageSetupDialog_destruct 2371 +#define wxPageSetupDialog_GetPageSetupData 2372 +#define wxPageSetupDialog_ShowModal 2373 +#define wxPageSetupDialogData_new_0 2374 +#define wxPageSetupDialogData_new_1_0 2375 +#define wxPageSetupDialogData_new_1_1 2376 +#define wxPageSetupDialogData_destruct 2377 +#define wxPageSetupDialogData_EnableHelp 2378 +#define wxPageSetupDialogData_EnableMargins 2379 +#define wxPageSetupDialogData_EnableOrientation 2380 +#define wxPageSetupDialogData_EnablePaper 2381 +#define wxPageSetupDialogData_EnablePrinter 2382 +#define wxPageSetupDialogData_GetDefaultMinMargins 2383 +#define wxPageSetupDialogData_GetEnableMargins 2384 +#define wxPageSetupDialogData_GetEnableOrientation 2385 +#define wxPageSetupDialogData_GetEnablePaper 2386 +#define wxPageSetupDialogData_GetEnablePrinter 2387 +#define wxPageSetupDialogData_GetEnableHelp 2388 +#define wxPageSetupDialogData_GetDefaultInfo 2389 +#define wxPageSetupDialogData_GetMarginTopLeft 2390 +#define wxPageSetupDialogData_GetMarginBottomRight 2391 +#define wxPageSetupDialogData_GetMinMarginTopLeft 2392 +#define wxPageSetupDialogData_GetMinMarginBottomRight 2393 +#define wxPageSetupDialogData_GetPaperId 2394 +#define wxPageSetupDialogData_GetPaperSize 2395 +#define wxPageSetupDialogData_GetPrintData 2397 +#define wxPageSetupDialogData_IsOk 2398 +#define wxPageSetupDialogData_SetDefaultInfo 2399 +#define wxPageSetupDialogData_SetDefaultMinMargins 2400 +#define wxPageSetupDialogData_SetMarginTopLeft 2401 +#define wxPageSetupDialogData_SetMarginBottomRight 2402 +#define wxPageSetupDialogData_SetMinMarginTopLeft 2403 +#define wxPageSetupDialogData_SetMinMarginBottomRight 2404 +#define wxPageSetupDialogData_SetPaperId 2405 +#define wxPageSetupDialogData_SetPaperSize_1_1 2406 +#define wxPageSetupDialogData_SetPaperSize_1_0 2407 +#define wxPageSetupDialogData_SetPrintData 2408 +#define wxPrintDialog_new_2_0 2409 +#define wxPrintDialog_new_2_1 2410 +#define wxPrintDialog_destruct 2411 +#define wxPrintDialog_GetPrintDialogData 2412 +#define wxPrintDialog_GetPrintDC 2413 +#define wxPrintDialogData_new_0 2414 +#define wxPrintDialogData_new_1_1 2415 +#define wxPrintDialogData_new_1_0 2416 +#define wxPrintDialogData_destruct 2417 +#define wxPrintDialogData_EnableHelp 2418 +#define wxPrintDialogData_EnablePageNumbers 2419 +#define wxPrintDialogData_EnablePrintToFile 2420 +#define wxPrintDialogData_EnableSelection 2421 +#define wxPrintDialogData_GetAllPages 2422 +#define wxPrintDialogData_GetCollate 2423 +#define wxPrintDialogData_GetFromPage 2424 +#define wxPrintDialogData_GetMaxPage 2425 +#define wxPrintDialogData_GetMinPage 2426 +#define wxPrintDialogData_GetNoCopies 2427 +#define wxPrintDialogData_GetPrintData 2428 +#define wxPrintDialogData_GetPrintToFile 2429 +#define wxPrintDialogData_GetSelection 2430 +#define wxPrintDialogData_GetToPage 2431 +#define wxPrintDialogData_IsOk 2432 +#define wxPrintDialogData_SetCollate 2433 +#define wxPrintDialogData_SetFromPage 2434 +#define wxPrintDialogData_SetMaxPage 2435 +#define wxPrintDialogData_SetMinPage 2436 +#define wxPrintDialogData_SetNoCopies 2437 +#define wxPrintDialogData_SetPrintData 2438 +#define wxPrintDialogData_SetPrintToFile 2439 +#define wxPrintDialogData_SetSelection 2440 +#define wxPrintDialogData_SetToPage 2441 +#define wxPrintData_new_0 2442 +#define wxPrintData_new_1 2443 +#define wxPrintData_destruct 2444 +#define wxPrintData_GetCollate 2445 +#define wxPrintData_GetBin 2446 +#define wxPrintData_GetColour 2447 +#define wxPrintData_GetDuplex 2448 +#define wxPrintData_GetNoCopies 2449 +#define wxPrintData_GetOrientation 2450 +#define wxPrintData_GetPaperId 2451 +#define wxPrintData_GetPrinterName 2452 +#define wxPrintData_GetQuality 2453 +#define wxPrintData_IsOk 2454 +#define wxPrintData_SetBin 2455 +#define wxPrintData_SetCollate 2456 +#define wxPrintData_SetColour 2457 +#define wxPrintData_SetDuplex 2458 +#define wxPrintData_SetNoCopies 2459 +#define wxPrintData_SetOrientation 2460 +#define wxPrintData_SetPaperId 2461 +#define wxPrintData_SetPrinterName 2462 +#define wxPrintData_SetQuality 2463 +#define wxPrintPreview_new_2 2466 +#define wxPrintPreview_new_3 2467 +#define wxPrintPreview_destruct 2469 +#define wxPrintPreview_GetCanvas 2470 +#define wxPrintPreview_GetCurrentPage 2471 +#define wxPrintPreview_GetFrame 2472 +#define wxPrintPreview_GetMaxPage 2473 +#define wxPrintPreview_GetMinPage 2474 +#define wxPrintPreview_GetPrintout 2475 +#define wxPrintPreview_GetPrintoutForPrinting 2476 +#define wxPrintPreview_IsOk 2477 +#define wxPrintPreview_PaintPage 2478 +#define wxPrintPreview_Print 2479 +#define wxPrintPreview_RenderPage 2480 +#define wxPrintPreview_SetCanvas 2481 +#define wxPrintPreview_SetCurrentPage 2482 +#define wxPrintPreview_SetFrame 2483 +#define wxPrintPreview_SetPrintout 2484 +#define wxPrintPreview_SetZoom 2485 +#define wxPreviewFrame_new 2486 +#define wxPreviewFrame_destruct 2487 +#define wxPreviewFrame_CreateControlBar 2488 +#define wxPreviewFrame_CreateCanvas 2489 +#define wxPreviewFrame_Initialize 2490 +#define wxPreviewFrame_OnCloseWindow 2491 +#define wxPreviewControlBar_new 2492 +#define wxPreviewControlBar_destruct 2493 +#define wxPreviewControlBar_CreateButtons 2494 +#define wxPreviewControlBar_GetPrintPreview 2495 +#define wxPreviewControlBar_GetZoomControl 2496 +#define wxPreviewControlBar_SetZoomControl 2497 +#define wxPrinter_new 2499 +#define wxPrinter_CreateAbortWindow 2500 +#define wxPrinter_GetAbort 2501 +#define wxPrinter_GetLastError 2502 +#define wxPrinter_GetPrintDialogData 2503 +#define wxPrinter_Print 2504 +#define wxPrinter_PrintDialog 2505 +#define wxPrinter_ReportError 2506 +#define wxPrinter_Setup 2507 +#define wxPrinter_destroy 2508 +#define wxXmlResource_new_1 2509 +#define wxXmlResource_new_2 2510 +#define wxXmlResource_destruct 2511 +#define wxXmlResource_AttachUnknownControl 2512 +#define wxXmlResource_ClearHandlers 2513 +#define wxXmlResource_CompareVersion 2514 +#define wxXmlResource_Get 2515 +#define wxXmlResource_GetFlags 2516 +#define wxXmlResource_GetVersion 2517 +#define wxXmlResource_GetXRCID 2518 +#define wxXmlResource_InitAllHandlers 2519 +#define wxXmlResource_Load 2520 +#define wxXmlResource_LoadBitmap 2521 +#define wxXmlResource_LoadDialog_2 2522 +#define wxXmlResource_LoadDialog_3 2523 +#define wxXmlResource_LoadFrame_2 2524 +#define wxXmlResource_LoadFrame_3 2525 +#define wxXmlResource_LoadIcon 2526 +#define wxXmlResource_LoadMenu 2527 +#define wxXmlResource_LoadMenuBar_2 2528 +#define wxXmlResource_LoadMenuBar_1 2529 +#define wxXmlResource_LoadPanel_2 2530 +#define wxXmlResource_LoadPanel_3 2531 +#define wxXmlResource_LoadToolBar 2532 +#define wxXmlResource_Set 2533 +#define wxXmlResource_SetFlags 2534 +#define wxXmlResource_Unload 2535 +#define wxXmlResource_xrcctrl 2536 +#define wxHtmlEasyPrinting_new 2537 +#define wxHtmlEasyPrinting_destruct 2538 +#define wxHtmlEasyPrinting_GetPrintData 2539 +#define wxHtmlEasyPrinting_GetPageSetupData 2540 +#define wxHtmlEasyPrinting_PreviewFile 2541 +#define wxHtmlEasyPrinting_PreviewText 2542 +#define wxHtmlEasyPrinting_PrintFile 2543 +#define wxHtmlEasyPrinting_PrintText 2544 +#define wxHtmlEasyPrinting_PageSetup 2545 +#define wxHtmlEasyPrinting_SetFonts 2546 +#define wxHtmlEasyPrinting_SetHeader 2547 +#define wxHtmlEasyPrinting_SetFooter 2548 +#define wxGLCanvas_new_2 2550 +#define wxGLCanvas_new_3_1 2551 +#define wxGLCanvas_new_3_0 2552 +#define wxGLCanvas_GetContext 2553 +#define wxGLCanvas_SetCurrent 2555 +#define wxGLCanvas_SwapBuffers 2556 +#define wxGLCanvas_destroy 2557 +#define wxAuiManager_new 2558 +#define wxAuiManager_destruct 2559 +#define wxAuiManager_AddPane_2_1 2560 +#define wxAuiManager_AddPane_3 2561 +#define wxAuiManager_AddPane_2_0 2562 +#define wxAuiManager_DetachPane 2563 +#define wxAuiManager_GetAllPanes 2564 +#define wxAuiManager_GetArtProvider 2565 +#define wxAuiManager_GetDockSizeConstraint 2566 +#define wxAuiManager_GetFlags 2567 +#define wxAuiManager_GetManagedWindow 2568 +#define wxAuiManager_GetManager 2569 +#define wxAuiManager_GetPane_1_1 2570 +#define wxAuiManager_GetPane_1_0 2571 +#define wxAuiManager_HideHint 2572 +#define wxAuiManager_InsertPane 2573 +#define wxAuiManager_LoadPaneInfo 2574 +#define wxAuiManager_LoadPerspective 2575 +#define wxAuiManager_SavePaneInfo 2576 +#define wxAuiManager_SavePerspective 2577 +#define wxAuiManager_SetArtProvider 2578 +#define wxAuiManager_SetDockSizeConstraint 2579 +#define wxAuiManager_SetFlags 2580 +#define wxAuiManager_SetManagedWindow 2581 +#define wxAuiManager_ShowHint 2582 +#define wxAuiManager_UnInit 2583 +#define wxAuiManager_Update 2584 +#define wxAuiPaneInfo_new_0 2585 +#define wxAuiPaneInfo_new_1 2586 +#define wxAuiPaneInfo_destruct 2587 +#define wxAuiPaneInfo_BestSize_1 2588 +#define wxAuiPaneInfo_BestSize_2 2589 +#define wxAuiPaneInfo_Bottom 2590 +#define wxAuiPaneInfo_BottomDockable 2591 +#define wxAuiPaneInfo_Caption 2592 +#define wxAuiPaneInfo_CaptionVisible 2593 +#define wxAuiPaneInfo_Centre 2594 +#define wxAuiPaneInfo_CentrePane 2595 +#define wxAuiPaneInfo_CloseButton 2596 +#define wxAuiPaneInfo_DefaultPane 2597 +#define wxAuiPaneInfo_DestroyOnClose 2598 +#define wxAuiPaneInfo_Direction 2599 +#define wxAuiPaneInfo_Dock 2600 +#define wxAuiPaneInfo_Dockable 2601 +#define wxAuiPaneInfo_Fixed 2602 +#define wxAuiPaneInfo_Float 2603 +#define wxAuiPaneInfo_Floatable 2604 +#define wxAuiPaneInfo_FloatingPosition_1 2605 +#define wxAuiPaneInfo_FloatingPosition_2 2606 +#define wxAuiPaneInfo_FloatingSize_1 2607 +#define wxAuiPaneInfo_FloatingSize_2 2608 +#define wxAuiPaneInfo_Gripper 2609 +#define wxAuiPaneInfo_GripperTop 2610 +#define wxAuiPaneInfo_HasBorder 2611 +#define wxAuiPaneInfo_HasCaption 2612 +#define wxAuiPaneInfo_HasCloseButton 2613 +#define wxAuiPaneInfo_HasFlag 2614 +#define wxAuiPaneInfo_HasGripper 2615 +#define wxAuiPaneInfo_HasGripperTop 2616 +#define wxAuiPaneInfo_HasMaximizeButton 2617 +#define wxAuiPaneInfo_HasMinimizeButton 2618 +#define wxAuiPaneInfo_HasPinButton 2619 +#define wxAuiPaneInfo_Hide 2620 +#define wxAuiPaneInfo_IsBottomDockable 2621 +#define wxAuiPaneInfo_IsDocked 2622 +#define wxAuiPaneInfo_IsFixed 2623 +#define wxAuiPaneInfo_IsFloatable 2624 +#define wxAuiPaneInfo_IsFloating 2625 +#define wxAuiPaneInfo_IsLeftDockable 2626 +#define wxAuiPaneInfo_IsMovable 2627 +#define wxAuiPaneInfo_IsOk 2628 +#define wxAuiPaneInfo_IsResizable 2629 +#define wxAuiPaneInfo_IsRightDockable 2630 +#define wxAuiPaneInfo_IsShown 2631 +#define wxAuiPaneInfo_IsToolbar 2632 +#define wxAuiPaneInfo_IsTopDockable 2633 +#define wxAuiPaneInfo_Layer 2634 +#define wxAuiPaneInfo_Left 2635 +#define wxAuiPaneInfo_LeftDockable 2636 +#define wxAuiPaneInfo_MaxSize_1 2637 +#define wxAuiPaneInfo_MaxSize_2 2638 +#define wxAuiPaneInfo_MaximizeButton 2639 +#define wxAuiPaneInfo_MinSize_1 2640 +#define wxAuiPaneInfo_MinSize_2 2641 +#define wxAuiPaneInfo_MinimizeButton 2642 +#define wxAuiPaneInfo_Movable 2643 +#define wxAuiPaneInfo_Name 2644 +#define wxAuiPaneInfo_PaneBorder 2645 +#define wxAuiPaneInfo_PinButton 2646 +#define wxAuiPaneInfo_Position 2647 +#define wxAuiPaneInfo_Resizable 2648 +#define wxAuiPaneInfo_Right 2649 +#define wxAuiPaneInfo_RightDockable 2650 +#define wxAuiPaneInfo_Row 2651 +#define wxAuiPaneInfo_SafeSet 2652 +#define wxAuiPaneInfo_SetFlag 2653 +#define wxAuiPaneInfo_Show 2654 +#define wxAuiPaneInfo_ToolbarPane 2655 +#define wxAuiPaneInfo_Top 2656 +#define wxAuiPaneInfo_TopDockable 2657 +#define wxAuiPaneInfo_Window 2658 +#define wxAuiPaneInfo_GetWindow 2659 +#define wxAuiPaneInfo_GetFrame 2660 +#define wxAuiPaneInfo_GetDirection 2661 +#define wxAuiPaneInfo_GetLayer 2662 +#define wxAuiPaneInfo_GetRow 2663 +#define wxAuiPaneInfo_GetPosition 2664 +#define wxAuiPaneInfo_GetFloatingPosition 2665 +#define wxAuiPaneInfo_GetFloatingSize 2666 +#define wxAuiNotebook_new_0 2667 +#define wxAuiNotebook_new_2 2668 +#define wxAuiNotebook_AddPage 2669 +#define wxAuiNotebook_Create 2670 +#define wxAuiNotebook_DeletePage 2671 +#define wxAuiNotebook_GetArtProvider 2672 +#define wxAuiNotebook_GetPage 2673 +#define wxAuiNotebook_GetPageBitmap 2674 +#define wxAuiNotebook_GetPageCount 2675 +#define wxAuiNotebook_GetPageIndex 2676 +#define wxAuiNotebook_GetPageText 2677 +#define wxAuiNotebook_GetSelection 2678 +#define wxAuiNotebook_InsertPage 2679 +#define wxAuiNotebook_RemovePage 2680 +#define wxAuiNotebook_SetArtProvider 2681 +#define wxAuiNotebook_SetFont 2682 +#define wxAuiNotebook_SetPageBitmap 2683 +#define wxAuiNotebook_SetPageText 2684 +#define wxAuiNotebook_SetSelection 2685 +#define wxAuiNotebook_SetTabCtrlHeight 2686 +#define wxAuiNotebook_SetUniformBitmapSize 2687 +#define wxAuiNotebook_destroy 2688 +#define wxAuiTabArt_SetFlags 2689 +#define wxAuiTabArt_SetMeasuringFont 2690 +#define wxAuiTabArt_SetNormalFont 2691 +#define wxAuiTabArt_SetSelectedFont 2692 +#define wxAuiTabArt_SetColour 2693 +#define wxAuiTabArt_SetActiveColour 2694 +#define wxAuiDockArt_GetColour 2695 +#define wxAuiDockArt_GetFont 2696 +#define wxAuiDockArt_GetMetric 2697 +#define wxAuiDockArt_SetColour 2698 +#define wxAuiDockArt_SetFont 2699 +#define wxAuiDockArt_SetMetric 2700 +#define wxAuiSimpleTabArt_new 2701 +#define wxAuiSimpleTabArt_destroy 2702 +#define wxMDIParentFrame_new_0 2703 +#define wxMDIParentFrame_new_4 2704 +#define wxMDIParentFrame_destruct 2705 +#define wxMDIParentFrame_ActivateNext 2706 +#define wxMDIParentFrame_ActivatePrevious 2707 +#define wxMDIParentFrame_ArrangeIcons 2708 +#define wxMDIParentFrame_Cascade 2709 +#define wxMDIParentFrame_Create 2710 +#define wxMDIParentFrame_GetActiveChild 2711 +#define wxMDIParentFrame_GetClientWindow 2712 +#define wxMDIParentFrame_Tile 2713 +#define wxMDIChildFrame_new_0 2714 +#define wxMDIChildFrame_new_4 2715 +#define wxMDIChildFrame_destruct 2716 +#define wxMDIChildFrame_Activate 2717 +#define wxMDIChildFrame_Create 2718 +#define wxMDIChildFrame_Maximize 2719 +#define wxMDIChildFrame_Restore 2720 +#define wxMDIClientWindow_new_0 2721 +#define wxMDIClientWindow_new_2 2722 +#define wxMDIClientWindow_destruct 2723 +#define wxMDIClientWindow_CreateClient 2724 +#define wxLayoutAlgorithm_new 2725 +#define wxLayoutAlgorithm_LayoutFrame 2726 +#define wxLayoutAlgorithm_LayoutMDIFrame 2727 +#define wxLayoutAlgorithm_LayoutWindow 2728 +#define wxLayoutAlgorithm_destroy 2729 +#define wxEvent_GetId 2730 +#define wxEvent_GetSkipped 2731 +#define wxEvent_GetTimestamp 2732 +#define wxEvent_IsCommandEvent 2733 +#define wxEvent_ResumePropagation 2734 +#define wxEvent_ShouldPropagate 2735 +#define wxEvent_Skip 2736 +#define wxEvent_StopPropagation 2737 +#define wxCommandEvent_getClientData 2738 +#define wxCommandEvent_GetExtraLong 2739 +#define wxCommandEvent_GetInt 2740 +#define wxCommandEvent_GetSelection 2741 +#define wxCommandEvent_GetString 2742 +#define wxCommandEvent_IsChecked 2743 +#define wxCommandEvent_IsSelection 2744 +#define wxCommandEvent_SetInt 2745 +#define wxCommandEvent_SetString 2746 +#define wxScrollEvent_GetOrientation 2747 +#define wxScrollEvent_GetPosition 2748 +#define wxScrollWinEvent_GetOrientation 2749 +#define wxScrollWinEvent_GetPosition 2750 +#define wxMouseEvent_AltDown 2751 +#define wxMouseEvent_Button 2752 +#define wxMouseEvent_ButtonDClick 2753 +#define wxMouseEvent_ButtonDown 2754 +#define wxMouseEvent_ButtonUp 2755 +#define wxMouseEvent_CmdDown 2756 +#define wxMouseEvent_ControlDown 2757 +#define wxMouseEvent_Dragging 2758 +#define wxMouseEvent_Entering 2759 +#define wxMouseEvent_GetButton 2760 +#define wxMouseEvent_GetPosition 2763 +#define wxMouseEvent_GetLogicalPosition 2764 +#define wxMouseEvent_GetLinesPerAction 2765 +#define wxMouseEvent_GetWheelRotation 2766 +#define wxMouseEvent_GetWheelDelta 2767 +#define wxMouseEvent_GetX 2768 +#define wxMouseEvent_GetY 2769 +#define wxMouseEvent_IsButton 2770 +#define wxMouseEvent_IsPageScroll 2771 +#define wxMouseEvent_Leaving 2772 +#define wxMouseEvent_LeftDClick 2773 +#define wxMouseEvent_LeftDown 2774 +#define wxMouseEvent_LeftIsDown 2775 +#define wxMouseEvent_LeftUp 2776 +#define wxMouseEvent_MetaDown 2777 +#define wxMouseEvent_MiddleDClick 2778 +#define wxMouseEvent_MiddleDown 2779 +#define wxMouseEvent_MiddleIsDown 2780 +#define wxMouseEvent_MiddleUp 2781 +#define wxMouseEvent_Moving 2782 +#define wxMouseEvent_RightDClick 2783 +#define wxMouseEvent_RightDown 2784 +#define wxMouseEvent_RightIsDown 2785 +#define wxMouseEvent_RightUp 2786 +#define wxMouseEvent_ShiftDown 2787 +#define wxSetCursorEvent_GetCursor 2788 +#define wxSetCursorEvent_GetX 2789 +#define wxSetCursorEvent_GetY 2790 +#define wxSetCursorEvent_HasCursor 2791 +#define wxSetCursorEvent_SetCursor 2792 +#define wxKeyEvent_AltDown 2793 +#define wxKeyEvent_CmdDown 2794 +#define wxKeyEvent_ControlDown 2795 +#define wxKeyEvent_GetKeyCode 2796 +#define wxKeyEvent_GetModifiers 2797 +#define wxKeyEvent_GetPosition 2800 +#define wxKeyEvent_GetRawKeyCode 2801 +#define wxKeyEvent_GetRawKeyFlags 2802 +#define wxKeyEvent_GetUnicodeKey 2803 +#define wxKeyEvent_GetX 2804 +#define wxKeyEvent_GetY 2805 +#define wxKeyEvent_HasModifiers 2806 +#define wxKeyEvent_MetaDown 2807 +#define wxKeyEvent_ShiftDown 2808 +#define wxSizeEvent_GetSize 2809 +#define wxMoveEvent_GetPosition 2810 +#define wxEraseEvent_GetDC 2811 +#define wxFocusEvent_GetWindow 2812 +#define wxChildFocusEvent_GetWindow 2813 +#define wxMenuEvent_GetMenu 2814 +#define wxMenuEvent_GetMenuId 2815 +#define wxMenuEvent_IsPopup 2816 +#define wxCloseEvent_CanVeto 2817 +#define wxCloseEvent_GetLoggingOff 2818 +#define wxCloseEvent_SetCanVeto 2819 +#define wxCloseEvent_SetLoggingOff 2820 +#define wxCloseEvent_Veto 2821 +#define wxShowEvent_SetShow 2822 +#define wxShowEvent_GetShow 2823 +#define wxIconizeEvent_Iconized 2824 +#define wxJoystickEvent_ButtonDown 2825 +#define wxJoystickEvent_ButtonIsDown 2826 +#define wxJoystickEvent_ButtonUp 2827 +#define wxJoystickEvent_GetButtonChange 2828 +#define wxJoystickEvent_GetButtonState 2829 +#define wxJoystickEvent_GetJoystick 2830 +#define wxJoystickEvent_GetPosition 2831 +#define wxJoystickEvent_GetZPosition 2832 +#define wxJoystickEvent_IsButton 2833 +#define wxJoystickEvent_IsMove 2834 +#define wxJoystickEvent_IsZMove 2835 +#define wxUpdateUIEvent_CanUpdate 2836 +#define wxUpdateUIEvent_Check 2837 +#define wxUpdateUIEvent_Enable 2838 +#define wxUpdateUIEvent_Show 2839 +#define wxUpdateUIEvent_GetChecked 2840 +#define wxUpdateUIEvent_GetEnabled 2841 +#define wxUpdateUIEvent_GetShown 2842 +#define wxUpdateUIEvent_GetSetChecked 2843 +#define wxUpdateUIEvent_GetSetEnabled 2844 +#define wxUpdateUIEvent_GetSetShown 2845 +#define wxUpdateUIEvent_GetSetText 2846 +#define wxUpdateUIEvent_GetText 2847 +#define wxUpdateUIEvent_GetMode 2848 +#define wxUpdateUIEvent_GetUpdateInterval 2849 +#define wxUpdateUIEvent_ResetUpdateTime 2850 +#define wxUpdateUIEvent_SetMode 2851 +#define wxUpdateUIEvent_SetText 2852 +#define wxUpdateUIEvent_SetUpdateInterval 2853 +#define wxMouseCaptureChangedEvent_GetCapturedWindow 2854 +#define wxPaletteChangedEvent_SetChangedWindow 2855 +#define wxPaletteChangedEvent_GetChangedWindow 2856 +#define wxQueryNewPaletteEvent_SetPaletteRealized 2857 +#define wxQueryNewPaletteEvent_GetPaletteRealized 2858 +#define wxNavigationKeyEvent_GetDirection 2859 +#define wxNavigationKeyEvent_SetDirection 2860 +#define wxNavigationKeyEvent_IsWindowChange 2861 +#define wxNavigationKeyEvent_SetWindowChange 2862 +#define wxNavigationKeyEvent_IsFromTab 2863 +#define wxNavigationKeyEvent_SetFromTab 2864 +#define wxNavigationKeyEvent_GetCurrentFocus 2865 +#define wxNavigationKeyEvent_SetCurrentFocus 2866 +#define wxHelpEvent_GetOrigin 2867 +#define wxHelpEvent_GetPosition 2868 +#define wxHelpEvent_SetOrigin 2869 +#define wxHelpEvent_SetPosition 2870 +#define wxContextMenuEvent_GetPosition 2871 +#define wxContextMenuEvent_SetPosition 2872 +#define wxIdleEvent_CanSend 2873 +#define wxIdleEvent_GetMode 2874 +#define wxIdleEvent_RequestMore 2875 +#define wxIdleEvent_MoreRequested 2876 +#define wxIdleEvent_SetMode 2877 +#define wxGridEvent_AltDown 2878 +#define wxGridEvent_ControlDown 2879 +#define wxGridEvent_GetCol 2880 +#define wxGridEvent_GetPosition 2881 +#define wxGridEvent_GetRow 2882 +#define wxGridEvent_MetaDown 2883 +#define wxGridEvent_Selecting 2884 +#define wxGridEvent_ShiftDown 2885 +#define wxNotifyEvent_Allow 2886 +#define wxNotifyEvent_IsAllowed 2887 +#define wxNotifyEvent_Veto 2888 +#define wxSashEvent_GetEdge 2889 +#define wxSashEvent_GetDragRect 2890 +#define wxSashEvent_GetDragStatus 2891 +#define wxListEvent_GetCacheFrom 2892 +#define wxListEvent_GetCacheTo 2893 +#define wxListEvent_GetKeyCode 2894 +#define wxListEvent_GetIndex 2895 +#define wxListEvent_GetColumn 2896 +#define wxListEvent_GetPoint 2897 +#define wxListEvent_GetLabel 2898 +#define wxListEvent_GetText 2899 +#define wxListEvent_GetImage 2900 +#define wxListEvent_GetData 2901 +#define wxListEvent_GetMask 2902 +#define wxListEvent_GetItem 2903 +#define wxListEvent_IsEditCancelled 2904 +#define wxDateEvent_GetDate 2905 +#define wxCalendarEvent_GetWeekDay 2906 +#define wxFileDirPickerEvent_GetPath 2907 +#define wxColourPickerEvent_GetColour 2908 +#define wxFontPickerEvent_GetFont 2909 +#define wxStyledTextEvent_GetPosition 2910 +#define wxStyledTextEvent_GetKey 2911 +#define wxStyledTextEvent_GetModifiers 2912 +#define wxStyledTextEvent_GetModificationType 2913 +#define wxStyledTextEvent_GetText 2914 +#define wxStyledTextEvent_GetLength 2915 +#define wxStyledTextEvent_GetLinesAdded 2916 +#define wxStyledTextEvent_GetLine 2917 +#define wxStyledTextEvent_GetFoldLevelNow 2918 +#define wxStyledTextEvent_GetFoldLevelPrev 2919 +#define wxStyledTextEvent_GetMargin 2920 +#define wxStyledTextEvent_GetMessage 2921 +#define wxStyledTextEvent_GetWParam 2922 +#define wxStyledTextEvent_GetLParam 2923 +#define wxStyledTextEvent_GetListType 2924 +#define wxStyledTextEvent_GetX 2925 +#define wxStyledTextEvent_GetY 2926 +#define wxStyledTextEvent_GetDragText 2927 +#define wxStyledTextEvent_GetDragAllowMove 2928 +#define wxStyledTextEvent_GetDragResult 2929 +#define wxStyledTextEvent_GetShift 2930 +#define wxStyledTextEvent_GetControl 2931 +#define wxStyledTextEvent_GetAlt 2932 +#define utils_wxGetKeyState 2933 +#define utils_wxGetMousePosition 2934 +#define utils_wxGetMouseState 2935 +#define utils_wxSetDetectableAutoRepeat 2936 +#define utils_wxBell 2937 +#define utils_wxFindMenuItemId 2938 +#define utils_wxGenericFindWindowAtPoint 2939 +#define utils_wxFindWindowAtPoint 2940 +#define utils_wxBeginBusyCursor 2941 +#define utils_wxEndBusyCursor 2942 +#define utils_wxIsBusy 2943 +#define utils_wxShutdown 2944 +#define utils_wxShell 2945 +#define utils_wxLaunchDefaultBrowser 2946 +#define utils_wxGetEmailAddress 2947 +#define utils_wxGetUserId 2948 +#define utils_wxGetHomeDir 2949 +#define utils_wxNewId 2950 +#define utils_wxRegisterId 2951 +#define utils_wxGetCurrentId 2952 +#define utils_wxGetOsDescription 2953 +#define utils_wxIsPlatformLittleEndian 2954 +#define utils_wxIsPlatform64Bit 2955 +#define gdicmn_wxDisplaySize 2956 +#define gdicmn_wxSetCursor 2957 +#define wxPrintout_new 2958 +#define wxPrintout_destruct 2959 +#define wxPrintout_GetDC 2960 +#define wxPrintout_GetPageSizeMM 2961 +#define wxPrintout_GetPageSizePixels 2962 +#define wxPrintout_GetPaperRectPixels 2963 +#define wxPrintout_GetPPIPrinter 2964 +#define wxPrintout_GetPPIScreen 2965 +#define wxPrintout_GetTitle 2966 +#define wxPrintout_IsPreview 2967 +#define wxPrintout_FitThisSizeToPaper 2968 +#define wxPrintout_FitThisSizeToPage 2969 +#define wxPrintout_FitThisSizeToPageMargins 2970 +#define wxPrintout_MapScreenSizeToPaper 2971 +#define wxPrintout_MapScreenSizeToPage 2972 +#define wxPrintout_MapScreenSizeToPageMargins 2973 +#define wxPrintout_MapScreenSizeToDevice 2974 +#define wxPrintout_GetLogicalPaperRect 2975 +#define wxPrintout_GetLogicalPageRect 2976 +#define wxPrintout_GetLogicalPageMarginsRect 2977 +#define wxPrintout_SetLogicalOrigin 2978 +#define wxPrintout_OffsetLogicalOrigin 2979 +#define wxStyledTextCtrl_new_2 2980 +#define wxStyledTextCtrl_new_0 2981 +#define wxStyledTextCtrl_destruct 2982 +#define wxStyledTextCtrl_Create 2983 +#define wxStyledTextCtrl_AddText 2984 +#define wxStyledTextCtrl_AddStyledText 2985 +#define wxStyledTextCtrl_InsertText 2986 +#define wxStyledTextCtrl_ClearAll 2987 +#define wxStyledTextCtrl_ClearDocumentStyle 2988 +#define wxStyledTextCtrl_GetLength 2989 +#define wxStyledTextCtrl_GetCharAt 2990 +#define wxStyledTextCtrl_GetCurrentPos 2991 +#define wxStyledTextCtrl_GetAnchor 2992 +#define wxStyledTextCtrl_GetStyleAt 2993 +#define wxStyledTextCtrl_Redo 2994 +#define wxStyledTextCtrl_SetUndoCollection 2995 +#define wxStyledTextCtrl_SelectAll 2996 +#define wxStyledTextCtrl_SetSavePoint 2997 +#define wxStyledTextCtrl_GetStyledText 2998 +#define wxStyledTextCtrl_CanRedo 2999 +#define wxStyledTextCtrl_MarkerLineFromHandle 3000 +#define wxStyledTextCtrl_MarkerDeleteHandle 3001 +#define wxStyledTextCtrl_GetUndoCollection 3002 +#define wxStyledTextCtrl_GetViewWhiteSpace 3003 +#define wxStyledTextCtrl_SetViewWhiteSpace 3004 +#define wxStyledTextCtrl_PositionFromPoint 3005 +#define wxStyledTextCtrl_PositionFromPointClose 3006 +#define wxStyledTextCtrl_GotoLine 3007 +#define wxStyledTextCtrl_GotoPos 3008 +#define wxStyledTextCtrl_SetAnchor 3009 +#define wxStyledTextCtrl_GetCurLine 3010 +#define wxStyledTextCtrl_GetEndStyled 3011 +#define wxStyledTextCtrl_ConvertEOLs 3012 +#define wxStyledTextCtrl_GetEOLMode 3013 +#define wxStyledTextCtrl_SetEOLMode 3014 +#define wxStyledTextCtrl_StartStyling 3015 +#define wxStyledTextCtrl_SetStyling 3016 +#define wxStyledTextCtrl_GetBufferedDraw 3017 +#define wxStyledTextCtrl_SetBufferedDraw 3018 +#define wxStyledTextCtrl_SetTabWidth 3019 +#define wxStyledTextCtrl_GetTabWidth 3020 +#define wxStyledTextCtrl_SetCodePage 3021 +#define wxStyledTextCtrl_MarkerDefine 3022 +#define wxStyledTextCtrl_MarkerSetForeground 3023 +#define wxStyledTextCtrl_MarkerSetBackground 3024 +#define wxStyledTextCtrl_MarkerAdd 3025 +#define wxStyledTextCtrl_MarkerDelete 3026 +#define wxStyledTextCtrl_MarkerDeleteAll 3027 +#define wxStyledTextCtrl_MarkerGet 3028 +#define wxStyledTextCtrl_MarkerNext 3029 +#define wxStyledTextCtrl_MarkerPrevious 3030 +#define wxStyledTextCtrl_MarkerDefineBitmap 3031 +#define wxStyledTextCtrl_MarkerAddSet 3032 +#define wxStyledTextCtrl_MarkerSetAlpha 3033 +#define wxStyledTextCtrl_SetMarginType 3034 +#define wxStyledTextCtrl_GetMarginType 3035 +#define wxStyledTextCtrl_SetMarginWidth 3036 +#define wxStyledTextCtrl_GetMarginWidth 3037 +#define wxStyledTextCtrl_SetMarginMask 3038 +#define wxStyledTextCtrl_GetMarginMask 3039 +#define wxStyledTextCtrl_SetMarginSensitive 3040 +#define wxStyledTextCtrl_GetMarginSensitive 3041 +#define wxStyledTextCtrl_StyleClearAll 3042 +#define wxStyledTextCtrl_StyleSetForeground 3043 +#define wxStyledTextCtrl_StyleSetBackground 3044 +#define wxStyledTextCtrl_StyleSetBold 3045 +#define wxStyledTextCtrl_StyleSetItalic 3046 +#define wxStyledTextCtrl_StyleSetSize 3047 +#define wxStyledTextCtrl_StyleSetFaceName 3048 +#define wxStyledTextCtrl_StyleSetEOLFilled 3049 +#define wxStyledTextCtrl_StyleResetDefault 3050 +#define wxStyledTextCtrl_StyleSetUnderline 3051 +#define wxStyledTextCtrl_StyleSetCase 3052 +#define wxStyledTextCtrl_StyleSetHotSpot 3053 +#define wxStyledTextCtrl_SetSelForeground 3054 +#define wxStyledTextCtrl_SetSelBackground 3055 +#define wxStyledTextCtrl_GetSelAlpha 3056 +#define wxStyledTextCtrl_SetSelAlpha 3057 +#define wxStyledTextCtrl_SetCaretForeground 3058 +#define wxStyledTextCtrl_CmdKeyAssign 3059 +#define wxStyledTextCtrl_CmdKeyClear 3060 +#define wxStyledTextCtrl_CmdKeyClearAll 3061 +#define wxStyledTextCtrl_SetStyleBytes 3062 +#define wxStyledTextCtrl_StyleSetVisible 3063 +#define wxStyledTextCtrl_GetCaretPeriod 3064 +#define wxStyledTextCtrl_SetCaretPeriod 3065 +#define wxStyledTextCtrl_SetWordChars 3066 +#define wxStyledTextCtrl_BeginUndoAction 3067 +#define wxStyledTextCtrl_EndUndoAction 3068 +#define wxStyledTextCtrl_IndicatorSetStyle 3069 +#define wxStyledTextCtrl_IndicatorGetStyle 3070 +#define wxStyledTextCtrl_IndicatorSetForeground 3071 +#define wxStyledTextCtrl_IndicatorGetForeground 3072 +#define wxStyledTextCtrl_SetWhitespaceForeground 3073 +#define wxStyledTextCtrl_SetWhitespaceBackground 3074 +#define wxStyledTextCtrl_GetStyleBits 3075 +#define wxStyledTextCtrl_SetLineState 3076 +#define wxStyledTextCtrl_GetLineState 3077 +#define wxStyledTextCtrl_GetMaxLineState 3078 +#define wxStyledTextCtrl_GetCaretLineVisible 3079 +#define wxStyledTextCtrl_SetCaretLineVisible 3080 +#define wxStyledTextCtrl_GetCaretLineBackground 3081 +#define wxStyledTextCtrl_SetCaretLineBackground 3082 +#define wxStyledTextCtrl_AutoCompShow 3083 +#define wxStyledTextCtrl_AutoCompCancel 3084 +#define wxStyledTextCtrl_AutoCompActive 3085 +#define wxStyledTextCtrl_AutoCompPosStart 3086 +#define wxStyledTextCtrl_AutoCompComplete 3087 +#define wxStyledTextCtrl_AutoCompStops 3088 +#define wxStyledTextCtrl_AutoCompSetSeparator 3089 +#define wxStyledTextCtrl_AutoCompGetSeparator 3090 +#define wxStyledTextCtrl_AutoCompSelect 3091 +#define wxStyledTextCtrl_AutoCompSetCancelAtStart 3092 +#define wxStyledTextCtrl_AutoCompGetCancelAtStart 3093 +#define wxStyledTextCtrl_AutoCompSetFillUps 3094 +#define wxStyledTextCtrl_AutoCompSetChooseSingle 3095 +#define wxStyledTextCtrl_AutoCompGetChooseSingle 3096 +#define wxStyledTextCtrl_AutoCompSetIgnoreCase 3097 +#define wxStyledTextCtrl_AutoCompGetIgnoreCase 3098 +#define wxStyledTextCtrl_UserListShow 3099 +#define wxStyledTextCtrl_AutoCompSetAutoHide 3100 +#define wxStyledTextCtrl_AutoCompGetAutoHide 3101 +#define wxStyledTextCtrl_AutoCompSetDropRestOfWord 3102 +#define wxStyledTextCtrl_AutoCompGetDropRestOfWord 3103 +#define wxStyledTextCtrl_RegisterImage 3104 +#define wxStyledTextCtrl_ClearRegisteredImages 3105 +#define wxStyledTextCtrl_AutoCompGetTypeSeparator 3106 +#define wxStyledTextCtrl_AutoCompSetTypeSeparator 3107 +#define wxStyledTextCtrl_AutoCompSetMaxWidth 3108 +#define wxStyledTextCtrl_AutoCompGetMaxWidth 3109 +#define wxStyledTextCtrl_AutoCompSetMaxHeight 3110 +#define wxStyledTextCtrl_AutoCompGetMaxHeight 3111 +#define wxStyledTextCtrl_SetIndent 3112 +#define wxStyledTextCtrl_GetIndent 3113 +#define wxStyledTextCtrl_SetUseTabs 3114 +#define wxStyledTextCtrl_GetUseTabs 3115 +#define wxStyledTextCtrl_SetLineIndentation 3116 +#define wxStyledTextCtrl_GetLineIndentation 3117 +#define wxStyledTextCtrl_GetLineIndentPosition 3118 +#define wxStyledTextCtrl_GetColumn 3119 +#define wxStyledTextCtrl_SetUseHorizontalScrollBar 3120 +#define wxStyledTextCtrl_GetUseHorizontalScrollBar 3121 +#define wxStyledTextCtrl_SetIndentationGuides 3122 +#define wxStyledTextCtrl_GetIndentationGuides 3123 +#define wxStyledTextCtrl_SetHighlightGuide 3124 +#define wxStyledTextCtrl_GetHighlightGuide 3125 +#define wxStyledTextCtrl_GetLineEndPosition 3126 +#define wxStyledTextCtrl_GetCodePage 3127 +#define wxStyledTextCtrl_GetCaretForeground 3128 +#define wxStyledTextCtrl_GetReadOnly 3129 +#define wxStyledTextCtrl_SetCurrentPos 3130 +#define wxStyledTextCtrl_SetSelectionStart 3131 +#define wxStyledTextCtrl_GetSelectionStart 3132 +#define wxStyledTextCtrl_SetSelectionEnd 3133 +#define wxStyledTextCtrl_GetSelectionEnd 3134 +#define wxStyledTextCtrl_SetPrintMagnification 3135 +#define wxStyledTextCtrl_GetPrintMagnification 3136 +#define wxStyledTextCtrl_SetPrintColourMode 3137 +#define wxStyledTextCtrl_GetPrintColourMode 3138 +#define wxStyledTextCtrl_FindText 3139 +#define wxStyledTextCtrl_FormatRange 3140 +#define wxStyledTextCtrl_GetFirstVisibleLine 3141 +#define wxStyledTextCtrl_GetLine 3142 +#define wxStyledTextCtrl_GetLineCount 3143 +#define wxStyledTextCtrl_SetMarginLeft 3144 +#define wxStyledTextCtrl_GetMarginLeft 3145 +#define wxStyledTextCtrl_SetMarginRight 3146 +#define wxStyledTextCtrl_GetMarginRight 3147 +#define wxStyledTextCtrl_GetModify 3148 +#define wxStyledTextCtrl_SetSelection 3149 +#define wxStyledTextCtrl_GetSelectedText 3150 +#define wxStyledTextCtrl_GetTextRange 3151 +#define wxStyledTextCtrl_HideSelection 3152 +#define wxStyledTextCtrl_LineFromPosition 3153 +#define wxStyledTextCtrl_PositionFromLine 3154 +#define wxStyledTextCtrl_LineScroll 3155 +#define wxStyledTextCtrl_EnsureCaretVisible 3156 +#define wxStyledTextCtrl_ReplaceSelection 3157 +#define wxStyledTextCtrl_SetReadOnly 3158 +#define wxStyledTextCtrl_CanPaste 3159 +#define wxStyledTextCtrl_CanUndo 3160 +#define wxStyledTextCtrl_EmptyUndoBuffer 3161 +#define wxStyledTextCtrl_Undo 3162 +#define wxStyledTextCtrl_Cut 3163 +#define wxStyledTextCtrl_Copy 3164 +#define wxStyledTextCtrl_Paste 3165 +#define wxStyledTextCtrl_Clear 3166 +#define wxStyledTextCtrl_SetText 3167 +#define wxStyledTextCtrl_GetText 3168 +#define wxStyledTextCtrl_GetTextLength 3169 +#define wxStyledTextCtrl_GetOvertype 3170 +#define wxStyledTextCtrl_SetCaretWidth 3171 +#define wxStyledTextCtrl_GetCaretWidth 3172 +#define wxStyledTextCtrl_SetTargetStart 3173 +#define wxStyledTextCtrl_GetTargetStart 3174 +#define wxStyledTextCtrl_SetTargetEnd 3175 +#define wxStyledTextCtrl_GetTargetEnd 3176 +#define wxStyledTextCtrl_ReplaceTarget 3177 +#define wxStyledTextCtrl_SearchInTarget 3178 +#define wxStyledTextCtrl_SetSearchFlags 3179 +#define wxStyledTextCtrl_GetSearchFlags 3180 +#define wxStyledTextCtrl_CallTipShow 3181 +#define wxStyledTextCtrl_CallTipCancel 3182 +#define wxStyledTextCtrl_CallTipActive 3183 +#define wxStyledTextCtrl_CallTipPosAtStart 3184 +#define wxStyledTextCtrl_CallTipSetHighlight 3185 +#define wxStyledTextCtrl_CallTipSetBackground 3186 +#define wxStyledTextCtrl_CallTipSetForeground 3187 +#define wxStyledTextCtrl_CallTipSetForegroundHighlight 3188 +#define wxStyledTextCtrl_CallTipUseStyle 3189 +#define wxStyledTextCtrl_VisibleFromDocLine 3190 +#define wxStyledTextCtrl_DocLineFromVisible 3191 +#define wxStyledTextCtrl_WrapCount 3192 +#define wxStyledTextCtrl_SetFoldLevel 3193 +#define wxStyledTextCtrl_GetFoldLevel 3194 +#define wxStyledTextCtrl_GetLastChild 3195 +#define wxStyledTextCtrl_GetFoldParent 3196 +#define wxStyledTextCtrl_ShowLines 3197 +#define wxStyledTextCtrl_HideLines 3198 +#define wxStyledTextCtrl_GetLineVisible 3199 +#define wxStyledTextCtrl_SetFoldExpanded 3200 +#define wxStyledTextCtrl_GetFoldExpanded 3201 +#define wxStyledTextCtrl_ToggleFold 3202 +#define wxStyledTextCtrl_EnsureVisible 3203 +#define wxStyledTextCtrl_SetFoldFlags 3204 +#define wxStyledTextCtrl_EnsureVisibleEnforcePolicy 3205 +#define wxStyledTextCtrl_SetTabIndents 3206 +#define wxStyledTextCtrl_GetTabIndents 3207 +#define wxStyledTextCtrl_SetBackSpaceUnIndents 3208 +#define wxStyledTextCtrl_GetBackSpaceUnIndents 3209 +#define wxStyledTextCtrl_SetMouseDwellTime 3210 +#define wxStyledTextCtrl_GetMouseDwellTime 3211 +#define wxStyledTextCtrl_WordStartPosition 3212 +#define wxStyledTextCtrl_WordEndPosition 3213 +#define wxStyledTextCtrl_SetWrapMode 3214 +#define wxStyledTextCtrl_GetWrapMode 3215 +#define wxStyledTextCtrl_SetWrapVisualFlags 3216 +#define wxStyledTextCtrl_GetWrapVisualFlags 3217 +#define wxStyledTextCtrl_SetWrapVisualFlagsLocation 3218 +#define wxStyledTextCtrl_GetWrapVisualFlagsLocation 3219 +#define wxStyledTextCtrl_SetWrapStartIndent 3220 +#define wxStyledTextCtrl_GetWrapStartIndent 3221 +#define wxStyledTextCtrl_SetLayoutCache 3222 +#define wxStyledTextCtrl_GetLayoutCache 3223 +#define wxStyledTextCtrl_SetScrollWidth 3224 +#define wxStyledTextCtrl_GetScrollWidth 3225 +#define wxStyledTextCtrl_TextWidth 3226 +#define wxStyledTextCtrl_GetEndAtLastLine 3227 +#define wxStyledTextCtrl_TextHeight 3228 +#define wxStyledTextCtrl_SetUseVerticalScrollBar 3229 +#define wxStyledTextCtrl_GetUseVerticalScrollBar 3230 +#define wxStyledTextCtrl_AppendText 3231 +#define wxStyledTextCtrl_GetTwoPhaseDraw 3232 +#define wxStyledTextCtrl_SetTwoPhaseDraw 3233 +#define wxStyledTextCtrl_TargetFromSelection 3234 +#define wxStyledTextCtrl_LinesJoin 3235 +#define wxStyledTextCtrl_LinesSplit 3236 +#define wxStyledTextCtrl_SetFoldMarginColour 3237 +#define wxStyledTextCtrl_SetFoldMarginHiColour 3238 +#define wxStyledTextCtrl_LineDown 3239 +#define wxStyledTextCtrl_LineDownExtend 3240 +#define wxStyledTextCtrl_LineUp 3241 +#define wxStyledTextCtrl_LineUpExtend 3242 +#define wxStyledTextCtrl_CharLeft 3243 +#define wxStyledTextCtrl_CharLeftExtend 3244 +#define wxStyledTextCtrl_CharRight 3245 +#define wxStyledTextCtrl_CharRightExtend 3246 +#define wxStyledTextCtrl_WordLeft 3247 +#define wxStyledTextCtrl_WordLeftExtend 3248 +#define wxStyledTextCtrl_WordRight 3249 +#define wxStyledTextCtrl_WordRightExtend 3250 +#define wxStyledTextCtrl_Home 3251 +#define wxStyledTextCtrl_HomeExtend 3252 +#define wxStyledTextCtrl_LineEnd 3253 +#define wxStyledTextCtrl_LineEndExtend 3254 +#define wxStyledTextCtrl_DocumentStart 3255 +#define wxStyledTextCtrl_DocumentStartExtend 3256 +#define wxStyledTextCtrl_DocumentEnd 3257 +#define wxStyledTextCtrl_DocumentEndExtend 3258 +#define wxStyledTextCtrl_PageUp 3259 +#define wxStyledTextCtrl_PageUpExtend 3260 +#define wxStyledTextCtrl_PageDown 3261 +#define wxStyledTextCtrl_PageDownExtend 3262 +#define wxStyledTextCtrl_EditToggleOvertype 3263 +#define wxStyledTextCtrl_Cancel 3264 +#define wxStyledTextCtrl_DeleteBack 3265 +#define wxStyledTextCtrl_Tab 3266 +#define wxStyledTextCtrl_BackTab 3267 +#define wxStyledTextCtrl_NewLine 3268 +#define wxStyledTextCtrl_FormFeed 3269 +#define wxStyledTextCtrl_VCHome 3270 +#define wxStyledTextCtrl_VCHomeExtend 3271 +#define wxStyledTextCtrl_ZoomIn 3272 +#define wxStyledTextCtrl_ZoomOut 3273 +#define wxStyledTextCtrl_DelWordLeft 3274 +#define wxStyledTextCtrl_DelWordRight 3275 +#define wxStyledTextCtrl_LineCut 3276 +#define wxStyledTextCtrl_LineDelete 3277 +#define wxStyledTextCtrl_LineTranspose 3278 +#define wxStyledTextCtrl_LineDuplicate 3279 +#define wxStyledTextCtrl_LowerCase 3280 +#define wxStyledTextCtrl_UpperCase 3281 +#define wxStyledTextCtrl_LineScrollDown 3282 +#define wxStyledTextCtrl_LineScrollUp 3283 +#define wxStyledTextCtrl_DeleteBackNotLine 3284 +#define wxStyledTextCtrl_HomeDisplay 3285 +#define wxStyledTextCtrl_HomeDisplayExtend 3286 +#define wxStyledTextCtrl_LineEndDisplay 3287 +#define wxStyledTextCtrl_LineEndDisplayExtend 3288 +#define wxStyledTextCtrl_HomeWrapExtend 3289 +#define wxStyledTextCtrl_LineEndWrap 3290 +#define wxStyledTextCtrl_LineEndWrapExtend 3291 +#define wxStyledTextCtrl_VCHomeWrap 3292 +#define wxStyledTextCtrl_VCHomeWrapExtend 3293 +#define wxStyledTextCtrl_LineCopy 3294 +#define wxStyledTextCtrl_MoveCaretInsideView 3295 +#define wxStyledTextCtrl_LineLength 3296 +#define wxStyledTextCtrl_BraceHighlight 3297 +#define wxStyledTextCtrl_BraceBadLight 3298 +#define wxStyledTextCtrl_BraceMatch 3299 +#define wxStyledTextCtrl_GetViewEOL 3300 +#define wxStyledTextCtrl_SetViewEOL 3301 +#define wxStyledTextCtrl_SetModEventMask 3302 +#define wxStyledTextCtrl_GetEdgeColumn 3303 +#define wxStyledTextCtrl_SetEdgeColumn 3304 +#define wxStyledTextCtrl_SetEdgeMode 3305 +#define wxStyledTextCtrl_GetEdgeMode 3306 +#define wxStyledTextCtrl_GetEdgeColour 3307 +#define wxStyledTextCtrl_SetEdgeColour 3308 +#define wxStyledTextCtrl_SearchAnchor 3309 +#define wxStyledTextCtrl_SearchNext 3310 +#define wxStyledTextCtrl_SearchPrev 3311 +#define wxStyledTextCtrl_LinesOnScreen 3312 +#define wxStyledTextCtrl_UsePopUp 3313 +#define wxStyledTextCtrl_SelectionIsRectangle 3314 +#define wxStyledTextCtrl_SetZoom 3315 +#define wxStyledTextCtrl_GetZoom 3316 +#define wxStyledTextCtrl_GetModEventMask 3317 +#define wxStyledTextCtrl_SetSTCFocus 3318 +#define wxStyledTextCtrl_GetSTCFocus 3319 +#define wxStyledTextCtrl_SetStatus 3320 +#define wxStyledTextCtrl_GetStatus 3321 +#define wxStyledTextCtrl_SetMouseDownCaptures 3322 +#define wxStyledTextCtrl_GetMouseDownCaptures 3323 +#define wxStyledTextCtrl_SetSTCCursor 3324 +#define wxStyledTextCtrl_GetSTCCursor 3325 +#define wxStyledTextCtrl_SetControlCharSymbol 3326 +#define wxStyledTextCtrl_GetControlCharSymbol 3327 +#define wxStyledTextCtrl_WordPartLeft 3328 +#define wxStyledTextCtrl_WordPartLeftExtend 3329 +#define wxStyledTextCtrl_WordPartRight 3330 +#define wxStyledTextCtrl_WordPartRightExtend 3331 +#define wxStyledTextCtrl_SetVisiblePolicy 3332 +#define wxStyledTextCtrl_DelLineLeft 3333 +#define wxStyledTextCtrl_DelLineRight 3334 +#define wxStyledTextCtrl_GetXOffset 3335 +#define wxStyledTextCtrl_ChooseCaretX 3336 +#define wxStyledTextCtrl_SetXCaretPolicy 3337 +#define wxStyledTextCtrl_SetYCaretPolicy 3338 +#define wxStyledTextCtrl_GetPrintWrapMode 3339 +#define wxStyledTextCtrl_SetHotspotActiveForeground 3340 +#define wxStyledTextCtrl_SetHotspotActiveBackground 3341 +#define wxStyledTextCtrl_SetHotspotActiveUnderline 3342 +#define wxStyledTextCtrl_SetHotspotSingleLine 3343 +#define wxStyledTextCtrl_ParaDownExtend 3344 +#define wxStyledTextCtrl_ParaUp 3345 +#define wxStyledTextCtrl_ParaUpExtend 3346 +#define wxStyledTextCtrl_PositionBefore 3347 +#define wxStyledTextCtrl_PositionAfter 3348 +#define wxStyledTextCtrl_CopyRange 3349 +#define wxStyledTextCtrl_CopyText 3350 +#define wxStyledTextCtrl_SetSelectionMode 3351 +#define wxStyledTextCtrl_GetSelectionMode 3352 +#define wxStyledTextCtrl_LineDownRectExtend 3353 +#define wxStyledTextCtrl_LineUpRectExtend 3354 +#define wxStyledTextCtrl_CharLeftRectExtend 3355 +#define wxStyledTextCtrl_CharRightRectExtend 3356 +#define wxStyledTextCtrl_HomeRectExtend 3357 +#define wxStyledTextCtrl_VCHomeRectExtend 3358 +#define wxStyledTextCtrl_LineEndRectExtend 3359 +#define wxStyledTextCtrl_PageUpRectExtend 3360 +#define wxStyledTextCtrl_PageDownRectExtend 3361 +#define wxStyledTextCtrl_StutteredPageUp 3362 +#define wxStyledTextCtrl_StutteredPageUpExtend 3363 +#define wxStyledTextCtrl_StutteredPageDown 3364 +#define wxStyledTextCtrl_StutteredPageDownExtend 3365 +#define wxStyledTextCtrl_WordLeftEnd 3366 +#define wxStyledTextCtrl_WordLeftEndExtend 3367 +#define wxStyledTextCtrl_WordRightEnd 3368 +#define wxStyledTextCtrl_WordRightEndExtend 3369 +#define wxStyledTextCtrl_SetWhitespaceChars 3370 +#define wxStyledTextCtrl_SetCharsDefault 3371 +#define wxStyledTextCtrl_AutoCompGetCurrent 3372 +#define wxStyledTextCtrl_Allocate 3373 +#define wxStyledTextCtrl_FindColumn 3374 +#define wxStyledTextCtrl_GetCaretSticky 3375 +#define wxStyledTextCtrl_SetCaretSticky 3376 +#define wxStyledTextCtrl_ToggleCaretSticky 3377 +#define wxStyledTextCtrl_SetPasteConvertEndings 3378 +#define wxStyledTextCtrl_GetPasteConvertEndings 3379 +#define wxStyledTextCtrl_SelectionDuplicate 3380 +#define wxStyledTextCtrl_SetCaretLineBackAlpha 3381 +#define wxStyledTextCtrl_GetCaretLineBackAlpha 3382 +#define wxStyledTextCtrl_StartRecord 3383 +#define wxStyledTextCtrl_StopRecord 3384 +#define wxStyledTextCtrl_SetLexer 3385 +#define wxStyledTextCtrl_GetLexer 3386 +#define wxStyledTextCtrl_Colourise 3387 +#define wxStyledTextCtrl_SetProperty 3388 +#define wxStyledTextCtrl_SetKeyWords 3389 +#define wxStyledTextCtrl_SetLexerLanguage 3390 +#define wxStyledTextCtrl_GetProperty 3391 +#define wxStyledTextCtrl_GetStyleBitsNeeded 3392 +#define wxStyledTextCtrl_GetCurrentLine 3393 +#define wxStyledTextCtrl_StyleSetSpec 3394 +#define wxStyledTextCtrl_StyleSetFont 3395 +#define wxStyledTextCtrl_StyleSetFontAttr 3396 +#define wxStyledTextCtrl_StyleSetCharacterSet 3397 +#define wxStyledTextCtrl_StyleSetFontEncoding 3398 +#define wxStyledTextCtrl_CmdKeyExecute 3399 +#define wxStyledTextCtrl_SetMargins 3400 +#define wxStyledTextCtrl_GetSelection 3401 +#define wxStyledTextCtrl_PointFromPosition 3402 +#define wxStyledTextCtrl_ScrollToLine 3403 +#define wxStyledTextCtrl_ScrollToColumn 3404 +#define wxStyledTextCtrl_SetVScrollBar 3405 +#define wxStyledTextCtrl_SetHScrollBar 3406 +#define wxStyledTextCtrl_GetLastKeydownProcessed 3407 +#define wxStyledTextCtrl_SetLastKeydownProcessed 3408 +#define wxStyledTextCtrl_SaveFile 3409 +#define wxStyledTextCtrl_LoadFile 3410 +#define wxStyledTextCtrl_DoDragOver 3411 +#define wxStyledTextCtrl_DoDropText 3412 +#define wxStyledTextCtrl_GetUseAntiAliasing 3413 +#define wxStyledTextCtrl_AddTextRaw 3414 +#define wxStyledTextCtrl_InsertTextRaw 3415 +#define wxStyledTextCtrl_GetCurLineRaw 3416 +#define wxStyledTextCtrl_GetLineRaw 3417 +#define wxStyledTextCtrl_GetSelectedTextRaw 3418 +#define wxStyledTextCtrl_GetTextRangeRaw 3419 +#define wxStyledTextCtrl_SetTextRaw 3420 +#define wxStyledTextCtrl_GetTextRaw 3421 +#define wxStyledTextCtrl_AppendTextRaw 3422 +#define wxArtProvider_GetBitmap 3423 +#define wxArtProvider_GetIcon 3424 +#define wxTreeEvent_GetKeyCode 3425 +#define wxTreeEvent_GetItem 3426 +#define wxTreeEvent_GetKeyEvent 3427 +#define wxTreeEvent_GetLabel 3428 +#define wxTreeEvent_GetOldItem 3429 +#define wxTreeEvent_GetPoint 3430 +#define wxTreeEvent_IsEditCancelled 3431 +#define wxTreeEvent_SetToolTip 3432 +#define wxNotebookEvent_GetOldSelection 3433 +#define wxNotebookEvent_GetSelection 3434 +#define wxNotebookEvent_SetOldSelection 3435 +#define wxNotebookEvent_SetSelection 3436 +#define wxFileDataObject_new 3437 +#define wxFileDataObject_AddFile 3438 +#define wxFileDataObject_GetFilenames 3439 +#define wxFileDataObject_destroy 3440 +#define wxTextDataObject_new 3441 +#define wxTextDataObject_GetTextLength 3442 +#define wxTextDataObject_GetText 3443 +#define wxTextDataObject_SetText 3444 +#define wxTextDataObject_destroy 3445 +#define wxBitmapDataObject_new_1_1 3446 +#define wxBitmapDataObject_new_1_0 3447 +#define wxBitmapDataObject_GetBitmap 3448 +#define wxBitmapDataObject_SetBitmap 3449 +#define wxBitmapDataObject_destroy 3450 +#define wxClipboard_new 3452 +#define wxClipboard_destruct 3453 +#define wxClipboard_AddData 3454 +#define wxClipboard_Clear 3455 +#define wxClipboard_Close 3456 +#define wxClipboard_Flush 3457 +#define wxClipboard_GetData 3458 +#define wxClipboard_IsOpened 3459 +#define wxClipboard_Open 3460 +#define wxClipboard_SetData 3461 +#define wxClipboard_UsePrimarySelection 3463 +#define wxClipboard_IsSupported 3464 +#define wxClipboard_Get 3465 +#define wxSpinEvent_GetPosition 3466 +#define wxSpinEvent_SetPosition 3467 +#define wxSplitterWindow_new_0 3468 +#define wxSplitterWindow_new_2 3469 +#define wxSplitterWindow_destruct 3470 +#define wxSplitterWindow_Create 3471 +#define wxSplitterWindow_GetMinimumPaneSize 3472 +#define wxSplitterWindow_GetSashGravity 3473 +#define wxSplitterWindow_GetSashPosition 3474 +#define wxSplitterWindow_GetSplitMode 3475 +#define wxSplitterWindow_GetWindow1 3476 +#define wxSplitterWindow_GetWindow2 3477 +#define wxSplitterWindow_Initialize 3478 +#define wxSplitterWindow_IsSplit 3479 +#define wxSplitterWindow_ReplaceWindow 3480 +#define wxSplitterWindow_SetSashGravity 3481 +#define wxSplitterWindow_SetSashPosition 3482 +#define wxSplitterWindow_SetSashSize 3483 +#define wxSplitterWindow_SetMinimumPaneSize 3484 +#define wxSplitterWindow_SetSplitMode 3485 +#define wxSplitterWindow_SplitHorizontally 3486 +#define wxSplitterWindow_SplitVertically 3487 +#define wxSplitterWindow_Unsplit 3488 +#define wxSplitterWindow_UpdateSize 3489 +#define wxSplitterEvent_GetSashPosition 3490 +#define wxSplitterEvent_GetX 3491 +#define wxSplitterEvent_GetY 3492 +#define wxSplitterEvent_GetWindowBeingRemoved 3493 +#define wxSplitterEvent_SetSashPosition 3494 +#define wxHtmlWindow_new_0 3495 +#define wxHtmlWindow_new_2 3496 +#define wxHtmlWindow_AppendToPage 3497 +#define wxHtmlWindow_GetOpenedAnchor 3498 +#define wxHtmlWindow_GetOpenedPage 3499 +#define wxHtmlWindow_GetOpenedPageTitle 3500 +#define wxHtmlWindow_GetRelatedFrame 3501 +#define wxHtmlWindow_HistoryBack 3502 +#define wxHtmlWindow_HistoryCanBack 3503 +#define wxHtmlWindow_HistoryCanForward 3504 +#define wxHtmlWindow_HistoryClear 3505 +#define wxHtmlWindow_HistoryForward 3506 +#define wxHtmlWindow_LoadFile 3507 +#define wxHtmlWindow_LoadPage 3508 +#define wxHtmlWindow_SelectAll 3509 +#define wxHtmlWindow_SelectionToText 3510 +#define wxHtmlWindow_SelectLine 3511 +#define wxHtmlWindow_SelectWord 3512 +#define wxHtmlWindow_SetBorders 3513 +#define wxHtmlWindow_SetFonts 3514 +#define wxHtmlWindow_SetPage 3515 +#define wxHtmlWindow_SetRelatedFrame 3516 +#define wxHtmlWindow_SetRelatedStatusBar 3517 +#define wxHtmlWindow_ToText 3518 +#define wxHtmlWindow_destroy 3519 +#define wxHtmlLinkEvent_GetLinkInfo 3520 +#define wxSystemSettings_GetColour 3521 +#define wxSystemSettings_GetFont 3522 +#define wxSystemSettings_GetMetric 3523 +#define wxSystemSettings_GetScreenType 3524 +#define wxSystemOptions_GetOption 3525 +#define wxSystemOptions_GetOptionInt 3526 +#define wxSystemOptions_HasOption 3527 +#define wxSystemOptions_IsFalse 3528 +#define wxSystemOptions_SetOption_2_1 3529 +#define wxSystemOptions_SetOption_2_0 3530 +#define wxAuiNotebookEvent_SetSelection 3531 +#define wxAuiNotebookEvent_GetSelection 3532 +#define wxAuiNotebookEvent_SetOldSelection 3533 +#define wxAuiNotebookEvent_GetOldSelection 3534 +#define wxAuiNotebookEvent_SetDragSource 3535 +#define wxAuiNotebookEvent_GetDragSource 3536 +#define wxAuiManagerEvent_SetManager 3537 +#define wxAuiManagerEvent_GetManager 3538 +#define wxAuiManagerEvent_SetPane 3539 +#define wxAuiManagerEvent_GetPane 3540 +#define wxAuiManagerEvent_SetButton 3541 +#define wxAuiManagerEvent_GetButton 3542 +#define wxAuiManagerEvent_SetDC 3543 +#define wxAuiManagerEvent_GetDC 3544 +#define wxAuiManagerEvent_Veto 3545 +#define wxAuiManagerEvent_GetVeto 3546 +#define wxAuiManagerEvent_SetCanVeto 3547 +#define wxAuiManagerEvent_CanVeto 3548 +#define wxLogNull_new 3549 +#define wxLogNull_destroy 3550 +#define wxTaskBarIcon_new 3551 +#define wxTaskBarIcon_destruct 3552 +#define wxTaskBarIcon_PopupMenu 3553 +#define wxTaskBarIcon_RemoveIcon 3554 +#define wxTaskBarIcon_SetIcon 3555 +#define wxLocale_new_0 3556 +#define wxLocale_new_2 3558 +#define wxLocale_destruct 3559 +#define wxLocale_Init 3561 +#define wxLocale_AddCatalog_1 3562 +#define wxLocale_AddCatalog_3 3563 +#define wxLocale_AddCatalogLookupPathPrefix 3564 +#define wxLocale_GetCanonicalName 3565 +#define wxLocale_GetLanguage 3566 +#define wxLocale_GetLanguageName 3567 +#define wxLocale_GetLocale 3568 +#define wxLocale_GetName 3569 +#define wxLocale_GetString_2 3570 +#define wxLocale_GetString_4 3571 +#define wxLocale_GetHeaderValue 3572 +#define wxLocale_GetSysName 3573 +#define wxLocale_GetSystemEncoding 3574 +#define wxLocale_GetSystemEncodingName 3575 +#define wxLocale_GetSystemLanguage 3576 +#define wxLocale_IsLoaded 3577 +#define wxLocale_IsOk 3578 +#define wxActivateEvent_GetActive 3579 +#define wxPopupWindow_new_2 3581 +#define wxPopupWindow_new_0 3582 +#define wxPopupWindow_destruct 3584 +#define wxPopupWindow_Create 3585 +#define wxPopupWindow_Position 3586 +#define wxPopupTransientWindow_new_0 3587 +#define wxPopupTransientWindow_new_2 3588 +#define wxPopupTransientWindow_destruct 3589 +#define wxPopupTransientWindow_Popup 3590 +#define wxPopupTransientWindow_Dismiss 3591 +#define wxOverlay_new 3592 +#define wxOverlay_destruct 3593 +#define wxOverlay_Reset 3594 +#define wxDCOverlay_new_6 3595 +#define wxDCOverlay_new_2 3596 +#define wxDCOverlay_destruct 3597 +#define wxDCOverlay_Clear 3598 diff --git a/lib/wx/c_src/wxe_driver.c b/lib/wx/c_src/wxe_driver.c index eb7d7dcaeb..6f027ea25b 100644 --- a/lib/wx/c_src/wxe_driver.c +++ b/lib/wx/c_src/wxe_driver.c @@ -241,12 +241,10 @@ standard_outputv(ErlDrvData drv_data, ErlIOVec* ev) bin = ev->binv[1]; driver_binary_inc_refc(bin); /* Otherwise it could get deallocated */ binref->bin = bin; - sd->bin = binref; } else { /* Empty binary (becomes NULL) */ binref->base = NULL; binref->size = 0; binref->from = driver_caller(sd->port_handle); binref->bin = NULL; - sd->bin = binref; } } diff --git a/lib/wx/c_src/wxe_gl.cpp b/lib/wx/c_src/wxe_gl.cpp index 5126804b9f..7f2e767a6b 100644 --- a/lib/wx/c_src/wxe_gl.cpp +++ b/lib/wx/c_src/wxe_gl.cpp @@ -138,9 +138,9 @@ void gl_dispatch(int op, char *bp,ErlDrvTermData caller,WXEBinRef *bins){ wxGLCanvas * current = glc[caller]; if(current) { if(current != glc[gl_active]) { - gl_active = caller; current->SetCurrent(); } + gl_active = caller; } else { ErlDrvTermData rt[] = // Error msg {ERL_DRV_ATOM, driver_mk_atom((char *) "_egl_error_"), diff --git a/lib/wx/c_src/wxe_helpers.cpp b/lib/wx/c_src/wxe_helpers.cpp index cc57374d5b..1696b8bd50 100644 --- a/lib/wx/c_src/wxe_helpers.cpp +++ b/lib/wx/c_src/wxe_helpers.cpp @@ -61,6 +61,7 @@ wxeFifo::wxeFifo(unsigned int sz) m_max = sz; m_n = 0; m_first = 0; + cb_start = 0; m_old = NULL; for(unsigned int i = 0; i < sz; i++) { m_q[i].buffer = NULL; @@ -76,15 +77,30 @@ wxeFifo::~wxeFifo() { wxeCommand * wxeFifo::Get() { unsigned int pos; - if(m_n > 0) { + do { + if(m_n <= 0) + return NULL; + pos = m_first++; m_n--; m_first %= m_max; - return &m_q[pos]; - } - return NULL; + } while(m_q[pos].op == -1); + return &m_q[pos]; +} + +wxeCommand * wxeFifo::Peek(unsigned int *i) +{ + unsigned int pos; + do { + if(*i >= m_n || m_n <= 0) + return NULL; + pos = (m_first+*i) % m_max; + (*i)++; + } while(m_q[pos].op == -1); + return &m_q[pos]; } + void wxeFifo::Add(int fc, char * cbuf,int buflen, wxe_data *sd) { unsigned int pos; @@ -140,10 +156,12 @@ void wxeFifo::Append(wxeCommand *orig) pos = (m_first + m_n) % m_max; m_n++; + curr = &m_q[pos]; + curr->op = orig->op; + if(curr->op == -1) return; curr->caller = orig->caller; curr->port = orig->port; - curr->op = orig->op; curr->len = orig->len; curr->bin[0] = orig->bin[0]; curr->bin[1] = orig->bin[1]; @@ -171,17 +189,19 @@ void wxeFifo::Realloc() wxeCommand * old = m_q; wxeCommand * queue = (wxeCommand *)driver_alloc(new_sz*sizeof(wxeCommand)); + // fprintf(stderr, "\r\nrealloc qsz %d\r\n", new_sz);fflush(stderr); + m_max=new_sz; m_first = 0; m_n=0; m_q = queue; for(i=0; i < n; i++) { - unsigned int pos = i+first; - if(old[pos%max].op >= 0) { - Append(&old[pos%max]); - } + unsigned int pos = (i+first)%max; + if(old[pos].op >= 0) + Append(&old[pos]); } + for(i = m_n; i < new_sz; i++) { // Reset the rest m_q[i].buffer = NULL; m_q[i].op = -1; @@ -190,6 +210,26 @@ void wxeFifo::Realloc() m_old = old; } +// Strip end of queue if ops are already taken care of, avoids reallocs +void wxeFifo::Strip() +{ + while((m_n > 0) && (m_q[(m_first + m_n - 1)%m_max].op == -1)) { + m_n--; + } +} + +unsigned int wxeFifo::Cleanup(unsigned int def) +{ + if(m_old) { + driver_free(m_old); + m_old = NULL; + // Realloced we need to start from the beginning + return 0; + } else { + return def; + } +} + /* **************************************************************************** * TreeItemData * ****************************************************************************/ diff --git a/lib/wx/c_src/wxe_helpers.h b/lib/wx/c_src/wxe_helpers.h index 4f9d9ca9c3..ff949e332b 100644 --- a/lib/wx/c_src/wxe_helpers.h +++ b/lib/wx/c_src/wxe_helpers.h @@ -67,9 +67,13 @@ class wxeFifo { void Append(wxeCommand *Other); wxeCommand * Get(); + wxeCommand * Peek(unsigned int *item); void Realloc(); + void Strip(); + unsigned int Cleanup(unsigned int peek=0); + unsigned int cb_start; unsigned int m_max; unsigned int m_first; unsigned int m_n; diff --git a/lib/wx/c_src/wxe_impl.cpp b/lib/wx/c_src/wxe_impl.cpp index 6236fb708e..f81d0bbbd9 100644 --- a/lib/wx/c_src/wxe_impl.cpp +++ b/lib/wx/c_src/wxe_impl.cpp @@ -57,7 +57,6 @@ extern ErlDrvTermData init_caller; extern int wxe_status; wxeFifo * wxe_queue = NULL; -wxeFifo * wxe_queue_cb_saved = NULL; unsigned int wxe_needs_signal = 0; // inside batch if larger than 0 @@ -122,11 +121,10 @@ bool WxeApp::OnInit() { global_me = new wxeMemEnv(); - wxe_queue = new wxeFifo(1000); - wxe_queue_cb_saved = new wxeFifo(200); + wxe_queue = new wxeFifo(2000); cb_buff = NULL; recurse_level = 0; - delayed_delete = new wxeFifo(10); + delayed_delete = new wxeFifo(100); delayed_cleanup = new wxList; wxe_ps_init2(); @@ -172,7 +170,6 @@ void WxeApp::shutdown(wxeMetaCommand& Ecmd) { wxe_status = WXE_EXITING; ExitMainLoop(); delete wxe_queue; - delete wxe_queue_cb_saved; } void WxeApp::dummy_close(wxEvent& Ev) { @@ -181,6 +178,25 @@ void WxeApp::dummy_close(wxEvent& Ev) { // windows open, and this will kill the erlang, override default handling } +void WxeApp::OnAssertFailure(const wxChar *file, int line, const wxChar *cfunc, + const wxChar *cond, const wxChar *cmsgUser) { + wxString msg; + wxString func(cfunc); + wxString msgUser(cmsgUser); + + msg.Printf(wxT("wxWidgets Assert failure: %s(%d): \"%s\""), + file, line, cond); + if ( !func.empty() ) { + msg << wxT(" in ") << func << wxT("()"); + } + // and the message itself + if ( !msgUser.empty() ) { + msg << wxT(" : ") << msgUser; + } + + send_msg("error", &msg); +} + // Called by wx thread void WxeApp::idle(wxIdleEvent& event) { event.Skip(true); @@ -210,7 +226,7 @@ void handle_event_callback(ErlDrvPort port, ErlDrvTermData process) // Should we be able to handle commands when recursing? probably // fprintf(stderr, "\r\nCB EV Start %lu \r\n", process);fflush(stderr); app->recurse_level++; - app->dispatch_cb(wxe_queue, wxe_queue_cb_saved, process); + app->dispatch_cb(wxe_queue, process); app->recurse_level--; // fprintf(stderr, "CB EV done %lu \r\n", process);fflush(stderr); driver_demonitor_process(port, &monitor); @@ -222,8 +238,9 @@ void WxeApp::dispatch_cmds() if(wxe_status != WXE_INITIATED) return; recurse_level++; - int level = dispatch(wxe_queue_cb_saved, 0, WXE_STORED); - dispatch(wxe_queue, level, WXE_NORMAL); + // fprintf(stderr, "\r\ndispatch_normal %d\r\n", level);fflush(stderr); + dispatch(wxe_queue); + // fprintf(stderr, "\r\ndispatch_done \r\n");fflush(stderr); recurse_level--; // Cleanup old memenv's and deleted objects @@ -233,6 +250,7 @@ void WxeApp::dispatch_cmds() wxe_dispatch(*curr); curr->Delete(); } + delayed_delete->Cleanup(); if(delayed_cleanup->size() > 0) for( wxList::compatibility_iterator node = delayed_cleanup->GetFirst(); node; @@ -242,28 +260,19 @@ void WxeApp::dispatch_cmds() destroyMemEnv(*event); delete event; } - if(wxe_queue_cb_saved->m_old) { - driver_free(wxe_queue_cb_saved->m_old); - wxe_queue_cb_saved->m_old = NULL; - } - if(delayed_delete->m_old) { - driver_free(delayed_delete->m_old); - delayed_delete->m_old = NULL; - } } } -int WxeApp::dispatch(wxeFifo * batch, int blevel, int list_type) +int WxeApp::dispatch(wxeFifo * batch) { int ping = 0; + int blevel = 0; wxeCommand *event; - if(list_type == WXE_NORMAL) erl_drv_mutex_lock(wxe_batch_locker_m); + erl_drv_mutex_lock(wxe_batch_locker_m); while(true) { while((event = batch->Get()) != NULL) { - if(list_type == WXE_NORMAL) erl_drv_mutex_unlock(wxe_batch_locker_m); + erl_drv_mutex_unlock(wxe_batch_locker_m); switch(event->op) { - case -1: - break; case WXE_BATCH_END: {--blevel; } break; @@ -294,15 +303,10 @@ int WxeApp::dispatch(wxeFifo * batch, int blevel, int list_type) break; } event->Delete(); - if(list_type == WXE_NORMAL) erl_drv_mutex_lock(wxe_batch_locker_m); + erl_drv_mutex_lock(wxe_batch_locker_m); + batch->Cleanup(); } - if(list_type == WXE_STORED) - return blevel; - if(blevel <= 0) { // list_type == WXE_NORMAL - if(wxe_queue->m_old) { - driver_free(wxe_queue->m_old); - wxe_queue->m_old = NULL; - } + if(blevel <= 0) { erl_drv_mutex_unlock(wxe_batch_locker_m); return blevel; } @@ -316,12 +320,13 @@ int WxeApp::dispatch(wxeFifo * batch, int blevel, int list_type) } } -void WxeApp::dispatch_cb(wxeFifo * batch, wxeFifo * temp, ErlDrvTermData process) { +void WxeApp::dispatch_cb(wxeFifo * batch, ErlDrvTermData process) { wxeCommand *event; + unsigned int peek; erl_drv_mutex_lock(wxe_batch_locker_m); + peek = batch->Cleanup(batch->cb_start); while(true) { - while((event = batch->Get()) != NULL) { - erl_drv_mutex_unlock(wxe_batch_locker_m); + while((event = batch->Peek(&peek)) != NULL) { wxeMemEnv *memenv = getMemEnv(event->port); // fprintf(stderr, " Ev %d %lu\r\n", event->op, event->caller); if(event->caller == process || // Callbacks from CB process only @@ -329,8 +334,8 @@ void WxeApp::dispatch_cb(wxeFifo * batch, wxeFifo * temp, ErlDrvTermData process event->op == WXE_CB_DIED || // Event callback process died // Allow connect_cb during CB i.e. msg from wxe_server. (memenv && event->caller == memenv->owner)) { + erl_drv_mutex_unlock(wxe_batch_locker_m); switch(event->op) { - case -1: case WXE_BATCH_END: case WXE_BATCH_BEGIN: case WXE_DEBUG_PING: @@ -341,52 +346,42 @@ void WxeApp::dispatch_cb(wxeFifo * batch, wxeFifo * temp, ErlDrvTermData process memcpy(cb_buff, event->buffer, event->len); } // continue case WXE_CB_DIED: + batch->cb_start = 0; event->Delete(); + erl_drv_mutex_lock(wxe_batch_locker_m); + batch->Strip(); + erl_drv_mutex_unlock(wxe_batch_locker_m); return; case WXE_CB_START: // CB start from now accept message from CB process only process = event->caller; break; default: - size_t start=temp->m_n; + batch->cb_start = peek; // In case of recursive callbacks if(event->op < OPENGL_START) { - // fprintf(stderr, " cb %d \r\n", event->op); wxe_dispatch(*event); } else { gl_dispatch(event->op,event->buffer,event->caller,event->bin); } - if(temp->m_n > start) { - erl_drv_mutex_lock(wxe_batch_locker_m); - // We have recursed dispatch_cb and messages for this - // callback may be saved on temp list move them - // to orig list - for(unsigned int i=start; i < temp->m_n; i++) { - wxeCommand *ev = &temp->m_q[(temp->m_first+i) % temp->m_max]; - if(ev->caller == process) { - batch->Append(ev); - } - } - erl_drv_mutex_unlock(wxe_batch_locker_m); - } break; } event->Delete(); - } else { - // fprintf(stderr, " save %d %lu\r\n", event->op, event->caller); - temp->Append(event); + erl_drv_mutex_lock(wxe_batch_locker_m); + peek = batch->Cleanup(peek); } - erl_drv_mutex_lock(wxe_batch_locker_m); } // sleep until something happens // fprintf(stderr, "%s:%d sleep %d %d\r\n", __FILE__, __LINE__, - // batch->m_n, temp->m_n);fflush(stderr); + // peek, batch->m_n);fflush(stderr); wxe_needs_signal = 1; - while(batch->m_n == 0) { + while(peek >= batch->m_n) { erl_drv_cond_wait(wxe_batch_locker_c, wxe_batch_locker_m); + peek = batch->Cleanup(peek); } wxe_needs_signal = 0; } } + /* Memory handling */ void WxeApp::newMemEnv(wxeMetaCommand& Ecmd) { diff --git a/lib/wx/c_src/wxe_impl.h b/lib/wx/c_src/wxe_impl.h index d8241d11a4..fd25296c73 100644 --- a/lib/wx/c_src/wxe_impl.h +++ b/lib/wx/c_src/wxe_impl.h @@ -57,13 +57,18 @@ class WxeApp : public wxApp { public: virtual bool OnInit(); + + virtual void OnAssertFailure(const wxChar *file, int line, const wxChar *func, + const wxChar *cond, const wxChar *msg); + #ifdef _MACOSX virtual void MacOpenFile(const wxString &filename); #endif + void shutdown(wxeMetaCommand& event); - int dispatch(wxeFifo *, int, int); - void dispatch_cb(wxeFifo * batch, wxeFifo * temp, ErlDrvTermData process); + int dispatch(wxeFifo *); + void dispatch_cb(wxeFifo * batch, ErlDrvTermData process); void wxe_dispatch(wxeCommand& event); diff --git a/lib/wx/configure.in b/lib/wx/configure.in index 48fcca640c..bf27b72aa7 100644 --- a/lib/wx/configure.in +++ b/lib/wx/configure.in @@ -164,14 +164,14 @@ case $host_os in CPPFLAGS="$CPPFLAGS -D_MACOSX $PTHR_CFLAGS" ;; mingw32) - CFLAGS="$CFLAGS -DWIN32 -DWINVER=0x0500 -D_WINDOWS -D_UNICODE -DUNICODE" - CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0500" + CFLAGS="$CFLAGS -DWIN32 -DWINVER=0x0600 -D_WINDOWS -D_UNICODE -DUNICODE" + CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0600" AC_MSG_WARN([Reverting to 32-bit time_t]) CPPFLAGS="$CPPFLAGS -D_USE_32BIT_TIME_T" ;; win32) - CFLAGS="$CFLAGS -DWIN32 -DWINVER=0x0500 -D_WINDOWS -D_UNICODE -DUNICODE" - CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0500" + CFLAGS="$CFLAGS -DWIN32 -DWINVER=0x0600 -D_WINDOWS -D_UNICODE -DUNICODE" + CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0600" ;; *) CFLAGS="$CFLAGS -Wno-deprecated-declarations" diff --git a/lib/wx/doc/src/notes.xml b/lib/wx/doc/src/notes.xml index 0f00309f1b..f895540b25 100644 --- a/lib/wx/doc/src/notes.xml +++ b/lib/wx/doc/src/notes.xml @@ -32,6 +32,59 @@ <p>This document describes the changes made to the wxErlang application.</p> +<section><title>Wx 1.6.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fixed commands with multiple binaries, such as + <c>wxImage:new/4</c>. Added + <c>wxWindow:SetDoubleBuffered/1</c>, + <c>wxWindow:isDoubleBuffered/1</c>, + <c>wxWindow:setTransparent/2</c> and + <c>wxWindow:canSetTransparent/1</c>. Fixed timing issues.</p> + <p> + Own Id: OTP-13404</p> + </item> + </list> + </section> + +</section> + +<section><title>Wx 1.6</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>Add wxOverlay and make wxPostScripDC optional to make + it easier to build on windows.</p> <p>Correct some + function specifications.</p> <p>The driver implementation + have been optimized and now invokes commands after events + have been sent to erlang.</p> + <p> + Own Id: OTP-13160</p> + </item> + </list> + </section> + +</section> + +<section><title>Wx 1.5</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Extend AUI functionality.</p> + <p> + Own Id: OTP-12961</p> + </item> + </list> + </section> + +</section> + <section><title>Wx 1.4</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/wx/examples/demo/ex_aui.erl b/lib/wx/examples/demo/ex_aui.erl index e0841da670..7fbf841d16 100644 --- a/lib/wx/examples/demo/ex_aui.erl +++ b/lib/wx/examples/demo/ex_aui.erl @@ -47,40 +47,54 @@ init(Config) -> -define(pi, wxAuiPaneInfo). do_init(Config) -> - Parent = proplists:get_value(parent, Config), + Parent = proplists:get_value(parent, Config), Panel = wxPanel:new(Parent, []), %% Setup sizers MainSizer = wxBoxSizer:new(?wxVERTICAL), Manager = wxAuiManager:new([{managed_wnd, Panel}]), - - Pane = ?pi:new(), - ?pi:closeButton(Pane), - ?pi:right(Pane), - ?pi:dockable(Pane, [{b, true}]), - ?pi:floatingSize(Pane, 300,200), - ?pi:minSize(Pane, {50,50}), - ?pi:paneBorder(Pane), - ?pi:floatable(Pane, [{b, true}]), - - create_pane(Panel, Manager, Pane), - create_pane(Panel, Manager, - ?pi:caption(?pi:top(?pi:new(Pane)), "One")), - create_pane(Panel, Manager, - ?pi:caption(?pi:left(?pi:new(Pane)), "two")), - create_pane(Panel, Manager, - ?pi:caption(?pi:bottom(?pi:new(Pane)), "Three")), - Pane2 = wxAuiPaneInfo:new(Pane), - ?pi:centrePane(Pane2), - create_notebook(Panel, Manager, ?pi:new(Pane2)), - - wxPanel:setSizer(Panel, MainSizer), - - wxAuiManager:connect(Manager, aui_pane_button, [{skip,true}]), - wxAuiManager:connect(Manager, aui_pane_maximize, [{skip,true}]), - wxAuiManager:update(Manager), - process_flag(trap_exit, true), - {Panel, #state{parent=Panel, config=Config, aui=Manager}}. + try + Art = wxAuiManager:getArtProvider(Manager), + wxAuiDockArt:setColour(Art, ?wxAUI_DOCKART_BACKGROUND_COLOUR, {200, 100, 100}), + wxAuiDockArt:setColour(Art, ?wxAUI_DOCKART_ACTIVE_CAPTION_COLOUR, {200, 100, 100}), + wxAuiDockArt:setColour(Art, ?wxAUI_DOCKART_INACTIVE_CAPTION_COLOUR, {100, 200, 100}), + + + Pane = ?pi:new(), + ?pi:closeButton(Pane), + ?pi:right(Pane), + ?pi:dockable(Pane, [{b, true}]), + ?pi:floatingSize(Pane, 300,200), + ?pi:minSize(Pane, {50,50}), + ?pi:paneBorder(Pane), + ?pi:floatable(Pane, [{b, true}]), + + create_pane(Panel, Manager, Pane), + create_pane(Panel, Manager, + ?pi:caption(?pi:top(?pi:new(Pane)), "One")), + create_pane(Panel, Manager, + ?pi:caption(?pi:left(?pi:new(Pane)), "two")), + create_pane(Panel, Manager, + ?pi:caption(?pi:bottom(?pi:new(Pane)), "Three")), + Pane2 = wxAuiPaneInfo:new(Pane), + ?pi:centrePane(Pane2), + create_notebook(Panel, Manager, ?pi:new(Pane2)), + + wxPanel:setSizer(Panel, MainSizer), + + wxAuiManager:connect(Manager, aui_pane_button, [{skip,true}]), + wxAuiManager:connect(Manager, aui_pane_maximize, [{skip,true}]), + wxAuiManager:update(Manager), + process_flag(trap_exit, true), + {Panel, #state{parent=Panel, config=Config, aui=Manager}} + catch Class:Reason -> + ST = erlang:get_stacktrace(), + io:format("AUI Crashed ~p ~p~n",[Reason, ST]), + wxAuiManager:unInit(Manager), + wxAuiManager:destroy(Manager), + wxPanel:destroy(Panel), + erlang:raise(Class, Reason, ST) + end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Callbacks handled as normal gen_server callbacks @@ -163,6 +177,15 @@ create_notebook(Parent, Manager, Pane) -> Notebook = wxAuiNotebook:new(Parent, [{style, Style}]), + Art = wxAuiSimpleTabArt:new(), + case ?wxMAJOR_VERSION > 2 of + true -> + wxAuiSimpleTabArt:setColour(Art, {200, 0, 0}), + wxAuiSimpleTabArt:setActiveColour(Art, {0, 0, 200}); + false -> ignore + end, + ok = wxAuiNotebook:setArtProvider(Notebook, Art), + Tab1 = wxPanel:new(Notebook, []), wxPanel:setBackgroundColour(Tab1, ?wxBLACK), wxButton:new(Tab1, ?wxID_ANY, [{label,"New tab"}]), diff --git a/lib/wx/examples/demo/ex_canvas.erl b/lib/wx/examples/demo/ex_canvas.erl index 1cbb96de1f..cdc783055c 100644 --- a/lib/wx/examples/demo/ex_canvas.erl +++ b/lib/wx/examples/demo/ex_canvas.erl @@ -35,7 +35,9 @@ parent, config, canvas, - bitmap + bitmap, + overlay, + pos }). start(Config) -> @@ -60,6 +62,10 @@ do_init(Config) -> wxPanel:connect(Canvas, paint, [callback]), wxPanel:connect(Canvas, size), + wxPanel:connect(Canvas, left_down), + wxPanel:connect(Canvas, left_up), + wxPanel:connect(Canvas, motion), + wxPanel:connect(Button, command_button_clicked), %% Add to sizers @@ -78,7 +84,9 @@ do_init(Config) -> Bitmap = wxBitmap:new(erlang:max(W,30),erlang:max(30,H)), {Panel, #state{parent=Panel, config=Config, - canvas = Canvas, bitmap = Bitmap}}. + canvas = Canvas, bitmap = Bitmap, + overlay = wxOverlay:new() + }}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Sync event from callback events, paint event must be handled in callbacks @@ -127,11 +135,39 @@ handle_event(#wx{event = #wxCommand{type = command_button_clicked}}, wxBitmap:destroy(Bmp), {noreply, State}; handle_event(#wx{event = #wxSize{size={W,H}}}, - State = #state{bitmap=Prev}) -> + State = #state{bitmap=Prev, canvas=Canvas}) -> Bitmap = wxBitmap:new(W,H), - draw(State#state.canvas, Bitmap, fun(DC) -> wxDC:clear(DC) end), + draw(Canvas, Bitmap, fun(DC) -> wxDC:clear(DC) end), wxBitmap:destroy(Prev), {noreply, State#state{bitmap = Bitmap}}; + +handle_event(#wx{event = #wxMouse{type=left_down, x=X, y=Y}}, State) -> + {noreply, State#state{pos={X,Y}}}; +handle_event(#wx{event = #wxMouse{type=motion, x=X1, y=Y1}}, + #state{pos=Start, overlay=Overlay, canvas=Canvas} = State) -> + case Start of + undefined -> ignore; + {X0,Y0} -> + DC = wxClientDC:new(Canvas), + DCO = wxDCOverlay:new(Overlay, DC), + wxDCOverlay:clear(DCO), + wxDC:setPen(DC, ?wxLIGHT_GREY_PEN), + wxDC:setBrush(DC, ?wxTRANSPARENT_BRUSH), + wxDC:drawRectangle(DC, {X0,Y0, X1-X0, Y1-Y0}), + wxDCOverlay:destroy(DCO), + wxClientDC:destroy(DC) + end, + {noreply, State}; +handle_event(#wx{event = #wxMouse{type=left_up}}, + #state{overlay=Overlay, canvas=Canvas} = State) -> + DC = wxClientDC:new(Canvas), + DCO = wxDCOverlay:new(Overlay, DC), + wxDCOverlay:clear(DCO), + wxDCOverlay:destroy(DCO), + wxClientDC:destroy(DC), + wxOverlay:reset(Overlay), + {noreply, State#state{pos=undefined}}; + handle_event(Ev = #wx{}, State = #state{}) -> demo:format(State#state.config, "Got Event ~p\n", [Ev]), {noreply, State}. @@ -155,7 +191,8 @@ handle_cast(Msg, State) -> code_change(_, _, State) -> {stop, ignore, State}. -terminate(_Reason, _) -> +terminate(_Reason, #state{overlay=Overlay}) -> + wxOverlay:destroy(Overlay), ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/wx/include/wx.hrl b/lib/wx/include/wx.hrl index 6705e34cb9..333ceca50c 100644 --- a/lib/wx/include/wx.hrl +++ b/lib/wx/include/wx.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2015. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -133,6 +133,10 @@ -type wxSetCursorEventType() :: set_cursor. -type wxSetCursor() :: #wxSetCursor{}. %% Callback event: {@link wxSetCursorEvent} +-record(wxMouseCaptureLost, {type :: wxMouseCaptureLostEventType()}). %% Callback event: {@link wxMouseCaptureLostEvent} +-type wxMouseCaptureLostEventType() :: mouse_capture_lost. +-type wxMouseCaptureLost() :: #wxMouseCaptureLost{}. %% Callback event: {@link wxMouseCaptureLostEvent} + -record(wxFontPicker,{type :: wxFontPickerEventType(), %% Callback event: {@link wxFontPickerEvent} font :: wxFont:wxFont()}). -type wxFontPickerEventType() :: command_fontpicker_changed. @@ -291,7 +295,7 @@ veto_flag :: boolean(), canveto_flag :: boolean(), dc :: wxDC:wxDC()}). --type wxAuiManagerEventType() :: aui_pane_button | aui_pane_close | aui_pane_maximize | aui_pane_restore | aui_render | aui_find_manager. +-type wxAuiManagerEventType() :: aui_pane_button | aui_pane_close | aui_pane_maximize | aui_pane_restore | aui_pane_activated | aui_render | aui_find_manager. -type wxAuiManager() :: #wxAuiManager{}. %% Callback event: {@link wxAuiManagerEvent} -record(wxInitDialog, {type :: wxInitDialogEventType()}). %% Callback event: {@link wxInitDialogEvent} @@ -344,8 +348,8 @@ -type wxTreeEventType() :: command_tree_begin_drag | command_tree_begin_rdrag | command_tree_begin_label_edit | command_tree_end_label_edit | command_tree_delete_item | command_tree_get_info | command_tree_set_info | command_tree_item_expanded | command_tree_item_expanding | command_tree_item_collapsed | command_tree_item_collapsing | command_tree_sel_changed | command_tree_sel_changing | command_tree_key_down | command_tree_item_activated | command_tree_item_right_click | command_tree_item_middle_click | command_tree_end_drag | command_tree_state_image_click | command_tree_item_gettooltip | command_tree_item_menu. -type wxTree() :: #wxTree{}. %% Callback event: {@link wxTreeEvent} --type event() :: wxActivate() | wxAuiManager() | wxAuiNotebook() | wxCalendar() | wxChildFocus() | wxClipboardText() | wxClose() | wxColourPicker() | wxCommand() | wxContextMenu() | wxDate() | wxDisplayChanged() | wxErase() | wxFileDirPicker() | wxFocus() | wxFontPicker() | wxGrid() | wxHelp() | wxHtmlLink() | wxIconize() | wxIdle() | wxInitDialog() | wxJoystick() | wxKey() | wxList() | wxMaximize() | wxMenu() | wxMouse() | wxMouseCaptureChanged() | wxMove() | wxNavigationKey() | wxNotebook() | wxPaint() | wxPaletteChanged() | wxQueryNewPalette() | wxSash() | wxScroll() | wxScrollWin() | wxSetCursor() | wxShow() | wxSize() | wxSpin() | wxSplitter() | wxStyledText() | wxSysColourChanged() | wxTaskBarIcon() | wxTree() | wxUpdateUI() | wxWindowCreate() | wxWindowDestroy(). --type wxEventType() :: wxActivateEventType() | wxAuiManagerEventType() | wxAuiNotebookEventType() | wxCalendarEventType() | wxChildFocusEventType() | wxClipboardTextEventType() | wxCloseEventType() | wxColourPickerEventType() | wxCommandEventType() | wxContextMenuEventType() | wxDateEventType() | wxDisplayChangedEventType() | wxEraseEventType() | wxFileDirPickerEventType() | wxFocusEventType() | wxFontPickerEventType() | wxGridEventType() | wxHelpEventType() | wxHtmlLinkEventType() | wxIconizeEventType() | wxIdleEventType() | wxInitDialogEventType() | wxJoystickEventType() | wxKeyEventType() | wxListEventType() | wxMaximizeEventType() | wxMenuEventType() | wxMouseCaptureChangedEventType() | wxMouseEventType() | wxMoveEventType() | wxNavigationKeyEventType() | wxNotebookEventType() | wxPaintEventType() | wxPaletteChangedEventType() | wxQueryNewPaletteEventType() | wxSashEventType() | wxScrollEventType() | wxScrollWinEventType() | wxSetCursorEventType() | wxShowEventType() | wxSizeEventType() | wxSpinEventType() | wxSplitterEventType() | wxStyledTextEventType() | wxSysColourChangedEventType() | wxTaskBarIconEventType() | wxTreeEventType() | wxUpdateUIEventType() | wxWindowCreateEventType() | wxWindowDestroyEventType(). +-type event() :: wxActivate() | wxAuiManager() | wxAuiNotebook() | wxCalendar() | wxChildFocus() | wxClipboardText() | wxClose() | wxColourPicker() | wxCommand() | wxContextMenu() | wxDate() | wxDisplayChanged() | wxErase() | wxFileDirPicker() | wxFocus() | wxFontPicker() | wxGrid() | wxHelp() | wxHtmlLink() | wxIconize() | wxIdle() | wxInitDialog() | wxJoystick() | wxKey() | wxList() | wxMaximize() | wxMenu() | wxMouse() | wxMouseCaptureChanged() | wxMouseCaptureLost() | wxMove() | wxNavigationKey() | wxNotebook() | wxPaint() | wxPaletteChanged() | wxQueryNewPalette() | wxSash() | wxScroll() | wxScrollWin() | wxSetCursor() | wxShow() | wxSize() | wxSpin() | wxSplitter() | wxStyledText() | wxSysColourChanged() | wxTaskBarIcon() | wxTree() | wxUpdateUI() | wxWindowCreate() | wxWindowDestroy(). +-type wxEventType() :: wxActivateEventType() | wxAuiManagerEventType() | wxAuiNotebookEventType() | wxCalendarEventType() | wxChildFocusEventType() | wxClipboardTextEventType() | wxCloseEventType() | wxColourPickerEventType() | wxCommandEventType() | wxContextMenuEventType() | wxDateEventType() | wxDisplayChangedEventType() | wxEraseEventType() | wxFileDirPickerEventType() | wxFocusEventType() | wxFontPickerEventType() | wxGridEventType() | wxHelpEventType() | wxHtmlLinkEventType() | wxIconizeEventType() | wxIdleEventType() | wxInitDialogEventType() | wxJoystickEventType() | wxKeyEventType() | wxListEventType() | wxMaximizeEventType() | wxMenuEventType() | wxMouseCaptureChangedEventType() | wxMouseCaptureLostEventType() | wxMouseEventType() | wxMoveEventType() | wxNavigationKeyEventType() | wxNotebookEventType() | wxPaintEventType() | wxPaletteChangedEventType() | wxQueryNewPaletteEventType() | wxSashEventType() | wxScrollEventType() | wxScrollWinEventType() | wxSetCursorEventType() | wxShowEventType() | wxSizeEventType() | wxSpinEventType() | wxSplitterEventType() | wxStyledTextEventType() | wxSysColourChangedEventType() | wxTaskBarIconEventType() | wxTreeEventType() | wxUpdateUIEventType() | wxWindowCreateEventType() | wxWindowDestroyEventType(). %% Hardcoded Records -record(wxMouseState, {x :: integer(), y :: integer(), @@ -2009,239 +2013,239 @@ -define(wxIMAGELIST_DRAW_TRANSPARENT, 2). -define(wxIMAGELIST_DRAW_NORMAL, 1). % From "intl.h": wxLanguage --define(wxLANGUAGE_DEFAULT, 0). --define(wxLANGUAGE_UNKNOWN, 1). --define(wxLANGUAGE_ABKHAZIAN, 2). --define(wxLANGUAGE_AFAR, 3). --define(wxLANGUAGE_AFRIKAANS, 4). --define(wxLANGUAGE_ALBANIAN, 5). --define(wxLANGUAGE_AMHARIC, 6). --define(wxLANGUAGE_ARABIC, 7). --define(wxLANGUAGE_ARABIC_ALGERIA, 8). --define(wxLANGUAGE_ARABIC_BAHRAIN, 9). --define(wxLANGUAGE_ARABIC_EGYPT, 10). --define(wxLANGUAGE_ARABIC_IRAQ, 11). --define(wxLANGUAGE_ARABIC_JORDAN, 12). --define(wxLANGUAGE_ARABIC_KUWAIT, 13). --define(wxLANGUAGE_ARABIC_LEBANON, 14). --define(wxLANGUAGE_ARABIC_LIBYA, 15). --define(wxLANGUAGE_ARABIC_MOROCCO, 16). --define(wxLANGUAGE_ARABIC_OMAN, 17). --define(wxLANGUAGE_ARABIC_QATAR, 18). --define(wxLANGUAGE_ARABIC_SAUDI_ARABIA, 19). --define(wxLANGUAGE_ARABIC_SUDAN, 20). --define(wxLANGUAGE_ARABIC_SYRIA, 21). --define(wxLANGUAGE_ARABIC_TUNISIA, 22). --define(wxLANGUAGE_ARABIC_UAE, 23). --define(wxLANGUAGE_ARABIC_YEMEN, 24). --define(wxLANGUAGE_ARMENIAN, 25). --define(wxLANGUAGE_ASSAMESE, 26). --define(wxLANGUAGE_AYMARA, 27). --define(wxLANGUAGE_AZERI, 28). --define(wxLANGUAGE_AZERI_CYRILLIC, 29). --define(wxLANGUAGE_AZERI_LATIN, 30). --define(wxLANGUAGE_BASHKIR, 31). --define(wxLANGUAGE_BASQUE, 32). --define(wxLANGUAGE_BELARUSIAN, 33). --define(wxLANGUAGE_BENGALI, 34). --define(wxLANGUAGE_BHUTANI, 35). --define(wxLANGUAGE_BIHARI, 36). --define(wxLANGUAGE_BISLAMA, 37). --define(wxLANGUAGE_BRETON, 38). --define(wxLANGUAGE_BULGARIAN, 39). --define(wxLANGUAGE_BURMESE, 40). --define(wxLANGUAGE_CAMBODIAN, 41). --define(wxLANGUAGE_CATALAN, 42). --define(wxLANGUAGE_CHINESE, 43). --define(wxLANGUAGE_CHINESE_SIMPLIFIED, 44). --define(wxLANGUAGE_CHINESE_TRADITIONAL, 45). --define(wxLANGUAGE_CHINESE_HONGKONG, 46). --define(wxLANGUAGE_CHINESE_MACAU, 47). --define(wxLANGUAGE_CHINESE_SINGAPORE, 48). --define(wxLANGUAGE_CHINESE_TAIWAN, 49). --define(wxLANGUAGE_CORSICAN, 50). --define(wxLANGUAGE_CROATIAN, 51). --define(wxLANGUAGE_CZECH, 52). --define(wxLANGUAGE_DANISH, 53). --define(wxLANGUAGE_DUTCH, 54). --define(wxLANGUAGE_DUTCH_BELGIAN, 55). --define(wxLANGUAGE_ENGLISH, 56). --define(wxLANGUAGE_ENGLISH_UK, 57). --define(wxLANGUAGE_ENGLISH_US, 58). --define(wxLANGUAGE_ENGLISH_AUSTRALIA, 59). --define(wxLANGUAGE_ENGLISH_BELIZE, 60). --define(wxLANGUAGE_ENGLISH_BOTSWANA, 61). --define(wxLANGUAGE_ENGLISH_CANADA, 62). --define(wxLANGUAGE_ENGLISH_CARIBBEAN, 63). --define(wxLANGUAGE_ENGLISH_DENMARK, 64). --define(wxLANGUAGE_ENGLISH_EIRE, 65). --define(wxLANGUAGE_ENGLISH_JAMAICA, 66). --define(wxLANGUAGE_ENGLISH_NEW_ZEALAND, 67). --define(wxLANGUAGE_ENGLISH_PHILIPPINES, 68). --define(wxLANGUAGE_ENGLISH_SOUTH_AFRICA, 69). --define(wxLANGUAGE_ENGLISH_TRINIDAD, 70). --define(wxLANGUAGE_ENGLISH_ZIMBABWE, 71). --define(wxLANGUAGE_ESPERANTO, 72). --define(wxLANGUAGE_ESTONIAN, 73). --define(wxLANGUAGE_FAEROESE, 74). --define(wxLANGUAGE_FARSI, 75). --define(wxLANGUAGE_FIJI, 76). --define(wxLANGUAGE_FINNISH, 77). --define(wxLANGUAGE_FRENCH, 78). --define(wxLANGUAGE_FRENCH_BELGIAN, 79). --define(wxLANGUAGE_FRENCH_CANADIAN, 80). --define(wxLANGUAGE_FRENCH_LUXEMBOURG, 81). --define(wxLANGUAGE_FRENCH_MONACO, 82). --define(wxLANGUAGE_FRENCH_SWISS, 83). --define(wxLANGUAGE_FRISIAN, 84). --define(wxLANGUAGE_GALICIAN, 85). --define(wxLANGUAGE_GEORGIAN, 86). --define(wxLANGUAGE_GERMAN, 87). --define(wxLANGUAGE_GERMAN_AUSTRIAN, 88). --define(wxLANGUAGE_GERMAN_BELGIUM, 89). --define(wxLANGUAGE_GERMAN_LIECHTENSTEIN, 90). --define(wxLANGUAGE_GERMAN_LUXEMBOURG, 91). --define(wxLANGUAGE_GERMAN_SWISS, 92). --define(wxLANGUAGE_GREEK, 93). --define(wxLANGUAGE_GREENLANDIC, 94). --define(wxLANGUAGE_GUARANI, 95). --define(wxLANGUAGE_GUJARATI, 96). --define(wxLANGUAGE_HAUSA, 97). --define(wxLANGUAGE_HEBREW, 98). --define(wxLANGUAGE_HINDI, 99). --define(wxLANGUAGE_HUNGARIAN, 100). --define(wxLANGUAGE_ICELANDIC, 101). --define(wxLANGUAGE_INDONESIAN, 102). --define(wxLANGUAGE_INTERLINGUA, 103). --define(wxLANGUAGE_INTERLINGUE, 104). --define(wxLANGUAGE_INUKTITUT, 105). --define(wxLANGUAGE_INUPIAK, 106). --define(wxLANGUAGE_IRISH, 107). --define(wxLANGUAGE_ITALIAN, 108). --define(wxLANGUAGE_ITALIAN_SWISS, 109). --define(wxLANGUAGE_JAPANESE, 110). --define(wxLANGUAGE_JAVANESE, 111). --define(wxLANGUAGE_KANNADA, 112). --define(wxLANGUAGE_KASHMIRI, 113). --define(wxLANGUAGE_KASHMIRI_INDIA, 114). --define(wxLANGUAGE_KAZAKH, 115). --define(wxLANGUAGE_KERNEWEK, 116). --define(wxLANGUAGE_KINYARWANDA, 117). --define(wxLANGUAGE_KIRGHIZ, 118). --define(wxLANGUAGE_KIRUNDI, 119). --define(wxLANGUAGE_KONKANI, 120). --define(wxLANGUAGE_KOREAN, 121). --define(wxLANGUAGE_KURDISH, 122). --define(wxLANGUAGE_LAOTHIAN, 123). --define(wxLANGUAGE_LATIN, 124). --define(wxLANGUAGE_LATVIAN, 125). --define(wxLANGUAGE_LINGALA, 126). --define(wxLANGUAGE_LITHUANIAN, 127). --define(wxLANGUAGE_MACEDONIAN, 128). --define(wxLANGUAGE_MALAGASY, 129). --define(wxLANGUAGE_MALAY, 130). --define(wxLANGUAGE_MALAYALAM, 131). --define(wxLANGUAGE_MALAY_BRUNEI_DARUSSALAM, 132). --define(wxLANGUAGE_MALAY_MALAYSIA, 133). --define(wxLANGUAGE_MALTESE, 134). --define(wxLANGUAGE_MANIPURI, 135). --define(wxLANGUAGE_MAORI, 136). --define(wxLANGUAGE_MARATHI, 137). --define(wxLANGUAGE_MOLDAVIAN, 138). --define(wxLANGUAGE_MONGOLIAN, 139). --define(wxLANGUAGE_NAURU, 140). --define(wxLANGUAGE_NEPALI, 141). --define(wxLANGUAGE_NEPALI_INDIA, 142). --define(wxLANGUAGE_NORWEGIAN_BOKMAL, 143). --define(wxLANGUAGE_NORWEGIAN_NYNORSK, 144). --define(wxLANGUAGE_OCCITAN, 145). --define(wxLANGUAGE_ORIYA, 146). --define(wxLANGUAGE_OROMO, 147). --define(wxLANGUAGE_PASHTO, 148). --define(wxLANGUAGE_POLISH, 149). --define(wxLANGUAGE_PORTUGUESE, 150). --define(wxLANGUAGE_PORTUGUESE_BRAZILIAN, 151). --define(wxLANGUAGE_PUNJABI, 152). --define(wxLANGUAGE_QUECHUA, 153). --define(wxLANGUAGE_RHAETO_ROMANCE, 154). --define(wxLANGUAGE_ROMANIAN, 155). --define(wxLANGUAGE_RUSSIAN, 156). --define(wxLANGUAGE_RUSSIAN_UKRAINE, 157). --define(wxLANGUAGE_SAMOAN, 158). --define(wxLANGUAGE_SANGHO, 159). --define(wxLANGUAGE_SANSKRIT, 160). --define(wxLANGUAGE_SCOTS_GAELIC, 161). --define(wxLANGUAGE_SERBIAN, 162). --define(wxLANGUAGE_SERBIAN_CYRILLIC, 163). --define(wxLANGUAGE_SERBIAN_LATIN, 164). --define(wxLANGUAGE_SERBO_CROATIAN, 165). --define(wxLANGUAGE_SESOTHO, 166). --define(wxLANGUAGE_SETSWANA, 167). --define(wxLANGUAGE_SHONA, 168). --define(wxLANGUAGE_SINDHI, 169). --define(wxLANGUAGE_SINHALESE, 170). --define(wxLANGUAGE_SISWATI, 171). --define(wxLANGUAGE_SLOVAK, 172). --define(wxLANGUAGE_SLOVENIAN, 173). --define(wxLANGUAGE_SOMALI, 174). --define(wxLANGUAGE_SPANISH, 175). --define(wxLANGUAGE_SPANISH_ARGENTINA, 176). --define(wxLANGUAGE_SPANISH_BOLIVIA, 177). --define(wxLANGUAGE_SPANISH_CHILE, 178). --define(wxLANGUAGE_SPANISH_COLOMBIA, 179). --define(wxLANGUAGE_SPANISH_COSTA_RICA, 180). --define(wxLANGUAGE_SPANISH_DOMINICAN_REPUBLIC, 181). --define(wxLANGUAGE_SPANISH_ECUADOR, 182). --define(wxLANGUAGE_SPANISH_EL_SALVADOR, 183). --define(wxLANGUAGE_SPANISH_GUATEMALA, 184). --define(wxLANGUAGE_SPANISH_HONDURAS, 185). --define(wxLANGUAGE_SPANISH_MEXICAN, 186). --define(wxLANGUAGE_SPANISH_MODERN, 187). --define(wxLANGUAGE_SPANISH_NICARAGUA, 188). --define(wxLANGUAGE_SPANISH_PANAMA, 189). --define(wxLANGUAGE_SPANISH_PARAGUAY, 190). --define(wxLANGUAGE_SPANISH_PERU, 191). --define(wxLANGUAGE_SPANISH_PUERTO_RICO, 192). --define(wxLANGUAGE_SPANISH_URUGUAY, 193). --define(wxLANGUAGE_SPANISH_US, 194). --define(wxLANGUAGE_SPANISH_VENEZUELA, 195). --define(wxLANGUAGE_SUNDANESE, 196). --define(wxLANGUAGE_SWAHILI, 197). --define(wxLANGUAGE_SWEDISH, 198). --define(wxLANGUAGE_SWEDISH_FINLAND, 199). --define(wxLANGUAGE_TAGALOG, 200). --define(wxLANGUAGE_TAJIK, 201). --define(wxLANGUAGE_TAMIL, 202). --define(wxLANGUAGE_TATAR, 203). --define(wxLANGUAGE_TELUGU, 204). --define(wxLANGUAGE_THAI, 205). --define(wxLANGUAGE_TIBETAN, 206). --define(wxLANGUAGE_TIGRINYA, 207). --define(wxLANGUAGE_TONGA, 208). --define(wxLANGUAGE_TSONGA, 209). --define(wxLANGUAGE_TURKISH, 210). --define(wxLANGUAGE_TURKMEN, 211). --define(wxLANGUAGE_TWI, 212). --define(wxLANGUAGE_UIGHUR, 213). --define(wxLANGUAGE_UKRAINIAN, 214). --define(wxLANGUAGE_URDU, 215). --define(wxLANGUAGE_URDU_INDIA, 216). --define(wxLANGUAGE_URDU_PAKISTAN, 217). --define(wxLANGUAGE_UZBEK, 218). --define(wxLANGUAGE_UZBEK_CYRILLIC, 219). --define(wxLANGUAGE_UZBEK_LATIN, 220). --define(wxLANGUAGE_VIETNAMESE, 221). --define(wxLANGUAGE_VOLAPUK, 222). --define(wxLANGUAGE_WELSH, 223). --define(wxLANGUAGE_WOLOF, 224). --define(wxLANGUAGE_XHOSA, 225). --define(wxLANGUAGE_YIDDISH, 226). --define(wxLANGUAGE_YORUBA, 227). --define(wxLANGUAGE_ZHUANG, 228). --define(wxLANGUAGE_ZULU, 229). --define(wxLANGUAGE_USER_DEFINED, 230). --define(wxLANGUAGE_VALENCIAN, 536870911). --define(wxLANGUAGE_SAMI, 536870912). +-define(wxLANGUAGE_DEFAULT, wxe_util:get_const(wxLANGUAGE_DEFAULT)). +-define(wxLANGUAGE_UNKNOWN, wxe_util:get_const(wxLANGUAGE_UNKNOWN)). +-define(wxLANGUAGE_ABKHAZIAN, wxe_util:get_const(wxLANGUAGE_ABKHAZIAN)). +-define(wxLANGUAGE_AFAR, wxe_util:get_const(wxLANGUAGE_AFAR)). +-define(wxLANGUAGE_AFRIKAANS, wxe_util:get_const(wxLANGUAGE_AFRIKAANS)). +-define(wxLANGUAGE_ALBANIAN, wxe_util:get_const(wxLANGUAGE_ALBANIAN)). +-define(wxLANGUAGE_AMHARIC, wxe_util:get_const(wxLANGUAGE_AMHARIC)). +-define(wxLANGUAGE_ARABIC, wxe_util:get_const(wxLANGUAGE_ARABIC)). +-define(wxLANGUAGE_ARABIC_ALGERIA, wxe_util:get_const(wxLANGUAGE_ARABIC_ALGERIA)). +-define(wxLANGUAGE_ARABIC_BAHRAIN, wxe_util:get_const(wxLANGUAGE_ARABIC_BAHRAIN)). +-define(wxLANGUAGE_ARABIC_EGYPT, wxe_util:get_const(wxLANGUAGE_ARABIC_EGYPT)). +-define(wxLANGUAGE_ARABIC_IRAQ, wxe_util:get_const(wxLANGUAGE_ARABIC_IRAQ)). +-define(wxLANGUAGE_ARABIC_JORDAN, wxe_util:get_const(wxLANGUAGE_ARABIC_JORDAN)). +-define(wxLANGUAGE_ARABIC_KUWAIT, wxe_util:get_const(wxLANGUAGE_ARABIC_KUWAIT)). +-define(wxLANGUAGE_ARABIC_LEBANON, wxe_util:get_const(wxLANGUAGE_ARABIC_LEBANON)). +-define(wxLANGUAGE_ARABIC_LIBYA, wxe_util:get_const(wxLANGUAGE_ARABIC_LIBYA)). +-define(wxLANGUAGE_ARABIC_MOROCCO, wxe_util:get_const(wxLANGUAGE_ARABIC_MOROCCO)). +-define(wxLANGUAGE_ARABIC_OMAN, wxe_util:get_const(wxLANGUAGE_ARABIC_OMAN)). +-define(wxLANGUAGE_ARABIC_QATAR, wxe_util:get_const(wxLANGUAGE_ARABIC_QATAR)). +-define(wxLANGUAGE_ARABIC_SAUDI_ARABIA, wxe_util:get_const(wxLANGUAGE_ARABIC_SAUDI_ARABIA)). +-define(wxLANGUAGE_ARABIC_SUDAN, wxe_util:get_const(wxLANGUAGE_ARABIC_SUDAN)). +-define(wxLANGUAGE_ARABIC_SYRIA, wxe_util:get_const(wxLANGUAGE_ARABIC_SYRIA)). +-define(wxLANGUAGE_ARABIC_TUNISIA, wxe_util:get_const(wxLANGUAGE_ARABIC_TUNISIA)). +-define(wxLANGUAGE_ARABIC_UAE, wxe_util:get_const(wxLANGUAGE_ARABIC_UAE)). +-define(wxLANGUAGE_ARABIC_YEMEN, wxe_util:get_const(wxLANGUAGE_ARABIC_YEMEN)). +-define(wxLANGUAGE_ARMENIAN, wxe_util:get_const(wxLANGUAGE_ARMENIAN)). +-define(wxLANGUAGE_ASSAMESE, wxe_util:get_const(wxLANGUAGE_ASSAMESE)). +-define(wxLANGUAGE_AYMARA, wxe_util:get_const(wxLANGUAGE_AYMARA)). +-define(wxLANGUAGE_AZERI, wxe_util:get_const(wxLANGUAGE_AZERI)). +-define(wxLANGUAGE_AZERI_CYRILLIC, wxe_util:get_const(wxLANGUAGE_AZERI_CYRILLIC)). +-define(wxLANGUAGE_AZERI_LATIN, wxe_util:get_const(wxLANGUAGE_AZERI_LATIN)). +-define(wxLANGUAGE_BASHKIR, wxe_util:get_const(wxLANGUAGE_BASHKIR)). +-define(wxLANGUAGE_BASQUE, wxe_util:get_const(wxLANGUAGE_BASQUE)). +-define(wxLANGUAGE_BELARUSIAN, wxe_util:get_const(wxLANGUAGE_BELARUSIAN)). +-define(wxLANGUAGE_BENGALI, wxe_util:get_const(wxLANGUAGE_BENGALI)). +-define(wxLANGUAGE_BHUTANI, wxe_util:get_const(wxLANGUAGE_BHUTANI)). +-define(wxLANGUAGE_BIHARI, wxe_util:get_const(wxLANGUAGE_BIHARI)). +-define(wxLANGUAGE_BISLAMA, wxe_util:get_const(wxLANGUAGE_BISLAMA)). +-define(wxLANGUAGE_BRETON, wxe_util:get_const(wxLANGUAGE_BRETON)). +-define(wxLANGUAGE_BULGARIAN, wxe_util:get_const(wxLANGUAGE_BULGARIAN)). +-define(wxLANGUAGE_BURMESE, wxe_util:get_const(wxLANGUAGE_BURMESE)). +-define(wxLANGUAGE_CAMBODIAN, wxe_util:get_const(wxLANGUAGE_CAMBODIAN)). +-define(wxLANGUAGE_CATALAN, wxe_util:get_const(wxLANGUAGE_CATALAN)). +-define(wxLANGUAGE_CHINESE, wxe_util:get_const(wxLANGUAGE_CHINESE)). +-define(wxLANGUAGE_CHINESE_SIMPLIFIED, wxe_util:get_const(wxLANGUAGE_CHINESE_SIMPLIFIED)). +-define(wxLANGUAGE_CHINESE_TRADITIONAL, wxe_util:get_const(wxLANGUAGE_CHINESE_TRADITIONAL)). +-define(wxLANGUAGE_CHINESE_HONGKONG, wxe_util:get_const(wxLANGUAGE_CHINESE_HONGKONG)). +-define(wxLANGUAGE_CHINESE_MACAU, wxe_util:get_const(wxLANGUAGE_CHINESE_MACAU)). +-define(wxLANGUAGE_CHINESE_SINGAPORE, wxe_util:get_const(wxLANGUAGE_CHINESE_SINGAPORE)). +-define(wxLANGUAGE_CHINESE_TAIWAN, wxe_util:get_const(wxLANGUAGE_CHINESE_TAIWAN)). +-define(wxLANGUAGE_CORSICAN, wxe_util:get_const(wxLANGUAGE_CORSICAN)). +-define(wxLANGUAGE_CROATIAN, wxe_util:get_const(wxLANGUAGE_CROATIAN)). +-define(wxLANGUAGE_CZECH, wxe_util:get_const(wxLANGUAGE_CZECH)). +-define(wxLANGUAGE_DANISH, wxe_util:get_const(wxLANGUAGE_DANISH)). +-define(wxLANGUAGE_DUTCH, wxe_util:get_const(wxLANGUAGE_DUTCH)). +-define(wxLANGUAGE_DUTCH_BELGIAN, wxe_util:get_const(wxLANGUAGE_DUTCH_BELGIAN)). +-define(wxLANGUAGE_ENGLISH, wxe_util:get_const(wxLANGUAGE_ENGLISH)). +-define(wxLANGUAGE_ENGLISH_UK, wxe_util:get_const(wxLANGUAGE_ENGLISH_UK)). +-define(wxLANGUAGE_ENGLISH_US, wxe_util:get_const(wxLANGUAGE_ENGLISH_US)). +-define(wxLANGUAGE_ENGLISH_AUSTRALIA, wxe_util:get_const(wxLANGUAGE_ENGLISH_AUSTRALIA)). +-define(wxLANGUAGE_ENGLISH_BELIZE, wxe_util:get_const(wxLANGUAGE_ENGLISH_BELIZE)). +-define(wxLANGUAGE_ENGLISH_BOTSWANA, wxe_util:get_const(wxLANGUAGE_ENGLISH_BOTSWANA)). +-define(wxLANGUAGE_ENGLISH_CANADA, wxe_util:get_const(wxLANGUAGE_ENGLISH_CANADA)). +-define(wxLANGUAGE_ENGLISH_CARIBBEAN, wxe_util:get_const(wxLANGUAGE_ENGLISH_CARIBBEAN)). +-define(wxLANGUAGE_ENGLISH_DENMARK, wxe_util:get_const(wxLANGUAGE_ENGLISH_DENMARK)). +-define(wxLANGUAGE_ENGLISH_EIRE, wxe_util:get_const(wxLANGUAGE_ENGLISH_EIRE)). +-define(wxLANGUAGE_ENGLISH_JAMAICA, wxe_util:get_const(wxLANGUAGE_ENGLISH_JAMAICA)). +-define(wxLANGUAGE_ENGLISH_NEW_ZEALAND, wxe_util:get_const(wxLANGUAGE_ENGLISH_NEW_ZEALAND)). +-define(wxLANGUAGE_ENGLISH_PHILIPPINES, wxe_util:get_const(wxLANGUAGE_ENGLISH_PHILIPPINES)). +-define(wxLANGUAGE_ENGLISH_SOUTH_AFRICA, wxe_util:get_const(wxLANGUAGE_ENGLISH_SOUTH_AFRICA)). +-define(wxLANGUAGE_ENGLISH_TRINIDAD, wxe_util:get_const(wxLANGUAGE_ENGLISH_TRINIDAD)). +-define(wxLANGUAGE_ENGLISH_ZIMBABWE, wxe_util:get_const(wxLANGUAGE_ENGLISH_ZIMBABWE)). +-define(wxLANGUAGE_ESPERANTO, wxe_util:get_const(wxLANGUAGE_ESPERANTO)). +-define(wxLANGUAGE_ESTONIAN, wxe_util:get_const(wxLANGUAGE_ESTONIAN)). +-define(wxLANGUAGE_FAEROESE, wxe_util:get_const(wxLANGUAGE_FAEROESE)). +-define(wxLANGUAGE_FARSI, wxe_util:get_const(wxLANGUAGE_FARSI)). +-define(wxLANGUAGE_FIJI, wxe_util:get_const(wxLANGUAGE_FIJI)). +-define(wxLANGUAGE_FINNISH, wxe_util:get_const(wxLANGUAGE_FINNISH)). +-define(wxLANGUAGE_FRENCH, wxe_util:get_const(wxLANGUAGE_FRENCH)). +-define(wxLANGUAGE_FRENCH_BELGIAN, wxe_util:get_const(wxLANGUAGE_FRENCH_BELGIAN)). +-define(wxLANGUAGE_FRENCH_CANADIAN, wxe_util:get_const(wxLANGUAGE_FRENCH_CANADIAN)). +-define(wxLANGUAGE_FRENCH_LUXEMBOURG, wxe_util:get_const(wxLANGUAGE_FRENCH_LUXEMBOURG)). +-define(wxLANGUAGE_FRENCH_MONACO, wxe_util:get_const(wxLANGUAGE_FRENCH_MONACO)). +-define(wxLANGUAGE_FRENCH_SWISS, wxe_util:get_const(wxLANGUAGE_FRENCH_SWISS)). +-define(wxLANGUAGE_FRISIAN, wxe_util:get_const(wxLANGUAGE_FRISIAN)). +-define(wxLANGUAGE_GALICIAN, wxe_util:get_const(wxLANGUAGE_GALICIAN)). +-define(wxLANGUAGE_GEORGIAN, wxe_util:get_const(wxLANGUAGE_GEORGIAN)). +-define(wxLANGUAGE_GERMAN, wxe_util:get_const(wxLANGUAGE_GERMAN)). +-define(wxLANGUAGE_GERMAN_AUSTRIAN, wxe_util:get_const(wxLANGUAGE_GERMAN_AUSTRIAN)). +-define(wxLANGUAGE_GERMAN_BELGIUM, wxe_util:get_const(wxLANGUAGE_GERMAN_BELGIUM)). +-define(wxLANGUAGE_GERMAN_LIECHTENSTEIN, wxe_util:get_const(wxLANGUAGE_GERMAN_LIECHTENSTEIN)). +-define(wxLANGUAGE_GERMAN_LUXEMBOURG, wxe_util:get_const(wxLANGUAGE_GERMAN_LUXEMBOURG)). +-define(wxLANGUAGE_GERMAN_SWISS, wxe_util:get_const(wxLANGUAGE_GERMAN_SWISS)). +-define(wxLANGUAGE_GREEK, wxe_util:get_const(wxLANGUAGE_GREEK)). +-define(wxLANGUAGE_GREENLANDIC, wxe_util:get_const(wxLANGUAGE_GREENLANDIC)). +-define(wxLANGUAGE_GUARANI, wxe_util:get_const(wxLANGUAGE_GUARANI)). +-define(wxLANGUAGE_GUJARATI, wxe_util:get_const(wxLANGUAGE_GUJARATI)). +-define(wxLANGUAGE_HAUSA, wxe_util:get_const(wxLANGUAGE_HAUSA)). +-define(wxLANGUAGE_HEBREW, wxe_util:get_const(wxLANGUAGE_HEBREW)). +-define(wxLANGUAGE_HINDI, wxe_util:get_const(wxLANGUAGE_HINDI)). +-define(wxLANGUAGE_HUNGARIAN, wxe_util:get_const(wxLANGUAGE_HUNGARIAN)). +-define(wxLANGUAGE_ICELANDIC, wxe_util:get_const(wxLANGUAGE_ICELANDIC)). +-define(wxLANGUAGE_INDONESIAN, wxe_util:get_const(wxLANGUAGE_INDONESIAN)). +-define(wxLANGUAGE_INTERLINGUA, wxe_util:get_const(wxLANGUAGE_INTERLINGUA)). +-define(wxLANGUAGE_INTERLINGUE, wxe_util:get_const(wxLANGUAGE_INTERLINGUE)). +-define(wxLANGUAGE_INUKTITUT, wxe_util:get_const(wxLANGUAGE_INUKTITUT)). +-define(wxLANGUAGE_INUPIAK, wxe_util:get_const(wxLANGUAGE_INUPIAK)). +-define(wxLANGUAGE_IRISH, wxe_util:get_const(wxLANGUAGE_IRISH)). +-define(wxLANGUAGE_ITALIAN, wxe_util:get_const(wxLANGUAGE_ITALIAN)). +-define(wxLANGUAGE_ITALIAN_SWISS, wxe_util:get_const(wxLANGUAGE_ITALIAN_SWISS)). +-define(wxLANGUAGE_JAPANESE, wxe_util:get_const(wxLANGUAGE_JAPANESE)). +-define(wxLANGUAGE_JAVANESE, wxe_util:get_const(wxLANGUAGE_JAVANESE)). +-define(wxLANGUAGE_KANNADA, wxe_util:get_const(wxLANGUAGE_KANNADA)). +-define(wxLANGUAGE_KASHMIRI, wxe_util:get_const(wxLANGUAGE_KASHMIRI)). +-define(wxLANGUAGE_KASHMIRI_INDIA, wxe_util:get_const(wxLANGUAGE_KASHMIRI_INDIA)). +-define(wxLANGUAGE_KAZAKH, wxe_util:get_const(wxLANGUAGE_KAZAKH)). +-define(wxLANGUAGE_KERNEWEK, wxe_util:get_const(wxLANGUAGE_KERNEWEK)). +-define(wxLANGUAGE_KINYARWANDA, wxe_util:get_const(wxLANGUAGE_KINYARWANDA)). +-define(wxLANGUAGE_KIRGHIZ, wxe_util:get_const(wxLANGUAGE_KIRGHIZ)). +-define(wxLANGUAGE_KIRUNDI, wxe_util:get_const(wxLANGUAGE_KIRUNDI)). +-define(wxLANGUAGE_KONKANI, wxe_util:get_const(wxLANGUAGE_KONKANI)). +-define(wxLANGUAGE_KOREAN, wxe_util:get_const(wxLANGUAGE_KOREAN)). +-define(wxLANGUAGE_KURDISH, wxe_util:get_const(wxLANGUAGE_KURDISH)). +-define(wxLANGUAGE_LAOTHIAN, wxe_util:get_const(wxLANGUAGE_LAOTHIAN)). +-define(wxLANGUAGE_LATIN, wxe_util:get_const(wxLANGUAGE_LATIN)). +-define(wxLANGUAGE_LATVIAN, wxe_util:get_const(wxLANGUAGE_LATVIAN)). +-define(wxLANGUAGE_LINGALA, wxe_util:get_const(wxLANGUAGE_LINGALA)). +-define(wxLANGUAGE_LITHUANIAN, wxe_util:get_const(wxLANGUAGE_LITHUANIAN)). +-define(wxLANGUAGE_MACEDONIAN, wxe_util:get_const(wxLANGUAGE_MACEDONIAN)). +-define(wxLANGUAGE_MALAGASY, wxe_util:get_const(wxLANGUAGE_MALAGASY)). +-define(wxLANGUAGE_MALAY, wxe_util:get_const(wxLANGUAGE_MALAY)). +-define(wxLANGUAGE_MALAYALAM, wxe_util:get_const(wxLANGUAGE_MALAYALAM)). +-define(wxLANGUAGE_MALAY_BRUNEI_DARUSSALAM, wxe_util:get_const(wxLANGUAGE_MALAY_BRUNEI_DARUSSALAM)). +-define(wxLANGUAGE_MALAY_MALAYSIA, wxe_util:get_const(wxLANGUAGE_MALAY_MALAYSIA)). +-define(wxLANGUAGE_MALTESE, wxe_util:get_const(wxLANGUAGE_MALTESE)). +-define(wxLANGUAGE_MANIPURI, wxe_util:get_const(wxLANGUAGE_MANIPURI)). +-define(wxLANGUAGE_MAORI, wxe_util:get_const(wxLANGUAGE_MAORI)). +-define(wxLANGUAGE_MARATHI, wxe_util:get_const(wxLANGUAGE_MARATHI)). +-define(wxLANGUAGE_MOLDAVIAN, wxe_util:get_const(wxLANGUAGE_MOLDAVIAN)). +-define(wxLANGUAGE_MONGOLIAN, wxe_util:get_const(wxLANGUAGE_MONGOLIAN)). +-define(wxLANGUAGE_NAURU, wxe_util:get_const(wxLANGUAGE_NAURU)). +-define(wxLANGUAGE_NEPALI, wxe_util:get_const(wxLANGUAGE_NEPALI)). +-define(wxLANGUAGE_NEPALI_INDIA, wxe_util:get_const(wxLANGUAGE_NEPALI_INDIA)). +-define(wxLANGUAGE_NORWEGIAN_BOKMAL, wxe_util:get_const(wxLANGUAGE_NORWEGIAN_BOKMAL)). +-define(wxLANGUAGE_NORWEGIAN_NYNORSK, wxe_util:get_const(wxLANGUAGE_NORWEGIAN_NYNORSK)). +-define(wxLANGUAGE_OCCITAN, wxe_util:get_const(wxLANGUAGE_OCCITAN)). +-define(wxLANGUAGE_ORIYA, wxe_util:get_const(wxLANGUAGE_ORIYA)). +-define(wxLANGUAGE_OROMO, wxe_util:get_const(wxLANGUAGE_OROMO)). +-define(wxLANGUAGE_PASHTO, wxe_util:get_const(wxLANGUAGE_PASHTO)). +-define(wxLANGUAGE_POLISH, wxe_util:get_const(wxLANGUAGE_POLISH)). +-define(wxLANGUAGE_PORTUGUESE, wxe_util:get_const(wxLANGUAGE_PORTUGUESE)). +-define(wxLANGUAGE_PORTUGUESE_BRAZILIAN, wxe_util:get_const(wxLANGUAGE_PORTUGUESE_BRAZILIAN)). +-define(wxLANGUAGE_PUNJABI, wxe_util:get_const(wxLANGUAGE_PUNJABI)). +-define(wxLANGUAGE_QUECHUA, wxe_util:get_const(wxLANGUAGE_QUECHUA)). +-define(wxLANGUAGE_RHAETO_ROMANCE, wxe_util:get_const(wxLANGUAGE_RHAETO_ROMANCE)). +-define(wxLANGUAGE_ROMANIAN, wxe_util:get_const(wxLANGUAGE_ROMANIAN)). +-define(wxLANGUAGE_RUSSIAN, wxe_util:get_const(wxLANGUAGE_RUSSIAN)). +-define(wxLANGUAGE_RUSSIAN_UKRAINE, wxe_util:get_const(wxLANGUAGE_RUSSIAN_UKRAINE)). +-define(wxLANGUAGE_SAMOAN, wxe_util:get_const(wxLANGUAGE_SAMOAN)). +-define(wxLANGUAGE_SANGHO, wxe_util:get_const(wxLANGUAGE_SANGHO)). +-define(wxLANGUAGE_SANSKRIT, wxe_util:get_const(wxLANGUAGE_SANSKRIT)). +-define(wxLANGUAGE_SCOTS_GAELIC, wxe_util:get_const(wxLANGUAGE_SCOTS_GAELIC)). +-define(wxLANGUAGE_SERBIAN, wxe_util:get_const(wxLANGUAGE_SERBIAN)). +-define(wxLANGUAGE_SERBIAN_CYRILLIC, wxe_util:get_const(wxLANGUAGE_SERBIAN_CYRILLIC)). +-define(wxLANGUAGE_SERBIAN_LATIN, wxe_util:get_const(wxLANGUAGE_SERBIAN_LATIN)). +-define(wxLANGUAGE_SERBO_CROATIAN, wxe_util:get_const(wxLANGUAGE_SERBO_CROATIAN)). +-define(wxLANGUAGE_SESOTHO, wxe_util:get_const(wxLANGUAGE_SESOTHO)). +-define(wxLANGUAGE_SETSWANA, wxe_util:get_const(wxLANGUAGE_SETSWANA)). +-define(wxLANGUAGE_SHONA, wxe_util:get_const(wxLANGUAGE_SHONA)). +-define(wxLANGUAGE_SINDHI, wxe_util:get_const(wxLANGUAGE_SINDHI)). +-define(wxLANGUAGE_SINHALESE, wxe_util:get_const(wxLANGUAGE_SINHALESE)). +-define(wxLANGUAGE_SISWATI, wxe_util:get_const(wxLANGUAGE_SISWATI)). +-define(wxLANGUAGE_SLOVAK, wxe_util:get_const(wxLANGUAGE_SLOVAK)). +-define(wxLANGUAGE_SLOVENIAN, wxe_util:get_const(wxLANGUAGE_SLOVENIAN)). +-define(wxLANGUAGE_SOMALI, wxe_util:get_const(wxLANGUAGE_SOMALI)). +-define(wxLANGUAGE_SPANISH, wxe_util:get_const(wxLANGUAGE_SPANISH)). +-define(wxLANGUAGE_SPANISH_ARGENTINA, wxe_util:get_const(wxLANGUAGE_SPANISH_ARGENTINA)). +-define(wxLANGUAGE_SPANISH_BOLIVIA, wxe_util:get_const(wxLANGUAGE_SPANISH_BOLIVIA)). +-define(wxLANGUAGE_SPANISH_CHILE, wxe_util:get_const(wxLANGUAGE_SPANISH_CHILE)). +-define(wxLANGUAGE_SPANISH_COLOMBIA, wxe_util:get_const(wxLANGUAGE_SPANISH_COLOMBIA)). +-define(wxLANGUAGE_SPANISH_COSTA_RICA, wxe_util:get_const(wxLANGUAGE_SPANISH_COSTA_RICA)). +-define(wxLANGUAGE_SPANISH_DOMINICAN_REPUBLIC, wxe_util:get_const(wxLANGUAGE_SPANISH_DOMINICAN_REPUBLIC)). +-define(wxLANGUAGE_SPANISH_ECUADOR, wxe_util:get_const(wxLANGUAGE_SPANISH_ECUADOR)). +-define(wxLANGUAGE_SPANISH_EL_SALVADOR, wxe_util:get_const(wxLANGUAGE_SPANISH_EL_SALVADOR)). +-define(wxLANGUAGE_SPANISH_GUATEMALA, wxe_util:get_const(wxLANGUAGE_SPANISH_GUATEMALA)). +-define(wxLANGUAGE_SPANISH_HONDURAS, wxe_util:get_const(wxLANGUAGE_SPANISH_HONDURAS)). +-define(wxLANGUAGE_SPANISH_MEXICAN, wxe_util:get_const(wxLANGUAGE_SPANISH_MEXICAN)). +-define(wxLANGUAGE_SPANISH_MODERN, wxe_util:get_const(wxLANGUAGE_SPANISH_MODERN)). +-define(wxLANGUAGE_SPANISH_NICARAGUA, wxe_util:get_const(wxLANGUAGE_SPANISH_NICARAGUA)). +-define(wxLANGUAGE_SPANISH_PANAMA, wxe_util:get_const(wxLANGUAGE_SPANISH_PANAMA)). +-define(wxLANGUAGE_SPANISH_PARAGUAY, wxe_util:get_const(wxLANGUAGE_SPANISH_PARAGUAY)). +-define(wxLANGUAGE_SPANISH_PERU, wxe_util:get_const(wxLANGUAGE_SPANISH_PERU)). +-define(wxLANGUAGE_SPANISH_PUERTO_RICO, wxe_util:get_const(wxLANGUAGE_SPANISH_PUERTO_RICO)). +-define(wxLANGUAGE_SPANISH_URUGUAY, wxe_util:get_const(wxLANGUAGE_SPANISH_URUGUAY)). +-define(wxLANGUAGE_SPANISH_US, wxe_util:get_const(wxLANGUAGE_SPANISH_US)). +-define(wxLANGUAGE_SPANISH_VENEZUELA, wxe_util:get_const(wxLANGUAGE_SPANISH_VENEZUELA)). +-define(wxLANGUAGE_SUNDANESE, wxe_util:get_const(wxLANGUAGE_SUNDANESE)). +-define(wxLANGUAGE_SWAHILI, wxe_util:get_const(wxLANGUAGE_SWAHILI)). +-define(wxLANGUAGE_SWEDISH, wxe_util:get_const(wxLANGUAGE_SWEDISH)). +-define(wxLANGUAGE_SWEDISH_FINLAND, wxe_util:get_const(wxLANGUAGE_SWEDISH_FINLAND)). +-define(wxLANGUAGE_TAGALOG, wxe_util:get_const(wxLANGUAGE_TAGALOG)). +-define(wxLANGUAGE_TAJIK, wxe_util:get_const(wxLANGUAGE_TAJIK)). +-define(wxLANGUAGE_TAMIL, wxe_util:get_const(wxLANGUAGE_TAMIL)). +-define(wxLANGUAGE_TATAR, wxe_util:get_const(wxLANGUAGE_TATAR)). +-define(wxLANGUAGE_TELUGU, wxe_util:get_const(wxLANGUAGE_TELUGU)). +-define(wxLANGUAGE_THAI, wxe_util:get_const(wxLANGUAGE_THAI)). +-define(wxLANGUAGE_TIBETAN, wxe_util:get_const(wxLANGUAGE_TIBETAN)). +-define(wxLANGUAGE_TIGRINYA, wxe_util:get_const(wxLANGUAGE_TIGRINYA)). +-define(wxLANGUAGE_TONGA, wxe_util:get_const(wxLANGUAGE_TONGA)). +-define(wxLANGUAGE_TSONGA, wxe_util:get_const(wxLANGUAGE_TSONGA)). +-define(wxLANGUAGE_TURKISH, wxe_util:get_const(wxLANGUAGE_TURKISH)). +-define(wxLANGUAGE_TURKMEN, wxe_util:get_const(wxLANGUAGE_TURKMEN)). +-define(wxLANGUAGE_TWI, wxe_util:get_const(wxLANGUAGE_TWI)). +-define(wxLANGUAGE_UIGHUR, wxe_util:get_const(wxLANGUAGE_UIGHUR)). +-define(wxLANGUAGE_UKRAINIAN, wxe_util:get_const(wxLANGUAGE_UKRAINIAN)). +-define(wxLANGUAGE_URDU, wxe_util:get_const(wxLANGUAGE_URDU)). +-define(wxLANGUAGE_URDU_INDIA, wxe_util:get_const(wxLANGUAGE_URDU_INDIA)). +-define(wxLANGUAGE_URDU_PAKISTAN, wxe_util:get_const(wxLANGUAGE_URDU_PAKISTAN)). +-define(wxLANGUAGE_UZBEK, wxe_util:get_const(wxLANGUAGE_UZBEK)). +-define(wxLANGUAGE_UZBEK_CYRILLIC, wxe_util:get_const(wxLANGUAGE_UZBEK_CYRILLIC)). +-define(wxLANGUAGE_UZBEK_LATIN, wxe_util:get_const(wxLANGUAGE_UZBEK_LATIN)). +-define(wxLANGUAGE_VIETNAMESE, wxe_util:get_const(wxLANGUAGE_VIETNAMESE)). +-define(wxLANGUAGE_VOLAPUK, wxe_util:get_const(wxLANGUAGE_VOLAPUK)). +-define(wxLANGUAGE_WELSH, wxe_util:get_const(wxLANGUAGE_WELSH)). +-define(wxLANGUAGE_WOLOF, wxe_util:get_const(wxLANGUAGE_WOLOF)). +-define(wxLANGUAGE_XHOSA, wxe_util:get_const(wxLANGUAGE_XHOSA)). +-define(wxLANGUAGE_YIDDISH, wxe_util:get_const(wxLANGUAGE_YIDDISH)). +-define(wxLANGUAGE_YORUBA, wxe_util:get_const(wxLANGUAGE_YORUBA)). +-define(wxLANGUAGE_ZHUANG, wxe_util:get_const(wxLANGUAGE_ZHUANG)). +-define(wxLANGUAGE_ZULU, wxe_util:get_const(wxLANGUAGE_ZULU)). +-define(wxLANGUAGE_USER_DEFINED, wxe_util:get_const(wxLANGUAGE_USER_DEFINED)). +-define(wxLANGUAGE_VALENCIAN, wxe_util:get_const(wxLANGUAGE_VALENCIAN)). +-define(wxLANGUAGE_SAMI, wxe_util:get_const(wxLANGUAGE_SAMI)). % From "intl.h": wxLayoutDirection -define(wxLayout_Default, 0). -define(wxLayout_LeftToRight, 1). @@ -4081,7 +4085,3 @@ -define(wxWINDOW_VARIANT_MINI, 2). -define(wxWINDOW_VARIANT_LARGE, 3). -define(wxWINDOW_VARIANT_MAX, 4). -% From "xmlres.h": wxXmlResourceFlags --define(wxXRC_USE_LOCALE, 1). --define(wxXRC_NO_SUBCLASSING, 2). --define(wxXRC_NO_RELOADING, 4). diff --git a/lib/wx/src/gen/gl.erl b/lib/wx/src/gen/gl.erl index 58cdb59aa2..bedd4e9cca 100644 --- a/lib/wx/src/gen/gl.erl +++ b/lib/wx/src/gen/gl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2015. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -53,10 +53,14 @@ -type enum() :: non_neg_integer(). %% See wx/include/gl.hrl -type clamp() :: float(). %% 0.0..1.0 -type offset() :: non_neg_integer(). %% Offset in memory block --type matrix() :: {float(),float(),float(),float(), +-type matrix12() :: {float(),float(),float(),float(), + float(),float(),float(),float(), + float(),float(),float(),float()}. +-type matrix16() :: {float(),float(),float(),float(), float(),float(),float(),float(), float(),float(),float(),float(), float(),float(),float(),float()}. +-type matrix() :: matrix12() | matrix16(). -type mem() :: binary() | tuple(). %% Memory block -export([clearIndex/1,clearColor/4,clear/1,indexMask/1,colorMask/4,alphaFunc/2, @@ -4289,14 +4293,14 @@ lighti(Light,Pname,Param) -> %% @doc %% See {@link lightf/3} --spec lightfv(Light, Pname, Params) -> ok when Light :: enum(),Pname :: enum(),Params :: {float()}. +-spec lightfv(Light, Pname, Params) -> ok when Light :: enum(),Pname :: enum(),Params :: tuple(). lightfv(Light,Pname,Params) -> cast(5207, <<Light:?GLenum,Pname:?GLenum,(size(Params)):?GLuint, (<< <<C:?GLfloat>> ||C <- tuple_to_list(Params)>>)/binary,0:(((1+size(Params)) rem 2)*32)>>). %% @doc %% See {@link lightf/3} --spec lightiv(Light, Pname, Params) -> ok when Light :: enum(),Pname :: enum(),Params :: {integer()}. +-spec lightiv(Light, Pname, Params) -> ok when Light :: enum(),Pname :: enum(),Params :: tuple(). lightiv(Light,Pname,Params) -> cast(5208, <<Light:?GLenum,Pname:?GLenum,(size(Params)):?GLuint, (<< <<C:?GLint>> ||C <- tuple_to_list(Params)>>)/binary,0:(((1+size(Params)) rem 2)*32)>>). @@ -4460,14 +4464,14 @@ lightModeli(Pname,Param) -> %% @doc %% See {@link lightModelf/2} --spec lightModelfv(Pname, Params) -> ok when Pname :: enum(),Params :: {float()}. +-spec lightModelfv(Pname, Params) -> ok when Pname :: enum(),Params :: tuple(). lightModelfv(Pname,Params) -> cast(5213, <<Pname:?GLenum,(size(Params)):?GLuint, (<< <<C:?GLfloat>> ||C <- tuple_to_list(Params)>>)/binary,0:(((0+size(Params)) rem 2)*32)>>). %% @doc %% See {@link lightModelf/2} --spec lightModeliv(Pname, Params) -> ok when Pname :: enum(),Params :: {integer()}. +-spec lightModeliv(Pname, Params) -> ok when Pname :: enum(),Params :: tuple(). lightModeliv(Pname,Params) -> cast(5214, <<Pname:?GLenum,(size(Params)):?GLuint, (<< <<C:?GLint>> ||C <- tuple_to_list(Params)>>)/binary,0:(((0+size(Params)) rem 2)*32)>>). @@ -4547,14 +4551,14 @@ materiali(Face,Pname,Param) -> %% @doc %% See {@link materialf/3} --spec materialfv(Face, Pname, Params) -> ok when Face :: enum(),Pname :: enum(),Params :: {float()}. +-spec materialfv(Face, Pname, Params) -> ok when Face :: enum(),Pname :: enum(),Params :: tuple(). materialfv(Face,Pname,Params) -> cast(5217, <<Face:?GLenum,Pname:?GLenum,(size(Params)):?GLuint, (<< <<C:?GLfloat>> ||C <- tuple_to_list(Params)>>)/binary,0:(((1+size(Params)) rem 2)*32)>>). %% @doc %% See {@link materialf/3} --spec materialiv(Face, Pname, Params) -> ok when Face :: enum(),Pname :: enum(),Params :: {integer()}. +-spec materialiv(Face, Pname, Params) -> ok when Face :: enum(),Pname :: enum(),Params :: tuple(). materialiv(Face,Pname,Params) -> cast(5218, <<Face:?GLenum,Pname:?GLenum,(size(Params)):?GLuint, (<< <<C:?GLint>> ||C <- tuple_to_list(Params)>>)/binary,0:(((1+size(Params)) rem 2)*32)>>). @@ -5890,21 +5894,21 @@ texGeni(Coord,Pname,Param) -> %% @doc %% See {@link texGend/3} --spec texGendv(Coord, Pname, Params) -> ok when Coord :: enum(),Pname :: enum(),Params :: {float()}. +-spec texGendv(Coord, Pname, Params) -> ok when Coord :: enum(),Pname :: enum(),Params :: tuple(). texGendv(Coord,Pname,Params) -> cast(5246, <<Coord:?GLenum,Pname:?GLenum,(size(Params)):?GLuint,0:32, (<< <<C:?GLdouble>> ||C <- tuple_to_list(Params)>>)/binary>>). %% @doc %% See {@link texGend/3} --spec texGenfv(Coord, Pname, Params) -> ok when Coord :: enum(),Pname :: enum(),Params :: {float()}. +-spec texGenfv(Coord, Pname, Params) -> ok when Coord :: enum(),Pname :: enum(),Params :: tuple(). texGenfv(Coord,Pname,Params) -> cast(5247, <<Coord:?GLenum,Pname:?GLenum,(size(Params)):?GLuint, (<< <<C:?GLfloat>> ||C <- tuple_to_list(Params)>>)/binary,0:(((1+size(Params)) rem 2)*32)>>). %% @doc %% See {@link texGend/3} --spec texGeniv(Coord, Pname, Params) -> ok when Coord :: enum(),Pname :: enum(),Params :: {integer()}. +-spec texGeniv(Coord, Pname, Params) -> ok when Coord :: enum(),Pname :: enum(),Params :: tuple(). texGeniv(Coord,Pname,Params) -> cast(5248, <<Coord:?GLenum,Pname:?GLenum,(size(Params)):?GLuint, (<< <<C:?GLint>> ||C <- tuple_to_list(Params)>>)/binary,0:(((1+size(Params)) rem 2)*32)>>). @@ -6123,14 +6127,14 @@ texEnvi(Target,Pname,Param) -> %% replacement. The default value is `?GL_FALSE'. %% %% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glTexEnv.xml">external</a> documentation. --spec texEnvfv(Target, Pname, Params) -> ok when Target :: enum(),Pname :: enum(),Params :: {float()}. +-spec texEnvfv(Target, Pname, Params) -> ok when Target :: enum(),Pname :: enum(),Params :: tuple(). texEnvfv(Target,Pname,Params) -> cast(5254, <<Target:?GLenum,Pname:?GLenum,(size(Params)):?GLuint, (<< <<C:?GLfloat>> ||C <- tuple_to_list(Params)>>)/binary,0:(((1+size(Params)) rem 2)*32)>>). %% @doc %% See {@link texEnvfv/3} --spec texEnviv(Target, Pname, Params) -> ok when Target :: enum(),Pname :: enum(),Params :: {integer()}. +-spec texEnviv(Target, Pname, Params) -> ok when Target :: enum(),Pname :: enum(),Params :: tuple(). texEnviv(Target,Pname,Params) -> cast(5255, <<Target:?GLenum,Pname:?GLenum,(size(Params)):?GLuint, (<< <<C:?GLint>> ||C <- tuple_to_list(Params)>>)/binary,0:(((1+size(Params)) rem 2)*32)>>). @@ -6455,14 +6459,14 @@ texParameteri(Target,Pname,Param) -> %% @doc %% See {@link texParameterf/3} --spec texParameterfv(Target, Pname, Params) -> ok when Target :: enum(),Pname :: enum(),Params :: {float()}. +-spec texParameterfv(Target, Pname, Params) -> ok when Target :: enum(),Pname :: enum(),Params :: tuple(). texParameterfv(Target,Pname,Params) -> cast(5260, <<Target:?GLenum,Pname:?GLenum,(size(Params)):?GLuint, (<< <<C:?GLfloat>> ||C <- tuple_to_list(Params)>>)/binary,0:(((1+size(Params)) rem 2)*32)>>). %% @doc %% See {@link texParameterf/3} --spec texParameteriv(Target, Pname, Params) -> ok when Target :: enum(),Pname :: enum(),Params :: {integer()}. +-spec texParameteriv(Target, Pname, Params) -> ok when Target :: enum(),Pname :: enum(),Params :: tuple(). texParameteriv(Target,Pname,Params) -> cast(5261, <<Target:?GLenum,Pname:?GLenum,(size(Params)):?GLuint, (<< <<C:?GLint>> ||C <- tuple_to_list(Params)>>)/binary,0:(((1+size(Params)) rem 2)*32)>>). @@ -7609,14 +7613,14 @@ fogi(Pname,Param) -> %% @doc %% See {@link fogf/2} --spec fogfv(Pname, Params) -> ok when Pname :: enum(),Params :: {float()}. +-spec fogfv(Pname, Params) -> ok when Pname :: enum(),Params :: tuple(). fogfv(Pname,Params) -> cast(5306, <<Pname:?GLenum,(size(Params)):?GLuint, (<< <<C:?GLfloat>> ||C <- tuple_to_list(Params)>>)/binary,0:(((0+size(Params)) rem 2)*32)>>). %% @doc %% See {@link fogf/2} --spec fogiv(Pname, Params) -> ok when Pname :: enum(),Params :: {integer()}. +-spec fogiv(Pname, Params) -> ok when Pname :: enum(),Params :: tuple(). fogiv(Pname,Params) -> cast(5307, <<Pname:?GLenum,(size(Params)):?GLuint, (<< <<C:?GLint>> ||C <- tuple_to_list(Params)>>)/binary,0:(((0+size(Params)) rem 2)*32)>>). @@ -8522,24 +8526,24 @@ convolutionFilter2D(Target,Internalformat,Width,Height,Format,Type,Image) -> %% image were replicated. %% %% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glConvolutionParameter.xml">external</a> documentation. --spec convolutionParameterf(Target, Pname, Params) -> ok when Target :: enum(),Pname :: enum(),Params :: {float()}. +-spec convolutionParameterf(Target, Pname, Params) -> ok when Target :: enum(),Pname :: enum(),Params :: tuple(). convolutionParameterf(Target,Pname,Params) -> cast(5339, <<Target:?GLenum,Pname:?GLenum,(size(Params)):?GLuint, (<< <<C:?GLfloat>> ||C <- tuple_to_list(Params)>>)/binary,0:(((1+size(Params)) rem 2)*32)>>). %% @equiv convolutionParameterf(Target,Pname,Params) --spec convolutionParameterfv(Target :: enum(),Pname :: enum(),Params) -> ok when Params :: {Params :: {float()}}. +-spec convolutionParameterfv(Target :: enum(),Pname :: enum(),Params) -> ok when Params :: {Params :: tuple()}. convolutionParameterfv(Target,Pname,{Params}) -> convolutionParameterf(Target,Pname,Params). %% @doc %% See {@link convolutionParameterf/3} --spec convolutionParameteri(Target, Pname, Params) -> ok when Target :: enum(),Pname :: enum(),Params :: {integer()}. +-spec convolutionParameteri(Target, Pname, Params) -> ok when Target :: enum(),Pname :: enum(),Params :: tuple(). convolutionParameteri(Target,Pname,Params) -> cast(5340, <<Target:?GLenum,Pname:?GLenum,(size(Params)):?GLuint, (<< <<C:?GLint>> ||C <- tuple_to_list(Params)>>)/binary,0:(((1+size(Params)) rem 2)*32)>>). %% @equiv convolutionParameteri(Target,Pname,Params) --spec convolutionParameteriv(Target :: enum(),Pname :: enum(),Params) -> ok when Params :: {Params :: {integer()}}. +-spec convolutionParameteriv(Target :: enum(),Pname :: enum(),Params) -> ok when Params :: {Params :: tuple()}. convolutionParameteriv(Target,Pname,{Params}) -> convolutionParameteri(Target,Pname,Params). %% @doc Copy pixels into a one-dimensional convolution filter @@ -9671,7 +9675,7 @@ pointParameterf(Pname,Param) -> %% @doc %% See {@link pointParameterf/2} --spec pointParameterfv(Pname, Params) -> ok when Pname :: enum(),Params :: {float()}. +-spec pointParameterfv(Pname, Params) -> ok when Pname :: enum(),Params :: tuple(). pointParameterfv(Pname,Params) -> cast(5397, <<Pname:?GLenum,(size(Params)):?GLuint, (<< <<C:?GLfloat>> ||C <- tuple_to_list(Params)>>)/binary,0:(((0+size(Params)) rem 2)*32)>>). @@ -9684,7 +9688,7 @@ pointParameteri(Pname,Param) -> %% @doc %% See {@link pointParameterf/2} --spec pointParameteriv(Pname, Params) -> ok when Pname :: enum(),Params :: {integer()}. +-spec pointParameteriv(Pname, Params) -> ok when Pname :: enum(),Params :: tuple(). pointParameteriv(Pname,Params) -> cast(5399, <<Pname:?GLenum,(size(Params)):?GLuint, (<< <<C:?GLint>> ||C <- tuple_to_list(Params)>>)/binary,0:(((0+size(Params)) rem 2)*32)>>). @@ -11529,7 +11533,7 @@ linkProgram(Program) -> %% scanned or parsed at this time; they are simply copied into the specified shader object. %% %% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glShaderSource.xml">external</a> documentation. --spec shaderSource(Shader, String) -> ok when Shader :: integer(),String :: [string()]. +-spec shaderSource(Shader, String) -> ok when Shader :: integer(),String :: iolist(). shaderSource(Shader,String) -> StringTemp = list_to_binary([[Str|[0]] || Str <- String ]), cast(5473, <<Shader:?GLuint,(length(String)):?GLuint,(size(StringTemp)):?GLuint,(StringTemp)/binary,0:((8-((size(StringTemp)+0) rem 8)) rem 8)>>). @@ -12278,7 +12282,7 @@ bindBufferBase(Target,Index,Buffer) -> %% and the buffer mode is `?GL_INTERLEAVED_ATTRIBS'. %% %% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glTransformFeedbackVaryings.xml">external</a> documentation. --spec transformFeedbackVaryings(Program, Varyings, BufferMode) -> ok when Program :: integer(),Varyings :: [string()],BufferMode :: enum(). +-spec transformFeedbackVaryings(Program, Varyings, BufferMode) -> ok when Program :: integer(),Varyings :: iolist(),BufferMode :: enum(). transformFeedbackVaryings(Program,Varyings,BufferMode) -> VaryingsTemp = list_to_binary([[Str|[0]] || Str <- Varyings ]), cast(5536, <<Program:?GLuint,(length(Varyings)):?GLuint,(size(VaryingsTemp)):?GLuint,(VaryingsTemp)/binary,0:((8-((size(VaryingsTemp)+0) rem 8)) rem 8),BufferMode:?GLenum>>). @@ -12596,7 +12600,7 @@ uniform4uiv(Location,Value) -> %% @doc %% See {@link texParameterf/3} --spec texParameterIiv(Target, Pname, Params) -> ok when Target :: enum(),Pname :: enum(),Params :: {integer()}. +-spec texParameterIiv(Target, Pname, Params) -> ok when Target :: enum(),Pname :: enum(),Params :: tuple(). texParameterIiv(Target,Pname,Params) -> cast(5568, <<Target:?GLenum,Pname:?GLenum,(size(Params)):?GLuint, (<< <<C:?GLint>> ||C <- tuple_to_list(Params)>>)/binary,0:(((1+size(Params)) rem 2)*32)>>). @@ -12604,7 +12608,7 @@ texParameterIiv(Target,Pname,Params) -> %% @doc glTexParameterI %% %% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glTexParameterI.xml">external</a> documentation. --spec texParameterIuiv(Target, Pname, Params) -> ok when Target :: enum(),Pname :: enum(),Params :: {integer()}. +-spec texParameterIuiv(Target, Pname, Params) -> ok when Target :: enum(),Pname :: enum(),Params :: tuple(). texParameterIuiv(Target,Pname,Params) -> cast(5569, <<Target:?GLenum,Pname:?GLenum,(size(Params)):?GLuint, (<< <<C:?GLuint>> ||C <- tuple_to_list(Params)>>)/binary,0:(((1+size(Params)) rem 2)*32)>>). @@ -12651,21 +12655,21 @@ getTexParameterIuiv(Target,Pname) -> %% and the buffer being cleared is defined. However, this is not an error. %% %% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glClearBuffer.xml">external</a> documentation. --spec clearBufferiv(Buffer, Drawbuffer, Value) -> ok when Buffer :: enum(),Drawbuffer :: integer(),Value :: {integer()}. +-spec clearBufferiv(Buffer, Drawbuffer, Value) -> ok when Buffer :: enum(),Drawbuffer :: integer(),Value :: tuple(). clearBufferiv(Buffer,Drawbuffer,Value) -> cast(5572, <<Buffer:?GLenum,Drawbuffer:?GLint,(size(Value)):?GLuint, (<< <<C:?GLint>> ||C <- tuple_to_list(Value)>>)/binary,0:(((1+size(Value)) rem 2)*32)>>). %% @doc %% See {@link clearBufferiv/3} --spec clearBufferuiv(Buffer, Drawbuffer, Value) -> ok when Buffer :: enum(),Drawbuffer :: integer(),Value :: {integer()}. +-spec clearBufferuiv(Buffer, Drawbuffer, Value) -> ok when Buffer :: enum(),Drawbuffer :: integer(),Value :: tuple(). clearBufferuiv(Buffer,Drawbuffer,Value) -> cast(5573, <<Buffer:?GLenum,Drawbuffer:?GLint,(size(Value)):?GLuint, (<< <<C:?GLuint>> ||C <- tuple_to_list(Value)>>)/binary,0:(((1+size(Value)) rem 2)*32)>>). %% @doc %% See {@link clearBufferiv/3} --spec clearBufferfv(Buffer, Drawbuffer, Value) -> ok when Buffer :: enum(),Drawbuffer :: integer(),Value :: {float()}. +-spec clearBufferfv(Buffer, Drawbuffer, Value) -> ok when Buffer :: enum(),Drawbuffer :: integer(),Value :: tuple(). clearBufferfv(Buffer,Drawbuffer,Value) -> cast(5574, <<Buffer:?GLenum,Drawbuffer:?GLint,(size(Value)):?GLuint, (<< <<C:?GLfloat>> ||C <- tuple_to_list(Value)>>)/binary,0:(((1+size(Value)) rem 2)*32)>>). @@ -13219,7 +13223,7 @@ createShaderObjectARB(ShaderType) -> %% @doc glShaderSourceARB %% %% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glShaderSourceARB.xml">external</a> documentation. --spec shaderSourceARB(ShaderObj, String) -> ok when ShaderObj :: integer(),String :: [string()]. +-spec shaderSourceARB(ShaderObj, String) -> ok when ShaderObj :: integer(),String :: iolist(). shaderSourceARB(ShaderObj,String) -> StringTemp = list_to_binary([[Str|[0]] || Str <- String ]), cast(5630, <<ShaderObj:?GLhandleARB,(length(String)):?GLuint,(size(StringTemp)):?GLuint,(StringTemp)/binary,0:((8-((size(StringTemp)+4) rem 8)) rem 8)>>). @@ -13927,7 +13931,7 @@ isVertexArray(Array) -> %% If an error occurs, nothing is written to `UniformIndices' . %% %% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetUniformIndices.xml">external</a> documentation. --spec getUniformIndices(Program, UniformNames) -> [integer()] when Program :: integer(),UniformNames :: [string()]. +-spec getUniformIndices(Program, UniformNames) -> [integer()] when Program :: integer(),UniformNames :: iolist(). getUniformIndices(Program,UniformNames) -> UniformNamesTemp = list_to_binary([[Str|[0]] || Str <- UniformNames ]), call(5675, <<Program:?GLuint,(length(UniformNames)):?GLuint,(size(UniformNamesTemp)):?GLuint,(UniformNamesTemp)/binary,0:((8-((size(UniformNamesTemp)+0) rem 8)) rem 8)>>). @@ -14458,7 +14462,7 @@ deleteNamedStringARB(Name) -> %% @doc glCompileShaderIncludeARB %% %% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glCompileShaderIncludeARB.xml">external</a> documentation. --spec compileShaderIncludeARB(Shader, Path) -> ok when Shader :: integer(),Path :: [string()]. +-spec compileShaderIncludeARB(Shader, Path) -> ok when Shader :: integer(),Path :: iolist(). compileShaderIncludeARB(Shader,Path) -> PathTemp = list_to_binary([[Str|[0]] || Str <- Path ]), cast(5703, <<Shader:?GLuint,(length(Path)):?GLuint,(size(PathTemp)):?GLuint,(PathTemp)/binary,0:((8-((size(PathTemp)+0) rem 8)) rem 8)>>). @@ -15617,7 +15621,7 @@ activeShaderProgram(Pipeline,Program) -> %% @doc glCreateShaderProgramv %% %% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glCreateShaderProgramv.xml">external</a> documentation. --spec createShaderProgramv(Type, Strings) -> integer() when Type :: enum(),Strings :: [string()]. +-spec createShaderProgramv(Type, Strings) -> integer() when Type :: enum(),Strings :: iolist(). createShaderProgramv(Type,Strings) -> StringsTemp = list_to_binary([[Str|[0]] || Str <- Strings ]), call(5778, <<Type:?GLenum,(length(Strings)):?GLuint,(size(StringsTemp)):?GLuint,(StringsTemp)/binary,0:((8-((size(StringsTemp)+0) rem 8)) rem 8)>>). diff --git a/lib/wx/src/gen/glu.erl b/lib/wx/src/gen/glu.erl index 6a6e20b3e4..5faba48930 100644 --- a/lib/wx/src/gen/glu.erl +++ b/lib/wx/src/gen/glu.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2015. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -51,10 +51,14 @@ -define(GLint64,64/native-signed). -type vertex() :: {float(), float(), float()}. -type enum() :: non_neg_integer(). %% See wx/include/gl.hrl or glu.hrl --type matrix() :: {float(),float(),float(),float(), +-type matrix12() :: {float(),float(),float(),float(), + float(),float(),float(),float(), + float(),float(),float(),float()}. +-type matrix16() :: {float(),float(),float(),float(), float(),float(),float(),float(), float(),float(),float(),float(), float(),float(),float(),float()}. +-type matrix() :: matrix12() | matrix16(). -type mem() :: binary() | tuple(). %% Memory block -export([tesselate/2,build1DMipmapLevels/9,build1DMipmaps/6,build2DMipmapLevels/10, diff --git a/lib/wx/src/gen/wxAuiDockArt.erl b/lib/wx/src/gen/wxAuiDockArt.erl index 499fbd9a23..4149b1d424 100644 --- a/lib/wx/src/gen/wxAuiDockArt.erl +++ b/lib/wx/src/gen/wxAuiDockArt.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2015. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -25,7 +25,7 @@ -module(wxAuiDockArt). -include("wxe.hrl"). --export([]). +-export([getColour/2,getFont/2,getMetric/2,setColour/3,setFont/3,setMetric/3]). %% inherited exports -export([parent_class/1]). @@ -35,3 +35,58 @@ parent_class(_Class) -> erlang:error({badtype, ?MODULE}). -type wxAuiDockArt() :: wx:wx_object(). +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxauidockart.html#wxauidockartgetcolour">external documentation</a>. +-spec getColour(This, Id) -> wx:wx_colour4() when + This::wxAuiDockArt(), Id::integer(). +getColour(#wx_ref{type=ThisT,ref=ThisRef},Id) + when is_integer(Id) -> + ?CLASS(ThisT,wxAuiDockArt), + wxe_util:call(?wxAuiDockArt_GetColour, + <<ThisRef:32/?UI,Id:32/?UI>>). + +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxauidockart.html#wxauidockartgetfont">external documentation</a>. +-spec getFont(This, Id) -> wxFont:wxFont() when + This::wxAuiDockArt(), Id::integer(). +getFont(#wx_ref{type=ThisT,ref=ThisRef},Id) + when is_integer(Id) -> + ?CLASS(ThisT,wxAuiDockArt), + wxe_util:call(?wxAuiDockArt_GetFont, + <<ThisRef:32/?UI,Id:32/?UI>>). + +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxauidockart.html#wxauidockartgetmetric">external documentation</a>. +-spec getMetric(This, Id) -> integer() when + This::wxAuiDockArt(), Id::integer(). +getMetric(#wx_ref{type=ThisT,ref=ThisRef},Id) + when is_integer(Id) -> + ?CLASS(ThisT,wxAuiDockArt), + wxe_util:call(?wxAuiDockArt_GetMetric, + <<ThisRef:32/?UI,Id:32/?UI>>). + +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxauidockart.html#wxauidockartsetcolour">external documentation</a>. +-spec setColour(This, Id, Colour) -> ok when + This::wxAuiDockArt(), Id::integer(), Colour::wx:wx_colour(). +setColour(#wx_ref{type=ThisT,ref=ThisRef},Id,Colour) + when is_integer(Id),tuple_size(Colour) =:= 3; tuple_size(Colour) =:= 4 -> + ?CLASS(ThisT,wxAuiDockArt), + wxe_util:cast(?wxAuiDockArt_SetColour, + <<ThisRef:32/?UI,Id:32/?UI,(wxe_util:colour_bin(Colour)):16/binary>>). + +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxauidockart.html#wxauidockartsetfont">external documentation</a>. +-spec setFont(This, Id, Font) -> ok when + This::wxAuiDockArt(), Id::integer(), Font::wxFont:wxFont(). +setFont(#wx_ref{type=ThisT,ref=ThisRef},Id,#wx_ref{type=FontT,ref=FontRef}) + when is_integer(Id) -> + ?CLASS(ThisT,wxAuiDockArt), + ?CLASS(FontT,wxFont), + wxe_util:cast(?wxAuiDockArt_SetFont, + <<ThisRef:32/?UI,Id:32/?UI,FontRef:32/?UI>>). + +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxauidockart.html#wxauidockartsetmetric">external documentation</a>. +-spec setMetric(This, Id, New_val) -> ok when + This::wxAuiDockArt(), Id::integer(), New_val::integer(). +setMetric(#wx_ref{type=ThisT,ref=ThisRef},Id,New_val) + when is_integer(Id),is_integer(New_val) -> + ?CLASS(ThisT,wxAuiDockArt), + wxe_util:cast(?wxAuiDockArt_SetMetric, + <<ThisRef:32/?UI,Id:32/?UI,New_val:32/?UI>>). + diff --git a/lib/wx/src/gen/wxAuiManager.erl b/lib/wx/src/gen/wxAuiManager.erl index 5a945f59e8..bf22e3091d 100644 --- a/lib/wx/src/gen/wxAuiManager.erl +++ b/lib/wx/src/gen/wxAuiManager.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2015. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -120,7 +120,7 @@ detachPane(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowRef}) <<ThisRef:32/?UI,WindowRef:32/?UI>>). %% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxauimanager.html#wxauimanagergetallpanes">external documentation</a>. --spec getAllPanes(This) -> wx:wx_object() when +-spec getAllPanes(This) -> [wxAuiPaneInfo:wxAuiPaneInfo()] when This::wxAuiManager(). getAllPanes(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxAuiManager), diff --git a/lib/wx/src/gen/wxAuiManagerEvent.erl b/lib/wx/src/gen/wxAuiManagerEvent.erl index 51ad211e10..88e4433f24 100644 --- a/lib/wx/src/gen/wxAuiManagerEvent.erl +++ b/lib/wx/src/gen/wxAuiManagerEvent.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2013. All Rights Reserved. +%% Copyright Ericsson AB 2009-2015. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ %% @doc See external documentation: <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxauimanagerevent.html">wxAuiManagerEvent</a>. %% <dl><dt>Use {@link wxEvtHandler:connect/3.} with EventType:</dt> -%% <dd><em>aui_pane_button</em>, <em>aui_pane_close</em>, <em>aui_pane_maximize</em>, <em>aui_pane_restore</em>, <em>aui_render</em>, <em>aui_find_manager</em></dd></dl> +%% <dd><em>aui_pane_button</em>, <em>aui_pane_close</em>, <em>aui_pane_maximize</em>, <em>aui_pane_restore</em>, <em>aui_pane_activated</em>, <em>aui_render</em>, <em>aui_find_manager</em></dd></dl> %% See also the message variant {@link wxEvtHandler:wxAuiManager(). #wxAuiManager{}} event record type. %% %% <p>This class is derived (and can use functions) from: diff --git a/lib/wx/src/gen/wxAuiNotebook.erl b/lib/wx/src/gen/wxAuiNotebook.erl index f66048f0d3..7ec1acb26d 100644 --- a/lib/wx/src/gen/wxAuiNotebook.erl +++ b/lib/wx/src/gen/wxAuiNotebook.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -37,10 +37,10 @@ setTabCtrlHeight/2,setUniformBitmapSize/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -52,23 +52,24 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setForegroundColour/2, setHelpText/2,setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2, setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,setPalette/2, setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,setSize/2, setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4, setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2, - setToolTip/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2, + setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2, setVirtualSizeHints/3,setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2, setWindowVariant/2,shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1, transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2, @@ -349,6 +350,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxAuiPaneInfo.erl b/lib/wx/src/gen/wxAuiPaneInfo.erl index 2b31df09fe..1f15e9cd39 100644 --- a/lib/wx/src/gen/wxAuiPaneInfo.erl +++ b/lib/wx/src/gen/wxAuiPaneInfo.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2015. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -30,17 +30,19 @@ closeButton/2,defaultPane/1,destroy/1,destroyOnClose/1,destroyOnClose/2, direction/2,dock/1,dockable/1,dockable/2,fixed/1,float/1,floatable/1, floatable/2,floatingPosition/2,floatingPosition/3,floatingSize/2, - floatingSize/3,gripper/1,gripper/2,gripperTop/1,gripperTop/2,hasBorder/1, - hasCaption/1,hasCloseButton/1,hasFlag/2,hasGripper/1,hasGripperTop/1, - hasMaximizeButton/1,hasMinimizeButton/1,hasPinButton/1,hide/1,isBottomDockable/1, - isDocked/1,isFixed/1,isFloatable/1,isFloating/1,isLeftDockable/1,isMovable/1, - isOk/1,isResizable/1,isRightDockable/1,isShown/1,isToolbar/1,isTopDockable/1, - layer/2,left/1,leftDockable/1,leftDockable/2,maxSize/2,maxSize/3,maximizeButton/1, - maximizeButton/2,minSize/2,minSize/3,minimizeButton/1,minimizeButton/2, - movable/1,movable/2,name/2,new/0,new/1,paneBorder/1,paneBorder/2,pinButton/1, - pinButton/2,position/2,resizable/1,resizable/2,right/1,rightDockable/1, - rightDockable/2,row/2,safeSet/2,setFlag/3,show/1,show/2,toolbarPane/1, - top/1,topDockable/1,topDockable/2,window/2]). + floatingSize/3,getDirection/1,getFloatingPosition/1,getFloatingSize/1, + getFrame/1,getLayer/1,getPosition/1,getRow/1,getWindow/1,gripper/1, + gripper/2,gripperTop/1,gripperTop/2,hasBorder/1,hasCaption/1,hasCloseButton/1, + hasFlag/2,hasGripper/1,hasGripperTop/1,hasMaximizeButton/1,hasMinimizeButton/1, + hasPinButton/1,hide/1,isBottomDockable/1,isDocked/1,isFixed/1,isFloatable/1, + isFloating/1,isLeftDockable/1,isMovable/1,isOk/1,isResizable/1,isRightDockable/1, + isShown/1,isToolbar/1,isTopDockable/1,layer/2,left/1,leftDockable/1, + leftDockable/2,maxSize/2,maxSize/3,maximizeButton/1,maximizeButton/2, + minSize/2,minSize/3,minimizeButton/1,minimizeButton/2,movable/1,movable/2, + name/2,new/0,new/1,paneBorder/1,paneBorder/2,pinButton/1,pinButton/2, + position/2,resizable/1,resizable/2,right/1,rightDockable/1,rightDockable/2, + row/2,safeSet/2,setFlag/3,show/1,show/2,toolbarPane/1,top/1,topDockable/1, + topDockable/2,window/2]). %% inherited exports -export([parent_class/1]). @@ -888,6 +890,70 @@ window(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WT,ref=WRef}) -> wxe_util:call(?wxAuiPaneInfo_Window, <<ThisRef:32/?UI,WRef:32/?UI>>). +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxauipaneinfo.html#wxauipaneinfogetwindow">external documentation</a>. +-spec getWindow(This) -> wxWindow:wxWindow() when + This::wxAuiPaneInfo(). +getWindow(#wx_ref{type=ThisT,ref=ThisRef}) -> + ?CLASS(ThisT,wxAuiPaneInfo), + wxe_util:call(?wxAuiPaneInfo_GetWindow, + <<ThisRef:32/?UI>>). + +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxauipaneinfo.html#wxauipaneinfogetframe">external documentation</a>. +-spec getFrame(This) -> wxFrame:wxFrame() when + This::wxAuiPaneInfo(). +getFrame(#wx_ref{type=ThisT,ref=ThisRef}) -> + ?CLASS(ThisT,wxAuiPaneInfo), + wxe_util:call(?wxAuiPaneInfo_GetFrame, + <<ThisRef:32/?UI>>). + +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxauipaneinfo.html#wxauipaneinfogetdirection">external documentation</a>. +-spec getDirection(This) -> integer() when + This::wxAuiPaneInfo(). +getDirection(#wx_ref{type=ThisT,ref=ThisRef}) -> + ?CLASS(ThisT,wxAuiPaneInfo), + wxe_util:call(?wxAuiPaneInfo_GetDirection, + <<ThisRef:32/?UI>>). + +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxauipaneinfo.html#wxauipaneinfogetlayer">external documentation</a>. +-spec getLayer(This) -> integer() when + This::wxAuiPaneInfo(). +getLayer(#wx_ref{type=ThisT,ref=ThisRef}) -> + ?CLASS(ThisT,wxAuiPaneInfo), + wxe_util:call(?wxAuiPaneInfo_GetLayer, + <<ThisRef:32/?UI>>). + +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxauipaneinfo.html#wxauipaneinfogetrow">external documentation</a>. +-spec getRow(This) -> integer() when + This::wxAuiPaneInfo(). +getRow(#wx_ref{type=ThisT,ref=ThisRef}) -> + ?CLASS(ThisT,wxAuiPaneInfo), + wxe_util:call(?wxAuiPaneInfo_GetRow, + <<ThisRef:32/?UI>>). + +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxauipaneinfo.html#wxauipaneinfogetposition">external documentation</a>. +-spec getPosition(This) -> integer() when + This::wxAuiPaneInfo(). +getPosition(#wx_ref{type=ThisT,ref=ThisRef}) -> + ?CLASS(ThisT,wxAuiPaneInfo), + wxe_util:call(?wxAuiPaneInfo_GetPosition, + <<ThisRef:32/?UI>>). + +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxauipaneinfo.html#wxauipaneinfogetfloatingposition">external documentation</a>. +-spec getFloatingPosition(This) -> {X::integer(), Y::integer()} when + This::wxAuiPaneInfo(). +getFloatingPosition(#wx_ref{type=ThisT,ref=ThisRef}) -> + ?CLASS(ThisT,wxAuiPaneInfo), + wxe_util:call(?wxAuiPaneInfo_GetFloatingPosition, + <<ThisRef:32/?UI>>). + +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxauipaneinfo.html#wxauipaneinfogetfloatingsize">external documentation</a>. +-spec getFloatingSize(This) -> {W::integer(), H::integer()} when + This::wxAuiPaneInfo(). +getFloatingSize(#wx_ref{type=ThisT,ref=ThisRef}) -> + ?CLASS(ThisT,wxAuiPaneInfo), + wxe_util:call(?wxAuiPaneInfo_GetFloatingSize, + <<ThisRef:32/?UI>>). + %% @doc Destroys this object, do not use object again -spec destroy(This::wxAuiPaneInfo()) -> ok. destroy(Obj=#wx_ref{type=Type}) -> diff --git a/lib/wx/src/gen/wxAuiSimpleTabArt.erl b/lib/wx/src/gen/wxAuiSimpleTabArt.erl new file mode 100644 index 0000000000..57d12e2eb4 --- /dev/null +++ b/lib/wx/src/gen/wxAuiSimpleTabArt.erl @@ -0,0 +1,67 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2015. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% This file is generated DO NOT EDIT + +%% @doc See external documentation: <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxauisimpletabart.html">wxAuiSimpleTabArt</a>. +%% <p>This class is derived (and can use functions) from: +%% <br />{@link wxAuiTabArt} +%% </p> +%% @type wxAuiSimpleTabArt(). 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(wxAuiSimpleTabArt). +-include("wxe.hrl"). +-export([destroy/1,new/0]). + +%% inherited exports +-export([parent_class/1,setActiveColour/2,setColour/2,setFlags/2,setMeasuringFont/2, + setNormalFont/2,setSelectedFont/2]). + +-export_type([wxAuiSimpleTabArt/0]). +%% @hidden +parent_class(wxAuiTabArt) -> true; +parent_class(_Class) -> erlang:error({badtype, ?MODULE}). + +-type wxAuiSimpleTabArt() :: wx:wx_object(). +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxauisimpletabart.html#wxauisimpletabartwxauisimpletabart">external documentation</a>. +-spec new() -> wxAuiSimpleTabArt(). +new() -> + wxe_util:construct(?wxAuiSimpleTabArt_new, + <<>>). + +%% @doc Destroys this object, do not use object again +-spec destroy(This::wxAuiSimpleTabArt()) -> ok. +destroy(Obj=#wx_ref{type=Type}) -> + ?CLASS(Type,wxAuiSimpleTabArt), + wxe_util:destroy(?wxAuiSimpleTabArt_destroy,Obj), + ok. + %% From wxAuiTabArt +%% @hidden +setActiveColour(This,Colour) -> wxAuiTabArt:setActiveColour(This,Colour). +%% @hidden +setColour(This,Colour) -> wxAuiTabArt:setColour(This,Colour). +%% @hidden +setSelectedFont(This,Font) -> wxAuiTabArt:setSelectedFont(This,Font). +%% @hidden +setNormalFont(This,Font) -> wxAuiTabArt:setNormalFont(This,Font). +%% @hidden +setMeasuringFont(This,Font) -> wxAuiTabArt:setMeasuringFont(This,Font). +%% @hidden +setFlags(This,Flags) -> wxAuiTabArt:setFlags(This,Flags). diff --git a/lib/wx/src/gen/wxAuiTabArt.erl b/lib/wx/src/gen/wxAuiTabArt.erl index 0386ef9dce..80924c0269 100644 --- a/lib/wx/src/gen/wxAuiTabArt.erl +++ b/lib/wx/src/gen/wxAuiTabArt.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2015. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -25,7 +25,8 @@ -module(wxAuiTabArt). -include("wxe.hrl"). --export([]). +-export([setActiveColour/2,setColour/2,setFlags/2,setMeasuringFont/2,setNormalFont/2, + setSelectedFont/2]). %% inherited exports -export([parent_class/1]). @@ -35,3 +36,57 @@ parent_class(_Class) -> erlang:error({badtype, ?MODULE}). -type wxAuiTabArt() :: wx:wx_object(). +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxauitabart.html#wxauitabartsetflags">external documentation</a>. +-spec setFlags(This, Flags) -> ok when + This::wxAuiTabArt(), Flags::integer(). +setFlags(#wx_ref{type=ThisT,ref=ThisRef},Flags) + when is_integer(Flags) -> + ?CLASS(ThisT,wxAuiTabArt), + wxe_util:cast(?wxAuiTabArt_SetFlags, + <<ThisRef:32/?UI,Flags:32/?UI>>). + +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxauitabart.html#wxauitabartsetmeasuringfont">external documentation</a>. +-spec setMeasuringFont(This, Font) -> ok when + This::wxAuiTabArt(), Font::wxFont:wxFont(). +setMeasuringFont(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=FontT,ref=FontRef}) -> + ?CLASS(ThisT,wxAuiTabArt), + ?CLASS(FontT,wxFont), + wxe_util:cast(?wxAuiTabArt_SetMeasuringFont, + <<ThisRef:32/?UI,FontRef:32/?UI>>). + +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxauitabart.html#wxauitabartsetnormalfont">external documentation</a>. +-spec setNormalFont(This, Font) -> ok when + This::wxAuiTabArt(), Font::wxFont:wxFont(). +setNormalFont(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=FontT,ref=FontRef}) -> + ?CLASS(ThisT,wxAuiTabArt), + ?CLASS(FontT,wxFont), + wxe_util:cast(?wxAuiTabArt_SetNormalFont, + <<ThisRef:32/?UI,FontRef:32/?UI>>). + +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxauitabart.html#wxauitabartsetselectedfont">external documentation</a>. +-spec setSelectedFont(This, Font) -> ok when + This::wxAuiTabArt(), Font::wxFont:wxFont(). +setSelectedFont(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=FontT,ref=FontRef}) -> + ?CLASS(ThisT,wxAuiTabArt), + ?CLASS(FontT,wxFont), + wxe_util:cast(?wxAuiTabArt_SetSelectedFont, + <<ThisRef:32/?UI,FontRef:32/?UI>>). + +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxauitabart.html#wxauitabartsetcolour">external documentation</a>. +-spec setColour(This, Colour) -> ok when + This::wxAuiTabArt(), Colour::wx:wx_colour(). +setColour(#wx_ref{type=ThisT,ref=ThisRef},Colour) + when tuple_size(Colour) =:= 3; tuple_size(Colour) =:= 4 -> + ?CLASS(ThisT,wxAuiTabArt), + wxe_util:cast(?wxAuiTabArt_SetColour, + <<ThisRef:32/?UI,(wxe_util:colour_bin(Colour)):16/binary>>). + +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxauitabart.html#wxauitabartsetactivecolour">external documentation</a>. +-spec setActiveColour(This, Colour) -> ok when + This::wxAuiTabArt(), Colour::wx:wx_colour(). +setActiveColour(#wx_ref{type=ThisT,ref=ThisRef},Colour) + when tuple_size(Colour) =:= 3; tuple_size(Colour) =:= 4 -> + ?CLASS(ThisT,wxAuiTabArt), + wxe_util:cast(?wxAuiTabArt_SetActiveColour, + <<ThisRef:32/?UI,(wxe_util:colour_bin(Colour)):16/binary>>). + diff --git a/lib/wx/src/gen/wxBitmapButton.erl b/lib/wx/src/gen/wxBitmapButton.erl index e0fb4bc78a..642828b0b0 100644 --- a/lib/wx/src/gen/wxBitmapButton.erl +++ b/lib/wx/src/gen/wxBitmapButton.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -36,10 +36,10 @@ setBitmapLabel/2,setBitmapSelected/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -51,24 +51,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, - setDefault/1,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, - setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDefault/1,setDoubleBuffered/2, + setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, + setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -229,6 +230,14 @@ setDefault(This) -> wxButton:setDefault(This). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxButton.erl b/lib/wx/src/gen/wxButton.erl index 06e6e53976..c94303bbea 100644 --- a/lib/wx/src/gen/wxButton.erl +++ b/lib/wx/src/gen/wxButton.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,10 +34,10 @@ setLabel/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -49,24 +49,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setMaxSize/2,setMinSize/2, setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -179,6 +180,14 @@ destroy(Obj=#wx_ref{type=Type}) -> getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxCalendarCtrl.erl b/lib/wx/src/gen/wxCalendarCtrl.erl index 2c24063372..1d4baeed08 100644 --- a/lib/wx/src/gen/wxCalendarCtrl.erl +++ b/lib/wx/src/gen/wxCalendarCtrl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -38,10 +38,10 @@ setHighlightColours/3,setHoliday/2,setHolidayColours/3]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -53,24 +53,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -363,6 +364,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxCheckBox.erl b/lib/wx/src/gen/wxCheckBox.erl index c190ebcf27..2cea4d04b4 100644 --- a/lib/wx/src/gen/wxCheckBox.erl +++ b/lib/wx/src/gen/wxCheckBox.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -35,10 +35,10 @@ setValue/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -50,24 +50,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -216,6 +217,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxCheckListBox.erl b/lib/wx/src/gen/wxCheckListBox.erl index 94656daac8..f6013e4863 100644 --- a/lib/wx/src/gen/wxCheckListBox.erl +++ b/lib/wx/src/gen/wxCheckListBox.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -35,46 +35,48 @@ -export([check/2,check/3,destroy/1,isChecked/2,new/0,new/2,new/3]). %% inherited exports --export([append/2,append/3,appendStrings/2,cacheBestSize/2,captureMouse/1,center/1, - center/2,centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, - centreOnParent/2,clear/1,clearBackground/1,clientToScreen/2,clientToScreen/3, - close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, - delete/2,deselect/2,destroyChildren/1,disable/1,disconnect/1,disconnect/2, - disconnect/3,enable/1,enable/2,findString/2,findString/3,findWindow/2, - fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,getBackgroundColour/1, - getBackgroundStyle/1,getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1, - getChildren/1,getClientData/2,getClientSize/1,getContainingSizer/1, - getCount/1,getCursor/1,getDropTarget/1,getEventHandler/1,getExtraStyle/1, - getFont/1,getForegroundColour/1,getGrandParent/1,getHandle/1,getHelpText/1, - getId/1,getLabel/1,getMaxSize/1,getMinSize/1,getName/1,getParent/1, - getPosition/1,getRect/1,getScreenPosition/1,getScreenRect/1,getScrollPos/2, - getScrollRange/2,getScrollThumb/2,getSelection/1,getSelections/1, - getSize/1,getSizer/1,getString/2,getStringSelection/1,getTextExtent/2, - getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, - getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,hitTest/2,inheritAttributes/1,initDialog/1,insert/3,insert/4, - insertItems/3,invalidateBestSize/1,isEmpty/1,isEnabled/1,isExposed/2, - isExposed/3,isExposed/5,isRetained/1,isSelected/2,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - select/2,set/2,setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2, - setBackgroundStyle/2,setCaret/2,setClientData/3,setClientSize/2,setClientSize/3, - setContainingSizer/2,setCursor/2,setDropTarget/2,setExtraStyle/2, - setFirstItem/2,setFocus/1,setFocusFromKbd/1,setFont/2,setForegroundColour/2, - setHelpText/2,setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2, - setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,setPalette/2, - setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,setSelection/2, - setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, - setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setString/3,setStringSelection/2,setThemeEnabled/2,setToolTip/2,setVirtualSize/2, - setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, - setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, - show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, - update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). +-export([append/2,append/3,appendStrings/2,cacheBestSize/2,canSetTransparent/1, + captureMouse/1,center/1,center/2,centerOnParent/1,centerOnParent/2, + centre/1,centre/2,centreOnParent/1,centreOnParent/2,clear/1,clearBackground/1, + clientToScreen/2,clientToScreen/3,close/1,close/2,connect/2,connect/3, + convertDialogToPixels/2,convertPixelsToDialog/2,delete/2,deselect/2, + destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, + enable/1,enable/2,findString/2,findString/3,findWindow/2,fit/1,fitInside/1, + freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1, + getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1, + getClientData/2,getClientSize/1,getContainingSizer/1,getCount/1,getCursor/1, + getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1, + getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1, + getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1, + getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2, + getSelection/1,getSelections/1,getSize/1,getSizer/1,getString/2,getStringSelection/1, + getTextExtent/2,getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1, + getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,hasScrollbar/2, + hasTransparentBackground/1,hide/1,hitTest/2,inheritAttributes/1,initDialog/1, + insert/3,insert/4,insertItems/3,invalidateBestSize/1,isDoubleBuffered/1, + isEmpty/1,isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1, + isSelected/2,isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1, + makeModal/1,makeModal/2,move/2,move/3,move/4,moveAfterInTabOrder/2, + moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1, + popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4, + raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1, + removeChild/2,reparent/2,screenToClient/1,screenToClient/2,scrollLines/2, + scrollPages/2,scrollWindow/3,scrollWindow/4,select/2,set/2,setAcceleratorTable/2, + setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,setCaret/2, + setClientData/3,setClientSize/2,setClientSize/3,setContainingSizer/2, + setCursor/2,setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFirstItem/2, + setFocus/1,setFocusFromKbd/1,setFont/2,setForegroundColour/2,setHelpText/2, + setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, + setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setScrollPos/3, + setScrollPos/4,setScrollbar/5,setScrollbar/6,setSelection/2,setSize/2, + setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4, + setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setString/3, + setStringSelection/2,setThemeEnabled/2,setToolTip/2,setTransparent/2, + setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3, + setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2, + shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1, + transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2, + validate/1,warpPointer/3]). -export_type([wxCheckListBox/0]). %% @hidden @@ -220,6 +222,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxChoice.erl b/lib/wx/src/gen/wxChoice.erl index ddeb00beca..73867d6597 100644 --- a/lib/wx/src/gen/wxChoice.erl +++ b/lib/wx/src/gen/wxChoice.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -35,45 +35,47 @@ setColumns/2]). %% inherited exports --export([append/2,append/3,appendStrings/2,cacheBestSize/2,captureMouse/1,center/1, - center/2,centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, - centreOnParent/2,clear/1,clearBackground/1,clientToScreen/2,clientToScreen/3, - close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, - destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, - enable/1,enable/2,findString/2,findString/3,findWindow/2,fit/1,fitInside/1, - freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1, - getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1, - getClientData/2,getClientSize/1,getContainingSizer/1,getCount/1,getCursor/1, - getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1, - getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1, - getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1, +-export([append/2,append/3,appendStrings/2,cacheBestSize/2,canSetTransparent/1, + captureMouse/1,center/1,center/2,centerOnParent/1,centerOnParent/2, + centre/1,centre/2,centreOnParent/1,centreOnParent/2,clear/1,clearBackground/1, + clientToScreen/2,clientToScreen/3,close/1,close/2,connect/2,connect/3, + convertDialogToPixels/2,convertPixelsToDialog/2,destroyChildren/1, + disable/1,disconnect/1,disconnect/2,disconnect/3,enable/1,enable/2, + findString/2,findString/3,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, + getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, + getCharHeight/1,getCharWidth/1,getChildren/1,getClientData/2,getClientSize/1, + getContainingSizer/1,getCount/1,getCursor/1,getDropTarget/1,getEventHandler/1, + getExtraStyle/1,getFont/1,getForegroundColour/1,getGrandParent/1, + getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,getMinSize/1, + getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1, getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2, getSelection/1,getSize/1,getSizer/1,getString/2,getStringSelection/1, getTextExtent/2,getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1, getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,hasScrollbar/2, hasTransparentBackground/1,hide/1,inheritAttributes/1,initDialog/1, - insert/3,insert/4,invalidateBestSize/1,isEmpty/1,isEnabled/1,isExposed/2, - isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,layout/1, - lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,move/3,move/4, - moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,navigate/2, - pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - select/2,setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2, - setBackgroundStyle/2,setCaret/2,setClientData/3,setClientSize/2,setClientSize/3, - setContainingSizer/2,setCursor/2,setDropTarget/2,setExtraStyle/2, - setFocus/1,setFocusFromKbd/1,setFont/2,setForegroundColour/2,setHelpText/2, - setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, - setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setScrollPos/3, - setScrollPos/4,setScrollbar/5,setScrollbar/6,setSelection/2,setSize/2, - setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4, - setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setString/3, - setStringSelection/2,setThemeEnabled/2,setToolTip/2,setVirtualSize/2, - setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, - setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, - show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, - update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). + insert/3,insert/4,invalidateBestSize/1,isDoubleBuffered/1,isEmpty/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,select/2,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientData/3, + setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, + setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, + setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, + setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, + setSelection/2,setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2, + setSizeHints/3,setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2, + setSizerAndFit/3,setString/3,setStringSelection/2,setThemeEnabled/2, + setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2, + setVirtualSizeHints/3,setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2, + setWindowVariant/2,shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1, + transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2, + validate/1,warpPointer/3]). -export_type([wxChoice/0]). %% @hidden @@ -235,6 +237,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxChoicebook.erl b/lib/wx/src/gen/wxChoicebook.erl index 7627662437..37a44a813a 100644 --- a/lib/wx/src/gen/wxChoicebook.erl +++ b/lib/wx/src/gen/wxChoicebook.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2013. All Rights Reserved. +%% Copyright Ericsson AB 2009-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -38,10 +38,10 @@ setPageSize/2,setPageText/3,setSelection/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -53,24 +53,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -383,6 +384,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxColourDialog.erl b/lib/wx/src/gen/wxColourDialog.erl index 66cde944c5..15eee30727 100644 --- a/lib/wx/src/gen/wxColourDialog.erl +++ b/lib/wx/src/gen/wxColourDialog.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,11 +34,11 @@ -export([create/2,create/3,destroy/1,getColourData/1,new/0,new/1,new/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centerOnScreen/1,centerOnScreen/2,centre/1,centre/2, - centreOnParent/1,centreOnParent/2,centreOnScreen/1,centreOnScreen/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centerOnScreen/1,centerOnScreen/2, + centre/1,centre/2,centreOnParent/1,centreOnParent/2,centreOnScreen/1, + centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, createButtonSizer/2,createStdDialogButtonSizer/2,destroyChildren/1, disable/1,disconnect/1,disconnect/2,disconnect/3,enable/1,enable/2, endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, @@ -53,25 +53,26 @@ getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1, - isActive/1,isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isFullScreen/1, - isIconized/1,isMaximized/1,isModal/1,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,maximize/1, - maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, - navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, - popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, - refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, - reparent/2,requestUserAttention/1,requestUserAttention/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2,setBackgroundColour/2, - setBackgroundStyle/2,setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2, - setCursor/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, - setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2, - setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, - setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setReturnCode/2, - setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2, - setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, - setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setTitle/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, + isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3, + isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isModal/1,isRetained/1, + isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1, + makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2, + moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1, + popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4, + raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1, + removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2, + screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3, + scrollWindow/4,setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, + setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, + setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2, + setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2, + setOwnForegroundColour/2,setPalette/2,setReturnCode/2,setScrollPos/3, + setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2, + setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4, + setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2, + setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3, setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,showFullScreen/2,showFullScreen/3,showModal/1,thaw/1, @@ -222,6 +223,14 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This). getIcon(This) -> wxTopLevelWindow:getIcon(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxColourPickerCtrl.erl b/lib/wx/src/gen/wxColourPickerCtrl.erl index a6ca31c06d..486441c005 100644 --- a/lib/wx/src/gen/wxColourPickerCtrl.erl +++ b/lib/wx/src/gen/wxColourPickerCtrl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,10 +34,10 @@ -export([create/3,create/4,destroy/1,getColour/1,new/0,new/2,new/3,setColour/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -50,30 +50,31 @@ getSize/1,getSizer/1,getTextCtrl/1,getTextCtrlProportion/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTextCtrl/1,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isPickerCtrlGrowable/1,isRetained/1, - isShown/1,isTextCtrlGrowable/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1, - lower/1,makeModal/1,makeModal/2,move/2,move/3,move/4,moveAfterInTabOrder/2, - moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1, - popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4, - raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1, - removeChild/2,reparent/2,screenToClient/1,screenToClient/2,scrollLines/2, - scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2, - setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,setCaret/2, - setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, - setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, - setForegroundColour/2,setHelpText/2,setId/2,setInternalMargin/2,setLabel/2, - setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2, - setOwnForegroundColour/2,setPalette/2,setPickerCtrlGrowable/1,setPickerCtrlGrowable/2, - setPickerCtrlProportion/2,setScrollPos/3,setScrollPos/4,setScrollbar/5, - setScrollbar/6,setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2, - setSizeHints/3,setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2, - setSizerAndFit/3,setTextCtrlGrowable/1,setTextCtrlGrowable/2,setTextCtrlProportion/2, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, - setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, - show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, - update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isPickerCtrlGrowable/1, + isRetained/1,isShown/1,isTextCtrlGrowable/1,isTopLevel/1,layout/1, + lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,move/3,move/4, + moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,navigate/2, + pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, + popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, + refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, + screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, + setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, + setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, + setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setInternalMargin/2, + setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, + setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setPickerCtrlGrowable/1, + setPickerCtrlGrowable/2,setPickerCtrlProportion/2,setScrollPos/3, + setScrollPos/4,setScrollbar/5,setScrollbar/6,setSize/2,setSize/3,setSize/5, + setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,setSizer/2, + setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setTextCtrlGrowable/1, + setTextCtrlGrowable/2,setTextCtrlProportion/2,setThemeEnabled/2, + setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2, + setVirtualSizeHints/3,setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2, + setWindowVariant/2,shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1, + transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2, + validate/1,warpPointer/3]). -export_type([wxColourPickerCtrl/0]). %% @hidden @@ -220,6 +221,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxComboBox.erl b/lib/wx/src/gen/wxComboBox.erl index 0e34c72934..37d6e71605 100644 --- a/lib/wx/src/gen/wxComboBox.erl +++ b/lib/wx/src/gen/wxComboBox.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -37,45 +37,47 @@ setSelection/2,setSelection/3,setValue/2,undo/1]). %% inherited exports --export([append/2,append/3,appendStrings/2,cacheBestSize/2,captureMouse/1,center/1, - center/2,centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, - centreOnParent/2,clear/1,clearBackground/1,clientToScreen/2,clientToScreen/3, - close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, - delete/2,destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, - enable/1,enable/2,findString/2,findString/3,findWindow/2,fit/1,fitInside/1, - freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1, - getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1, - getClientData/2,getClientSize/1,getContainingSizer/1,getCount/1,getCursor/1, - getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1, - getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1, - getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1, +-export([append/2,append/3,appendStrings/2,cacheBestSize/2,canSetTransparent/1, + captureMouse/1,center/1,center/2,centerOnParent/1,centerOnParent/2, + centre/1,centre/2,centreOnParent/1,centreOnParent/2,clear/1,clearBackground/1, + clientToScreen/2,clientToScreen/3,close/1,close/2,connect/2,connect/3, + convertDialogToPixels/2,convertPixelsToDialog/2,delete/2,destroyChildren/1, + disable/1,disconnect/1,disconnect/2,disconnect/3,enable/1,enable/2, + findString/2,findString/3,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, + getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, + getCharHeight/1,getCharWidth/1,getChildren/1,getClientData/2,getClientSize/1, + getContainingSizer/1,getCount/1,getCursor/1,getDropTarget/1,getEventHandler/1, + getExtraStyle/1,getFont/1,getForegroundColour/1,getGrandParent/1, + getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,getMinSize/1, + getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1, getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2, getSelection/1,getSize/1,getSizer/1,getString/2,getStringSelection/1, getTextExtent/2,getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1, getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,hasScrollbar/2, hasTransparentBackground/1,hide/1,inheritAttributes/1,initDialog/1, - insert/3,insert/4,invalidateBestSize/1,isEmpty/1,isEnabled/1,isExposed/2, - isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,layout/1, - lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,move/3,move/4, - moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,navigate/2, - pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - select/2,setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2, - setBackgroundStyle/2,setCaret/2,setClientData/3,setClientSize/2,setClientSize/3, - setContainingSizer/2,setCursor/2,setDropTarget/2,setExtraStyle/2, - setFocus/1,setFocusFromKbd/1,setFont/2,setForegroundColour/2,setHelpText/2, - setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, - setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setScrollPos/3, - setScrollPos/4,setScrollbar/5,setScrollbar/6,setSize/2,setSize/3,setSize/5, - setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,setSizer/2, - setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setString/3,setStringSelection/2, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, - setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, - show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, - update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). + insert/3,insert/4,invalidateBestSize/1,isDoubleBuffered/1,isEmpty/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,select/2,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientData/3, + setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, + setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, + setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, + setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, + setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, + setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, + setString/3,setStringSelection/2,setThemeEnabled/2,setToolTip/2,setTransparent/2, + setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3, + setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2, + shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1, + transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2, + validate/1,warpPointer/3]). -export_type([wxComboBox/0]). %% @hidden @@ -370,6 +372,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxControl.erl b/lib/wx/src/gen/wxControl.erl index f0fb88e3eb..f84ec34b02 100644 --- a/lib/wx/src/gen/wxControl.erl +++ b/lib/wx/src/gen/wxControl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -32,10 +32,10 @@ -export([getLabel/1,setLabel/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -47,24 +47,25 @@ getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3, getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setMaxSize/2,setMinSize/2, setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -96,6 +97,14 @@ setLabel(#wx_ref{type=ThisT,ref=ThisRef},Label) %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxControlWithItems.erl b/lib/wx/src/gen/wxControlWithItems.erl index 5f4ed9701b..d52c7917a2 100644 --- a/lib/wx/src/gen/wxControlWithItems.erl +++ b/lib/wx/src/gen/wxControlWithItems.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -36,10 +36,10 @@ setString/3,setStringSelection/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -51,24 +51,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -278,6 +279,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxDCOverlay.erl b/lib/wx/src/gen/wxDCOverlay.erl new file mode 100644 index 0000000000..f98e310ba6 --- /dev/null +++ b/lib/wx/src/gen/wxDCOverlay.erl @@ -0,0 +1,70 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2015. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% This file is generated DO NOT EDIT + +%% @doc See external documentation: <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxdcoverlay.html">wxDCOverlay</a>. +%% @type wxDCOverlay(). 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(wxDCOverlay). +-include("wxe.hrl"). +-export([clear/1,destroy/1,new/2,new/6]). + +%% inherited exports +-export([parent_class/1]). + +-export_type([wxDCOverlay/0]). +%% @hidden +parent_class(_Class) -> erlang:error({badtype, ?MODULE}). + +-type wxDCOverlay() :: wx:wx_object(). +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxdcoverlay.html#wxdcoverlaywxdcoverlay">external documentation</a>. +-spec new(Overlay, Dc) -> wxDCOverlay() when + Overlay::wxOverlay:wxOverlay(), Dc::wxWindowDC:wxWindowDC(). +new(#wx_ref{type=OverlayT,ref=OverlayRef},#wx_ref{type=DcT,ref=DcRef}) -> + ?CLASS(OverlayT,wxOverlay), + ?CLASS(DcT,wxWindowDC), + wxe_util:construct(?wxDCOverlay_new_2, + <<OverlayRef:32/?UI,DcRef:32/?UI>>). + +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxdcoverlay.html#wxdcoverlaywxdcoverlay">external documentation</a>. +-spec new(Overlay, Dc, X, Y, Width, Height) -> wxDCOverlay() when + Overlay::wxOverlay:wxOverlay(), Dc::wxWindowDC:wxWindowDC(), X::integer(), Y::integer(), Width::integer(), Height::integer(). +new(#wx_ref{type=OverlayT,ref=OverlayRef},#wx_ref{type=DcT,ref=DcRef},X,Y,Width,Height) + when is_integer(X),is_integer(Y),is_integer(Width),is_integer(Height) -> + ?CLASS(OverlayT,wxOverlay), + ?CLASS(DcT,wxWindowDC), + wxe_util:construct(?wxDCOverlay_new_6, + <<OverlayRef:32/?UI,DcRef:32/?UI,X:32/?UI,Y:32/?UI,Width:32/?UI,Height:32/?UI>>). + +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxdcoverlay.html#wxdcoverlayclear">external documentation</a>. +-spec clear(This) -> ok when + This::wxDCOverlay(). +clear(#wx_ref{type=ThisT,ref=ThisRef}) -> + ?CLASS(ThisT,wxDCOverlay), + wxe_util:cast(?wxDCOverlay_Clear, + <<ThisRef:32/?UI>>). + +%% @doc Destroys this object, do not use object again +-spec destroy(This::wxDCOverlay()) -> ok. +destroy(Obj=#wx_ref{type=Type}) -> + ?CLASS(Type,wxDCOverlay), + wxe_util:destroy(?wxDCOverlay_destruct,Obj), + ok. diff --git a/lib/wx/src/gen/wxDatePickerCtrl.erl b/lib/wx/src/gen/wxDatePickerCtrl.erl index 73df9c1395..057f91d4e8 100644 --- a/lib/wx/src/gen/wxDatePickerCtrl.erl +++ b/lib/wx/src/gen/wxDatePickerCtrl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,10 +34,10 @@ -export([destroy/1,getRange/3,getValue/1,new/0,new/2,new/3,setRange/3,setValue/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -50,30 +50,31 @@ getSize/1,getSizer/1,getTextCtrl/1,getTextCtrlProportion/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTextCtrl/1,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isPickerCtrlGrowable/1,isRetained/1, - isShown/1,isTextCtrlGrowable/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1, - lower/1,makeModal/1,makeModal/2,move/2,move/3,move/4,moveAfterInTabOrder/2, - moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1, - popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4, - raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1, - removeChild/2,reparent/2,screenToClient/1,screenToClient/2,scrollLines/2, - scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2, - setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,setCaret/2, - setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, - setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, - setForegroundColour/2,setHelpText/2,setId/2,setInternalMargin/2,setLabel/2, - setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2, - setOwnForegroundColour/2,setPalette/2,setPickerCtrlGrowable/1,setPickerCtrlGrowable/2, - setPickerCtrlProportion/2,setScrollPos/3,setScrollPos/4,setScrollbar/5, - setScrollbar/6,setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2, - setSizeHints/3,setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2, - setSizerAndFit/3,setTextCtrlGrowable/1,setTextCtrlGrowable/2,setTextCtrlProportion/2, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, - setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, - show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, - update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isPickerCtrlGrowable/1, + isRetained/1,isShown/1,isTextCtrlGrowable/1,isTopLevel/1,layout/1, + lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,move/3,move/4, + moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,navigate/2, + pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, + popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, + refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, + screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, + setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, + setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, + setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setInternalMargin/2, + setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, + setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setPickerCtrlGrowable/1, + setPickerCtrlGrowable/2,setPickerCtrlProportion/2,setScrollPos/3, + setScrollPos/4,setScrollbar/5,setScrollbar/6,setSize/2,setSize/3,setSize/5, + setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,setSizer/2, + setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setTextCtrlGrowable/1, + setTextCtrlGrowable/2,setTextCtrlProportion/2,setThemeEnabled/2, + setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2, + setVirtualSizeHints/3,setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2, + setWindowVariant/2,shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1, + transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2, + validate/1,warpPointer/3]). -export_type([wxDatePickerCtrl/0]). %% @hidden @@ -196,6 +197,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxDialog.erl b/lib/wx/src/gen/wxDialog.erl index aa4df5888c..c3f4828c68 100644 --- a/lib/wx/src/gen/wxDialog.erl +++ b/lib/wx/src/gen/wxDialog.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -35,11 +35,11 @@ new/0,new/3,new/4,setAffirmativeId/2,setReturnCode/2,show/1,show/2,showModal/1]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centerOnScreen/1,centerOnScreen/2,centre/1,centre/2, - centreOnParent/1,centreOnParent/2,centreOnScreen/1,centreOnScreen/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centerOnScreen/1,centerOnScreen/2, + centre/1,centre/2,centreOnParent/1,centreOnParent/2,centreOnScreen/1, + centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -53,29 +53,30 @@ getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1, hasScrollbar/2,hasTransparentBackground/1,hide/1,iconize/1,iconize/2, inheritAttributes/1,initDialog/1,invalidateBestSize/1,isActive/1, - isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isFullScreen/1,isIconized/1, - isMaximized/1,isRetained/1,isShown/1,isTopLevel/1,layout/1,lineDown/1, - lineUp/1,lower/1,makeModal/1,makeModal/2,maximize/1,maximize/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,requestUserAttention/1, - requestUserAttention/2,screenToClient/1,screenToClient/2,scrollLines/2, - scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2, - setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,setCaret/2, - setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, - setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, - setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2, - setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2, - setOwnForegroundColour/2,setPalette/2,setScrollPos/3,setScrollPos/4, - setScrollbar/5,setScrollbar/6,setShape/2,setSize/2,setSize/3,setSize/5, - setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,setSizer/2, - setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2,setTitle/2, - setToolTip/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2, - setVirtualSizeHints/3,setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2, - setWindowVariant/2,shouldInheritColours/1,showFullScreen/2,showFullScreen/3, - thaw/1,transferDataFromWindow/1,transferDataToWindow/1,update/1,updateWindowUI/1, - updateWindowUI/2,validate/1,warpPointer/3]). + isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3,isExposed/5, + isFullScreen/1,isIconized/1,isMaximized/1,isRetained/1,isShown/1,isTopLevel/1, + layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,maximize/1, + maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,requestUserAttention/1,requestUserAttention/2,screenToClient/1, + screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, + setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, + setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, + setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2, + setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, + setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setScrollPos/3, + setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2, + setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4, + setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2, + setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3, + setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, + showFullScreen/2,showFullScreen/3,thaw/1,transferDataFromWindow/1, + transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2, + validate/1,warpPointer/3]). -export_type([wxDialog/0]). %% @hidden @@ -297,6 +298,14 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This). getIcon(This) -> wxTopLevelWindow:getIcon(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxDirDialog.erl b/lib/wx/src/gen/wxDirDialog.erl index cf1d558b00..aa7a419bcd 100644 --- a/lib/wx/src/gen/wxDirDialog.erl +++ b/lib/wx/src/gen/wxDirDialog.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,11 +34,11 @@ -export([destroy/1,getMessage/1,getPath/1,new/1,new/2,setMessage/2,setPath/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centerOnScreen/1,centerOnScreen/2,centre/1,centre/2, - centreOnParent/1,centreOnParent/2,centreOnScreen/1,centreOnScreen/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centerOnScreen/1,centerOnScreen/2, + centre/1,centre/2,centreOnParent/1,centreOnParent/2,centreOnScreen/1, + centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, createButtonSizer/2,createStdDialogButtonSizer/2,destroyChildren/1, disable/1,disconnect/1,disconnect/2,disconnect/3,enable/1,enable/2, endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, @@ -53,25 +53,26 @@ getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1, - isActive/1,isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isFullScreen/1, - isIconized/1,isMaximized/1,isModal/1,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,maximize/1, - maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, - navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, - popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, - refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, - reparent/2,requestUserAttention/1,requestUserAttention/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2,setBackgroundColour/2, - setBackgroundStyle/2,setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2, - setCursor/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, - setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2, - setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, - setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setReturnCode/2, - setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2, - setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, - setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setTitle/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, + isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3, + isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isModal/1,isRetained/1, + isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1, + makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2, + moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1, + popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4, + raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1, + removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2, + screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3, + scrollWindow/4,setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, + setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, + setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2, + setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2, + setOwnForegroundColour/2,setPalette/2,setReturnCode/2,setScrollPos/3, + setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2, + setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4, + setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2, + setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3, setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,showFullScreen/2,showFullScreen/3,showModal/1,thaw/1, @@ -230,6 +231,14 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This). getIcon(This) -> wxTopLevelWindow:getIcon(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxDirPickerCtrl.erl b/lib/wx/src/gen/wxDirPickerCtrl.erl index 1db48b467c..fea7ee71a1 100644 --- a/lib/wx/src/gen/wxDirPickerCtrl.erl +++ b/lib/wx/src/gen/wxDirPickerCtrl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,10 +34,10 @@ -export([create/3,create/4,destroy/1,getPath/1,new/0,new/2,new/3,setPath/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -50,30 +50,31 @@ getSize/1,getSizer/1,getTextCtrl/1,getTextCtrlProportion/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTextCtrl/1,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isPickerCtrlGrowable/1,isRetained/1, - isShown/1,isTextCtrlGrowable/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1, - lower/1,makeModal/1,makeModal/2,move/2,move/3,move/4,moveAfterInTabOrder/2, - moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1, - popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4, - raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1, - removeChild/2,reparent/2,screenToClient/1,screenToClient/2,scrollLines/2, - scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2, - setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,setCaret/2, - setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, - setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, - setForegroundColour/2,setHelpText/2,setId/2,setInternalMargin/2,setLabel/2, - setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2, - setOwnForegroundColour/2,setPalette/2,setPickerCtrlGrowable/1,setPickerCtrlGrowable/2, - setPickerCtrlProportion/2,setScrollPos/3,setScrollPos/4,setScrollbar/5, - setScrollbar/6,setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2, - setSizeHints/3,setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2, - setSizerAndFit/3,setTextCtrlGrowable/1,setTextCtrlGrowable/2,setTextCtrlProportion/2, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, - setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, - show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, - update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isPickerCtrlGrowable/1, + isRetained/1,isShown/1,isTextCtrlGrowable/1,isTopLevel/1,layout/1, + lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,move/3,move/4, + moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,navigate/2, + pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, + popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, + refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, + screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, + setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, + setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, + setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setInternalMargin/2, + setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, + setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setPickerCtrlGrowable/1, + setPickerCtrlGrowable/2,setPickerCtrlProportion/2,setScrollPos/3, + setScrollPos/4,setScrollbar/5,setScrollbar/6,setSize/2,setSize/3,setSize/5, + setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,setSizer/2, + setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setTextCtrlGrowable/1, + setTextCtrlGrowable/2,setTextCtrlProportion/2,setThemeEnabled/2, + setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2, + setVirtualSizeHints/3,setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2, + setWindowVariant/2,shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1, + transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2, + validate/1,warpPointer/3]). -export_type([wxDirPickerCtrl/0]). %% @hidden @@ -213,6 +214,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxEvtHandler.erl b/lib/wx/src/gen/wxEvtHandler.erl index 6e9770bbb6..2d0a87f4dd 100644 --- a/lib/wx/src/gen/wxEvtHandler.erl +++ b/lib/wx/src/gen/wxEvtHandler.erl @@ -90,6 +90,8 @@ connect(This=#wx_ref{type=ThisT}, EventType, Options) -> parse_opts([{callback,Fun}|R], Opts) when is_function(Fun) -> %% Check Fun Arity? parse_opts(R, Opts#evh{cb=Fun}); +parse_opts([{callback,CB={nospawn, Fun}}|R], Opts) when is_function(Fun) -> + parse_opts(R, Opts#evh{cb=CB}); parse_opts([callback|R], Opts) -> parse_opts(R, Opts#evh{cb=self()}); parse_opts([{userData, UserData}|R],Opts) -> diff --git a/lib/wx/src/gen/wxFileDialog.erl b/lib/wx/src/gen/wxFileDialog.erl index d3dac3ba2d..36ee6463ae 100644 --- a/lib/wx/src/gen/wxFileDialog.erl +++ b/lib/wx/src/gen/wxFileDialog.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -36,11 +36,11 @@ setFilename/2,setFilterIndex/2,setMessage/2,setPath/2,setWildcard/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centerOnScreen/1,centerOnScreen/2,centre/1,centre/2, - centreOnParent/1,centreOnParent/2,centreOnScreen/1,centreOnScreen/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centerOnScreen/1,centerOnScreen/2, + centre/1,centre/2,centreOnParent/1,centreOnParent/2,centreOnScreen/1, + centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, createButtonSizer/2,createStdDialogButtonSizer/2,destroyChildren/1, disable/1,disconnect/1,disconnect/2,disconnect/3,enable/1,enable/2, endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, @@ -55,25 +55,26 @@ getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1, - isActive/1,isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isFullScreen/1, - isIconized/1,isMaximized/1,isModal/1,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,maximize/1, - maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, - navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, - popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, - refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, - reparent/2,requestUserAttention/1,requestUserAttention/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2,setBackgroundColour/2, - setBackgroundStyle/2,setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2, - setCursor/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, - setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2, - setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, - setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setReturnCode/2, - setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2, - setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, - setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setTitle/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, + isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3, + isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isModal/1,isRetained/1, + isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1, + makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2, + moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1, + popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4, + raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1, + removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2, + screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3, + scrollWindow/4,setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, + setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, + setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2, + setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2, + setOwnForegroundColour/2,setPalette/2,setReturnCode/2,setScrollPos/3, + setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2, + setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4, + setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2, + setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3, setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,showFullScreen/2,showFullScreen/3,showModal/1,thaw/1, @@ -323,6 +324,14 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This). getIcon(This) -> wxTopLevelWindow:getIcon(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxFilePickerCtrl.erl b/lib/wx/src/gen/wxFilePickerCtrl.erl index d781bdf000..2b57a5927b 100644 --- a/lib/wx/src/gen/wxFilePickerCtrl.erl +++ b/lib/wx/src/gen/wxFilePickerCtrl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,10 +34,10 @@ -export([create/3,create/4,destroy/1,getPath/1,new/0,new/2,new/3,setPath/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -50,30 +50,31 @@ getSize/1,getSizer/1,getTextCtrl/1,getTextCtrlProportion/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTextCtrl/1,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isPickerCtrlGrowable/1,isRetained/1, - isShown/1,isTextCtrlGrowable/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1, - lower/1,makeModal/1,makeModal/2,move/2,move/3,move/4,moveAfterInTabOrder/2, - moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1, - popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4, - raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1, - removeChild/2,reparent/2,screenToClient/1,screenToClient/2,scrollLines/2, - scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2, - setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,setCaret/2, - setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, - setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, - setForegroundColour/2,setHelpText/2,setId/2,setInternalMargin/2,setLabel/2, - setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2, - setOwnForegroundColour/2,setPalette/2,setPickerCtrlGrowable/1,setPickerCtrlGrowable/2, - setPickerCtrlProportion/2,setScrollPos/3,setScrollPos/4,setScrollbar/5, - setScrollbar/6,setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2, - setSizeHints/3,setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2, - setSizerAndFit/3,setTextCtrlGrowable/1,setTextCtrlGrowable/2,setTextCtrlProportion/2, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, - setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, - show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, - update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isPickerCtrlGrowable/1, + isRetained/1,isShown/1,isTextCtrlGrowable/1,isTopLevel/1,layout/1, + lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,move/3,move/4, + moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,navigate/2, + pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, + popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, + refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, + screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, + setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, + setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, + setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setInternalMargin/2, + setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, + setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setPickerCtrlGrowable/1, + setPickerCtrlGrowable/2,setPickerCtrlProportion/2,setScrollPos/3, + setScrollPos/4,setScrollbar/5,setScrollbar/6,setSize/2,setSize/3,setSize/5, + setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,setSizer/2, + setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setTextCtrlGrowable/1, + setTextCtrlGrowable/2,setTextCtrlProportion/2,setThemeEnabled/2, + setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2, + setVirtualSizeHints/3,setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2, + setWindowVariant/2,shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1, + transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2, + validate/1,warpPointer/3]). -export_type([wxFilePickerCtrl/0]). %% @hidden @@ -217,6 +218,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxFindReplaceDialog.erl b/lib/wx/src/gen/wxFindReplaceDialog.erl index a14a05fb8e..d265e232b3 100644 --- a/lib/wx/src/gen/wxFindReplaceDialog.erl +++ b/lib/wx/src/gen/wxFindReplaceDialog.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,11 +34,11 @@ -export([create/4,create/5,destroy/1,getData/1,new/0,new/3,new/4]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centerOnScreen/1,centerOnScreen/2,centre/1,centre/2, - centreOnParent/1,centreOnParent/2,centreOnScreen/1,centreOnScreen/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centerOnScreen/1,centerOnScreen/2, + centre/1,centre/2,centreOnParent/1,centreOnParent/2,centreOnScreen/1, + centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, createButtonSizer/2,createStdDialogButtonSizer/2,destroyChildren/1, disable/1,disconnect/1,disconnect/2,disconnect/3,enable/1,enable/2, endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, @@ -53,25 +53,26 @@ getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1, - isActive/1,isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isFullScreen/1, - isIconized/1,isMaximized/1,isModal/1,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,maximize/1, - maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, - navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, - popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, - refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, - reparent/2,requestUserAttention/1,requestUserAttention/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2,setBackgroundColour/2, - setBackgroundStyle/2,setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2, - setCursor/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, - setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2, - setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, - setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setReturnCode/2, - setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2, - setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, - setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setTitle/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, + isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3, + isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isModal/1,isRetained/1, + isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1, + makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2, + moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1, + popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4, + raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1, + removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2, + screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3, + scrollWindow/4,setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, + setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, + setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2, + setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2, + setOwnForegroundColour/2,setPalette/2,setReturnCode/2,setScrollPos/3, + setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2, + setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4, + setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2, + setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3, setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,showFullScreen/2,showFullScreen/3,showModal/1,thaw/1, @@ -226,6 +227,14 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This). getIcon(This) -> wxTopLevelWindow:getIcon(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxFontDialog.erl b/lib/wx/src/gen/wxFontDialog.erl index cf0938a57d..de199cfcce 100644 --- a/lib/wx/src/gen/wxFontDialog.erl +++ b/lib/wx/src/gen/wxFontDialog.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,11 +34,11 @@ -export([create/3,destroy/1,getFontData/1,new/0,new/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centerOnScreen/1,centerOnScreen/2,centre/1,centre/2, - centreOnParent/1,centreOnParent/2,centreOnScreen/1,centreOnScreen/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centerOnScreen/1,centerOnScreen/2, + centre/1,centre/2,centreOnParent/1,centreOnParent/2,centreOnScreen/1, + centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, createButtonSizer/2,createStdDialogButtonSizer/2,destroyChildren/1, disable/1,disconnect/1,disconnect/2,disconnect/3,enable/1,enable/2, endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, @@ -53,25 +53,26 @@ getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1, - isActive/1,isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isFullScreen/1, - isIconized/1,isMaximized/1,isModal/1,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,maximize/1, - maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, - navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, - popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, - refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, - reparent/2,requestUserAttention/1,requestUserAttention/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2,setBackgroundColour/2, - setBackgroundStyle/2,setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2, - setCursor/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, - setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2, - setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, - setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setReturnCode/2, - setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2, - setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, - setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setTitle/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, + isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3, + isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isModal/1,isRetained/1, + isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1, + makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2, + moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1, + popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4, + raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1, + removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2, + screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3, + scrollWindow/4,setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, + setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, + setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2, + setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2, + setOwnForegroundColour/2,setPalette/2,setReturnCode/2,setScrollPos/3, + setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2, + setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4, + setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2, + setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3, setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,showFullScreen/2,showFullScreen/3,showModal/1,thaw/1, @@ -198,6 +199,14 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This). getIcon(This) -> wxTopLevelWindow:getIcon(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxFontPickerCtrl.erl b/lib/wx/src/gen/wxFontPickerCtrl.erl index b5c3b641ee..c21061e0fe 100644 --- a/lib/wx/src/gen/wxFontPickerCtrl.erl +++ b/lib/wx/src/gen/wxFontPickerCtrl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -35,10 +35,10 @@ new/2,new/3,setMaxPointSize/2,setSelectedFont/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -51,30 +51,31 @@ getSize/1,getSizer/1,getTextCtrl/1,getTextCtrlProportion/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTextCtrl/1,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isPickerCtrlGrowable/1,isRetained/1, - isShown/1,isTextCtrlGrowable/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1, - lower/1,makeModal/1,makeModal/2,move/2,move/3,move/4,moveAfterInTabOrder/2, - moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1, - popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4, - raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1, - removeChild/2,reparent/2,screenToClient/1,screenToClient/2,scrollLines/2, - scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2, - setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,setCaret/2, - setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, - setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, - setForegroundColour/2,setHelpText/2,setId/2,setInternalMargin/2,setLabel/2, - setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2, - setOwnForegroundColour/2,setPalette/2,setPickerCtrlGrowable/1,setPickerCtrlGrowable/2, - setPickerCtrlProportion/2,setScrollPos/3,setScrollPos/4,setScrollbar/5, - setScrollbar/6,setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2, - setSizeHints/3,setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2, - setSizerAndFit/3,setTextCtrlGrowable/1,setTextCtrlGrowable/2,setTextCtrlProportion/2, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, - setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, - show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, - update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isPickerCtrlGrowable/1, + isRetained/1,isShown/1,isTextCtrlGrowable/1,isTopLevel/1,layout/1, + lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,move/3,move/4, + moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,navigate/2, + pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, + popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, + refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, + screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, + setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, + setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, + setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setInternalMargin/2, + setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, + setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setPickerCtrlGrowable/1, + setPickerCtrlGrowable/2,setPickerCtrlProportion/2,setScrollPos/3, + setScrollPos/4,setScrollbar/5,setScrollbar/6,setSize/2,setSize/3,setSize/5, + setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,setSizer/2, + setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setTextCtrlGrowable/1, + setTextCtrlGrowable/2,setTextCtrlProportion/2,setThemeEnabled/2, + setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2, + setVirtualSizeHints/3,setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2, + setWindowVariant/2,shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1, + transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2, + validate/1,warpPointer/3]). -export_type([wxFontPickerCtrl/0]). %% @hidden @@ -226,6 +227,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxFrame.erl b/lib/wx/src/gen/wxFrame.erl index 6fa1a2b958..75860cd9b7 100644 --- a/lib/wx/src/gen/wxFrame.erl +++ b/lib/wx/src/gen/wxFrame.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -37,11 +37,11 @@ setStatusText/3,setStatusWidths/2,setToolBar/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centerOnScreen/1,centerOnScreen/2,centre/1,centre/2, - centreOnParent/1,centreOnParent/2,centreOnScreen/1,centreOnScreen/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centerOnScreen/1,centerOnScreen/2, + centre/1,centre/2,centreOnParent/1,centreOnParent/2,centreOnScreen/1, + centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -55,29 +55,30 @@ getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1, hasScrollbar/2,hasTransparentBackground/1,hide/1,iconize/1,iconize/2, inheritAttributes/1,initDialog/1,invalidateBestSize/1,isActive/1, - isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isFullScreen/1,isIconized/1, - isMaximized/1,isRetained/1,isShown/1,isTopLevel/1,layout/1,lineDown/1, - lineUp/1,lower/1,makeModal/1,makeModal/2,maximize/1,maximize/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,requestUserAttention/1, - requestUserAttention/2,screenToClient/1,screenToClient/2,scrollLines/2, - scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2, - setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,setCaret/2, - setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, - setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, - setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2, - setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2, - setOwnForegroundColour/2,setPalette/2,setScrollPos/3,setScrollPos/4, - setScrollbar/5,setScrollbar/6,setShape/2,setSize/2,setSize/3,setSize/5, - setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,setSizer/2, - setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2,setTitle/2, - setToolTip/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2, - setVirtualSizeHints/3,setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2, - setWindowVariant/2,shouldInheritColours/1,show/1,show/2,showFullScreen/2, - showFullScreen/3,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, - update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). + isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3,isExposed/5, + isFullScreen/1,isIconized/1,isMaximized/1,isRetained/1,isShown/1,isTopLevel/1, + layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,maximize/1, + maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,requestUserAttention/1,requestUserAttention/2,screenToClient/1, + screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, + setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, + setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, + setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2, + setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, + setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setScrollPos/3, + setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2, + setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4, + setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2, + setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3, + setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, + show/1,show/2,showFullScreen/2,showFullScreen/3,thaw/1,transferDataFromWindow/1, + transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2, + validate/1,warpPointer/3]). -export_type([wxFrame/0]). %% @hidden @@ -374,6 +375,14 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This). getIcon(This) -> wxTopLevelWindow:getIcon(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxGLCanvas.erl b/lib/wx/src/gen/wxGLCanvas.erl index b00b45ad24..9d3d13740d 100644 --- a/lib/wx/src/gen/wxGLCanvas.erl +++ b/lib/wx/src/gen/wxGLCanvas.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -32,10 +32,10 @@ -export([destroy/1,getContext/1,new/1,new/2,new/3,setCurrent/1,swapBuffers/1]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -47,24 +47,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -193,6 +194,14 @@ destroy(Obj=#wx_ref{type=Type}) -> ok. %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxGauge.erl b/lib/wx/src/gen/wxGauge.erl index 0b64f097ad..51c35145c4 100644 --- a/lib/wx/src/gen/wxGauge.erl +++ b/lib/wx/src/gen/wxGauge.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -35,10 +35,10 @@ setShadowWidth/2,setValue/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -50,24 +50,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -238,6 +239,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxGenericDirCtrl.erl b/lib/wx/src/gen/wxGenericDirCtrl.erl index 014111144f..bc26a1645e 100644 --- a/lib/wx/src/gen/wxGenericDirCtrl.erl +++ b/lib/wx/src/gen/wxGenericDirCtrl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -36,10 +36,10 @@ setFilterIndex/2,setPath/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -51,24 +51,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -296,6 +297,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxGrid.erl b/lib/wx/src/gen/wxGrid.erl index 0d35804529..49bd89f188 100644 --- a/lib/wx/src/gen/wxGrid.erl +++ b/lib/wx/src/gen/wxGrid.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -86,10 +86,10 @@ %% inherited exports -export([cacheBestSize/2,calcScrolledPosition/2,calcScrolledPosition/3,calcUnscrolledPosition/2, - calcUnscrolledPosition/3,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, + calcUnscrolledPosition/3,canSetTransparent/1,captureMouse/1,center/1, + center/2,centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, doPrepareDC/2,enable/1,enable/2,enableScrolling/3,findWindow/2,fitInside/1, freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1, @@ -102,25 +102,26 @@ getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3, getToolTip/1,getUpdateRegion/1,getViewStart/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,prepareDC/2,raise/1,refresh/1,refresh/2, - refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,reparent/2, - screenToClient/1,screenToClient/2,scroll/3,scrollLines/2,scrollPages/2, - scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, - setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, - setClientSize/3,setContainingSizer/2,setCursor/2,setDropTarget/2, - setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFocusIgnoringChildren/1, - setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, - setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, - setPalette/2,setScrollPos/3,setScrollPos/4,setScrollRate/3,setScrollbar/5, - setScrollbar/6,setScrollbars/5,setScrollbars/6,setSize/2,setSize/3, - setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,setSizer/2, - setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setTargetWindow/2,setThemeEnabled/2, - setToolTip/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,prepareDC/2, + raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1, + removeChild/2,reparent/2,screenToClient/1,screenToClient/2,scroll/3, + scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2, + setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,setCaret/2, + setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, + setFocusIgnoringChildren/1,setFont/2,setForegroundColour/2,setHelpText/2, + setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, + setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setScrollPos/3, + setScrollPos/4,setScrollRate/3,setScrollbar/5,setScrollbar/6,setScrollbars/5, + setScrollbars/6,setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2, + setSizeHints/3,setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2, + setSizerAndFit/3,setTargetWindow/2,setThemeEnabled/2,setToolTip/2, + setTransparent/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2, setVirtualSizeHints/3,setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2, setWindowVariant/2,shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1, transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2, @@ -2157,6 +2158,14 @@ setFocusIgnoringChildren(This) -> wxPanel:setFocusIgnoringChildren(This). initDialog(This) -> wxPanel:initDialog(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxHtmlWindow.erl b/lib/wx/src/gen/wxHtmlWindow.erl index 6b0b172b24..759b8ba0fd 100644 --- a/lib/wx/src/gen/wxHtmlWindow.erl +++ b/lib/wx/src/gen/wxHtmlWindow.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2013. All Rights Reserved. +%% Copyright Ericsson AB 2009-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -40,10 +40,10 @@ %% inherited exports -export([cacheBestSize/2,calcScrolledPosition/2,calcScrolledPosition/3,calcUnscrolledPosition/2, - calcUnscrolledPosition/3,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, + calcUnscrolledPosition/3,canSetTransparent/1,captureMouse/1,center/1, + center/2,centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, doPrepareDC/2,enable/1,enable/2,enableScrolling/3,findWindow/2,fit/1, fitInside/1,freeze/1,getAcceleratorTable/1,getBackgroundColour/1, @@ -56,25 +56,26 @@ getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3, getToolTip/1,getUpdateRegion/1,getViewStart/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,prepareDC/2,raise/1,refresh/1,refresh/2, - refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,reparent/2, - screenToClient/1,screenToClient/2,scroll/3,scrollLines/2,scrollPages/2, - scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, - setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, - setClientSize/3,setContainingSizer/2,setCursor/2,setDropTarget/2, - setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFocusIgnoringChildren/1, - setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, - setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, - setPalette/2,setScrollPos/3,setScrollPos/4,setScrollRate/3,setScrollbar/5, - setScrollbar/6,setScrollbars/5,setScrollbars/6,setSize/2,setSize/3, - setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,setSizer/2, - setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setTargetWindow/2,setThemeEnabled/2, - setToolTip/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,prepareDC/2, + raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1, + removeChild/2,reparent/2,screenToClient/1,screenToClient/2,scroll/3, + scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2, + setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,setCaret/2, + setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, + setFocusIgnoringChildren/1,setFont/2,setForegroundColour/2,setHelpText/2, + setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, + setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setScrollPos/3, + setScrollPos/4,setScrollRate/3,setScrollbar/5,setScrollbar/6,setScrollbars/5, + setScrollbars/6,setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2, + setSizeHints/3,setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2, + setSizerAndFit/3,setTargetWindow/2,setThemeEnabled/2,setToolTip/2, + setTransparent/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2, setVirtualSizeHints/3,setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2, setWindowVariant/2,shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1, transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2, @@ -370,6 +371,14 @@ setFocusIgnoringChildren(This) -> wxPanel:setFocusIgnoringChildren(This). initDialog(This) -> wxPanel:initDialog(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxListBox.erl b/lib/wx/src/gen/wxListBox.erl index 14cc553935..eaa026839e 100644 --- a/lib/wx/src/gen/wxListBox.erl +++ b/lib/wx/src/gen/wxListBox.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -35,45 +35,47 @@ isSelected/2,new/0,new/2,new/3,set/2,setFirstItem/2]). %% inherited exports --export([append/2,append/3,appendStrings/2,cacheBestSize/2,captureMouse/1,center/1, - center/2,centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, - centreOnParent/2,clear/1,clearBackground/1,clientToScreen/2,clientToScreen/3, - close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, - delete/2,destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, - enable/1,enable/2,findString/2,findString/3,findWindow/2,fit/1,fitInside/1, - freeze/1,getAcceleratorTable/1,getBackgroundColour/1,getBackgroundStyle/1, - getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1, - getClientData/2,getClientSize/1,getContainingSizer/1,getCount/1,getCursor/1, - getDropTarget/1,getEventHandler/1,getExtraStyle/1,getFont/1,getForegroundColour/1, - getGrandParent/1,getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1, - getMinSize/1,getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1, +-export([append/2,append/3,appendStrings/2,cacheBestSize/2,canSetTransparent/1, + captureMouse/1,center/1,center/2,centerOnParent/1,centerOnParent/2, + centre/1,centre/2,centreOnParent/1,centreOnParent/2,clear/1,clearBackground/1, + clientToScreen/2,clientToScreen/3,close/1,close/2,connect/2,connect/3, + convertDialogToPixels/2,convertPixelsToDialog/2,delete/2,destroyChildren/1, + disable/1,disconnect/1,disconnect/2,disconnect/3,enable/1,enable/2, + findString/2,findString/3,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, + getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, + getCharHeight/1,getCharWidth/1,getChildren/1,getClientData/2,getClientSize/1, + getContainingSizer/1,getCount/1,getCursor/1,getDropTarget/1,getEventHandler/1, + getExtraStyle/1,getFont/1,getForegroundColour/1,getGrandParent/1, + getHandle/1,getHelpText/1,getId/1,getLabel/1,getMaxSize/1,getMinSize/1, + getName/1,getParent/1,getPosition/1,getRect/1,getScreenPosition/1, getScreenRect/1,getScrollPos/2,getScrollRange/2,getScrollThumb/2, getSelection/1,getSize/1,getSizer/1,getString/2,getStringSelection/1, getTextExtent/2,getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1, getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,hasScrollbar/2, hasTransparentBackground/1,hide/1,inheritAttributes/1,initDialog/1, - insert/3,insert/4,invalidateBestSize/1,isEmpty/1,isEnabled/1,isExposed/2, - isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,layout/1, - lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,move/3,move/4, - moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,navigate/2, - pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - select/2,setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2, - setBackgroundStyle/2,setCaret/2,setClientData/3,setClientSize/2,setClientSize/3, - setContainingSizer/2,setCursor/2,setDropTarget/2,setExtraStyle/2, - setFocus/1,setFocusFromKbd/1,setFont/2,setForegroundColour/2,setHelpText/2, - setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, - setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setScrollPos/3, - setScrollPos/4,setScrollbar/5,setScrollbar/6,setSelection/2,setSize/2, - setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4, - setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setString/3, - setStringSelection/2,setThemeEnabled/2,setToolTip/2,setVirtualSize/2, - setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, - setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, - show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, - update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). + insert/3,insert/4,invalidateBestSize/1,isDoubleBuffered/1,isEmpty/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,select/2,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientData/3, + setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, + setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, + setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, + setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, + setSelection/2,setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2, + setSizeHints/3,setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2, + setSizerAndFit/3,setString/3,setStringSelection/2,setThemeEnabled/2, + setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2, + setVirtualSizeHints/3,setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2, + setWindowVariant/2,shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1, + transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2, + validate/1,warpPointer/3]). -export_type([wxListBox/0]). %% @hidden @@ -278,6 +280,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxListCtrl.erl b/lib/wx/src/gen/wxListCtrl.erl index 491511b729..6750931fdb 100644 --- a/lib/wx/src/gen/wxListCtrl.erl +++ b/lib/wx/src/gen/wxListCtrl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -47,10 +47,10 @@ setSingleStyle/2,setSingleStyle/3,setTextColour/2,setWindowStyleFlag/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -62,27 +62,28 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundStyle/2,setCaret/2, - setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, - setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, - setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, - setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, - setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, - setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, - setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, - setWindowStyle/2,setWindowVariant/2,shouldInheritColours/1,show/1, - show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1,update/1, - updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundStyle/2,setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2, + setCursor/2,setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1, + setFocusFromKbd/1,setFont/2,setForegroundColour/2,setHelpText/2,setId/2, + setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, + setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setScrollPos/3, + setScrollPos/4,setScrollbar/5,setScrollbar/6,setSize/2,setSize/3,setSize/5, + setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,setSizer/2, + setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2,setToolTip/2, + setTransparent/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2, + setVirtualSizeHints/3,setVirtualSizeHints/4,setWindowStyle/2,setWindowVariant/2, + shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1, + transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2, + validate/1,warpPointer/3]). -export_type([wxListCtrl/0]). %% @hidden @@ -869,6 +870,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxListView.erl b/lib/wx/src/gen/wxListView.erl index 3720fe86c1..288afcee82 100644 --- a/lib/wx/src/gen/wxListView.erl +++ b/lib/wx/src/gen/wxListView.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,10 +34,10 @@ isSelected/2,select/2,select/3,setColumnImage/3]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -49,24 +49,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -168,6 +169,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxListbook.erl b/lib/wx/src/gen/wxListbook.erl index b5083c5746..6ea34e8eb1 100644 --- a/lib/wx/src/gen/wxListbook.erl +++ b/lib/wx/src/gen/wxListbook.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2013. All Rights Reserved. +%% Copyright Ericsson AB 2009-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -38,10 +38,10 @@ setPageSize/2,setPageText/3,setSelection/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -53,24 +53,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -383,6 +384,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxMDIChildFrame.erl b/lib/wx/src/gen/wxMDIChildFrame.erl index 05f07f1066..ed29e5431f 100644 --- a/lib/wx/src/gen/wxMDIChildFrame.erl +++ b/lib/wx/src/gen/wxMDIChildFrame.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -35,11 +35,11 @@ new/4,restore/1]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centerOnScreen/1,centerOnScreen/2,centre/1,centre/2, - centreOnParent/1,centreOnParent/2,centreOnScreen/1,centreOnScreen/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centerOnScreen/1,centerOnScreen/2, + centre/1,centre/2,centreOnParent/1,centreOnParent/2,centreOnScreen/1, + centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, createStatusBar/1,createStatusBar/2,createToolBar/1,createToolBar/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, @@ -55,26 +55,27 @@ getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1, - isActive/1,isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isFullScreen/1, - isIconized/1,isMaximized/1,isRetained/1,isShown/1,isTopLevel/1,layout/1, - lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,move/3,move/4, - moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,navigate/2, - pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,processCommand/2,raise/1,refresh/1, - refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, - reparent/2,requestUserAttention/1,requestUserAttention/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - sendSizeEvent/1,setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2, - setBackgroundStyle/2,setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2, - setCursor/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, - setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2, - setId/2,setLabel/2,setMaxSize/2,setMenuBar/2,setMinSize/2,setName/2, - setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,setPalette/2, - setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2, - setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, - setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setStatusBar/2,setStatusBarPane/2,setStatusText/2,setStatusText/3, - setStatusWidths/2,setThemeEnabled/2,setTitle/2,setToolBar/2,setToolTip/2, + isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3, + isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isRetained/1, + isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1, + makeModal/2,move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,processCommand/2, + raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1, + removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2, + screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3, + scrollWindow/4,sendSizeEvent/1,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, + setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, + setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2, + setMaxSize/2,setMenuBar/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, + setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setScrollPos/3, + setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2, + setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4, + setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setStatusBar/2, + setStatusBarPane/2,setStatusText/2,setStatusText/3,setStatusWidths/2, + setThemeEnabled/2,setTitle/2,setToolBar/2,setToolTip/2,setTransparent/2, setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3, setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2, shouldInheritColours/1,show/1,show/2,showFullScreen/2,showFullScreen/3, @@ -274,6 +275,14 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This). getIcon(This) -> wxTopLevelWindow:getIcon(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxMDIClientWindow.erl b/lib/wx/src/gen/wxMDIClientWindow.erl index 20569718f7..6f10627086 100644 --- a/lib/wx/src/gen/wxMDIClientWindow.erl +++ b/lib/wx/src/gen/wxMDIClientWindow.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -32,10 +32,10 @@ -export([createClient/2,createClient/3,destroy/1,new/0,new/1,new/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -47,24 +47,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -135,6 +136,14 @@ destroy(Obj=#wx_ref{type=Type}) -> ok. %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxMDIParentFrame.erl b/lib/wx/src/gen/wxMDIParentFrame.erl index 9aeba68ea3..47d9182d60 100644 --- a/lib/wx/src/gen/wxMDIParentFrame.erl +++ b/lib/wx/src/gen/wxMDIParentFrame.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -36,11 +36,11 @@ tile/1,tile/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centerOnScreen/1,centerOnScreen/2,centre/1,centre/2, - centreOnParent/1,centreOnParent/2,centreOnScreen/1,centreOnScreen/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centerOnScreen/1,centerOnScreen/2, + centre/1,centre/2,centreOnParent/1,centreOnParent/2,centreOnScreen/1, + centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, createStatusBar/1,createStatusBar/2,createToolBar/1,createToolBar/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, @@ -56,32 +56,32 @@ getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1, - isActive/1,isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isFullScreen/1, - isIconized/1,isMaximized/1,isRetained/1,isShown/1,isTopLevel/1,layout/1, - lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,maximize/1,maximize/2, - move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, - navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, - popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,processCommand/2, - raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1, - removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2, + isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3, + isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isRetained/1, + isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1, + makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2, + moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1, + popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4, + processCommand/2,raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3, + releaseMouse/1,removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2, screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3, scrollWindow/4,sendSizeEvent/1,setAcceleratorTable/2,setAutoLayout/2, setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, - setClientSize/3,setContainingSizer/2,setCursor/2,setDropTarget/2, - setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,setForegroundColour/2, - setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2,setMaxSize/2, - setMenuBar/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2, - setOwnForegroundColour/2,setPalette/2,setScrollPos/3,setScrollPos/4, - setScrollbar/5,setScrollbar/6,setShape/2,setSize/2,setSize/3,setSize/5, - setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,setSizer/2, - setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setStatusBar/2,setStatusBarPane/2, - setStatusText/2,setStatusText/3,setStatusWidths/2,setThemeEnabled/2, - setTitle/2,setToolBar/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, - setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, - show/1,show/2,showFullScreen/2,showFullScreen/3,thaw/1,transferDataFromWindow/1, - transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2, - validate/1,warpPointer/3]). + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, + setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, + setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2, + setMaxSize/2,setMenuBar/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, + setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setScrollPos/3, + setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2, + setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4, + setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setStatusBar/2, + setStatusBarPane/2,setStatusText/2,setStatusText/3,setStatusWidths/2, + setThemeEnabled/2,setTitle/2,setToolBar/2,setToolTip/2,setTransparent/2, + setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3, + setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2, + shouldInheritColours/1,show/1,show/2,showFullScreen/2,showFullScreen/3, + thaw/1,transferDataFromWindow/1,transferDataToWindow/1,update/1,updateWindowUI/1, + updateWindowUI/2,validate/1,warpPointer/3]). -export_type([wxMDIParentFrame/0]). %% @hidden @@ -313,6 +313,14 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This). getIcon(This) -> wxTopLevelWindow:getIcon(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxMenuBar.erl b/lib/wx/src/gen/wxMenuBar.erl index cb35015c08..5e879da5ed 100644 --- a/lib/wx/src/gen/wxMenuBar.erl +++ b/lib/wx/src/gen/wxMenuBar.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -36,10 +36,10 @@ setLabelTop/3]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,getBackgroundColour/1, getBackgroundStyle/1,getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1, @@ -51,24 +51,24 @@ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1, getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1, hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1, - initDialog/1,invalidateBestSize/1,isExposed/2,isExposed/3,isExposed/5, - isRetained/1,isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1, - makeModal/1,makeModal/2,move/2,move/3,move/4,moveAfterInTabOrder/2, - moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1, - popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4, - raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1, - removeChild/2,reparent/2,screenToClient/1,screenToClient/2,scrollLines/2, - scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2, - setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,setCaret/2, - setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, - setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, - setForegroundColour/2,setHelpText/2,setId/2,setMaxSize/2,setMinSize/2, - setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, + initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isExposed/2, + isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,layout/1, + lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,move/3,move/4, + moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,navigate/2, + pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, + popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, + refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, + screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, + setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, + setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, + setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setMaxSize/2, + setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -340,6 +340,14 @@ destroy(Obj=#wx_ref{type=Type}) -> ok. %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxMessageDialog.erl b/lib/wx/src/gen/wxMessageDialog.erl index f024145ed6..1fe99b2b88 100644 --- a/lib/wx/src/gen/wxMessageDialog.erl +++ b/lib/wx/src/gen/wxMessageDialog.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,11 +34,11 @@ -export([destroy/1,new/2,new/3]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centerOnScreen/1,centerOnScreen/2,centre/1,centre/2, - centreOnParent/1,centreOnParent/2,centreOnScreen/1,centreOnScreen/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centerOnScreen/1,centerOnScreen/2, + centre/1,centre/2,centreOnParent/1,centreOnParent/2,centreOnScreen/1, + centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, createButtonSizer/2,createStdDialogButtonSizer/2,destroyChildren/1, disable/1,disconnect/1,disconnect/2,disconnect/3,enable/1,enable/2, endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, @@ -53,25 +53,26 @@ getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1, - isActive/1,isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isFullScreen/1, - isIconized/1,isMaximized/1,isModal/1,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,maximize/1, - maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, - navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, - popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, - refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, - reparent/2,requestUserAttention/1,requestUserAttention/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2,setBackgroundColour/2, - setBackgroundStyle/2,setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2, - setCursor/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, - setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2, - setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, - setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setReturnCode/2, - setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2, - setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, - setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setTitle/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, + isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3, + isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isModal/1,isRetained/1, + isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1, + makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2, + moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1, + popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4, + raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1, + removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2, + screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3, + scrollWindow/4,setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, + setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, + setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2, + setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2, + setOwnForegroundColour/2,setPalette/2,setReturnCode/2,setScrollPos/3, + setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2, + setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4, + setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2, + setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3, setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,showFullScreen/2,showFullScreen/3,showModal/1,thaw/1, @@ -191,6 +192,14 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This). getIcon(This) -> wxTopLevelWindow:getIcon(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxMiniFrame.erl b/lib/wx/src/gen/wxMiniFrame.erl index 7622ddf0d2..f731cc5416 100644 --- a/lib/wx/src/gen/wxMiniFrame.erl +++ b/lib/wx/src/gen/wxMiniFrame.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,11 +34,11 @@ -export([create/4,create/5,destroy/1,new/0,new/3,new/4]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centerOnScreen/1,centerOnScreen/2,centre/1,centre/2, - centreOnParent/1,centreOnParent/2,centreOnScreen/1,centreOnScreen/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centerOnScreen/1,centerOnScreen/2, + centre/1,centre/2,centreOnParent/1,centreOnParent/2,centreOnScreen/1, + centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, createStatusBar/1,createStatusBar/2,createToolBar/1,createToolBar/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, @@ -54,32 +54,32 @@ getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1, - isActive/1,isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isFullScreen/1, - isIconized/1,isMaximized/1,isRetained/1,isShown/1,isTopLevel/1,layout/1, - lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,maximize/1,maximize/2, - move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, - navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, - popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,processCommand/2, - raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1, - removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2, + isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3, + isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isRetained/1, + isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1, + makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2, + moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1, + popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4, + processCommand/2,raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3, + releaseMouse/1,removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2, screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3, scrollWindow/4,sendSizeEvent/1,setAcceleratorTable/2,setAutoLayout/2, setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, - setClientSize/3,setContainingSizer/2,setCursor/2,setDropTarget/2, - setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,setForegroundColour/2, - setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2,setMaxSize/2, - setMenuBar/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2, - setOwnForegroundColour/2,setPalette/2,setScrollPos/3,setScrollPos/4, - setScrollbar/5,setScrollbar/6,setShape/2,setSize/2,setSize/3,setSize/5, - setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,setSizer/2, - setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setStatusBar/2,setStatusBarPane/2, - setStatusText/2,setStatusText/3,setStatusWidths/2,setThemeEnabled/2, - setTitle/2,setToolBar/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, - setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, - show/1,show/2,showFullScreen/2,showFullScreen/3,thaw/1,transferDataFromWindow/1, - transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2, - validate/1,warpPointer/3]). + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, + setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, + setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2, + setMaxSize/2,setMenuBar/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, + setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setScrollPos/3, + setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2, + setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4, + setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setStatusBar/2, + setStatusBarPane/2,setStatusText/2,setStatusText/3,setStatusWidths/2, + setThemeEnabled/2,setTitle/2,setToolBar/2,setToolTip/2,setTransparent/2, + setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3, + setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2, + shouldInheritColours/1,show/1,show/2,showFullScreen/2,showFullScreen/3, + thaw/1,transferDataFromWindow/1,transferDataToWindow/1,update/1,updateWindowUI/1, + updateWindowUI/2,validate/1,warpPointer/3]). -export_type([wxMiniFrame/0]). %% @hidden @@ -241,6 +241,14 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This). getIcon(This) -> wxTopLevelWindow:getIcon(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxMouseCaptureLostEvent.erl b/lib/wx/src/gen/wxMouseCaptureLostEvent.erl new file mode 100644 index 0000000000..a7e68a2d2f --- /dev/null +++ b/lib/wx/src/gen/wxMouseCaptureLostEvent.erl @@ -0,0 +1,65 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2015. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% This file is generated DO NOT EDIT + +%% @doc See external documentation: <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxmousecapturelostevent.html">wxMouseCaptureLostEvent</a>. +%% <dl><dt>Use {@link wxEvtHandler:connect/3.} with EventType:</dt> +%% <dd><em>mouse_capture_lost</em></dd></dl> +%% See also the message variant {@link wxEvtHandler:wxMouseCaptureLost(). #wxMouseCaptureLost{}} event record type. +%% +%% <p>This class is derived (and can use functions) from: +%% <br />{@link wxEvent} +%% </p> +%% @type wxMouseCaptureLostEvent(). 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(wxMouseCaptureLostEvent). +-include("wxe.hrl"). +-export([]). + +%% inherited exports +-export([getId/1,getSkipped/1,getTimestamp/1,isCommandEvent/1,parent_class/1, + resumePropagation/2,shouldPropagate/1,skip/1,skip/2,stopPropagation/1]). + +-export_type([wxMouseCaptureLostEvent/0]). +%% @hidden +parent_class(wxEvent) -> true; +parent_class(_Class) -> erlang:error({badtype, ?MODULE}). + +-type wxMouseCaptureLostEvent() :: wx:wx_object(). + %% From wxEvent +%% @hidden +stopPropagation(This) -> wxEvent:stopPropagation(This). +%% @hidden +skip(This, Options) -> wxEvent:skip(This, Options). +%% @hidden +skip(This) -> wxEvent:skip(This). +%% @hidden +shouldPropagate(This) -> wxEvent:shouldPropagate(This). +%% @hidden +resumePropagation(This,PropagationLevel) -> wxEvent:resumePropagation(This,PropagationLevel). +%% @hidden +isCommandEvent(This) -> wxEvent:isCommandEvent(This). +%% @hidden +getTimestamp(This) -> wxEvent:getTimestamp(This). +%% @hidden +getSkipped(This) -> wxEvent:getSkipped(This). +%% @hidden +getId(This) -> wxEvent:getId(This). diff --git a/lib/wx/src/gen/wxMultiChoiceDialog.erl b/lib/wx/src/gen/wxMultiChoiceDialog.erl index e79f11ef7d..96e9c070a3 100644 --- a/lib/wx/src/gen/wxMultiChoiceDialog.erl +++ b/lib/wx/src/gen/wxMultiChoiceDialog.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,11 +34,11 @@ -export([destroy/1,getSelections/1,new/0,new/4,new/5,setSelections/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centerOnScreen/1,centerOnScreen/2,centre/1,centre/2, - centreOnParent/1,centreOnParent/2,centreOnScreen/1,centreOnScreen/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centerOnScreen/1,centerOnScreen/2, + centre/1,centre/2,centreOnParent/1,centreOnParent/2,centreOnScreen/1, + centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, createButtonSizer/2,createStdDialogButtonSizer/2,destroyChildren/1, disable/1,disconnect/1,disconnect/2,disconnect/3,enable/1,enable/2, endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, @@ -53,25 +53,26 @@ getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1, - isActive/1,isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isFullScreen/1, - isIconized/1,isMaximized/1,isModal/1,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,maximize/1, - maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, - navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, - popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, - refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, - reparent/2,requestUserAttention/1,requestUserAttention/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2,setBackgroundColour/2, - setBackgroundStyle/2,setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2, - setCursor/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, - setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2, - setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, - setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setReturnCode/2, - setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2, - setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, - setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setTitle/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, + isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3, + isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isModal/1,isRetained/1, + isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1, + makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2, + moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1, + popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4, + raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1, + removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2, + screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3, + scrollWindow/4,setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, + setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, + setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2, + setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2, + setOwnForegroundColour/2,setPalette/2,setReturnCode/2,setScrollPos/3, + setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2, + setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4, + setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2, + setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3, setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,showFullScreen/2,showFullScreen/3,showModal/1,thaw/1, @@ -216,6 +217,14 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This). getIcon(This) -> wxTopLevelWindow:getIcon(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxNotebook.erl b/lib/wx/src/gen/wxNotebook.erl index 16c2d4fc6f..5011375aad 100644 --- a/lib/wx/src/gen/wxNotebook.erl +++ b/lib/wx/src/gen/wxNotebook.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -38,10 +38,10 @@ setPadding/2,setPageImage/3,setPageSize/2,setPageText/3,setSelection/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -53,24 +53,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -408,6 +409,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxOverlay.erl b/lib/wx/src/gen/wxOverlay.erl new file mode 100644 index 0000000000..7da3ece657 --- /dev/null +++ b/lib/wx/src/gen/wxOverlay.erl @@ -0,0 +1,57 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2015. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% This file is generated DO NOT EDIT + +%% @doc See external documentation: <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxoverlay.html">wxOverlay</a>. +%% @type wxOverlay(). 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(wxOverlay). +-include("wxe.hrl"). +-export([destroy/1,new/0,reset/1]). + +%% inherited exports +-export([parent_class/1]). + +-export_type([wxOverlay/0]). +%% @hidden +parent_class(_Class) -> erlang:error({badtype, ?MODULE}). + +-type wxOverlay() :: wx:wx_object(). +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxoverlay.html#wxoverlaywxoverlay">external documentation</a>. +-spec new() -> wxOverlay(). +new() -> + wxe_util:construct(?wxOverlay_new, + <<>>). + +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxoverlay.html#wxoverlayreset">external documentation</a>. +-spec reset(This) -> ok when + This::wxOverlay(). +reset(#wx_ref{type=ThisT,ref=ThisRef}) -> + ?CLASS(ThisT,wxOverlay), + wxe_util:cast(?wxOverlay_Reset, + <<ThisRef:32/?UI>>). + +%% @doc Destroys this object, do not use object again +-spec destroy(This::wxOverlay()) -> ok. +destroy(Obj=#wx_ref{type=Type}) -> + ?CLASS(Type,wxOverlay), + wxe_util:destroy(?wxOverlay_destruct,Obj), + ok. diff --git a/lib/wx/src/gen/wxPanel.erl b/lib/wx/src/gen/wxPanel.erl index 5b6d4a2974..ceb894fe31 100644 --- a/lib/wx/src/gen/wxPanel.erl +++ b/lib/wx/src/gen/wxPanel.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -32,10 +32,10 @@ -export([destroy/1,initDialog/1,new/0,new/1,new/2,new/5,new/6,setFocusIgnoringChildren/1]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -47,24 +47,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,invalidateBestSize/1,isEnabled/1,isExposed/2, - isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1,layout/1, - lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,move/3,move/4, - moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,navigate/2, - pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -154,6 +155,14 @@ destroy(Obj=#wx_ref{type=Type}) -> ok. %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxPasswordEntryDialog.erl b/lib/wx/src/gen/wxPasswordEntryDialog.erl index da9a711405..ac3f1c9d8c 100644 --- a/lib/wx/src/gen/wxPasswordEntryDialog.erl +++ b/lib/wx/src/gen/wxPasswordEntryDialog.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -35,11 +35,11 @@ -export([destroy/1,new/2,new/3]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centerOnScreen/1,centerOnScreen/2,centre/1,centre/2, - centreOnParent/1,centreOnParent/2,centreOnScreen/1,centreOnScreen/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centerOnScreen/1,centerOnScreen/2, + centre/1,centre/2,centreOnParent/1,centreOnParent/2,centreOnScreen/1, + centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, createButtonSizer/2,createStdDialogButtonSizer/2,destroyChildren/1, disable/1,disconnect/1,disconnect/2,disconnect/3,enable/1,enable/2, endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, @@ -54,8 +54,8 @@ getTitle/1,getToolTip/1,getUpdateRegion/1,getValue/1,getVirtualSize/1, getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,hasScrollbar/2, hasTransparentBackground/1,hide/1,iconize/1,iconize/2,inheritAttributes/1, - initDialog/1,invalidateBestSize/1,isActive/1,isEnabled/1,isExposed/2, - isExposed/3,isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1, + initDialog/1,invalidateBestSize/1,isActive/1,isDoubleBuffered/1,isEnabled/1, + isExposed/2,isExposed/3,isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1, isModal/1,isRetained/1,isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1, lower/1,makeModal/1,makeModal/2,maximize/1,maximize/2,move/2,move/3, move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,navigate/2, @@ -66,19 +66,19 @@ scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2, setAffirmativeId/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, - setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, - setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2, - setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2, - setOwnForegroundColour/2,setPalette/2,setReturnCode/2,setScrollPos/3, - setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2, - setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4, - setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2, - setTitle/2,setToolTip/2,setValue/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, - setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, - show/1,show/2,showFullScreen/2,showFullScreen/3,showModal/1,thaw/1, - transferDataFromWindow/1,transferDataToWindow/1,update/1,updateWindowUI/1, - updateWindowUI/2,validate/1,warpPointer/3]). + setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, + setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2, + setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, + setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setReturnCode/2, + setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2, + setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, + setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, + setThemeEnabled/2,setTitle/2,setToolTip/2,setTransparent/2,setValue/2, + setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3, + setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2, + shouldInheritColours/1,show/1,show/2,showFullScreen/2,showFullScreen/3, + showModal/1,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, + update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). -export_type([wxPasswordEntryDialog/0]). %% @hidden @@ -201,6 +201,14 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This). getIcon(This) -> wxTopLevelWindow:getIcon(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxPickerBase.erl b/lib/wx/src/gen/wxPickerBase.erl index 74de8bf7f1..bbdeaf6af8 100644 --- a/lib/wx/src/gen/wxPickerBase.erl +++ b/lib/wx/src/gen/wxPickerBase.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -36,10 +36,10 @@ setTextCtrlGrowable/1,setTextCtrlGrowable/2,setTextCtrlProportion/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -51,24 +51,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -213,6 +214,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxPopupTransientWindow.erl b/lib/wx/src/gen/wxPopupTransientWindow.erl index 40a63b09ec..c07c6e239e 100644 --- a/lib/wx/src/gen/wxPopupTransientWindow.erl +++ b/lib/wx/src/gen/wxPopupTransientWindow.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2014. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -33,10 +33,10 @@ -export([destroy/1,dismiss/1,new/0,new/1,new/2,popup/1,popup/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -48,24 +48,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,position/3,raise/1,refresh/1,refresh/2, - refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,reparent/2, - screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3, - scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2, - setBackgroundStyle/2,setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2, - setCursor/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, - setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,position/3,raise/1, + refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, + setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, + setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -145,6 +146,14 @@ destroy(Obj=#wx_ref{type=Type}) -> position(This,PtOrigin,Size) -> wxPopupWindow:position(This,PtOrigin,Size). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxPopupWindow.erl b/lib/wx/src/gen/wxPopupWindow.erl index 41390e08e7..439f5fac54 100644 --- a/lib/wx/src/gen/wxPopupWindow.erl +++ b/lib/wx/src/gen/wxPopupWindow.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2014. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -32,10 +32,10 @@ -export([create/2,create/3,destroy/1,new/0,new/1,new/2,position/3]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -47,24 +47,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -142,6 +143,14 @@ destroy(Obj=#wx_ref{type=Type}) -> ok. %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxPreviewCanvas.erl b/lib/wx/src/gen/wxPreviewCanvas.erl index 91d0672def..67357dbd65 100644 --- a/lib/wx/src/gen/wxPreviewCanvas.erl +++ b/lib/wx/src/gen/wxPreviewCanvas.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -35,10 +35,10 @@ %% inherited exports -export([cacheBestSize/2,calcScrolledPosition/2,calcScrolledPosition/3,calcUnscrolledPosition/2, - calcUnscrolledPosition/3,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, + calcUnscrolledPosition/3,canSetTransparent/1,captureMouse/1,center/1, + center/2,centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, doPrepareDC/2,enable/1,enable/2,enableScrolling/3,findWindow/2,fit/1, fitInside/1,freeze/1,getAcceleratorTable/1,getBackgroundColour/1, @@ -51,25 +51,26 @@ getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3, getToolTip/1,getUpdateRegion/1,getViewStart/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,prepareDC/2,raise/1,refresh/1,refresh/2, - refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2,reparent/2, - screenToClient/1,screenToClient/2,scroll/3,scrollLines/2,scrollPages/2, - scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, - setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, - setClientSize/3,setContainingSizer/2,setCursor/2,setDropTarget/2, - setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFocusIgnoringChildren/1, - setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, - setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, - setPalette/2,setScrollPos/3,setScrollPos/4,setScrollRate/3,setScrollbar/5, - setScrollbar/6,setScrollbars/5,setScrollbars/6,setSize/2,setSize/3, - setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,setSizer/2, - setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setTargetWindow/2,setThemeEnabled/2, - setToolTip/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,prepareDC/2, + raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1, + removeChild/2,reparent/2,screenToClient/1,screenToClient/2,scroll/3, + scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2, + setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,setCaret/2, + setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, + setFocusIgnoringChildren/1,setFont/2,setForegroundColour/2,setHelpText/2, + setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, + setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setScrollPos/3, + setScrollPos/4,setScrollRate/3,setScrollbar/5,setScrollbar/6,setScrollbars/5, + setScrollbars/6,setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2, + setSizeHints/3,setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2, + setSizerAndFit/3,setTargetWindow/2,setThemeEnabled/2,setToolTip/2, + setTransparent/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2, setVirtualSizeHints/3,setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2, setWindowVariant/2,shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1, transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2, @@ -120,6 +121,14 @@ setFocusIgnoringChildren(This) -> wxPanel:setFocusIgnoringChildren(This). initDialog(This) -> wxPanel:initDialog(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxPreviewControlBar.erl b/lib/wx/src/gen/wxPreviewControlBar.erl index 9bc290aef8..0e1828e87b 100644 --- a/lib/wx/src/gen/wxPreviewControlBar.erl +++ b/lib/wx/src/gen/wxPreviewControlBar.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,10 +34,10 @@ new/4,setZoomControl/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -49,24 +49,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFocusIgnoringChildren/1, setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -151,6 +152,14 @@ setFocusIgnoringChildren(This) -> wxPanel:setFocusIgnoringChildren(This). initDialog(This) -> wxPanel:initDialog(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxPreviewFrame.erl b/lib/wx/src/gen/wxPreviewFrame.erl index 9423fc2333..fe684478a5 100644 --- a/lib/wx/src/gen/wxPreviewFrame.erl +++ b/lib/wx/src/gen/wxPreviewFrame.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -35,11 +35,11 @@ onCloseWindow/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centerOnScreen/1,centerOnScreen/2,centre/1,centre/2, - centreOnParent/1,centreOnParent/2,centreOnScreen/1,centreOnScreen/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centerOnScreen/1,centerOnScreen/2, + centre/1,centre/2,centreOnParent/1,centreOnParent/2,centreOnScreen/1, + centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, createStatusBar/1,createStatusBar/2,createToolBar/1,createToolBar/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, @@ -55,32 +55,32 @@ getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1, - isActive/1,isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isFullScreen/1, - isIconized/1,isMaximized/1,isRetained/1,isShown/1,isTopLevel/1,layout/1, - lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,maximize/1,maximize/2, - move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, - navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, - popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,processCommand/2, - raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1, - removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2, + isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3, + isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isRetained/1, + isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1, + makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2, + moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1, + popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4, + processCommand/2,raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3, + releaseMouse/1,removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2, screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3, scrollWindow/4,sendSizeEvent/1,setAcceleratorTable/2,setAutoLayout/2, setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, - setClientSize/3,setContainingSizer/2,setCursor/2,setDropTarget/2, - setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,setForegroundColour/2, - setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2,setMaxSize/2, - setMenuBar/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2, - setOwnForegroundColour/2,setPalette/2,setScrollPos/3,setScrollPos/4, - setScrollbar/5,setScrollbar/6,setShape/2,setSize/2,setSize/3,setSize/5, - setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,setSizer/2, - setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setStatusBar/2,setStatusBarPane/2, - setStatusText/2,setStatusText/3,setStatusWidths/2,setThemeEnabled/2, - setTitle/2,setToolBar/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, - setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, - show/1,show/2,showFullScreen/2,showFullScreen/3,thaw/1,transferDataFromWindow/1, - transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2, - validate/1,warpPointer/3]). + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, + setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, + setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2, + setMaxSize/2,setMenuBar/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, + setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setScrollPos/3, + setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2, + setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4, + setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setStatusBar/2, + setStatusBarPane/2,setStatusText/2,setStatusText/3,setStatusWidths/2, + setThemeEnabled/2,setTitle/2,setToolBar/2,setToolTip/2,setTransparent/2, + setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3, + setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2, + shouldInheritColours/1,show/1,show/2,showFullScreen/2,showFullScreen/3, + thaw/1,transferDataFromWindow/1,transferDataToWindow/1,update/1,updateWindowUI/1, + updateWindowUI/2,validate/1,warpPointer/3]). -export_type([wxPreviewFrame/0]). %% @hidden @@ -244,6 +244,14 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This). getIcon(This) -> wxTopLevelWindow:getIcon(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxPrintDialog.erl b/lib/wx/src/gen/wxPrintDialog.erl index 4f253b4988..a337089d5a 100644 --- a/lib/wx/src/gen/wxPrintDialog.erl +++ b/lib/wx/src/gen/wxPrintDialog.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,11 +34,11 @@ -export([destroy/1,getPrintDC/1,getPrintDialogData/1,new/1,new/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centerOnScreen/1,centerOnScreen/2,centre/1,centre/2, - centreOnParent/1,centreOnParent/2,centreOnScreen/1,centreOnScreen/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centerOnScreen/1,centerOnScreen/2, + centre/1,centre/2,centreOnParent/1,centreOnParent/2,centreOnScreen/1, + centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, createButtonSizer/2,createStdDialogButtonSizer/2,destroyChildren/1, disable/1,disconnect/1,disconnect/2,disconnect/3,enable/1,enable/2, endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, @@ -53,25 +53,26 @@ getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1, - isActive/1,isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isFullScreen/1, - isIconized/1,isMaximized/1,isModal/1,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,maximize/1, - maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, - navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, - popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, - refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, - reparent/2,requestUserAttention/1,requestUserAttention/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2,setBackgroundColour/2, - setBackgroundStyle/2,setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2, - setCursor/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, - setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2, - setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, - setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setReturnCode/2, - setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2, - setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, - setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setTitle/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, + isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3, + isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isModal/1,isRetained/1, + isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1, + makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2, + moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1, + popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4, + raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1, + removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2, + screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3, + scrollWindow/4,setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, + setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, + setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2, + setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2, + setOwnForegroundColour/2,setPalette/2,setReturnCode/2,setScrollPos/3, + setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2, + setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4, + setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2, + setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3, setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,showFullScreen/2,showFullScreen/3,showModal/1,thaw/1, @@ -213,6 +214,14 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This). getIcon(This) -> wxTopLevelWindow:getIcon(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxProgressDialog.erl b/lib/wx/src/gen/wxProgressDialog.erl index 544d67a7d8..665b900729 100644 --- a/lib/wx/src/gen/wxProgressDialog.erl +++ b/lib/wx/src/gen/wxProgressDialog.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,11 +34,11 @@ -export([destroy/1,new/2,new/3,resume/1,update/1,update/2,update/3]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centerOnScreen/1,centerOnScreen/2,centre/1,centre/2, - centreOnParent/1,centreOnParent/2,centreOnScreen/1,centreOnScreen/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centerOnScreen/1,centerOnScreen/2, + centre/1,centre/2,centreOnParent/1,centreOnParent/2,centreOnScreen/1, + centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, createButtonSizer/2,createStdDialogButtonSizer/2,destroyChildren/1, disable/1,disconnect/1,disconnect/2,disconnect/3,enable/1,enable/2, endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, @@ -53,25 +53,26 @@ getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1, - isActive/1,isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isFullScreen/1, - isIconized/1,isMaximized/1,isModal/1,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,maximize/1, - maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, - navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, - popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, - refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, - reparent/2,requestUserAttention/1,requestUserAttention/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2,setBackgroundColour/2, - setBackgroundStyle/2,setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2, - setCursor/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, - setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2, - setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, - setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setReturnCode/2, - setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2, - setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, - setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setTitle/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, + isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3, + isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isModal/1,isRetained/1, + isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1, + makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2, + moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1, + popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4, + raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1, + removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2, + screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3, + scrollWindow/4,setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, + setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, + setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2, + setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2, + setOwnForegroundColour/2,setPalette/2,setReturnCode/2,setScrollPos/3, + setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2, + setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4, + setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2, + setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3, setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,showFullScreen/2,showFullScreen/3,showModal/1,thaw/1, @@ -228,6 +229,14 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This). getIcon(This) -> wxTopLevelWindow:getIcon(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxRadioBox.erl b/lib/wx/src/gen/wxRadioBox.erl index 331c83d695..5ef1deff66 100644 --- a/lib/wx/src/gen/wxRadioBox.erl +++ b/lib/wx/src/gen/wxRadioBox.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -36,10 +36,10 @@ setItemHelpText/3,setItemToolTip/3,setSelection/2,show/1,show/2,show/3]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1,getBackgroundColour/1, getBackgroundStyle/1,getBestSize/1,getCaret/1,getCharHeight/1,getCharWidth/1, @@ -51,24 +51,24 @@ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1, getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1, hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1, - initDialog/1,invalidateBestSize/1,isEnabled/1,isExposed/2,isExposed/3, - isExposed/5,isRetained/1,isShown/1,isTopLevel/1,layout/1,lineDown/1, - lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,move/3,move/4,moveAfterInTabOrder/2, - moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1, - popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4, - raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1, - removeChild/2,reparent/2,screenToClient/1,screenToClient/2,scrollLines/2, - scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2, - setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,setCaret/2, - setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, - setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, - setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, + initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1, + isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, + layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, + move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, + navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, + popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, + refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, + screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, + setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, + setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, + setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, thaw/1,transferDataFromWindow/1,transferDataToWindow/1,update/1,updateWindowUI/1, updateWindowUI/2,validate/1,warpPointer/3]). @@ -348,6 +348,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxRadioButton.erl b/lib/wx/src/gen/wxRadioButton.erl index ab08c5807e..3b4689a27b 100644 --- a/lib/wx/src/gen/wxRadioButton.erl +++ b/lib/wx/src/gen/wxRadioButton.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -33,10 +33,10 @@ -export([create/4,create/5,destroy/1,getValue/1,new/0,new/3,new/4,setValue/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -48,24 +48,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -171,6 +172,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxSashLayoutWindow.erl b/lib/wx/src/gen/wxSashLayoutWindow.erl index c64ed77f31..223c07419d 100644 --- a/lib/wx/src/gen/wxSashLayoutWindow.erl +++ b/lib/wx/src/gen/wxSashLayoutWindow.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,10 +34,10 @@ new/2,setAlignment/2,setDefaultSize/2,setOrientation/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -51,9 +51,9 @@ getTextExtent/2,getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1, getWindowStyleFlag/1,getWindowVariant/1,hasCapture/1,hasScrollbar/2, hasTransparentBackground/1,hide/1,inheritAttributes/1,initDialog/1, - invalidateBestSize/1,isEnabled/1,isExposed/2,isExposed/3,isExposed/5, - isRetained/1,isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1, - makeModal/1,makeModal/2,move/2,move/3,move/4,moveAfterInTabOrder/2, + invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3, + isExposed/5,isRetained/1,isShown/1,isTopLevel/1,layout/1,lineDown/1, + lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,move/3,move/4,moveAfterInTabOrder/2, moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1, popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4, raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1, @@ -61,17 +61,17 @@ scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2, setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,setCaret/2, setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, - setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, - setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, + setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, + setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMaximumSizeX/2,setMaximumSizeY/2,setMinSize/2,setMinimumSizeX/2, setMinimumSizeY/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2, setOwnForegroundColour/2,setPalette/2,setSashVisible/3,setScrollPos/3, setScrollPos/4,setScrollbar/5,setScrollbar/6,setSize/2,setSize/3,setSize/5, setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,setSizer/2, setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2,setToolTip/2, - setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3, - setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2, - shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1, + setTransparent/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2, + setVirtualSizeHints/3,setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2, + setWindowVariant/2,shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1, transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2, validate/1,warpPointer/3]). @@ -220,6 +220,14 @@ getMaximumSizeX(This) -> wxSashWindow:getMaximumSizeX(This). getSashVisible(This,Edge) -> wxSashWindow:getSashVisible(This,Edge). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxSashWindow.erl b/lib/wx/src/gen/wxSashWindow.erl index 7f9f15aa58..4a39726ffd 100644 --- a/lib/wx/src/gen/wxSashWindow.erl +++ b/lib/wx/src/gen/wxSashWindow.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,10 +34,10 @@ setMinimumSizeX/2,setMinimumSizeY/2,setSashVisible/3]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -49,24 +49,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -207,6 +208,14 @@ destroy(Obj=#wx_ref{type=Type}) -> ok. %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxScrollBar.erl b/lib/wx/src/gen/wxScrollBar.erl index 97c30f2972..ccddf84835 100644 --- a/lib/wx/src/gen/wxScrollBar.erl +++ b/lib/wx/src/gen/wxScrollBar.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,10 +34,10 @@ getThumbSize/1,new/0,new/2,new/3,setScrollbar/5,setScrollbar/6,setThumbPosition/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -49,25 +49,26 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setSize/2,setSize/3,setSize/5, setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,setSizer/2, setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2,setToolTip/2, - setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3, - setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2, - shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1, + setTransparent/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2, + setVirtualSizeHints/3,setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2, + setWindowVariant/2,shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1, transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2, validate/1,warpPointer/3]). @@ -215,6 +216,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxScrolledWindow.erl b/lib/wx/src/gen/wxScrolledWindow.erl index 5513014c31..7c807980b4 100644 --- a/lib/wx/src/gen/wxScrolledWindow.erl +++ b/lib/wx/src/gen/wxScrolledWindow.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -36,10 +36,10 @@ scroll/3,setScrollRate/3,setScrollbars/5,setScrollbars/6,setTargetWindow/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -51,24 +51,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFocusIgnoringChildren/1, setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -258,6 +259,14 @@ setFocusIgnoringChildren(This) -> wxPanel:setFocusIgnoringChildren(This). initDialog(This) -> wxPanel:initDialog(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxSingleChoiceDialog.erl b/lib/wx/src/gen/wxSingleChoiceDialog.erl index c5743c4ea1..641cb2836f 100644 --- a/lib/wx/src/gen/wxSingleChoiceDialog.erl +++ b/lib/wx/src/gen/wxSingleChoiceDialog.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,11 +34,11 @@ -export([destroy/1,getSelection/1,getStringSelection/1,new/0,new/4,new/5,setSelection/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centerOnScreen/1,centerOnScreen/2,centre/1,centre/2, - centreOnParent/1,centreOnParent/2,centreOnScreen/1,centreOnScreen/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centerOnScreen/1,centerOnScreen/2, + centre/1,centre/2,centreOnParent/1,centreOnParent/2,centreOnScreen/1, + centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, createButtonSizer/2,createStdDialogButtonSizer/2,destroyChildren/1, disable/1,disconnect/1,disconnect/2,disconnect/3,enable/1,enable/2, endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, @@ -53,25 +53,26 @@ getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1, - isActive/1,isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isFullScreen/1, - isIconized/1,isMaximized/1,isModal/1,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,maximize/1, - maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, - navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, - popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, - refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, - reparent/2,requestUserAttention/1,requestUserAttention/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2,setBackgroundColour/2, - setBackgroundStyle/2,setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2, - setCursor/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, - setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2, - setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, - setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setReturnCode/2, - setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2, - setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, - setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setTitle/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, + isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3, + isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isModal/1,isRetained/1, + isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1, + makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2, + moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1, + popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4, + raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1, + removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2, + screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3, + scrollWindow/4,setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, + setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, + setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2, + setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2, + setOwnForegroundColour/2,setPalette/2,setReturnCode/2,setScrollPos/3, + setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2, + setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4, + setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2, + setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3, setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,showFullScreen/2,showFullScreen/3,showModal/1,thaw/1, @@ -223,6 +224,14 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This). getIcon(This) -> wxTopLevelWindow:getIcon(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxSlider.erl b/lib/wx/src/gen/wxSlider.erl index 93ec783e48..02103aed01 100644 --- a/lib/wx/src/gen/wxSlider.erl +++ b/lib/wx/src/gen/wxSlider.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -35,10 +35,10 @@ setRange/3,setThumbLength/2,setValue/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -50,24 +50,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -247,6 +248,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxSpinButton.erl b/lib/wx/src/gen/wxSpinButton.erl index 52d71dd9c2..82b48f87da 100644 --- a/lib/wx/src/gen/wxSpinButton.erl +++ b/lib/wx/src/gen/wxSpinButton.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,10 +34,10 @@ new/2,setRange/3,setValue/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -49,24 +49,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -195,6 +196,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxSpinCtrl.erl b/lib/wx/src/gen/wxSpinCtrl.erl index 6fe5197359..89fa971543 100644 --- a/lib/wx/src/gen/wxSpinCtrl.erl +++ b/lib/wx/src/gen/wxSpinCtrl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,10 +34,10 @@ new/2,setRange/3,setSelection/3,setValue/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -49,24 +49,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -232,6 +233,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxSplashScreen.erl b/lib/wx/src/gen/wxSplashScreen.erl index 6c12907d38..fad8cfcd8e 100644 --- a/lib/wx/src/gen/wxSplashScreen.erl +++ b/lib/wx/src/gen/wxSplashScreen.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,11 +34,11 @@ -export([destroy/1,getSplashStyle/1,getTimeout/1,new/0,new/5,new/6]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centerOnScreen/1,centerOnScreen/2,centre/1,centre/2, - centreOnParent/1,centreOnParent/2,centreOnScreen/1,centreOnScreen/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centerOnScreen/1,centerOnScreen/2, + centre/1,centre/2,centreOnParent/1,centreOnParent/2,centreOnScreen/1, + centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, createStatusBar/1,createStatusBar/2,createToolBar/1,createToolBar/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, @@ -54,32 +54,32 @@ getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1, - isActive/1,isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isFullScreen/1, - isIconized/1,isMaximized/1,isRetained/1,isShown/1,isTopLevel/1,layout/1, - lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,maximize/1,maximize/2, - move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, - navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, - popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,processCommand/2, - raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1, - removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2, + isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3, + isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isRetained/1, + isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1, + makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2, + moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1, + popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4, + processCommand/2,raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3, + releaseMouse/1,removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2, screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3, scrollWindow/4,sendSizeEvent/1,setAcceleratorTable/2,setAutoLayout/2, setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, - setClientSize/3,setContainingSizer/2,setCursor/2,setDropTarget/2, - setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,setForegroundColour/2, - setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2,setMaxSize/2, - setMenuBar/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2, - setOwnForegroundColour/2,setPalette/2,setScrollPos/3,setScrollPos/4, - setScrollbar/5,setScrollbar/6,setShape/2,setSize/2,setSize/3,setSize/5, - setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4,setSizer/2, - setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setStatusBar/2,setStatusBarPane/2, - setStatusText/2,setStatusText/3,setStatusWidths/2,setThemeEnabled/2, - setTitle/2,setToolBar/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, - setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, - show/1,show/2,showFullScreen/2,showFullScreen/3,thaw/1,transferDataFromWindow/1, - transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2, - validate/1,warpPointer/3]). + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, + setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, + setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2, + setMaxSize/2,setMenuBar/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, + setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setScrollPos/3, + setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2, + setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4, + setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setStatusBar/2, + setStatusBarPane/2,setStatusText/2,setStatusText/3,setStatusWidths/2, + setThemeEnabled/2,setTitle/2,setToolBar/2,setToolTip/2,setTransparent/2, + setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3, + setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2, + shouldInheritColours/1,show/1,show/2,showFullScreen/2,showFullScreen/3, + thaw/1,transferDataFromWindow/1,transferDataToWindow/1,update/1,updateWindowUI/1, + updateWindowUI/2,validate/1,warpPointer/3]). -export_type([wxSplashScreen/0]). %% @hidden @@ -230,6 +230,14 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This). getIcon(This) -> wxTopLevelWindow:getIcon(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxSplitterWindow.erl b/lib/wx/src/gen/wxSplitterWindow.erl index b6b7a328ad..7db8dc60c4 100644 --- a/lib/wx/src/gen/wxSplitterWindow.erl +++ b/lib/wx/src/gen/wxSplitterWindow.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2013. All Rights Reserved. +%% Copyright Ericsson AB 2009-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -37,10 +37,10 @@ unsplit/1,unsplit/2,updateSize/1]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -52,24 +52,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -358,6 +359,14 @@ destroy(Obj=#wx_ref{type=Type}) -> ok. %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxStaticBitmap.erl b/lib/wx/src/gen/wxStaticBitmap.erl index 1673e3b62d..4da50262b9 100644 --- a/lib/wx/src/gen/wxStaticBitmap.erl +++ b/lib/wx/src/gen/wxStaticBitmap.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -33,10 +33,10 @@ -export([create/4,create/5,destroy/1,getBitmap/1,new/0,new/3,new/4,setBitmap/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -48,24 +48,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -167,6 +168,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxStaticBox.erl b/lib/wx/src/gen/wxStaticBox.erl index f6a715f051..04584f23b2 100644 --- a/lib/wx/src/gen/wxStaticBox.erl +++ b/lib/wx/src/gen/wxStaticBox.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -33,10 +33,10 @@ -export([create/4,create/5,destroy/1,new/0,new/3,new/4]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -48,24 +48,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -150,6 +151,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxStaticLine.erl b/lib/wx/src/gen/wxStaticLine.erl index 6306a01c62..6d23c5ac3d 100644 --- a/lib/wx/src/gen/wxStaticLine.erl +++ b/lib/wx/src/gen/wxStaticLine.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,10 +34,10 @@ new/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -49,24 +49,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -167,6 +168,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxStaticText.erl b/lib/wx/src/gen/wxStaticText.erl index 4c5d72d5e7..635f29a1e8 100644 --- a/lib/wx/src/gen/wxStaticText.erl +++ b/lib/wx/src/gen/wxStaticText.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -33,10 +33,10 @@ -export([create/4,create/5,destroy/1,getLabel/1,new/0,new/3,new/4,setLabel/2,wrap/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -48,24 +48,25 @@ getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3, getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setMaxSize/2,setMinSize/2, setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -173,6 +174,14 @@ destroy(Obj=#wx_ref{type=Type}) -> %% From wxControl %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxStatusBar.erl b/lib/wx/src/gen/wxStatusBar.erl index 254b9b0236..2cd0d4a43e 100644 --- a/lib/wx/src/gen/wxStatusBar.erl +++ b/lib/wx/src/gen/wxStatusBar.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -35,10 +35,10 @@ setStatusStyles/2,setStatusText/2,setStatusText/3,setStatusWidths/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -50,24 +50,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -295,6 +296,14 @@ destroy(Obj=#wx_ref{type=Type}) -> ok. %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxStyledTextCtrl.erl b/lib/wx/src/gen/wxStyledTextCtrl.erl index 4598cc7609..8e629db9ff 100644 --- a/lib/wx/src/gen/wxStyledTextCtrl.erl +++ b/lib/wx/src/gen/wxStyledTextCtrl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -135,10 +135,10 @@ wordRightExtend/1,wordStartPosition/3,wrapCount/2,zoomIn/1,zoomOut/1]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -150,27 +150,27 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lower/1,makeModal/1,makeModal/2,move/2,move/3,move/4,moveAfterInTabOrder/2, - moveBeforeInTabOrder/2,navigate/1,navigate/2,parent_class/1,popEventHandler/1, - popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, - refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, - reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, - scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, - setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, - setClientSize/3,setContainingSizer/2,setCursor/2,setDropTarget/2, - setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2,setForegroundColour/2, - setHelpText/2,setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2, - setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2,setPalette/2, - setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,setSize/2, - setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4, - setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2, - setToolTip/2,setVirtualSize/2,setVirtualSize/3,setVirtualSizeHints/2, - setVirtualSizeHints/3,setVirtualSizeHints/4,setWindowStyle/2,setWindowStyleFlag/2, - setWindowVariant/2,shouldInheritColours/1,show/1,show/2,thaw/1,transferDataFromWindow/1, - transferDataToWindow/1,update/1,updateWindowUI/1,updateWindowUI/2, - validate/1,warpPointer/3]). + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lower/1,makeModal/1,makeModal/2,move/2,move/3, + move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1,navigate/2, + parent_class/1,popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3, + popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3, + releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,screenToClient/2, + scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2, + setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,setCaret/2, + setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, + setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, + setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, + setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, + setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, + setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, + show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, + update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). -export_type([wxStyledTextCtrl/0]). %% @hidden @@ -4078,6 +4078,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxTextCtrl.erl b/lib/wx/src/gen/wxTextCtrl.erl index de9e1c307a..5840812579 100644 --- a/lib/wx/src/gen/wxTextCtrl.erl +++ b/lib/wx/src/gen/wxTextCtrl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2014. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -41,10 +41,10 @@ setStyle/4,setValue/2,showPosition/2,undo/1,writeText/2,xYToPosition/3]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -56,24 +56,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -597,6 +598,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxTextEntryDialog.erl b/lib/wx/src/gen/wxTextEntryDialog.erl index b18ba27607..a93c3857a8 100644 --- a/lib/wx/src/gen/wxTextEntryDialog.erl +++ b/lib/wx/src/gen/wxTextEntryDialog.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,11 +34,11 @@ -export([destroy/1,getValue/1,new/2,new/3,setValue/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centerOnScreen/1,centerOnScreen/2,centre/1,centre/2, - centreOnParent/1,centreOnParent/2,centreOnScreen/1,centreOnScreen/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centerOnScreen/1,centerOnScreen/2, + centre/1,centre/2,centreOnParent/1,centreOnParent/2,centreOnScreen/1, + centreOnScreen/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, createButtonSizer/2,createStdDialogButtonSizer/2,destroyChildren/1, disable/1,disconnect/1,disconnect/2,disconnect/3,enable/1,enable/2, endModal/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, @@ -53,25 +53,26 @@ getTitle/1,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, hide/1,iconize/1,iconize/2,inheritAttributes/1,initDialog/1,invalidateBestSize/1, - isActive/1,isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isFullScreen/1, - isIconized/1,isMaximized/1,isModal/1,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,maximize/1, - maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, - navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, - popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, - refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, - reparent/2,requestUserAttention/1,requestUserAttention/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2,setBackgroundColour/2, - setBackgroundStyle/2,setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2, - setCursor/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, - setFont/2,setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2, - setId/2,setLabel/2,setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2, - setOwnFont/2,setOwnForegroundColour/2,setPalette/2,setReturnCode/2, - setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2, - setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, - setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setTitle/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, + isActive/1,isDoubleBuffered/1,isEnabled/1,isExposed/2,isExposed/3, + isExposed/5,isFullScreen/1,isIconized/1,isMaximized/1,isModal/1,isRetained/1, + isShown/1,isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1, + makeModal/2,maximize/1,maximize/2,move/2,move/3,move/4,moveAfterInTabOrder/2, + moveBeforeInTabOrder/2,navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1, + popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4, + raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1, + removeChild/2,reparent/2,requestUserAttention/1,requestUserAttention/2, + screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3, + scrollWindow/4,setAcceleratorTable/2,setAffirmativeId/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, + setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, + setForegroundColour/2,setHelpText/2,setIcon/2,setIcons/2,setId/2,setLabel/2, + setMaxSize/2,setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2, + setOwnForegroundColour/2,setPalette/2,setReturnCode/2,setScrollPos/3, + setScrollPos/4,setScrollbar/5,setScrollbar/6,setShape/2,setSize/2, + setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3,setSizeHints/4, + setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3,setThemeEnabled/2, + setTitle/2,setToolTip/2,setTransparent/2,setVirtualSize/2,setVirtualSize/3, setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,showFullScreen/2,showFullScreen/3,showModal/1,thaw/1, @@ -211,6 +212,14 @@ getIcons(This) -> wxTopLevelWindow:getIcons(This). getIcon(This) -> wxTopLevelWindow:getIcon(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxToggleButton.erl b/lib/wx/src/gen/wxToggleButton.erl index 45795318c6..dffb4b159d 100644 --- a/lib/wx/src/gen/wxToggleButton.erl +++ b/lib/wx/src/gen/wxToggleButton.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -33,10 +33,10 @@ -export([create/4,create/5,destroy/1,getValue/1,new/0,new/3,new/4,setValue/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -48,24 +48,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -171,6 +172,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxToolBar.erl b/lib/wx/src/gen/wxToolBar.erl index 5c079fec1e..b3cce2b6e9 100644 --- a/lib/wx/src/gen/wxToolBar.erl +++ b/lib/wx/src/gen/wxToolBar.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -31,20 +31,21 @@ -module(wxToolBar). -include("wxe.hrl"). -export([addCheckTool/4,addCheckTool/5,addControl/2,addRadioTool/4,addRadioTool/5, - addSeparator/1,addTool/2,addTool/3,addTool/4,addTool/5,addTool/6,addTool/7, - deleteTool/2,deleteToolByPos/2,enableTool/3,findById/2,findControl/2, - findToolForPosition/3,getMargins/1,getToolBitmapSize/1,getToolEnabled/2, - getToolLongHelp/2,getToolPacking/1,getToolPos/2,getToolSeparation/1, - getToolShortHelp/2,getToolSize/1,getToolState/2,insertControl/3,insertSeparator/2, - insertTool/3,insertTool/4,insertTool/5,insertTool/6,realize/1,removeTool/2, - setMargins/3,setToolBitmapSize/2,setToolLongHelp/3,setToolPacking/2, - setToolSeparation/2,setToolShortHelp/3,toggleTool/3]). + addSeparator/1,addStretchableSpace/1,addTool/2,addTool/3,addTool/4, + addTool/5,addTool/6,addTool/7,deleteTool/2,deleteToolByPos/2,enableTool/3, + findById/2,findControl/2,findToolForPosition/3,getMargins/1,getToolBitmapSize/1, + getToolEnabled/2,getToolLongHelp/2,getToolPacking/1,getToolPos/2, + getToolSeparation/1,getToolShortHelp/2,getToolSize/1,getToolState/2, + insertControl/3,insertSeparator/2,insertStretchableSpace/2,insertTool/3, + insertTool/4,insertTool/5,insertTool/6,realize/1,removeTool/2,setMargins/3, + setToolBitmapSize/2,setToolLongHelp/3,setToolPacking/2,setToolSeparation/2, + setToolShortHelp/3,toggleTool/3]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -56,24 +57,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -328,6 +330,23 @@ addRadioTool(#wx_ref{type=ThisT,ref=ThisRef},Toolid,Label,#wx_ref{type=BitmapT,r wxe_util:call(?wxToolBar_AddRadioTool, <<ThisRef:32/?UI,Toolid:32/?UI,(byte_size(Label_UC)):32/?UI,(Label_UC)/binary, 0:(((8- ((4+byte_size(Label_UC)) band 16#7)) band 16#7))/unit:8,BitmapRef:32/?UI, 0:32,BinOpt/binary>>). +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxtoolbar.html#wxtoolbaraddstretchablespace">external documentation</a>. +-spec addStretchableSpace(This) -> wx:wx_object() when + This::wxToolBar(). +addStretchableSpace(#wx_ref{type=ThisT,ref=ThisRef}) -> + ?CLASS(ThisT,wxToolBar), + wxe_util:call(?wxToolBar_AddStretchableSpace, + <<ThisRef:32/?UI>>). + +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxtoolbar.html#wxtoolbarinsertstretchablespace">external documentation</a>. +-spec insertStretchableSpace(This, Pos) -> wx:wx_object() when + This::wxToolBar(), Pos::integer(). +insertStretchableSpace(#wx_ref{type=ThisT,ref=ThisRef},Pos) + when is_integer(Pos) -> + ?CLASS(ThisT,wxToolBar), + wxe_util:call(?wxToolBar_InsertStretchableSpace, + <<ThisRef:32/?UI,Pos:32/?UI>>). + %% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxtoolbar.html#wxtoolbardeletetool">external documentation</a>. -spec deleteTool(This, Toolid) -> boolean() when This::wxToolBar(), Toolid::integer(). @@ -655,6 +674,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxToolbook.erl b/lib/wx/src/gen/wxToolbook.erl index f959a73004..cf77aefd8a 100644 --- a/lib/wx/src/gen/wxToolbook.erl +++ b/lib/wx/src/gen/wxToolbook.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2013. All Rights Reserved. +%% Copyright Ericsson AB 2009-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -38,10 +38,10 @@ setPageSize/2,setPageText/3,setSelection/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -53,24 +53,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -383,6 +384,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxTopLevelWindow.erl b/lib/wx/src/gen/wxTopLevelWindow.erl index e11a72fab9..72813b0073 100644 --- a/lib/wx/src/gen/wxTopLevelWindow.erl +++ b/lib/wx/src/gen/wxTopLevelWindow.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -36,10 +36,10 @@ showFullScreen/2,showFullScreen/3]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -51,24 +51,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -301,6 +302,14 @@ showFullScreen(#wx_ref{type=ThisT,ref=ThisRef},Show, Options) %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxTreeCtrl.erl b/lib/wx/src/gen/wxTreeCtrl.erl index ef6e2b6fea..43dee9107d 100644 --- a/lib/wx/src/gen/wxTreeCtrl.erl +++ b/lib/wx/src/gen/wxTreeCtrl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -54,10 +54,10 @@ unselectItem/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -69,24 +69,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1,show/1, show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1,update/1, updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -945,6 +946,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxTreebook.erl b/lib/wx/src/gen/wxTreebook.erl index 19f1d7cfe4..1900f47289 100644 --- a/lib/wx/src/gen/wxTreebook.erl +++ b/lib/wx/src/gen/wxTreebook.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2013. All Rights Reserved. +%% Copyright Ericsson AB 2009-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -39,10 +39,10 @@ setPageSize/2,setPageText/3,setSelection/2]). %% inherited exports --export([cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, +-export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, + centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,connect/2,connect/3,convertDialogToPixels/2,convertPixelsToDialog/2, destroyChildren/1,disable/1,disconnect/1,disconnect/2,disconnect/3, enable/1,enable/2,findWindow/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCaret/1, @@ -54,24 +54,25 @@ getScrollRange/2,getScrollThumb/2,getSize/1,getSizer/1,getTextExtent/2, getTextExtent/3,getToolTip/1,getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1, getWindowVariant/1,hasCapture/1,hasScrollbar/2,hasTransparentBackground/1, - hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isEnabled/1, - isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, - layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, - move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, - navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1,popEventHandler/2, - popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, - refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, - screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, - setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, - setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + hide/1,inheritAttributes/1,initDialog/1,invalidateBestSize/1,isDoubleBuffered/1, + isEnabled/1,isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1, + isTopLevel/1,layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2, + move/2,move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2, + navigate/1,navigate/2,pageDown/1,pageUp/1,parent_class/1,popEventHandler/1, + popEventHandler/2,popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1, + refresh/2,refreshRect/2,refreshRect/3,releaseMouse/1,removeChild/2, + reparent/2,screenToClient/1,screenToClient/2,scrollLines/2,scrollPages/2, + scrollWindow/3,scrollWindow/4,setAcceleratorTable/2,setAutoLayout/2, + setBackgroundColour/2,setBackgroundStyle/2,setCaret/2,setClientSize/2, + setClientSize/3,setContainingSizer/2,setCursor/2,setDoubleBuffered/2, setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -439,6 +440,14 @@ setLabel(This,Label) -> wxControl:setLabel(This,Label). getLabel(This) -> wxControl:getLabel(This). %% From wxWindow %% @hidden +setDoubleBuffered(This,On) -> wxWindow:setDoubleBuffered(This,On). +%% @hidden +isDoubleBuffered(This) -> wxWindow:isDoubleBuffered(This). +%% @hidden +canSetTransparent(This) -> wxWindow:canSetTransparent(This). +%% @hidden +setTransparent(This,Alpha) -> wxWindow:setTransparent(This,Alpha). +%% @hidden warpPointer(This,X,Y) -> wxWindow:warpPointer(This,X,Y). %% @hidden validate(This) -> wxWindow:validate(This). diff --git a/lib/wx/src/gen/wxWindow.erl b/lib/wx/src/gen/wxWindow.erl index 09928de09a..a8a61d547b 100644 --- a/lib/wx/src/gen/wxWindow.erl +++ b/lib/wx/src/gen/wxWindow.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -28,13 +28,13 @@ -module(wxWindow). -include("wxe.hrl"). --export(['Destroy'/1,cacheBestSize/2,captureMouse/1,center/1,center/2,centerOnParent/1, - centerOnParent/2,centre/1,centre/2,centreOnParent/1,centreOnParent/2, - clearBackground/1,clientToScreen/2,clientToScreen/3,close/1,close/2, - convertDialogToPixels/2,convertPixelsToDialog/2,destroy/1,destroyChildren/1, - disable/1,enable/1,enable/2,findFocus/0,findWindow/2,findWindowById/1, - findWindowById/2,findWindowByLabel/1,findWindowByLabel/2,findWindowByName/1, - findWindowByName/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, +-export(['Destroy'/1,cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1, + center/2,centerOnParent/1,centerOnParent/2,centre/1,centre/2,centreOnParent/1, + centreOnParent/2,clearBackground/1,clientToScreen/2,clientToScreen/3, + close/1,close/2,convertDialogToPixels/2,convertPixelsToDialog/2,destroy/1, + destroyChildren/1,disable/1,enable/1,enable/2,findFocus/0,findWindow/2, + findWindowById/1,findWindowById/2,findWindowByLabel/1,findWindowByLabel/2, + findWindowByName/1,findWindowByName/2,fit/1,fitInside/1,freeze/1,getAcceleratorTable/1, getBackgroundColour/1,getBackgroundStyle/1,getBestSize/1,getCapture/0, getCaret/1,getCharHeight/1,getCharWidth/1,getChildren/1,getClientSize/1, getContainingSizer/1,getCursor/1,getDropTarget/1,getEventHandler/1, @@ -45,24 +45,24 @@ getSize/1,getSizer/1,getTextExtent/2,getTextExtent/3,getToolTip/1, getUpdateRegion/1,getVirtualSize/1,getWindowStyleFlag/1,getWindowVariant/1, hasCapture/1,hasScrollbar/2,hasTransparentBackground/1,hide/1,inheritAttributes/1, - initDialog/1,invalidateBestSize/1,isEnabled/1,isExposed/2,isExposed/3, - isExposed/5,isRetained/1,isShown/1,isTopLevel/1,layout/1,lineDown/1, - lineUp/1,lower/1,makeModal/1,makeModal/2,move/2,move/3,move/4,moveAfterInTabOrder/2, - moveBeforeInTabOrder/2,navigate/1,navigate/2,new/0,new/2,new/3,pageDown/1, - pageUp/1,popEventHandler/1,popEventHandler/2,popupMenu/2,popupMenu/3, - popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2,refreshRect/3, - releaseMouse/1,removeChild/2,reparent/2,screenToClient/1,screenToClient/2, - scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4,setAcceleratorTable/2, - setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2,setCaret/2, - setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, - setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1,setFont/2, - setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, + initDialog/1,invalidateBestSize/1,isDoubleBuffered/1,isEnabled/1, + isExposed/2,isExposed/3,isExposed/5,isRetained/1,isShown/1,isTopLevel/1, + layout/1,lineDown/1,lineUp/1,lower/1,makeModal/1,makeModal/2,move/2, + move/3,move/4,moveAfterInTabOrder/2,moveBeforeInTabOrder/2,navigate/1, + navigate/2,new/0,new/2,new/3,pageDown/1,pageUp/1,popEventHandler/1,popEventHandler/2, + popupMenu/2,popupMenu/3,popupMenu/4,raise/1,refresh/1,refresh/2,refreshRect/2, + refreshRect/3,releaseMouse/1,removeChild/2,reparent/2,screenToClient/1, + screenToClient/2,scrollLines/2,scrollPages/2,scrollWindow/3,scrollWindow/4, + setAcceleratorTable/2,setAutoLayout/2,setBackgroundColour/2,setBackgroundStyle/2, + setCaret/2,setClientSize/2,setClientSize/3,setContainingSizer/2,setCursor/2, + setDoubleBuffered/2,setDropTarget/2,setExtraStyle/2,setFocus/1,setFocusFromKbd/1, + setFont/2,setForegroundColour/2,setHelpText/2,setId/2,setLabel/2,setMaxSize/2, setMinSize/2,setName/2,setOwnBackgroundColour/2,setOwnFont/2,setOwnForegroundColour/2, setPalette/2,setScrollPos/3,setScrollPos/4,setScrollbar/5,setScrollbar/6, setSize/2,setSize/3,setSize/5,setSize/6,setSizeHints/2,setSizeHints/3, setSizeHints/4,setSizer/2,setSizer/3,setSizerAndFit/2,setSizerAndFit/3, - setThemeEnabled/2,setToolTip/2,setVirtualSize/2,setVirtualSize/3, - setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, + setThemeEnabled/2,setToolTip/2,setTransparent/2,setVirtualSize/2, + setVirtualSize/3,setVirtualSizeHints/2,setVirtualSizeHints/3,setVirtualSizeHints/4, setWindowStyle/2,setWindowStyleFlag/2,setWindowVariant/2,shouldInheritColours/1, show/1,show/2,thaw/1,transferDataFromWindow/1,transferDataToWindow/1, update/1,updateWindowUI/1,updateWindowUI/2,validate/1,warpPointer/3]). @@ -1910,6 +1910,40 @@ warpPointer(#wx_ref{type=ThisT,ref=ThisRef},X,Y) wxe_util:cast(?wxWindow_WarpPointer, <<ThisRef:32/?UI,X:32/?UI,Y:32/?UI>>). +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxwindow.html#wxwindowsettransparent">external documentation</a>. +-spec setTransparent(This, Alpha) -> boolean() when + This::wxWindow(), Alpha::integer(). +setTransparent(#wx_ref{type=ThisT,ref=ThisRef},Alpha) + when is_integer(Alpha) -> + ?CLASS(ThisT,wxWindow), + wxe_util:call(?wxWindow_SetTransparent, + <<ThisRef:32/?UI,Alpha:32/?UI>>). + +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxwindow.html#wxwindowcansettransparent">external documentation</a>. +-spec canSetTransparent(This) -> boolean() when + This::wxWindow(). +canSetTransparent(#wx_ref{type=ThisT,ref=ThisRef}) -> + ?CLASS(ThisT,wxWindow), + wxe_util:call(?wxWindow_CanSetTransparent, + <<ThisRef:32/?UI>>). + +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxwindow.html#wxwindowisdoublebuffered">external documentation</a>. +-spec isDoubleBuffered(This) -> boolean() when + This::wxWindow(). +isDoubleBuffered(#wx_ref{type=ThisT,ref=ThisRef}) -> + ?CLASS(ThisT,wxWindow), + wxe_util:call(?wxWindow_IsDoubleBuffered, + <<ThisRef:32/?UI>>). + +%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxwindow.html#wxwindowsetdoublebuffered">external documentation</a>. +-spec setDoubleBuffered(This, On) -> ok when + This::wxWindow(), On::boolean(). +setDoubleBuffered(#wx_ref{type=ThisT,ref=ThisRef},On) + when is_boolean(On) -> + ?CLASS(ThisT,wxWindow), + wxe_util:cast(?wxWindow_SetDoubleBuffered, + <<ThisRef:32/?UI,(wxe_util:from_bool(On)):32/?UI>>). + %% @doc Destroys this object, do not use object again -spec destroy(This::wxWindow()) -> ok. destroy(Obj=#wx_ref{type=Type}) -> diff --git a/lib/wx/src/gen/wxe_debug.hrl b/lib/wx/src/gen/wxe_debug.hrl index 58fbe8d061..a2462a6fb2 100644 --- a/lib/wx/src/gen/wxe_debug.hrl +++ b/lib/wx/src/gen/wxe_debug.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2014. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -192,3155 +192,3190 @@ wxdebug_table() -> {281, {wxWindow, updateWindowUI, 1}}, {282, {wxWindow, validate, 0}}, {283, {wxWindow, warpPointer, 2}}, - {284, {wxTopLevelWindow, getIcon, 0}}, - {285, {wxTopLevelWindow, getIcons, 0}}, - {286, {wxTopLevelWindow, getTitle, 0}}, - {287, {wxTopLevelWindow, isActive, 0}}, - {288, {wxTopLevelWindow, iconize, 1}}, - {289, {wxTopLevelWindow, isFullScreen, 0}}, - {290, {wxTopLevelWindow, isIconized, 0}}, - {291, {wxTopLevelWindow, isMaximized, 0}}, - {292, {wxTopLevelWindow, maximize, 1}}, - {293, {wxTopLevelWindow, requestUserAttention, 1}}, - {294, {wxTopLevelWindow, setIcon, 1}}, - {295, {wxTopLevelWindow, setIcons, 1}}, - {296, {wxTopLevelWindow, centerOnScreen, 1}}, - {297, {wxTopLevelWindow, centreOnScreen, 1}}, - {299, {wxTopLevelWindow, setShape, 1}}, - {300, {wxTopLevelWindow, setTitle, 1}}, - {301, {wxTopLevelWindow, showFullScreen, 2}}, - {303, {wxFrame, new_4, 4}}, - {304, {wxFrame, new_0, 0}}, - {306, {wxFrame, destruct, 0}}, - {307, {wxFrame, create, 4}}, - {308, {wxFrame, createStatusBar, 1}}, - {309, {wxFrame, createToolBar, 1}}, - {310, {wxFrame, getClientAreaOrigin, 0}}, - {311, {wxFrame, getMenuBar, 0}}, - {312, {wxFrame, getStatusBar, 0}}, - {313, {wxFrame, getStatusBarPane, 0}}, - {314, {wxFrame, getToolBar, 0}}, - {315, {wxFrame, processCommand, 1}}, - {316, {wxFrame, sendSizeEvent, 0}}, - {317, {wxFrame, setMenuBar, 1}}, - {318, {wxFrame, setStatusBar, 1}}, - {319, {wxFrame, setStatusBarPane, 1}}, - {320, {wxFrame, setStatusText, 2}}, - {321, {wxFrame, setStatusWidths, 2}}, - {322, {wxFrame, setToolBar, 1}}, - {323, {wxMiniFrame, new_0, 0}}, - {324, {wxMiniFrame, new_4, 4}}, - {325, {wxMiniFrame, create, 4}}, - {326, {wxMiniFrame, 'Destroy', undefined}}, - {327, {wxSplashScreen, new_0, 0}}, - {328, {wxSplashScreen, new_6, 6}}, - {329, {wxSplashScreen, destruct, 0}}, - {330, {wxSplashScreen, getSplashStyle, 0}}, - {331, {wxSplashScreen, getTimeout, 0}}, - {332, {wxPanel, new_0, 0}}, - {333, {wxPanel, new_6, 6}}, - {334, {wxPanel, new_2, 2}}, - {335, {wxPanel, destruct, 0}}, - {336, {wxPanel, initDialog, 0}}, - {337, {wxPanel, setFocusIgnoringChildren, 0}}, - {338, {wxScrolledWindow, new_0, 0}}, - {339, {wxScrolledWindow, new_2, 2}}, - {340, {wxScrolledWindow, destruct, 0}}, - {341, {wxScrolledWindow, calcScrolledPosition_4, 4}}, - {342, {wxScrolledWindow, calcScrolledPosition_1, 1}}, - {343, {wxScrolledWindow, calcUnscrolledPosition_4, 4}}, - {344, {wxScrolledWindow, calcUnscrolledPosition_1, 1}}, - {345, {wxScrolledWindow, enableScrolling, 2}}, - {346, {wxScrolledWindow, getScrollPixelsPerUnit, 2}}, - {347, {wxScrolledWindow, getViewStart, 2}}, - {348, {wxScrolledWindow, doPrepareDC, 1}}, - {349, {wxScrolledWindow, prepareDC, 1}}, - {350, {wxScrolledWindow, scroll, 2}}, - {351, {wxScrolledWindow, setScrollbars, 5}}, - {352, {wxScrolledWindow, setScrollRate, 2}}, - {353, {wxScrolledWindow, setTargetWindow, 1}}, - {354, {wxSashWindow, new_0, 0}}, - {355, {wxSashWindow, new_2, 2}}, - {356, {wxSashWindow, destruct, 0}}, - {357, {wxSashWindow, getSashVisible, 1}}, - {358, {wxSashWindow, getMaximumSizeX, 0}}, - {359, {wxSashWindow, getMaximumSizeY, 0}}, - {360, {wxSashWindow, getMinimumSizeX, 0}}, - {361, {wxSashWindow, getMinimumSizeY, 0}}, - {362, {wxSashWindow, setMaximumSizeX, 1}}, - {363, {wxSashWindow, setMaximumSizeY, 1}}, - {364, {wxSashWindow, setMinimumSizeX, 1}}, - {365, {wxSashWindow, setMinimumSizeY, 1}}, - {366, {wxSashWindow, setSashVisible, 2}}, - {367, {wxSashLayoutWindow, new_0, 0}}, - {368, {wxSashLayoutWindow, new_2, 2}}, - {369, {wxSashLayoutWindow, create, 2}}, - {370, {wxSashLayoutWindow, getAlignment, 0}}, - {371, {wxSashLayoutWindow, getOrientation, 0}}, - {372, {wxSashLayoutWindow, setAlignment, 1}}, - {373, {wxSashLayoutWindow, setDefaultSize, 1}}, - {374, {wxSashLayoutWindow, setOrientation, 1}}, - {375, {wxSashLayoutWindow, 'Destroy', undefined}}, - {376, {wxGrid, new_0, 0}}, - {377, {wxGrid, new_3, 3}}, - {378, {wxGrid, new_4, 4}}, - {379, {wxGrid, destruct, 0}}, - {380, {wxGrid, appendCols, 1}}, - {381, {wxGrid, appendRows, 1}}, - {382, {wxGrid, autoSize, 0}}, - {383, {wxGrid, autoSizeColumn, 2}}, - {384, {wxGrid, autoSizeColumns, 1}}, - {385, {wxGrid, autoSizeRow, 2}}, - {386, {wxGrid, autoSizeRows, 1}}, - {387, {wxGrid, beginBatch, 0}}, - {388, {wxGrid, blockToDeviceRect, 2}}, - {389, {wxGrid, canDragColSize, 0}}, - {390, {wxGrid, canDragRowSize, 0}}, - {391, {wxGrid, canDragGridSize, 0}}, - {392, {wxGrid, canEnableCellControl, 0}}, - {393, {wxGrid, cellToRect_2, 2}}, - {394, {wxGrid, cellToRect_1, 1}}, - {395, {wxGrid, clearGrid, 0}}, - {396, {wxGrid, clearSelection, 0}}, - {397, {wxGrid, createGrid, 3}}, - {398, {wxGrid, deleteCols, 1}}, - {399, {wxGrid, deleteRows, 1}}, - {400, {wxGrid, disableCellEditControl, 0}}, - {401, {wxGrid, disableDragColSize, 0}}, - {402, {wxGrid, disableDragGridSize, 0}}, - {403, {wxGrid, disableDragRowSize, 0}}, - {404, {wxGrid, enableCellEditControl, 1}}, - {405, {wxGrid, enableDragColSize, 1}}, - {406, {wxGrid, enableDragGridSize, 1}}, - {407, {wxGrid, enableDragRowSize, 1}}, - {408, {wxGrid, enableEditing, 1}}, - {409, {wxGrid, enableGridLines, 1}}, - {410, {wxGrid, endBatch, 0}}, - {411, {wxGrid, fit, 0}}, - {412, {wxGrid, forceRefresh, 0}}, - {413, {wxGrid, getBatchCount, 0}}, - {414, {wxGrid, getCellAlignment, 4}}, - {415, {wxGrid, getCellBackgroundColour, 2}}, - {416, {wxGrid, getCellEditor, 2}}, - {417, {wxGrid, getCellFont, 2}}, - {418, {wxGrid, getCellRenderer, 2}}, - {419, {wxGrid, getCellTextColour, 2}}, - {420, {wxGrid, getCellValue_2, 2}}, - {421, {wxGrid, getCellValue_1, 1}}, - {422, {wxGrid, getColLabelAlignment, 2}}, - {423, {wxGrid, getColLabelSize, 0}}, - {424, {wxGrid, getColLabelValue, 1}}, - {425, {wxGrid, getColMinimalAcceptableWidth, 0}}, - {426, {wxGrid, getDefaultCellAlignment, 2}}, - {427, {wxGrid, getDefaultCellBackgroundColour, 0}}, - {428, {wxGrid, getDefaultCellFont, 0}}, - {429, {wxGrid, getDefaultCellTextColour, 0}}, - {430, {wxGrid, getDefaultColLabelSize, 0}}, - {431, {wxGrid, getDefaultColSize, 0}}, - {432, {wxGrid, getDefaultEditor, 0}}, - {433, {wxGrid, getDefaultEditorForCell_2, 2}}, - {434, {wxGrid, getDefaultEditorForCell_1, 1}}, - {435, {wxGrid, getDefaultEditorForType, 1}}, - {436, {wxGrid, getDefaultRenderer, 0}}, - {437, {wxGrid, getDefaultRendererForCell, 2}}, - {438, {wxGrid, getDefaultRendererForType, 1}}, - {439, {wxGrid, getDefaultRowLabelSize, 0}}, - {440, {wxGrid, getDefaultRowSize, 0}}, - {441, {wxGrid, getGridCursorCol, 0}}, - {442, {wxGrid, getGridCursorRow, 0}}, - {443, {wxGrid, getGridLineColour, 0}}, - {444, {wxGrid, gridLinesEnabled, 0}}, - {445, {wxGrid, getLabelBackgroundColour, 0}}, - {446, {wxGrid, getLabelFont, 0}}, - {447, {wxGrid, getLabelTextColour, 0}}, - {448, {wxGrid, getNumberCols, 0}}, - {449, {wxGrid, getNumberRows, 0}}, - {450, {wxGrid, getOrCreateCellAttr, 2}}, - {451, {wxGrid, getRowMinimalAcceptableHeight, 0}}, - {452, {wxGrid, getRowLabelAlignment, 2}}, - {453, {wxGrid, getRowLabelSize, 0}}, - {454, {wxGrid, getRowLabelValue, 1}}, - {455, {wxGrid, getRowSize, 1}}, - {456, {wxGrid, getScrollLineX, 0}}, - {457, {wxGrid, getScrollLineY, 0}}, - {458, {wxGrid, getSelectedCells, 0}}, - {459, {wxGrid, getSelectedCols, 0}}, - {460, {wxGrid, getSelectedRows, 0}}, - {461, {wxGrid, getSelectionBackground, 0}}, - {462, {wxGrid, getSelectionBlockTopLeft, 0}}, - {463, {wxGrid, getSelectionBlockBottomRight, 0}}, - {464, {wxGrid, getSelectionForeground, 0}}, - {465, {wxGrid, getViewWidth, 0}}, - {466, {wxGrid, getGridWindow, 0}}, - {467, {wxGrid, getGridRowLabelWindow, 0}}, - {468, {wxGrid, getGridColLabelWindow, 0}}, - {469, {wxGrid, getGridCornerLabelWindow, 0}}, - {470, {wxGrid, hideCellEditControl, 0}}, - {471, {wxGrid, insertCols, 1}}, - {472, {wxGrid, insertRows, 1}}, - {473, {wxGrid, isCellEditControlEnabled, 0}}, - {474, {wxGrid, isCurrentCellReadOnly, 0}}, - {475, {wxGrid, isEditable, 0}}, - {476, {wxGrid, isInSelection_2, 2}}, - {477, {wxGrid, isInSelection_1, 1}}, - {478, {wxGrid, isReadOnly, 2}}, - {479, {wxGrid, isSelection, 0}}, - {480, {wxGrid, isVisible_3, 3}}, - {481, {wxGrid, isVisible_2, 2}}, - {482, {wxGrid, makeCellVisible_2, 2}}, - {483, {wxGrid, makeCellVisible_1, 1}}, - {484, {wxGrid, moveCursorDown, 1}}, - {485, {wxGrid, moveCursorLeft, 1}}, - {486, {wxGrid, moveCursorRight, 1}}, - {487, {wxGrid, moveCursorUp, 1}}, - {488, {wxGrid, moveCursorDownBlock, 1}}, - {489, {wxGrid, moveCursorLeftBlock, 1}}, - {490, {wxGrid, moveCursorRightBlock, 1}}, - {491, {wxGrid, moveCursorUpBlock, 1}}, - {492, {wxGrid, movePageDown, 0}}, - {493, {wxGrid, movePageUp, 0}}, - {494, {wxGrid, registerDataType, 3}}, - {495, {wxGrid, saveEditControlValue, 0}}, - {496, {wxGrid, selectAll, 0}}, - {497, {wxGrid, selectBlock_5, 5}}, - {498, {wxGrid, selectBlock_3, 3}}, - {499, {wxGrid, selectCol, 2}}, - {500, {wxGrid, selectRow, 2}}, - {501, {wxGrid, setCellAlignment_4, 4}}, - {502, {wxGrid, setCellAlignment_3, 3}}, - {503, {wxGrid, setCellAlignment_1, 1}}, - {504, {wxGrid, setCellBackgroundColour_3_0, 3}}, - {505, {wxGrid, setCellBackgroundColour_1, 1}}, - {506, {wxGrid, setCellBackgroundColour_3_1, 3}}, - {507, {wxGrid, setCellEditor, 3}}, - {508, {wxGrid, setCellFont, 3}}, - {509, {wxGrid, setCellRenderer, 3}}, - {510, {wxGrid, setCellTextColour_3_0, 3}}, - {511, {wxGrid, setCellTextColour_3_1, 3}}, - {512, {wxGrid, setCellTextColour_1, 1}}, - {513, {wxGrid, setCellValue_3_0, 3}}, - {514, {wxGrid, setCellValue_2, 2}}, - {515, {wxGrid, setCellValue_3_1, 3}}, - {516, {wxGrid, setColAttr, 2}}, - {517, {wxGrid, setColFormatBool, 1}}, - {518, {wxGrid, setColFormatNumber, 1}}, - {519, {wxGrid, setColFormatFloat, 2}}, - {520, {wxGrid, setColFormatCustom, 2}}, - {521, {wxGrid, setColLabelAlignment, 2}}, - {522, {wxGrid, setColLabelSize, 1}}, - {523, {wxGrid, setColLabelValue, 2}}, - {524, {wxGrid, setColMinimalWidth, 2}}, - {525, {wxGrid, setColMinimalAcceptableWidth, 1}}, - {526, {wxGrid, setColSize, 2}}, - {527, {wxGrid, setDefaultCellAlignment, 2}}, - {528, {wxGrid, setDefaultCellBackgroundColour, 1}}, - {529, {wxGrid, setDefaultCellFont, 1}}, - {530, {wxGrid, setDefaultCellTextColour, 1}}, - {531, {wxGrid, setDefaultEditor, 1}}, - {532, {wxGrid, setDefaultRenderer, 1}}, - {533, {wxGrid, setDefaultColSize, 2}}, - {534, {wxGrid, setDefaultRowSize, 2}}, - {535, {wxGrid, setGridCursor, 2}}, - {536, {wxGrid, setGridLineColour, 1}}, - {537, {wxGrid, setLabelBackgroundColour, 1}}, - {538, {wxGrid, setLabelFont, 1}}, - {539, {wxGrid, setLabelTextColour, 1}}, - {540, {wxGrid, setMargins, 2}}, - {541, {wxGrid, setReadOnly, 3}}, - {542, {wxGrid, setRowAttr, 2}}, - {543, {wxGrid, setRowLabelAlignment, 2}}, - {544, {wxGrid, setRowLabelSize, 1}}, - {545, {wxGrid, setRowLabelValue, 2}}, - {546, {wxGrid, setRowMinimalHeight, 2}}, - {547, {wxGrid, setRowMinimalAcceptableHeight, 1}}, - {548, {wxGrid, setRowSize, 2}}, - {549, {wxGrid, setScrollLineX, 1}}, - {550, {wxGrid, setScrollLineY, 1}}, - {551, {wxGrid, setSelectionBackground, 1}}, - {552, {wxGrid, setSelectionForeground, 1}}, - {553, {wxGrid, setSelectionMode, 1}}, - {554, {wxGrid, showCellEditControl, 0}}, - {555, {wxGrid, xToCol, 2}}, - {556, {wxGrid, xToEdgeOfCol, 1}}, - {557, {wxGrid, yToEdgeOfRow, 1}}, - {558, {wxGrid, yToRow, 1}}, - {559, {wxGridCellRenderer, draw, 7}}, - {560, {wxGridCellRenderer, getBestSize, 5}}, - {561, {wxGridCellEditor, create, 3}}, - {562, {wxGridCellEditor, isCreated, 0}}, - {563, {wxGridCellEditor, setSize, 1}}, - {564, {wxGridCellEditor, show, 2}}, - {565, {wxGridCellEditor, paintBackground, 2}}, - {566, {wxGridCellEditor, beginEdit, 3}}, - {567, {wxGridCellEditor, endEdit, 3}}, - {568, {wxGridCellEditor, reset, 0}}, - {569, {wxGridCellEditor, startingKey, 1}}, - {570, {wxGridCellEditor, startingClick, 0}}, - {571, {wxGridCellEditor, handleReturn, 1}}, - {572, {wxGridCellBoolRenderer, new, 0}}, - {573, {wxGridCellBoolRenderer, 'Destroy', undefined}}, - {574, {wxGridCellBoolEditor, new, 0}}, - {575, {wxGridCellBoolEditor, isTrueValue, 1}}, - {576, {wxGridCellBoolEditor, useStringValues, 1}}, - {577, {wxGridCellBoolEditor, 'Destroy', undefined}}, - {578, {wxGridCellFloatRenderer, new, 1}}, - {579, {wxGridCellFloatRenderer, getPrecision, 0}}, - {580, {wxGridCellFloatRenderer, getWidth, 0}}, - {581, {wxGridCellFloatRenderer, setParameters, 1}}, - {582, {wxGridCellFloatRenderer, setPrecision, 1}}, - {583, {wxGridCellFloatRenderer, setWidth, 1}}, - {584, {wxGridCellFloatRenderer, 'Destroy', undefined}}, - {585, {wxGridCellFloatEditor, new, 1}}, - {586, {wxGridCellFloatEditor, setParameters, 1}}, - {587, {wxGridCellFloatEditor, 'Destroy', undefined}}, - {588, {wxGridCellStringRenderer, new, 0}}, - {589, {wxGridCellStringRenderer, 'Destroy', undefined}}, - {590, {wxGridCellTextEditor, new, 0}}, - {591, {wxGridCellTextEditor, setParameters, 1}}, - {592, {wxGridCellTextEditor, 'Destroy', undefined}}, - {594, {wxGridCellChoiceEditor, new, 2}}, - {595, {wxGridCellChoiceEditor, setParameters, 1}}, - {596, {wxGridCellChoiceEditor, 'Destroy', undefined}}, - {597, {wxGridCellNumberRenderer, new, 0}}, - {598, {wxGridCellNumberRenderer, 'Destroy', undefined}}, - {599, {wxGridCellNumberEditor, new, 1}}, - {600, {wxGridCellNumberEditor, getValue, 0}}, - {601, {wxGridCellNumberEditor, setParameters, 1}}, - {602, {wxGridCellNumberEditor, 'Destroy', undefined}}, - {603, {wxGridCellAttr, setTextColour, 1}}, - {604, {wxGridCellAttr, setBackgroundColour, 1}}, - {605, {wxGridCellAttr, setFont, 1}}, - {606, {wxGridCellAttr, setAlignment, 2}}, - {607, {wxGridCellAttr, setReadOnly, 1}}, - {608, {wxGridCellAttr, setRenderer, 1}}, - {609, {wxGridCellAttr, setEditor, 1}}, - {610, {wxGridCellAttr, hasTextColour, 0}}, - {611, {wxGridCellAttr, hasBackgroundColour, 0}}, - {612, {wxGridCellAttr, hasFont, 0}}, - {613, {wxGridCellAttr, hasAlignment, 0}}, - {614, {wxGridCellAttr, hasRenderer, 0}}, - {615, {wxGridCellAttr, hasEditor, 0}}, - {616, {wxGridCellAttr, getTextColour, 0}}, - {617, {wxGridCellAttr, getBackgroundColour, 0}}, - {618, {wxGridCellAttr, getFont, 0}}, - {619, {wxGridCellAttr, getAlignment, 2}}, - {620, {wxGridCellAttr, getRenderer, 3}}, - {621, {wxGridCellAttr, getEditor, 3}}, - {622, {wxGridCellAttr, isReadOnly, 0}}, - {623, {wxGridCellAttr, setDefAttr, 1}}, - {624, {wxDC, blit, 5}}, - {625, {wxDC, calcBoundingBox, 2}}, - {626, {wxDC, clear, 0}}, - {627, {wxDC, computeScaleAndOrigin, 0}}, - {628, {wxDC, crossHair, 1}}, - {629, {wxDC, destroyClippingRegion, 0}}, - {630, {wxDC, deviceToLogicalX, 1}}, - {631, {wxDC, deviceToLogicalXRel, 1}}, - {632, {wxDC, deviceToLogicalY, 1}}, - {633, {wxDC, deviceToLogicalYRel, 1}}, - {634, {wxDC, drawArc, 3}}, - {635, {wxDC, drawBitmap, 3}}, - {636, {wxDC, drawCheckMark, 1}}, - {637, {wxDC, drawCircle, 2}}, - {639, {wxDC, drawEllipse_2, 2}}, - {640, {wxDC, drawEllipse_1, 1}}, - {641, {wxDC, drawEllipticArc, 4}}, - {642, {wxDC, drawIcon, 2}}, - {643, {wxDC, drawLabel, 3}}, - {644, {wxDC, drawLine, 2}}, - {645, {wxDC, drawLines, 3}}, - {647, {wxDC, drawPolygon, 3}}, - {649, {wxDC, drawPoint, 1}}, - {651, {wxDC, drawRectangle_2, 2}}, - {652, {wxDC, drawRectangle_1, 1}}, - {653, {wxDC, drawRotatedText, 3}}, - {655, {wxDC, drawRoundedRectangle_3, 3}}, - {656, {wxDC, drawRoundedRectangle_2, 2}}, - {657, {wxDC, drawText, 2}}, - {658, {wxDC, endDoc, 0}}, - {659, {wxDC, endPage, 0}}, - {660, {wxDC, floodFill, 3}}, - {661, {wxDC, getBackground, 0}}, - {662, {wxDC, getBackgroundMode, 0}}, - {663, {wxDC, getBrush, 0}}, - {664, {wxDC, getCharHeight, 0}}, - {665, {wxDC, getCharWidth, 0}}, - {666, {wxDC, getClippingBox, 4}}, - {668, {wxDC, getFont, 0}}, - {669, {wxDC, getLayoutDirection, 0}}, - {670, {wxDC, getLogicalFunction, 0}}, - {671, {wxDC, getMapMode, 0}}, - {672, {wxDC, getMultiLineTextExtent_4, 4}}, - {673, {wxDC, getMultiLineTextExtent_1, 1}}, - {674, {wxDC, getPartialTextExtents, 2}}, - {675, {wxDC, getPen, 0}}, - {676, {wxDC, getPixel, 2}}, - {677, {wxDC, getPPI, 0}}, - {679, {wxDC, getSize, 0}}, - {681, {wxDC, getSizeMM, 0}}, - {682, {wxDC, getTextBackground, 0}}, - {683, {wxDC, getTextExtent_4, 4}}, - {684, {wxDC, getTextExtent_1, 1}}, - {686, {wxDC, getTextForeground, 0}}, - {687, {wxDC, getUserScale, 2}}, - {688, {wxDC, gradientFillConcentric_3, 3}}, - {689, {wxDC, gradientFillConcentric_4, 4}}, - {690, {wxDC, gradientFillLinear, 4}}, - {691, {wxDC, logicalToDeviceX, 1}}, - {692, {wxDC, logicalToDeviceXRel, 1}}, - {693, {wxDC, logicalToDeviceY, 1}}, - {694, {wxDC, logicalToDeviceYRel, 1}}, - {695, {wxDC, maxX, 0}}, - {696, {wxDC, maxY, 0}}, - {697, {wxDC, minX, 0}}, - {698, {wxDC, minY, 0}}, - {699, {wxDC, isOk, 0}}, - {700, {wxDC, resetBoundingBox, 0}}, - {701, {wxDC, setAxisOrientation, 2}}, - {702, {wxDC, setBackground, 1}}, - {703, {wxDC, setBackgroundMode, 1}}, - {704, {wxDC, setBrush, 1}}, - {706, {wxDC, setClippingRegion_2, 2}}, - {707, {wxDC, setClippingRegion_1_1, 1}}, - {708, {wxDC, setClippingRegion_1_0, 1}}, - {709, {wxDC, setDeviceOrigin, 2}}, - {710, {wxDC, setFont, 1}}, - {711, {wxDC, setLayoutDirection, 1}}, - {712, {wxDC, setLogicalFunction, 1}}, - {713, {wxDC, setMapMode, 1}}, - {714, {wxDC, setPalette, 1}}, - {715, {wxDC, setPen, 1}}, - {716, {wxDC, setTextBackground, 1}}, - {717, {wxDC, setTextForeground, 1}}, - {718, {wxDC, setUserScale, 2}}, - {719, {wxDC, startDoc, 1}}, - {720, {wxDC, startPage, 0}}, - {721, {wxMirrorDC, new, 2}}, - {722, {wxMirrorDC, 'Destroy', undefined}}, - {723, {wxScreenDC, new, 0}}, - {724, {wxScreenDC, destruct, 0}}, - {725, {wxPostScriptDC, new_0, 0}}, - {726, {wxPostScriptDC, new_1, 1}}, - {727, {wxPostScriptDC, destruct, 0}}, - {728, {wxPostScriptDC, setResolution, 1}}, - {729, {wxPostScriptDC, getResolution, 0}}, - {730, {wxWindowDC, new_0, 0}}, - {731, {wxWindowDC, new_1, 1}}, - {732, {wxWindowDC, destruct, 0}}, - {733, {wxClientDC, new_0, 0}}, - {734, {wxClientDC, new_1, 1}}, - {735, {wxClientDC, 'Destroy', undefined}}, - {736, {wxPaintDC, new_0, 0}}, - {737, {wxPaintDC, new_1, 1}}, - {738, {wxPaintDC, 'Destroy', undefined}}, - {740, {wxMemoryDC, new_1_0, 1}}, - {741, {wxMemoryDC, new_1_1, 1}}, - {742, {wxMemoryDC, new_0, 0}}, - {744, {wxMemoryDC, destruct, 0}}, - {745, {wxMemoryDC, selectObject, 1}}, - {746, {wxMemoryDC, selectObjectAsSource, 1}}, - {747, {wxBufferedDC, new_0, 0}}, - {748, {wxBufferedDC, new_2, 2}}, - {749, {wxBufferedDC, new_3, 3}}, - {750, {wxBufferedDC, destruct, 0}}, - {751, {wxBufferedDC, init_2, 2}}, - {752, {wxBufferedDC, init_3, 3}}, - {753, {wxBufferedPaintDC, new_3, 3}}, - {754, {wxBufferedPaintDC, new_2, 2}}, - {755, {wxBufferedPaintDC, destruct, 0}}, - {756, {wxGraphicsObject, destruct, 0}}, - {757, {wxGraphicsObject, getRenderer, 0}}, - {758, {wxGraphicsObject, isNull, 0}}, - {759, {wxGraphicsContext, destruct, 0}}, - {760, {wxGraphicsContext, create_1_1, 1}}, - {761, {wxGraphicsContext, create_1_0, 1}}, - {762, {wxGraphicsContext, create_0, 0}}, - {763, {wxGraphicsContext, createPen, 1}}, - {764, {wxGraphicsContext, createBrush, 1}}, - {765, {wxGraphicsContext, createRadialGradientBrush, 7}}, - {766, {wxGraphicsContext, createLinearGradientBrush, 6}}, - {767, {wxGraphicsContext, createFont, 2}}, - {768, {wxGraphicsContext, createMatrix, 1}}, - {769, {wxGraphicsContext, createPath, 0}}, - {770, {wxGraphicsContext, clip_1, 1}}, - {771, {wxGraphicsContext, clip_4, 4}}, - {772, {wxGraphicsContext, resetClip, 0}}, - {773, {wxGraphicsContext, drawBitmap, 5}}, - {774, {wxGraphicsContext, drawEllipse, 4}}, - {775, {wxGraphicsContext, drawIcon, 5}}, - {776, {wxGraphicsContext, drawLines, 3}}, - {777, {wxGraphicsContext, drawPath, 2}}, - {778, {wxGraphicsContext, drawRectangle, 4}}, - {779, {wxGraphicsContext, drawRoundedRectangle, 5}}, - {780, {wxGraphicsContext, drawText_3, 3}}, - {781, {wxGraphicsContext, drawText_4_0, 4}}, - {782, {wxGraphicsContext, drawText_4_1, 4}}, - {783, {wxGraphicsContext, drawText_5, 5}}, - {784, {wxGraphicsContext, fillPath, 2}}, - {785, {wxGraphicsContext, strokePath, 1}}, - {786, {wxGraphicsContext, getPartialTextExtents, 2}}, - {787, {wxGraphicsContext, getTextExtent, 5}}, - {788, {wxGraphicsContext, rotate, 1}}, - {789, {wxGraphicsContext, scale, 2}}, - {790, {wxGraphicsContext, translate, 2}}, - {791, {wxGraphicsContext, getTransform, 0}}, - {792, {wxGraphicsContext, setTransform, 1}}, - {793, {wxGraphicsContext, concatTransform, 1}}, - {794, {wxGraphicsContext, setBrush_1_1, 1}}, - {795, {wxGraphicsContext, setBrush_1_0, 1}}, - {796, {wxGraphicsContext, setFont_1, 1}}, - {797, {wxGraphicsContext, setFont_2, 2}}, - {798, {wxGraphicsContext, setPen_1_0, 1}}, - {799, {wxGraphicsContext, setPen_1_1, 1}}, - {800, {wxGraphicsContext, strokeLine, 4}}, - {801, {wxGraphicsContext, strokeLines, 2}}, - {803, {wxGraphicsMatrix, concat, 1}}, - {805, {wxGraphicsMatrix, get, 1}}, - {806, {wxGraphicsMatrix, invert, 0}}, - {807, {wxGraphicsMatrix, isEqual, 1}}, - {809, {wxGraphicsMatrix, isIdentity, 0}}, - {810, {wxGraphicsMatrix, rotate, 1}}, - {811, {wxGraphicsMatrix, scale, 2}}, - {812, {wxGraphicsMatrix, translate, 2}}, - {813, {wxGraphicsMatrix, set, 1}}, - {814, {wxGraphicsMatrix, transformPoint, 2}}, - {815, {wxGraphicsMatrix, transformDistance, 2}}, - {816, {wxGraphicsPath, moveToPoint_2, 2}}, - {817, {wxGraphicsPath, moveToPoint_1, 1}}, - {818, {wxGraphicsPath, addArc_6, 6}}, - {819, {wxGraphicsPath, addArc_5, 5}}, - {820, {wxGraphicsPath, addArcToPoint, 5}}, - {821, {wxGraphicsPath, addCircle, 3}}, - {822, {wxGraphicsPath, addCurveToPoint_6, 6}}, - {823, {wxGraphicsPath, addCurveToPoint_3, 3}}, - {824, {wxGraphicsPath, addEllipse, 4}}, - {825, {wxGraphicsPath, addLineToPoint_2, 2}}, - {826, {wxGraphicsPath, addLineToPoint_1, 1}}, - {827, {wxGraphicsPath, addPath, 1}}, - {828, {wxGraphicsPath, addQuadCurveToPoint, 4}}, - {829, {wxGraphicsPath, addRectangle, 4}}, - {830, {wxGraphicsPath, addRoundedRectangle, 5}}, - {831, {wxGraphicsPath, closeSubpath, 0}}, - {832, {wxGraphicsPath, contains_3, 3}}, - {833, {wxGraphicsPath, contains_2, 2}}, - {835, {wxGraphicsPath, getBox, 0}}, - {837, {wxGraphicsPath, getCurrentPoint, 0}}, - {838, {wxGraphicsPath, transform, 1}}, - {839, {wxGraphicsRenderer, getDefaultRenderer, 0}}, - {840, {wxGraphicsRenderer, createContext_1_1, 1}}, - {841, {wxGraphicsRenderer, createContext_1_0, 1}}, - {842, {wxGraphicsRenderer, createPen, 1}}, - {843, {wxGraphicsRenderer, createBrush, 1}}, - {844, {wxGraphicsRenderer, createLinearGradientBrush, 6}}, - {845, {wxGraphicsRenderer, createRadialGradientBrush, 7}}, - {846, {wxGraphicsRenderer, createFont, 2}}, - {847, {wxGraphicsRenderer, createMatrix, 1}}, - {848, {wxGraphicsRenderer, createPath, 0}}, - {850, {wxMenuBar, new_1, 1}}, - {852, {wxMenuBar, new_0, 0}}, - {854, {wxMenuBar, destruct, 0}}, - {855, {wxMenuBar, append, 2}}, - {856, {wxMenuBar, check, 2}}, - {857, {wxMenuBar, enable_2, 2}}, - {858, {wxMenuBar, enable_1, 1}}, - {859, {wxMenuBar, enableTop, 2}}, - {860, {wxMenuBar, findMenu, 1}}, - {861, {wxMenuBar, findMenuItem, 2}}, - {862, {wxMenuBar, findItem, 2}}, - {863, {wxMenuBar, getHelpString, 1}}, - {864, {wxMenuBar, getLabel_1, 1}}, - {865, {wxMenuBar, getLabel_0, 0}}, - {866, {wxMenuBar, getLabelTop, 1}}, - {867, {wxMenuBar, getMenu, 1}}, - {868, {wxMenuBar, getMenuCount, 0}}, - {869, {wxMenuBar, insert, 3}}, - {870, {wxMenuBar, isChecked, 1}}, - {871, {wxMenuBar, isEnabled_1, 1}}, - {872, {wxMenuBar, isEnabled_0, 0}}, - {873, {wxMenuBar, remove, 1}}, - {874, {wxMenuBar, replace, 3}}, - {875, {wxMenuBar, setHelpString, 2}}, - {876, {wxMenuBar, setLabel_2, 2}}, - {877, {wxMenuBar, setLabel_1, 1}}, - {878, {wxMenuBar, setLabelTop, 2}}, - {879, {wxControl, getLabel, 0}}, - {880, {wxControl, setLabel, 1}}, - {881, {wxControlWithItems, append_1, 1}}, - {882, {wxControlWithItems, append_2, 2}}, - {883, {wxControlWithItems, appendStrings_1, 1}}, - {884, {wxControlWithItems, clear, 0}}, - {885, {wxControlWithItems, delete, 1}}, - {886, {wxControlWithItems, findString, 2}}, - {887, {wxControlWithItems, getClientData, 1}}, - {888, {wxControlWithItems, setClientData, 2}}, - {889, {wxControlWithItems, getCount, 0}}, - {890, {wxControlWithItems, getSelection, 0}}, - {891, {wxControlWithItems, getString, 1}}, - {892, {wxControlWithItems, getStringSelection, 0}}, - {893, {wxControlWithItems, insert_2, 2}}, - {894, {wxControlWithItems, insert_3, 3}}, - {895, {wxControlWithItems, isEmpty, 0}}, - {896, {wxControlWithItems, select, 1}}, - {897, {wxControlWithItems, setSelection, 1}}, - {898, {wxControlWithItems, setString, 2}}, - {899, {wxControlWithItems, setStringSelection, 1}}, - {902, {wxMenu, new_2, 2}}, - {903, {wxMenu, new_1, 1}}, - {905, {wxMenu, destruct, 0}}, - {906, {wxMenu, append_3, 3}}, - {907, {wxMenu, append_1, 1}}, - {908, {wxMenu, append_4_0, 4}}, - {909, {wxMenu, append_4_1, 4}}, - {910, {wxMenu, appendCheckItem, 3}}, - {911, {wxMenu, appendRadioItem, 3}}, - {912, {wxMenu, appendSeparator, 0}}, - {913, {wxMenu, break, 0}}, - {914, {wxMenu, check, 2}}, - {915, {wxMenu, delete_1_0, 1}}, - {916, {wxMenu, delete_1_1, 1}}, - {917, {wxMenu, destroy_1_0, 1}}, - {918, {wxMenu, destroy_1_1, 1}}, - {919, {wxMenu, enable, 2}}, - {920, {wxMenu, findItem_1, 1}}, - {921, {wxMenu, findItem_2, 2}}, - {922, {wxMenu, findItemByPosition, 1}}, - {923, {wxMenu, getHelpString, 1}}, - {924, {wxMenu, getLabel, 1}}, - {925, {wxMenu, getMenuItemCount, 0}}, - {926, {wxMenu, getMenuItems, 0}}, - {928, {wxMenu, getTitle, 0}}, - {929, {wxMenu, insert_2, 2}}, - {930, {wxMenu, insert_3, 3}}, - {931, {wxMenu, insert_5_1, 5}}, - {932, {wxMenu, insert_5_0, 5}}, - {933, {wxMenu, insertCheckItem, 4}}, - {934, {wxMenu, insertRadioItem, 4}}, - {935, {wxMenu, insertSeparator, 1}}, - {936, {wxMenu, isChecked, 1}}, - {937, {wxMenu, isEnabled, 1}}, - {938, {wxMenu, prepend_1, 1}}, - {939, {wxMenu, prepend_2, 2}}, - {940, {wxMenu, prepend_4_1, 4}}, - {941, {wxMenu, prepend_4_0, 4}}, - {942, {wxMenu, prependCheckItem, 3}}, - {943, {wxMenu, prependRadioItem, 3}}, - {944, {wxMenu, prependSeparator, 0}}, - {945, {wxMenu, remove_1_0, 1}}, - {946, {wxMenu, remove_1_1, 1}}, - {947, {wxMenu, setHelpString, 2}}, - {948, {wxMenu, setLabel, 2}}, - {949, {wxMenu, setTitle, 1}}, - {950, {wxMenuItem, new, 1}}, - {952, {wxMenuItem, destruct, 0}}, - {953, {wxMenuItem, check, 1}}, - {954, {wxMenuItem, enable, 1}}, - {955, {wxMenuItem, getBitmap, 0}}, - {956, {wxMenuItem, getHelp, 0}}, - {957, {wxMenuItem, getId, 0}}, - {958, {wxMenuItem, getKind, 0}}, - {959, {wxMenuItem, getLabel, 0}}, - {960, {wxMenuItem, getLabelFromText, 1}}, - {961, {wxMenuItem, getMenu, 0}}, - {962, {wxMenuItem, getText, 0}}, - {963, {wxMenuItem, getSubMenu, 0}}, - {964, {wxMenuItem, isCheckable, 0}}, - {965, {wxMenuItem, isChecked, 0}}, - {966, {wxMenuItem, isEnabled, 0}}, - {967, {wxMenuItem, isSeparator, 0}}, - {968, {wxMenuItem, isSubMenu, 0}}, - {969, {wxMenuItem, setBitmap, 1}}, - {970, {wxMenuItem, setHelp, 1}}, - {971, {wxMenuItem, setMenu, 1}}, - {972, {wxMenuItem, setSubMenu, 1}}, - {973, {wxMenuItem, setText, 1}}, - {974, {wxToolBar, addControl, 1}}, - {975, {wxToolBar, addSeparator, 0}}, - {976, {wxToolBar, addTool_5, 5}}, - {977, {wxToolBar, addTool_4_0, 4}}, - {978, {wxToolBar, addTool_1, 1}}, - {979, {wxToolBar, addTool_4_1, 4}}, - {980, {wxToolBar, addTool_3, 3}}, - {981, {wxToolBar, addTool_6, 6}}, - {982, {wxToolBar, addCheckTool, 4}}, - {983, {wxToolBar, addRadioTool, 4}}, - {984, {wxToolBar, deleteTool, 1}}, - {985, {wxToolBar, deleteToolByPos, 1}}, - {986, {wxToolBar, enableTool, 2}}, - {987, {wxToolBar, findById, 1}}, - {988, {wxToolBar, findControl, 1}}, - {989, {wxToolBar, findToolForPosition, 2}}, - {990, {wxToolBar, getToolSize, 0}}, - {991, {wxToolBar, getToolBitmapSize, 0}}, - {992, {wxToolBar, getMargins, 0}}, - {993, {wxToolBar, getToolEnabled, 1}}, - {994, {wxToolBar, getToolLongHelp, 1}}, - {995, {wxToolBar, getToolPacking, 0}}, - {996, {wxToolBar, getToolPos, 1}}, - {997, {wxToolBar, getToolSeparation, 0}}, - {998, {wxToolBar, getToolShortHelp, 1}}, - {999, {wxToolBar, getToolState, 1}}, - {1000, {wxToolBar, insertControl, 2}}, - {1001, {wxToolBar, insertSeparator, 1}}, - {1002, {wxToolBar, insertTool_5, 5}}, - {1003, {wxToolBar, insertTool_2, 2}}, - {1004, {wxToolBar, insertTool_4, 4}}, - {1005, {wxToolBar, realize, 0}}, - {1006, {wxToolBar, removeTool, 1}}, - {1007, {wxToolBar, setMargins, 2}}, - {1008, {wxToolBar, setToolBitmapSize, 1}}, - {1009, {wxToolBar, setToolLongHelp, 2}}, - {1010, {wxToolBar, setToolPacking, 1}}, - {1011, {wxToolBar, setToolShortHelp, 2}}, - {1012, {wxToolBar, setToolSeparation, 1}}, - {1013, {wxToolBar, toggleTool, 2}}, - {1015, {wxStatusBar, new_0, 0}}, - {1016, {wxStatusBar, new_2, 2}}, - {1018, {wxStatusBar, destruct, 0}}, - {1019, {wxStatusBar, create, 2}}, - {1020, {wxStatusBar, getFieldRect, 2}}, - {1021, {wxStatusBar, getFieldsCount, 0}}, - {1022, {wxStatusBar, getStatusText, 1}}, - {1023, {wxStatusBar, popStatusText, 1}}, - {1024, {wxStatusBar, pushStatusText, 2}}, - {1025, {wxStatusBar, setFieldsCount, 2}}, - {1026, {wxStatusBar, setMinHeight, 1}}, - {1027, {wxStatusBar, setStatusText, 2}}, - {1028, {wxStatusBar, setStatusWidths, 2}}, - {1029, {wxStatusBar, setStatusStyles, 2}}, - {1030, {wxBitmap, new_0, 0}}, - {1031, {wxBitmap, new_3, 3}}, - {1032, {wxBitmap, new_4, 4}}, - {1033, {wxBitmap, new_2_0, 2}}, - {1034, {wxBitmap, new_2_1, 2}}, - {1035, {wxBitmap, destruct, 0}}, - {1036, {wxBitmap, convertToImage, 0}}, - {1037, {wxBitmap, copyFromIcon, 1}}, - {1038, {wxBitmap, create, 3}}, - {1039, {wxBitmap, getDepth, 0}}, - {1040, {wxBitmap, getHeight, 0}}, - {1041, {wxBitmap, getPalette, 0}}, - {1042, {wxBitmap, getMask, 0}}, - {1043, {wxBitmap, getWidth, 0}}, - {1044, {wxBitmap, getSubBitmap, 1}}, - {1045, {wxBitmap, loadFile, 2}}, - {1046, {wxBitmap, ok, 0}}, - {1047, {wxBitmap, saveFile, 3}}, - {1048, {wxBitmap, setDepth, 1}}, - {1049, {wxBitmap, setHeight, 1}}, - {1050, {wxBitmap, setMask, 1}}, - {1051, {wxBitmap, setPalette, 1}}, - {1052, {wxBitmap, setWidth, 1}}, - {1053, {wxIcon, new_0, 0}}, - {1054, {wxIcon, new_2, 2}}, - {1055, {wxIcon, new_1, 1}}, - {1056, {wxIcon, copyFromBitmap, 1}}, - {1057, {wxIcon, 'Destroy', undefined}}, - {1058, {wxIconBundle, new_0, 0}}, - {1059, {wxIconBundle, new_2, 2}}, - {1060, {wxIconBundle, new_1_0, 1}}, - {1061, {wxIconBundle, new_1_1, 1}}, - {1062, {wxIconBundle, destruct, 0}}, - {1063, {wxIconBundle, addIcon_2, 2}}, - {1064, {wxIconBundle, addIcon_1, 1}}, - {1065, {wxIconBundle, getIcon_1_1, 1}}, - {1066, {wxIconBundle, getIcon_1_0, 1}}, - {1067, {wxCursor, new_0, 0}}, - {1068, {wxCursor, new_1_0, 1}}, - {1069, {wxCursor, new_1_1, 1}}, - {1070, {wxCursor, new_4, 4}}, - {1071, {wxCursor, destruct, 0}}, - {1072, {wxCursor, ok, 0}}, - {1073, {wxMask, new_0, 0}}, - {1074, {wxMask, new_2_1, 2}}, - {1075, {wxMask, new_2_0, 2}}, - {1076, {wxMask, new_1, 1}}, - {1077, {wxMask, destruct, 0}}, - {1078, {wxMask, create_2_1, 2}}, - {1079, {wxMask, create_2_0, 2}}, - {1080, {wxMask, create_1, 1}}, - {1081, {wxImage, new_0, 0}}, - {1082, {wxImage, new_3_0, 3}}, - {1083, {wxImage, new_4, 4}}, - {1084, {wxImage, new_5, 5}}, - {1085, {wxImage, new_2, 2}}, - {1086, {wxImage, new_3_1, 3}}, - {1087, {wxImage, blur, 1}}, - {1088, {wxImage, blurHorizontal, 1}}, - {1089, {wxImage, blurVertical, 1}}, - {1090, {wxImage, convertAlphaToMask, 1}}, - {1091, {wxImage, convertToGreyscale, 1}}, - {1092, {wxImage, convertToMono, 3}}, - {1093, {wxImage, copy, 0}}, - {1094, {wxImage, create_3, 3}}, - {1095, {wxImage, create_4, 4}}, - {1096, {wxImage, create_5, 5}}, - {1097, {wxImage, 'Destroy', 0}}, - {1098, {wxImage, findFirstUnusedColour, 4}}, - {1099, {wxImage, getImageExtWildcard, 0}}, - {1100, {wxImage, getAlpha_2, 2}}, - {1101, {wxImage, getAlpha_0, 0}}, - {1102, {wxImage, getBlue, 2}}, - {1103, {wxImage, getData, 0}}, - {1104, {wxImage, getGreen, 2}}, - {1105, {wxImage, getImageCount, 2}}, - {1106, {wxImage, getHeight, 0}}, - {1107, {wxImage, getMaskBlue, 0}}, - {1108, {wxImage, getMaskGreen, 0}}, - {1109, {wxImage, getMaskRed, 0}}, - {1110, {wxImage, getOrFindMaskColour, 3}}, - {1111, {wxImage, getPalette, 0}}, - {1112, {wxImage, getRed, 2}}, - {1113, {wxImage, getSubImage, 1}}, - {1114, {wxImage, getWidth, 0}}, - {1115, {wxImage, hasAlpha, 0}}, - {1116, {wxImage, hasMask, 0}}, - {1117, {wxImage, getOption, 1}}, - {1118, {wxImage, getOptionInt, 1}}, - {1119, {wxImage, hasOption, 1}}, - {1120, {wxImage, initAlpha, 0}}, - {1121, {wxImage, initStandardHandlers, 0}}, - {1122, {wxImage, isTransparent, 3}}, - {1123, {wxImage, loadFile_2, 2}}, - {1124, {wxImage, loadFile_3, 3}}, - {1125, {wxImage, ok, 0}}, - {1126, {wxImage, removeHandler, 1}}, - {1127, {wxImage, mirror, 1}}, - {1128, {wxImage, replace, 6}}, - {1129, {wxImage, rescale, 3}}, - {1130, {wxImage, resize, 3}}, - {1131, {wxImage, rotate, 3}}, - {1132, {wxImage, rotateHue, 1}}, - {1133, {wxImage, rotate90, 1}}, - {1134, {wxImage, saveFile_1, 1}}, - {1135, {wxImage, saveFile_2_0, 2}}, - {1136, {wxImage, saveFile_2_1, 2}}, - {1137, {wxImage, scale, 3}}, - {1138, {wxImage, size, 3}}, - {1139, {wxImage, setAlpha_3, 3}}, - {1140, {wxImage, setAlpha_2, 2}}, - {1141, {wxImage, setData_2, 2}}, - {1142, {wxImage, setData_4, 4}}, - {1143, {wxImage, setMask, 1}}, - {1144, {wxImage, setMaskColour, 3}}, - {1145, {wxImage, setMaskFromImage, 4}}, - {1146, {wxImage, setOption_2_1, 2}}, - {1147, {wxImage, setOption_2_0, 2}}, - {1148, {wxImage, setPalette, 1}}, - {1149, {wxImage, setRGB_5, 5}}, - {1150, {wxImage, setRGB_4, 4}}, - {1151, {wxImage, 'Destroy', undefined}}, - {1152, {wxBrush, new_0, 0}}, - {1153, {wxBrush, new_2, 2}}, - {1154, {wxBrush, new_1, 1}}, - {1156, {wxBrush, destruct, 0}}, - {1157, {wxBrush, getColour, 0}}, - {1158, {wxBrush, getStipple, 0}}, - {1159, {wxBrush, getStyle, 0}}, - {1160, {wxBrush, isHatch, 0}}, - {1161, {wxBrush, isOk, 0}}, - {1162, {wxBrush, setColour_1, 1}}, - {1163, {wxBrush, setColour_3, 3}}, - {1164, {wxBrush, setStipple, 1}}, - {1165, {wxBrush, setStyle, 1}}, - {1166, {wxPen, new_0, 0}}, - {1167, {wxPen, new_2, 2}}, - {1168, {wxPen, destruct, 0}}, - {1169, {wxPen, getCap, 0}}, - {1170, {wxPen, getColour, 0}}, - {1171, {wxPen, getJoin, 0}}, - {1172, {wxPen, getStyle, 0}}, - {1173, {wxPen, getWidth, 0}}, - {1174, {wxPen, isOk, 0}}, - {1175, {wxPen, setCap, 1}}, - {1176, {wxPen, setColour_1, 1}}, - {1177, {wxPen, setColour_3, 3}}, - {1178, {wxPen, setJoin, 1}}, - {1179, {wxPen, setStyle, 1}}, - {1180, {wxPen, setWidth, 1}}, - {1181, {wxRegion, new_0, 0}}, - {1182, {wxRegion, new_4, 4}}, - {1183, {wxRegion, new_2, 2}}, - {1184, {wxRegion, new_1_1, 1}}, - {1186, {wxRegion, new_1_0, 1}}, - {1188, {wxRegion, destruct, 0}}, - {1189, {wxRegion, clear, 0}}, - {1190, {wxRegion, contains_2, 2}}, - {1191, {wxRegion, contains_1_0, 1}}, - {1192, {wxRegion, contains_4, 4}}, - {1193, {wxRegion, contains_1_1, 1}}, - {1194, {wxRegion, convertToBitmap, 0}}, - {1195, {wxRegion, getBox, 0}}, - {1196, {wxRegion, intersect_4, 4}}, - {1197, {wxRegion, intersect_1_1, 1}}, - {1198, {wxRegion, intersect_1_0, 1}}, - {1199, {wxRegion, isEmpty, 0}}, - {1200, {wxRegion, subtract_4, 4}}, - {1201, {wxRegion, subtract_1_1, 1}}, - {1202, {wxRegion, subtract_1_0, 1}}, - {1203, {wxRegion, offset_2, 2}}, - {1204, {wxRegion, offset_1, 1}}, - {1205, {wxRegion, union_4, 4}}, - {1206, {wxRegion, union_1_2, 1}}, - {1207, {wxRegion, union_1_1, 1}}, - {1208, {wxRegion, union_1_0, 1}}, - {1209, {wxRegion, union_3, 3}}, - {1210, {wxRegion, xor_4, 4}}, - {1211, {wxRegion, xor_1_1, 1}}, - {1212, {wxRegion, xor_1_0, 1}}, - {1213, {wxAcceleratorTable, new_0, 0}}, - {1214, {wxAcceleratorTable, new_2, 2}}, - {1215, {wxAcceleratorTable, destruct, 0}}, - {1216, {wxAcceleratorTable, ok, 0}}, - {1217, {wxAcceleratorEntry, new_1_0, 1}}, - {1218, {wxAcceleratorEntry, new_1_1, 1}}, - {1219, {wxAcceleratorEntry, getCommand, 0}}, - {1220, {wxAcceleratorEntry, getFlags, 0}}, - {1221, {wxAcceleratorEntry, getKeyCode, 0}}, - {1222, {wxAcceleratorEntry, set, 4}}, - {1223, {wxAcceleratorEntry, 'Destroy', undefined}}, - {1228, {wxCaret, new_3, 3}}, - {1229, {wxCaret, new_2, 2}}, - {1231, {wxCaret, destruct, 0}}, - {1232, {wxCaret, create_3, 3}}, - {1233, {wxCaret, create_2, 2}}, - {1234, {wxCaret, getBlinkTime, 0}}, - {1236, {wxCaret, getPosition, 0}}, - {1238, {wxCaret, getSize, 0}}, - {1239, {wxCaret, getWindow, 0}}, - {1240, {wxCaret, hide, 0}}, - {1241, {wxCaret, isOk, 0}}, - {1242, {wxCaret, isVisible, 0}}, - {1243, {wxCaret, move_2, 2}}, - {1244, {wxCaret, move_1, 1}}, - {1245, {wxCaret, setBlinkTime, 1}}, - {1246, {wxCaret, setSize_2, 2}}, - {1247, {wxCaret, setSize_1, 1}}, - {1248, {wxCaret, show, 1}}, - {1249, {wxSizer, add_2_1, 2}}, - {1250, {wxSizer, add_2_0, 2}}, - {1251, {wxSizer, add_3, 3}}, - {1252, {wxSizer, add_2_3, 2}}, - {1253, {wxSizer, add_2_2, 2}}, - {1254, {wxSizer, addSpacer, 1}}, - {1255, {wxSizer, addStretchSpacer, 1}}, - {1256, {wxSizer, calcMin, 0}}, - {1257, {wxSizer, clear, 1}}, - {1258, {wxSizer, detach_1_2, 1}}, - {1259, {wxSizer, detach_1_1, 1}}, - {1260, {wxSizer, detach_1_0, 1}}, - {1261, {wxSizer, fit, 1}}, - {1262, {wxSizer, fitInside, 1}}, - {1263, {wxSizer, getChildren, 0}}, - {1264, {wxSizer, getItem_2_1, 2}}, - {1265, {wxSizer, getItem_2_0, 2}}, - {1266, {wxSizer, getItem_1, 1}}, - {1267, {wxSizer, getSize, 0}}, - {1268, {wxSizer, getPosition, 0}}, - {1269, {wxSizer, getMinSize, 0}}, - {1270, {wxSizer, hide_2_0, 2}}, - {1271, {wxSizer, hide_2_1, 2}}, - {1272, {wxSizer, hide_1, 1}}, - {1273, {wxSizer, insert_3_1, 3}}, - {1274, {wxSizer, insert_3_0, 3}}, - {1275, {wxSizer, insert_4, 4}}, - {1276, {wxSizer, insert_3_3, 3}}, - {1277, {wxSizer, insert_3_2, 3}}, - {1278, {wxSizer, insert_2, 2}}, - {1279, {wxSizer, insertSpacer, 2}}, - {1280, {wxSizer, insertStretchSpacer, 2}}, - {1281, {wxSizer, isShown_1_2, 1}}, - {1282, {wxSizer, isShown_1_1, 1}}, - {1283, {wxSizer, isShown_1_0, 1}}, - {1284, {wxSizer, layout, 0}}, - {1285, {wxSizer, prepend_2_1, 2}}, - {1286, {wxSizer, prepend_2_0, 2}}, - {1287, {wxSizer, prepend_3, 3}}, - {1288, {wxSizer, prepend_2_3, 2}}, - {1289, {wxSizer, prepend_2_2, 2}}, - {1290, {wxSizer, prepend_1, 1}}, - {1291, {wxSizer, prependSpacer, 1}}, - {1292, {wxSizer, prependStretchSpacer, 1}}, - {1293, {wxSizer, recalcSizes, 0}}, - {1294, {wxSizer, remove_1_1, 1}}, - {1295, {wxSizer, remove_1_0, 1}}, - {1296, {wxSizer, replace_3_1, 3}}, - {1297, {wxSizer, replace_3_0, 3}}, - {1298, {wxSizer, replace_2, 2}}, - {1299, {wxSizer, setDimension, 4}}, - {1300, {wxSizer, setMinSize_2, 2}}, - {1301, {wxSizer, setMinSize_1, 1}}, - {1302, {wxSizer, setItemMinSize_3_2, 3}}, - {1303, {wxSizer, setItemMinSize_2_2, 2}}, - {1304, {wxSizer, setItemMinSize_3_1, 3}}, - {1305, {wxSizer, setItemMinSize_2_1, 2}}, - {1306, {wxSizer, setItemMinSize_3_0, 3}}, - {1307, {wxSizer, setItemMinSize_2_0, 2}}, - {1308, {wxSizer, setSizeHints, 1}}, - {1309, {wxSizer, setVirtualSizeHints, 1}}, - {1310, {wxSizer, show_2_2, 2}}, - {1311, {wxSizer, show_2_1, 2}}, - {1312, {wxSizer, show_2_0, 2}}, - {1313, {wxSizer, show_1, 1}}, - {1314, {wxSizerFlags, new, 1}}, - {1315, {wxSizerFlags, align, 1}}, - {1316, {wxSizerFlags, border_2, 2}}, - {1317, {wxSizerFlags, border_1, 1}}, - {1318, {wxSizerFlags, center, 0}}, - {1319, {wxSizerFlags, centre, 0}}, - {1320, {wxSizerFlags, expand, 0}}, - {1321, {wxSizerFlags, left, 0}}, - {1322, {wxSizerFlags, proportion, 1}}, - {1323, {wxSizerFlags, right, 0}}, - {1324, {wxSizerFlags, 'Destroy', undefined}}, - {1325, {wxSizerItem, new_5_1, 5}}, - {1326, {wxSizerItem, new_2_1, 2}}, - {1327, {wxSizerItem, new_5_0, 5}}, - {1328, {wxSizerItem, new_2_0, 2}}, - {1329, {wxSizerItem, new_6, 6}}, - {1330, {wxSizerItem, new_3, 3}}, - {1331, {wxSizerItem, new_0, 0}}, - {1332, {wxSizerItem, destruct, 0}}, - {1333, {wxSizerItem, calcMin, 0}}, - {1334, {wxSizerItem, deleteWindows, 0}}, - {1335, {wxSizerItem, detachSizer, 0}}, - {1336, {wxSizerItem, getBorder, 0}}, - {1337, {wxSizerItem, getFlag, 0}}, - {1338, {wxSizerItem, getMinSize, 0}}, - {1339, {wxSizerItem, getPosition, 0}}, - {1340, {wxSizerItem, getProportion, 0}}, - {1341, {wxSizerItem, getRatio, 0}}, - {1342, {wxSizerItem, getRect, 0}}, - {1343, {wxSizerItem, getSize, 0}}, - {1344, {wxSizerItem, getSizer, 0}}, - {1345, {wxSizerItem, getSpacer, 0}}, - {1346, {wxSizerItem, getUserData, 0}}, - {1347, {wxSizerItem, getWindow, 0}}, - {1348, {wxSizerItem, isSizer, 0}}, - {1349, {wxSizerItem, isShown, 0}}, - {1350, {wxSizerItem, isSpacer, 0}}, - {1351, {wxSizerItem, isWindow, 0}}, - {1352, {wxSizerItem, setBorder, 1}}, - {1353, {wxSizerItem, setDimension, 2}}, - {1354, {wxSizerItem, setFlag, 1}}, - {1355, {wxSizerItem, setInitSize, 2}}, - {1356, {wxSizerItem, setMinSize_1, 1}}, - {1357, {wxSizerItem, setMinSize_2, 2}}, - {1358, {wxSizerItem, setProportion, 1}}, - {1359, {wxSizerItem, setRatio_2, 2}}, - {1360, {wxSizerItem, setRatio_1_1, 1}}, - {1361, {wxSizerItem, setRatio_1_0, 1}}, - {1362, {wxSizerItem, setSizer, 1}}, - {1363, {wxSizerItem, setSpacer_1, 1}}, - {1364, {wxSizerItem, setSpacer_2, 2}}, - {1365, {wxSizerItem, setWindow, 1}}, - {1366, {wxSizerItem, show, 1}}, - {1367, {wxBoxSizer, new, 1}}, - {1368, {wxBoxSizer, getOrientation, 0}}, - {1369, {wxBoxSizer, 'Destroy', undefined}}, - {1370, {wxStaticBoxSizer, new_2, 2}}, - {1371, {wxStaticBoxSizer, new_3, 3}}, - {1372, {wxStaticBoxSizer, getStaticBox, 0}}, - {1373, {wxStaticBoxSizer, 'Destroy', undefined}}, - {1374, {wxGridSizer, new_4, 4}}, - {1375, {wxGridSizer, new_2, 2}}, - {1376, {wxGridSizer, getCols, 0}}, - {1377, {wxGridSizer, getHGap, 0}}, - {1378, {wxGridSizer, getRows, 0}}, - {1379, {wxGridSizer, getVGap, 0}}, - {1380, {wxGridSizer, setCols, 1}}, - {1381, {wxGridSizer, setHGap, 1}}, - {1382, {wxGridSizer, setRows, 1}}, - {1383, {wxGridSizer, setVGap, 1}}, - {1384, {wxGridSizer, 'Destroy', undefined}}, - {1385, {wxFlexGridSizer, new_4, 4}}, - {1386, {wxFlexGridSizer, new_2, 2}}, - {1387, {wxFlexGridSizer, addGrowableCol, 2}}, - {1388, {wxFlexGridSizer, addGrowableRow, 2}}, - {1389, {wxFlexGridSizer, getFlexibleDirection, 0}}, - {1390, {wxFlexGridSizer, getNonFlexibleGrowMode, 0}}, - {1391, {wxFlexGridSizer, removeGrowableCol, 1}}, - {1392, {wxFlexGridSizer, removeGrowableRow, 1}}, - {1393, {wxFlexGridSizer, setFlexibleDirection, 1}}, - {1394, {wxFlexGridSizer, setNonFlexibleGrowMode, 1}}, - {1395, {wxFlexGridSizer, 'Destroy', undefined}}, - {1396, {wxGridBagSizer, new, 1}}, - {1397, {wxGridBagSizer, add_3_2, 3}}, - {1398, {wxGridBagSizer, add_3_1, 3}}, - {1399, {wxGridBagSizer, add_4, 4}}, - {1400, {wxGridBagSizer, add_1_0, 1}}, - {1401, {wxGridBagSizer, add_2_1, 2}}, - {1402, {wxGridBagSizer, add_2_0, 2}}, - {1403, {wxGridBagSizer, add_3_0, 3}}, - {1404, {wxGridBagSizer, add_1_1, 1}}, - {1405, {wxGridBagSizer, calcMin, 0}}, - {1406, {wxGridBagSizer, checkForIntersection_2, 2}}, - {1407, {wxGridBagSizer, checkForIntersection_3, 3}}, - {1408, {wxGridBagSizer, findItem_1_1, 1}}, - {1409, {wxGridBagSizer, findItem_1_0, 1}}, - {1410, {wxGridBagSizer, findItemAtPoint, 1}}, - {1411, {wxGridBagSizer, findItemAtPosition, 1}}, - {1412, {wxGridBagSizer, findItemWithData, 1}}, - {1413, {wxGridBagSizer, getCellSize, 2}}, - {1414, {wxGridBagSizer, getEmptyCellSize, 0}}, - {1415, {wxGridBagSizer, getItemPosition_1_2, 1}}, - {1416, {wxGridBagSizer, getItemPosition_1_1, 1}}, - {1417, {wxGridBagSizer, getItemPosition_1_0, 1}}, - {1418, {wxGridBagSizer, getItemSpan_1_2, 1}}, - {1419, {wxGridBagSizer, getItemSpan_1_1, 1}}, - {1420, {wxGridBagSizer, getItemSpan_1_0, 1}}, - {1421, {wxGridBagSizer, setEmptyCellSize, 1}}, - {1422, {wxGridBagSizer, setItemPosition_2_2, 2}}, - {1423, {wxGridBagSizer, setItemPosition_2_1, 2}}, - {1424, {wxGridBagSizer, setItemPosition_2_0, 2}}, - {1425, {wxGridBagSizer, setItemSpan_2_2, 2}}, - {1426, {wxGridBagSizer, setItemSpan_2_1, 2}}, - {1427, {wxGridBagSizer, setItemSpan_2_0, 2}}, - {1428, {wxGridBagSizer, 'Destroy', undefined}}, - {1429, {wxStdDialogButtonSizer, new, 0}}, - {1430, {wxStdDialogButtonSizer, addButton, 1}}, - {1431, {wxStdDialogButtonSizer, realize, 0}}, - {1432, {wxStdDialogButtonSizer, setAffirmativeButton, 1}}, - {1433, {wxStdDialogButtonSizer, setCancelButton, 1}}, - {1434, {wxStdDialogButtonSizer, setNegativeButton, 1}}, - {1435, {wxStdDialogButtonSizer, 'Destroy', undefined}}, - {1436, {wxFont, new_0, 0}}, - {1437, {wxFont, new_1, 1}}, - {1438, {wxFont, new_5, 5}}, - {1440, {wxFont, destruct, 0}}, - {1441, {wxFont, isFixedWidth, 0}}, - {1442, {wxFont, getDefaultEncoding, 0}}, - {1443, {wxFont, getFaceName, 0}}, - {1444, {wxFont, getFamily, 0}}, - {1445, {wxFont, getNativeFontInfoDesc, 0}}, - {1446, {wxFont, getNativeFontInfoUserDesc, 0}}, - {1447, {wxFont, getPointSize, 0}}, - {1448, {wxFont, getStyle, 0}}, - {1449, {wxFont, getUnderlined, 0}}, - {1450, {wxFont, getWeight, 0}}, - {1451, {wxFont, ok, 0}}, - {1452, {wxFont, setDefaultEncoding, 1}}, - {1453, {wxFont, setFaceName, 1}}, - {1454, {wxFont, setFamily, 1}}, - {1455, {wxFont, setPointSize, 1}}, - {1456, {wxFont, setStyle, 1}}, - {1457, {wxFont, setUnderlined, 1}}, - {1458, {wxFont, setWeight, 1}}, - {1459, {wxToolTip, enable, 1}}, - {1460, {wxToolTip, setDelay, 1}}, - {1461, {wxToolTip, new, 1}}, - {1462, {wxToolTip, setTip, 1}}, - {1463, {wxToolTip, getTip, 0}}, - {1464, {wxToolTip, getWindow, 0}}, - {1465, {wxToolTip, 'Destroy', undefined}}, - {1467, {wxButton, new_3, 3}}, - {1468, {wxButton, new_0, 0}}, - {1469, {wxButton, destruct, 0}}, - {1470, {wxButton, create, 3}}, - {1471, {wxButton, getDefaultSize, 0}}, - {1472, {wxButton, setDefault, 0}}, - {1473, {wxButton, setLabel, 1}}, - {1475, {wxBitmapButton, new_4, 4}}, - {1476, {wxBitmapButton, new_0, 0}}, - {1477, {wxBitmapButton, create, 4}}, - {1478, {wxBitmapButton, getBitmapDisabled, 0}}, - {1480, {wxBitmapButton, getBitmapFocus, 0}}, - {1482, {wxBitmapButton, getBitmapLabel, 0}}, - {1484, {wxBitmapButton, getBitmapSelected, 0}}, - {1486, {wxBitmapButton, setBitmapDisabled, 1}}, - {1487, {wxBitmapButton, setBitmapFocus, 1}}, - {1488, {wxBitmapButton, setBitmapLabel, 1}}, - {1489, {wxBitmapButton, setBitmapSelected, 1}}, - {1490, {wxBitmapButton, 'Destroy', undefined}}, - {1491, {wxToggleButton, new_0, 0}}, - {1492, {wxToggleButton, new_4, 4}}, - {1493, {wxToggleButton, create, 4}}, - {1494, {wxToggleButton, getValue, 0}}, - {1495, {wxToggleButton, setValue, 1}}, - {1496, {wxToggleButton, 'Destroy', undefined}}, - {1497, {wxCalendarCtrl, new_0, 0}}, - {1498, {wxCalendarCtrl, new_3, 3}}, - {1499, {wxCalendarCtrl, create, 3}}, - {1500, {wxCalendarCtrl, destruct, 0}}, - {1501, {wxCalendarCtrl, setDate, 1}}, - {1502, {wxCalendarCtrl, getDate, 0}}, - {1503, {wxCalendarCtrl, enableYearChange, 1}}, - {1504, {wxCalendarCtrl, enableMonthChange, 1}}, - {1505, {wxCalendarCtrl, enableHolidayDisplay, 1}}, - {1506, {wxCalendarCtrl, setHeaderColours, 2}}, - {1507, {wxCalendarCtrl, getHeaderColourFg, 0}}, - {1508, {wxCalendarCtrl, getHeaderColourBg, 0}}, - {1509, {wxCalendarCtrl, setHighlightColours, 2}}, - {1510, {wxCalendarCtrl, getHighlightColourFg, 0}}, - {1511, {wxCalendarCtrl, getHighlightColourBg, 0}}, - {1512, {wxCalendarCtrl, setHolidayColours, 2}}, - {1513, {wxCalendarCtrl, getHolidayColourFg, 0}}, - {1514, {wxCalendarCtrl, getHolidayColourBg, 0}}, - {1515, {wxCalendarCtrl, getAttr, 1}}, - {1516, {wxCalendarCtrl, setAttr, 2}}, - {1517, {wxCalendarCtrl, setHoliday, 1}}, - {1518, {wxCalendarCtrl, resetAttr, 1}}, - {1519, {wxCalendarCtrl, hitTest, 2}}, - {1520, {wxCalendarDateAttr, new_0, 0}}, - {1521, {wxCalendarDateAttr, new_2_1, 2}}, - {1522, {wxCalendarDateAttr, new_2_0, 2}}, - {1523, {wxCalendarDateAttr, setTextColour, 1}}, - {1524, {wxCalendarDateAttr, setBackgroundColour, 1}}, - {1525, {wxCalendarDateAttr, setBorderColour, 1}}, - {1526, {wxCalendarDateAttr, setFont, 1}}, - {1527, {wxCalendarDateAttr, setBorder, 1}}, - {1528, {wxCalendarDateAttr, setHoliday, 1}}, - {1529, {wxCalendarDateAttr, hasTextColour, 0}}, - {1530, {wxCalendarDateAttr, hasBackgroundColour, 0}}, - {1531, {wxCalendarDateAttr, hasBorderColour, 0}}, - {1532, {wxCalendarDateAttr, hasFont, 0}}, - {1533, {wxCalendarDateAttr, hasBorder, 0}}, - {1534, {wxCalendarDateAttr, isHoliday, 0}}, - {1535, {wxCalendarDateAttr, getTextColour, 0}}, - {1536, {wxCalendarDateAttr, getBackgroundColour, 0}}, - {1537, {wxCalendarDateAttr, getBorderColour, 0}}, - {1538, {wxCalendarDateAttr, getFont, 0}}, - {1539, {wxCalendarDateAttr, getBorder, 0}}, - {1540, {wxCalendarDateAttr, 'Destroy', undefined}}, - {1542, {wxCheckBox, new_4, 4}}, - {1543, {wxCheckBox, new_0, 0}}, - {1544, {wxCheckBox, create, 4}}, - {1545, {wxCheckBox, getValue, 0}}, - {1546, {wxCheckBox, get3StateValue, 0}}, - {1547, {wxCheckBox, is3rdStateAllowedForUser, 0}}, - {1548, {wxCheckBox, is3State, 0}}, - {1549, {wxCheckBox, isChecked, 0}}, - {1550, {wxCheckBox, setValue, 1}}, - {1551, {wxCheckBox, set3StateValue, 1}}, - {1552, {wxCheckBox, 'Destroy', undefined}}, - {1553, {wxCheckListBox, new_0, 0}}, - {1555, {wxCheckListBox, new_3, 3}}, - {1556, {wxCheckListBox, check, 2}}, - {1557, {wxCheckListBox, isChecked, 1}}, - {1558, {wxCheckListBox, 'Destroy', undefined}}, - {1561, {wxChoice, new_3, 3}}, - {1562, {wxChoice, new_0, 0}}, - {1564, {wxChoice, destruct, 0}}, - {1566, {wxChoice, create, 6}}, - {1567, {wxChoice, delete, 1}}, - {1568, {wxChoice, getColumns, 0}}, - {1569, {wxChoice, setColumns, 1}}, - {1570, {wxComboBox, new_0, 0}}, - {1572, {wxComboBox, new_3, 3}}, - {1573, {wxComboBox, destruct, 0}}, - {1575, {wxComboBox, create, 7}}, - {1576, {wxComboBox, canCopy, 0}}, - {1577, {wxComboBox, canCut, 0}}, - {1578, {wxComboBox, canPaste, 0}}, - {1579, {wxComboBox, canRedo, 0}}, - {1580, {wxComboBox, canUndo, 0}}, - {1581, {wxComboBox, copy, 0}}, - {1582, {wxComboBox, cut, 0}}, - {1583, {wxComboBox, getInsertionPoint, 0}}, - {1584, {wxComboBox, getLastPosition, 0}}, - {1585, {wxComboBox, getValue, 0}}, - {1586, {wxComboBox, paste, 0}}, - {1587, {wxComboBox, redo, 0}}, - {1588, {wxComboBox, replace, 3}}, - {1589, {wxComboBox, remove, 2}}, - {1590, {wxComboBox, setInsertionPoint, 1}}, - {1591, {wxComboBox, setInsertionPointEnd, 0}}, - {1592, {wxComboBox, setSelection_1, 1}}, - {1593, {wxComboBox, setSelection_2, 2}}, - {1594, {wxComboBox, setValue, 1}}, - {1595, {wxComboBox, undo, 0}}, - {1596, {wxGauge, new_0, 0}}, - {1597, {wxGauge, new_4, 4}}, - {1598, {wxGauge, create, 4}}, - {1599, {wxGauge, getBezelFace, 0}}, - {1600, {wxGauge, getRange, 0}}, - {1601, {wxGauge, getShadowWidth, 0}}, - {1602, {wxGauge, getValue, 0}}, - {1603, {wxGauge, isVertical, 0}}, - {1604, {wxGauge, setBezelFace, 1}}, - {1605, {wxGauge, setRange, 1}}, - {1606, {wxGauge, setShadowWidth, 1}}, - {1607, {wxGauge, setValue, 1}}, - {1608, {wxGauge, pulse, 0}}, - {1609, {wxGauge, 'Destroy', undefined}}, - {1610, {wxGenericDirCtrl, new_0, 0}}, - {1611, {wxGenericDirCtrl, new_2, 2}}, - {1612, {wxGenericDirCtrl, destruct, 0}}, - {1613, {wxGenericDirCtrl, create, 2}}, - {1614, {wxGenericDirCtrl, init, 0}}, - {1615, {wxGenericDirCtrl, collapseTree, 0}}, - {1616, {wxGenericDirCtrl, expandPath, 1}}, - {1617, {wxGenericDirCtrl, getDefaultPath, 0}}, - {1618, {wxGenericDirCtrl, getPath, 0}}, - {1619, {wxGenericDirCtrl, getFilePath, 0}}, - {1620, {wxGenericDirCtrl, getFilter, 0}}, - {1621, {wxGenericDirCtrl, getFilterIndex, 0}}, - {1622, {wxGenericDirCtrl, getRootId, 0}}, - {1623, {wxGenericDirCtrl, getTreeCtrl, 0}}, - {1624, {wxGenericDirCtrl, reCreateTree, 0}}, - {1625, {wxGenericDirCtrl, setDefaultPath, 1}}, - {1626, {wxGenericDirCtrl, setFilter, 1}}, - {1627, {wxGenericDirCtrl, setFilterIndex, 1}}, - {1628, {wxGenericDirCtrl, setPath, 1}}, - {1630, {wxStaticBox, new_4, 4}}, - {1631, {wxStaticBox, new_0, 0}}, - {1632, {wxStaticBox, create, 4}}, - {1633, {wxStaticBox, 'Destroy', undefined}}, - {1635, {wxStaticLine, new_2, 2}}, - {1636, {wxStaticLine, new_0, 0}}, - {1637, {wxStaticLine, create, 2}}, - {1638, {wxStaticLine, isVertical, 0}}, - {1639, {wxStaticLine, getDefaultSize, 0}}, - {1640, {wxStaticLine, 'Destroy', undefined}}, - {1643, {wxListBox, new_3, 3}}, - {1644, {wxListBox, new_0, 0}}, - {1646, {wxListBox, destruct, 0}}, - {1648, {wxListBox, create, 6}}, - {1649, {wxListBox, deselect, 1}}, - {1650, {wxListBox, getSelections, 1}}, - {1651, {wxListBox, insertItems, 2}}, - {1652, {wxListBox, isSelected, 1}}, - {1653, {wxListBox, set, 1}}, - {1654, {wxListBox, hitTest, 1}}, - {1655, {wxListBox, setFirstItem_1_0, 1}}, - {1656, {wxListBox, setFirstItem_1_1, 1}}, - {1657, {wxListCtrl, new_0, 0}}, - {1658, {wxListCtrl, new_2, 2}}, - {1659, {wxListCtrl, arrange, 1}}, - {1660, {wxListCtrl, assignImageList, 2}}, - {1661, {wxListCtrl, clearAll, 0}}, - {1662, {wxListCtrl, create, 2}}, - {1663, {wxListCtrl, deleteAllItems, 0}}, - {1664, {wxListCtrl, deleteColumn, 1}}, - {1665, {wxListCtrl, deleteItem, 1}}, - {1666, {wxListCtrl, editLabel, 1}}, - {1667, {wxListCtrl, ensureVisible, 1}}, - {1668, {wxListCtrl, findItem_3_0, 3}}, - {1669, {wxListCtrl, findItem_3_1, 3}}, - {1670, {wxListCtrl, getColumn, 2}}, - {1671, {wxListCtrl, getColumnCount, 0}}, - {1672, {wxListCtrl, getColumnWidth, 1}}, - {1673, {wxListCtrl, getCountPerPage, 0}}, - {1674, {wxListCtrl, getEditControl, 0}}, - {1675, {wxListCtrl, getImageList, 1}}, - {1676, {wxListCtrl, getItem, 1}}, - {1677, {wxListCtrl, getItemBackgroundColour, 1}}, - {1678, {wxListCtrl, getItemCount, 0}}, - {1679, {wxListCtrl, getItemData, 1}}, - {1680, {wxListCtrl, getItemFont, 1}}, - {1681, {wxListCtrl, getItemPosition, 2}}, - {1682, {wxListCtrl, getItemRect, 3}}, - {1683, {wxListCtrl, getItemSpacing, 0}}, - {1684, {wxListCtrl, getItemState, 2}}, - {1685, {wxListCtrl, getItemText, 1}}, - {1686, {wxListCtrl, getItemTextColour, 1}}, - {1687, {wxListCtrl, getNextItem, 2}}, - {1688, {wxListCtrl, getSelectedItemCount, 0}}, - {1689, {wxListCtrl, getTextColour, 0}}, - {1690, {wxListCtrl, getTopItem, 0}}, - {1691, {wxListCtrl, getViewRect, 0}}, - {1692, {wxListCtrl, hitTest, 2}}, - {1693, {wxListCtrl, insertColumn_2, 2}}, - {1694, {wxListCtrl, insertColumn_3, 3}}, - {1695, {wxListCtrl, insertItem_1, 1}}, - {1696, {wxListCtrl, insertItem_2_1, 2}}, - {1697, {wxListCtrl, insertItem_2_0, 2}}, - {1698, {wxListCtrl, insertItem_3, 3}}, - {1699, {wxListCtrl, refreshItem, 1}}, - {1700, {wxListCtrl, refreshItems, 2}}, - {1701, {wxListCtrl, scrollList, 2}}, - {1702, {wxListCtrl, setBackgroundColour, 1}}, - {1703, {wxListCtrl, setColumn, 2}}, - {1704, {wxListCtrl, setColumnWidth, 2}}, - {1705, {wxListCtrl, setImageList, 2}}, - {1706, {wxListCtrl, setItem_1, 1}}, - {1707, {wxListCtrl, setItem_4, 4}}, - {1708, {wxListCtrl, setItemBackgroundColour, 2}}, - {1709, {wxListCtrl, setItemCount, 1}}, - {1710, {wxListCtrl, setItemData, 2}}, - {1711, {wxListCtrl, setItemFont, 2}}, - {1712, {wxListCtrl, setItemImage, 3}}, - {1713, {wxListCtrl, setItemColumnImage, 3}}, - {1714, {wxListCtrl, setItemPosition, 2}}, - {1715, {wxListCtrl, setItemState, 3}}, - {1716, {wxListCtrl, setItemText, 2}}, - {1717, {wxListCtrl, setItemTextColour, 2}}, - {1718, {wxListCtrl, setSingleStyle, 2}}, - {1719, {wxListCtrl, setTextColour, 1}}, - {1720, {wxListCtrl, setWindowStyleFlag, 1}}, - {1721, {wxListCtrl, sortItems, 2}}, - {1722, {wxListCtrl, 'Destroy', undefined}}, - {1723, {wxListView, clearColumnImage, 1}}, - {1724, {wxListView, focus, 1}}, - {1725, {wxListView, getFirstSelected, 0}}, - {1726, {wxListView, getFocusedItem, 0}}, - {1727, {wxListView, getNextSelected, 1}}, - {1728, {wxListView, isSelected, 1}}, - {1729, {wxListView, select, 2}}, - {1730, {wxListView, setColumnImage, 2}}, - {1731, {wxListItem, new_0, 0}}, - {1732, {wxListItem, new_1, 1}}, - {1733, {wxListItem, destruct, 0}}, - {1734, {wxListItem, clear, 0}}, - {1735, {wxListItem, getAlign, 0}}, - {1736, {wxListItem, getBackgroundColour, 0}}, - {1737, {wxListItem, getColumn, 0}}, - {1738, {wxListItem, getFont, 0}}, - {1739, {wxListItem, getId, 0}}, - {1740, {wxListItem, getImage, 0}}, - {1741, {wxListItem, getMask, 0}}, - {1742, {wxListItem, getState, 0}}, - {1743, {wxListItem, getText, 0}}, - {1744, {wxListItem, getTextColour, 0}}, - {1745, {wxListItem, getWidth, 0}}, - {1746, {wxListItem, setAlign, 1}}, - {1747, {wxListItem, setBackgroundColour, 1}}, - {1748, {wxListItem, setColumn, 1}}, - {1749, {wxListItem, setFont, 1}}, - {1750, {wxListItem, setId, 1}}, - {1751, {wxListItem, setImage, 1}}, - {1752, {wxListItem, setMask, 1}}, - {1753, {wxListItem, setState, 1}}, - {1754, {wxListItem, setStateMask, 1}}, - {1755, {wxListItem, setText, 1}}, - {1756, {wxListItem, setTextColour, 1}}, - {1757, {wxListItem, setWidth, 1}}, - {1758, {wxListItemAttr, new_0, 0}}, - {1759, {wxListItemAttr, new_3, 3}}, - {1760, {wxListItemAttr, getBackgroundColour, 0}}, - {1761, {wxListItemAttr, getFont, 0}}, - {1762, {wxListItemAttr, getTextColour, 0}}, - {1763, {wxListItemAttr, hasBackgroundColour, 0}}, - {1764, {wxListItemAttr, hasFont, 0}}, - {1765, {wxListItemAttr, hasTextColour, 0}}, - {1766, {wxListItemAttr, setBackgroundColour, 1}}, - {1767, {wxListItemAttr, setFont, 1}}, - {1768, {wxListItemAttr, setTextColour, 1}}, - {1769, {wxListItemAttr, 'Destroy', undefined}}, - {1770, {wxImageList, new_0, 0}}, - {1771, {wxImageList, new_3, 3}}, - {1772, {wxImageList, add_1, 1}}, - {1773, {wxImageList, add_2_0, 2}}, - {1774, {wxImageList, add_2_1, 2}}, - {1775, {wxImageList, create, 3}}, - {1777, {wxImageList, draw, 5}}, - {1778, {wxImageList, getBitmap, 1}}, - {1779, {wxImageList, getIcon, 1}}, - {1780, {wxImageList, getImageCount, 0}}, - {1781, {wxImageList, getSize, 3}}, - {1782, {wxImageList, remove, 1}}, - {1783, {wxImageList, removeAll, 0}}, - {1784, {wxImageList, replace_2, 2}}, - {1785, {wxImageList, replace_3, 3}}, - {1786, {wxImageList, 'Destroy', undefined}}, - {1787, {wxTextAttr, new_0, 0}}, - {1788, {wxTextAttr, new_2, 2}}, - {1789, {wxTextAttr, getAlignment, 0}}, - {1790, {wxTextAttr, getBackgroundColour, 0}}, - {1791, {wxTextAttr, getFont, 0}}, - {1792, {wxTextAttr, getLeftIndent, 0}}, - {1793, {wxTextAttr, getLeftSubIndent, 0}}, - {1794, {wxTextAttr, getRightIndent, 0}}, - {1795, {wxTextAttr, getTabs, 0}}, - {1796, {wxTextAttr, getTextColour, 0}}, - {1797, {wxTextAttr, hasBackgroundColour, 0}}, - {1798, {wxTextAttr, hasFont, 0}}, - {1799, {wxTextAttr, hasTextColour, 0}}, - {1800, {wxTextAttr, getFlags, 0}}, - {1801, {wxTextAttr, isDefault, 0}}, - {1802, {wxTextAttr, setAlignment, 1}}, - {1803, {wxTextAttr, setBackgroundColour, 1}}, - {1804, {wxTextAttr, setFlags, 1}}, - {1805, {wxTextAttr, setFont, 2}}, - {1806, {wxTextAttr, setLeftIndent, 2}}, - {1807, {wxTextAttr, setRightIndent, 1}}, - {1808, {wxTextAttr, setTabs, 1}}, - {1809, {wxTextAttr, setTextColour, 1}}, - {1810, {wxTextAttr, 'Destroy', undefined}}, - {1812, {wxTextCtrl, new_3, 3}}, - {1813, {wxTextCtrl, new_0, 0}}, - {1815, {wxTextCtrl, destruct, 0}}, - {1816, {wxTextCtrl, appendText, 1}}, - {1817, {wxTextCtrl, canCopy, 0}}, - {1818, {wxTextCtrl, canCut, 0}}, - {1819, {wxTextCtrl, canPaste, 0}}, - {1820, {wxTextCtrl, canRedo, 0}}, - {1821, {wxTextCtrl, canUndo, 0}}, - {1822, {wxTextCtrl, clear, 0}}, - {1823, {wxTextCtrl, copy, 0}}, - {1824, {wxTextCtrl, create, 3}}, - {1825, {wxTextCtrl, cut, 0}}, - {1826, {wxTextCtrl, discardEdits, 0}}, - {1827, {wxTextCtrl, changeValue, 1}}, - {1828, {wxTextCtrl, emulateKeyPress, 1}}, - {1829, {wxTextCtrl, getDefaultStyle, 0}}, - {1830, {wxTextCtrl, getInsertionPoint, 0}}, - {1831, {wxTextCtrl, getLastPosition, 0}}, - {1832, {wxTextCtrl, getLineLength, 1}}, - {1833, {wxTextCtrl, getLineText, 1}}, - {1834, {wxTextCtrl, getNumberOfLines, 0}}, - {1835, {wxTextCtrl, getRange, 2}}, - {1836, {wxTextCtrl, getSelection, 2}}, - {1837, {wxTextCtrl, getStringSelection, 0}}, - {1838, {wxTextCtrl, getStyle, 2}}, - {1839, {wxTextCtrl, getValue, 0}}, - {1840, {wxTextCtrl, isEditable, 0}}, - {1841, {wxTextCtrl, isModified, 0}}, - {1842, {wxTextCtrl, isMultiLine, 0}}, - {1843, {wxTextCtrl, isSingleLine, 0}}, - {1844, {wxTextCtrl, loadFile, 2}}, - {1845, {wxTextCtrl, markDirty, 0}}, - {1846, {wxTextCtrl, paste, 0}}, - {1847, {wxTextCtrl, positionToXY, 3}}, - {1848, {wxTextCtrl, redo, 0}}, - {1849, {wxTextCtrl, remove, 2}}, - {1850, {wxTextCtrl, replace, 3}}, - {1851, {wxTextCtrl, saveFile, 1}}, - {1852, {wxTextCtrl, setDefaultStyle, 1}}, - {1853, {wxTextCtrl, setEditable, 1}}, - {1854, {wxTextCtrl, setInsertionPoint, 1}}, - {1855, {wxTextCtrl, setInsertionPointEnd, 0}}, - {1857, {wxTextCtrl, setMaxLength, 1}}, - {1858, {wxTextCtrl, setSelection, 2}}, - {1859, {wxTextCtrl, setStyle, 3}}, - {1860, {wxTextCtrl, setValue, 1}}, - {1861, {wxTextCtrl, showPosition, 1}}, - {1862, {wxTextCtrl, undo, 0}}, - {1863, {wxTextCtrl, writeText, 1}}, - {1864, {wxTextCtrl, xYToPosition, 2}}, - {1867, {wxNotebook, new_0, 0}}, - {1868, {wxNotebook, new_3, 3}}, - {1869, {wxNotebook, destruct, 0}}, - {1870, {wxNotebook, addPage, 3}}, - {1871, {wxNotebook, advanceSelection, 1}}, - {1872, {wxNotebook, assignImageList, 1}}, - {1873, {wxNotebook, create, 3}}, - {1874, {wxNotebook, deleteAllPages, 0}}, - {1875, {wxNotebook, deletePage, 1}}, - {1876, {wxNotebook, removePage, 1}}, - {1877, {wxNotebook, getCurrentPage, 0}}, - {1878, {wxNotebook, getImageList, 0}}, - {1880, {wxNotebook, getPage, 1}}, - {1881, {wxNotebook, getPageCount, 0}}, - {1882, {wxNotebook, getPageImage, 1}}, - {1883, {wxNotebook, getPageText, 1}}, - {1884, {wxNotebook, getRowCount, 0}}, - {1885, {wxNotebook, getSelection, 0}}, - {1886, {wxNotebook, getThemeBackgroundColour, 0}}, - {1888, {wxNotebook, hitTest, 2}}, - {1890, {wxNotebook, insertPage, 4}}, - {1891, {wxNotebook, setImageList, 1}}, - {1892, {wxNotebook, setPadding, 1}}, - {1893, {wxNotebook, setPageSize, 1}}, - {1894, {wxNotebook, setPageImage, 2}}, - {1895, {wxNotebook, setPageText, 2}}, - {1896, {wxNotebook, setSelection, 1}}, - {1897, {wxNotebook, changeSelection, 1}}, - {1898, {wxChoicebook, new_0, 0}}, - {1899, {wxChoicebook, new_3, 3}}, - {1900, {wxChoicebook, addPage, 3}}, - {1901, {wxChoicebook, advanceSelection, 1}}, - {1902, {wxChoicebook, assignImageList, 1}}, - {1903, {wxChoicebook, create, 3}}, - {1904, {wxChoicebook, deleteAllPages, 0}}, - {1905, {wxChoicebook, deletePage, 1}}, - {1906, {wxChoicebook, removePage, 1}}, - {1907, {wxChoicebook, getCurrentPage, 0}}, - {1908, {wxChoicebook, getImageList, 0}}, - {1910, {wxChoicebook, getPage, 1}}, - {1911, {wxChoicebook, getPageCount, 0}}, - {1912, {wxChoicebook, getPageImage, 1}}, - {1913, {wxChoicebook, getPageText, 1}}, - {1914, {wxChoicebook, getSelection, 0}}, - {1915, {wxChoicebook, hitTest, 2}}, - {1916, {wxChoicebook, insertPage, 4}}, - {1917, {wxChoicebook, setImageList, 1}}, - {1918, {wxChoicebook, setPageSize, 1}}, - {1919, {wxChoicebook, setPageImage, 2}}, - {1920, {wxChoicebook, setPageText, 2}}, - {1921, {wxChoicebook, setSelection, 1}}, - {1922, {wxChoicebook, changeSelection, 1}}, - {1923, {wxChoicebook, 'Destroy', undefined}}, - {1924, {wxToolbook, new_0, 0}}, - {1925, {wxToolbook, new_3, 3}}, - {1926, {wxToolbook, addPage, 3}}, - {1927, {wxToolbook, advanceSelection, 1}}, - {1928, {wxToolbook, assignImageList, 1}}, - {1929, {wxToolbook, create, 3}}, - {1930, {wxToolbook, deleteAllPages, 0}}, - {1931, {wxToolbook, deletePage, 1}}, - {1932, {wxToolbook, removePage, 1}}, - {1933, {wxToolbook, getCurrentPage, 0}}, - {1934, {wxToolbook, getImageList, 0}}, - {1936, {wxToolbook, getPage, 1}}, - {1937, {wxToolbook, getPageCount, 0}}, - {1938, {wxToolbook, getPageImage, 1}}, - {1939, {wxToolbook, getPageText, 1}}, - {1940, {wxToolbook, getSelection, 0}}, - {1942, {wxToolbook, hitTest, 2}}, - {1943, {wxToolbook, insertPage, 4}}, - {1944, {wxToolbook, setImageList, 1}}, - {1945, {wxToolbook, setPageSize, 1}}, - {1946, {wxToolbook, setPageImage, 2}}, - {1947, {wxToolbook, setPageText, 2}}, - {1948, {wxToolbook, setSelection, 1}}, - {1949, {wxToolbook, changeSelection, 1}}, - {1950, {wxToolbook, 'Destroy', undefined}}, - {1951, {wxListbook, new_0, 0}}, - {1952, {wxListbook, new_3, 3}}, - {1953, {wxListbook, addPage, 3}}, - {1954, {wxListbook, advanceSelection, 1}}, - {1955, {wxListbook, assignImageList, 1}}, - {1956, {wxListbook, create, 3}}, - {1957, {wxListbook, deleteAllPages, 0}}, - {1958, {wxListbook, deletePage, 1}}, - {1959, {wxListbook, removePage, 1}}, - {1960, {wxListbook, getCurrentPage, 0}}, - {1961, {wxListbook, getImageList, 0}}, - {1963, {wxListbook, getPage, 1}}, - {1964, {wxListbook, getPageCount, 0}}, - {1965, {wxListbook, getPageImage, 1}}, - {1966, {wxListbook, getPageText, 1}}, - {1967, {wxListbook, getSelection, 0}}, - {1969, {wxListbook, hitTest, 2}}, - {1970, {wxListbook, insertPage, 4}}, - {1971, {wxListbook, setImageList, 1}}, - {1972, {wxListbook, setPageSize, 1}}, - {1973, {wxListbook, setPageImage, 2}}, - {1974, {wxListbook, setPageText, 2}}, - {1975, {wxListbook, setSelection, 1}}, - {1976, {wxListbook, changeSelection, 1}}, - {1977, {wxListbook, 'Destroy', undefined}}, - {1978, {wxTreebook, new_0, 0}}, - {1979, {wxTreebook, new_3, 3}}, - {1980, {wxTreebook, addPage, 3}}, - {1981, {wxTreebook, advanceSelection, 1}}, - {1982, {wxTreebook, assignImageList, 1}}, - {1983, {wxTreebook, create, 3}}, - {1984, {wxTreebook, deleteAllPages, 0}}, - {1985, {wxTreebook, deletePage, 1}}, - {1986, {wxTreebook, removePage, 1}}, - {1987, {wxTreebook, getCurrentPage, 0}}, - {1988, {wxTreebook, getImageList, 0}}, - {1990, {wxTreebook, getPage, 1}}, - {1991, {wxTreebook, getPageCount, 0}}, - {1992, {wxTreebook, getPageImage, 1}}, - {1993, {wxTreebook, getPageText, 1}}, - {1994, {wxTreebook, getSelection, 0}}, - {1995, {wxTreebook, expandNode, 2}}, - {1996, {wxTreebook, isNodeExpanded, 1}}, - {1998, {wxTreebook, hitTest, 2}}, - {1999, {wxTreebook, insertPage, 4}}, - {2000, {wxTreebook, insertSubPage, 4}}, - {2001, {wxTreebook, setImageList, 1}}, - {2002, {wxTreebook, setPageSize, 1}}, - {2003, {wxTreebook, setPageImage, 2}}, - {2004, {wxTreebook, setPageText, 2}}, - {2005, {wxTreebook, setSelection, 1}}, - {2006, {wxTreebook, changeSelection, 1}}, - {2007, {wxTreebook, 'Destroy', undefined}}, - {2010, {wxTreeCtrl, new_2, 2}}, - {2011, {wxTreeCtrl, new_0, 0}}, - {2013, {wxTreeCtrl, destruct, 0}}, - {2014, {wxTreeCtrl, addRoot, 2}}, - {2015, {wxTreeCtrl, appendItem, 3}}, - {2016, {wxTreeCtrl, assignImageList, 1}}, - {2017, {wxTreeCtrl, assignStateImageList, 1}}, - {2018, {wxTreeCtrl, collapse, 1}}, - {2019, {wxTreeCtrl, collapseAndReset, 1}}, - {2020, {wxTreeCtrl, create, 2}}, - {2021, {wxTreeCtrl, delete, 1}}, - {2022, {wxTreeCtrl, deleteAllItems, 0}}, - {2023, {wxTreeCtrl, deleteChildren, 1}}, - {2024, {wxTreeCtrl, editLabel, 1}}, - {2025, {wxTreeCtrl, ensureVisible, 1}}, - {2026, {wxTreeCtrl, expand, 1}}, - {2027, {wxTreeCtrl, getBoundingRect, 3}}, - {2029, {wxTreeCtrl, getChildrenCount, 2}}, - {2030, {wxTreeCtrl, getCount, 0}}, - {2031, {wxTreeCtrl, getEditControl, 0}}, - {2032, {wxTreeCtrl, getFirstChild, 2}}, - {2033, {wxTreeCtrl, getNextChild, 2}}, - {2034, {wxTreeCtrl, getFirstVisibleItem, 0}}, - {2035, {wxTreeCtrl, getImageList, 0}}, - {2036, {wxTreeCtrl, getIndent, 0}}, - {2037, {wxTreeCtrl, getItemBackgroundColour, 1}}, - {2038, {wxTreeCtrl, getItemData, 1}}, - {2039, {wxTreeCtrl, getItemFont, 1}}, - {2040, {wxTreeCtrl, getItemImage_1, 1}}, - {2041, {wxTreeCtrl, getItemImage_2, 2}}, - {2042, {wxTreeCtrl, getItemText, 1}}, - {2043, {wxTreeCtrl, getItemTextColour, 1}}, - {2044, {wxTreeCtrl, getLastChild, 1}}, - {2045, {wxTreeCtrl, getNextSibling, 1}}, - {2046, {wxTreeCtrl, getNextVisible, 1}}, - {2047, {wxTreeCtrl, getItemParent, 1}}, - {2048, {wxTreeCtrl, getPrevSibling, 1}}, - {2049, {wxTreeCtrl, getPrevVisible, 1}}, - {2050, {wxTreeCtrl, getRootItem, 0}}, - {2051, {wxTreeCtrl, getSelection, 0}}, - {2052, {wxTreeCtrl, getSelections, 1}}, - {2053, {wxTreeCtrl, getStateImageList, 0}}, - {2054, {wxTreeCtrl, hitTest, 2}}, - {2056, {wxTreeCtrl, insertItem, 4}}, - {2057, {wxTreeCtrl, isBold, 1}}, - {2058, {wxTreeCtrl, isExpanded, 1}}, - {2059, {wxTreeCtrl, isSelected, 1}}, - {2060, {wxTreeCtrl, isVisible, 1}}, - {2061, {wxTreeCtrl, itemHasChildren, 1}}, - {2062, {wxTreeCtrl, isTreeItemIdOk, 1}}, - {2063, {wxTreeCtrl, prependItem, 3}}, - {2064, {wxTreeCtrl, scrollTo, 1}}, - {2065, {wxTreeCtrl, selectItem_1, 1}}, - {2066, {wxTreeCtrl, selectItem_2, 2}}, - {2067, {wxTreeCtrl, setIndent, 1}}, - {2068, {wxTreeCtrl, setImageList, 1}}, - {2069, {wxTreeCtrl, setItemBackgroundColour, 2}}, - {2070, {wxTreeCtrl, setItemBold, 2}}, - {2071, {wxTreeCtrl, setItemData, 2}}, - {2072, {wxTreeCtrl, setItemDropHighlight, 2}}, - {2073, {wxTreeCtrl, setItemFont, 2}}, - {2074, {wxTreeCtrl, setItemHasChildren, 2}}, - {2075, {wxTreeCtrl, setItemImage_2, 2}}, - {2076, {wxTreeCtrl, setItemImage_3, 3}}, - {2077, {wxTreeCtrl, setItemText, 2}}, - {2078, {wxTreeCtrl, setItemTextColour, 2}}, - {2079, {wxTreeCtrl, setStateImageList, 1}}, - {2080, {wxTreeCtrl, setWindowStyle, 1}}, - {2081, {wxTreeCtrl, sortChildren, 1}}, - {2082, {wxTreeCtrl, toggle, 1}}, - {2083, {wxTreeCtrl, toggleItemSelection, 1}}, - {2084, {wxTreeCtrl, unselect, 0}}, - {2085, {wxTreeCtrl, unselectAll, 0}}, - {2086, {wxTreeCtrl, unselectItem, 1}}, - {2087, {wxScrollBar, new_0, 0}}, - {2088, {wxScrollBar, new_3, 3}}, - {2089, {wxScrollBar, destruct, 0}}, - {2090, {wxScrollBar, create, 3}}, - {2091, {wxScrollBar, getRange, 0}}, - {2092, {wxScrollBar, getPageSize, 0}}, - {2093, {wxScrollBar, getThumbPosition, 0}}, - {2094, {wxScrollBar, getThumbSize, 0}}, - {2095, {wxScrollBar, setThumbPosition, 1}}, - {2096, {wxScrollBar, setScrollbar, 5}}, - {2098, {wxSpinButton, new_2, 2}}, - {2099, {wxSpinButton, new_0, 0}}, - {2100, {wxSpinButton, create, 2}}, - {2101, {wxSpinButton, getMax, 0}}, - {2102, {wxSpinButton, getMin, 0}}, - {2103, {wxSpinButton, getValue, 0}}, - {2104, {wxSpinButton, setRange, 2}}, - {2105, {wxSpinButton, setValue, 1}}, - {2106, {wxSpinButton, 'Destroy', undefined}}, - {2107, {wxSpinCtrl, new_0, 0}}, - {2108, {wxSpinCtrl, new_2, 2}}, - {2110, {wxSpinCtrl, create, 2}}, - {2113, {wxSpinCtrl, setValue_1_1, 1}}, - {2114, {wxSpinCtrl, setValue_1_0, 1}}, - {2116, {wxSpinCtrl, getValue, 0}}, - {2118, {wxSpinCtrl, setRange, 2}}, - {2119, {wxSpinCtrl, setSelection, 2}}, - {2121, {wxSpinCtrl, getMin, 0}}, - {2123, {wxSpinCtrl, getMax, 0}}, - {2124, {wxSpinCtrl, 'Destroy', undefined}}, - {2125, {wxStaticText, new_0, 0}}, - {2126, {wxStaticText, new_4, 4}}, - {2127, {wxStaticText, create, 4}}, - {2128, {wxStaticText, getLabel, 0}}, - {2129, {wxStaticText, setLabel, 1}}, - {2130, {wxStaticText, wrap, 1}}, - {2131, {wxStaticText, 'Destroy', undefined}}, - {2132, {wxStaticBitmap, new_0, 0}}, - {2133, {wxStaticBitmap, new_4, 4}}, - {2134, {wxStaticBitmap, create, 4}}, - {2135, {wxStaticBitmap, getBitmap, 0}}, - {2136, {wxStaticBitmap, setBitmap, 1}}, - {2137, {wxStaticBitmap, 'Destroy', undefined}}, - {2138, {wxRadioBox, new, 7}}, - {2140, {wxRadioBox, destruct, 0}}, - {2141, {wxRadioBox, create, 7}}, - {2142, {wxRadioBox, enable_2, 2}}, - {2143, {wxRadioBox, enable_1, 1}}, - {2144, {wxRadioBox, getSelection, 0}}, - {2145, {wxRadioBox, getString, 1}}, - {2146, {wxRadioBox, setSelection, 1}}, - {2147, {wxRadioBox, show_2, 2}}, - {2148, {wxRadioBox, show_1, 1}}, - {2149, {wxRadioBox, getColumnCount, 0}}, - {2150, {wxRadioBox, getItemHelpText, 1}}, - {2151, {wxRadioBox, getItemToolTip, 1}}, - {2153, {wxRadioBox, getItemFromPoint, 1}}, - {2154, {wxRadioBox, getRowCount, 0}}, - {2155, {wxRadioBox, isItemEnabled, 1}}, - {2156, {wxRadioBox, isItemShown, 1}}, - {2157, {wxRadioBox, setItemHelpText, 2}}, - {2158, {wxRadioBox, setItemToolTip, 2}}, - {2159, {wxRadioButton, new_0, 0}}, - {2160, {wxRadioButton, new_4, 4}}, - {2161, {wxRadioButton, create, 4}}, - {2162, {wxRadioButton, getValue, 0}}, - {2163, {wxRadioButton, setValue, 1}}, - {2164, {wxRadioButton, 'Destroy', undefined}}, - {2166, {wxSlider, new_6, 6}}, - {2167, {wxSlider, new_0, 0}}, - {2168, {wxSlider, create, 6}}, - {2169, {wxSlider, getLineSize, 0}}, - {2170, {wxSlider, getMax, 0}}, - {2171, {wxSlider, getMin, 0}}, - {2172, {wxSlider, getPageSize, 0}}, - {2173, {wxSlider, getThumbLength, 0}}, - {2174, {wxSlider, getValue, 0}}, - {2175, {wxSlider, setLineSize, 1}}, - {2176, {wxSlider, setPageSize, 1}}, - {2177, {wxSlider, setRange, 2}}, - {2178, {wxSlider, setThumbLength, 1}}, - {2179, {wxSlider, setValue, 1}}, - {2180, {wxSlider, 'Destroy', undefined}}, - {2182, {wxDialog, new_4, 4}}, - {2183, {wxDialog, new_0, 0}}, - {2185, {wxDialog, destruct, 0}}, - {2186, {wxDialog, create, 4}}, - {2187, {wxDialog, createButtonSizer, 1}}, - {2188, {wxDialog, createStdDialogButtonSizer, 1}}, - {2189, {wxDialog, endModal, 1}}, - {2190, {wxDialog, getAffirmativeId, 0}}, - {2191, {wxDialog, getReturnCode, 0}}, - {2192, {wxDialog, isModal, 0}}, - {2193, {wxDialog, setAffirmativeId, 1}}, - {2194, {wxDialog, setReturnCode, 1}}, - {2195, {wxDialog, show, 1}}, - {2196, {wxDialog, showModal, 0}}, - {2197, {wxColourDialog, new_0, 0}}, - {2198, {wxColourDialog, new_2, 2}}, - {2199, {wxColourDialog, destruct, 0}}, - {2200, {wxColourDialog, create, 2}}, - {2201, {wxColourDialog, getColourData, 0}}, - {2202, {wxColourData, new_0, 0}}, - {2203, {wxColourData, new_1, 1}}, - {2204, {wxColourData, destruct, 0}}, - {2205, {wxColourData, getChooseFull, 0}}, - {2206, {wxColourData, getColour, 0}}, - {2208, {wxColourData, getCustomColour, 1}}, - {2209, {wxColourData, setChooseFull, 1}}, - {2210, {wxColourData, setColour, 1}}, - {2211, {wxColourData, setCustomColour, 2}}, - {2212, {wxPalette, new_0, 0}}, - {2213, {wxPalette, new_4, 4}}, - {2215, {wxPalette, destruct, 0}}, - {2216, {wxPalette, create, 4}}, - {2217, {wxPalette, getColoursCount, 0}}, - {2218, {wxPalette, getPixel, 3}}, - {2219, {wxPalette, getRGB, 4}}, - {2220, {wxPalette, isOk, 0}}, - {2224, {wxDirDialog, new, 2}}, - {2225, {wxDirDialog, destruct, 0}}, - {2226, {wxDirDialog, getPath, 0}}, - {2227, {wxDirDialog, getMessage, 0}}, - {2228, {wxDirDialog, setMessage, 1}}, - {2229, {wxDirDialog, setPath, 1}}, - {2233, {wxFileDialog, new, 2}}, - {2234, {wxFileDialog, destruct, 0}}, - {2235, {wxFileDialog, getDirectory, 0}}, - {2236, {wxFileDialog, getFilename, 0}}, - {2237, {wxFileDialog, getFilenames, 1}}, - {2238, {wxFileDialog, getFilterIndex, 0}}, - {2239, {wxFileDialog, getMessage, 0}}, - {2240, {wxFileDialog, getPath, 0}}, - {2241, {wxFileDialog, getPaths, 1}}, - {2242, {wxFileDialog, getWildcard, 0}}, - {2243, {wxFileDialog, setDirectory, 1}}, - {2244, {wxFileDialog, setFilename, 1}}, - {2245, {wxFileDialog, setFilterIndex, 1}}, - {2246, {wxFileDialog, setMessage, 1}}, - {2247, {wxFileDialog, setPath, 1}}, - {2248, {wxFileDialog, setWildcard, 1}}, - {2249, {wxPickerBase, setInternalMargin, 1}}, - {2250, {wxPickerBase, getInternalMargin, 0}}, - {2251, {wxPickerBase, setTextCtrlProportion, 1}}, - {2252, {wxPickerBase, setPickerCtrlProportion, 1}}, - {2253, {wxPickerBase, getTextCtrlProportion, 0}}, - {2254, {wxPickerBase, getPickerCtrlProportion, 0}}, - {2255, {wxPickerBase, hasTextCtrl, 0}}, - {2256, {wxPickerBase, getTextCtrl, 0}}, - {2257, {wxPickerBase, isTextCtrlGrowable, 0}}, - {2258, {wxPickerBase, setPickerCtrlGrowable, 1}}, - {2259, {wxPickerBase, setTextCtrlGrowable, 1}}, - {2260, {wxPickerBase, isPickerCtrlGrowable, 0}}, - {2261, {wxFilePickerCtrl, new_0, 0}}, - {2262, {wxFilePickerCtrl, new_3, 3}}, - {2263, {wxFilePickerCtrl, create, 3}}, - {2264, {wxFilePickerCtrl, getPath, 0}}, - {2265, {wxFilePickerCtrl, setPath, 1}}, - {2266, {wxFilePickerCtrl, 'Destroy', undefined}}, - {2267, {wxDirPickerCtrl, new_0, 0}}, - {2268, {wxDirPickerCtrl, new_3, 3}}, - {2269, {wxDirPickerCtrl, create, 3}}, - {2270, {wxDirPickerCtrl, getPath, 0}}, - {2271, {wxDirPickerCtrl, setPath, 1}}, - {2272, {wxDirPickerCtrl, 'Destroy', undefined}}, - {2273, {wxColourPickerCtrl, new_0, 0}}, - {2274, {wxColourPickerCtrl, new_3, 3}}, - {2275, {wxColourPickerCtrl, create, 3}}, - {2276, {wxColourPickerCtrl, getColour, 0}}, - {2277, {wxColourPickerCtrl, setColour_1_1, 1}}, - {2278, {wxColourPickerCtrl, setColour_1_0, 1}}, - {2279, {wxColourPickerCtrl, 'Destroy', undefined}}, - {2280, {wxDatePickerCtrl, new_0, 0}}, - {2281, {wxDatePickerCtrl, new_3, 3}}, - {2282, {wxDatePickerCtrl, getRange, 2}}, - {2283, {wxDatePickerCtrl, getValue, 0}}, - {2284, {wxDatePickerCtrl, setRange, 2}}, - {2285, {wxDatePickerCtrl, setValue, 1}}, - {2286, {wxDatePickerCtrl, 'Destroy', undefined}}, - {2287, {wxFontPickerCtrl, new_0, 0}}, - {2288, {wxFontPickerCtrl, new_3, 3}}, - {2289, {wxFontPickerCtrl, create, 3}}, - {2290, {wxFontPickerCtrl, getSelectedFont, 0}}, - {2291, {wxFontPickerCtrl, setSelectedFont, 1}}, - {2292, {wxFontPickerCtrl, getMaxPointSize, 0}}, - {2293, {wxFontPickerCtrl, setMaxPointSize, 1}}, - {2294, {wxFontPickerCtrl, 'Destroy', undefined}}, - {2297, {wxFindReplaceDialog, new_0, 0}}, - {2298, {wxFindReplaceDialog, new_4, 4}}, - {2299, {wxFindReplaceDialog, destruct, 0}}, - {2300, {wxFindReplaceDialog, create, 4}}, - {2301, {wxFindReplaceDialog, getData, 0}}, - {2302, {wxFindReplaceData, new_0, 0}}, - {2303, {wxFindReplaceData, new_1, 1}}, - {2304, {wxFindReplaceData, getFindString, 0}}, - {2305, {wxFindReplaceData, getReplaceString, 0}}, - {2306, {wxFindReplaceData, getFlags, 0}}, - {2307, {wxFindReplaceData, setFlags, 1}}, - {2308, {wxFindReplaceData, setFindString, 1}}, - {2309, {wxFindReplaceData, setReplaceString, 1}}, - {2310, {wxFindReplaceData, 'Destroy', undefined}}, - {2311, {wxMultiChoiceDialog, new_0, 0}}, - {2313, {wxMultiChoiceDialog, new_5, 5}}, - {2314, {wxMultiChoiceDialog, getSelections, 0}}, - {2315, {wxMultiChoiceDialog, setSelections, 1}}, - {2316, {wxMultiChoiceDialog, 'Destroy', undefined}}, - {2317, {wxSingleChoiceDialog, new_0, 0}}, - {2319, {wxSingleChoiceDialog, new_5, 5}}, - {2320, {wxSingleChoiceDialog, getSelection, 0}}, - {2321, {wxSingleChoiceDialog, getStringSelection, 0}}, - {2322, {wxSingleChoiceDialog, setSelection, 1}}, - {2323, {wxSingleChoiceDialog, 'Destroy', undefined}}, - {2324, {wxTextEntryDialog, new, 3}}, - {2325, {wxTextEntryDialog, getValue, 0}}, - {2326, {wxTextEntryDialog, setValue, 1}}, - {2327, {wxTextEntryDialog, 'Destroy', undefined}}, - {2328, {wxPasswordEntryDialog, new, 3}}, - {2329, {wxPasswordEntryDialog, 'Destroy', undefined}}, - {2330, {wxFontData, new_0, 0}}, - {2331, {wxFontData, new_1, 1}}, - {2332, {wxFontData, destruct, 0}}, - {2333, {wxFontData, enableEffects, 1}}, - {2334, {wxFontData, getAllowSymbols, 0}}, - {2335, {wxFontData, getColour, 0}}, - {2336, {wxFontData, getChosenFont, 0}}, - {2337, {wxFontData, getEnableEffects, 0}}, - {2338, {wxFontData, getInitialFont, 0}}, - {2339, {wxFontData, getShowHelp, 0}}, - {2340, {wxFontData, setAllowSymbols, 1}}, - {2341, {wxFontData, setChosenFont, 1}}, - {2342, {wxFontData, setColour, 1}}, - {2343, {wxFontData, setInitialFont, 1}}, - {2344, {wxFontData, setRange, 2}}, - {2345, {wxFontData, setShowHelp, 1}}, - {2349, {wxFontDialog, new_0, 0}}, - {2351, {wxFontDialog, new_2, 2}}, - {2353, {wxFontDialog, create, 2}}, - {2354, {wxFontDialog, getFontData, 0}}, - {2356, {wxFontDialog, 'Destroy', undefined}}, - {2357, {wxProgressDialog, new, 3}}, - {2358, {wxProgressDialog, destruct, 0}}, - {2359, {wxProgressDialog, resume, 0}}, - {2360, {wxProgressDialog, update_2, 2}}, - {2361, {wxProgressDialog, update_0, 0}}, - {2362, {wxMessageDialog, new, 3}}, - {2363, {wxMessageDialog, destruct, 0}}, - {2364, {wxPageSetupDialog, new, 2}}, - {2365, {wxPageSetupDialog, destruct, 0}}, - {2366, {wxPageSetupDialog, getPageSetupData, 0}}, - {2367, {wxPageSetupDialog, showModal, 0}}, - {2368, {wxPageSetupDialogData, new_0, 0}}, - {2369, {wxPageSetupDialogData, new_1_0, 1}}, - {2370, {wxPageSetupDialogData, new_1_1, 1}}, - {2371, {wxPageSetupDialogData, destruct, 0}}, - {2372, {wxPageSetupDialogData, enableHelp, 1}}, - {2373, {wxPageSetupDialogData, enableMargins, 1}}, - {2374, {wxPageSetupDialogData, enableOrientation, 1}}, - {2375, {wxPageSetupDialogData, enablePaper, 1}}, - {2376, {wxPageSetupDialogData, enablePrinter, 1}}, - {2377, {wxPageSetupDialogData, getDefaultMinMargins, 0}}, - {2378, {wxPageSetupDialogData, getEnableMargins, 0}}, - {2379, {wxPageSetupDialogData, getEnableOrientation, 0}}, - {2380, {wxPageSetupDialogData, getEnablePaper, 0}}, - {2381, {wxPageSetupDialogData, getEnablePrinter, 0}}, - {2382, {wxPageSetupDialogData, getEnableHelp, 0}}, - {2383, {wxPageSetupDialogData, getDefaultInfo, 0}}, - {2384, {wxPageSetupDialogData, getMarginTopLeft, 0}}, - {2385, {wxPageSetupDialogData, getMarginBottomRight, 0}}, - {2386, {wxPageSetupDialogData, getMinMarginTopLeft, 0}}, - {2387, {wxPageSetupDialogData, getMinMarginBottomRight, 0}}, - {2388, {wxPageSetupDialogData, getPaperId, 0}}, - {2389, {wxPageSetupDialogData, getPaperSize, 0}}, - {2391, {wxPageSetupDialogData, getPrintData, 0}}, - {2392, {wxPageSetupDialogData, isOk, 0}}, - {2393, {wxPageSetupDialogData, setDefaultInfo, 1}}, - {2394, {wxPageSetupDialogData, setDefaultMinMargins, 1}}, - {2395, {wxPageSetupDialogData, setMarginTopLeft, 1}}, - {2396, {wxPageSetupDialogData, setMarginBottomRight, 1}}, - {2397, {wxPageSetupDialogData, setMinMarginTopLeft, 1}}, - {2398, {wxPageSetupDialogData, setMinMarginBottomRight, 1}}, - {2399, {wxPageSetupDialogData, setPaperId, 1}}, - {2400, {wxPageSetupDialogData, setPaperSize_1_1, 1}}, - {2401, {wxPageSetupDialogData, setPaperSize_1_0, 1}}, - {2402, {wxPageSetupDialogData, setPrintData, 1}}, - {2403, {wxPrintDialog, new_2_0, 2}}, - {2404, {wxPrintDialog, new_2_1, 2}}, - {2405, {wxPrintDialog, destruct, 0}}, - {2406, {wxPrintDialog, getPrintDialogData, 0}}, - {2407, {wxPrintDialog, getPrintDC, 0}}, - {2408, {wxPrintDialogData, new_0, 0}}, - {2409, {wxPrintDialogData, new_1_1, 1}}, - {2410, {wxPrintDialogData, new_1_0, 1}}, - {2411, {wxPrintDialogData, destruct, 0}}, - {2412, {wxPrintDialogData, enableHelp, 1}}, - {2413, {wxPrintDialogData, enablePageNumbers, 1}}, - {2414, {wxPrintDialogData, enablePrintToFile, 1}}, - {2415, {wxPrintDialogData, enableSelection, 1}}, - {2416, {wxPrintDialogData, getAllPages, 0}}, - {2417, {wxPrintDialogData, getCollate, 0}}, - {2418, {wxPrintDialogData, getFromPage, 0}}, - {2419, {wxPrintDialogData, getMaxPage, 0}}, - {2420, {wxPrintDialogData, getMinPage, 0}}, - {2421, {wxPrintDialogData, getNoCopies, 0}}, - {2422, {wxPrintDialogData, getPrintData, 0}}, - {2423, {wxPrintDialogData, getPrintToFile, 0}}, - {2424, {wxPrintDialogData, getSelection, 0}}, - {2425, {wxPrintDialogData, getToPage, 0}}, - {2426, {wxPrintDialogData, isOk, 0}}, - {2427, {wxPrintDialogData, setCollate, 1}}, - {2428, {wxPrintDialogData, setFromPage, 1}}, - {2429, {wxPrintDialogData, setMaxPage, 1}}, - {2430, {wxPrintDialogData, setMinPage, 1}}, - {2431, {wxPrintDialogData, setNoCopies, 1}}, - {2432, {wxPrintDialogData, setPrintData, 1}}, - {2433, {wxPrintDialogData, setPrintToFile, 1}}, - {2434, {wxPrintDialogData, setSelection, 1}}, - {2435, {wxPrintDialogData, setToPage, 1}}, - {2436, {wxPrintData, new_0, 0}}, - {2437, {wxPrintData, new_1, 1}}, - {2438, {wxPrintData, destruct, 0}}, - {2439, {wxPrintData, getCollate, 0}}, - {2440, {wxPrintData, getBin, 0}}, - {2441, {wxPrintData, getColour, 0}}, - {2442, {wxPrintData, getDuplex, 0}}, - {2443, {wxPrintData, getNoCopies, 0}}, - {2444, {wxPrintData, getOrientation, 0}}, - {2445, {wxPrintData, getPaperId, 0}}, - {2446, {wxPrintData, getPrinterName, 0}}, - {2447, {wxPrintData, getQuality, 0}}, - {2448, {wxPrintData, isOk, 0}}, - {2449, {wxPrintData, setBin, 1}}, - {2450, {wxPrintData, setCollate, 1}}, - {2451, {wxPrintData, setColour, 1}}, - {2452, {wxPrintData, setDuplex, 1}}, - {2453, {wxPrintData, setNoCopies, 1}}, - {2454, {wxPrintData, setOrientation, 1}}, - {2455, {wxPrintData, setPaperId, 1}}, - {2456, {wxPrintData, setPrinterName, 1}}, - {2457, {wxPrintData, setQuality, 1}}, - {2460, {wxPrintPreview, new_2, 2}}, - {2461, {wxPrintPreview, new_3, 3}}, - {2463, {wxPrintPreview, destruct, 0}}, - {2464, {wxPrintPreview, getCanvas, 0}}, - {2465, {wxPrintPreview, getCurrentPage, 0}}, - {2466, {wxPrintPreview, getFrame, 0}}, - {2467, {wxPrintPreview, getMaxPage, 0}}, - {2468, {wxPrintPreview, getMinPage, 0}}, - {2469, {wxPrintPreview, getPrintout, 0}}, - {2470, {wxPrintPreview, getPrintoutForPrinting, 0}}, - {2471, {wxPrintPreview, isOk, 0}}, - {2472, {wxPrintPreview, paintPage, 2}}, - {2473, {wxPrintPreview, print, 1}}, - {2474, {wxPrintPreview, renderPage, 1}}, - {2475, {wxPrintPreview, setCanvas, 1}}, - {2476, {wxPrintPreview, setCurrentPage, 1}}, - {2477, {wxPrintPreview, setFrame, 1}}, - {2478, {wxPrintPreview, setPrintout, 1}}, - {2479, {wxPrintPreview, setZoom, 1}}, - {2480, {wxPreviewFrame, new, 3}}, - {2481, {wxPreviewFrame, destruct, 0}}, - {2482, {wxPreviewFrame, createControlBar, 0}}, - {2483, {wxPreviewFrame, createCanvas, 0}}, - {2484, {wxPreviewFrame, initialize, 0}}, - {2485, {wxPreviewFrame, onCloseWindow, 1}}, - {2486, {wxPreviewControlBar, new, 4}}, - {2487, {wxPreviewControlBar, destruct, 0}}, - {2488, {wxPreviewControlBar, createButtons, 0}}, - {2489, {wxPreviewControlBar, getPrintPreview, 0}}, - {2490, {wxPreviewControlBar, getZoomControl, 0}}, - {2491, {wxPreviewControlBar, setZoomControl, 1}}, - {2493, {wxPrinter, new, 1}}, - {2494, {wxPrinter, createAbortWindow, 2}}, - {2495, {wxPrinter, getAbort, 0}}, - {2496, {wxPrinter, getLastError, 0}}, - {2497, {wxPrinter, getPrintDialogData, 0}}, - {2498, {wxPrinter, print, 3}}, - {2499, {wxPrinter, printDialog, 1}}, - {2500, {wxPrinter, reportError, 3}}, - {2501, {wxPrinter, setup, 1}}, - {2502, {wxPrinter, 'Destroy', undefined}}, - {2503, {wxXmlResource, new_1, 1}}, - {2504, {wxXmlResource, new_2, 2}}, - {2505, {wxXmlResource, destruct, 0}}, - {2506, {wxXmlResource, attachUnknownControl, 3}}, - {2507, {wxXmlResource, clearHandlers, 0}}, - {2508, {wxXmlResource, compareVersion, 4}}, - {2509, {wxXmlResource, get, 0}}, - {2510, {wxXmlResource, getFlags, 0}}, - {2511, {wxXmlResource, getVersion, 0}}, - {2512, {wxXmlResource, getXRCID, 2}}, - {2513, {wxXmlResource, initAllHandlers, 0}}, - {2514, {wxXmlResource, load, 1}}, - {2515, {wxXmlResource, loadBitmap, 1}}, - {2516, {wxXmlResource, loadDialog_2, 2}}, - {2517, {wxXmlResource, loadDialog_3, 3}}, - {2518, {wxXmlResource, loadFrame_2, 2}}, - {2519, {wxXmlResource, loadFrame_3, 3}}, - {2520, {wxXmlResource, loadIcon, 1}}, - {2521, {wxXmlResource, loadMenu, 1}}, - {2522, {wxXmlResource, loadMenuBar_2, 2}}, - {2523, {wxXmlResource, loadMenuBar_1, 1}}, - {2524, {wxXmlResource, loadPanel_2, 2}}, - {2525, {wxXmlResource, loadPanel_3, 3}}, - {2526, {wxXmlResource, loadToolBar, 2}}, - {2527, {wxXmlResource, set, 1}}, - {2528, {wxXmlResource, setFlags, 1}}, - {2529, {wxXmlResource, unload, 1}}, - {2530, {wxXmlResource, xrcctrl, 3}}, - {2531, {wxHtmlEasyPrinting, new, 1}}, - {2532, {wxHtmlEasyPrinting, destruct, 0}}, - {2533, {wxHtmlEasyPrinting, getPrintData, 0}}, - {2534, {wxHtmlEasyPrinting, getPageSetupData, 0}}, - {2535, {wxHtmlEasyPrinting, previewFile, 1}}, - {2536, {wxHtmlEasyPrinting, previewText, 2}}, - {2537, {wxHtmlEasyPrinting, printFile, 1}}, - {2538, {wxHtmlEasyPrinting, printText, 2}}, - {2539, {wxHtmlEasyPrinting, pageSetup, 0}}, - {2540, {wxHtmlEasyPrinting, setFonts, 3}}, - {2541, {wxHtmlEasyPrinting, setHeader, 2}}, - {2542, {wxHtmlEasyPrinting, setFooter, 2}}, - {2544, {wxGLCanvas, new_2, 2}}, - {2545, {wxGLCanvas, new_3_1, 3}}, - {2546, {wxGLCanvas, new_3_0, 3}}, - {2547, {wxGLCanvas, getContext, 0}}, - {2549, {wxGLCanvas, setCurrent, 0}}, - {2550, {wxGLCanvas, swapBuffers, 0}}, - {2551, {wxGLCanvas, 'Destroy', undefined}}, - {2552, {wxAuiManager, new, 1}}, - {2553, {wxAuiManager, destruct, 0}}, - {2554, {wxAuiManager, addPane_2_1, 2}}, - {2555, {wxAuiManager, addPane_3, 3}}, - {2556, {wxAuiManager, addPane_2_0, 2}}, - {2557, {wxAuiManager, detachPane, 1}}, - {2558, {wxAuiManager, getAllPanes, 0}}, - {2559, {wxAuiManager, getArtProvider, 0}}, - {2560, {wxAuiManager, getDockSizeConstraint, 2}}, - {2561, {wxAuiManager, getFlags, 0}}, - {2562, {wxAuiManager, getManagedWindow, 0}}, - {2563, {wxAuiManager, getManager, 1}}, - {2564, {wxAuiManager, getPane_1_1, 1}}, - {2565, {wxAuiManager, getPane_1_0, 1}}, - {2566, {wxAuiManager, hideHint, 0}}, - {2567, {wxAuiManager, insertPane, 3}}, - {2568, {wxAuiManager, loadPaneInfo, 2}}, - {2569, {wxAuiManager, loadPerspective, 2}}, - {2570, {wxAuiManager, savePaneInfo, 1}}, - {2571, {wxAuiManager, savePerspective, 0}}, - {2572, {wxAuiManager, setArtProvider, 1}}, - {2573, {wxAuiManager, setDockSizeConstraint, 2}}, - {2574, {wxAuiManager, setFlags, 1}}, - {2575, {wxAuiManager, setManagedWindow, 1}}, - {2576, {wxAuiManager, showHint, 1}}, - {2577, {wxAuiManager, unInit, 0}}, - {2578, {wxAuiManager, update, 0}}, - {2579, {wxAuiPaneInfo, new_0, 0}}, - {2580, {wxAuiPaneInfo, new_1, 1}}, - {2581, {wxAuiPaneInfo, destruct, 0}}, - {2582, {wxAuiPaneInfo, bestSize_1, 1}}, - {2583, {wxAuiPaneInfo, bestSize_2, 2}}, - {2584, {wxAuiPaneInfo, bottom, 0}}, - {2585, {wxAuiPaneInfo, bottomDockable, 1}}, - {2586, {wxAuiPaneInfo, caption, 1}}, - {2587, {wxAuiPaneInfo, captionVisible, 1}}, - {2588, {wxAuiPaneInfo, centre, 0}}, - {2589, {wxAuiPaneInfo, centrePane, 0}}, - {2590, {wxAuiPaneInfo, closeButton, 1}}, - {2591, {wxAuiPaneInfo, defaultPane, 0}}, - {2592, {wxAuiPaneInfo, destroyOnClose, 1}}, - {2593, {wxAuiPaneInfo, direction, 1}}, - {2594, {wxAuiPaneInfo, dock, 0}}, - {2595, {wxAuiPaneInfo, dockable, 1}}, - {2596, {wxAuiPaneInfo, fixed, 0}}, - {2597, {wxAuiPaneInfo, float, 0}}, - {2598, {wxAuiPaneInfo, floatable, 1}}, - {2599, {wxAuiPaneInfo, floatingPosition_1, 1}}, - {2600, {wxAuiPaneInfo, floatingPosition_2, 2}}, - {2601, {wxAuiPaneInfo, floatingSize_1, 1}}, - {2602, {wxAuiPaneInfo, floatingSize_2, 2}}, - {2603, {wxAuiPaneInfo, gripper, 1}}, - {2604, {wxAuiPaneInfo, gripperTop, 1}}, - {2605, {wxAuiPaneInfo, hasBorder, 0}}, - {2606, {wxAuiPaneInfo, hasCaption, 0}}, - {2607, {wxAuiPaneInfo, hasCloseButton, 0}}, - {2608, {wxAuiPaneInfo, hasFlag, 1}}, - {2609, {wxAuiPaneInfo, hasGripper, 0}}, - {2610, {wxAuiPaneInfo, hasGripperTop, 0}}, - {2611, {wxAuiPaneInfo, hasMaximizeButton, 0}}, - {2612, {wxAuiPaneInfo, hasMinimizeButton, 0}}, - {2613, {wxAuiPaneInfo, hasPinButton, 0}}, - {2614, {wxAuiPaneInfo, hide, 0}}, - {2615, {wxAuiPaneInfo, isBottomDockable, 0}}, - {2616, {wxAuiPaneInfo, isDocked, 0}}, - {2617, {wxAuiPaneInfo, isFixed, 0}}, - {2618, {wxAuiPaneInfo, isFloatable, 0}}, - {2619, {wxAuiPaneInfo, isFloating, 0}}, - {2620, {wxAuiPaneInfo, isLeftDockable, 0}}, - {2621, {wxAuiPaneInfo, isMovable, 0}}, - {2622, {wxAuiPaneInfo, isOk, 0}}, - {2623, {wxAuiPaneInfo, isResizable, 0}}, - {2624, {wxAuiPaneInfo, isRightDockable, 0}}, - {2625, {wxAuiPaneInfo, isShown, 0}}, - {2626, {wxAuiPaneInfo, isToolbar, 0}}, - {2627, {wxAuiPaneInfo, isTopDockable, 0}}, - {2628, {wxAuiPaneInfo, layer, 1}}, - {2629, {wxAuiPaneInfo, left, 0}}, - {2630, {wxAuiPaneInfo, leftDockable, 1}}, - {2631, {wxAuiPaneInfo, maxSize_1, 1}}, - {2632, {wxAuiPaneInfo, maxSize_2, 2}}, - {2633, {wxAuiPaneInfo, maximizeButton, 1}}, - {2634, {wxAuiPaneInfo, minSize_1, 1}}, - {2635, {wxAuiPaneInfo, minSize_2, 2}}, - {2636, {wxAuiPaneInfo, minimizeButton, 1}}, - {2637, {wxAuiPaneInfo, movable, 1}}, - {2638, {wxAuiPaneInfo, name, 1}}, - {2639, {wxAuiPaneInfo, paneBorder, 1}}, - {2640, {wxAuiPaneInfo, pinButton, 1}}, - {2641, {wxAuiPaneInfo, position, 1}}, - {2642, {wxAuiPaneInfo, resizable, 1}}, - {2643, {wxAuiPaneInfo, right, 0}}, - {2644, {wxAuiPaneInfo, rightDockable, 1}}, - {2645, {wxAuiPaneInfo, row, 1}}, - {2646, {wxAuiPaneInfo, safeSet, 1}}, - {2647, {wxAuiPaneInfo, setFlag, 2}}, - {2648, {wxAuiPaneInfo, show, 1}}, - {2649, {wxAuiPaneInfo, toolbarPane, 0}}, - {2650, {wxAuiPaneInfo, top, 0}}, - {2651, {wxAuiPaneInfo, topDockable, 1}}, - {2652, {wxAuiPaneInfo, window, 1}}, - {2653, {wxAuiNotebook, new_0, 0}}, - {2654, {wxAuiNotebook, new_2, 2}}, - {2655, {wxAuiNotebook, addPage, 3}}, - {2656, {wxAuiNotebook, create, 2}}, - {2657, {wxAuiNotebook, deletePage, 1}}, - {2658, {wxAuiNotebook, getArtProvider, 0}}, - {2659, {wxAuiNotebook, getPage, 1}}, - {2660, {wxAuiNotebook, getPageBitmap, 1}}, - {2661, {wxAuiNotebook, getPageCount, 0}}, - {2662, {wxAuiNotebook, getPageIndex, 1}}, - {2663, {wxAuiNotebook, getPageText, 1}}, - {2664, {wxAuiNotebook, getSelection, 0}}, - {2665, {wxAuiNotebook, insertPage, 4}}, - {2666, {wxAuiNotebook, removePage, 1}}, - {2667, {wxAuiNotebook, setArtProvider, 1}}, - {2668, {wxAuiNotebook, setFont, 1}}, - {2669, {wxAuiNotebook, setPageBitmap, 2}}, - {2670, {wxAuiNotebook, setPageText, 2}}, - {2671, {wxAuiNotebook, setSelection, 1}}, - {2672, {wxAuiNotebook, setTabCtrlHeight, 1}}, - {2673, {wxAuiNotebook, setUniformBitmapSize, 1}}, - {2674, {wxAuiNotebook, 'Destroy', undefined}}, - {2675, {wxMDIParentFrame, new_0, 0}}, - {2676, {wxMDIParentFrame, new_4, 4}}, - {2677, {wxMDIParentFrame, destruct, 0}}, - {2678, {wxMDIParentFrame, activateNext, 0}}, - {2679, {wxMDIParentFrame, activatePrevious, 0}}, - {2680, {wxMDIParentFrame, arrangeIcons, 0}}, - {2681, {wxMDIParentFrame, cascade, 0}}, - {2682, {wxMDIParentFrame, create, 4}}, - {2683, {wxMDIParentFrame, getActiveChild, 0}}, - {2684, {wxMDIParentFrame, getClientWindow, 0}}, - {2685, {wxMDIParentFrame, tile, 1}}, - {2686, {wxMDIChildFrame, new_0, 0}}, - {2687, {wxMDIChildFrame, new_4, 4}}, - {2688, {wxMDIChildFrame, destruct, 0}}, - {2689, {wxMDIChildFrame, activate, 0}}, - {2690, {wxMDIChildFrame, create, 4}}, - {2691, {wxMDIChildFrame, maximize, 1}}, - {2692, {wxMDIChildFrame, restore, 0}}, - {2693, {wxMDIClientWindow, new_0, 0}}, - {2694, {wxMDIClientWindow, new_2, 2}}, - {2695, {wxMDIClientWindow, destruct, 0}}, - {2696, {wxMDIClientWindow, createClient, 2}}, - {2697, {wxLayoutAlgorithm, new, 0}}, - {2698, {wxLayoutAlgorithm, layoutFrame, 2}}, - {2699, {wxLayoutAlgorithm, layoutMDIFrame, 2}}, - {2700, {wxLayoutAlgorithm, layoutWindow, 2}}, - {2701, {wxLayoutAlgorithm, 'Destroy', undefined}}, - {2702, {wxEvent, getId, 0}}, - {2703, {wxEvent, getSkipped, 0}}, - {2704, {wxEvent, getTimestamp, 0}}, - {2705, {wxEvent, isCommandEvent, 0}}, - {2706, {wxEvent, resumePropagation, 1}}, - {2707, {wxEvent, shouldPropagate, 0}}, - {2708, {wxEvent, skip, 1}}, - {2709, {wxEvent, stopPropagation, 0}}, - {2710, {wxCommandEvent, getClientData, 0}}, - {2711, {wxCommandEvent, getExtraLong, 0}}, - {2712, {wxCommandEvent, getInt, 0}}, - {2713, {wxCommandEvent, getSelection, 0}}, - {2714, {wxCommandEvent, getString, 0}}, - {2715, {wxCommandEvent, isChecked, 0}}, - {2716, {wxCommandEvent, isSelection, 0}}, - {2717, {wxCommandEvent, setInt, 1}}, - {2718, {wxCommandEvent, setString, 1}}, - {2719, {wxScrollEvent, getOrientation, 0}}, - {2720, {wxScrollEvent, getPosition, 0}}, - {2721, {wxScrollWinEvent, getOrientation, 0}}, - {2722, {wxScrollWinEvent, getPosition, 0}}, - {2723, {wxMouseEvent, altDown, 0}}, - {2724, {wxMouseEvent, button, 1}}, - {2725, {wxMouseEvent, buttonDClick, 1}}, - {2726, {wxMouseEvent, buttonDown, 1}}, - {2727, {wxMouseEvent, buttonUp, 1}}, - {2728, {wxMouseEvent, cmdDown, 0}}, - {2729, {wxMouseEvent, controlDown, 0}}, - {2730, {wxMouseEvent, dragging, 0}}, - {2731, {wxMouseEvent, entering, 0}}, - {2732, {wxMouseEvent, getButton, 0}}, - {2735, {wxMouseEvent, getPosition, 0}}, - {2736, {wxMouseEvent, getLogicalPosition, 1}}, - {2737, {wxMouseEvent, getLinesPerAction, 0}}, - {2738, {wxMouseEvent, getWheelRotation, 0}}, - {2739, {wxMouseEvent, getWheelDelta, 0}}, - {2740, {wxMouseEvent, getX, 0}}, - {2741, {wxMouseEvent, getY, 0}}, - {2742, {wxMouseEvent, isButton, 0}}, - {2743, {wxMouseEvent, isPageScroll, 0}}, - {2744, {wxMouseEvent, leaving, 0}}, - {2745, {wxMouseEvent, leftDClick, 0}}, - {2746, {wxMouseEvent, leftDown, 0}}, - {2747, {wxMouseEvent, leftIsDown, 0}}, - {2748, {wxMouseEvent, leftUp, 0}}, - {2749, {wxMouseEvent, metaDown, 0}}, - {2750, {wxMouseEvent, middleDClick, 0}}, - {2751, {wxMouseEvent, middleDown, 0}}, - {2752, {wxMouseEvent, middleIsDown, 0}}, - {2753, {wxMouseEvent, middleUp, 0}}, - {2754, {wxMouseEvent, moving, 0}}, - {2755, {wxMouseEvent, rightDClick, 0}}, - {2756, {wxMouseEvent, rightDown, 0}}, - {2757, {wxMouseEvent, rightIsDown, 0}}, - {2758, {wxMouseEvent, rightUp, 0}}, - {2759, {wxMouseEvent, shiftDown, 0}}, - {2760, {wxSetCursorEvent, getCursor, 0}}, - {2761, {wxSetCursorEvent, getX, 0}}, - {2762, {wxSetCursorEvent, getY, 0}}, - {2763, {wxSetCursorEvent, hasCursor, 0}}, - {2764, {wxSetCursorEvent, setCursor, 1}}, - {2765, {wxKeyEvent, altDown, 0}}, - {2766, {wxKeyEvent, cmdDown, 0}}, - {2767, {wxKeyEvent, controlDown, 0}}, - {2768, {wxKeyEvent, getKeyCode, 0}}, - {2769, {wxKeyEvent, getModifiers, 0}}, - {2772, {wxKeyEvent, getPosition, 0}}, - {2773, {wxKeyEvent, getRawKeyCode, 0}}, - {2774, {wxKeyEvent, getRawKeyFlags, 0}}, - {2775, {wxKeyEvent, getUnicodeKey, 0}}, - {2776, {wxKeyEvent, getX, 0}}, - {2777, {wxKeyEvent, getY, 0}}, - {2778, {wxKeyEvent, hasModifiers, 0}}, - {2779, {wxKeyEvent, metaDown, 0}}, - {2780, {wxKeyEvent, shiftDown, 0}}, - {2781, {wxSizeEvent, getSize, 0}}, - {2782, {wxMoveEvent, getPosition, 0}}, - {2783, {wxEraseEvent, getDC, 0}}, - {2784, {wxFocusEvent, getWindow, 0}}, - {2785, {wxChildFocusEvent, getWindow, 0}}, - {2786, {wxMenuEvent, getMenu, 0}}, - {2787, {wxMenuEvent, getMenuId, 0}}, - {2788, {wxMenuEvent, isPopup, 0}}, - {2789, {wxCloseEvent, canVeto, 0}}, - {2790, {wxCloseEvent, getLoggingOff, 0}}, - {2791, {wxCloseEvent, setCanVeto, 1}}, - {2792, {wxCloseEvent, setLoggingOff, 1}}, - {2793, {wxCloseEvent, veto, 1}}, - {2794, {wxShowEvent, setShow, 1}}, - {2795, {wxShowEvent, getShow, 0}}, - {2796, {wxIconizeEvent, iconized, 0}}, - {2797, {wxJoystickEvent, buttonDown, 1}}, - {2798, {wxJoystickEvent, buttonIsDown, 1}}, - {2799, {wxJoystickEvent, buttonUp, 1}}, - {2800, {wxJoystickEvent, getButtonChange, 0}}, - {2801, {wxJoystickEvent, getButtonState, 0}}, - {2802, {wxJoystickEvent, getJoystick, 0}}, - {2803, {wxJoystickEvent, getPosition, 0}}, - {2804, {wxJoystickEvent, getZPosition, 0}}, - {2805, {wxJoystickEvent, isButton, 0}}, - {2806, {wxJoystickEvent, isMove, 0}}, - {2807, {wxJoystickEvent, isZMove, 0}}, - {2808, {wxUpdateUIEvent, canUpdate, 1}}, - {2809, {wxUpdateUIEvent, check, 1}}, - {2810, {wxUpdateUIEvent, enable, 1}}, - {2811, {wxUpdateUIEvent, show, 1}}, - {2812, {wxUpdateUIEvent, getChecked, 0}}, - {2813, {wxUpdateUIEvent, getEnabled, 0}}, - {2814, {wxUpdateUIEvent, getShown, 0}}, - {2815, {wxUpdateUIEvent, getSetChecked, 0}}, - {2816, {wxUpdateUIEvent, getSetEnabled, 0}}, - {2817, {wxUpdateUIEvent, getSetShown, 0}}, - {2818, {wxUpdateUIEvent, getSetText, 0}}, - {2819, {wxUpdateUIEvent, getText, 0}}, - {2820, {wxUpdateUIEvent, getMode, 0}}, - {2821, {wxUpdateUIEvent, getUpdateInterval, 0}}, - {2822, {wxUpdateUIEvent, resetUpdateTime, 0}}, - {2823, {wxUpdateUIEvent, setMode, 1}}, - {2824, {wxUpdateUIEvent, setText, 1}}, - {2825, {wxUpdateUIEvent, setUpdateInterval, 1}}, - {2826, {wxMouseCaptureChangedEvent, getCapturedWindow, 0}}, - {2827, {wxPaletteChangedEvent, setChangedWindow, 1}}, - {2828, {wxPaletteChangedEvent, getChangedWindow, 0}}, - {2829, {wxQueryNewPaletteEvent, setPaletteRealized, 1}}, - {2830, {wxQueryNewPaletteEvent, getPaletteRealized, 0}}, - {2831, {wxNavigationKeyEvent, getDirection, 0}}, - {2832, {wxNavigationKeyEvent, setDirection, 1}}, - {2833, {wxNavigationKeyEvent, isWindowChange, 0}}, - {2834, {wxNavigationKeyEvent, setWindowChange, 1}}, - {2835, {wxNavigationKeyEvent, isFromTab, 0}}, - {2836, {wxNavigationKeyEvent, setFromTab, 1}}, - {2837, {wxNavigationKeyEvent, getCurrentFocus, 0}}, - {2838, {wxNavigationKeyEvent, setCurrentFocus, 1}}, - {2839, {wxHelpEvent, getOrigin, 0}}, - {2840, {wxHelpEvent, getPosition, 0}}, - {2841, {wxHelpEvent, setOrigin, 1}}, - {2842, {wxHelpEvent, setPosition, 1}}, - {2843, {wxContextMenuEvent, getPosition, 0}}, - {2844, {wxContextMenuEvent, setPosition, 1}}, - {2845, {wxIdleEvent, canSend, 1}}, - {2846, {wxIdleEvent, getMode, 0}}, - {2847, {wxIdleEvent, requestMore, 1}}, - {2848, {wxIdleEvent, moreRequested, 0}}, - {2849, {wxIdleEvent, setMode, 1}}, - {2850, {wxGridEvent, altDown, 0}}, - {2851, {wxGridEvent, controlDown, 0}}, - {2852, {wxGridEvent, getCol, 0}}, - {2853, {wxGridEvent, getPosition, 0}}, - {2854, {wxGridEvent, getRow, 0}}, - {2855, {wxGridEvent, metaDown, 0}}, - {2856, {wxGridEvent, selecting, 0}}, - {2857, {wxGridEvent, shiftDown, 0}}, - {2858, {wxNotifyEvent, allow, 0}}, - {2859, {wxNotifyEvent, isAllowed, 0}}, - {2860, {wxNotifyEvent, veto, 0}}, - {2861, {wxSashEvent, getEdge, 0}}, - {2862, {wxSashEvent, getDragRect, 0}}, - {2863, {wxSashEvent, getDragStatus, 0}}, - {2864, {wxListEvent, getCacheFrom, 0}}, - {2865, {wxListEvent, getCacheTo, 0}}, - {2866, {wxListEvent, getKeyCode, 0}}, - {2867, {wxListEvent, getIndex, 0}}, - {2868, {wxListEvent, getColumn, 0}}, - {2869, {wxListEvent, getPoint, 0}}, - {2870, {wxListEvent, getLabel, 0}}, - {2871, {wxListEvent, getText, 0}}, - {2872, {wxListEvent, getImage, 0}}, - {2873, {wxListEvent, getData, 0}}, - {2874, {wxListEvent, getMask, 0}}, - {2875, {wxListEvent, getItem, 0}}, - {2876, {wxListEvent, isEditCancelled, 0}}, - {2877, {wxDateEvent, getDate, 0}}, - {2878, {wxCalendarEvent, getWeekDay, 0}}, - {2879, {wxFileDirPickerEvent, getPath, 0}}, - {2880, {wxColourPickerEvent, getColour, 0}}, - {2881, {wxFontPickerEvent, getFont, 0}}, - {2882, {wxStyledTextEvent, getPosition, 0}}, - {2883, {wxStyledTextEvent, getKey, 0}}, - {2884, {wxStyledTextEvent, getModifiers, 0}}, - {2885, {wxStyledTextEvent, getModificationType, 0}}, - {2886, {wxStyledTextEvent, getText, 0}}, - {2887, {wxStyledTextEvent, getLength, 0}}, - {2888, {wxStyledTextEvent, getLinesAdded, 0}}, - {2889, {wxStyledTextEvent, getLine, 0}}, - {2890, {wxStyledTextEvent, getFoldLevelNow, 0}}, - {2891, {wxStyledTextEvent, getFoldLevelPrev, 0}}, - {2892, {wxStyledTextEvent, getMargin, 0}}, - {2893, {wxStyledTextEvent, getMessage, 0}}, - {2894, {wxStyledTextEvent, getWParam, 0}}, - {2895, {wxStyledTextEvent, getLParam, 0}}, - {2896, {wxStyledTextEvent, getListType, 0}}, - {2897, {wxStyledTextEvent, getX, 0}}, - {2898, {wxStyledTextEvent, getY, 0}}, - {2899, {wxStyledTextEvent, getDragText, 0}}, - {2900, {wxStyledTextEvent, getDragAllowMove, 0}}, - {2901, {wxStyledTextEvent, getDragResult, 0}}, - {2902, {wxStyledTextEvent, getShift, 0}}, - {2903, {wxStyledTextEvent, getControl, 0}}, - {2904, {wxStyledTextEvent, getAlt, 0}}, - {2905, {utils, getKeyState, 1}}, - {2906, {utils, getMousePosition, 2}}, - {2907, {utils, getMouseState, 0}}, - {2908, {utils, setDetectableAutoRepeat, 1}}, - {2909, {utils, bell, 0}}, - {2910, {utils, findMenuItemId, 3}}, - {2911, {utils, genericFindWindowAtPoint, 1}}, - {2912, {utils, findWindowAtPoint, 1}}, - {2913, {utils, beginBusyCursor, 1}}, - {2914, {utils, endBusyCursor, 0}}, - {2915, {utils, isBusy, 0}}, - {2916, {utils, shutdown, 1}}, - {2917, {utils, shell, 1}}, - {2918, {utils, launchDefaultBrowser, 2}}, - {2919, {utils, getEmailAddress, 0}}, - {2920, {utils, getUserId, 0}}, - {2921, {utils, getHomeDir, 0}}, - {2922, {utils, newId, 0}}, - {2923, {utils, registerId, 1}}, - {2924, {utils, getCurrentId, 0}}, - {2925, {utils, getOsDescription, 0}}, - {2926, {utils, isPlatformLittleEndian, 0}}, - {2927, {utils, isPlatform64Bit, 0}}, - {2928, {gdicmn, displaySize, 2}}, - {2929, {gdicmn, setCursor, 1}}, - {2930, {wxPrintout, new, 1}}, - {2931, {wxPrintout, destruct, 0}}, - {2932, {wxPrintout, getDC, 0}}, - {2933, {wxPrintout, getPageSizeMM, 2}}, - {2934, {wxPrintout, getPageSizePixels, 2}}, - {2935, {wxPrintout, getPaperRectPixels, 0}}, - {2936, {wxPrintout, getPPIPrinter, 2}}, - {2937, {wxPrintout, getPPIScreen, 2}}, - {2938, {wxPrintout, getTitle, 0}}, - {2939, {wxPrintout, isPreview, 0}}, - {2940, {wxPrintout, fitThisSizeToPaper, 1}}, - {2941, {wxPrintout, fitThisSizeToPage, 1}}, - {2942, {wxPrintout, fitThisSizeToPageMargins, 2}}, - {2943, {wxPrintout, mapScreenSizeToPaper, 0}}, - {2944, {wxPrintout, mapScreenSizeToPage, 0}}, - {2945, {wxPrintout, mapScreenSizeToPageMargins, 1}}, - {2946, {wxPrintout, mapScreenSizeToDevice, 0}}, - {2947, {wxPrintout, getLogicalPaperRect, 0}}, - {2948, {wxPrintout, getLogicalPageRect, 0}}, - {2949, {wxPrintout, getLogicalPageMarginsRect, 1}}, - {2950, {wxPrintout, setLogicalOrigin, 2}}, - {2951, {wxPrintout, offsetLogicalOrigin, 2}}, - {2952, {wxStyledTextCtrl, new_2, 2}}, - {2953, {wxStyledTextCtrl, new_0, 0}}, - {2954, {wxStyledTextCtrl, destruct, 0}}, - {2955, {wxStyledTextCtrl, create, 2}}, - {2956, {wxStyledTextCtrl, addText, 1}}, - {2957, {wxStyledTextCtrl, addStyledText, 1}}, - {2958, {wxStyledTextCtrl, insertText, 2}}, - {2959, {wxStyledTextCtrl, clearAll, 0}}, - {2960, {wxStyledTextCtrl, clearDocumentStyle, 0}}, - {2961, {wxStyledTextCtrl, getLength, 0}}, - {2962, {wxStyledTextCtrl, getCharAt, 1}}, - {2963, {wxStyledTextCtrl, getCurrentPos, 0}}, - {2964, {wxStyledTextCtrl, getAnchor, 0}}, - {2965, {wxStyledTextCtrl, getStyleAt, 1}}, - {2966, {wxStyledTextCtrl, redo, 0}}, - {2967, {wxStyledTextCtrl, setUndoCollection, 1}}, - {2968, {wxStyledTextCtrl, selectAll, 0}}, - {2969, {wxStyledTextCtrl, setSavePoint, 0}}, - {2970, {wxStyledTextCtrl, getStyledText, 2}}, - {2971, {wxStyledTextCtrl, canRedo, 0}}, - {2972, {wxStyledTextCtrl, markerLineFromHandle, 1}}, - {2973, {wxStyledTextCtrl, markerDeleteHandle, 1}}, - {2974, {wxStyledTextCtrl, getUndoCollection, 0}}, - {2975, {wxStyledTextCtrl, getViewWhiteSpace, 0}}, - {2976, {wxStyledTextCtrl, setViewWhiteSpace, 1}}, - {2977, {wxStyledTextCtrl, positionFromPoint, 1}}, - {2978, {wxStyledTextCtrl, positionFromPointClose, 2}}, - {2979, {wxStyledTextCtrl, gotoLine, 1}}, - {2980, {wxStyledTextCtrl, gotoPos, 1}}, - {2981, {wxStyledTextCtrl, setAnchor, 1}}, - {2982, {wxStyledTextCtrl, getCurLine, 1}}, - {2983, {wxStyledTextCtrl, getEndStyled, 0}}, - {2984, {wxStyledTextCtrl, convertEOLs, 1}}, - {2985, {wxStyledTextCtrl, getEOLMode, 0}}, - {2986, {wxStyledTextCtrl, setEOLMode, 1}}, - {2987, {wxStyledTextCtrl, startStyling, 2}}, - {2988, {wxStyledTextCtrl, setStyling, 2}}, - {2989, {wxStyledTextCtrl, getBufferedDraw, 0}}, - {2990, {wxStyledTextCtrl, setBufferedDraw, 1}}, - {2991, {wxStyledTextCtrl, setTabWidth, 1}}, - {2992, {wxStyledTextCtrl, getTabWidth, 0}}, - {2993, {wxStyledTextCtrl, setCodePage, 1}}, - {2994, {wxStyledTextCtrl, markerDefine, 3}}, - {2995, {wxStyledTextCtrl, markerSetForeground, 2}}, - {2996, {wxStyledTextCtrl, markerSetBackground, 2}}, - {2997, {wxStyledTextCtrl, markerAdd, 2}}, - {2998, {wxStyledTextCtrl, markerDelete, 2}}, - {2999, {wxStyledTextCtrl, markerDeleteAll, 1}}, - {3000, {wxStyledTextCtrl, markerGet, 1}}, - {3001, {wxStyledTextCtrl, markerNext, 2}}, - {3002, {wxStyledTextCtrl, markerPrevious, 2}}, - {3003, {wxStyledTextCtrl, markerDefineBitmap, 2}}, - {3004, {wxStyledTextCtrl, markerAddSet, 2}}, - {3005, {wxStyledTextCtrl, markerSetAlpha, 2}}, - {3006, {wxStyledTextCtrl, setMarginType, 2}}, - {3007, {wxStyledTextCtrl, getMarginType, 1}}, - {3008, {wxStyledTextCtrl, setMarginWidth, 2}}, - {3009, {wxStyledTextCtrl, getMarginWidth, 1}}, - {3010, {wxStyledTextCtrl, setMarginMask, 2}}, - {3011, {wxStyledTextCtrl, getMarginMask, 1}}, - {3012, {wxStyledTextCtrl, setMarginSensitive, 2}}, - {3013, {wxStyledTextCtrl, getMarginSensitive, 1}}, - {3014, {wxStyledTextCtrl, styleClearAll, 0}}, - {3015, {wxStyledTextCtrl, styleSetForeground, 2}}, - {3016, {wxStyledTextCtrl, styleSetBackground, 2}}, - {3017, {wxStyledTextCtrl, styleSetBold, 2}}, - {3018, {wxStyledTextCtrl, styleSetItalic, 2}}, - {3019, {wxStyledTextCtrl, styleSetSize, 2}}, - {3020, {wxStyledTextCtrl, styleSetFaceName, 2}}, - {3021, {wxStyledTextCtrl, styleSetEOLFilled, 2}}, - {3022, {wxStyledTextCtrl, styleResetDefault, 0}}, - {3023, {wxStyledTextCtrl, styleSetUnderline, 2}}, - {3024, {wxStyledTextCtrl, styleSetCase, 2}}, - {3025, {wxStyledTextCtrl, styleSetHotSpot, 2}}, - {3026, {wxStyledTextCtrl, setSelForeground, 2}}, - {3027, {wxStyledTextCtrl, setSelBackground, 2}}, - {3028, {wxStyledTextCtrl, getSelAlpha, 0}}, - {3029, {wxStyledTextCtrl, setSelAlpha, 1}}, - {3030, {wxStyledTextCtrl, setCaretForeground, 1}}, - {3031, {wxStyledTextCtrl, cmdKeyAssign, 3}}, - {3032, {wxStyledTextCtrl, cmdKeyClear, 2}}, - {3033, {wxStyledTextCtrl, cmdKeyClearAll, 0}}, - {3034, {wxStyledTextCtrl, setStyleBytes, 2}}, - {3035, {wxStyledTextCtrl, styleSetVisible, 2}}, - {3036, {wxStyledTextCtrl, getCaretPeriod, 0}}, - {3037, {wxStyledTextCtrl, setCaretPeriod, 1}}, - {3038, {wxStyledTextCtrl, setWordChars, 1}}, - {3039, {wxStyledTextCtrl, beginUndoAction, 0}}, - {3040, {wxStyledTextCtrl, endUndoAction, 0}}, - {3041, {wxStyledTextCtrl, indicatorSetStyle, 2}}, - {3042, {wxStyledTextCtrl, indicatorGetStyle, 1}}, - {3043, {wxStyledTextCtrl, indicatorSetForeground, 2}}, - {3044, {wxStyledTextCtrl, indicatorGetForeground, 1}}, - {3045, {wxStyledTextCtrl, setWhitespaceForeground, 2}}, - {3046, {wxStyledTextCtrl, setWhitespaceBackground, 2}}, - {3047, {wxStyledTextCtrl, getStyleBits, 0}}, - {3048, {wxStyledTextCtrl, setLineState, 2}}, - {3049, {wxStyledTextCtrl, getLineState, 1}}, - {3050, {wxStyledTextCtrl, getMaxLineState, 0}}, - {3051, {wxStyledTextCtrl, getCaretLineVisible, 0}}, - {3052, {wxStyledTextCtrl, setCaretLineVisible, 1}}, - {3053, {wxStyledTextCtrl, getCaretLineBackground, 0}}, - {3054, {wxStyledTextCtrl, setCaretLineBackground, 1}}, - {3055, {wxStyledTextCtrl, autoCompShow, 2}}, - {3056, {wxStyledTextCtrl, autoCompCancel, 0}}, - {3057, {wxStyledTextCtrl, autoCompActive, 0}}, - {3058, {wxStyledTextCtrl, autoCompPosStart, 0}}, - {3059, {wxStyledTextCtrl, autoCompComplete, 0}}, - {3060, {wxStyledTextCtrl, autoCompStops, 1}}, - {3061, {wxStyledTextCtrl, autoCompSetSeparator, 1}}, - {3062, {wxStyledTextCtrl, autoCompGetSeparator, 0}}, - {3063, {wxStyledTextCtrl, autoCompSelect, 1}}, - {3064, {wxStyledTextCtrl, autoCompSetCancelAtStart, 1}}, - {3065, {wxStyledTextCtrl, autoCompGetCancelAtStart, 0}}, - {3066, {wxStyledTextCtrl, autoCompSetFillUps, 1}}, - {3067, {wxStyledTextCtrl, autoCompSetChooseSingle, 1}}, - {3068, {wxStyledTextCtrl, autoCompGetChooseSingle, 0}}, - {3069, {wxStyledTextCtrl, autoCompSetIgnoreCase, 1}}, - {3070, {wxStyledTextCtrl, autoCompGetIgnoreCase, 0}}, - {3071, {wxStyledTextCtrl, userListShow, 2}}, - {3072, {wxStyledTextCtrl, autoCompSetAutoHide, 1}}, - {3073, {wxStyledTextCtrl, autoCompGetAutoHide, 0}}, - {3074, {wxStyledTextCtrl, autoCompSetDropRestOfWord, 1}}, - {3075, {wxStyledTextCtrl, autoCompGetDropRestOfWord, 0}}, - {3076, {wxStyledTextCtrl, registerImage, 2}}, - {3077, {wxStyledTextCtrl, clearRegisteredImages, 0}}, - {3078, {wxStyledTextCtrl, autoCompGetTypeSeparator, 0}}, - {3079, {wxStyledTextCtrl, autoCompSetTypeSeparator, 1}}, - {3080, {wxStyledTextCtrl, autoCompSetMaxWidth, 1}}, - {3081, {wxStyledTextCtrl, autoCompGetMaxWidth, 0}}, - {3082, {wxStyledTextCtrl, autoCompSetMaxHeight, 1}}, - {3083, {wxStyledTextCtrl, autoCompGetMaxHeight, 0}}, - {3084, {wxStyledTextCtrl, setIndent, 1}}, - {3085, {wxStyledTextCtrl, getIndent, 0}}, - {3086, {wxStyledTextCtrl, setUseTabs, 1}}, - {3087, {wxStyledTextCtrl, getUseTabs, 0}}, - {3088, {wxStyledTextCtrl, setLineIndentation, 2}}, - {3089, {wxStyledTextCtrl, getLineIndentation, 1}}, - {3090, {wxStyledTextCtrl, getLineIndentPosition, 1}}, - {3091, {wxStyledTextCtrl, getColumn, 1}}, - {3092, {wxStyledTextCtrl, setUseHorizontalScrollBar, 1}}, - {3093, {wxStyledTextCtrl, getUseHorizontalScrollBar, 0}}, - {3094, {wxStyledTextCtrl, setIndentationGuides, 1}}, - {3095, {wxStyledTextCtrl, getIndentationGuides, 0}}, - {3096, {wxStyledTextCtrl, setHighlightGuide, 1}}, - {3097, {wxStyledTextCtrl, getHighlightGuide, 0}}, - {3098, {wxStyledTextCtrl, getLineEndPosition, 1}}, - {3099, {wxStyledTextCtrl, getCodePage, 0}}, - {3100, {wxStyledTextCtrl, getCaretForeground, 0}}, - {3101, {wxStyledTextCtrl, getReadOnly, 0}}, - {3102, {wxStyledTextCtrl, setCurrentPos, 1}}, - {3103, {wxStyledTextCtrl, setSelectionStart, 1}}, - {3104, {wxStyledTextCtrl, getSelectionStart, 0}}, - {3105, {wxStyledTextCtrl, setSelectionEnd, 1}}, - {3106, {wxStyledTextCtrl, getSelectionEnd, 0}}, - {3107, {wxStyledTextCtrl, setPrintMagnification, 1}}, - {3108, {wxStyledTextCtrl, getPrintMagnification, 0}}, - {3109, {wxStyledTextCtrl, setPrintColourMode, 1}}, - {3110, {wxStyledTextCtrl, getPrintColourMode, 0}}, - {3111, {wxStyledTextCtrl, findText, 4}}, - {3112, {wxStyledTextCtrl, formatRange, 7}}, - {3113, {wxStyledTextCtrl, getFirstVisibleLine, 0}}, - {3114, {wxStyledTextCtrl, getLine, 1}}, - {3115, {wxStyledTextCtrl, getLineCount, 0}}, - {3116, {wxStyledTextCtrl, setMarginLeft, 1}}, - {3117, {wxStyledTextCtrl, getMarginLeft, 0}}, - {3118, {wxStyledTextCtrl, setMarginRight, 1}}, - {3119, {wxStyledTextCtrl, getMarginRight, 0}}, - {3120, {wxStyledTextCtrl, getModify, 0}}, - {3121, {wxStyledTextCtrl, setSelection, 2}}, - {3122, {wxStyledTextCtrl, getSelectedText, 0}}, - {3123, {wxStyledTextCtrl, getTextRange, 2}}, - {3124, {wxStyledTextCtrl, hideSelection, 1}}, - {3125, {wxStyledTextCtrl, lineFromPosition, 1}}, - {3126, {wxStyledTextCtrl, positionFromLine, 1}}, - {3127, {wxStyledTextCtrl, lineScroll, 2}}, - {3128, {wxStyledTextCtrl, ensureCaretVisible, 0}}, - {3129, {wxStyledTextCtrl, replaceSelection, 1}}, - {3130, {wxStyledTextCtrl, setReadOnly, 1}}, - {3131, {wxStyledTextCtrl, canPaste, 0}}, - {3132, {wxStyledTextCtrl, canUndo, 0}}, - {3133, {wxStyledTextCtrl, emptyUndoBuffer, 0}}, - {3134, {wxStyledTextCtrl, undo, 0}}, - {3135, {wxStyledTextCtrl, cut, 0}}, - {3136, {wxStyledTextCtrl, copy, 0}}, - {3137, {wxStyledTextCtrl, paste, 0}}, - {3138, {wxStyledTextCtrl, clear, 0}}, - {3139, {wxStyledTextCtrl, setText, 1}}, - {3140, {wxStyledTextCtrl, getText, 0}}, - {3141, {wxStyledTextCtrl, getTextLength, 0}}, - {3142, {wxStyledTextCtrl, getOvertype, 0}}, - {3143, {wxStyledTextCtrl, setCaretWidth, 1}}, - {3144, {wxStyledTextCtrl, getCaretWidth, 0}}, - {3145, {wxStyledTextCtrl, setTargetStart, 1}}, - {3146, {wxStyledTextCtrl, getTargetStart, 0}}, - {3147, {wxStyledTextCtrl, setTargetEnd, 1}}, - {3148, {wxStyledTextCtrl, getTargetEnd, 0}}, - {3149, {wxStyledTextCtrl, replaceTarget, 1}}, - {3150, {wxStyledTextCtrl, searchInTarget, 1}}, - {3151, {wxStyledTextCtrl, setSearchFlags, 1}}, - {3152, {wxStyledTextCtrl, getSearchFlags, 0}}, - {3153, {wxStyledTextCtrl, callTipShow, 2}}, - {3154, {wxStyledTextCtrl, callTipCancel, 0}}, - {3155, {wxStyledTextCtrl, callTipActive, 0}}, - {3156, {wxStyledTextCtrl, callTipPosAtStart, 0}}, - {3157, {wxStyledTextCtrl, callTipSetHighlight, 2}}, - {3158, {wxStyledTextCtrl, callTipSetBackground, 1}}, - {3159, {wxStyledTextCtrl, callTipSetForeground, 1}}, - {3160, {wxStyledTextCtrl, callTipSetForegroundHighlight, 1}}, - {3161, {wxStyledTextCtrl, callTipUseStyle, 1}}, - {3162, {wxStyledTextCtrl, visibleFromDocLine, 1}}, - {3163, {wxStyledTextCtrl, docLineFromVisible, 1}}, - {3164, {wxStyledTextCtrl, wrapCount, 1}}, - {3165, {wxStyledTextCtrl, setFoldLevel, 2}}, - {3166, {wxStyledTextCtrl, getFoldLevel, 1}}, - {3167, {wxStyledTextCtrl, getLastChild, 2}}, - {3168, {wxStyledTextCtrl, getFoldParent, 1}}, - {3169, {wxStyledTextCtrl, showLines, 2}}, - {3170, {wxStyledTextCtrl, hideLines, 2}}, - {3171, {wxStyledTextCtrl, getLineVisible, 1}}, - {3172, {wxStyledTextCtrl, setFoldExpanded, 2}}, - {3173, {wxStyledTextCtrl, getFoldExpanded, 1}}, - {3174, {wxStyledTextCtrl, toggleFold, 1}}, - {3175, {wxStyledTextCtrl, ensureVisible, 1}}, - {3176, {wxStyledTextCtrl, setFoldFlags, 1}}, - {3177, {wxStyledTextCtrl, ensureVisibleEnforcePolicy, 1}}, - {3178, {wxStyledTextCtrl, setTabIndents, 1}}, - {3179, {wxStyledTextCtrl, getTabIndents, 0}}, - {3180, {wxStyledTextCtrl, setBackSpaceUnIndents, 1}}, - {3181, {wxStyledTextCtrl, getBackSpaceUnIndents, 0}}, - {3182, {wxStyledTextCtrl, setMouseDwellTime, 1}}, - {3183, {wxStyledTextCtrl, getMouseDwellTime, 0}}, - {3184, {wxStyledTextCtrl, wordStartPosition, 2}}, - {3185, {wxStyledTextCtrl, wordEndPosition, 2}}, - {3186, {wxStyledTextCtrl, setWrapMode, 1}}, - {3187, {wxStyledTextCtrl, getWrapMode, 0}}, - {3188, {wxStyledTextCtrl, setWrapVisualFlags, 1}}, - {3189, {wxStyledTextCtrl, getWrapVisualFlags, 0}}, - {3190, {wxStyledTextCtrl, setWrapVisualFlagsLocation, 1}}, - {3191, {wxStyledTextCtrl, getWrapVisualFlagsLocation, 0}}, - {3192, {wxStyledTextCtrl, setWrapStartIndent, 1}}, - {3193, {wxStyledTextCtrl, getWrapStartIndent, 0}}, - {3194, {wxStyledTextCtrl, setLayoutCache, 1}}, - {3195, {wxStyledTextCtrl, getLayoutCache, 0}}, - {3196, {wxStyledTextCtrl, setScrollWidth, 1}}, - {3197, {wxStyledTextCtrl, getScrollWidth, 0}}, - {3198, {wxStyledTextCtrl, textWidth, 2}}, - {3199, {wxStyledTextCtrl, getEndAtLastLine, 0}}, - {3200, {wxStyledTextCtrl, textHeight, 1}}, - {3201, {wxStyledTextCtrl, setUseVerticalScrollBar, 1}}, - {3202, {wxStyledTextCtrl, getUseVerticalScrollBar, 0}}, - {3203, {wxStyledTextCtrl, appendText, 1}}, - {3204, {wxStyledTextCtrl, getTwoPhaseDraw, 0}}, - {3205, {wxStyledTextCtrl, setTwoPhaseDraw, 1}}, - {3206, {wxStyledTextCtrl, targetFromSelection, 0}}, - {3207, {wxStyledTextCtrl, linesJoin, 0}}, - {3208, {wxStyledTextCtrl, linesSplit, 1}}, - {3209, {wxStyledTextCtrl, setFoldMarginColour, 2}}, - {3210, {wxStyledTextCtrl, setFoldMarginHiColour, 2}}, - {3211, {wxStyledTextCtrl, lineDown, 0}}, - {3212, {wxStyledTextCtrl, lineDownExtend, 0}}, - {3213, {wxStyledTextCtrl, lineUp, 0}}, - {3214, {wxStyledTextCtrl, lineUpExtend, 0}}, - {3215, {wxStyledTextCtrl, charLeft, 0}}, - {3216, {wxStyledTextCtrl, charLeftExtend, 0}}, - {3217, {wxStyledTextCtrl, charRight, 0}}, - {3218, {wxStyledTextCtrl, charRightExtend, 0}}, - {3219, {wxStyledTextCtrl, wordLeft, 0}}, - {3220, {wxStyledTextCtrl, wordLeftExtend, 0}}, - {3221, {wxStyledTextCtrl, wordRight, 0}}, - {3222, {wxStyledTextCtrl, wordRightExtend, 0}}, - {3223, {wxStyledTextCtrl, home, 0}}, - {3224, {wxStyledTextCtrl, homeExtend, 0}}, - {3225, {wxStyledTextCtrl, lineEnd, 0}}, - {3226, {wxStyledTextCtrl, lineEndExtend, 0}}, - {3227, {wxStyledTextCtrl, documentStart, 0}}, - {3228, {wxStyledTextCtrl, documentStartExtend, 0}}, - {3229, {wxStyledTextCtrl, documentEnd, 0}}, - {3230, {wxStyledTextCtrl, documentEndExtend, 0}}, - {3231, {wxStyledTextCtrl, pageUp, 0}}, - {3232, {wxStyledTextCtrl, pageUpExtend, 0}}, - {3233, {wxStyledTextCtrl, pageDown, 0}}, - {3234, {wxStyledTextCtrl, pageDownExtend, 0}}, - {3235, {wxStyledTextCtrl, editToggleOvertype, 0}}, - {3236, {wxStyledTextCtrl, cancel, 0}}, - {3237, {wxStyledTextCtrl, deleteBack, 0}}, - {3238, {wxStyledTextCtrl, tab, 0}}, - {3239, {wxStyledTextCtrl, backTab, 0}}, - {3240, {wxStyledTextCtrl, newLine, 0}}, - {3241, {wxStyledTextCtrl, formFeed, 0}}, - {3242, {wxStyledTextCtrl, vCHome, 0}}, - {3243, {wxStyledTextCtrl, vCHomeExtend, 0}}, - {3244, {wxStyledTextCtrl, zoomIn, 0}}, - {3245, {wxStyledTextCtrl, zoomOut, 0}}, - {3246, {wxStyledTextCtrl, delWordLeft, 0}}, - {3247, {wxStyledTextCtrl, delWordRight, 0}}, - {3248, {wxStyledTextCtrl, lineCut, 0}}, - {3249, {wxStyledTextCtrl, lineDelete, 0}}, - {3250, {wxStyledTextCtrl, lineTranspose, 0}}, - {3251, {wxStyledTextCtrl, lineDuplicate, 0}}, - {3252, {wxStyledTextCtrl, lowerCase, 0}}, - {3253, {wxStyledTextCtrl, upperCase, 0}}, - {3254, {wxStyledTextCtrl, lineScrollDown, 0}}, - {3255, {wxStyledTextCtrl, lineScrollUp, 0}}, - {3256, {wxStyledTextCtrl, deleteBackNotLine, 0}}, - {3257, {wxStyledTextCtrl, homeDisplay, 0}}, - {3258, {wxStyledTextCtrl, homeDisplayExtend, 0}}, - {3259, {wxStyledTextCtrl, lineEndDisplay, 0}}, - {3260, {wxStyledTextCtrl, lineEndDisplayExtend, 0}}, - {3261, {wxStyledTextCtrl, homeWrapExtend, 0}}, - {3262, {wxStyledTextCtrl, lineEndWrap, 0}}, - {3263, {wxStyledTextCtrl, lineEndWrapExtend, 0}}, - {3264, {wxStyledTextCtrl, vCHomeWrap, 0}}, - {3265, {wxStyledTextCtrl, vCHomeWrapExtend, 0}}, - {3266, {wxStyledTextCtrl, lineCopy, 0}}, - {3267, {wxStyledTextCtrl, moveCaretInsideView, 0}}, - {3268, {wxStyledTextCtrl, lineLength, 1}}, - {3269, {wxStyledTextCtrl, braceHighlight, 2}}, - {3270, {wxStyledTextCtrl, braceBadLight, 1}}, - {3271, {wxStyledTextCtrl, braceMatch, 1}}, - {3272, {wxStyledTextCtrl, getViewEOL, 0}}, - {3273, {wxStyledTextCtrl, setViewEOL, 1}}, - {3274, {wxStyledTextCtrl, setModEventMask, 1}}, - {3275, {wxStyledTextCtrl, getEdgeColumn, 0}}, - {3276, {wxStyledTextCtrl, setEdgeColumn, 1}}, - {3277, {wxStyledTextCtrl, setEdgeMode, 1}}, - {3278, {wxStyledTextCtrl, getEdgeMode, 0}}, - {3279, {wxStyledTextCtrl, getEdgeColour, 0}}, - {3280, {wxStyledTextCtrl, setEdgeColour, 1}}, - {3281, {wxStyledTextCtrl, searchAnchor, 0}}, - {3282, {wxStyledTextCtrl, searchNext, 2}}, - {3283, {wxStyledTextCtrl, searchPrev, 2}}, - {3284, {wxStyledTextCtrl, linesOnScreen, 0}}, - {3285, {wxStyledTextCtrl, usePopUp, 1}}, - {3286, {wxStyledTextCtrl, selectionIsRectangle, 0}}, - {3287, {wxStyledTextCtrl, setZoom, 1}}, - {3288, {wxStyledTextCtrl, getZoom, 0}}, - {3289, {wxStyledTextCtrl, getModEventMask, 0}}, - {3290, {wxStyledTextCtrl, setSTCFocus, 1}}, - {3291, {wxStyledTextCtrl, getSTCFocus, 0}}, - {3292, {wxStyledTextCtrl, setStatus, 1}}, - {3293, {wxStyledTextCtrl, getStatus, 0}}, - {3294, {wxStyledTextCtrl, setMouseDownCaptures, 1}}, - {3295, {wxStyledTextCtrl, getMouseDownCaptures, 0}}, - {3296, {wxStyledTextCtrl, setSTCCursor, 1}}, - {3297, {wxStyledTextCtrl, getSTCCursor, 0}}, - {3298, {wxStyledTextCtrl, setControlCharSymbol, 1}}, - {3299, {wxStyledTextCtrl, getControlCharSymbol, 0}}, - {3300, {wxStyledTextCtrl, wordPartLeft, 0}}, - {3301, {wxStyledTextCtrl, wordPartLeftExtend, 0}}, - {3302, {wxStyledTextCtrl, wordPartRight, 0}}, - {3303, {wxStyledTextCtrl, wordPartRightExtend, 0}}, - {3304, {wxStyledTextCtrl, setVisiblePolicy, 2}}, - {3305, {wxStyledTextCtrl, delLineLeft, 0}}, - {3306, {wxStyledTextCtrl, delLineRight, 0}}, - {3307, {wxStyledTextCtrl, getXOffset, 0}}, - {3308, {wxStyledTextCtrl, chooseCaretX, 0}}, - {3309, {wxStyledTextCtrl, setXCaretPolicy, 2}}, - {3310, {wxStyledTextCtrl, setYCaretPolicy, 2}}, - {3311, {wxStyledTextCtrl, getPrintWrapMode, 0}}, - {3312, {wxStyledTextCtrl, setHotspotActiveForeground, 2}}, - {3313, {wxStyledTextCtrl, setHotspotActiveBackground, 2}}, - {3314, {wxStyledTextCtrl, setHotspotActiveUnderline, 1}}, - {3315, {wxStyledTextCtrl, setHotspotSingleLine, 1}}, - {3316, {wxStyledTextCtrl, paraDownExtend, 0}}, - {3317, {wxStyledTextCtrl, paraUp, 0}}, - {3318, {wxStyledTextCtrl, paraUpExtend, 0}}, - {3319, {wxStyledTextCtrl, positionBefore, 1}}, - {3320, {wxStyledTextCtrl, positionAfter, 1}}, - {3321, {wxStyledTextCtrl, copyRange, 2}}, - {3322, {wxStyledTextCtrl, copyText, 2}}, - {3323, {wxStyledTextCtrl, setSelectionMode, 1}}, - {3324, {wxStyledTextCtrl, getSelectionMode, 0}}, - {3325, {wxStyledTextCtrl, lineDownRectExtend, 0}}, - {3326, {wxStyledTextCtrl, lineUpRectExtend, 0}}, - {3327, {wxStyledTextCtrl, charLeftRectExtend, 0}}, - {3328, {wxStyledTextCtrl, charRightRectExtend, 0}}, - {3329, {wxStyledTextCtrl, homeRectExtend, 0}}, - {3330, {wxStyledTextCtrl, vCHomeRectExtend, 0}}, - {3331, {wxStyledTextCtrl, lineEndRectExtend, 0}}, - {3332, {wxStyledTextCtrl, pageUpRectExtend, 0}}, - {3333, {wxStyledTextCtrl, pageDownRectExtend, 0}}, - {3334, {wxStyledTextCtrl, stutteredPageUp, 0}}, - {3335, {wxStyledTextCtrl, stutteredPageUpExtend, 0}}, - {3336, {wxStyledTextCtrl, stutteredPageDown, 0}}, - {3337, {wxStyledTextCtrl, stutteredPageDownExtend, 0}}, - {3338, {wxStyledTextCtrl, wordLeftEnd, 0}}, - {3339, {wxStyledTextCtrl, wordLeftEndExtend, 0}}, - {3340, {wxStyledTextCtrl, wordRightEnd, 0}}, - {3341, {wxStyledTextCtrl, wordRightEndExtend, 0}}, - {3342, {wxStyledTextCtrl, setWhitespaceChars, 1}}, - {3343, {wxStyledTextCtrl, setCharsDefault, 0}}, - {3344, {wxStyledTextCtrl, autoCompGetCurrent, 0}}, - {3345, {wxStyledTextCtrl, allocate, 1}}, - {3346, {wxStyledTextCtrl, findColumn, 2}}, - {3347, {wxStyledTextCtrl, getCaretSticky, 0}}, - {3348, {wxStyledTextCtrl, setCaretSticky, 1}}, - {3349, {wxStyledTextCtrl, toggleCaretSticky, 0}}, - {3350, {wxStyledTextCtrl, setPasteConvertEndings, 1}}, - {3351, {wxStyledTextCtrl, getPasteConvertEndings, 0}}, - {3352, {wxStyledTextCtrl, selectionDuplicate, 0}}, - {3353, {wxStyledTextCtrl, setCaretLineBackAlpha, 1}}, - {3354, {wxStyledTextCtrl, getCaretLineBackAlpha, 0}}, - {3355, {wxStyledTextCtrl, startRecord, 0}}, - {3356, {wxStyledTextCtrl, stopRecord, 0}}, - {3357, {wxStyledTextCtrl, setLexer, 1}}, - {3358, {wxStyledTextCtrl, getLexer, 0}}, - {3359, {wxStyledTextCtrl, colourise, 2}}, - {3360, {wxStyledTextCtrl, setProperty, 2}}, - {3361, {wxStyledTextCtrl, setKeyWords, 2}}, - {3362, {wxStyledTextCtrl, setLexerLanguage, 1}}, - {3363, {wxStyledTextCtrl, getProperty, 1}}, - {3364, {wxStyledTextCtrl, getStyleBitsNeeded, 0}}, - {3365, {wxStyledTextCtrl, getCurrentLine, 0}}, - {3366, {wxStyledTextCtrl, styleSetSpec, 2}}, - {3367, {wxStyledTextCtrl, styleSetFont, 2}}, - {3368, {wxStyledTextCtrl, styleSetFontAttr, 7}}, - {3369, {wxStyledTextCtrl, styleSetCharacterSet, 2}}, - {3370, {wxStyledTextCtrl, styleSetFontEncoding, 2}}, - {3371, {wxStyledTextCtrl, cmdKeyExecute, 1}}, - {3372, {wxStyledTextCtrl, setMargins, 2}}, - {3373, {wxStyledTextCtrl, getSelection, 2}}, - {3374, {wxStyledTextCtrl, pointFromPosition, 1}}, - {3375, {wxStyledTextCtrl, scrollToLine, 1}}, - {3376, {wxStyledTextCtrl, scrollToColumn, 1}}, - {3377, {wxStyledTextCtrl, setVScrollBar, 1}}, - {3378, {wxStyledTextCtrl, setHScrollBar, 1}}, - {3379, {wxStyledTextCtrl, getLastKeydownProcessed, 0}}, - {3380, {wxStyledTextCtrl, setLastKeydownProcessed, 1}}, - {3381, {wxStyledTextCtrl, saveFile, 1}}, - {3382, {wxStyledTextCtrl, loadFile, 1}}, - {3383, {wxStyledTextCtrl, doDragOver, 3}}, - {3384, {wxStyledTextCtrl, doDropText, 3}}, - {3385, {wxStyledTextCtrl, getUseAntiAliasing, 0}}, - {3386, {wxStyledTextCtrl, addTextRaw, 1}}, - {3387, {wxStyledTextCtrl, insertTextRaw, 2}}, - {3388, {wxStyledTextCtrl, getCurLineRaw, 1}}, - {3389, {wxStyledTextCtrl, getLineRaw, 1}}, - {3390, {wxStyledTextCtrl, getSelectedTextRaw, 0}}, - {3391, {wxStyledTextCtrl, getTextRangeRaw, 2}}, - {3392, {wxStyledTextCtrl, setTextRaw, 1}}, - {3393, {wxStyledTextCtrl, getTextRaw, 0}}, - {3394, {wxStyledTextCtrl, appendTextRaw, 1}}, - {3395, {wxArtProvider, getBitmap, 2}}, - {3396, {wxArtProvider, getIcon, 2}}, - {3397, {wxTreeEvent, getKeyCode, 0}}, - {3398, {wxTreeEvent, getItem, 0}}, - {3399, {wxTreeEvent, getKeyEvent, 0}}, - {3400, {wxTreeEvent, getLabel, 0}}, - {3401, {wxTreeEvent, getOldItem, 0}}, - {3402, {wxTreeEvent, getPoint, 0}}, - {3403, {wxTreeEvent, isEditCancelled, 0}}, - {3404, {wxTreeEvent, setToolTip, 1}}, - {3405, {wxNotebookEvent, getOldSelection, 0}}, - {3406, {wxNotebookEvent, getSelection, 0}}, - {3407, {wxNotebookEvent, setOldSelection, 1}}, - {3408, {wxNotebookEvent, setSelection, 1}}, - {3409, {wxFileDataObject, new, 0}}, - {3410, {wxFileDataObject, addFile, 1}}, - {3411, {wxFileDataObject, getFilenames, 0}}, - {3412, {wxFileDataObject, 'Destroy', undefined}}, - {3413, {wxTextDataObject, new, 1}}, - {3414, {wxTextDataObject, getTextLength, 0}}, - {3415, {wxTextDataObject, getText, 0}}, - {3416, {wxTextDataObject, setText, 1}}, - {3417, {wxTextDataObject, 'Destroy', undefined}}, - {3418, {wxBitmapDataObject, new_1_1, 1}}, - {3419, {wxBitmapDataObject, new_1_0, 1}}, - {3420, {wxBitmapDataObject, getBitmap, 0}}, - {3421, {wxBitmapDataObject, setBitmap, 1}}, - {3422, {wxBitmapDataObject, 'Destroy', undefined}}, - {3424, {wxClipboard, new, 0}}, - {3425, {wxClipboard, destruct, 0}}, - {3426, {wxClipboard, addData, 1}}, - {3427, {wxClipboard, clear, 0}}, - {3428, {wxClipboard, close, 0}}, - {3429, {wxClipboard, flush, 0}}, - {3430, {wxClipboard, getData, 1}}, - {3431, {wxClipboard, isOpened, 0}}, - {3432, {wxClipboard, open, 0}}, - {3433, {wxClipboard, setData, 1}}, - {3435, {wxClipboard, usePrimarySelection, 1}}, - {3436, {wxClipboard, isSupported, 1}}, - {3437, {wxClipboard, get, 0}}, - {3438, {wxSpinEvent, getPosition, 0}}, - {3439, {wxSpinEvent, setPosition, 1}}, - {3440, {wxSplitterWindow, new_0, 0}}, - {3441, {wxSplitterWindow, new_2, 2}}, - {3442, {wxSplitterWindow, destruct, 0}}, - {3443, {wxSplitterWindow, create, 2}}, - {3444, {wxSplitterWindow, getMinimumPaneSize, 0}}, - {3445, {wxSplitterWindow, getSashGravity, 0}}, - {3446, {wxSplitterWindow, getSashPosition, 0}}, - {3447, {wxSplitterWindow, getSplitMode, 0}}, - {3448, {wxSplitterWindow, getWindow1, 0}}, - {3449, {wxSplitterWindow, getWindow2, 0}}, - {3450, {wxSplitterWindow, initialize, 1}}, - {3451, {wxSplitterWindow, isSplit, 0}}, - {3452, {wxSplitterWindow, replaceWindow, 2}}, - {3453, {wxSplitterWindow, setSashGravity, 1}}, - {3454, {wxSplitterWindow, setSashPosition, 2}}, - {3455, {wxSplitterWindow, setSashSize, 1}}, - {3456, {wxSplitterWindow, setMinimumPaneSize, 1}}, - {3457, {wxSplitterWindow, setSplitMode, 1}}, - {3458, {wxSplitterWindow, splitHorizontally, 3}}, - {3459, {wxSplitterWindow, splitVertically, 3}}, - {3460, {wxSplitterWindow, unsplit, 1}}, - {3461, {wxSplitterWindow, updateSize, 0}}, - {3462, {wxSplitterEvent, getSashPosition, 0}}, - {3463, {wxSplitterEvent, getX, 0}}, - {3464, {wxSplitterEvent, getY, 0}}, - {3465, {wxSplitterEvent, getWindowBeingRemoved, 0}}, - {3466, {wxSplitterEvent, setSashPosition, 1}}, - {3467, {wxHtmlWindow, new_0, 0}}, - {3468, {wxHtmlWindow, new_2, 2}}, - {3469, {wxHtmlWindow, appendToPage, 1}}, - {3470, {wxHtmlWindow, getOpenedAnchor, 0}}, - {3471, {wxHtmlWindow, getOpenedPage, 0}}, - {3472, {wxHtmlWindow, getOpenedPageTitle, 0}}, - {3473, {wxHtmlWindow, getRelatedFrame, 0}}, - {3474, {wxHtmlWindow, historyBack, 0}}, - {3475, {wxHtmlWindow, historyCanBack, 0}}, - {3476, {wxHtmlWindow, historyCanForward, 0}}, - {3477, {wxHtmlWindow, historyClear, 0}}, - {3478, {wxHtmlWindow, historyForward, 0}}, - {3479, {wxHtmlWindow, loadFile, 1}}, - {3480, {wxHtmlWindow, loadPage, 1}}, - {3481, {wxHtmlWindow, selectAll, 0}}, - {3482, {wxHtmlWindow, selectionToText, 0}}, - {3483, {wxHtmlWindow, selectLine, 1}}, - {3484, {wxHtmlWindow, selectWord, 1}}, - {3485, {wxHtmlWindow, setBorders, 1}}, - {3486, {wxHtmlWindow, setFonts, 3}}, - {3487, {wxHtmlWindow, setPage, 1}}, - {3488, {wxHtmlWindow, setRelatedFrame, 2}}, - {3489, {wxHtmlWindow, setRelatedStatusBar, 1}}, - {3490, {wxHtmlWindow, toText, 0}}, - {3491, {wxHtmlWindow, 'Destroy', undefined}}, - {3492, {wxHtmlLinkEvent, getLinkInfo, 0}}, - {3493, {wxSystemSettings, getColour, 1}}, - {3494, {wxSystemSettings, getFont, 1}}, - {3495, {wxSystemSettings, getMetric, 2}}, - {3496, {wxSystemSettings, getScreenType, 0}}, - {3497, {wxSystemOptions, getOption, 1}}, - {3498, {wxSystemOptions, getOptionInt, 1}}, - {3499, {wxSystemOptions, hasOption, 1}}, - {3500, {wxSystemOptions, isFalse, 1}}, - {3501, {wxSystemOptions, setOption_2_1, 2}}, - {3502, {wxSystemOptions, setOption_2_0, 2}}, - {3503, {wxAuiNotebookEvent, setSelection, 1}}, - {3504, {wxAuiNotebookEvent, getSelection, 0}}, - {3505, {wxAuiNotebookEvent, setOldSelection, 1}}, - {3506, {wxAuiNotebookEvent, getOldSelection, 0}}, - {3507, {wxAuiNotebookEvent, setDragSource, 1}}, - {3508, {wxAuiNotebookEvent, getDragSource, 0}}, - {3509, {wxAuiManagerEvent, setManager, 1}}, - {3510, {wxAuiManagerEvent, getManager, 0}}, - {3511, {wxAuiManagerEvent, setPane, 1}}, - {3512, {wxAuiManagerEvent, getPane, 0}}, - {3513, {wxAuiManagerEvent, setButton, 1}}, - {3514, {wxAuiManagerEvent, getButton, 0}}, - {3515, {wxAuiManagerEvent, setDC, 1}}, - {3516, {wxAuiManagerEvent, getDC, 0}}, - {3517, {wxAuiManagerEvent, veto, 1}}, - {3518, {wxAuiManagerEvent, getVeto, 0}}, - {3519, {wxAuiManagerEvent, setCanVeto, 1}}, - {3520, {wxAuiManagerEvent, canVeto, 0}}, - {3521, {wxLogNull, new, 0}}, - {3522, {wxLogNull, 'Destroy', undefined}}, - {3523, {wxTaskBarIcon, new, 0}}, - {3524, {wxTaskBarIcon, destruct, 0}}, - {3525, {wxTaskBarIcon, popupMenu, 1}}, - {3526, {wxTaskBarIcon, removeIcon, 0}}, - {3527, {wxTaskBarIcon, setIcon, 2}}, - {3528, {wxLocale, new_0, 0}}, - {3530, {wxLocale, new_2, 2}}, - {3531, {wxLocale, destruct, 0}}, - {3533, {wxLocale, init, 1}}, - {3534, {wxLocale, addCatalog_1, 1}}, - {3535, {wxLocale, addCatalog_3, 3}}, - {3536, {wxLocale, addCatalogLookupPathPrefix, 1}}, - {3537, {wxLocale, getCanonicalName, 0}}, - {3538, {wxLocale, getLanguage, 0}}, - {3539, {wxLocale, getLanguageName, 1}}, - {3540, {wxLocale, getLocale, 0}}, - {3541, {wxLocale, getName, 0}}, - {3542, {wxLocale, getString_2, 2}}, - {3543, {wxLocale, getString_4, 4}}, - {3544, {wxLocale, getHeaderValue, 2}}, - {3545, {wxLocale, getSysName, 0}}, - {3546, {wxLocale, getSystemEncoding, 0}}, - {3547, {wxLocale, getSystemEncodingName, 0}}, - {3548, {wxLocale, getSystemLanguage, 0}}, - {3549, {wxLocale, isLoaded, 1}}, - {3550, {wxLocale, isOk, 0}}, - {3551, {wxActivateEvent, getActive, 0}}, - {3553, {wxPopupWindow, new_2, 2}}, - {3554, {wxPopupWindow, new_0, 0}}, - {3556, {wxPopupWindow, destruct, 0}}, - {3557, {wxPopupWindow, create, 2}}, - {3558, {wxPopupWindow, position, 2}}, - {3559, {wxPopupTransientWindow, new_0, 0}}, - {3560, {wxPopupTransientWindow, new_2, 2}}, - {3561, {wxPopupTransientWindow, destruct, 0}}, - {3562, {wxPopupTransientWindow, popup, 1}}, - {3563, {wxPopupTransientWindow, dismiss, 0}}, + {284, {wxWindow, setTransparent, 1}}, + {285, {wxWindow, canSetTransparent, 0}}, + {286, {wxWindow, isDoubleBuffered, 0}}, + {287, {wxWindow, setDoubleBuffered, 1}}, + {288, {wxTopLevelWindow, getIcon, 0}}, + {289, {wxTopLevelWindow, getIcons, 0}}, + {290, {wxTopLevelWindow, getTitle, 0}}, + {291, {wxTopLevelWindow, isActive, 0}}, + {292, {wxTopLevelWindow, iconize, 1}}, + {293, {wxTopLevelWindow, isFullScreen, 0}}, + {294, {wxTopLevelWindow, isIconized, 0}}, + {295, {wxTopLevelWindow, isMaximized, 0}}, + {296, {wxTopLevelWindow, maximize, 1}}, + {297, {wxTopLevelWindow, requestUserAttention, 1}}, + {298, {wxTopLevelWindow, setIcon, 1}}, + {299, {wxTopLevelWindow, setIcons, 1}}, + {300, {wxTopLevelWindow, centerOnScreen, 1}}, + {301, {wxTopLevelWindow, centreOnScreen, 1}}, + {303, {wxTopLevelWindow, setShape, 1}}, + {304, {wxTopLevelWindow, setTitle, 1}}, + {305, {wxTopLevelWindow, showFullScreen, 2}}, + {307, {wxFrame, new_4, 4}}, + {308, {wxFrame, new_0, 0}}, + {310, {wxFrame, destruct, 0}}, + {311, {wxFrame, create, 4}}, + {312, {wxFrame, createStatusBar, 1}}, + {313, {wxFrame, createToolBar, 1}}, + {314, {wxFrame, getClientAreaOrigin, 0}}, + {315, {wxFrame, getMenuBar, 0}}, + {316, {wxFrame, getStatusBar, 0}}, + {317, {wxFrame, getStatusBarPane, 0}}, + {318, {wxFrame, getToolBar, 0}}, + {319, {wxFrame, processCommand, 1}}, + {320, {wxFrame, sendSizeEvent, 0}}, + {321, {wxFrame, setMenuBar, 1}}, + {322, {wxFrame, setStatusBar, 1}}, + {323, {wxFrame, setStatusBarPane, 1}}, + {324, {wxFrame, setStatusText, 2}}, + {325, {wxFrame, setStatusWidths, 2}}, + {326, {wxFrame, setToolBar, 1}}, + {327, {wxMiniFrame, new_0, 0}}, + {328, {wxMiniFrame, new_4, 4}}, + {329, {wxMiniFrame, create, 4}}, + {330, {wxMiniFrame, 'Destroy', undefined}}, + {331, {wxSplashScreen, new_0, 0}}, + {332, {wxSplashScreen, new_6, 6}}, + {333, {wxSplashScreen, destruct, 0}}, + {334, {wxSplashScreen, getSplashStyle, 0}}, + {335, {wxSplashScreen, getTimeout, 0}}, + {336, {wxPanel, new_0, 0}}, + {337, {wxPanel, new_6, 6}}, + {338, {wxPanel, new_2, 2}}, + {339, {wxPanel, destruct, 0}}, + {340, {wxPanel, initDialog, 0}}, + {341, {wxPanel, setFocusIgnoringChildren, 0}}, + {342, {wxScrolledWindow, new_0, 0}}, + {343, {wxScrolledWindow, new_2, 2}}, + {344, {wxScrolledWindow, destruct, 0}}, + {345, {wxScrolledWindow, calcScrolledPosition_4, 4}}, + {346, {wxScrolledWindow, calcScrolledPosition_1, 1}}, + {347, {wxScrolledWindow, calcUnscrolledPosition_4, 4}}, + {348, {wxScrolledWindow, calcUnscrolledPosition_1, 1}}, + {349, {wxScrolledWindow, enableScrolling, 2}}, + {350, {wxScrolledWindow, getScrollPixelsPerUnit, 2}}, + {351, {wxScrolledWindow, getViewStart, 2}}, + {352, {wxScrolledWindow, doPrepareDC, 1}}, + {353, {wxScrolledWindow, prepareDC, 1}}, + {354, {wxScrolledWindow, scroll, 2}}, + {355, {wxScrolledWindow, setScrollbars, 5}}, + {356, {wxScrolledWindow, setScrollRate, 2}}, + {357, {wxScrolledWindow, setTargetWindow, 1}}, + {358, {wxSashWindow, new_0, 0}}, + {359, {wxSashWindow, new_2, 2}}, + {360, {wxSashWindow, destruct, 0}}, + {361, {wxSashWindow, getSashVisible, 1}}, + {362, {wxSashWindow, getMaximumSizeX, 0}}, + {363, {wxSashWindow, getMaximumSizeY, 0}}, + {364, {wxSashWindow, getMinimumSizeX, 0}}, + {365, {wxSashWindow, getMinimumSizeY, 0}}, + {366, {wxSashWindow, setMaximumSizeX, 1}}, + {367, {wxSashWindow, setMaximumSizeY, 1}}, + {368, {wxSashWindow, setMinimumSizeX, 1}}, + {369, {wxSashWindow, setMinimumSizeY, 1}}, + {370, {wxSashWindow, setSashVisible, 2}}, + {371, {wxSashLayoutWindow, new_0, 0}}, + {372, {wxSashLayoutWindow, new_2, 2}}, + {373, {wxSashLayoutWindow, create, 2}}, + {374, {wxSashLayoutWindow, getAlignment, 0}}, + {375, {wxSashLayoutWindow, getOrientation, 0}}, + {376, {wxSashLayoutWindow, setAlignment, 1}}, + {377, {wxSashLayoutWindow, setDefaultSize, 1}}, + {378, {wxSashLayoutWindow, setOrientation, 1}}, + {379, {wxSashLayoutWindow, 'Destroy', undefined}}, + {380, {wxGrid, new_0, 0}}, + {381, {wxGrid, new_3, 3}}, + {382, {wxGrid, new_4, 4}}, + {383, {wxGrid, destruct, 0}}, + {384, {wxGrid, appendCols, 1}}, + {385, {wxGrid, appendRows, 1}}, + {386, {wxGrid, autoSize, 0}}, + {387, {wxGrid, autoSizeColumn, 2}}, + {388, {wxGrid, autoSizeColumns, 1}}, + {389, {wxGrid, autoSizeRow, 2}}, + {390, {wxGrid, autoSizeRows, 1}}, + {391, {wxGrid, beginBatch, 0}}, + {392, {wxGrid, blockToDeviceRect, 2}}, + {393, {wxGrid, canDragColSize, 0}}, + {394, {wxGrid, canDragRowSize, 0}}, + {395, {wxGrid, canDragGridSize, 0}}, + {396, {wxGrid, canEnableCellControl, 0}}, + {397, {wxGrid, cellToRect_2, 2}}, + {398, {wxGrid, cellToRect_1, 1}}, + {399, {wxGrid, clearGrid, 0}}, + {400, {wxGrid, clearSelection, 0}}, + {401, {wxGrid, createGrid, 3}}, + {402, {wxGrid, deleteCols, 1}}, + {403, {wxGrid, deleteRows, 1}}, + {404, {wxGrid, disableCellEditControl, 0}}, + {405, {wxGrid, disableDragColSize, 0}}, + {406, {wxGrid, disableDragGridSize, 0}}, + {407, {wxGrid, disableDragRowSize, 0}}, + {408, {wxGrid, enableCellEditControl, 1}}, + {409, {wxGrid, enableDragColSize, 1}}, + {410, {wxGrid, enableDragGridSize, 1}}, + {411, {wxGrid, enableDragRowSize, 1}}, + {412, {wxGrid, enableEditing, 1}}, + {413, {wxGrid, enableGridLines, 1}}, + {414, {wxGrid, endBatch, 0}}, + {415, {wxGrid, fit, 0}}, + {416, {wxGrid, forceRefresh, 0}}, + {417, {wxGrid, getBatchCount, 0}}, + {418, {wxGrid, getCellAlignment, 4}}, + {419, {wxGrid, getCellBackgroundColour, 2}}, + {420, {wxGrid, getCellEditor, 2}}, + {421, {wxGrid, getCellFont, 2}}, + {422, {wxGrid, getCellRenderer, 2}}, + {423, {wxGrid, getCellTextColour, 2}}, + {424, {wxGrid, getCellValue_2, 2}}, + {425, {wxGrid, getCellValue_1, 1}}, + {426, {wxGrid, getColLabelAlignment, 2}}, + {427, {wxGrid, getColLabelSize, 0}}, + {428, {wxGrid, getColLabelValue, 1}}, + {429, {wxGrid, getColMinimalAcceptableWidth, 0}}, + {430, {wxGrid, getDefaultCellAlignment, 2}}, + {431, {wxGrid, getDefaultCellBackgroundColour, 0}}, + {432, {wxGrid, getDefaultCellFont, 0}}, + {433, {wxGrid, getDefaultCellTextColour, 0}}, + {434, {wxGrid, getDefaultColLabelSize, 0}}, + {435, {wxGrid, getDefaultColSize, 0}}, + {436, {wxGrid, getDefaultEditor, 0}}, + {437, {wxGrid, getDefaultEditorForCell_2, 2}}, + {438, {wxGrid, getDefaultEditorForCell_1, 1}}, + {439, {wxGrid, getDefaultEditorForType, 1}}, + {440, {wxGrid, getDefaultRenderer, 0}}, + {441, {wxGrid, getDefaultRendererForCell, 2}}, + {442, {wxGrid, getDefaultRendererForType, 1}}, + {443, {wxGrid, getDefaultRowLabelSize, 0}}, + {444, {wxGrid, getDefaultRowSize, 0}}, + {445, {wxGrid, getGridCursorCol, 0}}, + {446, {wxGrid, getGridCursorRow, 0}}, + {447, {wxGrid, getGridLineColour, 0}}, + {448, {wxGrid, gridLinesEnabled, 0}}, + {449, {wxGrid, getLabelBackgroundColour, 0}}, + {450, {wxGrid, getLabelFont, 0}}, + {451, {wxGrid, getLabelTextColour, 0}}, + {452, {wxGrid, getNumberCols, 0}}, + {453, {wxGrid, getNumberRows, 0}}, + {454, {wxGrid, getOrCreateCellAttr, 2}}, + {455, {wxGrid, getRowMinimalAcceptableHeight, 0}}, + {456, {wxGrid, getRowLabelAlignment, 2}}, + {457, {wxGrid, getRowLabelSize, 0}}, + {458, {wxGrid, getRowLabelValue, 1}}, + {459, {wxGrid, getRowSize, 1}}, + {460, {wxGrid, getScrollLineX, 0}}, + {461, {wxGrid, getScrollLineY, 0}}, + {462, {wxGrid, getSelectedCells, 0}}, + {463, {wxGrid, getSelectedCols, 0}}, + {464, {wxGrid, getSelectedRows, 0}}, + {465, {wxGrid, getSelectionBackground, 0}}, + {466, {wxGrid, getSelectionBlockTopLeft, 0}}, + {467, {wxGrid, getSelectionBlockBottomRight, 0}}, + {468, {wxGrid, getSelectionForeground, 0}}, + {469, {wxGrid, getViewWidth, 0}}, + {470, {wxGrid, getGridWindow, 0}}, + {471, {wxGrid, getGridRowLabelWindow, 0}}, + {472, {wxGrid, getGridColLabelWindow, 0}}, + {473, {wxGrid, getGridCornerLabelWindow, 0}}, + {474, {wxGrid, hideCellEditControl, 0}}, + {475, {wxGrid, insertCols, 1}}, + {476, {wxGrid, insertRows, 1}}, + {477, {wxGrid, isCellEditControlEnabled, 0}}, + {478, {wxGrid, isCurrentCellReadOnly, 0}}, + {479, {wxGrid, isEditable, 0}}, + {480, {wxGrid, isInSelection_2, 2}}, + {481, {wxGrid, isInSelection_1, 1}}, + {482, {wxGrid, isReadOnly, 2}}, + {483, {wxGrid, isSelection, 0}}, + {484, {wxGrid, isVisible_3, 3}}, + {485, {wxGrid, isVisible_2, 2}}, + {486, {wxGrid, makeCellVisible_2, 2}}, + {487, {wxGrid, makeCellVisible_1, 1}}, + {488, {wxGrid, moveCursorDown, 1}}, + {489, {wxGrid, moveCursorLeft, 1}}, + {490, {wxGrid, moveCursorRight, 1}}, + {491, {wxGrid, moveCursorUp, 1}}, + {492, {wxGrid, moveCursorDownBlock, 1}}, + {493, {wxGrid, moveCursorLeftBlock, 1}}, + {494, {wxGrid, moveCursorRightBlock, 1}}, + {495, {wxGrid, moveCursorUpBlock, 1}}, + {496, {wxGrid, movePageDown, 0}}, + {497, {wxGrid, movePageUp, 0}}, + {498, {wxGrid, registerDataType, 3}}, + {499, {wxGrid, saveEditControlValue, 0}}, + {500, {wxGrid, selectAll, 0}}, + {501, {wxGrid, selectBlock_5, 5}}, + {502, {wxGrid, selectBlock_3, 3}}, + {503, {wxGrid, selectCol, 2}}, + {504, {wxGrid, selectRow, 2}}, + {505, {wxGrid, setCellAlignment_4, 4}}, + {506, {wxGrid, setCellAlignment_3, 3}}, + {507, {wxGrid, setCellAlignment_1, 1}}, + {508, {wxGrid, setCellBackgroundColour_3_0, 3}}, + {509, {wxGrid, setCellBackgroundColour_1, 1}}, + {510, {wxGrid, setCellBackgroundColour_3_1, 3}}, + {511, {wxGrid, setCellEditor, 3}}, + {512, {wxGrid, setCellFont, 3}}, + {513, {wxGrid, setCellRenderer, 3}}, + {514, {wxGrid, setCellTextColour_3_0, 3}}, + {515, {wxGrid, setCellTextColour_3_1, 3}}, + {516, {wxGrid, setCellTextColour_1, 1}}, + {517, {wxGrid, setCellValue_3_0, 3}}, + {518, {wxGrid, setCellValue_2, 2}}, + {519, {wxGrid, setCellValue_3_1, 3}}, + {520, {wxGrid, setColAttr, 2}}, + {521, {wxGrid, setColFormatBool, 1}}, + {522, {wxGrid, setColFormatNumber, 1}}, + {523, {wxGrid, setColFormatFloat, 2}}, + {524, {wxGrid, setColFormatCustom, 2}}, + {525, {wxGrid, setColLabelAlignment, 2}}, + {526, {wxGrid, setColLabelSize, 1}}, + {527, {wxGrid, setColLabelValue, 2}}, + {528, {wxGrid, setColMinimalWidth, 2}}, + {529, {wxGrid, setColMinimalAcceptableWidth, 1}}, + {530, {wxGrid, setColSize, 2}}, + {531, {wxGrid, setDefaultCellAlignment, 2}}, + {532, {wxGrid, setDefaultCellBackgroundColour, 1}}, + {533, {wxGrid, setDefaultCellFont, 1}}, + {534, {wxGrid, setDefaultCellTextColour, 1}}, + {535, {wxGrid, setDefaultEditor, 1}}, + {536, {wxGrid, setDefaultRenderer, 1}}, + {537, {wxGrid, setDefaultColSize, 2}}, + {538, {wxGrid, setDefaultRowSize, 2}}, + {539, {wxGrid, setGridCursor, 2}}, + {540, {wxGrid, setGridLineColour, 1}}, + {541, {wxGrid, setLabelBackgroundColour, 1}}, + {542, {wxGrid, setLabelFont, 1}}, + {543, {wxGrid, setLabelTextColour, 1}}, + {544, {wxGrid, setMargins, 2}}, + {545, {wxGrid, setReadOnly, 3}}, + {546, {wxGrid, setRowAttr, 2}}, + {547, {wxGrid, setRowLabelAlignment, 2}}, + {548, {wxGrid, setRowLabelSize, 1}}, + {549, {wxGrid, setRowLabelValue, 2}}, + {550, {wxGrid, setRowMinimalHeight, 2}}, + {551, {wxGrid, setRowMinimalAcceptableHeight, 1}}, + {552, {wxGrid, setRowSize, 2}}, + {553, {wxGrid, setScrollLineX, 1}}, + {554, {wxGrid, setScrollLineY, 1}}, + {555, {wxGrid, setSelectionBackground, 1}}, + {556, {wxGrid, setSelectionForeground, 1}}, + {557, {wxGrid, setSelectionMode, 1}}, + {558, {wxGrid, showCellEditControl, 0}}, + {559, {wxGrid, xToCol, 2}}, + {560, {wxGrid, xToEdgeOfCol, 1}}, + {561, {wxGrid, yToEdgeOfRow, 1}}, + {562, {wxGrid, yToRow, 1}}, + {563, {wxGridCellRenderer, draw, 7}}, + {564, {wxGridCellRenderer, getBestSize, 5}}, + {565, {wxGridCellEditor, create, 3}}, + {566, {wxGridCellEditor, isCreated, 0}}, + {567, {wxGridCellEditor, setSize, 1}}, + {568, {wxGridCellEditor, show, 2}}, + {569, {wxGridCellEditor, paintBackground, 2}}, + {570, {wxGridCellEditor, beginEdit, 3}}, + {571, {wxGridCellEditor, endEdit, 3}}, + {572, {wxGridCellEditor, reset, 0}}, + {573, {wxGridCellEditor, startingKey, 1}}, + {574, {wxGridCellEditor, startingClick, 0}}, + {575, {wxGridCellEditor, handleReturn, 1}}, + {576, {wxGridCellBoolRenderer, new, 0}}, + {577, {wxGridCellBoolRenderer, 'Destroy', undefined}}, + {578, {wxGridCellBoolEditor, new, 0}}, + {579, {wxGridCellBoolEditor, isTrueValue, 1}}, + {580, {wxGridCellBoolEditor, useStringValues, 1}}, + {581, {wxGridCellBoolEditor, 'Destroy', undefined}}, + {582, {wxGridCellFloatRenderer, new, 1}}, + {583, {wxGridCellFloatRenderer, getPrecision, 0}}, + {584, {wxGridCellFloatRenderer, getWidth, 0}}, + {585, {wxGridCellFloatRenderer, setParameters, 1}}, + {586, {wxGridCellFloatRenderer, setPrecision, 1}}, + {587, {wxGridCellFloatRenderer, setWidth, 1}}, + {588, {wxGridCellFloatRenderer, 'Destroy', undefined}}, + {589, {wxGridCellFloatEditor, new, 1}}, + {590, {wxGridCellFloatEditor, setParameters, 1}}, + {591, {wxGridCellFloatEditor, 'Destroy', undefined}}, + {592, {wxGridCellStringRenderer, new, 0}}, + {593, {wxGridCellStringRenderer, 'Destroy', undefined}}, + {594, {wxGridCellTextEditor, new, 0}}, + {595, {wxGridCellTextEditor, setParameters, 1}}, + {596, {wxGridCellTextEditor, 'Destroy', undefined}}, + {598, {wxGridCellChoiceEditor, new, 2}}, + {599, {wxGridCellChoiceEditor, setParameters, 1}}, + {600, {wxGridCellChoiceEditor, 'Destroy', undefined}}, + {601, {wxGridCellNumberRenderer, new, 0}}, + {602, {wxGridCellNumberRenderer, 'Destroy', undefined}}, + {603, {wxGridCellNumberEditor, new, 1}}, + {604, {wxGridCellNumberEditor, getValue, 0}}, + {605, {wxGridCellNumberEditor, setParameters, 1}}, + {606, {wxGridCellNumberEditor, 'Destroy', undefined}}, + {607, {wxGridCellAttr, setTextColour, 1}}, + {608, {wxGridCellAttr, setBackgroundColour, 1}}, + {609, {wxGridCellAttr, setFont, 1}}, + {610, {wxGridCellAttr, setAlignment, 2}}, + {611, {wxGridCellAttr, setReadOnly, 1}}, + {612, {wxGridCellAttr, setRenderer, 1}}, + {613, {wxGridCellAttr, setEditor, 1}}, + {614, {wxGridCellAttr, hasTextColour, 0}}, + {615, {wxGridCellAttr, hasBackgroundColour, 0}}, + {616, {wxGridCellAttr, hasFont, 0}}, + {617, {wxGridCellAttr, hasAlignment, 0}}, + {618, {wxGridCellAttr, hasRenderer, 0}}, + {619, {wxGridCellAttr, hasEditor, 0}}, + {620, {wxGridCellAttr, getTextColour, 0}}, + {621, {wxGridCellAttr, getBackgroundColour, 0}}, + {622, {wxGridCellAttr, getFont, 0}}, + {623, {wxGridCellAttr, getAlignment, 2}}, + {624, {wxGridCellAttr, getRenderer, 3}}, + {625, {wxGridCellAttr, getEditor, 3}}, + {626, {wxGridCellAttr, isReadOnly, 0}}, + {627, {wxGridCellAttr, setDefAttr, 1}}, + {628, {wxDC, blit, 5}}, + {629, {wxDC, calcBoundingBox, 2}}, + {630, {wxDC, clear, 0}}, + {631, {wxDC, computeScaleAndOrigin, 0}}, + {632, {wxDC, crossHair, 1}}, + {633, {wxDC, destroyClippingRegion, 0}}, + {634, {wxDC, deviceToLogicalX, 1}}, + {635, {wxDC, deviceToLogicalXRel, 1}}, + {636, {wxDC, deviceToLogicalY, 1}}, + {637, {wxDC, deviceToLogicalYRel, 1}}, + {638, {wxDC, drawArc, 3}}, + {639, {wxDC, drawBitmap, 3}}, + {640, {wxDC, drawCheckMark, 1}}, + {641, {wxDC, drawCircle, 2}}, + {643, {wxDC, drawEllipse_2, 2}}, + {644, {wxDC, drawEllipse_1, 1}}, + {645, {wxDC, drawEllipticArc, 4}}, + {646, {wxDC, drawIcon, 2}}, + {647, {wxDC, drawLabel, 3}}, + {648, {wxDC, drawLine, 2}}, + {649, {wxDC, drawLines, 3}}, + {651, {wxDC, drawPolygon, 3}}, + {653, {wxDC, drawPoint, 1}}, + {655, {wxDC, drawRectangle_2, 2}}, + {656, {wxDC, drawRectangle_1, 1}}, + {657, {wxDC, drawRotatedText, 3}}, + {659, {wxDC, drawRoundedRectangle_3, 3}}, + {660, {wxDC, drawRoundedRectangle_2, 2}}, + {661, {wxDC, drawText, 2}}, + {662, {wxDC, endDoc, 0}}, + {663, {wxDC, endPage, 0}}, + {664, {wxDC, floodFill, 3}}, + {665, {wxDC, getBackground, 0}}, + {666, {wxDC, getBackgroundMode, 0}}, + {667, {wxDC, getBrush, 0}}, + {668, {wxDC, getCharHeight, 0}}, + {669, {wxDC, getCharWidth, 0}}, + {670, {wxDC, getClippingBox, 4}}, + {672, {wxDC, getFont, 0}}, + {673, {wxDC, getLayoutDirection, 0}}, + {674, {wxDC, getLogicalFunction, 0}}, + {675, {wxDC, getMapMode, 0}}, + {676, {wxDC, getMultiLineTextExtent_4, 4}}, + {677, {wxDC, getMultiLineTextExtent_1, 1}}, + {678, {wxDC, getPartialTextExtents, 2}}, + {679, {wxDC, getPen, 0}}, + {680, {wxDC, getPixel, 2}}, + {681, {wxDC, getPPI, 0}}, + {683, {wxDC, getSize, 0}}, + {685, {wxDC, getSizeMM, 0}}, + {686, {wxDC, getTextBackground, 0}}, + {687, {wxDC, getTextExtent_4, 4}}, + {688, {wxDC, getTextExtent_1, 1}}, + {690, {wxDC, getTextForeground, 0}}, + {691, {wxDC, getUserScale, 2}}, + {692, {wxDC, gradientFillConcentric_3, 3}}, + {693, {wxDC, gradientFillConcentric_4, 4}}, + {694, {wxDC, gradientFillLinear, 4}}, + {695, {wxDC, logicalToDeviceX, 1}}, + {696, {wxDC, logicalToDeviceXRel, 1}}, + {697, {wxDC, logicalToDeviceY, 1}}, + {698, {wxDC, logicalToDeviceYRel, 1}}, + {699, {wxDC, maxX, 0}}, + {700, {wxDC, maxY, 0}}, + {701, {wxDC, minX, 0}}, + {702, {wxDC, minY, 0}}, + {703, {wxDC, isOk, 0}}, + {704, {wxDC, resetBoundingBox, 0}}, + {705, {wxDC, setAxisOrientation, 2}}, + {706, {wxDC, setBackground, 1}}, + {707, {wxDC, setBackgroundMode, 1}}, + {708, {wxDC, setBrush, 1}}, + {710, {wxDC, setClippingRegion_2, 2}}, + {711, {wxDC, setClippingRegion_1_1, 1}}, + {712, {wxDC, setClippingRegion_1_0, 1}}, + {713, {wxDC, setDeviceOrigin, 2}}, + {714, {wxDC, setFont, 1}}, + {715, {wxDC, setLayoutDirection, 1}}, + {716, {wxDC, setLogicalFunction, 1}}, + {717, {wxDC, setMapMode, 1}}, + {718, {wxDC, setPalette, 1}}, + {719, {wxDC, setPen, 1}}, + {720, {wxDC, setTextBackground, 1}}, + {721, {wxDC, setTextForeground, 1}}, + {722, {wxDC, setUserScale, 2}}, + {723, {wxDC, startDoc, 1}}, + {724, {wxDC, startPage, 0}}, + {725, {wxMirrorDC, new, 2}}, + {726, {wxMirrorDC, 'Destroy', undefined}}, + {727, {wxScreenDC, new, 0}}, + {728, {wxScreenDC, destruct, 0}}, + {729, {wxPostScriptDC, new_0, 0}}, + {730, {wxPostScriptDC, new_1, 1}}, + {731, {wxPostScriptDC, destruct, 0}}, + {732, {wxPostScriptDC, setResolution, 1}}, + {733, {wxPostScriptDC, getResolution, 0}}, + {734, {wxWindowDC, new_0, 0}}, + {735, {wxWindowDC, new_1, 1}}, + {736, {wxWindowDC, destruct, 0}}, + {737, {wxClientDC, new_0, 0}}, + {738, {wxClientDC, new_1, 1}}, + {739, {wxClientDC, 'Destroy', undefined}}, + {740, {wxPaintDC, new_0, 0}}, + {741, {wxPaintDC, new_1, 1}}, + {742, {wxPaintDC, 'Destroy', undefined}}, + {744, {wxMemoryDC, new_1_0, 1}}, + {745, {wxMemoryDC, new_1_1, 1}}, + {746, {wxMemoryDC, new_0, 0}}, + {748, {wxMemoryDC, destruct, 0}}, + {749, {wxMemoryDC, selectObject, 1}}, + {750, {wxMemoryDC, selectObjectAsSource, 1}}, + {751, {wxBufferedDC, new_0, 0}}, + {752, {wxBufferedDC, new_2, 2}}, + {753, {wxBufferedDC, new_3, 3}}, + {754, {wxBufferedDC, destruct, 0}}, + {755, {wxBufferedDC, init_2, 2}}, + {756, {wxBufferedDC, init_3, 3}}, + {757, {wxBufferedPaintDC, new_3, 3}}, + {758, {wxBufferedPaintDC, new_2, 2}}, + {759, {wxBufferedPaintDC, destruct, 0}}, + {760, {wxGraphicsObject, destruct, 0}}, + {761, {wxGraphicsObject, getRenderer, 0}}, + {762, {wxGraphicsObject, isNull, 0}}, + {763, {wxGraphicsContext, destruct, 0}}, + {764, {wxGraphicsContext, create_1_1, 1}}, + {765, {wxGraphicsContext, create_1_0, 1}}, + {766, {wxGraphicsContext, create_0, 0}}, + {767, {wxGraphicsContext, createPen, 1}}, + {768, {wxGraphicsContext, createBrush, 1}}, + {769, {wxGraphicsContext, createRadialGradientBrush, 7}}, + {770, {wxGraphicsContext, createLinearGradientBrush, 6}}, + {771, {wxGraphicsContext, createFont, 2}}, + {772, {wxGraphicsContext, createMatrix, 1}}, + {773, {wxGraphicsContext, createPath, 0}}, + {774, {wxGraphicsContext, clip_1, 1}}, + {775, {wxGraphicsContext, clip_4, 4}}, + {776, {wxGraphicsContext, resetClip, 0}}, + {777, {wxGraphicsContext, drawBitmap, 5}}, + {778, {wxGraphicsContext, drawEllipse, 4}}, + {779, {wxGraphicsContext, drawIcon, 5}}, + {780, {wxGraphicsContext, drawLines, 3}}, + {781, {wxGraphicsContext, drawPath, 2}}, + {782, {wxGraphicsContext, drawRectangle, 4}}, + {783, {wxGraphicsContext, drawRoundedRectangle, 5}}, + {784, {wxGraphicsContext, drawText_3, 3}}, + {785, {wxGraphicsContext, drawText_4_0, 4}}, + {786, {wxGraphicsContext, drawText_4_1, 4}}, + {787, {wxGraphicsContext, drawText_5, 5}}, + {788, {wxGraphicsContext, fillPath, 2}}, + {789, {wxGraphicsContext, strokePath, 1}}, + {790, {wxGraphicsContext, getPartialTextExtents, 2}}, + {791, {wxGraphicsContext, getTextExtent, 5}}, + {792, {wxGraphicsContext, rotate, 1}}, + {793, {wxGraphicsContext, scale, 2}}, + {794, {wxGraphicsContext, translate, 2}}, + {795, {wxGraphicsContext, getTransform, 0}}, + {796, {wxGraphicsContext, setTransform, 1}}, + {797, {wxGraphicsContext, concatTransform, 1}}, + {798, {wxGraphicsContext, setBrush_1_1, 1}}, + {799, {wxGraphicsContext, setBrush_1_0, 1}}, + {800, {wxGraphicsContext, setFont_1, 1}}, + {801, {wxGraphicsContext, setFont_2, 2}}, + {802, {wxGraphicsContext, setPen_1_0, 1}}, + {803, {wxGraphicsContext, setPen_1_1, 1}}, + {804, {wxGraphicsContext, strokeLine, 4}}, + {805, {wxGraphicsContext, strokeLines, 2}}, + {807, {wxGraphicsMatrix, concat, 1}}, + {809, {wxGraphicsMatrix, get, 1}}, + {810, {wxGraphicsMatrix, invert, 0}}, + {811, {wxGraphicsMatrix, isEqual, 1}}, + {813, {wxGraphicsMatrix, isIdentity, 0}}, + {814, {wxGraphicsMatrix, rotate, 1}}, + {815, {wxGraphicsMatrix, scale, 2}}, + {816, {wxGraphicsMatrix, translate, 2}}, + {817, {wxGraphicsMatrix, set, 1}}, + {818, {wxGraphicsMatrix, transformPoint, 2}}, + {819, {wxGraphicsMatrix, transformDistance, 2}}, + {820, {wxGraphicsPath, moveToPoint_2, 2}}, + {821, {wxGraphicsPath, moveToPoint_1, 1}}, + {822, {wxGraphicsPath, addArc_6, 6}}, + {823, {wxGraphicsPath, addArc_5, 5}}, + {824, {wxGraphicsPath, addArcToPoint, 5}}, + {825, {wxGraphicsPath, addCircle, 3}}, + {826, {wxGraphicsPath, addCurveToPoint_6, 6}}, + {827, {wxGraphicsPath, addCurveToPoint_3, 3}}, + {828, {wxGraphicsPath, addEllipse, 4}}, + {829, {wxGraphicsPath, addLineToPoint_2, 2}}, + {830, {wxGraphicsPath, addLineToPoint_1, 1}}, + {831, {wxGraphicsPath, addPath, 1}}, + {832, {wxGraphicsPath, addQuadCurveToPoint, 4}}, + {833, {wxGraphicsPath, addRectangle, 4}}, + {834, {wxGraphicsPath, addRoundedRectangle, 5}}, + {835, {wxGraphicsPath, closeSubpath, 0}}, + {836, {wxGraphicsPath, contains_3, 3}}, + {837, {wxGraphicsPath, contains_2, 2}}, + {839, {wxGraphicsPath, getBox, 0}}, + {841, {wxGraphicsPath, getCurrentPoint, 0}}, + {842, {wxGraphicsPath, transform, 1}}, + {843, {wxGraphicsRenderer, getDefaultRenderer, 0}}, + {844, {wxGraphicsRenderer, createContext_1_1, 1}}, + {845, {wxGraphicsRenderer, createContext_1_0, 1}}, + {846, {wxGraphicsRenderer, createPen, 1}}, + {847, {wxGraphicsRenderer, createBrush, 1}}, + {848, {wxGraphicsRenderer, createLinearGradientBrush, 6}}, + {849, {wxGraphicsRenderer, createRadialGradientBrush, 7}}, + {850, {wxGraphicsRenderer, createFont, 2}}, + {851, {wxGraphicsRenderer, createMatrix, 1}}, + {852, {wxGraphicsRenderer, createPath, 0}}, + {854, {wxMenuBar, new_1, 1}}, + {856, {wxMenuBar, new_0, 0}}, + {858, {wxMenuBar, destruct, 0}}, + {859, {wxMenuBar, append, 2}}, + {860, {wxMenuBar, check, 2}}, + {861, {wxMenuBar, enable_2, 2}}, + {862, {wxMenuBar, enable_1, 1}}, + {863, {wxMenuBar, enableTop, 2}}, + {864, {wxMenuBar, findMenu, 1}}, + {865, {wxMenuBar, findMenuItem, 2}}, + {866, {wxMenuBar, findItem, 2}}, + {867, {wxMenuBar, getHelpString, 1}}, + {868, {wxMenuBar, getLabel_1, 1}}, + {869, {wxMenuBar, getLabel_0, 0}}, + {870, {wxMenuBar, getLabelTop, 1}}, + {871, {wxMenuBar, getMenu, 1}}, + {872, {wxMenuBar, getMenuCount, 0}}, + {873, {wxMenuBar, insert, 3}}, + {874, {wxMenuBar, isChecked, 1}}, + {875, {wxMenuBar, isEnabled_1, 1}}, + {876, {wxMenuBar, isEnabled_0, 0}}, + {877, {wxMenuBar, remove, 1}}, + {878, {wxMenuBar, replace, 3}}, + {879, {wxMenuBar, setHelpString, 2}}, + {880, {wxMenuBar, setLabel_2, 2}}, + {881, {wxMenuBar, setLabel_1, 1}}, + {882, {wxMenuBar, setLabelTop, 2}}, + {883, {wxControl, getLabel, 0}}, + {884, {wxControl, setLabel, 1}}, + {885, {wxControlWithItems, append_1, 1}}, + {886, {wxControlWithItems, append_2, 2}}, + {887, {wxControlWithItems, appendStrings_1, 1}}, + {888, {wxControlWithItems, clear, 0}}, + {889, {wxControlWithItems, delete, 1}}, + {890, {wxControlWithItems, findString, 2}}, + {891, {wxControlWithItems, getClientData, 1}}, + {892, {wxControlWithItems, setClientData, 2}}, + {893, {wxControlWithItems, getCount, 0}}, + {894, {wxControlWithItems, getSelection, 0}}, + {895, {wxControlWithItems, getString, 1}}, + {896, {wxControlWithItems, getStringSelection, 0}}, + {897, {wxControlWithItems, insert_2, 2}}, + {898, {wxControlWithItems, insert_3, 3}}, + {899, {wxControlWithItems, isEmpty, 0}}, + {900, {wxControlWithItems, select, 1}}, + {901, {wxControlWithItems, setSelection, 1}}, + {902, {wxControlWithItems, setString, 2}}, + {903, {wxControlWithItems, setStringSelection, 1}}, + {906, {wxMenu, new_2, 2}}, + {907, {wxMenu, new_1, 1}}, + {909, {wxMenu, destruct, 0}}, + {910, {wxMenu, append_3, 3}}, + {911, {wxMenu, append_1, 1}}, + {912, {wxMenu, append_4_0, 4}}, + {913, {wxMenu, append_4_1, 4}}, + {914, {wxMenu, appendCheckItem, 3}}, + {915, {wxMenu, appendRadioItem, 3}}, + {916, {wxMenu, appendSeparator, 0}}, + {917, {wxMenu, break, 0}}, + {918, {wxMenu, check, 2}}, + {919, {wxMenu, delete_1_0, 1}}, + {920, {wxMenu, delete_1_1, 1}}, + {921, {wxMenu, destroy_1_0, 1}}, + {922, {wxMenu, destroy_1_1, 1}}, + {923, {wxMenu, enable, 2}}, + {924, {wxMenu, findItem_1, 1}}, + {925, {wxMenu, findItem_2, 2}}, + {926, {wxMenu, findItemByPosition, 1}}, + {927, {wxMenu, getHelpString, 1}}, + {928, {wxMenu, getLabel, 1}}, + {929, {wxMenu, getMenuItemCount, 0}}, + {930, {wxMenu, getMenuItems, 0}}, + {932, {wxMenu, getTitle, 0}}, + {933, {wxMenu, insert_2, 2}}, + {934, {wxMenu, insert_3, 3}}, + {935, {wxMenu, insert_5_1, 5}}, + {936, {wxMenu, insert_5_0, 5}}, + {937, {wxMenu, insertCheckItem, 4}}, + {938, {wxMenu, insertRadioItem, 4}}, + {939, {wxMenu, insertSeparator, 1}}, + {940, {wxMenu, isChecked, 1}}, + {941, {wxMenu, isEnabled, 1}}, + {942, {wxMenu, prepend_1, 1}}, + {943, {wxMenu, prepend_2, 2}}, + {944, {wxMenu, prepend_4_1, 4}}, + {945, {wxMenu, prepend_4_0, 4}}, + {946, {wxMenu, prependCheckItem, 3}}, + {947, {wxMenu, prependRadioItem, 3}}, + {948, {wxMenu, prependSeparator, 0}}, + {949, {wxMenu, remove_1_0, 1}}, + {950, {wxMenu, remove_1_1, 1}}, + {951, {wxMenu, setHelpString, 2}}, + {952, {wxMenu, setLabel, 2}}, + {953, {wxMenu, setTitle, 1}}, + {954, {wxMenuItem, new, 1}}, + {956, {wxMenuItem, destruct, 0}}, + {957, {wxMenuItem, check, 1}}, + {958, {wxMenuItem, enable, 1}}, + {959, {wxMenuItem, getBitmap, 0}}, + {960, {wxMenuItem, getHelp, 0}}, + {961, {wxMenuItem, getId, 0}}, + {962, {wxMenuItem, getKind, 0}}, + {963, {wxMenuItem, getLabel, 0}}, + {964, {wxMenuItem, getLabelFromText, 1}}, + {965, {wxMenuItem, getMenu, 0}}, + {966, {wxMenuItem, getText, 0}}, + {967, {wxMenuItem, getSubMenu, 0}}, + {968, {wxMenuItem, isCheckable, 0}}, + {969, {wxMenuItem, isChecked, 0}}, + {970, {wxMenuItem, isEnabled, 0}}, + {971, {wxMenuItem, isSeparator, 0}}, + {972, {wxMenuItem, isSubMenu, 0}}, + {973, {wxMenuItem, setBitmap, 1}}, + {974, {wxMenuItem, setHelp, 1}}, + {975, {wxMenuItem, setMenu, 1}}, + {976, {wxMenuItem, setSubMenu, 1}}, + {977, {wxMenuItem, setText, 1}}, + {978, {wxToolBar, addControl, 1}}, + {979, {wxToolBar, addSeparator, 0}}, + {980, {wxToolBar, addTool_5, 5}}, + {981, {wxToolBar, addTool_4_0, 4}}, + {982, {wxToolBar, addTool_1, 1}}, + {983, {wxToolBar, addTool_4_1, 4}}, + {984, {wxToolBar, addTool_3, 3}}, + {985, {wxToolBar, addTool_6, 6}}, + {986, {wxToolBar, addCheckTool, 4}}, + {987, {wxToolBar, addRadioTool, 4}}, + {988, {wxToolBar, addStretchableSpace, 0}}, + {989, {wxToolBar, insertStretchableSpace, 1}}, + {990, {wxToolBar, deleteTool, 1}}, + {991, {wxToolBar, deleteToolByPos, 1}}, + {992, {wxToolBar, enableTool, 2}}, + {993, {wxToolBar, findById, 1}}, + {994, {wxToolBar, findControl, 1}}, + {995, {wxToolBar, findToolForPosition, 2}}, + {996, {wxToolBar, getToolSize, 0}}, + {997, {wxToolBar, getToolBitmapSize, 0}}, + {998, {wxToolBar, getMargins, 0}}, + {999, {wxToolBar, getToolEnabled, 1}}, + {1000, {wxToolBar, getToolLongHelp, 1}}, + {1001, {wxToolBar, getToolPacking, 0}}, + {1002, {wxToolBar, getToolPos, 1}}, + {1003, {wxToolBar, getToolSeparation, 0}}, + {1004, {wxToolBar, getToolShortHelp, 1}}, + {1005, {wxToolBar, getToolState, 1}}, + {1006, {wxToolBar, insertControl, 2}}, + {1007, {wxToolBar, insertSeparator, 1}}, + {1008, {wxToolBar, insertTool_5, 5}}, + {1009, {wxToolBar, insertTool_2, 2}}, + {1010, {wxToolBar, insertTool_4, 4}}, + {1011, {wxToolBar, realize, 0}}, + {1012, {wxToolBar, removeTool, 1}}, + {1013, {wxToolBar, setMargins, 2}}, + {1014, {wxToolBar, setToolBitmapSize, 1}}, + {1015, {wxToolBar, setToolLongHelp, 2}}, + {1016, {wxToolBar, setToolPacking, 1}}, + {1017, {wxToolBar, setToolShortHelp, 2}}, + {1018, {wxToolBar, setToolSeparation, 1}}, + {1019, {wxToolBar, toggleTool, 2}}, + {1021, {wxStatusBar, new_0, 0}}, + {1022, {wxStatusBar, new_2, 2}}, + {1024, {wxStatusBar, destruct, 0}}, + {1025, {wxStatusBar, create, 2}}, + {1026, {wxStatusBar, getFieldRect, 2}}, + {1027, {wxStatusBar, getFieldsCount, 0}}, + {1028, {wxStatusBar, getStatusText, 1}}, + {1029, {wxStatusBar, popStatusText, 1}}, + {1030, {wxStatusBar, pushStatusText, 2}}, + {1031, {wxStatusBar, setFieldsCount, 2}}, + {1032, {wxStatusBar, setMinHeight, 1}}, + {1033, {wxStatusBar, setStatusText, 2}}, + {1034, {wxStatusBar, setStatusWidths, 2}}, + {1035, {wxStatusBar, setStatusStyles, 2}}, + {1036, {wxBitmap, new_0, 0}}, + {1037, {wxBitmap, new_3, 3}}, + {1038, {wxBitmap, new_4, 4}}, + {1039, {wxBitmap, new_2_0, 2}}, + {1040, {wxBitmap, new_2_1, 2}}, + {1041, {wxBitmap, destruct, 0}}, + {1042, {wxBitmap, convertToImage, 0}}, + {1043, {wxBitmap, copyFromIcon, 1}}, + {1044, {wxBitmap, create, 3}}, + {1045, {wxBitmap, getDepth, 0}}, + {1046, {wxBitmap, getHeight, 0}}, + {1047, {wxBitmap, getPalette, 0}}, + {1048, {wxBitmap, getMask, 0}}, + {1049, {wxBitmap, getWidth, 0}}, + {1050, {wxBitmap, getSubBitmap, 1}}, + {1051, {wxBitmap, loadFile, 2}}, + {1052, {wxBitmap, ok, 0}}, + {1053, {wxBitmap, saveFile, 3}}, + {1054, {wxBitmap, setDepth, 1}}, + {1055, {wxBitmap, setHeight, 1}}, + {1056, {wxBitmap, setMask, 1}}, + {1057, {wxBitmap, setPalette, 1}}, + {1058, {wxBitmap, setWidth, 1}}, + {1059, {wxIcon, new_0, 0}}, + {1060, {wxIcon, new_2, 2}}, + {1061, {wxIcon, new_1, 1}}, + {1062, {wxIcon, copyFromBitmap, 1}}, + {1063, {wxIcon, 'Destroy', undefined}}, + {1064, {wxIconBundle, new_0, 0}}, + {1065, {wxIconBundle, new_2, 2}}, + {1066, {wxIconBundle, new_1_0, 1}}, + {1067, {wxIconBundle, new_1_1, 1}}, + {1068, {wxIconBundle, destruct, 0}}, + {1069, {wxIconBundle, addIcon_2, 2}}, + {1070, {wxIconBundle, addIcon_1, 1}}, + {1071, {wxIconBundle, getIcon_1_1, 1}}, + {1072, {wxIconBundle, getIcon_1_0, 1}}, + {1073, {wxCursor, new_0, 0}}, + {1074, {wxCursor, new_1_0, 1}}, + {1075, {wxCursor, new_1_1, 1}}, + {1076, {wxCursor, new_4, 4}}, + {1077, {wxCursor, destruct, 0}}, + {1078, {wxCursor, ok, 0}}, + {1079, {wxMask, new_0, 0}}, + {1080, {wxMask, new_2_1, 2}}, + {1081, {wxMask, new_2_0, 2}}, + {1082, {wxMask, new_1, 1}}, + {1083, {wxMask, destruct, 0}}, + {1084, {wxMask, create_2_1, 2}}, + {1085, {wxMask, create_2_0, 2}}, + {1086, {wxMask, create_1, 1}}, + {1087, {wxImage, new_0, 0}}, + {1088, {wxImage, new_3_0, 3}}, + {1089, {wxImage, new_4, 4}}, + {1090, {wxImage, new_5, 5}}, + {1091, {wxImage, new_2, 2}}, + {1092, {wxImage, new_3_1, 3}}, + {1093, {wxImage, blur, 1}}, + {1094, {wxImage, blurHorizontal, 1}}, + {1095, {wxImage, blurVertical, 1}}, + {1096, {wxImage, convertAlphaToMask, 1}}, + {1097, {wxImage, convertToGreyscale, 1}}, + {1098, {wxImage, convertToMono, 3}}, + {1099, {wxImage, copy, 0}}, + {1100, {wxImage, create_3, 3}}, + {1101, {wxImage, create_4, 4}}, + {1102, {wxImage, create_5, 5}}, + {1103, {wxImage, 'Destroy', 0}}, + {1104, {wxImage, findFirstUnusedColour, 4}}, + {1105, {wxImage, getImageExtWildcard, 0}}, + {1106, {wxImage, getAlpha_2, 2}}, + {1107, {wxImage, getAlpha_0, 0}}, + {1108, {wxImage, getBlue, 2}}, + {1109, {wxImage, getData, 0}}, + {1110, {wxImage, getGreen, 2}}, + {1111, {wxImage, getImageCount, 2}}, + {1112, {wxImage, getHeight, 0}}, + {1113, {wxImage, getMaskBlue, 0}}, + {1114, {wxImage, getMaskGreen, 0}}, + {1115, {wxImage, getMaskRed, 0}}, + {1116, {wxImage, getOrFindMaskColour, 3}}, + {1117, {wxImage, getPalette, 0}}, + {1118, {wxImage, getRed, 2}}, + {1119, {wxImage, getSubImage, 1}}, + {1120, {wxImage, getWidth, 0}}, + {1121, {wxImage, hasAlpha, 0}}, + {1122, {wxImage, hasMask, 0}}, + {1123, {wxImage, getOption, 1}}, + {1124, {wxImage, getOptionInt, 1}}, + {1125, {wxImage, hasOption, 1}}, + {1126, {wxImage, initAlpha, 0}}, + {1127, {wxImage, initStandardHandlers, 0}}, + {1128, {wxImage, isTransparent, 3}}, + {1129, {wxImage, loadFile_2, 2}}, + {1130, {wxImage, loadFile_3, 3}}, + {1131, {wxImage, ok, 0}}, + {1132, {wxImage, removeHandler, 1}}, + {1133, {wxImage, mirror, 1}}, + {1134, {wxImage, replace, 6}}, + {1135, {wxImage, rescale, 3}}, + {1136, {wxImage, resize, 3}}, + {1137, {wxImage, rotate, 3}}, + {1138, {wxImage, rotateHue, 1}}, + {1139, {wxImage, rotate90, 1}}, + {1140, {wxImage, saveFile_1, 1}}, + {1141, {wxImage, saveFile_2_0, 2}}, + {1142, {wxImage, saveFile_2_1, 2}}, + {1143, {wxImage, scale, 3}}, + {1144, {wxImage, size, 3}}, + {1145, {wxImage, setAlpha_3, 3}}, + {1146, {wxImage, setAlpha_2, 2}}, + {1147, {wxImage, setData_2, 2}}, + {1148, {wxImage, setData_4, 4}}, + {1149, {wxImage, setMask, 1}}, + {1150, {wxImage, setMaskColour, 3}}, + {1151, {wxImage, setMaskFromImage, 4}}, + {1152, {wxImage, setOption_2_1, 2}}, + {1153, {wxImage, setOption_2_0, 2}}, + {1154, {wxImage, setPalette, 1}}, + {1155, {wxImage, setRGB_5, 5}}, + {1156, {wxImage, setRGB_4, 4}}, + {1157, {wxImage, 'Destroy', undefined}}, + {1158, {wxBrush, new_0, 0}}, + {1159, {wxBrush, new_2, 2}}, + {1160, {wxBrush, new_1, 1}}, + {1162, {wxBrush, destruct, 0}}, + {1163, {wxBrush, getColour, 0}}, + {1164, {wxBrush, getStipple, 0}}, + {1165, {wxBrush, getStyle, 0}}, + {1166, {wxBrush, isHatch, 0}}, + {1167, {wxBrush, isOk, 0}}, + {1168, {wxBrush, setColour_1, 1}}, + {1169, {wxBrush, setColour_3, 3}}, + {1170, {wxBrush, setStipple, 1}}, + {1171, {wxBrush, setStyle, 1}}, + {1172, {wxPen, new_0, 0}}, + {1173, {wxPen, new_2, 2}}, + {1174, {wxPen, destruct, 0}}, + {1175, {wxPen, getCap, 0}}, + {1176, {wxPen, getColour, 0}}, + {1177, {wxPen, getJoin, 0}}, + {1178, {wxPen, getStyle, 0}}, + {1179, {wxPen, getWidth, 0}}, + {1180, {wxPen, isOk, 0}}, + {1181, {wxPen, setCap, 1}}, + {1182, {wxPen, setColour_1, 1}}, + {1183, {wxPen, setColour_3, 3}}, + {1184, {wxPen, setJoin, 1}}, + {1185, {wxPen, setStyle, 1}}, + {1186, {wxPen, setWidth, 1}}, + {1187, {wxRegion, new_0, 0}}, + {1188, {wxRegion, new_4, 4}}, + {1189, {wxRegion, new_2, 2}}, + {1190, {wxRegion, new_1_1, 1}}, + {1192, {wxRegion, new_1_0, 1}}, + {1194, {wxRegion, destruct, 0}}, + {1195, {wxRegion, clear, 0}}, + {1196, {wxRegion, contains_2, 2}}, + {1197, {wxRegion, contains_1_0, 1}}, + {1198, {wxRegion, contains_4, 4}}, + {1199, {wxRegion, contains_1_1, 1}}, + {1200, {wxRegion, convertToBitmap, 0}}, + {1201, {wxRegion, getBox, 0}}, + {1202, {wxRegion, intersect_4, 4}}, + {1203, {wxRegion, intersect_1_1, 1}}, + {1204, {wxRegion, intersect_1_0, 1}}, + {1205, {wxRegion, isEmpty, 0}}, + {1206, {wxRegion, subtract_4, 4}}, + {1207, {wxRegion, subtract_1_1, 1}}, + {1208, {wxRegion, subtract_1_0, 1}}, + {1209, {wxRegion, offset_2, 2}}, + {1210, {wxRegion, offset_1, 1}}, + {1211, {wxRegion, union_4, 4}}, + {1212, {wxRegion, union_1_2, 1}}, + {1213, {wxRegion, union_1_1, 1}}, + {1214, {wxRegion, union_1_0, 1}}, + {1215, {wxRegion, union_3, 3}}, + {1216, {wxRegion, xor_4, 4}}, + {1217, {wxRegion, xor_1_1, 1}}, + {1218, {wxRegion, xor_1_0, 1}}, + {1219, {wxAcceleratorTable, new_0, 0}}, + {1220, {wxAcceleratorTable, new_2, 2}}, + {1221, {wxAcceleratorTable, destruct, 0}}, + {1222, {wxAcceleratorTable, ok, 0}}, + {1223, {wxAcceleratorEntry, new_1_0, 1}}, + {1224, {wxAcceleratorEntry, new_1_1, 1}}, + {1225, {wxAcceleratorEntry, getCommand, 0}}, + {1226, {wxAcceleratorEntry, getFlags, 0}}, + {1227, {wxAcceleratorEntry, getKeyCode, 0}}, + {1228, {wxAcceleratorEntry, set, 4}}, + {1229, {wxAcceleratorEntry, 'Destroy', undefined}}, + {1234, {wxCaret, new_3, 3}}, + {1235, {wxCaret, new_2, 2}}, + {1237, {wxCaret, destruct, 0}}, + {1238, {wxCaret, create_3, 3}}, + {1239, {wxCaret, create_2, 2}}, + {1240, {wxCaret, getBlinkTime, 0}}, + {1242, {wxCaret, getPosition, 0}}, + {1244, {wxCaret, getSize, 0}}, + {1245, {wxCaret, getWindow, 0}}, + {1246, {wxCaret, hide, 0}}, + {1247, {wxCaret, isOk, 0}}, + {1248, {wxCaret, isVisible, 0}}, + {1249, {wxCaret, move_2, 2}}, + {1250, {wxCaret, move_1, 1}}, + {1251, {wxCaret, setBlinkTime, 1}}, + {1252, {wxCaret, setSize_2, 2}}, + {1253, {wxCaret, setSize_1, 1}}, + {1254, {wxCaret, show, 1}}, + {1255, {wxSizer, add_2_1, 2}}, + {1256, {wxSizer, add_2_0, 2}}, + {1257, {wxSizer, add_3, 3}}, + {1258, {wxSizer, add_2_3, 2}}, + {1259, {wxSizer, add_2_2, 2}}, + {1260, {wxSizer, addSpacer, 1}}, + {1261, {wxSizer, addStretchSpacer, 1}}, + {1262, {wxSizer, calcMin, 0}}, + {1263, {wxSizer, clear, 1}}, + {1264, {wxSizer, detach_1_2, 1}}, + {1265, {wxSizer, detach_1_1, 1}}, + {1266, {wxSizer, detach_1_0, 1}}, + {1267, {wxSizer, fit, 1}}, + {1268, {wxSizer, fitInside, 1}}, + {1269, {wxSizer, getChildren, 0}}, + {1270, {wxSizer, getItem_2_1, 2}}, + {1271, {wxSizer, getItem_2_0, 2}}, + {1272, {wxSizer, getItem_1, 1}}, + {1273, {wxSizer, getSize, 0}}, + {1274, {wxSizer, getPosition, 0}}, + {1275, {wxSizer, getMinSize, 0}}, + {1276, {wxSizer, hide_2_0, 2}}, + {1277, {wxSizer, hide_2_1, 2}}, + {1278, {wxSizer, hide_1, 1}}, + {1279, {wxSizer, insert_3_1, 3}}, + {1280, {wxSizer, insert_3_0, 3}}, + {1281, {wxSizer, insert_4, 4}}, + {1282, {wxSizer, insert_3_3, 3}}, + {1283, {wxSizer, insert_3_2, 3}}, + {1284, {wxSizer, insert_2, 2}}, + {1285, {wxSizer, insertSpacer, 2}}, + {1286, {wxSizer, insertStretchSpacer, 2}}, + {1287, {wxSizer, isShown_1_2, 1}}, + {1288, {wxSizer, isShown_1_1, 1}}, + {1289, {wxSizer, isShown_1_0, 1}}, + {1290, {wxSizer, layout, 0}}, + {1291, {wxSizer, prepend_2_1, 2}}, + {1292, {wxSizer, prepend_2_0, 2}}, + {1293, {wxSizer, prepend_3, 3}}, + {1294, {wxSizer, prepend_2_3, 2}}, + {1295, {wxSizer, prepend_2_2, 2}}, + {1296, {wxSizer, prepend_1, 1}}, + {1297, {wxSizer, prependSpacer, 1}}, + {1298, {wxSizer, prependStretchSpacer, 1}}, + {1299, {wxSizer, recalcSizes, 0}}, + {1300, {wxSizer, remove_1_1, 1}}, + {1301, {wxSizer, remove_1_0, 1}}, + {1302, {wxSizer, replace_3_1, 3}}, + {1303, {wxSizer, replace_3_0, 3}}, + {1304, {wxSizer, replace_2, 2}}, + {1305, {wxSizer, setDimension, 4}}, + {1306, {wxSizer, setMinSize_2, 2}}, + {1307, {wxSizer, setMinSize_1, 1}}, + {1308, {wxSizer, setItemMinSize_3_2, 3}}, + {1309, {wxSizer, setItemMinSize_2_2, 2}}, + {1310, {wxSizer, setItemMinSize_3_1, 3}}, + {1311, {wxSizer, setItemMinSize_2_1, 2}}, + {1312, {wxSizer, setItemMinSize_3_0, 3}}, + {1313, {wxSizer, setItemMinSize_2_0, 2}}, + {1314, {wxSizer, setSizeHints, 1}}, + {1315, {wxSizer, setVirtualSizeHints, 1}}, + {1316, {wxSizer, show_2_2, 2}}, + {1317, {wxSizer, show_2_1, 2}}, + {1318, {wxSizer, show_2_0, 2}}, + {1319, {wxSizer, show_1, 1}}, + {1320, {wxSizerFlags, new, 1}}, + {1321, {wxSizerFlags, align, 1}}, + {1322, {wxSizerFlags, border_2, 2}}, + {1323, {wxSizerFlags, border_1, 1}}, + {1324, {wxSizerFlags, center, 0}}, + {1325, {wxSizerFlags, centre, 0}}, + {1326, {wxSizerFlags, expand, 0}}, + {1327, {wxSizerFlags, left, 0}}, + {1328, {wxSizerFlags, proportion, 1}}, + {1329, {wxSizerFlags, right, 0}}, + {1330, {wxSizerFlags, 'Destroy', undefined}}, + {1331, {wxSizerItem, new_5_1, 5}}, + {1332, {wxSizerItem, new_2_1, 2}}, + {1333, {wxSizerItem, new_5_0, 5}}, + {1334, {wxSizerItem, new_2_0, 2}}, + {1335, {wxSizerItem, new_6, 6}}, + {1336, {wxSizerItem, new_3, 3}}, + {1337, {wxSizerItem, new_0, 0}}, + {1338, {wxSizerItem, destruct, 0}}, + {1339, {wxSizerItem, calcMin, 0}}, + {1340, {wxSizerItem, deleteWindows, 0}}, + {1341, {wxSizerItem, detachSizer, 0}}, + {1342, {wxSizerItem, getBorder, 0}}, + {1343, {wxSizerItem, getFlag, 0}}, + {1344, {wxSizerItem, getMinSize, 0}}, + {1345, {wxSizerItem, getPosition, 0}}, + {1346, {wxSizerItem, getProportion, 0}}, + {1347, {wxSizerItem, getRatio, 0}}, + {1348, {wxSizerItem, getRect, 0}}, + {1349, {wxSizerItem, getSize, 0}}, + {1350, {wxSizerItem, getSizer, 0}}, + {1351, {wxSizerItem, getSpacer, 0}}, + {1352, {wxSizerItem, getUserData, 0}}, + {1353, {wxSizerItem, getWindow, 0}}, + {1354, {wxSizerItem, isSizer, 0}}, + {1355, {wxSizerItem, isShown, 0}}, + {1356, {wxSizerItem, isSpacer, 0}}, + {1357, {wxSizerItem, isWindow, 0}}, + {1358, {wxSizerItem, setBorder, 1}}, + {1359, {wxSizerItem, setDimension, 2}}, + {1360, {wxSizerItem, setFlag, 1}}, + {1361, {wxSizerItem, setInitSize, 2}}, + {1362, {wxSizerItem, setMinSize_1, 1}}, + {1363, {wxSizerItem, setMinSize_2, 2}}, + {1364, {wxSizerItem, setProportion, 1}}, + {1365, {wxSizerItem, setRatio_2, 2}}, + {1366, {wxSizerItem, setRatio_1_1, 1}}, + {1367, {wxSizerItem, setRatio_1_0, 1}}, + {1368, {wxSizerItem, setSizer, 1}}, + {1369, {wxSizerItem, setSpacer_1, 1}}, + {1370, {wxSizerItem, setSpacer_2, 2}}, + {1371, {wxSizerItem, setWindow, 1}}, + {1372, {wxSizerItem, show, 1}}, + {1373, {wxBoxSizer, new, 1}}, + {1374, {wxBoxSizer, getOrientation, 0}}, + {1375, {wxBoxSizer, 'Destroy', undefined}}, + {1376, {wxStaticBoxSizer, new_2, 2}}, + {1377, {wxStaticBoxSizer, new_3, 3}}, + {1378, {wxStaticBoxSizer, getStaticBox, 0}}, + {1379, {wxStaticBoxSizer, 'Destroy', undefined}}, + {1380, {wxGridSizer, new_4, 4}}, + {1381, {wxGridSizer, new_2, 2}}, + {1382, {wxGridSizer, getCols, 0}}, + {1383, {wxGridSizer, getHGap, 0}}, + {1384, {wxGridSizer, getRows, 0}}, + {1385, {wxGridSizer, getVGap, 0}}, + {1386, {wxGridSizer, setCols, 1}}, + {1387, {wxGridSizer, setHGap, 1}}, + {1388, {wxGridSizer, setRows, 1}}, + {1389, {wxGridSizer, setVGap, 1}}, + {1390, {wxGridSizer, 'Destroy', undefined}}, + {1391, {wxFlexGridSizer, new_4, 4}}, + {1392, {wxFlexGridSizer, new_2, 2}}, + {1393, {wxFlexGridSizer, addGrowableCol, 2}}, + {1394, {wxFlexGridSizer, addGrowableRow, 2}}, + {1395, {wxFlexGridSizer, getFlexibleDirection, 0}}, + {1396, {wxFlexGridSizer, getNonFlexibleGrowMode, 0}}, + {1397, {wxFlexGridSizer, removeGrowableCol, 1}}, + {1398, {wxFlexGridSizer, removeGrowableRow, 1}}, + {1399, {wxFlexGridSizer, setFlexibleDirection, 1}}, + {1400, {wxFlexGridSizer, setNonFlexibleGrowMode, 1}}, + {1401, {wxFlexGridSizer, 'Destroy', undefined}}, + {1402, {wxGridBagSizer, new, 1}}, + {1403, {wxGridBagSizer, add_3_2, 3}}, + {1404, {wxGridBagSizer, add_3_1, 3}}, + {1405, {wxGridBagSizer, add_4, 4}}, + {1406, {wxGridBagSizer, add_1_0, 1}}, + {1407, {wxGridBagSizer, add_2_1, 2}}, + {1408, {wxGridBagSizer, add_2_0, 2}}, + {1409, {wxGridBagSizer, add_3_0, 3}}, + {1410, {wxGridBagSizer, add_1_1, 1}}, + {1411, {wxGridBagSizer, calcMin, 0}}, + {1412, {wxGridBagSizer, checkForIntersection_2, 2}}, + {1413, {wxGridBagSizer, checkForIntersection_3, 3}}, + {1414, {wxGridBagSizer, findItem_1_1, 1}}, + {1415, {wxGridBagSizer, findItem_1_0, 1}}, + {1416, {wxGridBagSizer, findItemAtPoint, 1}}, + {1417, {wxGridBagSizer, findItemAtPosition, 1}}, + {1418, {wxGridBagSizer, findItemWithData, 1}}, + {1419, {wxGridBagSizer, getCellSize, 2}}, + {1420, {wxGridBagSizer, getEmptyCellSize, 0}}, + {1421, {wxGridBagSizer, getItemPosition_1_2, 1}}, + {1422, {wxGridBagSizer, getItemPosition_1_1, 1}}, + {1423, {wxGridBagSizer, getItemPosition_1_0, 1}}, + {1424, {wxGridBagSizer, getItemSpan_1_2, 1}}, + {1425, {wxGridBagSizer, getItemSpan_1_1, 1}}, + {1426, {wxGridBagSizer, getItemSpan_1_0, 1}}, + {1427, {wxGridBagSizer, setEmptyCellSize, 1}}, + {1428, {wxGridBagSizer, setItemPosition_2_2, 2}}, + {1429, {wxGridBagSizer, setItemPosition_2_1, 2}}, + {1430, {wxGridBagSizer, setItemPosition_2_0, 2}}, + {1431, {wxGridBagSizer, setItemSpan_2_2, 2}}, + {1432, {wxGridBagSizer, setItemSpan_2_1, 2}}, + {1433, {wxGridBagSizer, setItemSpan_2_0, 2}}, + {1434, {wxGridBagSizer, 'Destroy', undefined}}, + {1435, {wxStdDialogButtonSizer, new, 0}}, + {1436, {wxStdDialogButtonSizer, addButton, 1}}, + {1437, {wxStdDialogButtonSizer, realize, 0}}, + {1438, {wxStdDialogButtonSizer, setAffirmativeButton, 1}}, + {1439, {wxStdDialogButtonSizer, setCancelButton, 1}}, + {1440, {wxStdDialogButtonSizer, setNegativeButton, 1}}, + {1441, {wxStdDialogButtonSizer, 'Destroy', undefined}}, + {1442, {wxFont, new_0, 0}}, + {1443, {wxFont, new_1, 1}}, + {1444, {wxFont, new_5, 5}}, + {1446, {wxFont, destruct, 0}}, + {1447, {wxFont, isFixedWidth, 0}}, + {1448, {wxFont, getDefaultEncoding, 0}}, + {1449, {wxFont, getFaceName, 0}}, + {1450, {wxFont, getFamily, 0}}, + {1451, {wxFont, getNativeFontInfoDesc, 0}}, + {1452, {wxFont, getNativeFontInfoUserDesc, 0}}, + {1453, {wxFont, getPointSize, 0}}, + {1454, {wxFont, getStyle, 0}}, + {1455, {wxFont, getUnderlined, 0}}, + {1456, {wxFont, getWeight, 0}}, + {1457, {wxFont, ok, 0}}, + {1458, {wxFont, setDefaultEncoding, 1}}, + {1459, {wxFont, setFaceName, 1}}, + {1460, {wxFont, setFamily, 1}}, + {1461, {wxFont, setPointSize, 1}}, + {1462, {wxFont, setStyle, 1}}, + {1463, {wxFont, setUnderlined, 1}}, + {1464, {wxFont, setWeight, 1}}, + {1465, {wxToolTip, enable, 1}}, + {1466, {wxToolTip, setDelay, 1}}, + {1467, {wxToolTip, new, 1}}, + {1468, {wxToolTip, setTip, 1}}, + {1469, {wxToolTip, getTip, 0}}, + {1470, {wxToolTip, getWindow, 0}}, + {1471, {wxToolTip, 'Destroy', undefined}}, + {1473, {wxButton, new_3, 3}}, + {1474, {wxButton, new_0, 0}}, + {1475, {wxButton, destruct, 0}}, + {1476, {wxButton, create, 3}}, + {1477, {wxButton, getDefaultSize, 0}}, + {1478, {wxButton, setDefault, 0}}, + {1479, {wxButton, setLabel, 1}}, + {1481, {wxBitmapButton, new_4, 4}}, + {1482, {wxBitmapButton, new_0, 0}}, + {1483, {wxBitmapButton, create, 4}}, + {1484, {wxBitmapButton, getBitmapDisabled, 0}}, + {1486, {wxBitmapButton, getBitmapFocus, 0}}, + {1488, {wxBitmapButton, getBitmapLabel, 0}}, + {1490, {wxBitmapButton, getBitmapSelected, 0}}, + {1492, {wxBitmapButton, setBitmapDisabled, 1}}, + {1493, {wxBitmapButton, setBitmapFocus, 1}}, + {1494, {wxBitmapButton, setBitmapLabel, 1}}, + {1495, {wxBitmapButton, setBitmapSelected, 1}}, + {1496, {wxBitmapButton, 'Destroy', undefined}}, + {1497, {wxToggleButton, new_0, 0}}, + {1498, {wxToggleButton, new_4, 4}}, + {1499, {wxToggleButton, create, 4}}, + {1500, {wxToggleButton, getValue, 0}}, + {1501, {wxToggleButton, setValue, 1}}, + {1502, {wxToggleButton, 'Destroy', undefined}}, + {1503, {wxCalendarCtrl, new_0, 0}}, + {1504, {wxCalendarCtrl, new_3, 3}}, + {1505, {wxCalendarCtrl, create, 3}}, + {1506, {wxCalendarCtrl, destruct, 0}}, + {1507, {wxCalendarCtrl, setDate, 1}}, + {1508, {wxCalendarCtrl, getDate, 0}}, + {1509, {wxCalendarCtrl, enableYearChange, 1}}, + {1510, {wxCalendarCtrl, enableMonthChange, 1}}, + {1511, {wxCalendarCtrl, enableHolidayDisplay, 1}}, + {1512, {wxCalendarCtrl, setHeaderColours, 2}}, + {1513, {wxCalendarCtrl, getHeaderColourFg, 0}}, + {1514, {wxCalendarCtrl, getHeaderColourBg, 0}}, + {1515, {wxCalendarCtrl, setHighlightColours, 2}}, + {1516, {wxCalendarCtrl, getHighlightColourFg, 0}}, + {1517, {wxCalendarCtrl, getHighlightColourBg, 0}}, + {1518, {wxCalendarCtrl, setHolidayColours, 2}}, + {1519, {wxCalendarCtrl, getHolidayColourFg, 0}}, + {1520, {wxCalendarCtrl, getHolidayColourBg, 0}}, + {1521, {wxCalendarCtrl, getAttr, 1}}, + {1522, {wxCalendarCtrl, setAttr, 2}}, + {1523, {wxCalendarCtrl, setHoliday, 1}}, + {1524, {wxCalendarCtrl, resetAttr, 1}}, + {1525, {wxCalendarCtrl, hitTest, 2}}, + {1526, {wxCalendarDateAttr, new_0, 0}}, + {1527, {wxCalendarDateAttr, new_2_1, 2}}, + {1528, {wxCalendarDateAttr, new_2_0, 2}}, + {1529, {wxCalendarDateAttr, setTextColour, 1}}, + {1530, {wxCalendarDateAttr, setBackgroundColour, 1}}, + {1531, {wxCalendarDateAttr, setBorderColour, 1}}, + {1532, {wxCalendarDateAttr, setFont, 1}}, + {1533, {wxCalendarDateAttr, setBorder, 1}}, + {1534, {wxCalendarDateAttr, setHoliday, 1}}, + {1535, {wxCalendarDateAttr, hasTextColour, 0}}, + {1536, {wxCalendarDateAttr, hasBackgroundColour, 0}}, + {1537, {wxCalendarDateAttr, hasBorderColour, 0}}, + {1538, {wxCalendarDateAttr, hasFont, 0}}, + {1539, {wxCalendarDateAttr, hasBorder, 0}}, + {1540, {wxCalendarDateAttr, isHoliday, 0}}, + {1541, {wxCalendarDateAttr, getTextColour, 0}}, + {1542, {wxCalendarDateAttr, getBackgroundColour, 0}}, + {1543, {wxCalendarDateAttr, getBorderColour, 0}}, + {1544, {wxCalendarDateAttr, getFont, 0}}, + {1545, {wxCalendarDateAttr, getBorder, 0}}, + {1546, {wxCalendarDateAttr, 'Destroy', undefined}}, + {1548, {wxCheckBox, new_4, 4}}, + {1549, {wxCheckBox, new_0, 0}}, + {1550, {wxCheckBox, create, 4}}, + {1551, {wxCheckBox, getValue, 0}}, + {1552, {wxCheckBox, get3StateValue, 0}}, + {1553, {wxCheckBox, is3rdStateAllowedForUser, 0}}, + {1554, {wxCheckBox, is3State, 0}}, + {1555, {wxCheckBox, isChecked, 0}}, + {1556, {wxCheckBox, setValue, 1}}, + {1557, {wxCheckBox, set3StateValue, 1}}, + {1558, {wxCheckBox, 'Destroy', undefined}}, + {1559, {wxCheckListBox, new_0, 0}}, + {1561, {wxCheckListBox, new_3, 3}}, + {1562, {wxCheckListBox, check, 2}}, + {1563, {wxCheckListBox, isChecked, 1}}, + {1564, {wxCheckListBox, 'Destroy', undefined}}, + {1567, {wxChoice, new_3, 3}}, + {1568, {wxChoice, new_0, 0}}, + {1570, {wxChoice, destruct, 0}}, + {1572, {wxChoice, create, 6}}, + {1573, {wxChoice, delete, 1}}, + {1574, {wxChoice, getColumns, 0}}, + {1575, {wxChoice, setColumns, 1}}, + {1576, {wxComboBox, new_0, 0}}, + {1578, {wxComboBox, new_3, 3}}, + {1579, {wxComboBox, destruct, 0}}, + {1581, {wxComboBox, create, 7}}, + {1582, {wxComboBox, canCopy, 0}}, + {1583, {wxComboBox, canCut, 0}}, + {1584, {wxComboBox, canPaste, 0}}, + {1585, {wxComboBox, canRedo, 0}}, + {1586, {wxComboBox, canUndo, 0}}, + {1587, {wxComboBox, copy, 0}}, + {1588, {wxComboBox, cut, 0}}, + {1589, {wxComboBox, getInsertionPoint, 0}}, + {1590, {wxComboBox, getLastPosition, 0}}, + {1591, {wxComboBox, getValue, 0}}, + {1592, {wxComboBox, paste, 0}}, + {1593, {wxComboBox, redo, 0}}, + {1594, {wxComboBox, replace, 3}}, + {1595, {wxComboBox, remove, 2}}, + {1596, {wxComboBox, setInsertionPoint, 1}}, + {1597, {wxComboBox, setInsertionPointEnd, 0}}, + {1598, {wxComboBox, setSelection_1, 1}}, + {1599, {wxComboBox, setSelection_2, 2}}, + {1600, {wxComboBox, setValue, 1}}, + {1601, {wxComboBox, undo, 0}}, + {1602, {wxGauge, new_0, 0}}, + {1603, {wxGauge, new_4, 4}}, + {1604, {wxGauge, create, 4}}, + {1605, {wxGauge, getBezelFace, 0}}, + {1606, {wxGauge, getRange, 0}}, + {1607, {wxGauge, getShadowWidth, 0}}, + {1608, {wxGauge, getValue, 0}}, + {1609, {wxGauge, isVertical, 0}}, + {1610, {wxGauge, setBezelFace, 1}}, + {1611, {wxGauge, setRange, 1}}, + {1612, {wxGauge, setShadowWidth, 1}}, + {1613, {wxGauge, setValue, 1}}, + {1614, {wxGauge, pulse, 0}}, + {1615, {wxGauge, 'Destroy', undefined}}, + {1616, {wxGenericDirCtrl, new_0, 0}}, + {1617, {wxGenericDirCtrl, new_2, 2}}, + {1618, {wxGenericDirCtrl, destruct, 0}}, + {1619, {wxGenericDirCtrl, create, 2}}, + {1620, {wxGenericDirCtrl, init, 0}}, + {1621, {wxGenericDirCtrl, collapseTree, 0}}, + {1622, {wxGenericDirCtrl, expandPath, 1}}, + {1623, {wxGenericDirCtrl, getDefaultPath, 0}}, + {1624, {wxGenericDirCtrl, getPath, 0}}, + {1625, {wxGenericDirCtrl, getFilePath, 0}}, + {1626, {wxGenericDirCtrl, getFilter, 0}}, + {1627, {wxGenericDirCtrl, getFilterIndex, 0}}, + {1628, {wxGenericDirCtrl, getRootId, 0}}, + {1629, {wxGenericDirCtrl, getTreeCtrl, 0}}, + {1630, {wxGenericDirCtrl, reCreateTree, 0}}, + {1631, {wxGenericDirCtrl, setDefaultPath, 1}}, + {1632, {wxGenericDirCtrl, setFilter, 1}}, + {1633, {wxGenericDirCtrl, setFilterIndex, 1}}, + {1634, {wxGenericDirCtrl, setPath, 1}}, + {1636, {wxStaticBox, new_4, 4}}, + {1637, {wxStaticBox, new_0, 0}}, + {1638, {wxStaticBox, create, 4}}, + {1639, {wxStaticBox, 'Destroy', undefined}}, + {1641, {wxStaticLine, new_2, 2}}, + {1642, {wxStaticLine, new_0, 0}}, + {1643, {wxStaticLine, create, 2}}, + {1644, {wxStaticLine, isVertical, 0}}, + {1645, {wxStaticLine, getDefaultSize, 0}}, + {1646, {wxStaticLine, 'Destroy', undefined}}, + {1649, {wxListBox, new_3, 3}}, + {1650, {wxListBox, new_0, 0}}, + {1652, {wxListBox, destruct, 0}}, + {1654, {wxListBox, create, 6}}, + {1655, {wxListBox, deselect, 1}}, + {1656, {wxListBox, getSelections, 1}}, + {1657, {wxListBox, insertItems, 2}}, + {1658, {wxListBox, isSelected, 1}}, + {1659, {wxListBox, set, 1}}, + {1660, {wxListBox, hitTest, 1}}, + {1661, {wxListBox, setFirstItem_1_0, 1}}, + {1662, {wxListBox, setFirstItem_1_1, 1}}, + {1663, {wxListCtrl, new_0, 0}}, + {1664, {wxListCtrl, new_2, 2}}, + {1665, {wxListCtrl, arrange, 1}}, + {1666, {wxListCtrl, assignImageList, 2}}, + {1667, {wxListCtrl, clearAll, 0}}, + {1668, {wxListCtrl, create, 2}}, + {1669, {wxListCtrl, deleteAllItems, 0}}, + {1670, {wxListCtrl, deleteColumn, 1}}, + {1671, {wxListCtrl, deleteItem, 1}}, + {1672, {wxListCtrl, editLabel, 1}}, + {1673, {wxListCtrl, ensureVisible, 1}}, + {1674, {wxListCtrl, findItem_3_0, 3}}, + {1675, {wxListCtrl, findItem_3_1, 3}}, + {1676, {wxListCtrl, getColumn, 2}}, + {1677, {wxListCtrl, getColumnCount, 0}}, + {1678, {wxListCtrl, getColumnWidth, 1}}, + {1679, {wxListCtrl, getCountPerPage, 0}}, + {1680, {wxListCtrl, getEditControl, 0}}, + {1681, {wxListCtrl, getImageList, 1}}, + {1682, {wxListCtrl, getItem, 1}}, + {1683, {wxListCtrl, getItemBackgroundColour, 1}}, + {1684, {wxListCtrl, getItemCount, 0}}, + {1685, {wxListCtrl, getItemData, 1}}, + {1686, {wxListCtrl, getItemFont, 1}}, + {1687, {wxListCtrl, getItemPosition, 2}}, + {1688, {wxListCtrl, getItemRect, 3}}, + {1689, {wxListCtrl, getItemSpacing, 0}}, + {1690, {wxListCtrl, getItemState, 2}}, + {1691, {wxListCtrl, getItemText, 1}}, + {1692, {wxListCtrl, getItemTextColour, 1}}, + {1693, {wxListCtrl, getNextItem, 2}}, + {1694, {wxListCtrl, getSelectedItemCount, 0}}, + {1695, {wxListCtrl, getTextColour, 0}}, + {1696, {wxListCtrl, getTopItem, 0}}, + {1697, {wxListCtrl, getViewRect, 0}}, + {1698, {wxListCtrl, hitTest, 2}}, + {1699, {wxListCtrl, insertColumn_2, 2}}, + {1700, {wxListCtrl, insertColumn_3, 3}}, + {1701, {wxListCtrl, insertItem_1, 1}}, + {1702, {wxListCtrl, insertItem_2_1, 2}}, + {1703, {wxListCtrl, insertItem_2_0, 2}}, + {1704, {wxListCtrl, insertItem_3, 3}}, + {1705, {wxListCtrl, refreshItem, 1}}, + {1706, {wxListCtrl, refreshItems, 2}}, + {1707, {wxListCtrl, scrollList, 2}}, + {1708, {wxListCtrl, setBackgroundColour, 1}}, + {1709, {wxListCtrl, setColumn, 2}}, + {1710, {wxListCtrl, setColumnWidth, 2}}, + {1711, {wxListCtrl, setImageList, 2}}, + {1712, {wxListCtrl, setItem_1, 1}}, + {1713, {wxListCtrl, setItem_4, 4}}, + {1714, {wxListCtrl, setItemBackgroundColour, 2}}, + {1715, {wxListCtrl, setItemCount, 1}}, + {1716, {wxListCtrl, setItemData, 2}}, + {1717, {wxListCtrl, setItemFont, 2}}, + {1718, {wxListCtrl, setItemImage, 3}}, + {1719, {wxListCtrl, setItemColumnImage, 3}}, + {1720, {wxListCtrl, setItemPosition, 2}}, + {1721, {wxListCtrl, setItemState, 3}}, + {1722, {wxListCtrl, setItemText, 2}}, + {1723, {wxListCtrl, setItemTextColour, 2}}, + {1724, {wxListCtrl, setSingleStyle, 2}}, + {1725, {wxListCtrl, setTextColour, 1}}, + {1726, {wxListCtrl, setWindowStyleFlag, 1}}, + {1727, {wxListCtrl, sortItems, 2}}, + {1728, {wxListCtrl, 'Destroy', undefined}}, + {1729, {wxListView, clearColumnImage, 1}}, + {1730, {wxListView, focus, 1}}, + {1731, {wxListView, getFirstSelected, 0}}, + {1732, {wxListView, getFocusedItem, 0}}, + {1733, {wxListView, getNextSelected, 1}}, + {1734, {wxListView, isSelected, 1}}, + {1735, {wxListView, select, 2}}, + {1736, {wxListView, setColumnImage, 2}}, + {1737, {wxListItem, new_0, 0}}, + {1738, {wxListItem, new_1, 1}}, + {1739, {wxListItem, destruct, 0}}, + {1740, {wxListItem, clear, 0}}, + {1741, {wxListItem, getAlign, 0}}, + {1742, {wxListItem, getBackgroundColour, 0}}, + {1743, {wxListItem, getColumn, 0}}, + {1744, {wxListItem, getFont, 0}}, + {1745, {wxListItem, getId, 0}}, + {1746, {wxListItem, getImage, 0}}, + {1747, {wxListItem, getMask, 0}}, + {1748, {wxListItem, getState, 0}}, + {1749, {wxListItem, getText, 0}}, + {1750, {wxListItem, getTextColour, 0}}, + {1751, {wxListItem, getWidth, 0}}, + {1752, {wxListItem, setAlign, 1}}, + {1753, {wxListItem, setBackgroundColour, 1}}, + {1754, {wxListItem, setColumn, 1}}, + {1755, {wxListItem, setFont, 1}}, + {1756, {wxListItem, setId, 1}}, + {1757, {wxListItem, setImage, 1}}, + {1758, {wxListItem, setMask, 1}}, + {1759, {wxListItem, setState, 1}}, + {1760, {wxListItem, setStateMask, 1}}, + {1761, {wxListItem, setText, 1}}, + {1762, {wxListItem, setTextColour, 1}}, + {1763, {wxListItem, setWidth, 1}}, + {1764, {wxListItemAttr, new_0, 0}}, + {1765, {wxListItemAttr, new_3, 3}}, + {1766, {wxListItemAttr, getBackgroundColour, 0}}, + {1767, {wxListItemAttr, getFont, 0}}, + {1768, {wxListItemAttr, getTextColour, 0}}, + {1769, {wxListItemAttr, hasBackgroundColour, 0}}, + {1770, {wxListItemAttr, hasFont, 0}}, + {1771, {wxListItemAttr, hasTextColour, 0}}, + {1772, {wxListItemAttr, setBackgroundColour, 1}}, + {1773, {wxListItemAttr, setFont, 1}}, + {1774, {wxListItemAttr, setTextColour, 1}}, + {1775, {wxListItemAttr, 'Destroy', undefined}}, + {1776, {wxImageList, new_0, 0}}, + {1777, {wxImageList, new_3, 3}}, + {1778, {wxImageList, add_1, 1}}, + {1779, {wxImageList, add_2_0, 2}}, + {1780, {wxImageList, add_2_1, 2}}, + {1781, {wxImageList, create, 3}}, + {1783, {wxImageList, draw, 5}}, + {1784, {wxImageList, getBitmap, 1}}, + {1785, {wxImageList, getIcon, 1}}, + {1786, {wxImageList, getImageCount, 0}}, + {1787, {wxImageList, getSize, 3}}, + {1788, {wxImageList, remove, 1}}, + {1789, {wxImageList, removeAll, 0}}, + {1790, {wxImageList, replace_2, 2}}, + {1791, {wxImageList, replace_3, 3}}, + {1792, {wxImageList, 'Destroy', undefined}}, + {1793, {wxTextAttr, new_0, 0}}, + {1794, {wxTextAttr, new_2, 2}}, + {1795, {wxTextAttr, getAlignment, 0}}, + {1796, {wxTextAttr, getBackgroundColour, 0}}, + {1797, {wxTextAttr, getFont, 0}}, + {1798, {wxTextAttr, getLeftIndent, 0}}, + {1799, {wxTextAttr, getLeftSubIndent, 0}}, + {1800, {wxTextAttr, getRightIndent, 0}}, + {1801, {wxTextAttr, getTabs, 0}}, + {1802, {wxTextAttr, getTextColour, 0}}, + {1803, {wxTextAttr, hasBackgroundColour, 0}}, + {1804, {wxTextAttr, hasFont, 0}}, + {1805, {wxTextAttr, hasTextColour, 0}}, + {1806, {wxTextAttr, getFlags, 0}}, + {1807, {wxTextAttr, isDefault, 0}}, + {1808, {wxTextAttr, setAlignment, 1}}, + {1809, {wxTextAttr, setBackgroundColour, 1}}, + {1810, {wxTextAttr, setFlags, 1}}, + {1811, {wxTextAttr, setFont, 2}}, + {1812, {wxTextAttr, setLeftIndent, 2}}, + {1813, {wxTextAttr, setRightIndent, 1}}, + {1814, {wxTextAttr, setTabs, 1}}, + {1815, {wxTextAttr, setTextColour, 1}}, + {1816, {wxTextAttr, 'Destroy', undefined}}, + {1818, {wxTextCtrl, new_3, 3}}, + {1819, {wxTextCtrl, new_0, 0}}, + {1821, {wxTextCtrl, destruct, 0}}, + {1822, {wxTextCtrl, appendText, 1}}, + {1823, {wxTextCtrl, canCopy, 0}}, + {1824, {wxTextCtrl, canCut, 0}}, + {1825, {wxTextCtrl, canPaste, 0}}, + {1826, {wxTextCtrl, canRedo, 0}}, + {1827, {wxTextCtrl, canUndo, 0}}, + {1828, {wxTextCtrl, clear, 0}}, + {1829, {wxTextCtrl, copy, 0}}, + {1830, {wxTextCtrl, create, 3}}, + {1831, {wxTextCtrl, cut, 0}}, + {1832, {wxTextCtrl, discardEdits, 0}}, + {1833, {wxTextCtrl, changeValue, 1}}, + {1834, {wxTextCtrl, emulateKeyPress, 1}}, + {1835, {wxTextCtrl, getDefaultStyle, 0}}, + {1836, {wxTextCtrl, getInsertionPoint, 0}}, + {1837, {wxTextCtrl, getLastPosition, 0}}, + {1838, {wxTextCtrl, getLineLength, 1}}, + {1839, {wxTextCtrl, getLineText, 1}}, + {1840, {wxTextCtrl, getNumberOfLines, 0}}, + {1841, {wxTextCtrl, getRange, 2}}, + {1842, {wxTextCtrl, getSelection, 2}}, + {1843, {wxTextCtrl, getStringSelection, 0}}, + {1844, {wxTextCtrl, getStyle, 2}}, + {1845, {wxTextCtrl, getValue, 0}}, + {1846, {wxTextCtrl, isEditable, 0}}, + {1847, {wxTextCtrl, isModified, 0}}, + {1848, {wxTextCtrl, isMultiLine, 0}}, + {1849, {wxTextCtrl, isSingleLine, 0}}, + {1850, {wxTextCtrl, loadFile, 2}}, + {1851, {wxTextCtrl, markDirty, 0}}, + {1852, {wxTextCtrl, paste, 0}}, + {1853, {wxTextCtrl, positionToXY, 3}}, + {1854, {wxTextCtrl, redo, 0}}, + {1855, {wxTextCtrl, remove, 2}}, + {1856, {wxTextCtrl, replace, 3}}, + {1857, {wxTextCtrl, saveFile, 1}}, + {1858, {wxTextCtrl, setDefaultStyle, 1}}, + {1859, {wxTextCtrl, setEditable, 1}}, + {1860, {wxTextCtrl, setInsertionPoint, 1}}, + {1861, {wxTextCtrl, setInsertionPointEnd, 0}}, + {1863, {wxTextCtrl, setMaxLength, 1}}, + {1864, {wxTextCtrl, setSelection, 2}}, + {1865, {wxTextCtrl, setStyle, 3}}, + {1866, {wxTextCtrl, setValue, 1}}, + {1867, {wxTextCtrl, showPosition, 1}}, + {1868, {wxTextCtrl, undo, 0}}, + {1869, {wxTextCtrl, writeText, 1}}, + {1870, {wxTextCtrl, xYToPosition, 2}}, + {1873, {wxNotebook, new_0, 0}}, + {1874, {wxNotebook, new_3, 3}}, + {1875, {wxNotebook, destruct, 0}}, + {1876, {wxNotebook, addPage, 3}}, + {1877, {wxNotebook, advanceSelection, 1}}, + {1878, {wxNotebook, assignImageList, 1}}, + {1879, {wxNotebook, create, 3}}, + {1880, {wxNotebook, deleteAllPages, 0}}, + {1881, {wxNotebook, deletePage, 1}}, + {1882, {wxNotebook, removePage, 1}}, + {1883, {wxNotebook, getCurrentPage, 0}}, + {1884, {wxNotebook, getImageList, 0}}, + {1886, {wxNotebook, getPage, 1}}, + {1887, {wxNotebook, getPageCount, 0}}, + {1888, {wxNotebook, getPageImage, 1}}, + {1889, {wxNotebook, getPageText, 1}}, + {1890, {wxNotebook, getRowCount, 0}}, + {1891, {wxNotebook, getSelection, 0}}, + {1892, {wxNotebook, getThemeBackgroundColour, 0}}, + {1894, {wxNotebook, hitTest, 2}}, + {1896, {wxNotebook, insertPage, 4}}, + {1897, {wxNotebook, setImageList, 1}}, + {1898, {wxNotebook, setPadding, 1}}, + {1899, {wxNotebook, setPageSize, 1}}, + {1900, {wxNotebook, setPageImage, 2}}, + {1901, {wxNotebook, setPageText, 2}}, + {1902, {wxNotebook, setSelection, 1}}, + {1903, {wxNotebook, changeSelection, 1}}, + {1904, {wxChoicebook, new_0, 0}}, + {1905, {wxChoicebook, new_3, 3}}, + {1906, {wxChoicebook, addPage, 3}}, + {1907, {wxChoicebook, advanceSelection, 1}}, + {1908, {wxChoicebook, assignImageList, 1}}, + {1909, {wxChoicebook, create, 3}}, + {1910, {wxChoicebook, deleteAllPages, 0}}, + {1911, {wxChoicebook, deletePage, 1}}, + {1912, {wxChoicebook, removePage, 1}}, + {1913, {wxChoicebook, getCurrentPage, 0}}, + {1914, {wxChoicebook, getImageList, 0}}, + {1916, {wxChoicebook, getPage, 1}}, + {1917, {wxChoicebook, getPageCount, 0}}, + {1918, {wxChoicebook, getPageImage, 1}}, + {1919, {wxChoicebook, getPageText, 1}}, + {1920, {wxChoicebook, getSelection, 0}}, + {1921, {wxChoicebook, hitTest, 2}}, + {1922, {wxChoicebook, insertPage, 4}}, + {1923, {wxChoicebook, setImageList, 1}}, + {1924, {wxChoicebook, setPageSize, 1}}, + {1925, {wxChoicebook, setPageImage, 2}}, + {1926, {wxChoicebook, setPageText, 2}}, + {1927, {wxChoicebook, setSelection, 1}}, + {1928, {wxChoicebook, changeSelection, 1}}, + {1929, {wxChoicebook, 'Destroy', undefined}}, + {1930, {wxToolbook, new_0, 0}}, + {1931, {wxToolbook, new_3, 3}}, + {1932, {wxToolbook, addPage, 3}}, + {1933, {wxToolbook, advanceSelection, 1}}, + {1934, {wxToolbook, assignImageList, 1}}, + {1935, {wxToolbook, create, 3}}, + {1936, {wxToolbook, deleteAllPages, 0}}, + {1937, {wxToolbook, deletePage, 1}}, + {1938, {wxToolbook, removePage, 1}}, + {1939, {wxToolbook, getCurrentPage, 0}}, + {1940, {wxToolbook, getImageList, 0}}, + {1942, {wxToolbook, getPage, 1}}, + {1943, {wxToolbook, getPageCount, 0}}, + {1944, {wxToolbook, getPageImage, 1}}, + {1945, {wxToolbook, getPageText, 1}}, + {1946, {wxToolbook, getSelection, 0}}, + {1948, {wxToolbook, hitTest, 2}}, + {1949, {wxToolbook, insertPage, 4}}, + {1950, {wxToolbook, setImageList, 1}}, + {1951, {wxToolbook, setPageSize, 1}}, + {1952, {wxToolbook, setPageImage, 2}}, + {1953, {wxToolbook, setPageText, 2}}, + {1954, {wxToolbook, setSelection, 1}}, + {1955, {wxToolbook, changeSelection, 1}}, + {1956, {wxToolbook, 'Destroy', undefined}}, + {1957, {wxListbook, new_0, 0}}, + {1958, {wxListbook, new_3, 3}}, + {1959, {wxListbook, addPage, 3}}, + {1960, {wxListbook, advanceSelection, 1}}, + {1961, {wxListbook, assignImageList, 1}}, + {1962, {wxListbook, create, 3}}, + {1963, {wxListbook, deleteAllPages, 0}}, + {1964, {wxListbook, deletePage, 1}}, + {1965, {wxListbook, removePage, 1}}, + {1966, {wxListbook, getCurrentPage, 0}}, + {1967, {wxListbook, getImageList, 0}}, + {1969, {wxListbook, getPage, 1}}, + {1970, {wxListbook, getPageCount, 0}}, + {1971, {wxListbook, getPageImage, 1}}, + {1972, {wxListbook, getPageText, 1}}, + {1973, {wxListbook, getSelection, 0}}, + {1975, {wxListbook, hitTest, 2}}, + {1976, {wxListbook, insertPage, 4}}, + {1977, {wxListbook, setImageList, 1}}, + {1978, {wxListbook, setPageSize, 1}}, + {1979, {wxListbook, setPageImage, 2}}, + {1980, {wxListbook, setPageText, 2}}, + {1981, {wxListbook, setSelection, 1}}, + {1982, {wxListbook, changeSelection, 1}}, + {1983, {wxListbook, 'Destroy', undefined}}, + {1984, {wxTreebook, new_0, 0}}, + {1985, {wxTreebook, new_3, 3}}, + {1986, {wxTreebook, addPage, 3}}, + {1987, {wxTreebook, advanceSelection, 1}}, + {1988, {wxTreebook, assignImageList, 1}}, + {1989, {wxTreebook, create, 3}}, + {1990, {wxTreebook, deleteAllPages, 0}}, + {1991, {wxTreebook, deletePage, 1}}, + {1992, {wxTreebook, removePage, 1}}, + {1993, {wxTreebook, getCurrentPage, 0}}, + {1994, {wxTreebook, getImageList, 0}}, + {1996, {wxTreebook, getPage, 1}}, + {1997, {wxTreebook, getPageCount, 0}}, + {1998, {wxTreebook, getPageImage, 1}}, + {1999, {wxTreebook, getPageText, 1}}, + {2000, {wxTreebook, getSelection, 0}}, + {2001, {wxTreebook, expandNode, 2}}, + {2002, {wxTreebook, isNodeExpanded, 1}}, + {2004, {wxTreebook, hitTest, 2}}, + {2005, {wxTreebook, insertPage, 4}}, + {2006, {wxTreebook, insertSubPage, 4}}, + {2007, {wxTreebook, setImageList, 1}}, + {2008, {wxTreebook, setPageSize, 1}}, + {2009, {wxTreebook, setPageImage, 2}}, + {2010, {wxTreebook, setPageText, 2}}, + {2011, {wxTreebook, setSelection, 1}}, + {2012, {wxTreebook, changeSelection, 1}}, + {2013, {wxTreebook, 'Destroy', undefined}}, + {2016, {wxTreeCtrl, new_2, 2}}, + {2017, {wxTreeCtrl, new_0, 0}}, + {2019, {wxTreeCtrl, destruct, 0}}, + {2020, {wxTreeCtrl, addRoot, 2}}, + {2021, {wxTreeCtrl, appendItem, 3}}, + {2022, {wxTreeCtrl, assignImageList, 1}}, + {2023, {wxTreeCtrl, assignStateImageList, 1}}, + {2024, {wxTreeCtrl, collapse, 1}}, + {2025, {wxTreeCtrl, collapseAndReset, 1}}, + {2026, {wxTreeCtrl, create, 2}}, + {2027, {wxTreeCtrl, delete, 1}}, + {2028, {wxTreeCtrl, deleteAllItems, 0}}, + {2029, {wxTreeCtrl, deleteChildren, 1}}, + {2030, {wxTreeCtrl, editLabel, 1}}, + {2031, {wxTreeCtrl, ensureVisible, 1}}, + {2032, {wxTreeCtrl, expand, 1}}, + {2033, {wxTreeCtrl, getBoundingRect, 3}}, + {2035, {wxTreeCtrl, getChildrenCount, 2}}, + {2036, {wxTreeCtrl, getCount, 0}}, + {2037, {wxTreeCtrl, getEditControl, 0}}, + {2038, {wxTreeCtrl, getFirstChild, 2}}, + {2039, {wxTreeCtrl, getNextChild, 2}}, + {2040, {wxTreeCtrl, getFirstVisibleItem, 0}}, + {2041, {wxTreeCtrl, getImageList, 0}}, + {2042, {wxTreeCtrl, getIndent, 0}}, + {2043, {wxTreeCtrl, getItemBackgroundColour, 1}}, + {2044, {wxTreeCtrl, getItemData, 1}}, + {2045, {wxTreeCtrl, getItemFont, 1}}, + {2046, {wxTreeCtrl, getItemImage_1, 1}}, + {2047, {wxTreeCtrl, getItemImage_2, 2}}, + {2048, {wxTreeCtrl, getItemText, 1}}, + {2049, {wxTreeCtrl, getItemTextColour, 1}}, + {2050, {wxTreeCtrl, getLastChild, 1}}, + {2051, {wxTreeCtrl, getNextSibling, 1}}, + {2052, {wxTreeCtrl, getNextVisible, 1}}, + {2053, {wxTreeCtrl, getItemParent, 1}}, + {2054, {wxTreeCtrl, getPrevSibling, 1}}, + {2055, {wxTreeCtrl, getPrevVisible, 1}}, + {2056, {wxTreeCtrl, getRootItem, 0}}, + {2057, {wxTreeCtrl, getSelection, 0}}, + {2058, {wxTreeCtrl, getSelections, 1}}, + {2059, {wxTreeCtrl, getStateImageList, 0}}, + {2060, {wxTreeCtrl, hitTest, 2}}, + {2062, {wxTreeCtrl, insertItem, 4}}, + {2063, {wxTreeCtrl, isBold, 1}}, + {2064, {wxTreeCtrl, isExpanded, 1}}, + {2065, {wxTreeCtrl, isSelected, 1}}, + {2066, {wxTreeCtrl, isVisible, 1}}, + {2067, {wxTreeCtrl, itemHasChildren, 1}}, + {2068, {wxTreeCtrl, isTreeItemIdOk, 1}}, + {2069, {wxTreeCtrl, prependItem, 3}}, + {2070, {wxTreeCtrl, scrollTo, 1}}, + {2071, {wxTreeCtrl, selectItem_1, 1}}, + {2072, {wxTreeCtrl, selectItem_2, 2}}, + {2073, {wxTreeCtrl, setIndent, 1}}, + {2074, {wxTreeCtrl, setImageList, 1}}, + {2075, {wxTreeCtrl, setItemBackgroundColour, 2}}, + {2076, {wxTreeCtrl, setItemBold, 2}}, + {2077, {wxTreeCtrl, setItemData, 2}}, + {2078, {wxTreeCtrl, setItemDropHighlight, 2}}, + {2079, {wxTreeCtrl, setItemFont, 2}}, + {2080, {wxTreeCtrl, setItemHasChildren, 2}}, + {2081, {wxTreeCtrl, setItemImage_2, 2}}, + {2082, {wxTreeCtrl, setItemImage_3, 3}}, + {2083, {wxTreeCtrl, setItemText, 2}}, + {2084, {wxTreeCtrl, setItemTextColour, 2}}, + {2085, {wxTreeCtrl, setStateImageList, 1}}, + {2086, {wxTreeCtrl, setWindowStyle, 1}}, + {2087, {wxTreeCtrl, sortChildren, 1}}, + {2088, {wxTreeCtrl, toggle, 1}}, + {2089, {wxTreeCtrl, toggleItemSelection, 1}}, + {2090, {wxTreeCtrl, unselect, 0}}, + {2091, {wxTreeCtrl, unselectAll, 0}}, + {2092, {wxTreeCtrl, unselectItem, 1}}, + {2093, {wxScrollBar, new_0, 0}}, + {2094, {wxScrollBar, new_3, 3}}, + {2095, {wxScrollBar, destruct, 0}}, + {2096, {wxScrollBar, create, 3}}, + {2097, {wxScrollBar, getRange, 0}}, + {2098, {wxScrollBar, getPageSize, 0}}, + {2099, {wxScrollBar, getThumbPosition, 0}}, + {2100, {wxScrollBar, getThumbSize, 0}}, + {2101, {wxScrollBar, setThumbPosition, 1}}, + {2102, {wxScrollBar, setScrollbar, 5}}, + {2104, {wxSpinButton, new_2, 2}}, + {2105, {wxSpinButton, new_0, 0}}, + {2106, {wxSpinButton, create, 2}}, + {2107, {wxSpinButton, getMax, 0}}, + {2108, {wxSpinButton, getMin, 0}}, + {2109, {wxSpinButton, getValue, 0}}, + {2110, {wxSpinButton, setRange, 2}}, + {2111, {wxSpinButton, setValue, 1}}, + {2112, {wxSpinButton, 'Destroy', undefined}}, + {2113, {wxSpinCtrl, new_0, 0}}, + {2114, {wxSpinCtrl, new_2, 2}}, + {2116, {wxSpinCtrl, create, 2}}, + {2119, {wxSpinCtrl, setValue_1_1, 1}}, + {2120, {wxSpinCtrl, setValue_1_0, 1}}, + {2122, {wxSpinCtrl, getValue, 0}}, + {2124, {wxSpinCtrl, setRange, 2}}, + {2125, {wxSpinCtrl, setSelection, 2}}, + {2127, {wxSpinCtrl, getMin, 0}}, + {2129, {wxSpinCtrl, getMax, 0}}, + {2130, {wxSpinCtrl, 'Destroy', undefined}}, + {2131, {wxStaticText, new_0, 0}}, + {2132, {wxStaticText, new_4, 4}}, + {2133, {wxStaticText, create, 4}}, + {2134, {wxStaticText, getLabel, 0}}, + {2135, {wxStaticText, setLabel, 1}}, + {2136, {wxStaticText, wrap, 1}}, + {2137, {wxStaticText, 'Destroy', undefined}}, + {2138, {wxStaticBitmap, new_0, 0}}, + {2139, {wxStaticBitmap, new_4, 4}}, + {2140, {wxStaticBitmap, create, 4}}, + {2141, {wxStaticBitmap, getBitmap, 0}}, + {2142, {wxStaticBitmap, setBitmap, 1}}, + {2143, {wxStaticBitmap, 'Destroy', undefined}}, + {2144, {wxRadioBox, new, 7}}, + {2146, {wxRadioBox, destruct, 0}}, + {2147, {wxRadioBox, create, 7}}, + {2148, {wxRadioBox, enable_2, 2}}, + {2149, {wxRadioBox, enable_1, 1}}, + {2150, {wxRadioBox, getSelection, 0}}, + {2151, {wxRadioBox, getString, 1}}, + {2152, {wxRadioBox, setSelection, 1}}, + {2153, {wxRadioBox, show_2, 2}}, + {2154, {wxRadioBox, show_1, 1}}, + {2155, {wxRadioBox, getColumnCount, 0}}, + {2156, {wxRadioBox, getItemHelpText, 1}}, + {2157, {wxRadioBox, getItemToolTip, 1}}, + {2159, {wxRadioBox, getItemFromPoint, 1}}, + {2160, {wxRadioBox, getRowCount, 0}}, + {2161, {wxRadioBox, isItemEnabled, 1}}, + {2162, {wxRadioBox, isItemShown, 1}}, + {2163, {wxRadioBox, setItemHelpText, 2}}, + {2164, {wxRadioBox, setItemToolTip, 2}}, + {2165, {wxRadioButton, new_0, 0}}, + {2166, {wxRadioButton, new_4, 4}}, + {2167, {wxRadioButton, create, 4}}, + {2168, {wxRadioButton, getValue, 0}}, + {2169, {wxRadioButton, setValue, 1}}, + {2170, {wxRadioButton, 'Destroy', undefined}}, + {2172, {wxSlider, new_6, 6}}, + {2173, {wxSlider, new_0, 0}}, + {2174, {wxSlider, create, 6}}, + {2175, {wxSlider, getLineSize, 0}}, + {2176, {wxSlider, getMax, 0}}, + {2177, {wxSlider, getMin, 0}}, + {2178, {wxSlider, getPageSize, 0}}, + {2179, {wxSlider, getThumbLength, 0}}, + {2180, {wxSlider, getValue, 0}}, + {2181, {wxSlider, setLineSize, 1}}, + {2182, {wxSlider, setPageSize, 1}}, + {2183, {wxSlider, setRange, 2}}, + {2184, {wxSlider, setThumbLength, 1}}, + {2185, {wxSlider, setValue, 1}}, + {2186, {wxSlider, 'Destroy', undefined}}, + {2188, {wxDialog, new_4, 4}}, + {2189, {wxDialog, new_0, 0}}, + {2191, {wxDialog, destruct, 0}}, + {2192, {wxDialog, create, 4}}, + {2193, {wxDialog, createButtonSizer, 1}}, + {2194, {wxDialog, createStdDialogButtonSizer, 1}}, + {2195, {wxDialog, endModal, 1}}, + {2196, {wxDialog, getAffirmativeId, 0}}, + {2197, {wxDialog, getReturnCode, 0}}, + {2198, {wxDialog, isModal, 0}}, + {2199, {wxDialog, setAffirmativeId, 1}}, + {2200, {wxDialog, setReturnCode, 1}}, + {2201, {wxDialog, show, 1}}, + {2202, {wxDialog, showModal, 0}}, + {2203, {wxColourDialog, new_0, 0}}, + {2204, {wxColourDialog, new_2, 2}}, + {2205, {wxColourDialog, destruct, 0}}, + {2206, {wxColourDialog, create, 2}}, + {2207, {wxColourDialog, getColourData, 0}}, + {2208, {wxColourData, new_0, 0}}, + {2209, {wxColourData, new_1, 1}}, + {2210, {wxColourData, destruct, 0}}, + {2211, {wxColourData, getChooseFull, 0}}, + {2212, {wxColourData, getColour, 0}}, + {2214, {wxColourData, getCustomColour, 1}}, + {2215, {wxColourData, setChooseFull, 1}}, + {2216, {wxColourData, setColour, 1}}, + {2217, {wxColourData, setCustomColour, 2}}, + {2218, {wxPalette, new_0, 0}}, + {2219, {wxPalette, new_4, 4}}, + {2221, {wxPalette, destruct, 0}}, + {2222, {wxPalette, create, 4}}, + {2223, {wxPalette, getColoursCount, 0}}, + {2224, {wxPalette, getPixel, 3}}, + {2225, {wxPalette, getRGB, 4}}, + {2226, {wxPalette, isOk, 0}}, + {2230, {wxDirDialog, new, 2}}, + {2231, {wxDirDialog, destruct, 0}}, + {2232, {wxDirDialog, getPath, 0}}, + {2233, {wxDirDialog, getMessage, 0}}, + {2234, {wxDirDialog, setMessage, 1}}, + {2235, {wxDirDialog, setPath, 1}}, + {2239, {wxFileDialog, new, 2}}, + {2240, {wxFileDialog, destruct, 0}}, + {2241, {wxFileDialog, getDirectory, 0}}, + {2242, {wxFileDialog, getFilename, 0}}, + {2243, {wxFileDialog, getFilenames, 1}}, + {2244, {wxFileDialog, getFilterIndex, 0}}, + {2245, {wxFileDialog, getMessage, 0}}, + {2246, {wxFileDialog, getPath, 0}}, + {2247, {wxFileDialog, getPaths, 1}}, + {2248, {wxFileDialog, getWildcard, 0}}, + {2249, {wxFileDialog, setDirectory, 1}}, + {2250, {wxFileDialog, setFilename, 1}}, + {2251, {wxFileDialog, setFilterIndex, 1}}, + {2252, {wxFileDialog, setMessage, 1}}, + {2253, {wxFileDialog, setPath, 1}}, + {2254, {wxFileDialog, setWildcard, 1}}, + {2255, {wxPickerBase, setInternalMargin, 1}}, + {2256, {wxPickerBase, getInternalMargin, 0}}, + {2257, {wxPickerBase, setTextCtrlProportion, 1}}, + {2258, {wxPickerBase, setPickerCtrlProportion, 1}}, + {2259, {wxPickerBase, getTextCtrlProportion, 0}}, + {2260, {wxPickerBase, getPickerCtrlProportion, 0}}, + {2261, {wxPickerBase, hasTextCtrl, 0}}, + {2262, {wxPickerBase, getTextCtrl, 0}}, + {2263, {wxPickerBase, isTextCtrlGrowable, 0}}, + {2264, {wxPickerBase, setPickerCtrlGrowable, 1}}, + {2265, {wxPickerBase, setTextCtrlGrowable, 1}}, + {2266, {wxPickerBase, isPickerCtrlGrowable, 0}}, + {2267, {wxFilePickerCtrl, new_0, 0}}, + {2268, {wxFilePickerCtrl, new_3, 3}}, + {2269, {wxFilePickerCtrl, create, 3}}, + {2270, {wxFilePickerCtrl, getPath, 0}}, + {2271, {wxFilePickerCtrl, setPath, 1}}, + {2272, {wxFilePickerCtrl, 'Destroy', undefined}}, + {2273, {wxDirPickerCtrl, new_0, 0}}, + {2274, {wxDirPickerCtrl, new_3, 3}}, + {2275, {wxDirPickerCtrl, create, 3}}, + {2276, {wxDirPickerCtrl, getPath, 0}}, + {2277, {wxDirPickerCtrl, setPath, 1}}, + {2278, {wxDirPickerCtrl, 'Destroy', undefined}}, + {2279, {wxColourPickerCtrl, new_0, 0}}, + {2280, {wxColourPickerCtrl, new_3, 3}}, + {2281, {wxColourPickerCtrl, create, 3}}, + {2282, {wxColourPickerCtrl, getColour, 0}}, + {2283, {wxColourPickerCtrl, setColour_1_1, 1}}, + {2284, {wxColourPickerCtrl, setColour_1_0, 1}}, + {2285, {wxColourPickerCtrl, 'Destroy', undefined}}, + {2286, {wxDatePickerCtrl, new_0, 0}}, + {2287, {wxDatePickerCtrl, new_3, 3}}, + {2288, {wxDatePickerCtrl, getRange, 2}}, + {2289, {wxDatePickerCtrl, getValue, 0}}, + {2290, {wxDatePickerCtrl, setRange, 2}}, + {2291, {wxDatePickerCtrl, setValue, 1}}, + {2292, {wxDatePickerCtrl, 'Destroy', undefined}}, + {2293, {wxFontPickerCtrl, new_0, 0}}, + {2294, {wxFontPickerCtrl, new_3, 3}}, + {2295, {wxFontPickerCtrl, create, 3}}, + {2296, {wxFontPickerCtrl, getSelectedFont, 0}}, + {2297, {wxFontPickerCtrl, setSelectedFont, 1}}, + {2298, {wxFontPickerCtrl, getMaxPointSize, 0}}, + {2299, {wxFontPickerCtrl, setMaxPointSize, 1}}, + {2300, {wxFontPickerCtrl, 'Destroy', undefined}}, + {2303, {wxFindReplaceDialog, new_0, 0}}, + {2304, {wxFindReplaceDialog, new_4, 4}}, + {2305, {wxFindReplaceDialog, destruct, 0}}, + {2306, {wxFindReplaceDialog, create, 4}}, + {2307, {wxFindReplaceDialog, getData, 0}}, + {2308, {wxFindReplaceData, new_0, 0}}, + {2309, {wxFindReplaceData, new_1, 1}}, + {2310, {wxFindReplaceData, getFindString, 0}}, + {2311, {wxFindReplaceData, getReplaceString, 0}}, + {2312, {wxFindReplaceData, getFlags, 0}}, + {2313, {wxFindReplaceData, setFlags, 1}}, + {2314, {wxFindReplaceData, setFindString, 1}}, + {2315, {wxFindReplaceData, setReplaceString, 1}}, + {2316, {wxFindReplaceData, 'Destroy', undefined}}, + {2317, {wxMultiChoiceDialog, new_0, 0}}, + {2319, {wxMultiChoiceDialog, new_5, 5}}, + {2320, {wxMultiChoiceDialog, getSelections, 0}}, + {2321, {wxMultiChoiceDialog, setSelections, 1}}, + {2322, {wxMultiChoiceDialog, 'Destroy', undefined}}, + {2323, {wxSingleChoiceDialog, new_0, 0}}, + {2325, {wxSingleChoiceDialog, new_5, 5}}, + {2326, {wxSingleChoiceDialog, getSelection, 0}}, + {2327, {wxSingleChoiceDialog, getStringSelection, 0}}, + {2328, {wxSingleChoiceDialog, setSelection, 1}}, + {2329, {wxSingleChoiceDialog, 'Destroy', undefined}}, + {2330, {wxTextEntryDialog, new, 3}}, + {2331, {wxTextEntryDialog, getValue, 0}}, + {2332, {wxTextEntryDialog, setValue, 1}}, + {2333, {wxTextEntryDialog, 'Destroy', undefined}}, + {2334, {wxPasswordEntryDialog, new, 3}}, + {2335, {wxPasswordEntryDialog, 'Destroy', undefined}}, + {2336, {wxFontData, new_0, 0}}, + {2337, {wxFontData, new_1, 1}}, + {2338, {wxFontData, destruct, 0}}, + {2339, {wxFontData, enableEffects, 1}}, + {2340, {wxFontData, getAllowSymbols, 0}}, + {2341, {wxFontData, getColour, 0}}, + {2342, {wxFontData, getChosenFont, 0}}, + {2343, {wxFontData, getEnableEffects, 0}}, + {2344, {wxFontData, getInitialFont, 0}}, + {2345, {wxFontData, getShowHelp, 0}}, + {2346, {wxFontData, setAllowSymbols, 1}}, + {2347, {wxFontData, setChosenFont, 1}}, + {2348, {wxFontData, setColour, 1}}, + {2349, {wxFontData, setInitialFont, 1}}, + {2350, {wxFontData, setRange, 2}}, + {2351, {wxFontData, setShowHelp, 1}}, + {2355, {wxFontDialog, new_0, 0}}, + {2357, {wxFontDialog, new_2, 2}}, + {2359, {wxFontDialog, create, 2}}, + {2360, {wxFontDialog, getFontData, 0}}, + {2362, {wxFontDialog, 'Destroy', undefined}}, + {2363, {wxProgressDialog, new, 3}}, + {2364, {wxProgressDialog, destruct, 0}}, + {2365, {wxProgressDialog, resume, 0}}, + {2366, {wxProgressDialog, update_2, 2}}, + {2367, {wxProgressDialog, update_0, 0}}, + {2368, {wxMessageDialog, new, 3}}, + {2369, {wxMessageDialog, destruct, 0}}, + {2370, {wxPageSetupDialog, new, 2}}, + {2371, {wxPageSetupDialog, destruct, 0}}, + {2372, {wxPageSetupDialog, getPageSetupData, 0}}, + {2373, {wxPageSetupDialog, showModal, 0}}, + {2374, {wxPageSetupDialogData, new_0, 0}}, + {2375, {wxPageSetupDialogData, new_1_0, 1}}, + {2376, {wxPageSetupDialogData, new_1_1, 1}}, + {2377, {wxPageSetupDialogData, destruct, 0}}, + {2378, {wxPageSetupDialogData, enableHelp, 1}}, + {2379, {wxPageSetupDialogData, enableMargins, 1}}, + {2380, {wxPageSetupDialogData, enableOrientation, 1}}, + {2381, {wxPageSetupDialogData, enablePaper, 1}}, + {2382, {wxPageSetupDialogData, enablePrinter, 1}}, + {2383, {wxPageSetupDialogData, getDefaultMinMargins, 0}}, + {2384, {wxPageSetupDialogData, getEnableMargins, 0}}, + {2385, {wxPageSetupDialogData, getEnableOrientation, 0}}, + {2386, {wxPageSetupDialogData, getEnablePaper, 0}}, + {2387, {wxPageSetupDialogData, getEnablePrinter, 0}}, + {2388, {wxPageSetupDialogData, getEnableHelp, 0}}, + {2389, {wxPageSetupDialogData, getDefaultInfo, 0}}, + {2390, {wxPageSetupDialogData, getMarginTopLeft, 0}}, + {2391, {wxPageSetupDialogData, getMarginBottomRight, 0}}, + {2392, {wxPageSetupDialogData, getMinMarginTopLeft, 0}}, + {2393, {wxPageSetupDialogData, getMinMarginBottomRight, 0}}, + {2394, {wxPageSetupDialogData, getPaperId, 0}}, + {2395, {wxPageSetupDialogData, getPaperSize, 0}}, + {2397, {wxPageSetupDialogData, getPrintData, 0}}, + {2398, {wxPageSetupDialogData, isOk, 0}}, + {2399, {wxPageSetupDialogData, setDefaultInfo, 1}}, + {2400, {wxPageSetupDialogData, setDefaultMinMargins, 1}}, + {2401, {wxPageSetupDialogData, setMarginTopLeft, 1}}, + {2402, {wxPageSetupDialogData, setMarginBottomRight, 1}}, + {2403, {wxPageSetupDialogData, setMinMarginTopLeft, 1}}, + {2404, {wxPageSetupDialogData, setMinMarginBottomRight, 1}}, + {2405, {wxPageSetupDialogData, setPaperId, 1}}, + {2406, {wxPageSetupDialogData, setPaperSize_1_1, 1}}, + {2407, {wxPageSetupDialogData, setPaperSize_1_0, 1}}, + {2408, {wxPageSetupDialogData, setPrintData, 1}}, + {2409, {wxPrintDialog, new_2_0, 2}}, + {2410, {wxPrintDialog, new_2_1, 2}}, + {2411, {wxPrintDialog, destruct, 0}}, + {2412, {wxPrintDialog, getPrintDialogData, 0}}, + {2413, {wxPrintDialog, getPrintDC, 0}}, + {2414, {wxPrintDialogData, new_0, 0}}, + {2415, {wxPrintDialogData, new_1_1, 1}}, + {2416, {wxPrintDialogData, new_1_0, 1}}, + {2417, {wxPrintDialogData, destruct, 0}}, + {2418, {wxPrintDialogData, enableHelp, 1}}, + {2419, {wxPrintDialogData, enablePageNumbers, 1}}, + {2420, {wxPrintDialogData, enablePrintToFile, 1}}, + {2421, {wxPrintDialogData, enableSelection, 1}}, + {2422, {wxPrintDialogData, getAllPages, 0}}, + {2423, {wxPrintDialogData, getCollate, 0}}, + {2424, {wxPrintDialogData, getFromPage, 0}}, + {2425, {wxPrintDialogData, getMaxPage, 0}}, + {2426, {wxPrintDialogData, getMinPage, 0}}, + {2427, {wxPrintDialogData, getNoCopies, 0}}, + {2428, {wxPrintDialogData, getPrintData, 0}}, + {2429, {wxPrintDialogData, getPrintToFile, 0}}, + {2430, {wxPrintDialogData, getSelection, 0}}, + {2431, {wxPrintDialogData, getToPage, 0}}, + {2432, {wxPrintDialogData, isOk, 0}}, + {2433, {wxPrintDialogData, setCollate, 1}}, + {2434, {wxPrintDialogData, setFromPage, 1}}, + {2435, {wxPrintDialogData, setMaxPage, 1}}, + {2436, {wxPrintDialogData, setMinPage, 1}}, + {2437, {wxPrintDialogData, setNoCopies, 1}}, + {2438, {wxPrintDialogData, setPrintData, 1}}, + {2439, {wxPrintDialogData, setPrintToFile, 1}}, + {2440, {wxPrintDialogData, setSelection, 1}}, + {2441, {wxPrintDialogData, setToPage, 1}}, + {2442, {wxPrintData, new_0, 0}}, + {2443, {wxPrintData, new_1, 1}}, + {2444, {wxPrintData, destruct, 0}}, + {2445, {wxPrintData, getCollate, 0}}, + {2446, {wxPrintData, getBin, 0}}, + {2447, {wxPrintData, getColour, 0}}, + {2448, {wxPrintData, getDuplex, 0}}, + {2449, {wxPrintData, getNoCopies, 0}}, + {2450, {wxPrintData, getOrientation, 0}}, + {2451, {wxPrintData, getPaperId, 0}}, + {2452, {wxPrintData, getPrinterName, 0}}, + {2453, {wxPrintData, getQuality, 0}}, + {2454, {wxPrintData, isOk, 0}}, + {2455, {wxPrintData, setBin, 1}}, + {2456, {wxPrintData, setCollate, 1}}, + {2457, {wxPrintData, setColour, 1}}, + {2458, {wxPrintData, setDuplex, 1}}, + {2459, {wxPrintData, setNoCopies, 1}}, + {2460, {wxPrintData, setOrientation, 1}}, + {2461, {wxPrintData, setPaperId, 1}}, + {2462, {wxPrintData, setPrinterName, 1}}, + {2463, {wxPrintData, setQuality, 1}}, + {2466, {wxPrintPreview, new_2, 2}}, + {2467, {wxPrintPreview, new_3, 3}}, + {2469, {wxPrintPreview, destruct, 0}}, + {2470, {wxPrintPreview, getCanvas, 0}}, + {2471, {wxPrintPreview, getCurrentPage, 0}}, + {2472, {wxPrintPreview, getFrame, 0}}, + {2473, {wxPrintPreview, getMaxPage, 0}}, + {2474, {wxPrintPreview, getMinPage, 0}}, + {2475, {wxPrintPreview, getPrintout, 0}}, + {2476, {wxPrintPreview, getPrintoutForPrinting, 0}}, + {2477, {wxPrintPreview, isOk, 0}}, + {2478, {wxPrintPreview, paintPage, 2}}, + {2479, {wxPrintPreview, print, 1}}, + {2480, {wxPrintPreview, renderPage, 1}}, + {2481, {wxPrintPreview, setCanvas, 1}}, + {2482, {wxPrintPreview, setCurrentPage, 1}}, + {2483, {wxPrintPreview, setFrame, 1}}, + {2484, {wxPrintPreview, setPrintout, 1}}, + {2485, {wxPrintPreview, setZoom, 1}}, + {2486, {wxPreviewFrame, new, 3}}, + {2487, {wxPreviewFrame, destruct, 0}}, + {2488, {wxPreviewFrame, createControlBar, 0}}, + {2489, {wxPreviewFrame, createCanvas, 0}}, + {2490, {wxPreviewFrame, initialize, 0}}, + {2491, {wxPreviewFrame, onCloseWindow, 1}}, + {2492, {wxPreviewControlBar, new, 4}}, + {2493, {wxPreviewControlBar, destruct, 0}}, + {2494, {wxPreviewControlBar, createButtons, 0}}, + {2495, {wxPreviewControlBar, getPrintPreview, 0}}, + {2496, {wxPreviewControlBar, getZoomControl, 0}}, + {2497, {wxPreviewControlBar, setZoomControl, 1}}, + {2499, {wxPrinter, new, 1}}, + {2500, {wxPrinter, createAbortWindow, 2}}, + {2501, {wxPrinter, getAbort, 0}}, + {2502, {wxPrinter, getLastError, 0}}, + {2503, {wxPrinter, getPrintDialogData, 0}}, + {2504, {wxPrinter, print, 3}}, + {2505, {wxPrinter, printDialog, 1}}, + {2506, {wxPrinter, reportError, 3}}, + {2507, {wxPrinter, setup, 1}}, + {2508, {wxPrinter, 'Destroy', undefined}}, + {2509, {wxXmlResource, new_1, 1}}, + {2510, {wxXmlResource, new_2, 2}}, + {2511, {wxXmlResource, destruct, 0}}, + {2512, {wxXmlResource, attachUnknownControl, 3}}, + {2513, {wxXmlResource, clearHandlers, 0}}, + {2514, {wxXmlResource, compareVersion, 4}}, + {2515, {wxXmlResource, get, 0}}, + {2516, {wxXmlResource, getFlags, 0}}, + {2517, {wxXmlResource, getVersion, 0}}, + {2518, {wxXmlResource, getXRCID, 2}}, + {2519, {wxXmlResource, initAllHandlers, 0}}, + {2520, {wxXmlResource, load, 1}}, + {2521, {wxXmlResource, loadBitmap, 1}}, + {2522, {wxXmlResource, loadDialog_2, 2}}, + {2523, {wxXmlResource, loadDialog_3, 3}}, + {2524, {wxXmlResource, loadFrame_2, 2}}, + {2525, {wxXmlResource, loadFrame_3, 3}}, + {2526, {wxXmlResource, loadIcon, 1}}, + {2527, {wxXmlResource, loadMenu, 1}}, + {2528, {wxXmlResource, loadMenuBar_2, 2}}, + {2529, {wxXmlResource, loadMenuBar_1, 1}}, + {2530, {wxXmlResource, loadPanel_2, 2}}, + {2531, {wxXmlResource, loadPanel_3, 3}}, + {2532, {wxXmlResource, loadToolBar, 2}}, + {2533, {wxXmlResource, set, 1}}, + {2534, {wxXmlResource, setFlags, 1}}, + {2535, {wxXmlResource, unload, 1}}, + {2536, {wxXmlResource, xrcctrl, 3}}, + {2537, {wxHtmlEasyPrinting, new, 1}}, + {2538, {wxHtmlEasyPrinting, destruct, 0}}, + {2539, {wxHtmlEasyPrinting, getPrintData, 0}}, + {2540, {wxHtmlEasyPrinting, getPageSetupData, 0}}, + {2541, {wxHtmlEasyPrinting, previewFile, 1}}, + {2542, {wxHtmlEasyPrinting, previewText, 2}}, + {2543, {wxHtmlEasyPrinting, printFile, 1}}, + {2544, {wxHtmlEasyPrinting, printText, 2}}, + {2545, {wxHtmlEasyPrinting, pageSetup, 0}}, + {2546, {wxHtmlEasyPrinting, setFonts, 3}}, + {2547, {wxHtmlEasyPrinting, setHeader, 2}}, + {2548, {wxHtmlEasyPrinting, setFooter, 2}}, + {2550, {wxGLCanvas, new_2, 2}}, + {2551, {wxGLCanvas, new_3_1, 3}}, + {2552, {wxGLCanvas, new_3_0, 3}}, + {2553, {wxGLCanvas, getContext, 0}}, + {2555, {wxGLCanvas, setCurrent, 0}}, + {2556, {wxGLCanvas, swapBuffers, 0}}, + {2557, {wxGLCanvas, 'Destroy', undefined}}, + {2558, {wxAuiManager, new, 1}}, + {2559, {wxAuiManager, destruct, 0}}, + {2560, {wxAuiManager, addPane_2_1, 2}}, + {2561, {wxAuiManager, addPane_3, 3}}, + {2562, {wxAuiManager, addPane_2_0, 2}}, + {2563, {wxAuiManager, detachPane, 1}}, + {2564, {wxAuiManager, getAllPanes, 0}}, + {2565, {wxAuiManager, getArtProvider, 0}}, + {2566, {wxAuiManager, getDockSizeConstraint, 2}}, + {2567, {wxAuiManager, getFlags, 0}}, + {2568, {wxAuiManager, getManagedWindow, 0}}, + {2569, {wxAuiManager, getManager, 1}}, + {2570, {wxAuiManager, getPane_1_1, 1}}, + {2571, {wxAuiManager, getPane_1_0, 1}}, + {2572, {wxAuiManager, hideHint, 0}}, + {2573, {wxAuiManager, insertPane, 3}}, + {2574, {wxAuiManager, loadPaneInfo, 2}}, + {2575, {wxAuiManager, loadPerspective, 2}}, + {2576, {wxAuiManager, savePaneInfo, 1}}, + {2577, {wxAuiManager, savePerspective, 0}}, + {2578, {wxAuiManager, setArtProvider, 1}}, + {2579, {wxAuiManager, setDockSizeConstraint, 2}}, + {2580, {wxAuiManager, setFlags, 1}}, + {2581, {wxAuiManager, setManagedWindow, 1}}, + {2582, {wxAuiManager, showHint, 1}}, + {2583, {wxAuiManager, unInit, 0}}, + {2584, {wxAuiManager, update, 0}}, + {2585, {wxAuiPaneInfo, new_0, 0}}, + {2586, {wxAuiPaneInfo, new_1, 1}}, + {2587, {wxAuiPaneInfo, destruct, 0}}, + {2588, {wxAuiPaneInfo, bestSize_1, 1}}, + {2589, {wxAuiPaneInfo, bestSize_2, 2}}, + {2590, {wxAuiPaneInfo, bottom, 0}}, + {2591, {wxAuiPaneInfo, bottomDockable, 1}}, + {2592, {wxAuiPaneInfo, caption, 1}}, + {2593, {wxAuiPaneInfo, captionVisible, 1}}, + {2594, {wxAuiPaneInfo, centre, 0}}, + {2595, {wxAuiPaneInfo, centrePane, 0}}, + {2596, {wxAuiPaneInfo, closeButton, 1}}, + {2597, {wxAuiPaneInfo, defaultPane, 0}}, + {2598, {wxAuiPaneInfo, destroyOnClose, 1}}, + {2599, {wxAuiPaneInfo, direction, 1}}, + {2600, {wxAuiPaneInfo, dock, 0}}, + {2601, {wxAuiPaneInfo, dockable, 1}}, + {2602, {wxAuiPaneInfo, fixed, 0}}, + {2603, {wxAuiPaneInfo, float, 0}}, + {2604, {wxAuiPaneInfo, floatable, 1}}, + {2605, {wxAuiPaneInfo, floatingPosition_1, 1}}, + {2606, {wxAuiPaneInfo, floatingPosition_2, 2}}, + {2607, {wxAuiPaneInfo, floatingSize_1, 1}}, + {2608, {wxAuiPaneInfo, floatingSize_2, 2}}, + {2609, {wxAuiPaneInfo, gripper, 1}}, + {2610, {wxAuiPaneInfo, gripperTop, 1}}, + {2611, {wxAuiPaneInfo, hasBorder, 0}}, + {2612, {wxAuiPaneInfo, hasCaption, 0}}, + {2613, {wxAuiPaneInfo, hasCloseButton, 0}}, + {2614, {wxAuiPaneInfo, hasFlag, 1}}, + {2615, {wxAuiPaneInfo, hasGripper, 0}}, + {2616, {wxAuiPaneInfo, hasGripperTop, 0}}, + {2617, {wxAuiPaneInfo, hasMaximizeButton, 0}}, + {2618, {wxAuiPaneInfo, hasMinimizeButton, 0}}, + {2619, {wxAuiPaneInfo, hasPinButton, 0}}, + {2620, {wxAuiPaneInfo, hide, 0}}, + {2621, {wxAuiPaneInfo, isBottomDockable, 0}}, + {2622, {wxAuiPaneInfo, isDocked, 0}}, + {2623, {wxAuiPaneInfo, isFixed, 0}}, + {2624, {wxAuiPaneInfo, isFloatable, 0}}, + {2625, {wxAuiPaneInfo, isFloating, 0}}, + {2626, {wxAuiPaneInfo, isLeftDockable, 0}}, + {2627, {wxAuiPaneInfo, isMovable, 0}}, + {2628, {wxAuiPaneInfo, isOk, 0}}, + {2629, {wxAuiPaneInfo, isResizable, 0}}, + {2630, {wxAuiPaneInfo, isRightDockable, 0}}, + {2631, {wxAuiPaneInfo, isShown, 0}}, + {2632, {wxAuiPaneInfo, isToolbar, 0}}, + {2633, {wxAuiPaneInfo, isTopDockable, 0}}, + {2634, {wxAuiPaneInfo, layer, 1}}, + {2635, {wxAuiPaneInfo, left, 0}}, + {2636, {wxAuiPaneInfo, leftDockable, 1}}, + {2637, {wxAuiPaneInfo, maxSize_1, 1}}, + {2638, {wxAuiPaneInfo, maxSize_2, 2}}, + {2639, {wxAuiPaneInfo, maximizeButton, 1}}, + {2640, {wxAuiPaneInfo, minSize_1, 1}}, + {2641, {wxAuiPaneInfo, minSize_2, 2}}, + {2642, {wxAuiPaneInfo, minimizeButton, 1}}, + {2643, {wxAuiPaneInfo, movable, 1}}, + {2644, {wxAuiPaneInfo, name, 1}}, + {2645, {wxAuiPaneInfo, paneBorder, 1}}, + {2646, {wxAuiPaneInfo, pinButton, 1}}, + {2647, {wxAuiPaneInfo, position, 1}}, + {2648, {wxAuiPaneInfo, resizable, 1}}, + {2649, {wxAuiPaneInfo, right, 0}}, + {2650, {wxAuiPaneInfo, rightDockable, 1}}, + {2651, {wxAuiPaneInfo, row, 1}}, + {2652, {wxAuiPaneInfo, safeSet, 1}}, + {2653, {wxAuiPaneInfo, setFlag, 2}}, + {2654, {wxAuiPaneInfo, show, 1}}, + {2655, {wxAuiPaneInfo, toolbarPane, 0}}, + {2656, {wxAuiPaneInfo, top, 0}}, + {2657, {wxAuiPaneInfo, topDockable, 1}}, + {2658, {wxAuiPaneInfo, window, 1}}, + {2659, {wxAuiPaneInfo, getWindow, 0}}, + {2660, {wxAuiPaneInfo, getFrame, 0}}, + {2661, {wxAuiPaneInfo, getDirection, 0}}, + {2662, {wxAuiPaneInfo, getLayer, 0}}, + {2663, {wxAuiPaneInfo, getRow, 0}}, + {2664, {wxAuiPaneInfo, getPosition, 0}}, + {2665, {wxAuiPaneInfo, getFloatingPosition, 0}}, + {2666, {wxAuiPaneInfo, getFloatingSize, 0}}, + {2667, {wxAuiNotebook, new_0, 0}}, + {2668, {wxAuiNotebook, new_2, 2}}, + {2669, {wxAuiNotebook, addPage, 3}}, + {2670, {wxAuiNotebook, create, 2}}, + {2671, {wxAuiNotebook, deletePage, 1}}, + {2672, {wxAuiNotebook, getArtProvider, 0}}, + {2673, {wxAuiNotebook, getPage, 1}}, + {2674, {wxAuiNotebook, getPageBitmap, 1}}, + {2675, {wxAuiNotebook, getPageCount, 0}}, + {2676, {wxAuiNotebook, getPageIndex, 1}}, + {2677, {wxAuiNotebook, getPageText, 1}}, + {2678, {wxAuiNotebook, getSelection, 0}}, + {2679, {wxAuiNotebook, insertPage, 4}}, + {2680, {wxAuiNotebook, removePage, 1}}, + {2681, {wxAuiNotebook, setArtProvider, 1}}, + {2682, {wxAuiNotebook, setFont, 1}}, + {2683, {wxAuiNotebook, setPageBitmap, 2}}, + {2684, {wxAuiNotebook, setPageText, 2}}, + {2685, {wxAuiNotebook, setSelection, 1}}, + {2686, {wxAuiNotebook, setTabCtrlHeight, 1}}, + {2687, {wxAuiNotebook, setUniformBitmapSize, 1}}, + {2688, {wxAuiNotebook, 'Destroy', undefined}}, + {2689, {wxAuiTabArt, setFlags, 1}}, + {2690, {wxAuiTabArt, setMeasuringFont, 1}}, + {2691, {wxAuiTabArt, setNormalFont, 1}}, + {2692, {wxAuiTabArt, setSelectedFont, 1}}, + {2693, {wxAuiTabArt, setColour, 1}}, + {2694, {wxAuiTabArt, setActiveColour, 1}}, + {2695, {wxAuiDockArt, getColour, 1}}, + {2696, {wxAuiDockArt, getFont, 1}}, + {2697, {wxAuiDockArt, getMetric, 1}}, + {2698, {wxAuiDockArt, setColour, 2}}, + {2699, {wxAuiDockArt, setFont, 2}}, + {2700, {wxAuiDockArt, setMetric, 2}}, + {2701, {wxAuiSimpleTabArt, new, 0}}, + {2702, {wxAuiSimpleTabArt, 'Destroy', undefined}}, + {2703, {wxMDIParentFrame, new_0, 0}}, + {2704, {wxMDIParentFrame, new_4, 4}}, + {2705, {wxMDIParentFrame, destruct, 0}}, + {2706, {wxMDIParentFrame, activateNext, 0}}, + {2707, {wxMDIParentFrame, activatePrevious, 0}}, + {2708, {wxMDIParentFrame, arrangeIcons, 0}}, + {2709, {wxMDIParentFrame, cascade, 0}}, + {2710, {wxMDIParentFrame, create, 4}}, + {2711, {wxMDIParentFrame, getActiveChild, 0}}, + {2712, {wxMDIParentFrame, getClientWindow, 0}}, + {2713, {wxMDIParentFrame, tile, 1}}, + {2714, {wxMDIChildFrame, new_0, 0}}, + {2715, {wxMDIChildFrame, new_4, 4}}, + {2716, {wxMDIChildFrame, destruct, 0}}, + {2717, {wxMDIChildFrame, activate, 0}}, + {2718, {wxMDIChildFrame, create, 4}}, + {2719, {wxMDIChildFrame, maximize, 1}}, + {2720, {wxMDIChildFrame, restore, 0}}, + {2721, {wxMDIClientWindow, new_0, 0}}, + {2722, {wxMDIClientWindow, new_2, 2}}, + {2723, {wxMDIClientWindow, destruct, 0}}, + {2724, {wxMDIClientWindow, createClient, 2}}, + {2725, {wxLayoutAlgorithm, new, 0}}, + {2726, {wxLayoutAlgorithm, layoutFrame, 2}}, + {2727, {wxLayoutAlgorithm, layoutMDIFrame, 2}}, + {2728, {wxLayoutAlgorithm, layoutWindow, 2}}, + {2729, {wxLayoutAlgorithm, 'Destroy', undefined}}, + {2730, {wxEvent, getId, 0}}, + {2731, {wxEvent, getSkipped, 0}}, + {2732, {wxEvent, getTimestamp, 0}}, + {2733, {wxEvent, isCommandEvent, 0}}, + {2734, {wxEvent, resumePropagation, 1}}, + {2735, {wxEvent, shouldPropagate, 0}}, + {2736, {wxEvent, skip, 1}}, + {2737, {wxEvent, stopPropagation, 0}}, + {2738, {wxCommandEvent, getClientData, 0}}, + {2739, {wxCommandEvent, getExtraLong, 0}}, + {2740, {wxCommandEvent, getInt, 0}}, + {2741, {wxCommandEvent, getSelection, 0}}, + {2742, {wxCommandEvent, getString, 0}}, + {2743, {wxCommandEvent, isChecked, 0}}, + {2744, {wxCommandEvent, isSelection, 0}}, + {2745, {wxCommandEvent, setInt, 1}}, + {2746, {wxCommandEvent, setString, 1}}, + {2747, {wxScrollEvent, getOrientation, 0}}, + {2748, {wxScrollEvent, getPosition, 0}}, + {2749, {wxScrollWinEvent, getOrientation, 0}}, + {2750, {wxScrollWinEvent, getPosition, 0}}, + {2751, {wxMouseEvent, altDown, 0}}, + {2752, {wxMouseEvent, button, 1}}, + {2753, {wxMouseEvent, buttonDClick, 1}}, + {2754, {wxMouseEvent, buttonDown, 1}}, + {2755, {wxMouseEvent, buttonUp, 1}}, + {2756, {wxMouseEvent, cmdDown, 0}}, + {2757, {wxMouseEvent, controlDown, 0}}, + {2758, {wxMouseEvent, dragging, 0}}, + {2759, {wxMouseEvent, entering, 0}}, + {2760, {wxMouseEvent, getButton, 0}}, + {2763, {wxMouseEvent, getPosition, 0}}, + {2764, {wxMouseEvent, getLogicalPosition, 1}}, + {2765, {wxMouseEvent, getLinesPerAction, 0}}, + {2766, {wxMouseEvent, getWheelRotation, 0}}, + {2767, {wxMouseEvent, getWheelDelta, 0}}, + {2768, {wxMouseEvent, getX, 0}}, + {2769, {wxMouseEvent, getY, 0}}, + {2770, {wxMouseEvent, isButton, 0}}, + {2771, {wxMouseEvent, isPageScroll, 0}}, + {2772, {wxMouseEvent, leaving, 0}}, + {2773, {wxMouseEvent, leftDClick, 0}}, + {2774, {wxMouseEvent, leftDown, 0}}, + {2775, {wxMouseEvent, leftIsDown, 0}}, + {2776, {wxMouseEvent, leftUp, 0}}, + {2777, {wxMouseEvent, metaDown, 0}}, + {2778, {wxMouseEvent, middleDClick, 0}}, + {2779, {wxMouseEvent, middleDown, 0}}, + {2780, {wxMouseEvent, middleIsDown, 0}}, + {2781, {wxMouseEvent, middleUp, 0}}, + {2782, {wxMouseEvent, moving, 0}}, + {2783, {wxMouseEvent, rightDClick, 0}}, + {2784, {wxMouseEvent, rightDown, 0}}, + {2785, {wxMouseEvent, rightIsDown, 0}}, + {2786, {wxMouseEvent, rightUp, 0}}, + {2787, {wxMouseEvent, shiftDown, 0}}, + {2788, {wxSetCursorEvent, getCursor, 0}}, + {2789, {wxSetCursorEvent, getX, 0}}, + {2790, {wxSetCursorEvent, getY, 0}}, + {2791, {wxSetCursorEvent, hasCursor, 0}}, + {2792, {wxSetCursorEvent, setCursor, 1}}, + {2793, {wxKeyEvent, altDown, 0}}, + {2794, {wxKeyEvent, cmdDown, 0}}, + {2795, {wxKeyEvent, controlDown, 0}}, + {2796, {wxKeyEvent, getKeyCode, 0}}, + {2797, {wxKeyEvent, getModifiers, 0}}, + {2800, {wxKeyEvent, getPosition, 0}}, + {2801, {wxKeyEvent, getRawKeyCode, 0}}, + {2802, {wxKeyEvent, getRawKeyFlags, 0}}, + {2803, {wxKeyEvent, getUnicodeKey, 0}}, + {2804, {wxKeyEvent, getX, 0}}, + {2805, {wxKeyEvent, getY, 0}}, + {2806, {wxKeyEvent, hasModifiers, 0}}, + {2807, {wxKeyEvent, metaDown, 0}}, + {2808, {wxKeyEvent, shiftDown, 0}}, + {2809, {wxSizeEvent, getSize, 0}}, + {2810, {wxMoveEvent, getPosition, 0}}, + {2811, {wxEraseEvent, getDC, 0}}, + {2812, {wxFocusEvent, getWindow, 0}}, + {2813, {wxChildFocusEvent, getWindow, 0}}, + {2814, {wxMenuEvent, getMenu, 0}}, + {2815, {wxMenuEvent, getMenuId, 0}}, + {2816, {wxMenuEvent, isPopup, 0}}, + {2817, {wxCloseEvent, canVeto, 0}}, + {2818, {wxCloseEvent, getLoggingOff, 0}}, + {2819, {wxCloseEvent, setCanVeto, 1}}, + {2820, {wxCloseEvent, setLoggingOff, 1}}, + {2821, {wxCloseEvent, veto, 1}}, + {2822, {wxShowEvent, setShow, 1}}, + {2823, {wxShowEvent, getShow, 0}}, + {2824, {wxIconizeEvent, iconized, 0}}, + {2825, {wxJoystickEvent, buttonDown, 1}}, + {2826, {wxJoystickEvent, buttonIsDown, 1}}, + {2827, {wxJoystickEvent, buttonUp, 1}}, + {2828, {wxJoystickEvent, getButtonChange, 0}}, + {2829, {wxJoystickEvent, getButtonState, 0}}, + {2830, {wxJoystickEvent, getJoystick, 0}}, + {2831, {wxJoystickEvent, getPosition, 0}}, + {2832, {wxJoystickEvent, getZPosition, 0}}, + {2833, {wxJoystickEvent, isButton, 0}}, + {2834, {wxJoystickEvent, isMove, 0}}, + {2835, {wxJoystickEvent, isZMove, 0}}, + {2836, {wxUpdateUIEvent, canUpdate, 1}}, + {2837, {wxUpdateUIEvent, check, 1}}, + {2838, {wxUpdateUIEvent, enable, 1}}, + {2839, {wxUpdateUIEvent, show, 1}}, + {2840, {wxUpdateUIEvent, getChecked, 0}}, + {2841, {wxUpdateUIEvent, getEnabled, 0}}, + {2842, {wxUpdateUIEvent, getShown, 0}}, + {2843, {wxUpdateUIEvent, getSetChecked, 0}}, + {2844, {wxUpdateUIEvent, getSetEnabled, 0}}, + {2845, {wxUpdateUIEvent, getSetShown, 0}}, + {2846, {wxUpdateUIEvent, getSetText, 0}}, + {2847, {wxUpdateUIEvent, getText, 0}}, + {2848, {wxUpdateUIEvent, getMode, 0}}, + {2849, {wxUpdateUIEvent, getUpdateInterval, 0}}, + {2850, {wxUpdateUIEvent, resetUpdateTime, 0}}, + {2851, {wxUpdateUIEvent, setMode, 1}}, + {2852, {wxUpdateUIEvent, setText, 1}}, + {2853, {wxUpdateUIEvent, setUpdateInterval, 1}}, + {2854, {wxMouseCaptureChangedEvent, getCapturedWindow, 0}}, + {2855, {wxPaletteChangedEvent, setChangedWindow, 1}}, + {2856, {wxPaletteChangedEvent, getChangedWindow, 0}}, + {2857, {wxQueryNewPaletteEvent, setPaletteRealized, 1}}, + {2858, {wxQueryNewPaletteEvent, getPaletteRealized, 0}}, + {2859, {wxNavigationKeyEvent, getDirection, 0}}, + {2860, {wxNavigationKeyEvent, setDirection, 1}}, + {2861, {wxNavigationKeyEvent, isWindowChange, 0}}, + {2862, {wxNavigationKeyEvent, setWindowChange, 1}}, + {2863, {wxNavigationKeyEvent, isFromTab, 0}}, + {2864, {wxNavigationKeyEvent, setFromTab, 1}}, + {2865, {wxNavigationKeyEvent, getCurrentFocus, 0}}, + {2866, {wxNavigationKeyEvent, setCurrentFocus, 1}}, + {2867, {wxHelpEvent, getOrigin, 0}}, + {2868, {wxHelpEvent, getPosition, 0}}, + {2869, {wxHelpEvent, setOrigin, 1}}, + {2870, {wxHelpEvent, setPosition, 1}}, + {2871, {wxContextMenuEvent, getPosition, 0}}, + {2872, {wxContextMenuEvent, setPosition, 1}}, + {2873, {wxIdleEvent, canSend, 1}}, + {2874, {wxIdleEvent, getMode, 0}}, + {2875, {wxIdleEvent, requestMore, 1}}, + {2876, {wxIdleEvent, moreRequested, 0}}, + {2877, {wxIdleEvent, setMode, 1}}, + {2878, {wxGridEvent, altDown, 0}}, + {2879, {wxGridEvent, controlDown, 0}}, + {2880, {wxGridEvent, getCol, 0}}, + {2881, {wxGridEvent, getPosition, 0}}, + {2882, {wxGridEvent, getRow, 0}}, + {2883, {wxGridEvent, metaDown, 0}}, + {2884, {wxGridEvent, selecting, 0}}, + {2885, {wxGridEvent, shiftDown, 0}}, + {2886, {wxNotifyEvent, allow, 0}}, + {2887, {wxNotifyEvent, isAllowed, 0}}, + {2888, {wxNotifyEvent, veto, 0}}, + {2889, {wxSashEvent, getEdge, 0}}, + {2890, {wxSashEvent, getDragRect, 0}}, + {2891, {wxSashEvent, getDragStatus, 0}}, + {2892, {wxListEvent, getCacheFrom, 0}}, + {2893, {wxListEvent, getCacheTo, 0}}, + {2894, {wxListEvent, getKeyCode, 0}}, + {2895, {wxListEvent, getIndex, 0}}, + {2896, {wxListEvent, getColumn, 0}}, + {2897, {wxListEvent, getPoint, 0}}, + {2898, {wxListEvent, getLabel, 0}}, + {2899, {wxListEvent, getText, 0}}, + {2900, {wxListEvent, getImage, 0}}, + {2901, {wxListEvent, getData, 0}}, + {2902, {wxListEvent, getMask, 0}}, + {2903, {wxListEvent, getItem, 0}}, + {2904, {wxListEvent, isEditCancelled, 0}}, + {2905, {wxDateEvent, getDate, 0}}, + {2906, {wxCalendarEvent, getWeekDay, 0}}, + {2907, {wxFileDirPickerEvent, getPath, 0}}, + {2908, {wxColourPickerEvent, getColour, 0}}, + {2909, {wxFontPickerEvent, getFont, 0}}, + {2910, {wxStyledTextEvent, getPosition, 0}}, + {2911, {wxStyledTextEvent, getKey, 0}}, + {2912, {wxStyledTextEvent, getModifiers, 0}}, + {2913, {wxStyledTextEvent, getModificationType, 0}}, + {2914, {wxStyledTextEvent, getText, 0}}, + {2915, {wxStyledTextEvent, getLength, 0}}, + {2916, {wxStyledTextEvent, getLinesAdded, 0}}, + {2917, {wxStyledTextEvent, getLine, 0}}, + {2918, {wxStyledTextEvent, getFoldLevelNow, 0}}, + {2919, {wxStyledTextEvent, getFoldLevelPrev, 0}}, + {2920, {wxStyledTextEvent, getMargin, 0}}, + {2921, {wxStyledTextEvent, getMessage, 0}}, + {2922, {wxStyledTextEvent, getWParam, 0}}, + {2923, {wxStyledTextEvent, getLParam, 0}}, + {2924, {wxStyledTextEvent, getListType, 0}}, + {2925, {wxStyledTextEvent, getX, 0}}, + {2926, {wxStyledTextEvent, getY, 0}}, + {2927, {wxStyledTextEvent, getDragText, 0}}, + {2928, {wxStyledTextEvent, getDragAllowMove, 0}}, + {2929, {wxStyledTextEvent, getDragResult, 0}}, + {2930, {wxStyledTextEvent, getShift, 0}}, + {2931, {wxStyledTextEvent, getControl, 0}}, + {2932, {wxStyledTextEvent, getAlt, 0}}, + {2933, {utils, getKeyState, 1}}, + {2934, {utils, getMousePosition, 2}}, + {2935, {utils, getMouseState, 0}}, + {2936, {utils, setDetectableAutoRepeat, 1}}, + {2937, {utils, bell, 0}}, + {2938, {utils, findMenuItemId, 3}}, + {2939, {utils, genericFindWindowAtPoint, 1}}, + {2940, {utils, findWindowAtPoint, 1}}, + {2941, {utils, beginBusyCursor, 1}}, + {2942, {utils, endBusyCursor, 0}}, + {2943, {utils, isBusy, 0}}, + {2944, {utils, shutdown, 1}}, + {2945, {utils, shell, 1}}, + {2946, {utils, launchDefaultBrowser, 2}}, + {2947, {utils, getEmailAddress, 0}}, + {2948, {utils, getUserId, 0}}, + {2949, {utils, getHomeDir, 0}}, + {2950, {utils, newId, 0}}, + {2951, {utils, registerId, 1}}, + {2952, {utils, getCurrentId, 0}}, + {2953, {utils, getOsDescription, 0}}, + {2954, {utils, isPlatformLittleEndian, 0}}, + {2955, {utils, isPlatform64Bit, 0}}, + {2956, {gdicmn, displaySize, 2}}, + {2957, {gdicmn, setCursor, 1}}, + {2958, {wxPrintout, new, 1}}, + {2959, {wxPrintout, destruct, 0}}, + {2960, {wxPrintout, getDC, 0}}, + {2961, {wxPrintout, getPageSizeMM, 2}}, + {2962, {wxPrintout, getPageSizePixels, 2}}, + {2963, {wxPrintout, getPaperRectPixels, 0}}, + {2964, {wxPrintout, getPPIPrinter, 2}}, + {2965, {wxPrintout, getPPIScreen, 2}}, + {2966, {wxPrintout, getTitle, 0}}, + {2967, {wxPrintout, isPreview, 0}}, + {2968, {wxPrintout, fitThisSizeToPaper, 1}}, + {2969, {wxPrintout, fitThisSizeToPage, 1}}, + {2970, {wxPrintout, fitThisSizeToPageMargins, 2}}, + {2971, {wxPrintout, mapScreenSizeToPaper, 0}}, + {2972, {wxPrintout, mapScreenSizeToPage, 0}}, + {2973, {wxPrintout, mapScreenSizeToPageMargins, 1}}, + {2974, {wxPrintout, mapScreenSizeToDevice, 0}}, + {2975, {wxPrintout, getLogicalPaperRect, 0}}, + {2976, {wxPrintout, getLogicalPageRect, 0}}, + {2977, {wxPrintout, getLogicalPageMarginsRect, 1}}, + {2978, {wxPrintout, setLogicalOrigin, 2}}, + {2979, {wxPrintout, offsetLogicalOrigin, 2}}, + {2980, {wxStyledTextCtrl, new_2, 2}}, + {2981, {wxStyledTextCtrl, new_0, 0}}, + {2982, {wxStyledTextCtrl, destruct, 0}}, + {2983, {wxStyledTextCtrl, create, 2}}, + {2984, {wxStyledTextCtrl, addText, 1}}, + {2985, {wxStyledTextCtrl, addStyledText, 1}}, + {2986, {wxStyledTextCtrl, insertText, 2}}, + {2987, {wxStyledTextCtrl, clearAll, 0}}, + {2988, {wxStyledTextCtrl, clearDocumentStyle, 0}}, + {2989, {wxStyledTextCtrl, getLength, 0}}, + {2990, {wxStyledTextCtrl, getCharAt, 1}}, + {2991, {wxStyledTextCtrl, getCurrentPos, 0}}, + {2992, {wxStyledTextCtrl, getAnchor, 0}}, + {2993, {wxStyledTextCtrl, getStyleAt, 1}}, + {2994, {wxStyledTextCtrl, redo, 0}}, + {2995, {wxStyledTextCtrl, setUndoCollection, 1}}, + {2996, {wxStyledTextCtrl, selectAll, 0}}, + {2997, {wxStyledTextCtrl, setSavePoint, 0}}, + {2998, {wxStyledTextCtrl, getStyledText, 2}}, + {2999, {wxStyledTextCtrl, canRedo, 0}}, + {3000, {wxStyledTextCtrl, markerLineFromHandle, 1}}, + {3001, {wxStyledTextCtrl, markerDeleteHandle, 1}}, + {3002, {wxStyledTextCtrl, getUndoCollection, 0}}, + {3003, {wxStyledTextCtrl, getViewWhiteSpace, 0}}, + {3004, {wxStyledTextCtrl, setViewWhiteSpace, 1}}, + {3005, {wxStyledTextCtrl, positionFromPoint, 1}}, + {3006, {wxStyledTextCtrl, positionFromPointClose, 2}}, + {3007, {wxStyledTextCtrl, gotoLine, 1}}, + {3008, {wxStyledTextCtrl, gotoPos, 1}}, + {3009, {wxStyledTextCtrl, setAnchor, 1}}, + {3010, {wxStyledTextCtrl, getCurLine, 1}}, + {3011, {wxStyledTextCtrl, getEndStyled, 0}}, + {3012, {wxStyledTextCtrl, convertEOLs, 1}}, + {3013, {wxStyledTextCtrl, getEOLMode, 0}}, + {3014, {wxStyledTextCtrl, setEOLMode, 1}}, + {3015, {wxStyledTextCtrl, startStyling, 2}}, + {3016, {wxStyledTextCtrl, setStyling, 2}}, + {3017, {wxStyledTextCtrl, getBufferedDraw, 0}}, + {3018, {wxStyledTextCtrl, setBufferedDraw, 1}}, + {3019, {wxStyledTextCtrl, setTabWidth, 1}}, + {3020, {wxStyledTextCtrl, getTabWidth, 0}}, + {3021, {wxStyledTextCtrl, setCodePage, 1}}, + {3022, {wxStyledTextCtrl, markerDefine, 3}}, + {3023, {wxStyledTextCtrl, markerSetForeground, 2}}, + {3024, {wxStyledTextCtrl, markerSetBackground, 2}}, + {3025, {wxStyledTextCtrl, markerAdd, 2}}, + {3026, {wxStyledTextCtrl, markerDelete, 2}}, + {3027, {wxStyledTextCtrl, markerDeleteAll, 1}}, + {3028, {wxStyledTextCtrl, markerGet, 1}}, + {3029, {wxStyledTextCtrl, markerNext, 2}}, + {3030, {wxStyledTextCtrl, markerPrevious, 2}}, + {3031, {wxStyledTextCtrl, markerDefineBitmap, 2}}, + {3032, {wxStyledTextCtrl, markerAddSet, 2}}, + {3033, {wxStyledTextCtrl, markerSetAlpha, 2}}, + {3034, {wxStyledTextCtrl, setMarginType, 2}}, + {3035, {wxStyledTextCtrl, getMarginType, 1}}, + {3036, {wxStyledTextCtrl, setMarginWidth, 2}}, + {3037, {wxStyledTextCtrl, getMarginWidth, 1}}, + {3038, {wxStyledTextCtrl, setMarginMask, 2}}, + {3039, {wxStyledTextCtrl, getMarginMask, 1}}, + {3040, {wxStyledTextCtrl, setMarginSensitive, 2}}, + {3041, {wxStyledTextCtrl, getMarginSensitive, 1}}, + {3042, {wxStyledTextCtrl, styleClearAll, 0}}, + {3043, {wxStyledTextCtrl, styleSetForeground, 2}}, + {3044, {wxStyledTextCtrl, styleSetBackground, 2}}, + {3045, {wxStyledTextCtrl, styleSetBold, 2}}, + {3046, {wxStyledTextCtrl, styleSetItalic, 2}}, + {3047, {wxStyledTextCtrl, styleSetSize, 2}}, + {3048, {wxStyledTextCtrl, styleSetFaceName, 2}}, + {3049, {wxStyledTextCtrl, styleSetEOLFilled, 2}}, + {3050, {wxStyledTextCtrl, styleResetDefault, 0}}, + {3051, {wxStyledTextCtrl, styleSetUnderline, 2}}, + {3052, {wxStyledTextCtrl, styleSetCase, 2}}, + {3053, {wxStyledTextCtrl, styleSetHotSpot, 2}}, + {3054, {wxStyledTextCtrl, setSelForeground, 2}}, + {3055, {wxStyledTextCtrl, setSelBackground, 2}}, + {3056, {wxStyledTextCtrl, getSelAlpha, 0}}, + {3057, {wxStyledTextCtrl, setSelAlpha, 1}}, + {3058, {wxStyledTextCtrl, setCaretForeground, 1}}, + {3059, {wxStyledTextCtrl, cmdKeyAssign, 3}}, + {3060, {wxStyledTextCtrl, cmdKeyClear, 2}}, + {3061, {wxStyledTextCtrl, cmdKeyClearAll, 0}}, + {3062, {wxStyledTextCtrl, setStyleBytes, 2}}, + {3063, {wxStyledTextCtrl, styleSetVisible, 2}}, + {3064, {wxStyledTextCtrl, getCaretPeriod, 0}}, + {3065, {wxStyledTextCtrl, setCaretPeriod, 1}}, + {3066, {wxStyledTextCtrl, setWordChars, 1}}, + {3067, {wxStyledTextCtrl, beginUndoAction, 0}}, + {3068, {wxStyledTextCtrl, endUndoAction, 0}}, + {3069, {wxStyledTextCtrl, indicatorSetStyle, 2}}, + {3070, {wxStyledTextCtrl, indicatorGetStyle, 1}}, + {3071, {wxStyledTextCtrl, indicatorSetForeground, 2}}, + {3072, {wxStyledTextCtrl, indicatorGetForeground, 1}}, + {3073, {wxStyledTextCtrl, setWhitespaceForeground, 2}}, + {3074, {wxStyledTextCtrl, setWhitespaceBackground, 2}}, + {3075, {wxStyledTextCtrl, getStyleBits, 0}}, + {3076, {wxStyledTextCtrl, setLineState, 2}}, + {3077, {wxStyledTextCtrl, getLineState, 1}}, + {3078, {wxStyledTextCtrl, getMaxLineState, 0}}, + {3079, {wxStyledTextCtrl, getCaretLineVisible, 0}}, + {3080, {wxStyledTextCtrl, setCaretLineVisible, 1}}, + {3081, {wxStyledTextCtrl, getCaretLineBackground, 0}}, + {3082, {wxStyledTextCtrl, setCaretLineBackground, 1}}, + {3083, {wxStyledTextCtrl, autoCompShow, 2}}, + {3084, {wxStyledTextCtrl, autoCompCancel, 0}}, + {3085, {wxStyledTextCtrl, autoCompActive, 0}}, + {3086, {wxStyledTextCtrl, autoCompPosStart, 0}}, + {3087, {wxStyledTextCtrl, autoCompComplete, 0}}, + {3088, {wxStyledTextCtrl, autoCompStops, 1}}, + {3089, {wxStyledTextCtrl, autoCompSetSeparator, 1}}, + {3090, {wxStyledTextCtrl, autoCompGetSeparator, 0}}, + {3091, {wxStyledTextCtrl, autoCompSelect, 1}}, + {3092, {wxStyledTextCtrl, autoCompSetCancelAtStart, 1}}, + {3093, {wxStyledTextCtrl, autoCompGetCancelAtStart, 0}}, + {3094, {wxStyledTextCtrl, autoCompSetFillUps, 1}}, + {3095, {wxStyledTextCtrl, autoCompSetChooseSingle, 1}}, + {3096, {wxStyledTextCtrl, autoCompGetChooseSingle, 0}}, + {3097, {wxStyledTextCtrl, autoCompSetIgnoreCase, 1}}, + {3098, {wxStyledTextCtrl, autoCompGetIgnoreCase, 0}}, + {3099, {wxStyledTextCtrl, userListShow, 2}}, + {3100, {wxStyledTextCtrl, autoCompSetAutoHide, 1}}, + {3101, {wxStyledTextCtrl, autoCompGetAutoHide, 0}}, + {3102, {wxStyledTextCtrl, autoCompSetDropRestOfWord, 1}}, + {3103, {wxStyledTextCtrl, autoCompGetDropRestOfWord, 0}}, + {3104, {wxStyledTextCtrl, registerImage, 2}}, + {3105, {wxStyledTextCtrl, clearRegisteredImages, 0}}, + {3106, {wxStyledTextCtrl, autoCompGetTypeSeparator, 0}}, + {3107, {wxStyledTextCtrl, autoCompSetTypeSeparator, 1}}, + {3108, {wxStyledTextCtrl, autoCompSetMaxWidth, 1}}, + {3109, {wxStyledTextCtrl, autoCompGetMaxWidth, 0}}, + {3110, {wxStyledTextCtrl, autoCompSetMaxHeight, 1}}, + {3111, {wxStyledTextCtrl, autoCompGetMaxHeight, 0}}, + {3112, {wxStyledTextCtrl, setIndent, 1}}, + {3113, {wxStyledTextCtrl, getIndent, 0}}, + {3114, {wxStyledTextCtrl, setUseTabs, 1}}, + {3115, {wxStyledTextCtrl, getUseTabs, 0}}, + {3116, {wxStyledTextCtrl, setLineIndentation, 2}}, + {3117, {wxStyledTextCtrl, getLineIndentation, 1}}, + {3118, {wxStyledTextCtrl, getLineIndentPosition, 1}}, + {3119, {wxStyledTextCtrl, getColumn, 1}}, + {3120, {wxStyledTextCtrl, setUseHorizontalScrollBar, 1}}, + {3121, {wxStyledTextCtrl, getUseHorizontalScrollBar, 0}}, + {3122, {wxStyledTextCtrl, setIndentationGuides, 1}}, + {3123, {wxStyledTextCtrl, getIndentationGuides, 0}}, + {3124, {wxStyledTextCtrl, setHighlightGuide, 1}}, + {3125, {wxStyledTextCtrl, getHighlightGuide, 0}}, + {3126, {wxStyledTextCtrl, getLineEndPosition, 1}}, + {3127, {wxStyledTextCtrl, getCodePage, 0}}, + {3128, {wxStyledTextCtrl, getCaretForeground, 0}}, + {3129, {wxStyledTextCtrl, getReadOnly, 0}}, + {3130, {wxStyledTextCtrl, setCurrentPos, 1}}, + {3131, {wxStyledTextCtrl, setSelectionStart, 1}}, + {3132, {wxStyledTextCtrl, getSelectionStart, 0}}, + {3133, {wxStyledTextCtrl, setSelectionEnd, 1}}, + {3134, {wxStyledTextCtrl, getSelectionEnd, 0}}, + {3135, {wxStyledTextCtrl, setPrintMagnification, 1}}, + {3136, {wxStyledTextCtrl, getPrintMagnification, 0}}, + {3137, {wxStyledTextCtrl, setPrintColourMode, 1}}, + {3138, {wxStyledTextCtrl, getPrintColourMode, 0}}, + {3139, {wxStyledTextCtrl, findText, 4}}, + {3140, {wxStyledTextCtrl, formatRange, 7}}, + {3141, {wxStyledTextCtrl, getFirstVisibleLine, 0}}, + {3142, {wxStyledTextCtrl, getLine, 1}}, + {3143, {wxStyledTextCtrl, getLineCount, 0}}, + {3144, {wxStyledTextCtrl, setMarginLeft, 1}}, + {3145, {wxStyledTextCtrl, getMarginLeft, 0}}, + {3146, {wxStyledTextCtrl, setMarginRight, 1}}, + {3147, {wxStyledTextCtrl, getMarginRight, 0}}, + {3148, {wxStyledTextCtrl, getModify, 0}}, + {3149, {wxStyledTextCtrl, setSelection, 2}}, + {3150, {wxStyledTextCtrl, getSelectedText, 0}}, + {3151, {wxStyledTextCtrl, getTextRange, 2}}, + {3152, {wxStyledTextCtrl, hideSelection, 1}}, + {3153, {wxStyledTextCtrl, lineFromPosition, 1}}, + {3154, {wxStyledTextCtrl, positionFromLine, 1}}, + {3155, {wxStyledTextCtrl, lineScroll, 2}}, + {3156, {wxStyledTextCtrl, ensureCaretVisible, 0}}, + {3157, {wxStyledTextCtrl, replaceSelection, 1}}, + {3158, {wxStyledTextCtrl, setReadOnly, 1}}, + {3159, {wxStyledTextCtrl, canPaste, 0}}, + {3160, {wxStyledTextCtrl, canUndo, 0}}, + {3161, {wxStyledTextCtrl, emptyUndoBuffer, 0}}, + {3162, {wxStyledTextCtrl, undo, 0}}, + {3163, {wxStyledTextCtrl, cut, 0}}, + {3164, {wxStyledTextCtrl, copy, 0}}, + {3165, {wxStyledTextCtrl, paste, 0}}, + {3166, {wxStyledTextCtrl, clear, 0}}, + {3167, {wxStyledTextCtrl, setText, 1}}, + {3168, {wxStyledTextCtrl, getText, 0}}, + {3169, {wxStyledTextCtrl, getTextLength, 0}}, + {3170, {wxStyledTextCtrl, getOvertype, 0}}, + {3171, {wxStyledTextCtrl, setCaretWidth, 1}}, + {3172, {wxStyledTextCtrl, getCaretWidth, 0}}, + {3173, {wxStyledTextCtrl, setTargetStart, 1}}, + {3174, {wxStyledTextCtrl, getTargetStart, 0}}, + {3175, {wxStyledTextCtrl, setTargetEnd, 1}}, + {3176, {wxStyledTextCtrl, getTargetEnd, 0}}, + {3177, {wxStyledTextCtrl, replaceTarget, 1}}, + {3178, {wxStyledTextCtrl, searchInTarget, 1}}, + {3179, {wxStyledTextCtrl, setSearchFlags, 1}}, + {3180, {wxStyledTextCtrl, getSearchFlags, 0}}, + {3181, {wxStyledTextCtrl, callTipShow, 2}}, + {3182, {wxStyledTextCtrl, callTipCancel, 0}}, + {3183, {wxStyledTextCtrl, callTipActive, 0}}, + {3184, {wxStyledTextCtrl, callTipPosAtStart, 0}}, + {3185, {wxStyledTextCtrl, callTipSetHighlight, 2}}, + {3186, {wxStyledTextCtrl, callTipSetBackground, 1}}, + {3187, {wxStyledTextCtrl, callTipSetForeground, 1}}, + {3188, {wxStyledTextCtrl, callTipSetForegroundHighlight, 1}}, + {3189, {wxStyledTextCtrl, callTipUseStyle, 1}}, + {3190, {wxStyledTextCtrl, visibleFromDocLine, 1}}, + {3191, {wxStyledTextCtrl, docLineFromVisible, 1}}, + {3192, {wxStyledTextCtrl, wrapCount, 1}}, + {3193, {wxStyledTextCtrl, setFoldLevel, 2}}, + {3194, {wxStyledTextCtrl, getFoldLevel, 1}}, + {3195, {wxStyledTextCtrl, getLastChild, 2}}, + {3196, {wxStyledTextCtrl, getFoldParent, 1}}, + {3197, {wxStyledTextCtrl, showLines, 2}}, + {3198, {wxStyledTextCtrl, hideLines, 2}}, + {3199, {wxStyledTextCtrl, getLineVisible, 1}}, + {3200, {wxStyledTextCtrl, setFoldExpanded, 2}}, + {3201, {wxStyledTextCtrl, getFoldExpanded, 1}}, + {3202, {wxStyledTextCtrl, toggleFold, 1}}, + {3203, {wxStyledTextCtrl, ensureVisible, 1}}, + {3204, {wxStyledTextCtrl, setFoldFlags, 1}}, + {3205, {wxStyledTextCtrl, ensureVisibleEnforcePolicy, 1}}, + {3206, {wxStyledTextCtrl, setTabIndents, 1}}, + {3207, {wxStyledTextCtrl, getTabIndents, 0}}, + {3208, {wxStyledTextCtrl, setBackSpaceUnIndents, 1}}, + {3209, {wxStyledTextCtrl, getBackSpaceUnIndents, 0}}, + {3210, {wxStyledTextCtrl, setMouseDwellTime, 1}}, + {3211, {wxStyledTextCtrl, getMouseDwellTime, 0}}, + {3212, {wxStyledTextCtrl, wordStartPosition, 2}}, + {3213, {wxStyledTextCtrl, wordEndPosition, 2}}, + {3214, {wxStyledTextCtrl, setWrapMode, 1}}, + {3215, {wxStyledTextCtrl, getWrapMode, 0}}, + {3216, {wxStyledTextCtrl, setWrapVisualFlags, 1}}, + {3217, {wxStyledTextCtrl, getWrapVisualFlags, 0}}, + {3218, {wxStyledTextCtrl, setWrapVisualFlagsLocation, 1}}, + {3219, {wxStyledTextCtrl, getWrapVisualFlagsLocation, 0}}, + {3220, {wxStyledTextCtrl, setWrapStartIndent, 1}}, + {3221, {wxStyledTextCtrl, getWrapStartIndent, 0}}, + {3222, {wxStyledTextCtrl, setLayoutCache, 1}}, + {3223, {wxStyledTextCtrl, getLayoutCache, 0}}, + {3224, {wxStyledTextCtrl, setScrollWidth, 1}}, + {3225, {wxStyledTextCtrl, getScrollWidth, 0}}, + {3226, {wxStyledTextCtrl, textWidth, 2}}, + {3227, {wxStyledTextCtrl, getEndAtLastLine, 0}}, + {3228, {wxStyledTextCtrl, textHeight, 1}}, + {3229, {wxStyledTextCtrl, setUseVerticalScrollBar, 1}}, + {3230, {wxStyledTextCtrl, getUseVerticalScrollBar, 0}}, + {3231, {wxStyledTextCtrl, appendText, 1}}, + {3232, {wxStyledTextCtrl, getTwoPhaseDraw, 0}}, + {3233, {wxStyledTextCtrl, setTwoPhaseDraw, 1}}, + {3234, {wxStyledTextCtrl, targetFromSelection, 0}}, + {3235, {wxStyledTextCtrl, linesJoin, 0}}, + {3236, {wxStyledTextCtrl, linesSplit, 1}}, + {3237, {wxStyledTextCtrl, setFoldMarginColour, 2}}, + {3238, {wxStyledTextCtrl, setFoldMarginHiColour, 2}}, + {3239, {wxStyledTextCtrl, lineDown, 0}}, + {3240, {wxStyledTextCtrl, lineDownExtend, 0}}, + {3241, {wxStyledTextCtrl, lineUp, 0}}, + {3242, {wxStyledTextCtrl, lineUpExtend, 0}}, + {3243, {wxStyledTextCtrl, charLeft, 0}}, + {3244, {wxStyledTextCtrl, charLeftExtend, 0}}, + {3245, {wxStyledTextCtrl, charRight, 0}}, + {3246, {wxStyledTextCtrl, charRightExtend, 0}}, + {3247, {wxStyledTextCtrl, wordLeft, 0}}, + {3248, {wxStyledTextCtrl, wordLeftExtend, 0}}, + {3249, {wxStyledTextCtrl, wordRight, 0}}, + {3250, {wxStyledTextCtrl, wordRightExtend, 0}}, + {3251, {wxStyledTextCtrl, home, 0}}, + {3252, {wxStyledTextCtrl, homeExtend, 0}}, + {3253, {wxStyledTextCtrl, lineEnd, 0}}, + {3254, {wxStyledTextCtrl, lineEndExtend, 0}}, + {3255, {wxStyledTextCtrl, documentStart, 0}}, + {3256, {wxStyledTextCtrl, documentStartExtend, 0}}, + {3257, {wxStyledTextCtrl, documentEnd, 0}}, + {3258, {wxStyledTextCtrl, documentEndExtend, 0}}, + {3259, {wxStyledTextCtrl, pageUp, 0}}, + {3260, {wxStyledTextCtrl, pageUpExtend, 0}}, + {3261, {wxStyledTextCtrl, pageDown, 0}}, + {3262, {wxStyledTextCtrl, pageDownExtend, 0}}, + {3263, {wxStyledTextCtrl, editToggleOvertype, 0}}, + {3264, {wxStyledTextCtrl, cancel, 0}}, + {3265, {wxStyledTextCtrl, deleteBack, 0}}, + {3266, {wxStyledTextCtrl, tab, 0}}, + {3267, {wxStyledTextCtrl, backTab, 0}}, + {3268, {wxStyledTextCtrl, newLine, 0}}, + {3269, {wxStyledTextCtrl, formFeed, 0}}, + {3270, {wxStyledTextCtrl, vCHome, 0}}, + {3271, {wxStyledTextCtrl, vCHomeExtend, 0}}, + {3272, {wxStyledTextCtrl, zoomIn, 0}}, + {3273, {wxStyledTextCtrl, zoomOut, 0}}, + {3274, {wxStyledTextCtrl, delWordLeft, 0}}, + {3275, {wxStyledTextCtrl, delWordRight, 0}}, + {3276, {wxStyledTextCtrl, lineCut, 0}}, + {3277, {wxStyledTextCtrl, lineDelete, 0}}, + {3278, {wxStyledTextCtrl, lineTranspose, 0}}, + {3279, {wxStyledTextCtrl, lineDuplicate, 0}}, + {3280, {wxStyledTextCtrl, lowerCase, 0}}, + {3281, {wxStyledTextCtrl, upperCase, 0}}, + {3282, {wxStyledTextCtrl, lineScrollDown, 0}}, + {3283, {wxStyledTextCtrl, lineScrollUp, 0}}, + {3284, {wxStyledTextCtrl, deleteBackNotLine, 0}}, + {3285, {wxStyledTextCtrl, homeDisplay, 0}}, + {3286, {wxStyledTextCtrl, homeDisplayExtend, 0}}, + {3287, {wxStyledTextCtrl, lineEndDisplay, 0}}, + {3288, {wxStyledTextCtrl, lineEndDisplayExtend, 0}}, + {3289, {wxStyledTextCtrl, homeWrapExtend, 0}}, + {3290, {wxStyledTextCtrl, lineEndWrap, 0}}, + {3291, {wxStyledTextCtrl, lineEndWrapExtend, 0}}, + {3292, {wxStyledTextCtrl, vCHomeWrap, 0}}, + {3293, {wxStyledTextCtrl, vCHomeWrapExtend, 0}}, + {3294, {wxStyledTextCtrl, lineCopy, 0}}, + {3295, {wxStyledTextCtrl, moveCaretInsideView, 0}}, + {3296, {wxStyledTextCtrl, lineLength, 1}}, + {3297, {wxStyledTextCtrl, braceHighlight, 2}}, + {3298, {wxStyledTextCtrl, braceBadLight, 1}}, + {3299, {wxStyledTextCtrl, braceMatch, 1}}, + {3300, {wxStyledTextCtrl, getViewEOL, 0}}, + {3301, {wxStyledTextCtrl, setViewEOL, 1}}, + {3302, {wxStyledTextCtrl, setModEventMask, 1}}, + {3303, {wxStyledTextCtrl, getEdgeColumn, 0}}, + {3304, {wxStyledTextCtrl, setEdgeColumn, 1}}, + {3305, {wxStyledTextCtrl, setEdgeMode, 1}}, + {3306, {wxStyledTextCtrl, getEdgeMode, 0}}, + {3307, {wxStyledTextCtrl, getEdgeColour, 0}}, + {3308, {wxStyledTextCtrl, setEdgeColour, 1}}, + {3309, {wxStyledTextCtrl, searchAnchor, 0}}, + {3310, {wxStyledTextCtrl, searchNext, 2}}, + {3311, {wxStyledTextCtrl, searchPrev, 2}}, + {3312, {wxStyledTextCtrl, linesOnScreen, 0}}, + {3313, {wxStyledTextCtrl, usePopUp, 1}}, + {3314, {wxStyledTextCtrl, selectionIsRectangle, 0}}, + {3315, {wxStyledTextCtrl, setZoom, 1}}, + {3316, {wxStyledTextCtrl, getZoom, 0}}, + {3317, {wxStyledTextCtrl, getModEventMask, 0}}, + {3318, {wxStyledTextCtrl, setSTCFocus, 1}}, + {3319, {wxStyledTextCtrl, getSTCFocus, 0}}, + {3320, {wxStyledTextCtrl, setStatus, 1}}, + {3321, {wxStyledTextCtrl, getStatus, 0}}, + {3322, {wxStyledTextCtrl, setMouseDownCaptures, 1}}, + {3323, {wxStyledTextCtrl, getMouseDownCaptures, 0}}, + {3324, {wxStyledTextCtrl, setSTCCursor, 1}}, + {3325, {wxStyledTextCtrl, getSTCCursor, 0}}, + {3326, {wxStyledTextCtrl, setControlCharSymbol, 1}}, + {3327, {wxStyledTextCtrl, getControlCharSymbol, 0}}, + {3328, {wxStyledTextCtrl, wordPartLeft, 0}}, + {3329, {wxStyledTextCtrl, wordPartLeftExtend, 0}}, + {3330, {wxStyledTextCtrl, wordPartRight, 0}}, + {3331, {wxStyledTextCtrl, wordPartRightExtend, 0}}, + {3332, {wxStyledTextCtrl, setVisiblePolicy, 2}}, + {3333, {wxStyledTextCtrl, delLineLeft, 0}}, + {3334, {wxStyledTextCtrl, delLineRight, 0}}, + {3335, {wxStyledTextCtrl, getXOffset, 0}}, + {3336, {wxStyledTextCtrl, chooseCaretX, 0}}, + {3337, {wxStyledTextCtrl, setXCaretPolicy, 2}}, + {3338, {wxStyledTextCtrl, setYCaretPolicy, 2}}, + {3339, {wxStyledTextCtrl, getPrintWrapMode, 0}}, + {3340, {wxStyledTextCtrl, setHotspotActiveForeground, 2}}, + {3341, {wxStyledTextCtrl, setHotspotActiveBackground, 2}}, + {3342, {wxStyledTextCtrl, setHotspotActiveUnderline, 1}}, + {3343, {wxStyledTextCtrl, setHotspotSingleLine, 1}}, + {3344, {wxStyledTextCtrl, paraDownExtend, 0}}, + {3345, {wxStyledTextCtrl, paraUp, 0}}, + {3346, {wxStyledTextCtrl, paraUpExtend, 0}}, + {3347, {wxStyledTextCtrl, positionBefore, 1}}, + {3348, {wxStyledTextCtrl, positionAfter, 1}}, + {3349, {wxStyledTextCtrl, copyRange, 2}}, + {3350, {wxStyledTextCtrl, copyText, 2}}, + {3351, {wxStyledTextCtrl, setSelectionMode, 1}}, + {3352, {wxStyledTextCtrl, getSelectionMode, 0}}, + {3353, {wxStyledTextCtrl, lineDownRectExtend, 0}}, + {3354, {wxStyledTextCtrl, lineUpRectExtend, 0}}, + {3355, {wxStyledTextCtrl, charLeftRectExtend, 0}}, + {3356, {wxStyledTextCtrl, charRightRectExtend, 0}}, + {3357, {wxStyledTextCtrl, homeRectExtend, 0}}, + {3358, {wxStyledTextCtrl, vCHomeRectExtend, 0}}, + {3359, {wxStyledTextCtrl, lineEndRectExtend, 0}}, + {3360, {wxStyledTextCtrl, pageUpRectExtend, 0}}, + {3361, {wxStyledTextCtrl, pageDownRectExtend, 0}}, + {3362, {wxStyledTextCtrl, stutteredPageUp, 0}}, + {3363, {wxStyledTextCtrl, stutteredPageUpExtend, 0}}, + {3364, {wxStyledTextCtrl, stutteredPageDown, 0}}, + {3365, {wxStyledTextCtrl, stutteredPageDownExtend, 0}}, + {3366, {wxStyledTextCtrl, wordLeftEnd, 0}}, + {3367, {wxStyledTextCtrl, wordLeftEndExtend, 0}}, + {3368, {wxStyledTextCtrl, wordRightEnd, 0}}, + {3369, {wxStyledTextCtrl, wordRightEndExtend, 0}}, + {3370, {wxStyledTextCtrl, setWhitespaceChars, 1}}, + {3371, {wxStyledTextCtrl, setCharsDefault, 0}}, + {3372, {wxStyledTextCtrl, autoCompGetCurrent, 0}}, + {3373, {wxStyledTextCtrl, allocate, 1}}, + {3374, {wxStyledTextCtrl, findColumn, 2}}, + {3375, {wxStyledTextCtrl, getCaretSticky, 0}}, + {3376, {wxStyledTextCtrl, setCaretSticky, 1}}, + {3377, {wxStyledTextCtrl, toggleCaretSticky, 0}}, + {3378, {wxStyledTextCtrl, setPasteConvertEndings, 1}}, + {3379, {wxStyledTextCtrl, getPasteConvertEndings, 0}}, + {3380, {wxStyledTextCtrl, selectionDuplicate, 0}}, + {3381, {wxStyledTextCtrl, setCaretLineBackAlpha, 1}}, + {3382, {wxStyledTextCtrl, getCaretLineBackAlpha, 0}}, + {3383, {wxStyledTextCtrl, startRecord, 0}}, + {3384, {wxStyledTextCtrl, stopRecord, 0}}, + {3385, {wxStyledTextCtrl, setLexer, 1}}, + {3386, {wxStyledTextCtrl, getLexer, 0}}, + {3387, {wxStyledTextCtrl, colourise, 2}}, + {3388, {wxStyledTextCtrl, setProperty, 2}}, + {3389, {wxStyledTextCtrl, setKeyWords, 2}}, + {3390, {wxStyledTextCtrl, setLexerLanguage, 1}}, + {3391, {wxStyledTextCtrl, getProperty, 1}}, + {3392, {wxStyledTextCtrl, getStyleBitsNeeded, 0}}, + {3393, {wxStyledTextCtrl, getCurrentLine, 0}}, + {3394, {wxStyledTextCtrl, styleSetSpec, 2}}, + {3395, {wxStyledTextCtrl, styleSetFont, 2}}, + {3396, {wxStyledTextCtrl, styleSetFontAttr, 7}}, + {3397, {wxStyledTextCtrl, styleSetCharacterSet, 2}}, + {3398, {wxStyledTextCtrl, styleSetFontEncoding, 2}}, + {3399, {wxStyledTextCtrl, cmdKeyExecute, 1}}, + {3400, {wxStyledTextCtrl, setMargins, 2}}, + {3401, {wxStyledTextCtrl, getSelection, 2}}, + {3402, {wxStyledTextCtrl, pointFromPosition, 1}}, + {3403, {wxStyledTextCtrl, scrollToLine, 1}}, + {3404, {wxStyledTextCtrl, scrollToColumn, 1}}, + {3405, {wxStyledTextCtrl, setVScrollBar, 1}}, + {3406, {wxStyledTextCtrl, setHScrollBar, 1}}, + {3407, {wxStyledTextCtrl, getLastKeydownProcessed, 0}}, + {3408, {wxStyledTextCtrl, setLastKeydownProcessed, 1}}, + {3409, {wxStyledTextCtrl, saveFile, 1}}, + {3410, {wxStyledTextCtrl, loadFile, 1}}, + {3411, {wxStyledTextCtrl, doDragOver, 3}}, + {3412, {wxStyledTextCtrl, doDropText, 3}}, + {3413, {wxStyledTextCtrl, getUseAntiAliasing, 0}}, + {3414, {wxStyledTextCtrl, addTextRaw, 1}}, + {3415, {wxStyledTextCtrl, insertTextRaw, 2}}, + {3416, {wxStyledTextCtrl, getCurLineRaw, 1}}, + {3417, {wxStyledTextCtrl, getLineRaw, 1}}, + {3418, {wxStyledTextCtrl, getSelectedTextRaw, 0}}, + {3419, {wxStyledTextCtrl, getTextRangeRaw, 2}}, + {3420, {wxStyledTextCtrl, setTextRaw, 1}}, + {3421, {wxStyledTextCtrl, getTextRaw, 0}}, + {3422, {wxStyledTextCtrl, appendTextRaw, 1}}, + {3423, {wxArtProvider, getBitmap, 2}}, + {3424, {wxArtProvider, getIcon, 2}}, + {3425, {wxTreeEvent, getKeyCode, 0}}, + {3426, {wxTreeEvent, getItem, 0}}, + {3427, {wxTreeEvent, getKeyEvent, 0}}, + {3428, {wxTreeEvent, getLabel, 0}}, + {3429, {wxTreeEvent, getOldItem, 0}}, + {3430, {wxTreeEvent, getPoint, 0}}, + {3431, {wxTreeEvent, isEditCancelled, 0}}, + {3432, {wxTreeEvent, setToolTip, 1}}, + {3433, {wxNotebookEvent, getOldSelection, 0}}, + {3434, {wxNotebookEvent, getSelection, 0}}, + {3435, {wxNotebookEvent, setOldSelection, 1}}, + {3436, {wxNotebookEvent, setSelection, 1}}, + {3437, {wxFileDataObject, new, 0}}, + {3438, {wxFileDataObject, addFile, 1}}, + {3439, {wxFileDataObject, getFilenames, 0}}, + {3440, {wxFileDataObject, 'Destroy', undefined}}, + {3441, {wxTextDataObject, new, 1}}, + {3442, {wxTextDataObject, getTextLength, 0}}, + {3443, {wxTextDataObject, getText, 0}}, + {3444, {wxTextDataObject, setText, 1}}, + {3445, {wxTextDataObject, 'Destroy', undefined}}, + {3446, {wxBitmapDataObject, new_1_1, 1}}, + {3447, {wxBitmapDataObject, new_1_0, 1}}, + {3448, {wxBitmapDataObject, getBitmap, 0}}, + {3449, {wxBitmapDataObject, setBitmap, 1}}, + {3450, {wxBitmapDataObject, 'Destroy', undefined}}, + {3452, {wxClipboard, new, 0}}, + {3453, {wxClipboard, destruct, 0}}, + {3454, {wxClipboard, addData, 1}}, + {3455, {wxClipboard, clear, 0}}, + {3456, {wxClipboard, close, 0}}, + {3457, {wxClipboard, flush, 0}}, + {3458, {wxClipboard, getData, 1}}, + {3459, {wxClipboard, isOpened, 0}}, + {3460, {wxClipboard, open, 0}}, + {3461, {wxClipboard, setData, 1}}, + {3463, {wxClipboard, usePrimarySelection, 1}}, + {3464, {wxClipboard, isSupported, 1}}, + {3465, {wxClipboard, get, 0}}, + {3466, {wxSpinEvent, getPosition, 0}}, + {3467, {wxSpinEvent, setPosition, 1}}, + {3468, {wxSplitterWindow, new_0, 0}}, + {3469, {wxSplitterWindow, new_2, 2}}, + {3470, {wxSplitterWindow, destruct, 0}}, + {3471, {wxSplitterWindow, create, 2}}, + {3472, {wxSplitterWindow, getMinimumPaneSize, 0}}, + {3473, {wxSplitterWindow, getSashGravity, 0}}, + {3474, {wxSplitterWindow, getSashPosition, 0}}, + {3475, {wxSplitterWindow, getSplitMode, 0}}, + {3476, {wxSplitterWindow, getWindow1, 0}}, + {3477, {wxSplitterWindow, getWindow2, 0}}, + {3478, {wxSplitterWindow, initialize, 1}}, + {3479, {wxSplitterWindow, isSplit, 0}}, + {3480, {wxSplitterWindow, replaceWindow, 2}}, + {3481, {wxSplitterWindow, setSashGravity, 1}}, + {3482, {wxSplitterWindow, setSashPosition, 2}}, + {3483, {wxSplitterWindow, setSashSize, 1}}, + {3484, {wxSplitterWindow, setMinimumPaneSize, 1}}, + {3485, {wxSplitterWindow, setSplitMode, 1}}, + {3486, {wxSplitterWindow, splitHorizontally, 3}}, + {3487, {wxSplitterWindow, splitVertically, 3}}, + {3488, {wxSplitterWindow, unsplit, 1}}, + {3489, {wxSplitterWindow, updateSize, 0}}, + {3490, {wxSplitterEvent, getSashPosition, 0}}, + {3491, {wxSplitterEvent, getX, 0}}, + {3492, {wxSplitterEvent, getY, 0}}, + {3493, {wxSplitterEvent, getWindowBeingRemoved, 0}}, + {3494, {wxSplitterEvent, setSashPosition, 1}}, + {3495, {wxHtmlWindow, new_0, 0}}, + {3496, {wxHtmlWindow, new_2, 2}}, + {3497, {wxHtmlWindow, appendToPage, 1}}, + {3498, {wxHtmlWindow, getOpenedAnchor, 0}}, + {3499, {wxHtmlWindow, getOpenedPage, 0}}, + {3500, {wxHtmlWindow, getOpenedPageTitle, 0}}, + {3501, {wxHtmlWindow, getRelatedFrame, 0}}, + {3502, {wxHtmlWindow, historyBack, 0}}, + {3503, {wxHtmlWindow, historyCanBack, 0}}, + {3504, {wxHtmlWindow, historyCanForward, 0}}, + {3505, {wxHtmlWindow, historyClear, 0}}, + {3506, {wxHtmlWindow, historyForward, 0}}, + {3507, {wxHtmlWindow, loadFile, 1}}, + {3508, {wxHtmlWindow, loadPage, 1}}, + {3509, {wxHtmlWindow, selectAll, 0}}, + {3510, {wxHtmlWindow, selectionToText, 0}}, + {3511, {wxHtmlWindow, selectLine, 1}}, + {3512, {wxHtmlWindow, selectWord, 1}}, + {3513, {wxHtmlWindow, setBorders, 1}}, + {3514, {wxHtmlWindow, setFonts, 3}}, + {3515, {wxHtmlWindow, setPage, 1}}, + {3516, {wxHtmlWindow, setRelatedFrame, 2}}, + {3517, {wxHtmlWindow, setRelatedStatusBar, 1}}, + {3518, {wxHtmlWindow, toText, 0}}, + {3519, {wxHtmlWindow, 'Destroy', undefined}}, + {3520, {wxHtmlLinkEvent, getLinkInfo, 0}}, + {3521, {wxSystemSettings, getColour, 1}}, + {3522, {wxSystemSettings, getFont, 1}}, + {3523, {wxSystemSettings, getMetric, 2}}, + {3524, {wxSystemSettings, getScreenType, 0}}, + {3525, {wxSystemOptions, getOption, 1}}, + {3526, {wxSystemOptions, getOptionInt, 1}}, + {3527, {wxSystemOptions, hasOption, 1}}, + {3528, {wxSystemOptions, isFalse, 1}}, + {3529, {wxSystemOptions, setOption_2_1, 2}}, + {3530, {wxSystemOptions, setOption_2_0, 2}}, + {3531, {wxAuiNotebookEvent, setSelection, 1}}, + {3532, {wxAuiNotebookEvent, getSelection, 0}}, + {3533, {wxAuiNotebookEvent, setOldSelection, 1}}, + {3534, {wxAuiNotebookEvent, getOldSelection, 0}}, + {3535, {wxAuiNotebookEvent, setDragSource, 1}}, + {3536, {wxAuiNotebookEvent, getDragSource, 0}}, + {3537, {wxAuiManagerEvent, setManager, 1}}, + {3538, {wxAuiManagerEvent, getManager, 0}}, + {3539, {wxAuiManagerEvent, setPane, 1}}, + {3540, {wxAuiManagerEvent, getPane, 0}}, + {3541, {wxAuiManagerEvent, setButton, 1}}, + {3542, {wxAuiManagerEvent, getButton, 0}}, + {3543, {wxAuiManagerEvent, setDC, 1}}, + {3544, {wxAuiManagerEvent, getDC, 0}}, + {3545, {wxAuiManagerEvent, veto, 1}}, + {3546, {wxAuiManagerEvent, getVeto, 0}}, + {3547, {wxAuiManagerEvent, setCanVeto, 1}}, + {3548, {wxAuiManagerEvent, canVeto, 0}}, + {3549, {wxLogNull, new, 0}}, + {3550, {wxLogNull, 'Destroy', undefined}}, + {3551, {wxTaskBarIcon, new, 0}}, + {3552, {wxTaskBarIcon, destruct, 0}}, + {3553, {wxTaskBarIcon, popupMenu, 1}}, + {3554, {wxTaskBarIcon, removeIcon, 0}}, + {3555, {wxTaskBarIcon, setIcon, 2}}, + {3556, {wxLocale, new_0, 0}}, + {3558, {wxLocale, new_2, 2}}, + {3559, {wxLocale, destruct, 0}}, + {3561, {wxLocale, init, 1}}, + {3562, {wxLocale, addCatalog_1, 1}}, + {3563, {wxLocale, addCatalog_3, 3}}, + {3564, {wxLocale, addCatalogLookupPathPrefix, 1}}, + {3565, {wxLocale, getCanonicalName, 0}}, + {3566, {wxLocale, getLanguage, 0}}, + {3567, {wxLocale, getLanguageName, 1}}, + {3568, {wxLocale, getLocale, 0}}, + {3569, {wxLocale, getName, 0}}, + {3570, {wxLocale, getString_2, 2}}, + {3571, {wxLocale, getString_4, 4}}, + {3572, {wxLocale, getHeaderValue, 2}}, + {3573, {wxLocale, getSysName, 0}}, + {3574, {wxLocale, getSystemEncoding, 0}}, + {3575, {wxLocale, getSystemEncodingName, 0}}, + {3576, {wxLocale, getSystemLanguage, 0}}, + {3577, {wxLocale, isLoaded, 1}}, + {3578, {wxLocale, isOk, 0}}, + {3579, {wxActivateEvent, getActive, 0}}, + {3581, {wxPopupWindow, new_2, 2}}, + {3582, {wxPopupWindow, new_0, 0}}, + {3584, {wxPopupWindow, destruct, 0}}, + {3585, {wxPopupWindow, create, 2}}, + {3586, {wxPopupWindow, position, 2}}, + {3587, {wxPopupTransientWindow, new_0, 0}}, + {3588, {wxPopupTransientWindow, new_2, 2}}, + {3589, {wxPopupTransientWindow, destruct, 0}}, + {3590, {wxPopupTransientWindow, popup, 1}}, + {3591, {wxPopupTransientWindow, dismiss, 0}}, + {3592, {wxOverlay, new, 0}}, + {3593, {wxOverlay, destruct, 0}}, + {3594, {wxOverlay, reset, 0}}, + {3595, {wxDCOverlay, new_6, 6}}, + {3596, {wxDCOverlay, new_2, 2}}, + {3597, {wxDCOverlay, destruct, 0}}, + {3598, {wxDCOverlay, clear, 0}}, {-1, {mod, func, -1}} ]. diff --git a/lib/wx/src/gen/wxe_funcs.hrl b/lib/wx/src/gen/wxe_funcs.hrl index faab72184d..f5f839ac67 100644 --- a/lib/wx/src/gen/wxe_funcs.hrl +++ b/lib/wx/src/gen/wxe_funcs.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2014. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -189,3152 +189,3187 @@ -define(wxWindow_UpdateWindowUI, 281). -define(wxWindow_Validate, 282). -define(wxWindow_WarpPointer, 283). --define(wxTopLevelWindow_GetIcon, 284). --define(wxTopLevelWindow_GetIcons, 285). --define(wxTopLevelWindow_GetTitle, 286). --define(wxTopLevelWindow_IsActive, 287). --define(wxTopLevelWindow_Iconize, 288). --define(wxTopLevelWindow_IsFullScreen, 289). --define(wxTopLevelWindow_IsIconized, 290). --define(wxTopLevelWindow_IsMaximized, 291). --define(wxTopLevelWindow_Maximize, 292). --define(wxTopLevelWindow_RequestUserAttention, 293). --define(wxTopLevelWindow_SetIcon, 294). --define(wxTopLevelWindow_SetIcons, 295). --define(wxTopLevelWindow_CenterOnScreen, 296). --define(wxTopLevelWindow_CentreOnScreen, 297). --define(wxTopLevelWindow_SetShape, 299). --define(wxTopLevelWindow_SetTitle, 300). --define(wxTopLevelWindow_ShowFullScreen, 301). --define(wxFrame_new_4, 303). --define(wxFrame_new_0, 304). --define(wxFrame_destruct, 306). --define(wxFrame_Create, 307). --define(wxFrame_CreateStatusBar, 308). --define(wxFrame_CreateToolBar, 309). --define(wxFrame_GetClientAreaOrigin, 310). --define(wxFrame_GetMenuBar, 311). --define(wxFrame_GetStatusBar, 312). --define(wxFrame_GetStatusBarPane, 313). --define(wxFrame_GetToolBar, 314). --define(wxFrame_ProcessCommand, 315). --define(wxFrame_SendSizeEvent, 316). --define(wxFrame_SetMenuBar, 317). --define(wxFrame_SetStatusBar, 318). --define(wxFrame_SetStatusBarPane, 319). --define(wxFrame_SetStatusText, 320). --define(wxFrame_SetStatusWidths, 321). --define(wxFrame_SetToolBar, 322). --define(wxMiniFrame_new_0, 323). --define(wxMiniFrame_new_4, 324). --define(wxMiniFrame_Create, 325). --define(wxMiniFrame_destroy, 326). --define(wxSplashScreen_new_0, 327). --define(wxSplashScreen_new_6, 328). --define(wxSplashScreen_destruct, 329). --define(wxSplashScreen_GetSplashStyle, 330). --define(wxSplashScreen_GetTimeout, 331). --define(wxPanel_new_0, 332). --define(wxPanel_new_6, 333). --define(wxPanel_new_2, 334). --define(wxPanel_destruct, 335). --define(wxPanel_InitDialog, 336). --define(wxPanel_SetFocusIgnoringChildren, 337). --define(wxScrolledWindow_new_0, 338). --define(wxScrolledWindow_new_2, 339). --define(wxScrolledWindow_destruct, 340). --define(wxScrolledWindow_CalcScrolledPosition_4, 341). --define(wxScrolledWindow_CalcScrolledPosition_1, 342). --define(wxScrolledWindow_CalcUnscrolledPosition_4, 343). --define(wxScrolledWindow_CalcUnscrolledPosition_1, 344). --define(wxScrolledWindow_EnableScrolling, 345). --define(wxScrolledWindow_GetScrollPixelsPerUnit, 346). --define(wxScrolledWindow_GetViewStart, 347). --define(wxScrolledWindow_DoPrepareDC, 348). --define(wxScrolledWindow_PrepareDC, 349). --define(wxScrolledWindow_Scroll, 350). --define(wxScrolledWindow_SetScrollbars, 351). --define(wxScrolledWindow_SetScrollRate, 352). --define(wxScrolledWindow_SetTargetWindow, 353). --define(wxSashWindow_new_0, 354). --define(wxSashWindow_new_2, 355). --define(wxSashWindow_destruct, 356). --define(wxSashWindow_GetSashVisible, 357). --define(wxSashWindow_GetMaximumSizeX, 358). --define(wxSashWindow_GetMaximumSizeY, 359). --define(wxSashWindow_GetMinimumSizeX, 360). --define(wxSashWindow_GetMinimumSizeY, 361). --define(wxSashWindow_SetMaximumSizeX, 362). --define(wxSashWindow_SetMaximumSizeY, 363). --define(wxSashWindow_SetMinimumSizeX, 364). --define(wxSashWindow_SetMinimumSizeY, 365). --define(wxSashWindow_SetSashVisible, 366). --define(wxSashLayoutWindow_new_0, 367). --define(wxSashLayoutWindow_new_2, 368). --define(wxSashLayoutWindow_Create, 369). --define(wxSashLayoutWindow_GetAlignment, 370). --define(wxSashLayoutWindow_GetOrientation, 371). --define(wxSashLayoutWindow_SetAlignment, 372). --define(wxSashLayoutWindow_SetDefaultSize, 373). --define(wxSashLayoutWindow_SetOrientation, 374). --define(wxSashLayoutWindow_destroy, 375). --define(wxGrid_new_0, 376). --define(wxGrid_new_3, 377). --define(wxGrid_new_4, 378). --define(wxGrid_destruct, 379). --define(wxGrid_AppendCols, 380). --define(wxGrid_AppendRows, 381). --define(wxGrid_AutoSize, 382). --define(wxGrid_AutoSizeColumn, 383). --define(wxGrid_AutoSizeColumns, 384). --define(wxGrid_AutoSizeRow, 385). --define(wxGrid_AutoSizeRows, 386). --define(wxGrid_BeginBatch, 387). --define(wxGrid_BlockToDeviceRect, 388). --define(wxGrid_CanDragColSize, 389). --define(wxGrid_CanDragRowSize, 390). --define(wxGrid_CanDragGridSize, 391). --define(wxGrid_CanEnableCellControl, 392). --define(wxGrid_CellToRect_2, 393). --define(wxGrid_CellToRect_1, 394). --define(wxGrid_ClearGrid, 395). --define(wxGrid_ClearSelection, 396). --define(wxGrid_CreateGrid, 397). --define(wxGrid_DeleteCols, 398). --define(wxGrid_DeleteRows, 399). --define(wxGrid_DisableCellEditControl, 400). --define(wxGrid_DisableDragColSize, 401). --define(wxGrid_DisableDragGridSize, 402). --define(wxGrid_DisableDragRowSize, 403). --define(wxGrid_EnableCellEditControl, 404). --define(wxGrid_EnableDragColSize, 405). --define(wxGrid_EnableDragGridSize, 406). --define(wxGrid_EnableDragRowSize, 407). --define(wxGrid_EnableEditing, 408). --define(wxGrid_EnableGridLines, 409). --define(wxGrid_EndBatch, 410). --define(wxGrid_Fit, 411). --define(wxGrid_ForceRefresh, 412). --define(wxGrid_GetBatchCount, 413). --define(wxGrid_GetCellAlignment, 414). --define(wxGrid_GetCellBackgroundColour, 415). --define(wxGrid_GetCellEditor, 416). --define(wxGrid_GetCellFont, 417). --define(wxGrid_GetCellRenderer, 418). --define(wxGrid_GetCellTextColour, 419). --define(wxGrid_GetCellValue_2, 420). --define(wxGrid_GetCellValue_1, 421). --define(wxGrid_GetColLabelAlignment, 422). --define(wxGrid_GetColLabelSize, 423). --define(wxGrid_GetColLabelValue, 424). --define(wxGrid_GetColMinimalAcceptableWidth, 425). --define(wxGrid_GetDefaultCellAlignment, 426). --define(wxGrid_GetDefaultCellBackgroundColour, 427). --define(wxGrid_GetDefaultCellFont, 428). --define(wxGrid_GetDefaultCellTextColour, 429). --define(wxGrid_GetDefaultColLabelSize, 430). --define(wxGrid_GetDefaultColSize, 431). --define(wxGrid_GetDefaultEditor, 432). --define(wxGrid_GetDefaultEditorForCell_2, 433). --define(wxGrid_GetDefaultEditorForCell_1, 434). --define(wxGrid_GetDefaultEditorForType, 435). --define(wxGrid_GetDefaultRenderer, 436). --define(wxGrid_GetDefaultRendererForCell, 437). --define(wxGrid_GetDefaultRendererForType, 438). --define(wxGrid_GetDefaultRowLabelSize, 439). --define(wxGrid_GetDefaultRowSize, 440). --define(wxGrid_GetGridCursorCol, 441). --define(wxGrid_GetGridCursorRow, 442). --define(wxGrid_GetGridLineColour, 443). --define(wxGrid_GridLinesEnabled, 444). --define(wxGrid_GetLabelBackgroundColour, 445). --define(wxGrid_GetLabelFont, 446). --define(wxGrid_GetLabelTextColour, 447). --define(wxGrid_GetNumberCols, 448). --define(wxGrid_GetNumberRows, 449). --define(wxGrid_GetOrCreateCellAttr, 450). --define(wxGrid_GetRowMinimalAcceptableHeight, 451). --define(wxGrid_GetRowLabelAlignment, 452). --define(wxGrid_GetRowLabelSize, 453). --define(wxGrid_GetRowLabelValue, 454). --define(wxGrid_GetRowSize, 455). --define(wxGrid_GetScrollLineX, 456). --define(wxGrid_GetScrollLineY, 457). --define(wxGrid_GetSelectedCells, 458). --define(wxGrid_GetSelectedCols, 459). --define(wxGrid_GetSelectedRows, 460). --define(wxGrid_GetSelectionBackground, 461). --define(wxGrid_GetSelectionBlockTopLeft, 462). --define(wxGrid_GetSelectionBlockBottomRight, 463). --define(wxGrid_GetSelectionForeground, 464). --define(wxGrid_GetViewWidth, 465). --define(wxGrid_GetGridWindow, 466). --define(wxGrid_GetGridRowLabelWindow, 467). --define(wxGrid_GetGridColLabelWindow, 468). --define(wxGrid_GetGridCornerLabelWindow, 469). --define(wxGrid_HideCellEditControl, 470). --define(wxGrid_InsertCols, 471). --define(wxGrid_InsertRows, 472). --define(wxGrid_IsCellEditControlEnabled, 473). --define(wxGrid_IsCurrentCellReadOnly, 474). --define(wxGrid_IsEditable, 475). --define(wxGrid_IsInSelection_2, 476). --define(wxGrid_IsInSelection_1, 477). --define(wxGrid_IsReadOnly, 478). --define(wxGrid_IsSelection, 479). --define(wxGrid_IsVisible_3, 480). --define(wxGrid_IsVisible_2, 481). --define(wxGrid_MakeCellVisible_2, 482). --define(wxGrid_MakeCellVisible_1, 483). --define(wxGrid_MoveCursorDown, 484). --define(wxGrid_MoveCursorLeft, 485). --define(wxGrid_MoveCursorRight, 486). --define(wxGrid_MoveCursorUp, 487). --define(wxGrid_MoveCursorDownBlock, 488). --define(wxGrid_MoveCursorLeftBlock, 489). --define(wxGrid_MoveCursorRightBlock, 490). --define(wxGrid_MoveCursorUpBlock, 491). --define(wxGrid_MovePageDown, 492). --define(wxGrid_MovePageUp, 493). --define(wxGrid_RegisterDataType, 494). --define(wxGrid_SaveEditControlValue, 495). --define(wxGrid_SelectAll, 496). --define(wxGrid_SelectBlock_5, 497). --define(wxGrid_SelectBlock_3, 498). --define(wxGrid_SelectCol, 499). --define(wxGrid_SelectRow, 500). --define(wxGrid_SetCellAlignment_4, 501). --define(wxGrid_SetCellAlignment_3, 502). --define(wxGrid_SetCellAlignment_1, 503). --define(wxGrid_SetCellBackgroundColour_3_0, 504). --define(wxGrid_SetCellBackgroundColour_1, 505). --define(wxGrid_SetCellBackgroundColour_3_1, 506). --define(wxGrid_SetCellEditor, 507). --define(wxGrid_SetCellFont, 508). --define(wxGrid_SetCellRenderer, 509). --define(wxGrid_SetCellTextColour_3_0, 510). --define(wxGrid_SetCellTextColour_3_1, 511). --define(wxGrid_SetCellTextColour_1, 512). --define(wxGrid_SetCellValue_3_0, 513). --define(wxGrid_SetCellValue_2, 514). --define(wxGrid_SetCellValue_3_1, 515). --define(wxGrid_SetColAttr, 516). --define(wxGrid_SetColFormatBool, 517). --define(wxGrid_SetColFormatNumber, 518). --define(wxGrid_SetColFormatFloat, 519). --define(wxGrid_SetColFormatCustom, 520). --define(wxGrid_SetColLabelAlignment, 521). --define(wxGrid_SetColLabelSize, 522). --define(wxGrid_SetColLabelValue, 523). --define(wxGrid_SetColMinimalWidth, 524). --define(wxGrid_SetColMinimalAcceptableWidth, 525). --define(wxGrid_SetColSize, 526). --define(wxGrid_SetDefaultCellAlignment, 527). --define(wxGrid_SetDefaultCellBackgroundColour, 528). --define(wxGrid_SetDefaultCellFont, 529). --define(wxGrid_SetDefaultCellTextColour, 530). --define(wxGrid_SetDefaultEditor, 531). --define(wxGrid_SetDefaultRenderer, 532). --define(wxGrid_SetDefaultColSize, 533). --define(wxGrid_SetDefaultRowSize, 534). --define(wxGrid_SetGridCursor, 535). --define(wxGrid_SetGridLineColour, 536). --define(wxGrid_SetLabelBackgroundColour, 537). --define(wxGrid_SetLabelFont, 538). --define(wxGrid_SetLabelTextColour, 539). --define(wxGrid_SetMargins, 540). --define(wxGrid_SetReadOnly, 541). --define(wxGrid_SetRowAttr, 542). --define(wxGrid_SetRowLabelAlignment, 543). --define(wxGrid_SetRowLabelSize, 544). --define(wxGrid_SetRowLabelValue, 545). --define(wxGrid_SetRowMinimalHeight, 546). --define(wxGrid_SetRowMinimalAcceptableHeight, 547). --define(wxGrid_SetRowSize, 548). --define(wxGrid_SetScrollLineX, 549). --define(wxGrid_SetScrollLineY, 550). --define(wxGrid_SetSelectionBackground, 551). --define(wxGrid_SetSelectionForeground, 552). --define(wxGrid_SetSelectionMode, 553). --define(wxGrid_ShowCellEditControl, 554). --define(wxGrid_XToCol, 555). --define(wxGrid_XToEdgeOfCol, 556). --define(wxGrid_YToEdgeOfRow, 557). --define(wxGrid_YToRow, 558). --define(wxGridCellRenderer_Draw, 559). --define(wxGridCellRenderer_GetBestSize, 560). --define(wxGridCellEditor_Create, 561). --define(wxGridCellEditor_IsCreated, 562). --define(wxGridCellEditor_SetSize, 563). --define(wxGridCellEditor_Show, 564). --define(wxGridCellEditor_PaintBackground, 565). --define(wxGridCellEditor_BeginEdit, 566). --define(wxGridCellEditor_EndEdit, 567). --define(wxGridCellEditor_Reset, 568). --define(wxGridCellEditor_StartingKey, 569). --define(wxGridCellEditor_StartingClick, 570). --define(wxGridCellEditor_HandleReturn, 571). --define(wxGridCellBoolRenderer_new, 572). --define(wxGridCellBoolRenderer_destroy, 573). --define(wxGridCellBoolEditor_new, 574). --define(wxGridCellBoolEditor_IsTrueValue, 575). --define(wxGridCellBoolEditor_UseStringValues, 576). --define(wxGridCellBoolEditor_destroy, 577). --define(wxGridCellFloatRenderer_new, 578). --define(wxGridCellFloatRenderer_GetPrecision, 579). --define(wxGridCellFloatRenderer_GetWidth, 580). --define(wxGridCellFloatRenderer_SetParameters, 581). --define(wxGridCellFloatRenderer_SetPrecision, 582). --define(wxGridCellFloatRenderer_SetWidth, 583). --define(wxGridCellFloatRenderer_destroy, 584). --define(wxGridCellFloatEditor_new, 585). --define(wxGridCellFloatEditor_SetParameters, 586). --define(wxGridCellFloatEditor_destroy, 587). --define(wxGridCellStringRenderer_new, 588). --define(wxGridCellStringRenderer_destroy, 589). --define(wxGridCellTextEditor_new, 590). --define(wxGridCellTextEditor_SetParameters, 591). --define(wxGridCellTextEditor_destroy, 592). --define(wxGridCellChoiceEditor_new, 594). --define(wxGridCellChoiceEditor_SetParameters, 595). --define(wxGridCellChoiceEditor_destroy, 596). --define(wxGridCellNumberRenderer_new, 597). --define(wxGridCellNumberRenderer_destroy, 598). --define(wxGridCellNumberEditor_new, 599). --define(wxGridCellNumberEditor_GetValue, 600). --define(wxGridCellNumberEditor_SetParameters, 601). --define(wxGridCellNumberEditor_destroy, 602). --define(wxGridCellAttr_SetTextColour, 603). --define(wxGridCellAttr_SetBackgroundColour, 604). --define(wxGridCellAttr_SetFont, 605). --define(wxGridCellAttr_SetAlignment, 606). --define(wxGridCellAttr_SetReadOnly, 607). --define(wxGridCellAttr_SetRenderer, 608). --define(wxGridCellAttr_SetEditor, 609). --define(wxGridCellAttr_HasTextColour, 610). --define(wxGridCellAttr_HasBackgroundColour, 611). --define(wxGridCellAttr_HasFont, 612). --define(wxGridCellAttr_HasAlignment, 613). --define(wxGridCellAttr_HasRenderer, 614). --define(wxGridCellAttr_HasEditor, 615). --define(wxGridCellAttr_GetTextColour, 616). --define(wxGridCellAttr_GetBackgroundColour, 617). --define(wxGridCellAttr_GetFont, 618). --define(wxGridCellAttr_GetAlignment, 619). --define(wxGridCellAttr_GetRenderer, 620). --define(wxGridCellAttr_GetEditor, 621). --define(wxGridCellAttr_IsReadOnly, 622). --define(wxGridCellAttr_SetDefAttr, 623). --define(wxDC_Blit, 624). --define(wxDC_CalcBoundingBox, 625). --define(wxDC_Clear, 626). --define(wxDC_ComputeScaleAndOrigin, 627). --define(wxDC_CrossHair, 628). --define(wxDC_DestroyClippingRegion, 629). --define(wxDC_DeviceToLogicalX, 630). --define(wxDC_DeviceToLogicalXRel, 631). --define(wxDC_DeviceToLogicalY, 632). --define(wxDC_DeviceToLogicalYRel, 633). --define(wxDC_DrawArc, 634). --define(wxDC_DrawBitmap, 635). --define(wxDC_DrawCheckMark, 636). --define(wxDC_DrawCircle, 637). --define(wxDC_DrawEllipse_2, 639). --define(wxDC_DrawEllipse_1, 640). --define(wxDC_DrawEllipticArc, 641). --define(wxDC_DrawIcon, 642). --define(wxDC_DrawLabel, 643). --define(wxDC_DrawLine, 644). --define(wxDC_DrawLines, 645). --define(wxDC_DrawPolygon, 647). --define(wxDC_DrawPoint, 649). --define(wxDC_DrawRectangle_2, 651). --define(wxDC_DrawRectangle_1, 652). --define(wxDC_DrawRotatedText, 653). --define(wxDC_DrawRoundedRectangle_3, 655). --define(wxDC_DrawRoundedRectangle_2, 656). --define(wxDC_DrawText, 657). --define(wxDC_EndDoc, 658). --define(wxDC_EndPage, 659). --define(wxDC_FloodFill, 660). --define(wxDC_GetBackground, 661). --define(wxDC_GetBackgroundMode, 662). --define(wxDC_GetBrush, 663). --define(wxDC_GetCharHeight, 664). --define(wxDC_GetCharWidth, 665). --define(wxDC_GetClippingBox, 666). --define(wxDC_GetFont, 668). --define(wxDC_GetLayoutDirection, 669). --define(wxDC_GetLogicalFunction, 670). --define(wxDC_GetMapMode, 671). --define(wxDC_GetMultiLineTextExtent_4, 672). --define(wxDC_GetMultiLineTextExtent_1, 673). --define(wxDC_GetPartialTextExtents, 674). --define(wxDC_GetPen, 675). --define(wxDC_GetPixel, 676). --define(wxDC_GetPPI, 677). --define(wxDC_GetSize, 679). --define(wxDC_GetSizeMM, 681). --define(wxDC_GetTextBackground, 682). --define(wxDC_GetTextExtent_4, 683). --define(wxDC_GetTextExtent_1, 684). --define(wxDC_GetTextForeground, 686). --define(wxDC_GetUserScale, 687). --define(wxDC_GradientFillConcentric_3, 688). --define(wxDC_GradientFillConcentric_4, 689). --define(wxDC_GradientFillLinear, 690). --define(wxDC_LogicalToDeviceX, 691). --define(wxDC_LogicalToDeviceXRel, 692). --define(wxDC_LogicalToDeviceY, 693). --define(wxDC_LogicalToDeviceYRel, 694). --define(wxDC_MaxX, 695). --define(wxDC_MaxY, 696). --define(wxDC_MinX, 697). --define(wxDC_MinY, 698). --define(wxDC_IsOk, 699). --define(wxDC_ResetBoundingBox, 700). --define(wxDC_SetAxisOrientation, 701). --define(wxDC_SetBackground, 702). --define(wxDC_SetBackgroundMode, 703). --define(wxDC_SetBrush, 704). --define(wxDC_SetClippingRegion_2, 706). --define(wxDC_SetClippingRegion_1_1, 707). --define(wxDC_SetClippingRegion_1_0, 708). --define(wxDC_SetDeviceOrigin, 709). --define(wxDC_SetFont, 710). --define(wxDC_SetLayoutDirection, 711). --define(wxDC_SetLogicalFunction, 712). --define(wxDC_SetMapMode, 713). --define(wxDC_SetPalette, 714). --define(wxDC_SetPen, 715). --define(wxDC_SetTextBackground, 716). --define(wxDC_SetTextForeground, 717). --define(wxDC_SetUserScale, 718). --define(wxDC_StartDoc, 719). --define(wxDC_StartPage, 720). --define(wxMirrorDC_new, 721). --define(wxMirrorDC_destroy, 722). --define(wxScreenDC_new, 723). --define(wxScreenDC_destruct, 724). --define(wxPostScriptDC_new_0, 725). --define(wxPostScriptDC_new_1, 726). --define(wxPostScriptDC_destruct, 727). --define(wxPostScriptDC_SetResolution, 728). --define(wxPostScriptDC_GetResolution, 729). --define(wxWindowDC_new_0, 730). --define(wxWindowDC_new_1, 731). --define(wxWindowDC_destruct, 732). --define(wxClientDC_new_0, 733). --define(wxClientDC_new_1, 734). --define(wxClientDC_destroy, 735). --define(wxPaintDC_new_0, 736). --define(wxPaintDC_new_1, 737). --define(wxPaintDC_destroy, 738). --define(wxMemoryDC_new_1_0, 740). --define(wxMemoryDC_new_1_1, 741). --define(wxMemoryDC_new_0, 742). --define(wxMemoryDC_destruct, 744). --define(wxMemoryDC_SelectObject, 745). --define(wxMemoryDC_SelectObjectAsSource, 746). --define(wxBufferedDC_new_0, 747). --define(wxBufferedDC_new_2, 748). --define(wxBufferedDC_new_3, 749). --define(wxBufferedDC_destruct, 750). --define(wxBufferedDC_Init_2, 751). --define(wxBufferedDC_Init_3, 752). --define(wxBufferedPaintDC_new_3, 753). --define(wxBufferedPaintDC_new_2, 754). --define(wxBufferedPaintDC_destruct, 755). --define(wxGraphicsObject_destruct, 756). --define(wxGraphicsObject_GetRenderer, 757). --define(wxGraphicsObject_IsNull, 758). --define(wxGraphicsContext_destruct, 759). --define(wxGraphicsContext_Create_1_1, 760). --define(wxGraphicsContext_Create_1_0, 761). --define(wxGraphicsContext_Create_0, 762). --define(wxGraphicsContext_CreatePen, 763). --define(wxGraphicsContext_CreateBrush, 764). --define(wxGraphicsContext_CreateRadialGradientBrush, 765). --define(wxGraphicsContext_CreateLinearGradientBrush, 766). --define(wxGraphicsContext_CreateFont, 767). --define(wxGraphicsContext_CreateMatrix, 768). --define(wxGraphicsContext_CreatePath, 769). --define(wxGraphicsContext_Clip_1, 770). --define(wxGraphicsContext_Clip_4, 771). --define(wxGraphicsContext_ResetClip, 772). --define(wxGraphicsContext_DrawBitmap, 773). --define(wxGraphicsContext_DrawEllipse, 774). --define(wxGraphicsContext_DrawIcon, 775). --define(wxGraphicsContext_DrawLines, 776). --define(wxGraphicsContext_DrawPath, 777). --define(wxGraphicsContext_DrawRectangle, 778). --define(wxGraphicsContext_DrawRoundedRectangle, 779). --define(wxGraphicsContext_DrawText_3, 780). --define(wxGraphicsContext_DrawText_4_0, 781). --define(wxGraphicsContext_DrawText_4_1, 782). --define(wxGraphicsContext_DrawText_5, 783). --define(wxGraphicsContext_FillPath, 784). --define(wxGraphicsContext_StrokePath, 785). --define(wxGraphicsContext_GetPartialTextExtents, 786). --define(wxGraphicsContext_GetTextExtent, 787). --define(wxGraphicsContext_Rotate, 788). --define(wxGraphicsContext_Scale, 789). --define(wxGraphicsContext_Translate, 790). --define(wxGraphicsContext_GetTransform, 791). --define(wxGraphicsContext_SetTransform, 792). --define(wxGraphicsContext_ConcatTransform, 793). --define(wxGraphicsContext_SetBrush_1_1, 794). --define(wxGraphicsContext_SetBrush_1_0, 795). --define(wxGraphicsContext_SetFont_1, 796). --define(wxGraphicsContext_SetFont_2, 797). --define(wxGraphicsContext_SetPen_1_0, 798). --define(wxGraphicsContext_SetPen_1_1, 799). --define(wxGraphicsContext_StrokeLine, 800). --define(wxGraphicsContext_StrokeLines, 801). --define(wxGraphicsMatrix_Concat, 803). --define(wxGraphicsMatrix_Get, 805). --define(wxGraphicsMatrix_Invert, 806). --define(wxGraphicsMatrix_IsEqual, 807). --define(wxGraphicsMatrix_IsIdentity, 809). --define(wxGraphicsMatrix_Rotate, 810). --define(wxGraphicsMatrix_Scale, 811). --define(wxGraphicsMatrix_Translate, 812). --define(wxGraphicsMatrix_Set, 813). --define(wxGraphicsMatrix_TransformPoint, 814). --define(wxGraphicsMatrix_TransformDistance, 815). --define(wxGraphicsPath_MoveToPoint_2, 816). --define(wxGraphicsPath_MoveToPoint_1, 817). --define(wxGraphicsPath_AddArc_6, 818). --define(wxGraphicsPath_AddArc_5, 819). --define(wxGraphicsPath_AddArcToPoint, 820). --define(wxGraphicsPath_AddCircle, 821). --define(wxGraphicsPath_AddCurveToPoint_6, 822). --define(wxGraphicsPath_AddCurveToPoint_3, 823). --define(wxGraphicsPath_AddEllipse, 824). --define(wxGraphicsPath_AddLineToPoint_2, 825). --define(wxGraphicsPath_AddLineToPoint_1, 826). --define(wxGraphicsPath_AddPath, 827). --define(wxGraphicsPath_AddQuadCurveToPoint, 828). --define(wxGraphicsPath_AddRectangle, 829). --define(wxGraphicsPath_AddRoundedRectangle, 830). --define(wxGraphicsPath_CloseSubpath, 831). --define(wxGraphicsPath_Contains_3, 832). --define(wxGraphicsPath_Contains_2, 833). --define(wxGraphicsPath_GetBox, 835). --define(wxGraphicsPath_GetCurrentPoint, 837). --define(wxGraphicsPath_Transform, 838). --define(wxGraphicsRenderer_GetDefaultRenderer, 839). --define(wxGraphicsRenderer_CreateContext_1_1, 840). --define(wxGraphicsRenderer_CreateContext_1_0, 841). --define(wxGraphicsRenderer_CreatePen, 842). --define(wxGraphicsRenderer_CreateBrush, 843). --define(wxGraphicsRenderer_CreateLinearGradientBrush, 844). --define(wxGraphicsRenderer_CreateRadialGradientBrush, 845). --define(wxGraphicsRenderer_CreateFont, 846). --define(wxGraphicsRenderer_CreateMatrix, 847). --define(wxGraphicsRenderer_CreatePath, 848). --define(wxMenuBar_new_1, 850). --define(wxMenuBar_new_0, 852). --define(wxMenuBar_destruct, 854). --define(wxMenuBar_Append, 855). --define(wxMenuBar_Check, 856). --define(wxMenuBar_Enable_2, 857). --define(wxMenuBar_Enable_1, 858). --define(wxMenuBar_EnableTop, 859). --define(wxMenuBar_FindMenu, 860). --define(wxMenuBar_FindMenuItem, 861). --define(wxMenuBar_FindItem, 862). --define(wxMenuBar_GetHelpString, 863). --define(wxMenuBar_GetLabel_1, 864). --define(wxMenuBar_GetLabel_0, 865). --define(wxMenuBar_GetLabelTop, 866). --define(wxMenuBar_GetMenu, 867). --define(wxMenuBar_GetMenuCount, 868). --define(wxMenuBar_Insert, 869). --define(wxMenuBar_IsChecked, 870). --define(wxMenuBar_IsEnabled_1, 871). --define(wxMenuBar_IsEnabled_0, 872). --define(wxMenuBar_Remove, 873). --define(wxMenuBar_Replace, 874). --define(wxMenuBar_SetHelpString, 875). --define(wxMenuBar_SetLabel_2, 876). --define(wxMenuBar_SetLabel_1, 877). --define(wxMenuBar_SetLabelTop, 878). --define(wxControl_GetLabel, 879). --define(wxControl_SetLabel, 880). --define(wxControlWithItems_Append_1, 881). --define(wxControlWithItems_Append_2, 882). --define(wxControlWithItems_appendStrings_1, 883). --define(wxControlWithItems_Clear, 884). --define(wxControlWithItems_Delete, 885). --define(wxControlWithItems_FindString, 886). --define(wxControlWithItems_getClientData, 887). --define(wxControlWithItems_setClientData, 888). --define(wxControlWithItems_GetCount, 889). --define(wxControlWithItems_GetSelection, 890). --define(wxControlWithItems_GetString, 891). --define(wxControlWithItems_GetStringSelection, 892). --define(wxControlWithItems_Insert_2, 893). --define(wxControlWithItems_Insert_3, 894). --define(wxControlWithItems_IsEmpty, 895). --define(wxControlWithItems_Select, 896). --define(wxControlWithItems_SetSelection, 897). --define(wxControlWithItems_SetString, 898). --define(wxControlWithItems_SetStringSelection, 899). --define(wxMenu_new_2, 902). --define(wxMenu_new_1, 903). --define(wxMenu_destruct, 905). --define(wxMenu_Append_3, 906). --define(wxMenu_Append_1, 907). --define(wxMenu_Append_4_0, 908). --define(wxMenu_Append_4_1, 909). --define(wxMenu_AppendCheckItem, 910). --define(wxMenu_AppendRadioItem, 911). --define(wxMenu_AppendSeparator, 912). --define(wxMenu_Break, 913). --define(wxMenu_Check, 914). --define(wxMenu_Delete_1_0, 915). --define(wxMenu_Delete_1_1, 916). --define(wxMenu_Destroy_1_0, 917). --define(wxMenu_Destroy_1_1, 918). --define(wxMenu_Enable, 919). --define(wxMenu_FindItem_1, 920). --define(wxMenu_FindItem_2, 921). --define(wxMenu_FindItemByPosition, 922). --define(wxMenu_GetHelpString, 923). --define(wxMenu_GetLabel, 924). --define(wxMenu_GetMenuItemCount, 925). --define(wxMenu_GetMenuItems, 926). --define(wxMenu_GetTitle, 928). --define(wxMenu_Insert_2, 929). --define(wxMenu_Insert_3, 930). --define(wxMenu_Insert_5_1, 931). --define(wxMenu_Insert_5_0, 932). --define(wxMenu_InsertCheckItem, 933). --define(wxMenu_InsertRadioItem, 934). --define(wxMenu_InsertSeparator, 935). --define(wxMenu_IsChecked, 936). --define(wxMenu_IsEnabled, 937). --define(wxMenu_Prepend_1, 938). --define(wxMenu_Prepend_2, 939). --define(wxMenu_Prepend_4_1, 940). --define(wxMenu_Prepend_4_0, 941). --define(wxMenu_PrependCheckItem, 942). --define(wxMenu_PrependRadioItem, 943). --define(wxMenu_PrependSeparator, 944). --define(wxMenu_Remove_1_0, 945). --define(wxMenu_Remove_1_1, 946). --define(wxMenu_SetHelpString, 947). --define(wxMenu_SetLabel, 948). --define(wxMenu_SetTitle, 949). --define(wxMenuItem_new, 950). --define(wxMenuItem_destruct, 952). --define(wxMenuItem_Check, 953). --define(wxMenuItem_Enable, 954). --define(wxMenuItem_GetBitmap, 955). --define(wxMenuItem_GetHelp, 956). --define(wxMenuItem_GetId, 957). --define(wxMenuItem_GetKind, 958). --define(wxMenuItem_GetLabel, 959). --define(wxMenuItem_GetLabelFromText, 960). --define(wxMenuItem_GetMenu, 961). --define(wxMenuItem_GetText, 962). --define(wxMenuItem_GetSubMenu, 963). --define(wxMenuItem_IsCheckable, 964). --define(wxMenuItem_IsChecked, 965). --define(wxMenuItem_IsEnabled, 966). --define(wxMenuItem_IsSeparator, 967). --define(wxMenuItem_IsSubMenu, 968). --define(wxMenuItem_SetBitmap, 969). --define(wxMenuItem_SetHelp, 970). --define(wxMenuItem_SetMenu, 971). --define(wxMenuItem_SetSubMenu, 972). --define(wxMenuItem_SetText, 973). --define(wxToolBar_AddControl, 974). --define(wxToolBar_AddSeparator, 975). --define(wxToolBar_AddTool_5, 976). --define(wxToolBar_AddTool_4_0, 977). --define(wxToolBar_AddTool_1, 978). --define(wxToolBar_AddTool_4_1, 979). --define(wxToolBar_AddTool_3, 980). --define(wxToolBar_AddTool_6, 981). --define(wxToolBar_AddCheckTool, 982). --define(wxToolBar_AddRadioTool, 983). --define(wxToolBar_DeleteTool, 984). --define(wxToolBar_DeleteToolByPos, 985). --define(wxToolBar_EnableTool, 986). --define(wxToolBar_FindById, 987). --define(wxToolBar_FindControl, 988). --define(wxToolBar_FindToolForPosition, 989). --define(wxToolBar_GetToolSize, 990). --define(wxToolBar_GetToolBitmapSize, 991). --define(wxToolBar_GetMargins, 992). --define(wxToolBar_GetToolEnabled, 993). --define(wxToolBar_GetToolLongHelp, 994). --define(wxToolBar_GetToolPacking, 995). --define(wxToolBar_GetToolPos, 996). --define(wxToolBar_GetToolSeparation, 997). --define(wxToolBar_GetToolShortHelp, 998). --define(wxToolBar_GetToolState, 999). --define(wxToolBar_InsertControl, 1000). --define(wxToolBar_InsertSeparator, 1001). --define(wxToolBar_InsertTool_5, 1002). --define(wxToolBar_InsertTool_2, 1003). --define(wxToolBar_InsertTool_4, 1004). --define(wxToolBar_Realize, 1005). --define(wxToolBar_RemoveTool, 1006). --define(wxToolBar_SetMargins, 1007). --define(wxToolBar_SetToolBitmapSize, 1008). --define(wxToolBar_SetToolLongHelp, 1009). --define(wxToolBar_SetToolPacking, 1010). --define(wxToolBar_SetToolShortHelp, 1011). --define(wxToolBar_SetToolSeparation, 1012). --define(wxToolBar_ToggleTool, 1013). --define(wxStatusBar_new_0, 1015). --define(wxStatusBar_new_2, 1016). --define(wxStatusBar_destruct, 1018). --define(wxStatusBar_Create, 1019). --define(wxStatusBar_GetFieldRect, 1020). --define(wxStatusBar_GetFieldsCount, 1021). --define(wxStatusBar_GetStatusText, 1022). --define(wxStatusBar_PopStatusText, 1023). --define(wxStatusBar_PushStatusText, 1024). --define(wxStatusBar_SetFieldsCount, 1025). --define(wxStatusBar_SetMinHeight, 1026). --define(wxStatusBar_SetStatusText, 1027). --define(wxStatusBar_SetStatusWidths, 1028). --define(wxStatusBar_SetStatusStyles, 1029). --define(wxBitmap_new_0, 1030). --define(wxBitmap_new_3, 1031). --define(wxBitmap_new_4, 1032). --define(wxBitmap_new_2_0, 1033). --define(wxBitmap_new_2_1, 1034). --define(wxBitmap_destruct, 1035). --define(wxBitmap_ConvertToImage, 1036). --define(wxBitmap_CopyFromIcon, 1037). --define(wxBitmap_Create, 1038). --define(wxBitmap_GetDepth, 1039). --define(wxBitmap_GetHeight, 1040). --define(wxBitmap_GetPalette, 1041). --define(wxBitmap_GetMask, 1042). --define(wxBitmap_GetWidth, 1043). --define(wxBitmap_GetSubBitmap, 1044). --define(wxBitmap_LoadFile, 1045). --define(wxBitmap_Ok, 1046). --define(wxBitmap_SaveFile, 1047). --define(wxBitmap_SetDepth, 1048). --define(wxBitmap_SetHeight, 1049). --define(wxBitmap_SetMask, 1050). --define(wxBitmap_SetPalette, 1051). --define(wxBitmap_SetWidth, 1052). --define(wxIcon_new_0, 1053). --define(wxIcon_new_2, 1054). --define(wxIcon_new_1, 1055). --define(wxIcon_CopyFromBitmap, 1056). --define(wxIcon_destroy, 1057). --define(wxIconBundle_new_0, 1058). --define(wxIconBundle_new_2, 1059). --define(wxIconBundle_new_1_0, 1060). --define(wxIconBundle_new_1_1, 1061). --define(wxIconBundle_destruct, 1062). --define(wxIconBundle_AddIcon_2, 1063). --define(wxIconBundle_AddIcon_1, 1064). --define(wxIconBundle_GetIcon_1_1, 1065). --define(wxIconBundle_GetIcon_1_0, 1066). --define(wxCursor_new_0, 1067). --define(wxCursor_new_1_0, 1068). --define(wxCursor_new_1_1, 1069). --define(wxCursor_new_4, 1070). --define(wxCursor_destruct, 1071). --define(wxCursor_Ok, 1072). --define(wxMask_new_0, 1073). --define(wxMask_new_2_1, 1074). --define(wxMask_new_2_0, 1075). --define(wxMask_new_1, 1076). --define(wxMask_destruct, 1077). --define(wxMask_Create_2_1, 1078). --define(wxMask_Create_2_0, 1079). --define(wxMask_Create_1, 1080). --define(wxImage_new_0, 1081). --define(wxImage_new_3_0, 1082). --define(wxImage_new_4, 1083). --define(wxImage_new_5, 1084). --define(wxImage_new_2, 1085). --define(wxImage_new_3_1, 1086). --define(wxImage_Blur, 1087). --define(wxImage_BlurHorizontal, 1088). --define(wxImage_BlurVertical, 1089). --define(wxImage_ConvertAlphaToMask, 1090). --define(wxImage_ConvertToGreyscale, 1091). --define(wxImage_ConvertToMono, 1092). --define(wxImage_Copy, 1093). --define(wxImage_Create_3, 1094). --define(wxImage_Create_4, 1095). --define(wxImage_Create_5, 1096). --define(wxImage_Destroy, 1097). --define(wxImage_FindFirstUnusedColour, 1098). --define(wxImage_GetImageExtWildcard, 1099). --define(wxImage_GetAlpha_2, 1100). --define(wxImage_GetAlpha_0, 1101). --define(wxImage_GetBlue, 1102). --define(wxImage_GetData, 1103). --define(wxImage_GetGreen, 1104). --define(wxImage_GetImageCount, 1105). --define(wxImage_GetHeight, 1106). --define(wxImage_GetMaskBlue, 1107). --define(wxImage_GetMaskGreen, 1108). --define(wxImage_GetMaskRed, 1109). --define(wxImage_GetOrFindMaskColour, 1110). --define(wxImage_GetPalette, 1111). --define(wxImage_GetRed, 1112). --define(wxImage_GetSubImage, 1113). --define(wxImage_GetWidth, 1114). --define(wxImage_HasAlpha, 1115). --define(wxImage_HasMask, 1116). --define(wxImage_GetOption, 1117). --define(wxImage_GetOptionInt, 1118). --define(wxImage_HasOption, 1119). --define(wxImage_InitAlpha, 1120). --define(wxImage_InitStandardHandlers, 1121). --define(wxImage_IsTransparent, 1122). --define(wxImage_LoadFile_2, 1123). --define(wxImage_LoadFile_3, 1124). --define(wxImage_Ok, 1125). --define(wxImage_RemoveHandler, 1126). --define(wxImage_Mirror, 1127). --define(wxImage_Replace, 1128). --define(wxImage_Rescale, 1129). --define(wxImage_Resize, 1130). --define(wxImage_Rotate, 1131). --define(wxImage_RotateHue, 1132). --define(wxImage_Rotate90, 1133). --define(wxImage_SaveFile_1, 1134). --define(wxImage_SaveFile_2_0, 1135). --define(wxImage_SaveFile_2_1, 1136). --define(wxImage_Scale, 1137). --define(wxImage_Size, 1138). --define(wxImage_SetAlpha_3, 1139). --define(wxImage_SetAlpha_2, 1140). --define(wxImage_SetData_2, 1141). --define(wxImage_SetData_4, 1142). --define(wxImage_SetMask, 1143). --define(wxImage_SetMaskColour, 1144). --define(wxImage_SetMaskFromImage, 1145). --define(wxImage_SetOption_2_1, 1146). --define(wxImage_SetOption_2_0, 1147). --define(wxImage_SetPalette, 1148). --define(wxImage_SetRGB_5, 1149). --define(wxImage_SetRGB_4, 1150). --define(wxImage_destroy, 1151). --define(wxBrush_new_0, 1152). --define(wxBrush_new_2, 1153). --define(wxBrush_new_1, 1154). --define(wxBrush_destruct, 1156). --define(wxBrush_GetColour, 1157). --define(wxBrush_GetStipple, 1158). --define(wxBrush_GetStyle, 1159). --define(wxBrush_IsHatch, 1160). --define(wxBrush_IsOk, 1161). --define(wxBrush_SetColour_1, 1162). --define(wxBrush_SetColour_3, 1163). --define(wxBrush_SetStipple, 1164). --define(wxBrush_SetStyle, 1165). --define(wxPen_new_0, 1166). --define(wxPen_new_2, 1167). --define(wxPen_destruct, 1168). --define(wxPen_GetCap, 1169). --define(wxPen_GetColour, 1170). --define(wxPen_GetJoin, 1171). --define(wxPen_GetStyle, 1172). --define(wxPen_GetWidth, 1173). --define(wxPen_IsOk, 1174). --define(wxPen_SetCap, 1175). --define(wxPen_SetColour_1, 1176). --define(wxPen_SetColour_3, 1177). --define(wxPen_SetJoin, 1178). --define(wxPen_SetStyle, 1179). --define(wxPen_SetWidth, 1180). --define(wxRegion_new_0, 1181). --define(wxRegion_new_4, 1182). --define(wxRegion_new_2, 1183). --define(wxRegion_new_1_1, 1184). --define(wxRegion_new_1_0, 1186). --define(wxRegion_destruct, 1188). --define(wxRegion_Clear, 1189). --define(wxRegion_Contains_2, 1190). --define(wxRegion_Contains_1_0, 1191). --define(wxRegion_Contains_4, 1192). --define(wxRegion_Contains_1_1, 1193). --define(wxRegion_ConvertToBitmap, 1194). --define(wxRegion_GetBox, 1195). --define(wxRegion_Intersect_4, 1196). --define(wxRegion_Intersect_1_1, 1197). --define(wxRegion_Intersect_1_0, 1198). --define(wxRegion_IsEmpty, 1199). --define(wxRegion_Subtract_4, 1200). --define(wxRegion_Subtract_1_1, 1201). --define(wxRegion_Subtract_1_0, 1202). --define(wxRegion_Offset_2, 1203). --define(wxRegion_Offset_1, 1204). --define(wxRegion_Union_4, 1205). --define(wxRegion_Union_1_2, 1206). --define(wxRegion_Union_1_1, 1207). --define(wxRegion_Union_1_0, 1208). --define(wxRegion_Union_3, 1209). --define(wxRegion_Xor_4, 1210). --define(wxRegion_Xor_1_1, 1211). --define(wxRegion_Xor_1_0, 1212). --define(wxAcceleratorTable_new_0, 1213). --define(wxAcceleratorTable_new_2, 1214). --define(wxAcceleratorTable_destruct, 1215). --define(wxAcceleratorTable_Ok, 1216). --define(wxAcceleratorEntry_new_1_0, 1217). --define(wxAcceleratorEntry_new_1_1, 1218). --define(wxAcceleratorEntry_GetCommand, 1219). --define(wxAcceleratorEntry_GetFlags, 1220). --define(wxAcceleratorEntry_GetKeyCode, 1221). --define(wxAcceleratorEntry_Set, 1222). --define(wxAcceleratorEntry_destroy, 1223). --define(wxCaret_new_3, 1228). --define(wxCaret_new_2, 1229). --define(wxCaret_destruct, 1231). --define(wxCaret_Create_3, 1232). --define(wxCaret_Create_2, 1233). --define(wxCaret_GetBlinkTime, 1234). --define(wxCaret_GetPosition, 1236). --define(wxCaret_GetSize, 1238). --define(wxCaret_GetWindow, 1239). --define(wxCaret_Hide, 1240). --define(wxCaret_IsOk, 1241). --define(wxCaret_IsVisible, 1242). --define(wxCaret_Move_2, 1243). --define(wxCaret_Move_1, 1244). --define(wxCaret_SetBlinkTime, 1245). --define(wxCaret_SetSize_2, 1246). --define(wxCaret_SetSize_1, 1247). --define(wxCaret_Show, 1248). --define(wxSizer_Add_2_1, 1249). --define(wxSizer_Add_2_0, 1250). --define(wxSizer_Add_3, 1251). --define(wxSizer_Add_2_3, 1252). --define(wxSizer_Add_2_2, 1253). --define(wxSizer_AddSpacer, 1254). --define(wxSizer_AddStretchSpacer, 1255). --define(wxSizer_CalcMin, 1256). --define(wxSizer_Clear, 1257). --define(wxSizer_Detach_1_2, 1258). --define(wxSizer_Detach_1_1, 1259). --define(wxSizer_Detach_1_0, 1260). --define(wxSizer_Fit, 1261). --define(wxSizer_FitInside, 1262). --define(wxSizer_GetChildren, 1263). --define(wxSizer_GetItem_2_1, 1264). --define(wxSizer_GetItem_2_0, 1265). --define(wxSizer_GetItem_1, 1266). --define(wxSizer_GetSize, 1267). --define(wxSizer_GetPosition, 1268). --define(wxSizer_GetMinSize, 1269). --define(wxSizer_Hide_2_0, 1270). --define(wxSizer_Hide_2_1, 1271). --define(wxSizer_Hide_1, 1272). --define(wxSizer_Insert_3_1, 1273). --define(wxSizer_Insert_3_0, 1274). --define(wxSizer_Insert_4, 1275). --define(wxSizer_Insert_3_3, 1276). --define(wxSizer_Insert_3_2, 1277). --define(wxSizer_Insert_2, 1278). --define(wxSizer_InsertSpacer, 1279). --define(wxSizer_InsertStretchSpacer, 1280). --define(wxSizer_IsShown_1_2, 1281). --define(wxSizer_IsShown_1_1, 1282). --define(wxSizer_IsShown_1_0, 1283). --define(wxSizer_Layout, 1284). --define(wxSizer_Prepend_2_1, 1285). --define(wxSizer_Prepend_2_0, 1286). --define(wxSizer_Prepend_3, 1287). --define(wxSizer_Prepend_2_3, 1288). --define(wxSizer_Prepend_2_2, 1289). --define(wxSizer_Prepend_1, 1290). --define(wxSizer_PrependSpacer, 1291). --define(wxSizer_PrependStretchSpacer, 1292). --define(wxSizer_RecalcSizes, 1293). --define(wxSizer_Remove_1_1, 1294). --define(wxSizer_Remove_1_0, 1295). --define(wxSizer_Replace_3_1, 1296). --define(wxSizer_Replace_3_0, 1297). --define(wxSizer_Replace_2, 1298). --define(wxSizer_SetDimension, 1299). --define(wxSizer_SetMinSize_2, 1300). --define(wxSizer_SetMinSize_1, 1301). --define(wxSizer_SetItemMinSize_3_2, 1302). --define(wxSizer_SetItemMinSize_2_2, 1303). --define(wxSizer_SetItemMinSize_3_1, 1304). --define(wxSizer_SetItemMinSize_2_1, 1305). --define(wxSizer_SetItemMinSize_3_0, 1306). --define(wxSizer_SetItemMinSize_2_0, 1307). --define(wxSizer_SetSizeHints, 1308). --define(wxSizer_SetVirtualSizeHints, 1309). --define(wxSizer_Show_2_2, 1310). --define(wxSizer_Show_2_1, 1311). --define(wxSizer_Show_2_0, 1312). --define(wxSizer_Show_1, 1313). --define(wxSizerFlags_new, 1314). --define(wxSizerFlags_Align, 1315). --define(wxSizerFlags_Border_2, 1316). --define(wxSizerFlags_Border_1, 1317). --define(wxSizerFlags_Center, 1318). --define(wxSizerFlags_Centre, 1319). --define(wxSizerFlags_Expand, 1320). --define(wxSizerFlags_Left, 1321). --define(wxSizerFlags_Proportion, 1322). --define(wxSizerFlags_Right, 1323). --define(wxSizerFlags_destroy, 1324). --define(wxSizerItem_new_5_1, 1325). --define(wxSizerItem_new_2_1, 1326). --define(wxSizerItem_new_5_0, 1327). --define(wxSizerItem_new_2_0, 1328). --define(wxSizerItem_new_6, 1329). --define(wxSizerItem_new_3, 1330). --define(wxSizerItem_new_0, 1331). --define(wxSizerItem_destruct, 1332). --define(wxSizerItem_CalcMin, 1333). --define(wxSizerItem_DeleteWindows, 1334). --define(wxSizerItem_DetachSizer, 1335). --define(wxSizerItem_GetBorder, 1336). --define(wxSizerItem_GetFlag, 1337). --define(wxSizerItem_GetMinSize, 1338). --define(wxSizerItem_GetPosition, 1339). --define(wxSizerItem_GetProportion, 1340). --define(wxSizerItem_GetRatio, 1341). --define(wxSizerItem_GetRect, 1342). --define(wxSizerItem_GetSize, 1343). --define(wxSizerItem_GetSizer, 1344). --define(wxSizerItem_GetSpacer, 1345). --define(wxSizerItem_GetUserData, 1346). --define(wxSizerItem_GetWindow, 1347). --define(wxSizerItem_IsSizer, 1348). --define(wxSizerItem_IsShown, 1349). --define(wxSizerItem_IsSpacer, 1350). --define(wxSizerItem_IsWindow, 1351). --define(wxSizerItem_SetBorder, 1352). --define(wxSizerItem_SetDimension, 1353). --define(wxSizerItem_SetFlag, 1354). --define(wxSizerItem_SetInitSize, 1355). --define(wxSizerItem_SetMinSize_1, 1356). --define(wxSizerItem_SetMinSize_2, 1357). --define(wxSizerItem_SetProportion, 1358). --define(wxSizerItem_SetRatio_2, 1359). --define(wxSizerItem_SetRatio_1_1, 1360). --define(wxSizerItem_SetRatio_1_0, 1361). --define(wxSizerItem_SetSizer, 1362). --define(wxSizerItem_SetSpacer_1, 1363). --define(wxSizerItem_SetSpacer_2, 1364). --define(wxSizerItem_SetWindow, 1365). --define(wxSizerItem_Show, 1366). --define(wxBoxSizer_new, 1367). --define(wxBoxSizer_GetOrientation, 1368). --define(wxBoxSizer_destroy, 1369). --define(wxStaticBoxSizer_new_2, 1370). --define(wxStaticBoxSizer_new_3, 1371). --define(wxStaticBoxSizer_GetStaticBox, 1372). --define(wxStaticBoxSizer_destroy, 1373). --define(wxGridSizer_new_4, 1374). --define(wxGridSizer_new_2, 1375). --define(wxGridSizer_GetCols, 1376). --define(wxGridSizer_GetHGap, 1377). --define(wxGridSizer_GetRows, 1378). --define(wxGridSizer_GetVGap, 1379). --define(wxGridSizer_SetCols, 1380). --define(wxGridSizer_SetHGap, 1381). --define(wxGridSizer_SetRows, 1382). --define(wxGridSizer_SetVGap, 1383). --define(wxGridSizer_destroy, 1384). --define(wxFlexGridSizer_new_4, 1385). --define(wxFlexGridSizer_new_2, 1386). --define(wxFlexGridSizer_AddGrowableCol, 1387). --define(wxFlexGridSizer_AddGrowableRow, 1388). --define(wxFlexGridSizer_GetFlexibleDirection, 1389). --define(wxFlexGridSizer_GetNonFlexibleGrowMode, 1390). --define(wxFlexGridSizer_RemoveGrowableCol, 1391). --define(wxFlexGridSizer_RemoveGrowableRow, 1392). --define(wxFlexGridSizer_SetFlexibleDirection, 1393). --define(wxFlexGridSizer_SetNonFlexibleGrowMode, 1394). --define(wxFlexGridSizer_destroy, 1395). --define(wxGridBagSizer_new, 1396). --define(wxGridBagSizer_Add_3_2, 1397). --define(wxGridBagSizer_Add_3_1, 1398). --define(wxGridBagSizer_Add_4, 1399). --define(wxGridBagSizer_Add_1_0, 1400). --define(wxGridBagSizer_Add_2_1, 1401). --define(wxGridBagSizer_Add_2_0, 1402). --define(wxGridBagSizer_Add_3_0, 1403). --define(wxGridBagSizer_Add_1_1, 1404). --define(wxGridBagSizer_CalcMin, 1405). --define(wxGridBagSizer_CheckForIntersection_2, 1406). --define(wxGridBagSizer_CheckForIntersection_3, 1407). --define(wxGridBagSizer_FindItem_1_1, 1408). --define(wxGridBagSizer_FindItem_1_0, 1409). --define(wxGridBagSizer_FindItemAtPoint, 1410). --define(wxGridBagSizer_FindItemAtPosition, 1411). --define(wxGridBagSizer_FindItemWithData, 1412). --define(wxGridBagSizer_GetCellSize, 1413). --define(wxGridBagSizer_GetEmptyCellSize, 1414). --define(wxGridBagSizer_GetItemPosition_1_2, 1415). --define(wxGridBagSizer_GetItemPosition_1_1, 1416). --define(wxGridBagSizer_GetItemPosition_1_0, 1417). --define(wxGridBagSizer_GetItemSpan_1_2, 1418). --define(wxGridBagSizer_GetItemSpan_1_1, 1419). --define(wxGridBagSizer_GetItemSpan_1_0, 1420). --define(wxGridBagSizer_SetEmptyCellSize, 1421). --define(wxGridBagSizer_SetItemPosition_2_2, 1422). --define(wxGridBagSizer_SetItemPosition_2_1, 1423). --define(wxGridBagSizer_SetItemPosition_2_0, 1424). --define(wxGridBagSizer_SetItemSpan_2_2, 1425). --define(wxGridBagSizer_SetItemSpan_2_1, 1426). --define(wxGridBagSizer_SetItemSpan_2_0, 1427). --define(wxGridBagSizer_destroy, 1428). --define(wxStdDialogButtonSizer_new, 1429). --define(wxStdDialogButtonSizer_AddButton, 1430). --define(wxStdDialogButtonSizer_Realize, 1431). --define(wxStdDialogButtonSizer_SetAffirmativeButton, 1432). --define(wxStdDialogButtonSizer_SetCancelButton, 1433). --define(wxStdDialogButtonSizer_SetNegativeButton, 1434). --define(wxStdDialogButtonSizer_destroy, 1435). --define(wxFont_new_0, 1436). --define(wxFont_new_1, 1437). --define(wxFont_new_5, 1438). --define(wxFont_destruct, 1440). --define(wxFont_IsFixedWidth, 1441). --define(wxFont_GetDefaultEncoding, 1442). --define(wxFont_GetFaceName, 1443). --define(wxFont_GetFamily, 1444). --define(wxFont_GetNativeFontInfoDesc, 1445). --define(wxFont_GetNativeFontInfoUserDesc, 1446). --define(wxFont_GetPointSize, 1447). --define(wxFont_GetStyle, 1448). --define(wxFont_GetUnderlined, 1449). --define(wxFont_GetWeight, 1450). --define(wxFont_Ok, 1451). --define(wxFont_SetDefaultEncoding, 1452). --define(wxFont_SetFaceName, 1453). --define(wxFont_SetFamily, 1454). --define(wxFont_SetPointSize, 1455). --define(wxFont_SetStyle, 1456). --define(wxFont_SetUnderlined, 1457). --define(wxFont_SetWeight, 1458). --define(wxToolTip_Enable, 1459). --define(wxToolTip_SetDelay, 1460). --define(wxToolTip_new, 1461). --define(wxToolTip_SetTip, 1462). --define(wxToolTip_GetTip, 1463). --define(wxToolTip_GetWindow, 1464). --define(wxToolTip_destroy, 1465). --define(wxButton_new_3, 1467). --define(wxButton_new_0, 1468). --define(wxButton_destruct, 1469). --define(wxButton_Create, 1470). --define(wxButton_GetDefaultSize, 1471). --define(wxButton_SetDefault, 1472). --define(wxButton_SetLabel, 1473). --define(wxBitmapButton_new_4, 1475). --define(wxBitmapButton_new_0, 1476). --define(wxBitmapButton_Create, 1477). --define(wxBitmapButton_GetBitmapDisabled, 1478). --define(wxBitmapButton_GetBitmapFocus, 1480). --define(wxBitmapButton_GetBitmapLabel, 1482). --define(wxBitmapButton_GetBitmapSelected, 1484). --define(wxBitmapButton_SetBitmapDisabled, 1486). --define(wxBitmapButton_SetBitmapFocus, 1487). --define(wxBitmapButton_SetBitmapLabel, 1488). --define(wxBitmapButton_SetBitmapSelected, 1489). --define(wxBitmapButton_destroy, 1490). --define(wxToggleButton_new_0, 1491). --define(wxToggleButton_new_4, 1492). --define(wxToggleButton_Create, 1493). --define(wxToggleButton_GetValue, 1494). --define(wxToggleButton_SetValue, 1495). --define(wxToggleButton_destroy, 1496). --define(wxCalendarCtrl_new_0, 1497). --define(wxCalendarCtrl_new_3, 1498). --define(wxCalendarCtrl_Create, 1499). --define(wxCalendarCtrl_destruct, 1500). --define(wxCalendarCtrl_SetDate, 1501). --define(wxCalendarCtrl_GetDate, 1502). --define(wxCalendarCtrl_EnableYearChange, 1503). --define(wxCalendarCtrl_EnableMonthChange, 1504). --define(wxCalendarCtrl_EnableHolidayDisplay, 1505). --define(wxCalendarCtrl_SetHeaderColours, 1506). --define(wxCalendarCtrl_GetHeaderColourFg, 1507). --define(wxCalendarCtrl_GetHeaderColourBg, 1508). --define(wxCalendarCtrl_SetHighlightColours, 1509). --define(wxCalendarCtrl_GetHighlightColourFg, 1510). --define(wxCalendarCtrl_GetHighlightColourBg, 1511). --define(wxCalendarCtrl_SetHolidayColours, 1512). --define(wxCalendarCtrl_GetHolidayColourFg, 1513). --define(wxCalendarCtrl_GetHolidayColourBg, 1514). --define(wxCalendarCtrl_GetAttr, 1515). --define(wxCalendarCtrl_SetAttr, 1516). --define(wxCalendarCtrl_SetHoliday, 1517). --define(wxCalendarCtrl_ResetAttr, 1518). --define(wxCalendarCtrl_HitTest, 1519). --define(wxCalendarDateAttr_new_0, 1520). --define(wxCalendarDateAttr_new_2_1, 1521). --define(wxCalendarDateAttr_new_2_0, 1522). --define(wxCalendarDateAttr_SetTextColour, 1523). --define(wxCalendarDateAttr_SetBackgroundColour, 1524). --define(wxCalendarDateAttr_SetBorderColour, 1525). --define(wxCalendarDateAttr_SetFont, 1526). --define(wxCalendarDateAttr_SetBorder, 1527). --define(wxCalendarDateAttr_SetHoliday, 1528). --define(wxCalendarDateAttr_HasTextColour, 1529). --define(wxCalendarDateAttr_HasBackgroundColour, 1530). --define(wxCalendarDateAttr_HasBorderColour, 1531). --define(wxCalendarDateAttr_HasFont, 1532). --define(wxCalendarDateAttr_HasBorder, 1533). --define(wxCalendarDateAttr_IsHoliday, 1534). --define(wxCalendarDateAttr_GetTextColour, 1535). --define(wxCalendarDateAttr_GetBackgroundColour, 1536). --define(wxCalendarDateAttr_GetBorderColour, 1537). --define(wxCalendarDateAttr_GetFont, 1538). --define(wxCalendarDateAttr_GetBorder, 1539). --define(wxCalendarDateAttr_destroy, 1540). --define(wxCheckBox_new_4, 1542). --define(wxCheckBox_new_0, 1543). --define(wxCheckBox_Create, 1544). --define(wxCheckBox_GetValue, 1545). --define(wxCheckBox_Get3StateValue, 1546). --define(wxCheckBox_Is3rdStateAllowedForUser, 1547). --define(wxCheckBox_Is3State, 1548). --define(wxCheckBox_IsChecked, 1549). --define(wxCheckBox_SetValue, 1550). --define(wxCheckBox_Set3StateValue, 1551). --define(wxCheckBox_destroy, 1552). --define(wxCheckListBox_new_0, 1553). --define(wxCheckListBox_new_3, 1555). --define(wxCheckListBox_Check, 1556). --define(wxCheckListBox_IsChecked, 1557). --define(wxCheckListBox_destroy, 1558). --define(wxChoice_new_3, 1561). --define(wxChoice_new_0, 1562). --define(wxChoice_destruct, 1564). --define(wxChoice_Create, 1566). --define(wxChoice_Delete, 1567). --define(wxChoice_GetColumns, 1568). --define(wxChoice_SetColumns, 1569). --define(wxComboBox_new_0, 1570). --define(wxComboBox_new_3, 1572). --define(wxComboBox_destruct, 1573). --define(wxComboBox_Create, 1575). --define(wxComboBox_CanCopy, 1576). --define(wxComboBox_CanCut, 1577). --define(wxComboBox_CanPaste, 1578). --define(wxComboBox_CanRedo, 1579). --define(wxComboBox_CanUndo, 1580). --define(wxComboBox_Copy, 1581). --define(wxComboBox_Cut, 1582). --define(wxComboBox_GetInsertionPoint, 1583). --define(wxComboBox_GetLastPosition, 1584). --define(wxComboBox_GetValue, 1585). --define(wxComboBox_Paste, 1586). --define(wxComboBox_Redo, 1587). --define(wxComboBox_Replace, 1588). --define(wxComboBox_Remove, 1589). --define(wxComboBox_SetInsertionPoint, 1590). --define(wxComboBox_SetInsertionPointEnd, 1591). --define(wxComboBox_SetSelection_1, 1592). --define(wxComboBox_SetSelection_2, 1593). --define(wxComboBox_SetValue, 1594). --define(wxComboBox_Undo, 1595). --define(wxGauge_new_0, 1596). --define(wxGauge_new_4, 1597). --define(wxGauge_Create, 1598). --define(wxGauge_GetBezelFace, 1599). --define(wxGauge_GetRange, 1600). --define(wxGauge_GetShadowWidth, 1601). --define(wxGauge_GetValue, 1602). --define(wxGauge_IsVertical, 1603). --define(wxGauge_SetBezelFace, 1604). --define(wxGauge_SetRange, 1605). --define(wxGauge_SetShadowWidth, 1606). --define(wxGauge_SetValue, 1607). --define(wxGauge_Pulse, 1608). --define(wxGauge_destroy, 1609). --define(wxGenericDirCtrl_new_0, 1610). --define(wxGenericDirCtrl_new_2, 1611). --define(wxGenericDirCtrl_destruct, 1612). --define(wxGenericDirCtrl_Create, 1613). --define(wxGenericDirCtrl_Init, 1614). --define(wxGenericDirCtrl_CollapseTree, 1615). --define(wxGenericDirCtrl_ExpandPath, 1616). --define(wxGenericDirCtrl_GetDefaultPath, 1617). --define(wxGenericDirCtrl_GetPath, 1618). --define(wxGenericDirCtrl_GetFilePath, 1619). --define(wxGenericDirCtrl_GetFilter, 1620). --define(wxGenericDirCtrl_GetFilterIndex, 1621). --define(wxGenericDirCtrl_GetRootId, 1622). --define(wxGenericDirCtrl_GetTreeCtrl, 1623). --define(wxGenericDirCtrl_ReCreateTree, 1624). --define(wxGenericDirCtrl_SetDefaultPath, 1625). --define(wxGenericDirCtrl_SetFilter, 1626). --define(wxGenericDirCtrl_SetFilterIndex, 1627). --define(wxGenericDirCtrl_SetPath, 1628). --define(wxStaticBox_new_4, 1630). --define(wxStaticBox_new_0, 1631). --define(wxStaticBox_Create, 1632). --define(wxStaticBox_destroy, 1633). --define(wxStaticLine_new_2, 1635). --define(wxStaticLine_new_0, 1636). --define(wxStaticLine_Create, 1637). --define(wxStaticLine_IsVertical, 1638). --define(wxStaticLine_GetDefaultSize, 1639). --define(wxStaticLine_destroy, 1640). --define(wxListBox_new_3, 1643). --define(wxListBox_new_0, 1644). --define(wxListBox_destruct, 1646). --define(wxListBox_Create, 1648). --define(wxListBox_Deselect, 1649). --define(wxListBox_GetSelections, 1650). --define(wxListBox_InsertItems, 1651). --define(wxListBox_IsSelected, 1652). --define(wxListBox_Set, 1653). --define(wxListBox_HitTest, 1654). --define(wxListBox_SetFirstItem_1_0, 1655). --define(wxListBox_SetFirstItem_1_1, 1656). --define(wxListCtrl_new_0, 1657). --define(wxListCtrl_new_2, 1658). --define(wxListCtrl_Arrange, 1659). --define(wxListCtrl_AssignImageList, 1660). --define(wxListCtrl_ClearAll, 1661). --define(wxListCtrl_Create, 1662). --define(wxListCtrl_DeleteAllItems, 1663). --define(wxListCtrl_DeleteColumn, 1664). --define(wxListCtrl_DeleteItem, 1665). --define(wxListCtrl_EditLabel, 1666). --define(wxListCtrl_EnsureVisible, 1667). --define(wxListCtrl_FindItem_3_0, 1668). --define(wxListCtrl_FindItem_3_1, 1669). --define(wxListCtrl_GetColumn, 1670). --define(wxListCtrl_GetColumnCount, 1671). --define(wxListCtrl_GetColumnWidth, 1672). --define(wxListCtrl_GetCountPerPage, 1673). --define(wxListCtrl_GetEditControl, 1674). --define(wxListCtrl_GetImageList, 1675). --define(wxListCtrl_GetItem, 1676). --define(wxListCtrl_GetItemBackgroundColour, 1677). --define(wxListCtrl_GetItemCount, 1678). --define(wxListCtrl_GetItemData, 1679). --define(wxListCtrl_GetItemFont, 1680). --define(wxListCtrl_GetItemPosition, 1681). --define(wxListCtrl_GetItemRect, 1682). --define(wxListCtrl_GetItemSpacing, 1683). --define(wxListCtrl_GetItemState, 1684). --define(wxListCtrl_GetItemText, 1685). --define(wxListCtrl_GetItemTextColour, 1686). --define(wxListCtrl_GetNextItem, 1687). --define(wxListCtrl_GetSelectedItemCount, 1688). --define(wxListCtrl_GetTextColour, 1689). --define(wxListCtrl_GetTopItem, 1690). --define(wxListCtrl_GetViewRect, 1691). --define(wxListCtrl_HitTest, 1692). --define(wxListCtrl_InsertColumn_2, 1693). --define(wxListCtrl_InsertColumn_3, 1694). --define(wxListCtrl_InsertItem_1, 1695). --define(wxListCtrl_InsertItem_2_1, 1696). --define(wxListCtrl_InsertItem_2_0, 1697). --define(wxListCtrl_InsertItem_3, 1698). --define(wxListCtrl_RefreshItem, 1699). --define(wxListCtrl_RefreshItems, 1700). --define(wxListCtrl_ScrollList, 1701). --define(wxListCtrl_SetBackgroundColour, 1702). --define(wxListCtrl_SetColumn, 1703). --define(wxListCtrl_SetColumnWidth, 1704). --define(wxListCtrl_SetImageList, 1705). --define(wxListCtrl_SetItem_1, 1706). --define(wxListCtrl_SetItem_4, 1707). --define(wxListCtrl_SetItemBackgroundColour, 1708). --define(wxListCtrl_SetItemCount, 1709). --define(wxListCtrl_SetItemData, 1710). --define(wxListCtrl_SetItemFont, 1711). --define(wxListCtrl_SetItemImage, 1712). --define(wxListCtrl_SetItemColumnImage, 1713). --define(wxListCtrl_SetItemPosition, 1714). --define(wxListCtrl_SetItemState, 1715). --define(wxListCtrl_SetItemText, 1716). --define(wxListCtrl_SetItemTextColour, 1717). --define(wxListCtrl_SetSingleStyle, 1718). --define(wxListCtrl_SetTextColour, 1719). --define(wxListCtrl_SetWindowStyleFlag, 1720). --define(wxListCtrl_SortItems, 1721). --define(wxListCtrl_destroy, 1722). --define(wxListView_ClearColumnImage, 1723). --define(wxListView_Focus, 1724). --define(wxListView_GetFirstSelected, 1725). --define(wxListView_GetFocusedItem, 1726). --define(wxListView_GetNextSelected, 1727). --define(wxListView_IsSelected, 1728). --define(wxListView_Select, 1729). --define(wxListView_SetColumnImage, 1730). --define(wxListItem_new_0, 1731). --define(wxListItem_new_1, 1732). --define(wxListItem_destruct, 1733). --define(wxListItem_Clear, 1734). --define(wxListItem_GetAlign, 1735). --define(wxListItem_GetBackgroundColour, 1736). --define(wxListItem_GetColumn, 1737). --define(wxListItem_GetFont, 1738). --define(wxListItem_GetId, 1739). --define(wxListItem_GetImage, 1740). --define(wxListItem_GetMask, 1741). --define(wxListItem_GetState, 1742). --define(wxListItem_GetText, 1743). --define(wxListItem_GetTextColour, 1744). --define(wxListItem_GetWidth, 1745). --define(wxListItem_SetAlign, 1746). --define(wxListItem_SetBackgroundColour, 1747). --define(wxListItem_SetColumn, 1748). --define(wxListItem_SetFont, 1749). --define(wxListItem_SetId, 1750). --define(wxListItem_SetImage, 1751). --define(wxListItem_SetMask, 1752). --define(wxListItem_SetState, 1753). --define(wxListItem_SetStateMask, 1754). --define(wxListItem_SetText, 1755). --define(wxListItem_SetTextColour, 1756). --define(wxListItem_SetWidth, 1757). --define(wxListItemAttr_new_0, 1758). --define(wxListItemAttr_new_3, 1759). --define(wxListItemAttr_GetBackgroundColour, 1760). --define(wxListItemAttr_GetFont, 1761). --define(wxListItemAttr_GetTextColour, 1762). --define(wxListItemAttr_HasBackgroundColour, 1763). --define(wxListItemAttr_HasFont, 1764). --define(wxListItemAttr_HasTextColour, 1765). --define(wxListItemAttr_SetBackgroundColour, 1766). --define(wxListItemAttr_SetFont, 1767). --define(wxListItemAttr_SetTextColour, 1768). --define(wxListItemAttr_destroy, 1769). --define(wxImageList_new_0, 1770). --define(wxImageList_new_3, 1771). --define(wxImageList_Add_1, 1772). --define(wxImageList_Add_2_0, 1773). --define(wxImageList_Add_2_1, 1774). --define(wxImageList_Create, 1775). --define(wxImageList_Draw, 1777). --define(wxImageList_GetBitmap, 1778). --define(wxImageList_GetIcon, 1779). --define(wxImageList_GetImageCount, 1780). --define(wxImageList_GetSize, 1781). --define(wxImageList_Remove, 1782). --define(wxImageList_RemoveAll, 1783). --define(wxImageList_Replace_2, 1784). --define(wxImageList_Replace_3, 1785). --define(wxImageList_destroy, 1786). --define(wxTextAttr_new_0, 1787). --define(wxTextAttr_new_2, 1788). --define(wxTextAttr_GetAlignment, 1789). --define(wxTextAttr_GetBackgroundColour, 1790). --define(wxTextAttr_GetFont, 1791). --define(wxTextAttr_GetLeftIndent, 1792). --define(wxTextAttr_GetLeftSubIndent, 1793). --define(wxTextAttr_GetRightIndent, 1794). --define(wxTextAttr_GetTabs, 1795). --define(wxTextAttr_GetTextColour, 1796). --define(wxTextAttr_HasBackgroundColour, 1797). --define(wxTextAttr_HasFont, 1798). --define(wxTextAttr_HasTextColour, 1799). --define(wxTextAttr_GetFlags, 1800). --define(wxTextAttr_IsDefault, 1801). --define(wxTextAttr_SetAlignment, 1802). --define(wxTextAttr_SetBackgroundColour, 1803). --define(wxTextAttr_SetFlags, 1804). --define(wxTextAttr_SetFont, 1805). --define(wxTextAttr_SetLeftIndent, 1806). --define(wxTextAttr_SetRightIndent, 1807). --define(wxTextAttr_SetTabs, 1808). --define(wxTextAttr_SetTextColour, 1809). --define(wxTextAttr_destroy, 1810). --define(wxTextCtrl_new_3, 1812). --define(wxTextCtrl_new_0, 1813). --define(wxTextCtrl_destruct, 1815). --define(wxTextCtrl_AppendText, 1816). --define(wxTextCtrl_CanCopy, 1817). --define(wxTextCtrl_CanCut, 1818). --define(wxTextCtrl_CanPaste, 1819). --define(wxTextCtrl_CanRedo, 1820). --define(wxTextCtrl_CanUndo, 1821). --define(wxTextCtrl_Clear, 1822). --define(wxTextCtrl_Copy, 1823). --define(wxTextCtrl_Create, 1824). --define(wxTextCtrl_Cut, 1825). --define(wxTextCtrl_DiscardEdits, 1826). --define(wxTextCtrl_ChangeValue, 1827). --define(wxTextCtrl_EmulateKeyPress, 1828). --define(wxTextCtrl_GetDefaultStyle, 1829). --define(wxTextCtrl_GetInsertionPoint, 1830). --define(wxTextCtrl_GetLastPosition, 1831). --define(wxTextCtrl_GetLineLength, 1832). --define(wxTextCtrl_GetLineText, 1833). --define(wxTextCtrl_GetNumberOfLines, 1834). --define(wxTextCtrl_GetRange, 1835). --define(wxTextCtrl_GetSelection, 1836). --define(wxTextCtrl_GetStringSelection, 1837). --define(wxTextCtrl_GetStyle, 1838). --define(wxTextCtrl_GetValue, 1839). --define(wxTextCtrl_IsEditable, 1840). --define(wxTextCtrl_IsModified, 1841). --define(wxTextCtrl_IsMultiLine, 1842). --define(wxTextCtrl_IsSingleLine, 1843). --define(wxTextCtrl_LoadFile, 1844). --define(wxTextCtrl_MarkDirty, 1845). --define(wxTextCtrl_Paste, 1846). --define(wxTextCtrl_PositionToXY, 1847). --define(wxTextCtrl_Redo, 1848). --define(wxTextCtrl_Remove, 1849). --define(wxTextCtrl_Replace, 1850). --define(wxTextCtrl_SaveFile, 1851). --define(wxTextCtrl_SetDefaultStyle, 1852). --define(wxTextCtrl_SetEditable, 1853). --define(wxTextCtrl_SetInsertionPoint, 1854). --define(wxTextCtrl_SetInsertionPointEnd, 1855). --define(wxTextCtrl_SetMaxLength, 1857). --define(wxTextCtrl_SetSelection, 1858). --define(wxTextCtrl_SetStyle, 1859). --define(wxTextCtrl_SetValue, 1860). --define(wxTextCtrl_ShowPosition, 1861). --define(wxTextCtrl_Undo, 1862). --define(wxTextCtrl_WriteText, 1863). --define(wxTextCtrl_XYToPosition, 1864). --define(wxNotebook_new_0, 1867). --define(wxNotebook_new_3, 1868). --define(wxNotebook_destruct, 1869). --define(wxNotebook_AddPage, 1870). --define(wxNotebook_AdvanceSelection, 1871). --define(wxNotebook_AssignImageList, 1872). --define(wxNotebook_Create, 1873). --define(wxNotebook_DeleteAllPages, 1874). --define(wxNotebook_DeletePage, 1875). --define(wxNotebook_RemovePage, 1876). --define(wxNotebook_GetCurrentPage, 1877). --define(wxNotebook_GetImageList, 1878). --define(wxNotebook_GetPage, 1880). --define(wxNotebook_GetPageCount, 1881). --define(wxNotebook_GetPageImage, 1882). --define(wxNotebook_GetPageText, 1883). --define(wxNotebook_GetRowCount, 1884). --define(wxNotebook_GetSelection, 1885). --define(wxNotebook_GetThemeBackgroundColour, 1886). --define(wxNotebook_HitTest, 1888). --define(wxNotebook_InsertPage, 1890). --define(wxNotebook_SetImageList, 1891). --define(wxNotebook_SetPadding, 1892). --define(wxNotebook_SetPageSize, 1893). --define(wxNotebook_SetPageImage, 1894). --define(wxNotebook_SetPageText, 1895). --define(wxNotebook_SetSelection, 1896). --define(wxNotebook_ChangeSelection, 1897). --define(wxChoicebook_new_0, 1898). --define(wxChoicebook_new_3, 1899). --define(wxChoicebook_AddPage, 1900). --define(wxChoicebook_AdvanceSelection, 1901). --define(wxChoicebook_AssignImageList, 1902). --define(wxChoicebook_Create, 1903). --define(wxChoicebook_DeleteAllPages, 1904). --define(wxChoicebook_DeletePage, 1905). --define(wxChoicebook_RemovePage, 1906). --define(wxChoicebook_GetCurrentPage, 1907). --define(wxChoicebook_GetImageList, 1908). --define(wxChoicebook_GetPage, 1910). --define(wxChoicebook_GetPageCount, 1911). --define(wxChoicebook_GetPageImage, 1912). --define(wxChoicebook_GetPageText, 1913). --define(wxChoicebook_GetSelection, 1914). --define(wxChoicebook_HitTest, 1915). --define(wxChoicebook_InsertPage, 1916). --define(wxChoicebook_SetImageList, 1917). --define(wxChoicebook_SetPageSize, 1918). --define(wxChoicebook_SetPageImage, 1919). --define(wxChoicebook_SetPageText, 1920). --define(wxChoicebook_SetSelection, 1921). --define(wxChoicebook_ChangeSelection, 1922). --define(wxChoicebook_destroy, 1923). --define(wxToolbook_new_0, 1924). --define(wxToolbook_new_3, 1925). --define(wxToolbook_AddPage, 1926). --define(wxToolbook_AdvanceSelection, 1927). --define(wxToolbook_AssignImageList, 1928). --define(wxToolbook_Create, 1929). --define(wxToolbook_DeleteAllPages, 1930). --define(wxToolbook_DeletePage, 1931). --define(wxToolbook_RemovePage, 1932). --define(wxToolbook_GetCurrentPage, 1933). --define(wxToolbook_GetImageList, 1934). --define(wxToolbook_GetPage, 1936). --define(wxToolbook_GetPageCount, 1937). --define(wxToolbook_GetPageImage, 1938). --define(wxToolbook_GetPageText, 1939). --define(wxToolbook_GetSelection, 1940). --define(wxToolbook_HitTest, 1942). --define(wxToolbook_InsertPage, 1943). --define(wxToolbook_SetImageList, 1944). --define(wxToolbook_SetPageSize, 1945). --define(wxToolbook_SetPageImage, 1946). --define(wxToolbook_SetPageText, 1947). --define(wxToolbook_SetSelection, 1948). --define(wxToolbook_ChangeSelection, 1949). --define(wxToolbook_destroy, 1950). --define(wxListbook_new_0, 1951). --define(wxListbook_new_3, 1952). --define(wxListbook_AddPage, 1953). --define(wxListbook_AdvanceSelection, 1954). --define(wxListbook_AssignImageList, 1955). --define(wxListbook_Create, 1956). --define(wxListbook_DeleteAllPages, 1957). --define(wxListbook_DeletePage, 1958). --define(wxListbook_RemovePage, 1959). --define(wxListbook_GetCurrentPage, 1960). --define(wxListbook_GetImageList, 1961). --define(wxListbook_GetPage, 1963). --define(wxListbook_GetPageCount, 1964). --define(wxListbook_GetPageImage, 1965). --define(wxListbook_GetPageText, 1966). --define(wxListbook_GetSelection, 1967). --define(wxListbook_HitTest, 1969). --define(wxListbook_InsertPage, 1970). --define(wxListbook_SetImageList, 1971). --define(wxListbook_SetPageSize, 1972). --define(wxListbook_SetPageImage, 1973). --define(wxListbook_SetPageText, 1974). --define(wxListbook_SetSelection, 1975). --define(wxListbook_ChangeSelection, 1976). --define(wxListbook_destroy, 1977). --define(wxTreebook_new_0, 1978). --define(wxTreebook_new_3, 1979). --define(wxTreebook_AddPage, 1980). --define(wxTreebook_AdvanceSelection, 1981). --define(wxTreebook_AssignImageList, 1982). --define(wxTreebook_Create, 1983). --define(wxTreebook_DeleteAllPages, 1984). --define(wxTreebook_DeletePage, 1985). --define(wxTreebook_RemovePage, 1986). --define(wxTreebook_GetCurrentPage, 1987). --define(wxTreebook_GetImageList, 1988). --define(wxTreebook_GetPage, 1990). --define(wxTreebook_GetPageCount, 1991). --define(wxTreebook_GetPageImage, 1992). --define(wxTreebook_GetPageText, 1993). --define(wxTreebook_GetSelection, 1994). --define(wxTreebook_ExpandNode, 1995). --define(wxTreebook_IsNodeExpanded, 1996). --define(wxTreebook_HitTest, 1998). --define(wxTreebook_InsertPage, 1999). --define(wxTreebook_InsertSubPage, 2000). --define(wxTreebook_SetImageList, 2001). --define(wxTreebook_SetPageSize, 2002). --define(wxTreebook_SetPageImage, 2003). --define(wxTreebook_SetPageText, 2004). --define(wxTreebook_SetSelection, 2005). --define(wxTreebook_ChangeSelection, 2006). --define(wxTreebook_destroy, 2007). --define(wxTreeCtrl_new_2, 2010). --define(wxTreeCtrl_new_0, 2011). --define(wxTreeCtrl_destruct, 2013). --define(wxTreeCtrl_AddRoot, 2014). --define(wxTreeCtrl_AppendItem, 2015). --define(wxTreeCtrl_AssignImageList, 2016). --define(wxTreeCtrl_AssignStateImageList, 2017). --define(wxTreeCtrl_Collapse, 2018). --define(wxTreeCtrl_CollapseAndReset, 2019). --define(wxTreeCtrl_Create, 2020). --define(wxTreeCtrl_Delete, 2021). --define(wxTreeCtrl_DeleteAllItems, 2022). --define(wxTreeCtrl_DeleteChildren, 2023). --define(wxTreeCtrl_EditLabel, 2024). --define(wxTreeCtrl_EnsureVisible, 2025). --define(wxTreeCtrl_Expand, 2026). --define(wxTreeCtrl_GetBoundingRect, 2027). --define(wxTreeCtrl_GetChildrenCount, 2029). --define(wxTreeCtrl_GetCount, 2030). --define(wxTreeCtrl_GetEditControl, 2031). --define(wxTreeCtrl_GetFirstChild, 2032). --define(wxTreeCtrl_GetNextChild, 2033). --define(wxTreeCtrl_GetFirstVisibleItem, 2034). --define(wxTreeCtrl_GetImageList, 2035). --define(wxTreeCtrl_GetIndent, 2036). --define(wxTreeCtrl_GetItemBackgroundColour, 2037). --define(wxTreeCtrl_GetItemData, 2038). --define(wxTreeCtrl_GetItemFont, 2039). --define(wxTreeCtrl_GetItemImage_1, 2040). --define(wxTreeCtrl_GetItemImage_2, 2041). --define(wxTreeCtrl_GetItemText, 2042). --define(wxTreeCtrl_GetItemTextColour, 2043). --define(wxTreeCtrl_GetLastChild, 2044). --define(wxTreeCtrl_GetNextSibling, 2045). --define(wxTreeCtrl_GetNextVisible, 2046). --define(wxTreeCtrl_GetItemParent, 2047). --define(wxTreeCtrl_GetPrevSibling, 2048). --define(wxTreeCtrl_GetPrevVisible, 2049). --define(wxTreeCtrl_GetRootItem, 2050). --define(wxTreeCtrl_GetSelection, 2051). --define(wxTreeCtrl_GetSelections, 2052). --define(wxTreeCtrl_GetStateImageList, 2053). --define(wxTreeCtrl_HitTest, 2054). --define(wxTreeCtrl_InsertItem, 2056). --define(wxTreeCtrl_IsBold, 2057). --define(wxTreeCtrl_IsExpanded, 2058). --define(wxTreeCtrl_IsSelected, 2059). --define(wxTreeCtrl_IsVisible, 2060). --define(wxTreeCtrl_ItemHasChildren, 2061). --define(wxTreeCtrl_IsTreeItemIdOk, 2062). --define(wxTreeCtrl_PrependItem, 2063). --define(wxTreeCtrl_ScrollTo, 2064). --define(wxTreeCtrl_SelectItem_1, 2065). --define(wxTreeCtrl_SelectItem_2, 2066). --define(wxTreeCtrl_SetIndent, 2067). --define(wxTreeCtrl_SetImageList, 2068). --define(wxTreeCtrl_SetItemBackgroundColour, 2069). --define(wxTreeCtrl_SetItemBold, 2070). --define(wxTreeCtrl_SetItemData, 2071). --define(wxTreeCtrl_SetItemDropHighlight, 2072). --define(wxTreeCtrl_SetItemFont, 2073). --define(wxTreeCtrl_SetItemHasChildren, 2074). --define(wxTreeCtrl_SetItemImage_2, 2075). --define(wxTreeCtrl_SetItemImage_3, 2076). --define(wxTreeCtrl_SetItemText, 2077). --define(wxTreeCtrl_SetItemTextColour, 2078). --define(wxTreeCtrl_SetStateImageList, 2079). --define(wxTreeCtrl_SetWindowStyle, 2080). --define(wxTreeCtrl_SortChildren, 2081). --define(wxTreeCtrl_Toggle, 2082). --define(wxTreeCtrl_ToggleItemSelection, 2083). --define(wxTreeCtrl_Unselect, 2084). --define(wxTreeCtrl_UnselectAll, 2085). --define(wxTreeCtrl_UnselectItem, 2086). --define(wxScrollBar_new_0, 2087). --define(wxScrollBar_new_3, 2088). --define(wxScrollBar_destruct, 2089). --define(wxScrollBar_Create, 2090). --define(wxScrollBar_GetRange, 2091). --define(wxScrollBar_GetPageSize, 2092). --define(wxScrollBar_GetThumbPosition, 2093). --define(wxScrollBar_GetThumbSize, 2094). --define(wxScrollBar_SetThumbPosition, 2095). --define(wxScrollBar_SetScrollbar, 2096). --define(wxSpinButton_new_2, 2098). --define(wxSpinButton_new_0, 2099). --define(wxSpinButton_Create, 2100). --define(wxSpinButton_GetMax, 2101). --define(wxSpinButton_GetMin, 2102). --define(wxSpinButton_GetValue, 2103). --define(wxSpinButton_SetRange, 2104). --define(wxSpinButton_SetValue, 2105). --define(wxSpinButton_destroy, 2106). --define(wxSpinCtrl_new_0, 2107). --define(wxSpinCtrl_new_2, 2108). --define(wxSpinCtrl_Create, 2110). --define(wxSpinCtrl_SetValue_1_1, 2113). --define(wxSpinCtrl_SetValue_1_0, 2114). --define(wxSpinCtrl_GetValue, 2116). --define(wxSpinCtrl_SetRange, 2118). --define(wxSpinCtrl_SetSelection, 2119). --define(wxSpinCtrl_GetMin, 2121). --define(wxSpinCtrl_GetMax, 2123). --define(wxSpinCtrl_destroy, 2124). --define(wxStaticText_new_0, 2125). --define(wxStaticText_new_4, 2126). --define(wxStaticText_Create, 2127). --define(wxStaticText_GetLabel, 2128). --define(wxStaticText_SetLabel, 2129). --define(wxStaticText_Wrap, 2130). --define(wxStaticText_destroy, 2131). --define(wxStaticBitmap_new_0, 2132). --define(wxStaticBitmap_new_4, 2133). --define(wxStaticBitmap_Create, 2134). --define(wxStaticBitmap_GetBitmap, 2135). --define(wxStaticBitmap_SetBitmap, 2136). --define(wxStaticBitmap_destroy, 2137). --define(wxRadioBox_new, 2138). --define(wxRadioBox_destruct, 2140). --define(wxRadioBox_Create, 2141). --define(wxRadioBox_Enable_2, 2142). --define(wxRadioBox_Enable_1, 2143). --define(wxRadioBox_GetSelection, 2144). --define(wxRadioBox_GetString, 2145). --define(wxRadioBox_SetSelection, 2146). --define(wxRadioBox_Show_2, 2147). --define(wxRadioBox_Show_1, 2148). --define(wxRadioBox_GetColumnCount, 2149). --define(wxRadioBox_GetItemHelpText, 2150). --define(wxRadioBox_GetItemToolTip, 2151). --define(wxRadioBox_GetItemFromPoint, 2153). --define(wxRadioBox_GetRowCount, 2154). --define(wxRadioBox_IsItemEnabled, 2155). --define(wxRadioBox_IsItemShown, 2156). --define(wxRadioBox_SetItemHelpText, 2157). --define(wxRadioBox_SetItemToolTip, 2158). --define(wxRadioButton_new_0, 2159). --define(wxRadioButton_new_4, 2160). --define(wxRadioButton_Create, 2161). --define(wxRadioButton_GetValue, 2162). --define(wxRadioButton_SetValue, 2163). --define(wxRadioButton_destroy, 2164). --define(wxSlider_new_6, 2166). --define(wxSlider_new_0, 2167). --define(wxSlider_Create, 2168). --define(wxSlider_GetLineSize, 2169). --define(wxSlider_GetMax, 2170). --define(wxSlider_GetMin, 2171). --define(wxSlider_GetPageSize, 2172). --define(wxSlider_GetThumbLength, 2173). --define(wxSlider_GetValue, 2174). --define(wxSlider_SetLineSize, 2175). --define(wxSlider_SetPageSize, 2176). --define(wxSlider_SetRange, 2177). --define(wxSlider_SetThumbLength, 2178). --define(wxSlider_SetValue, 2179). --define(wxSlider_destroy, 2180). --define(wxDialog_new_4, 2182). --define(wxDialog_new_0, 2183). --define(wxDialog_destruct, 2185). --define(wxDialog_Create, 2186). --define(wxDialog_CreateButtonSizer, 2187). --define(wxDialog_CreateStdDialogButtonSizer, 2188). --define(wxDialog_EndModal, 2189). --define(wxDialog_GetAffirmativeId, 2190). --define(wxDialog_GetReturnCode, 2191). --define(wxDialog_IsModal, 2192). --define(wxDialog_SetAffirmativeId, 2193). --define(wxDialog_SetReturnCode, 2194). --define(wxDialog_Show, 2195). --define(wxDialog_ShowModal, 2196). --define(wxColourDialog_new_0, 2197). --define(wxColourDialog_new_2, 2198). --define(wxColourDialog_destruct, 2199). --define(wxColourDialog_Create, 2200). --define(wxColourDialog_GetColourData, 2201). --define(wxColourData_new_0, 2202). --define(wxColourData_new_1, 2203). --define(wxColourData_destruct, 2204). --define(wxColourData_GetChooseFull, 2205). --define(wxColourData_GetColour, 2206). --define(wxColourData_GetCustomColour, 2208). --define(wxColourData_SetChooseFull, 2209). --define(wxColourData_SetColour, 2210). --define(wxColourData_SetCustomColour, 2211). --define(wxPalette_new_0, 2212). --define(wxPalette_new_4, 2213). --define(wxPalette_destruct, 2215). --define(wxPalette_Create, 2216). --define(wxPalette_GetColoursCount, 2217). --define(wxPalette_GetPixel, 2218). --define(wxPalette_GetRGB, 2219). --define(wxPalette_IsOk, 2220). --define(wxDirDialog_new, 2224). --define(wxDirDialog_destruct, 2225). --define(wxDirDialog_GetPath, 2226). --define(wxDirDialog_GetMessage, 2227). --define(wxDirDialog_SetMessage, 2228). --define(wxDirDialog_SetPath, 2229). --define(wxFileDialog_new, 2233). --define(wxFileDialog_destruct, 2234). --define(wxFileDialog_GetDirectory, 2235). --define(wxFileDialog_GetFilename, 2236). --define(wxFileDialog_GetFilenames, 2237). --define(wxFileDialog_GetFilterIndex, 2238). --define(wxFileDialog_GetMessage, 2239). --define(wxFileDialog_GetPath, 2240). --define(wxFileDialog_GetPaths, 2241). --define(wxFileDialog_GetWildcard, 2242). --define(wxFileDialog_SetDirectory, 2243). --define(wxFileDialog_SetFilename, 2244). --define(wxFileDialog_SetFilterIndex, 2245). --define(wxFileDialog_SetMessage, 2246). --define(wxFileDialog_SetPath, 2247). --define(wxFileDialog_SetWildcard, 2248). --define(wxPickerBase_SetInternalMargin, 2249). --define(wxPickerBase_GetInternalMargin, 2250). --define(wxPickerBase_SetTextCtrlProportion, 2251). --define(wxPickerBase_SetPickerCtrlProportion, 2252). --define(wxPickerBase_GetTextCtrlProportion, 2253). --define(wxPickerBase_GetPickerCtrlProportion, 2254). --define(wxPickerBase_HasTextCtrl, 2255). --define(wxPickerBase_GetTextCtrl, 2256). --define(wxPickerBase_IsTextCtrlGrowable, 2257). --define(wxPickerBase_SetPickerCtrlGrowable, 2258). --define(wxPickerBase_SetTextCtrlGrowable, 2259). --define(wxPickerBase_IsPickerCtrlGrowable, 2260). --define(wxFilePickerCtrl_new_0, 2261). --define(wxFilePickerCtrl_new_3, 2262). --define(wxFilePickerCtrl_Create, 2263). --define(wxFilePickerCtrl_GetPath, 2264). --define(wxFilePickerCtrl_SetPath, 2265). --define(wxFilePickerCtrl_destroy, 2266). --define(wxDirPickerCtrl_new_0, 2267). --define(wxDirPickerCtrl_new_3, 2268). --define(wxDirPickerCtrl_Create, 2269). --define(wxDirPickerCtrl_GetPath, 2270). --define(wxDirPickerCtrl_SetPath, 2271). --define(wxDirPickerCtrl_destroy, 2272). --define(wxColourPickerCtrl_new_0, 2273). --define(wxColourPickerCtrl_new_3, 2274). --define(wxColourPickerCtrl_Create, 2275). --define(wxColourPickerCtrl_GetColour, 2276). --define(wxColourPickerCtrl_SetColour_1_1, 2277). --define(wxColourPickerCtrl_SetColour_1_0, 2278). --define(wxColourPickerCtrl_destroy, 2279). --define(wxDatePickerCtrl_new_0, 2280). --define(wxDatePickerCtrl_new_3, 2281). --define(wxDatePickerCtrl_GetRange, 2282). --define(wxDatePickerCtrl_GetValue, 2283). --define(wxDatePickerCtrl_SetRange, 2284). --define(wxDatePickerCtrl_SetValue, 2285). --define(wxDatePickerCtrl_destroy, 2286). --define(wxFontPickerCtrl_new_0, 2287). --define(wxFontPickerCtrl_new_3, 2288). --define(wxFontPickerCtrl_Create, 2289). --define(wxFontPickerCtrl_GetSelectedFont, 2290). --define(wxFontPickerCtrl_SetSelectedFont, 2291). --define(wxFontPickerCtrl_GetMaxPointSize, 2292). --define(wxFontPickerCtrl_SetMaxPointSize, 2293). --define(wxFontPickerCtrl_destroy, 2294). --define(wxFindReplaceDialog_new_0, 2297). --define(wxFindReplaceDialog_new_4, 2298). --define(wxFindReplaceDialog_destruct, 2299). --define(wxFindReplaceDialog_Create, 2300). --define(wxFindReplaceDialog_GetData, 2301). --define(wxFindReplaceData_new_0, 2302). --define(wxFindReplaceData_new_1, 2303). --define(wxFindReplaceData_GetFindString, 2304). --define(wxFindReplaceData_GetReplaceString, 2305). --define(wxFindReplaceData_GetFlags, 2306). --define(wxFindReplaceData_SetFlags, 2307). --define(wxFindReplaceData_SetFindString, 2308). --define(wxFindReplaceData_SetReplaceString, 2309). --define(wxFindReplaceData_destroy, 2310). --define(wxMultiChoiceDialog_new_0, 2311). --define(wxMultiChoiceDialog_new_5, 2313). --define(wxMultiChoiceDialog_GetSelections, 2314). --define(wxMultiChoiceDialog_SetSelections, 2315). --define(wxMultiChoiceDialog_destroy, 2316). --define(wxSingleChoiceDialog_new_0, 2317). --define(wxSingleChoiceDialog_new_5, 2319). --define(wxSingleChoiceDialog_GetSelection, 2320). --define(wxSingleChoiceDialog_GetStringSelection, 2321). --define(wxSingleChoiceDialog_SetSelection, 2322). --define(wxSingleChoiceDialog_destroy, 2323). --define(wxTextEntryDialog_new, 2324). --define(wxTextEntryDialog_GetValue, 2325). --define(wxTextEntryDialog_SetValue, 2326). --define(wxTextEntryDialog_destroy, 2327). --define(wxPasswordEntryDialog_new, 2328). --define(wxPasswordEntryDialog_destroy, 2329). --define(wxFontData_new_0, 2330). --define(wxFontData_new_1, 2331). --define(wxFontData_destruct, 2332). --define(wxFontData_EnableEffects, 2333). --define(wxFontData_GetAllowSymbols, 2334). --define(wxFontData_GetColour, 2335). --define(wxFontData_GetChosenFont, 2336). --define(wxFontData_GetEnableEffects, 2337). --define(wxFontData_GetInitialFont, 2338). --define(wxFontData_GetShowHelp, 2339). --define(wxFontData_SetAllowSymbols, 2340). --define(wxFontData_SetChosenFont, 2341). --define(wxFontData_SetColour, 2342). --define(wxFontData_SetInitialFont, 2343). --define(wxFontData_SetRange, 2344). --define(wxFontData_SetShowHelp, 2345). --define(wxFontDialog_new_0, 2349). --define(wxFontDialog_new_2, 2351). --define(wxFontDialog_Create, 2353). --define(wxFontDialog_GetFontData, 2354). --define(wxFontDialog_destroy, 2356). --define(wxProgressDialog_new, 2357). --define(wxProgressDialog_destruct, 2358). --define(wxProgressDialog_Resume, 2359). --define(wxProgressDialog_Update_2, 2360). --define(wxProgressDialog_Update_0, 2361). --define(wxMessageDialog_new, 2362). --define(wxMessageDialog_destruct, 2363). --define(wxPageSetupDialog_new, 2364). --define(wxPageSetupDialog_destruct, 2365). --define(wxPageSetupDialog_GetPageSetupData, 2366). --define(wxPageSetupDialog_ShowModal, 2367). --define(wxPageSetupDialogData_new_0, 2368). --define(wxPageSetupDialogData_new_1_0, 2369). --define(wxPageSetupDialogData_new_1_1, 2370). --define(wxPageSetupDialogData_destruct, 2371). --define(wxPageSetupDialogData_EnableHelp, 2372). --define(wxPageSetupDialogData_EnableMargins, 2373). --define(wxPageSetupDialogData_EnableOrientation, 2374). --define(wxPageSetupDialogData_EnablePaper, 2375). --define(wxPageSetupDialogData_EnablePrinter, 2376). --define(wxPageSetupDialogData_GetDefaultMinMargins, 2377). --define(wxPageSetupDialogData_GetEnableMargins, 2378). --define(wxPageSetupDialogData_GetEnableOrientation, 2379). --define(wxPageSetupDialogData_GetEnablePaper, 2380). --define(wxPageSetupDialogData_GetEnablePrinter, 2381). --define(wxPageSetupDialogData_GetEnableHelp, 2382). --define(wxPageSetupDialogData_GetDefaultInfo, 2383). --define(wxPageSetupDialogData_GetMarginTopLeft, 2384). --define(wxPageSetupDialogData_GetMarginBottomRight, 2385). --define(wxPageSetupDialogData_GetMinMarginTopLeft, 2386). --define(wxPageSetupDialogData_GetMinMarginBottomRight, 2387). --define(wxPageSetupDialogData_GetPaperId, 2388). --define(wxPageSetupDialogData_GetPaperSize, 2389). --define(wxPageSetupDialogData_GetPrintData, 2391). --define(wxPageSetupDialogData_IsOk, 2392). --define(wxPageSetupDialogData_SetDefaultInfo, 2393). --define(wxPageSetupDialogData_SetDefaultMinMargins, 2394). --define(wxPageSetupDialogData_SetMarginTopLeft, 2395). --define(wxPageSetupDialogData_SetMarginBottomRight, 2396). --define(wxPageSetupDialogData_SetMinMarginTopLeft, 2397). --define(wxPageSetupDialogData_SetMinMarginBottomRight, 2398). --define(wxPageSetupDialogData_SetPaperId, 2399). --define(wxPageSetupDialogData_SetPaperSize_1_1, 2400). --define(wxPageSetupDialogData_SetPaperSize_1_0, 2401). --define(wxPageSetupDialogData_SetPrintData, 2402). --define(wxPrintDialog_new_2_0, 2403). --define(wxPrintDialog_new_2_1, 2404). --define(wxPrintDialog_destruct, 2405). --define(wxPrintDialog_GetPrintDialogData, 2406). --define(wxPrintDialog_GetPrintDC, 2407). --define(wxPrintDialogData_new_0, 2408). --define(wxPrintDialogData_new_1_1, 2409). --define(wxPrintDialogData_new_1_0, 2410). --define(wxPrintDialogData_destruct, 2411). --define(wxPrintDialogData_EnableHelp, 2412). --define(wxPrintDialogData_EnablePageNumbers, 2413). --define(wxPrintDialogData_EnablePrintToFile, 2414). --define(wxPrintDialogData_EnableSelection, 2415). --define(wxPrintDialogData_GetAllPages, 2416). --define(wxPrintDialogData_GetCollate, 2417). --define(wxPrintDialogData_GetFromPage, 2418). --define(wxPrintDialogData_GetMaxPage, 2419). --define(wxPrintDialogData_GetMinPage, 2420). --define(wxPrintDialogData_GetNoCopies, 2421). --define(wxPrintDialogData_GetPrintData, 2422). --define(wxPrintDialogData_GetPrintToFile, 2423). --define(wxPrintDialogData_GetSelection, 2424). --define(wxPrintDialogData_GetToPage, 2425). --define(wxPrintDialogData_IsOk, 2426). --define(wxPrintDialogData_SetCollate, 2427). --define(wxPrintDialogData_SetFromPage, 2428). --define(wxPrintDialogData_SetMaxPage, 2429). --define(wxPrintDialogData_SetMinPage, 2430). --define(wxPrintDialogData_SetNoCopies, 2431). --define(wxPrintDialogData_SetPrintData, 2432). --define(wxPrintDialogData_SetPrintToFile, 2433). --define(wxPrintDialogData_SetSelection, 2434). --define(wxPrintDialogData_SetToPage, 2435). --define(wxPrintData_new_0, 2436). --define(wxPrintData_new_1, 2437). --define(wxPrintData_destruct, 2438). --define(wxPrintData_GetCollate, 2439). --define(wxPrintData_GetBin, 2440). --define(wxPrintData_GetColour, 2441). --define(wxPrintData_GetDuplex, 2442). --define(wxPrintData_GetNoCopies, 2443). --define(wxPrintData_GetOrientation, 2444). --define(wxPrintData_GetPaperId, 2445). --define(wxPrintData_GetPrinterName, 2446). --define(wxPrintData_GetQuality, 2447). --define(wxPrintData_IsOk, 2448). --define(wxPrintData_SetBin, 2449). --define(wxPrintData_SetCollate, 2450). --define(wxPrintData_SetColour, 2451). --define(wxPrintData_SetDuplex, 2452). --define(wxPrintData_SetNoCopies, 2453). --define(wxPrintData_SetOrientation, 2454). --define(wxPrintData_SetPaperId, 2455). --define(wxPrintData_SetPrinterName, 2456). --define(wxPrintData_SetQuality, 2457). --define(wxPrintPreview_new_2, 2460). --define(wxPrintPreview_new_3, 2461). --define(wxPrintPreview_destruct, 2463). --define(wxPrintPreview_GetCanvas, 2464). --define(wxPrintPreview_GetCurrentPage, 2465). --define(wxPrintPreview_GetFrame, 2466). --define(wxPrintPreview_GetMaxPage, 2467). --define(wxPrintPreview_GetMinPage, 2468). --define(wxPrintPreview_GetPrintout, 2469). --define(wxPrintPreview_GetPrintoutForPrinting, 2470). --define(wxPrintPreview_IsOk, 2471). --define(wxPrintPreview_PaintPage, 2472). --define(wxPrintPreview_Print, 2473). --define(wxPrintPreview_RenderPage, 2474). --define(wxPrintPreview_SetCanvas, 2475). --define(wxPrintPreview_SetCurrentPage, 2476). --define(wxPrintPreview_SetFrame, 2477). --define(wxPrintPreview_SetPrintout, 2478). --define(wxPrintPreview_SetZoom, 2479). --define(wxPreviewFrame_new, 2480). --define(wxPreviewFrame_destruct, 2481). --define(wxPreviewFrame_CreateControlBar, 2482). --define(wxPreviewFrame_CreateCanvas, 2483). --define(wxPreviewFrame_Initialize, 2484). --define(wxPreviewFrame_OnCloseWindow, 2485). --define(wxPreviewControlBar_new, 2486). --define(wxPreviewControlBar_destruct, 2487). --define(wxPreviewControlBar_CreateButtons, 2488). --define(wxPreviewControlBar_GetPrintPreview, 2489). --define(wxPreviewControlBar_GetZoomControl, 2490). --define(wxPreviewControlBar_SetZoomControl, 2491). --define(wxPrinter_new, 2493). --define(wxPrinter_CreateAbortWindow, 2494). --define(wxPrinter_GetAbort, 2495). --define(wxPrinter_GetLastError, 2496). --define(wxPrinter_GetPrintDialogData, 2497). --define(wxPrinter_Print, 2498). --define(wxPrinter_PrintDialog, 2499). --define(wxPrinter_ReportError, 2500). --define(wxPrinter_Setup, 2501). --define(wxPrinter_destroy, 2502). --define(wxXmlResource_new_1, 2503). --define(wxXmlResource_new_2, 2504). --define(wxXmlResource_destruct, 2505). --define(wxXmlResource_AttachUnknownControl, 2506). --define(wxXmlResource_ClearHandlers, 2507). --define(wxXmlResource_CompareVersion, 2508). --define(wxXmlResource_Get, 2509). --define(wxXmlResource_GetFlags, 2510). --define(wxXmlResource_GetVersion, 2511). --define(wxXmlResource_GetXRCID, 2512). --define(wxXmlResource_InitAllHandlers, 2513). --define(wxXmlResource_Load, 2514). --define(wxXmlResource_LoadBitmap, 2515). --define(wxXmlResource_LoadDialog_2, 2516). --define(wxXmlResource_LoadDialog_3, 2517). --define(wxXmlResource_LoadFrame_2, 2518). --define(wxXmlResource_LoadFrame_3, 2519). --define(wxXmlResource_LoadIcon, 2520). --define(wxXmlResource_LoadMenu, 2521). --define(wxXmlResource_LoadMenuBar_2, 2522). --define(wxXmlResource_LoadMenuBar_1, 2523). --define(wxXmlResource_LoadPanel_2, 2524). --define(wxXmlResource_LoadPanel_3, 2525). --define(wxXmlResource_LoadToolBar, 2526). --define(wxXmlResource_Set, 2527). --define(wxXmlResource_SetFlags, 2528). --define(wxXmlResource_Unload, 2529). --define(wxXmlResource_xrcctrl, 2530). --define(wxHtmlEasyPrinting_new, 2531). --define(wxHtmlEasyPrinting_destruct, 2532). --define(wxHtmlEasyPrinting_GetPrintData, 2533). --define(wxHtmlEasyPrinting_GetPageSetupData, 2534). --define(wxHtmlEasyPrinting_PreviewFile, 2535). --define(wxHtmlEasyPrinting_PreviewText, 2536). --define(wxHtmlEasyPrinting_PrintFile, 2537). --define(wxHtmlEasyPrinting_PrintText, 2538). --define(wxHtmlEasyPrinting_PageSetup, 2539). --define(wxHtmlEasyPrinting_SetFonts, 2540). --define(wxHtmlEasyPrinting_SetHeader, 2541). --define(wxHtmlEasyPrinting_SetFooter, 2542). --define(wxGLCanvas_new_2, 2544). --define(wxGLCanvas_new_3_1, 2545). --define(wxGLCanvas_new_3_0, 2546). --define(wxGLCanvas_GetContext, 2547). --define(wxGLCanvas_SetCurrent, 2549). --define(wxGLCanvas_SwapBuffers, 2550). --define(wxGLCanvas_destroy, 2551). --define(wxAuiManager_new, 2552). --define(wxAuiManager_destruct, 2553). --define(wxAuiManager_AddPane_2_1, 2554). --define(wxAuiManager_AddPane_3, 2555). --define(wxAuiManager_AddPane_2_0, 2556). --define(wxAuiManager_DetachPane, 2557). --define(wxAuiManager_GetAllPanes, 2558). --define(wxAuiManager_GetArtProvider, 2559). --define(wxAuiManager_GetDockSizeConstraint, 2560). --define(wxAuiManager_GetFlags, 2561). --define(wxAuiManager_GetManagedWindow, 2562). --define(wxAuiManager_GetManager, 2563). --define(wxAuiManager_GetPane_1_1, 2564). --define(wxAuiManager_GetPane_1_0, 2565). --define(wxAuiManager_HideHint, 2566). --define(wxAuiManager_InsertPane, 2567). --define(wxAuiManager_LoadPaneInfo, 2568). --define(wxAuiManager_LoadPerspective, 2569). --define(wxAuiManager_SavePaneInfo, 2570). --define(wxAuiManager_SavePerspective, 2571). --define(wxAuiManager_SetArtProvider, 2572). --define(wxAuiManager_SetDockSizeConstraint, 2573). --define(wxAuiManager_SetFlags, 2574). --define(wxAuiManager_SetManagedWindow, 2575). --define(wxAuiManager_ShowHint, 2576). --define(wxAuiManager_UnInit, 2577). --define(wxAuiManager_Update, 2578). --define(wxAuiPaneInfo_new_0, 2579). --define(wxAuiPaneInfo_new_1, 2580). --define(wxAuiPaneInfo_destruct, 2581). --define(wxAuiPaneInfo_BestSize_1, 2582). --define(wxAuiPaneInfo_BestSize_2, 2583). --define(wxAuiPaneInfo_Bottom, 2584). --define(wxAuiPaneInfo_BottomDockable, 2585). --define(wxAuiPaneInfo_Caption, 2586). --define(wxAuiPaneInfo_CaptionVisible, 2587). --define(wxAuiPaneInfo_Centre, 2588). --define(wxAuiPaneInfo_CentrePane, 2589). --define(wxAuiPaneInfo_CloseButton, 2590). --define(wxAuiPaneInfo_DefaultPane, 2591). --define(wxAuiPaneInfo_DestroyOnClose, 2592). --define(wxAuiPaneInfo_Direction, 2593). --define(wxAuiPaneInfo_Dock, 2594). --define(wxAuiPaneInfo_Dockable, 2595). --define(wxAuiPaneInfo_Fixed, 2596). --define(wxAuiPaneInfo_Float, 2597). --define(wxAuiPaneInfo_Floatable, 2598). --define(wxAuiPaneInfo_FloatingPosition_1, 2599). --define(wxAuiPaneInfo_FloatingPosition_2, 2600). --define(wxAuiPaneInfo_FloatingSize_1, 2601). --define(wxAuiPaneInfo_FloatingSize_2, 2602). --define(wxAuiPaneInfo_Gripper, 2603). --define(wxAuiPaneInfo_GripperTop, 2604). --define(wxAuiPaneInfo_HasBorder, 2605). --define(wxAuiPaneInfo_HasCaption, 2606). --define(wxAuiPaneInfo_HasCloseButton, 2607). --define(wxAuiPaneInfo_HasFlag, 2608). --define(wxAuiPaneInfo_HasGripper, 2609). --define(wxAuiPaneInfo_HasGripperTop, 2610). --define(wxAuiPaneInfo_HasMaximizeButton, 2611). --define(wxAuiPaneInfo_HasMinimizeButton, 2612). --define(wxAuiPaneInfo_HasPinButton, 2613). --define(wxAuiPaneInfo_Hide, 2614). --define(wxAuiPaneInfo_IsBottomDockable, 2615). --define(wxAuiPaneInfo_IsDocked, 2616). --define(wxAuiPaneInfo_IsFixed, 2617). --define(wxAuiPaneInfo_IsFloatable, 2618). --define(wxAuiPaneInfo_IsFloating, 2619). --define(wxAuiPaneInfo_IsLeftDockable, 2620). --define(wxAuiPaneInfo_IsMovable, 2621). --define(wxAuiPaneInfo_IsOk, 2622). --define(wxAuiPaneInfo_IsResizable, 2623). --define(wxAuiPaneInfo_IsRightDockable, 2624). --define(wxAuiPaneInfo_IsShown, 2625). --define(wxAuiPaneInfo_IsToolbar, 2626). --define(wxAuiPaneInfo_IsTopDockable, 2627). --define(wxAuiPaneInfo_Layer, 2628). --define(wxAuiPaneInfo_Left, 2629). --define(wxAuiPaneInfo_LeftDockable, 2630). --define(wxAuiPaneInfo_MaxSize_1, 2631). --define(wxAuiPaneInfo_MaxSize_2, 2632). --define(wxAuiPaneInfo_MaximizeButton, 2633). --define(wxAuiPaneInfo_MinSize_1, 2634). --define(wxAuiPaneInfo_MinSize_2, 2635). --define(wxAuiPaneInfo_MinimizeButton, 2636). --define(wxAuiPaneInfo_Movable, 2637). --define(wxAuiPaneInfo_Name, 2638). --define(wxAuiPaneInfo_PaneBorder, 2639). --define(wxAuiPaneInfo_PinButton, 2640). --define(wxAuiPaneInfo_Position, 2641). --define(wxAuiPaneInfo_Resizable, 2642). --define(wxAuiPaneInfo_Right, 2643). --define(wxAuiPaneInfo_RightDockable, 2644). --define(wxAuiPaneInfo_Row, 2645). --define(wxAuiPaneInfo_SafeSet, 2646). --define(wxAuiPaneInfo_SetFlag, 2647). --define(wxAuiPaneInfo_Show, 2648). --define(wxAuiPaneInfo_ToolbarPane, 2649). --define(wxAuiPaneInfo_Top, 2650). --define(wxAuiPaneInfo_TopDockable, 2651). --define(wxAuiPaneInfo_Window, 2652). --define(wxAuiNotebook_new_0, 2653). --define(wxAuiNotebook_new_2, 2654). --define(wxAuiNotebook_AddPage, 2655). --define(wxAuiNotebook_Create, 2656). --define(wxAuiNotebook_DeletePage, 2657). --define(wxAuiNotebook_GetArtProvider, 2658). --define(wxAuiNotebook_GetPage, 2659). --define(wxAuiNotebook_GetPageBitmap, 2660). --define(wxAuiNotebook_GetPageCount, 2661). --define(wxAuiNotebook_GetPageIndex, 2662). --define(wxAuiNotebook_GetPageText, 2663). --define(wxAuiNotebook_GetSelection, 2664). --define(wxAuiNotebook_InsertPage, 2665). --define(wxAuiNotebook_RemovePage, 2666). --define(wxAuiNotebook_SetArtProvider, 2667). --define(wxAuiNotebook_SetFont, 2668). --define(wxAuiNotebook_SetPageBitmap, 2669). --define(wxAuiNotebook_SetPageText, 2670). --define(wxAuiNotebook_SetSelection, 2671). --define(wxAuiNotebook_SetTabCtrlHeight, 2672). --define(wxAuiNotebook_SetUniformBitmapSize, 2673). --define(wxAuiNotebook_destroy, 2674). --define(wxMDIParentFrame_new_0, 2675). --define(wxMDIParentFrame_new_4, 2676). --define(wxMDIParentFrame_destruct, 2677). --define(wxMDIParentFrame_ActivateNext, 2678). --define(wxMDIParentFrame_ActivatePrevious, 2679). --define(wxMDIParentFrame_ArrangeIcons, 2680). --define(wxMDIParentFrame_Cascade, 2681). --define(wxMDIParentFrame_Create, 2682). --define(wxMDIParentFrame_GetActiveChild, 2683). --define(wxMDIParentFrame_GetClientWindow, 2684). --define(wxMDIParentFrame_Tile, 2685). --define(wxMDIChildFrame_new_0, 2686). --define(wxMDIChildFrame_new_4, 2687). --define(wxMDIChildFrame_destruct, 2688). --define(wxMDIChildFrame_Activate, 2689). --define(wxMDIChildFrame_Create, 2690). --define(wxMDIChildFrame_Maximize, 2691). --define(wxMDIChildFrame_Restore, 2692). --define(wxMDIClientWindow_new_0, 2693). --define(wxMDIClientWindow_new_2, 2694). --define(wxMDIClientWindow_destruct, 2695). --define(wxMDIClientWindow_CreateClient, 2696). --define(wxLayoutAlgorithm_new, 2697). --define(wxLayoutAlgorithm_LayoutFrame, 2698). --define(wxLayoutAlgorithm_LayoutMDIFrame, 2699). --define(wxLayoutAlgorithm_LayoutWindow, 2700). --define(wxLayoutAlgorithm_destroy, 2701). --define(wxEvent_GetId, 2702). --define(wxEvent_GetSkipped, 2703). --define(wxEvent_GetTimestamp, 2704). --define(wxEvent_IsCommandEvent, 2705). --define(wxEvent_ResumePropagation, 2706). --define(wxEvent_ShouldPropagate, 2707). --define(wxEvent_Skip, 2708). --define(wxEvent_StopPropagation, 2709). --define(wxCommandEvent_getClientData, 2710). --define(wxCommandEvent_GetExtraLong, 2711). --define(wxCommandEvent_GetInt, 2712). --define(wxCommandEvent_GetSelection, 2713). --define(wxCommandEvent_GetString, 2714). --define(wxCommandEvent_IsChecked, 2715). --define(wxCommandEvent_IsSelection, 2716). --define(wxCommandEvent_SetInt, 2717). --define(wxCommandEvent_SetString, 2718). --define(wxScrollEvent_GetOrientation, 2719). --define(wxScrollEvent_GetPosition, 2720). --define(wxScrollWinEvent_GetOrientation, 2721). --define(wxScrollWinEvent_GetPosition, 2722). --define(wxMouseEvent_AltDown, 2723). --define(wxMouseEvent_Button, 2724). --define(wxMouseEvent_ButtonDClick, 2725). --define(wxMouseEvent_ButtonDown, 2726). --define(wxMouseEvent_ButtonUp, 2727). --define(wxMouseEvent_CmdDown, 2728). --define(wxMouseEvent_ControlDown, 2729). --define(wxMouseEvent_Dragging, 2730). --define(wxMouseEvent_Entering, 2731). --define(wxMouseEvent_GetButton, 2732). --define(wxMouseEvent_GetPosition, 2735). --define(wxMouseEvent_GetLogicalPosition, 2736). --define(wxMouseEvent_GetLinesPerAction, 2737). --define(wxMouseEvent_GetWheelRotation, 2738). --define(wxMouseEvent_GetWheelDelta, 2739). --define(wxMouseEvent_GetX, 2740). --define(wxMouseEvent_GetY, 2741). --define(wxMouseEvent_IsButton, 2742). --define(wxMouseEvent_IsPageScroll, 2743). --define(wxMouseEvent_Leaving, 2744). --define(wxMouseEvent_LeftDClick, 2745). --define(wxMouseEvent_LeftDown, 2746). --define(wxMouseEvent_LeftIsDown, 2747). --define(wxMouseEvent_LeftUp, 2748). --define(wxMouseEvent_MetaDown, 2749). --define(wxMouseEvent_MiddleDClick, 2750). --define(wxMouseEvent_MiddleDown, 2751). --define(wxMouseEvent_MiddleIsDown, 2752). --define(wxMouseEvent_MiddleUp, 2753). --define(wxMouseEvent_Moving, 2754). --define(wxMouseEvent_RightDClick, 2755). --define(wxMouseEvent_RightDown, 2756). --define(wxMouseEvent_RightIsDown, 2757). --define(wxMouseEvent_RightUp, 2758). --define(wxMouseEvent_ShiftDown, 2759). --define(wxSetCursorEvent_GetCursor, 2760). --define(wxSetCursorEvent_GetX, 2761). --define(wxSetCursorEvent_GetY, 2762). --define(wxSetCursorEvent_HasCursor, 2763). --define(wxSetCursorEvent_SetCursor, 2764). --define(wxKeyEvent_AltDown, 2765). --define(wxKeyEvent_CmdDown, 2766). --define(wxKeyEvent_ControlDown, 2767). --define(wxKeyEvent_GetKeyCode, 2768). --define(wxKeyEvent_GetModifiers, 2769). --define(wxKeyEvent_GetPosition, 2772). --define(wxKeyEvent_GetRawKeyCode, 2773). --define(wxKeyEvent_GetRawKeyFlags, 2774). --define(wxKeyEvent_GetUnicodeKey, 2775). --define(wxKeyEvent_GetX, 2776). --define(wxKeyEvent_GetY, 2777). --define(wxKeyEvent_HasModifiers, 2778). --define(wxKeyEvent_MetaDown, 2779). --define(wxKeyEvent_ShiftDown, 2780). --define(wxSizeEvent_GetSize, 2781). --define(wxMoveEvent_GetPosition, 2782). --define(wxEraseEvent_GetDC, 2783). --define(wxFocusEvent_GetWindow, 2784). --define(wxChildFocusEvent_GetWindow, 2785). --define(wxMenuEvent_GetMenu, 2786). --define(wxMenuEvent_GetMenuId, 2787). --define(wxMenuEvent_IsPopup, 2788). --define(wxCloseEvent_CanVeto, 2789). --define(wxCloseEvent_GetLoggingOff, 2790). --define(wxCloseEvent_SetCanVeto, 2791). --define(wxCloseEvent_SetLoggingOff, 2792). --define(wxCloseEvent_Veto, 2793). --define(wxShowEvent_SetShow, 2794). --define(wxShowEvent_GetShow, 2795). --define(wxIconizeEvent_Iconized, 2796). --define(wxJoystickEvent_ButtonDown, 2797). --define(wxJoystickEvent_ButtonIsDown, 2798). --define(wxJoystickEvent_ButtonUp, 2799). --define(wxJoystickEvent_GetButtonChange, 2800). --define(wxJoystickEvent_GetButtonState, 2801). --define(wxJoystickEvent_GetJoystick, 2802). --define(wxJoystickEvent_GetPosition, 2803). --define(wxJoystickEvent_GetZPosition, 2804). --define(wxJoystickEvent_IsButton, 2805). --define(wxJoystickEvent_IsMove, 2806). --define(wxJoystickEvent_IsZMove, 2807). --define(wxUpdateUIEvent_CanUpdate, 2808). --define(wxUpdateUIEvent_Check, 2809). --define(wxUpdateUIEvent_Enable, 2810). --define(wxUpdateUIEvent_Show, 2811). --define(wxUpdateUIEvent_GetChecked, 2812). --define(wxUpdateUIEvent_GetEnabled, 2813). --define(wxUpdateUIEvent_GetShown, 2814). --define(wxUpdateUIEvent_GetSetChecked, 2815). --define(wxUpdateUIEvent_GetSetEnabled, 2816). --define(wxUpdateUIEvent_GetSetShown, 2817). --define(wxUpdateUIEvent_GetSetText, 2818). --define(wxUpdateUIEvent_GetText, 2819). --define(wxUpdateUIEvent_GetMode, 2820). --define(wxUpdateUIEvent_GetUpdateInterval, 2821). --define(wxUpdateUIEvent_ResetUpdateTime, 2822). --define(wxUpdateUIEvent_SetMode, 2823). --define(wxUpdateUIEvent_SetText, 2824). --define(wxUpdateUIEvent_SetUpdateInterval, 2825). --define(wxMouseCaptureChangedEvent_GetCapturedWindow, 2826). --define(wxPaletteChangedEvent_SetChangedWindow, 2827). --define(wxPaletteChangedEvent_GetChangedWindow, 2828). --define(wxQueryNewPaletteEvent_SetPaletteRealized, 2829). --define(wxQueryNewPaletteEvent_GetPaletteRealized, 2830). --define(wxNavigationKeyEvent_GetDirection, 2831). --define(wxNavigationKeyEvent_SetDirection, 2832). --define(wxNavigationKeyEvent_IsWindowChange, 2833). --define(wxNavigationKeyEvent_SetWindowChange, 2834). --define(wxNavigationKeyEvent_IsFromTab, 2835). --define(wxNavigationKeyEvent_SetFromTab, 2836). --define(wxNavigationKeyEvent_GetCurrentFocus, 2837). --define(wxNavigationKeyEvent_SetCurrentFocus, 2838). --define(wxHelpEvent_GetOrigin, 2839). --define(wxHelpEvent_GetPosition, 2840). --define(wxHelpEvent_SetOrigin, 2841). --define(wxHelpEvent_SetPosition, 2842). --define(wxContextMenuEvent_GetPosition, 2843). --define(wxContextMenuEvent_SetPosition, 2844). --define(wxIdleEvent_CanSend, 2845). --define(wxIdleEvent_GetMode, 2846). --define(wxIdleEvent_RequestMore, 2847). --define(wxIdleEvent_MoreRequested, 2848). --define(wxIdleEvent_SetMode, 2849). --define(wxGridEvent_AltDown, 2850). --define(wxGridEvent_ControlDown, 2851). --define(wxGridEvent_GetCol, 2852). --define(wxGridEvent_GetPosition, 2853). --define(wxGridEvent_GetRow, 2854). --define(wxGridEvent_MetaDown, 2855). --define(wxGridEvent_Selecting, 2856). --define(wxGridEvent_ShiftDown, 2857). --define(wxNotifyEvent_Allow, 2858). --define(wxNotifyEvent_IsAllowed, 2859). --define(wxNotifyEvent_Veto, 2860). --define(wxSashEvent_GetEdge, 2861). --define(wxSashEvent_GetDragRect, 2862). --define(wxSashEvent_GetDragStatus, 2863). --define(wxListEvent_GetCacheFrom, 2864). --define(wxListEvent_GetCacheTo, 2865). --define(wxListEvent_GetKeyCode, 2866). --define(wxListEvent_GetIndex, 2867). --define(wxListEvent_GetColumn, 2868). --define(wxListEvent_GetPoint, 2869). --define(wxListEvent_GetLabel, 2870). --define(wxListEvent_GetText, 2871). --define(wxListEvent_GetImage, 2872). --define(wxListEvent_GetData, 2873). --define(wxListEvent_GetMask, 2874). --define(wxListEvent_GetItem, 2875). --define(wxListEvent_IsEditCancelled, 2876). --define(wxDateEvent_GetDate, 2877). --define(wxCalendarEvent_GetWeekDay, 2878). --define(wxFileDirPickerEvent_GetPath, 2879). --define(wxColourPickerEvent_GetColour, 2880). --define(wxFontPickerEvent_GetFont, 2881). --define(wxStyledTextEvent_GetPosition, 2882). --define(wxStyledTextEvent_GetKey, 2883). --define(wxStyledTextEvent_GetModifiers, 2884). --define(wxStyledTextEvent_GetModificationType, 2885). --define(wxStyledTextEvent_GetText, 2886). --define(wxStyledTextEvent_GetLength, 2887). --define(wxStyledTextEvent_GetLinesAdded, 2888). --define(wxStyledTextEvent_GetLine, 2889). --define(wxStyledTextEvent_GetFoldLevelNow, 2890). --define(wxStyledTextEvent_GetFoldLevelPrev, 2891). --define(wxStyledTextEvent_GetMargin, 2892). --define(wxStyledTextEvent_GetMessage, 2893). --define(wxStyledTextEvent_GetWParam, 2894). --define(wxStyledTextEvent_GetLParam, 2895). --define(wxStyledTextEvent_GetListType, 2896). --define(wxStyledTextEvent_GetX, 2897). --define(wxStyledTextEvent_GetY, 2898). --define(wxStyledTextEvent_GetDragText, 2899). --define(wxStyledTextEvent_GetDragAllowMove, 2900). --define(wxStyledTextEvent_GetDragResult, 2901). --define(wxStyledTextEvent_GetShift, 2902). --define(wxStyledTextEvent_GetControl, 2903). --define(wxStyledTextEvent_GetAlt, 2904). --define(utils_wxGetKeyState, 2905). --define(utils_wxGetMousePosition, 2906). --define(utils_wxGetMouseState, 2907). --define(utils_wxSetDetectableAutoRepeat, 2908). --define(utils_wxBell, 2909). --define(utils_wxFindMenuItemId, 2910). --define(utils_wxGenericFindWindowAtPoint, 2911). --define(utils_wxFindWindowAtPoint, 2912). --define(utils_wxBeginBusyCursor, 2913). --define(utils_wxEndBusyCursor, 2914). --define(utils_wxIsBusy, 2915). --define(utils_wxShutdown, 2916). --define(utils_wxShell, 2917). --define(utils_wxLaunchDefaultBrowser, 2918). --define(utils_wxGetEmailAddress, 2919). --define(utils_wxGetUserId, 2920). --define(utils_wxGetHomeDir, 2921). --define(utils_wxNewId, 2922). --define(utils_wxRegisterId, 2923). --define(utils_wxGetCurrentId, 2924). --define(utils_wxGetOsDescription, 2925). --define(utils_wxIsPlatformLittleEndian, 2926). --define(utils_wxIsPlatform64Bit, 2927). --define(gdicmn_wxDisplaySize, 2928). --define(gdicmn_wxSetCursor, 2929). --define(wxPrintout_new, 2930). --define(wxPrintout_destruct, 2931). --define(wxPrintout_GetDC, 2932). --define(wxPrintout_GetPageSizeMM, 2933). --define(wxPrintout_GetPageSizePixels, 2934). --define(wxPrintout_GetPaperRectPixels, 2935). --define(wxPrintout_GetPPIPrinter, 2936). --define(wxPrintout_GetPPIScreen, 2937). --define(wxPrintout_GetTitle, 2938). --define(wxPrintout_IsPreview, 2939). --define(wxPrintout_FitThisSizeToPaper, 2940). --define(wxPrintout_FitThisSizeToPage, 2941). --define(wxPrintout_FitThisSizeToPageMargins, 2942). --define(wxPrintout_MapScreenSizeToPaper, 2943). --define(wxPrintout_MapScreenSizeToPage, 2944). --define(wxPrintout_MapScreenSizeToPageMargins, 2945). --define(wxPrintout_MapScreenSizeToDevice, 2946). --define(wxPrintout_GetLogicalPaperRect, 2947). --define(wxPrintout_GetLogicalPageRect, 2948). --define(wxPrintout_GetLogicalPageMarginsRect, 2949). --define(wxPrintout_SetLogicalOrigin, 2950). --define(wxPrintout_OffsetLogicalOrigin, 2951). --define(wxStyledTextCtrl_new_2, 2952). --define(wxStyledTextCtrl_new_0, 2953). --define(wxStyledTextCtrl_destruct, 2954). --define(wxStyledTextCtrl_Create, 2955). --define(wxStyledTextCtrl_AddText, 2956). --define(wxStyledTextCtrl_AddStyledText, 2957). --define(wxStyledTextCtrl_InsertText, 2958). --define(wxStyledTextCtrl_ClearAll, 2959). --define(wxStyledTextCtrl_ClearDocumentStyle, 2960). --define(wxStyledTextCtrl_GetLength, 2961). --define(wxStyledTextCtrl_GetCharAt, 2962). --define(wxStyledTextCtrl_GetCurrentPos, 2963). --define(wxStyledTextCtrl_GetAnchor, 2964). --define(wxStyledTextCtrl_GetStyleAt, 2965). --define(wxStyledTextCtrl_Redo, 2966). --define(wxStyledTextCtrl_SetUndoCollection, 2967). --define(wxStyledTextCtrl_SelectAll, 2968). --define(wxStyledTextCtrl_SetSavePoint, 2969). --define(wxStyledTextCtrl_GetStyledText, 2970). --define(wxStyledTextCtrl_CanRedo, 2971). --define(wxStyledTextCtrl_MarkerLineFromHandle, 2972). --define(wxStyledTextCtrl_MarkerDeleteHandle, 2973). --define(wxStyledTextCtrl_GetUndoCollection, 2974). --define(wxStyledTextCtrl_GetViewWhiteSpace, 2975). --define(wxStyledTextCtrl_SetViewWhiteSpace, 2976). --define(wxStyledTextCtrl_PositionFromPoint, 2977). --define(wxStyledTextCtrl_PositionFromPointClose, 2978). --define(wxStyledTextCtrl_GotoLine, 2979). --define(wxStyledTextCtrl_GotoPos, 2980). --define(wxStyledTextCtrl_SetAnchor, 2981). --define(wxStyledTextCtrl_GetCurLine, 2982). --define(wxStyledTextCtrl_GetEndStyled, 2983). --define(wxStyledTextCtrl_ConvertEOLs, 2984). --define(wxStyledTextCtrl_GetEOLMode, 2985). --define(wxStyledTextCtrl_SetEOLMode, 2986). --define(wxStyledTextCtrl_StartStyling, 2987). --define(wxStyledTextCtrl_SetStyling, 2988). --define(wxStyledTextCtrl_GetBufferedDraw, 2989). --define(wxStyledTextCtrl_SetBufferedDraw, 2990). --define(wxStyledTextCtrl_SetTabWidth, 2991). --define(wxStyledTextCtrl_GetTabWidth, 2992). --define(wxStyledTextCtrl_SetCodePage, 2993). --define(wxStyledTextCtrl_MarkerDefine, 2994). --define(wxStyledTextCtrl_MarkerSetForeground, 2995). --define(wxStyledTextCtrl_MarkerSetBackground, 2996). --define(wxStyledTextCtrl_MarkerAdd, 2997). --define(wxStyledTextCtrl_MarkerDelete, 2998). --define(wxStyledTextCtrl_MarkerDeleteAll, 2999). --define(wxStyledTextCtrl_MarkerGet, 3000). --define(wxStyledTextCtrl_MarkerNext, 3001). --define(wxStyledTextCtrl_MarkerPrevious, 3002). --define(wxStyledTextCtrl_MarkerDefineBitmap, 3003). --define(wxStyledTextCtrl_MarkerAddSet, 3004). --define(wxStyledTextCtrl_MarkerSetAlpha, 3005). --define(wxStyledTextCtrl_SetMarginType, 3006). --define(wxStyledTextCtrl_GetMarginType, 3007). --define(wxStyledTextCtrl_SetMarginWidth, 3008). --define(wxStyledTextCtrl_GetMarginWidth, 3009). --define(wxStyledTextCtrl_SetMarginMask, 3010). --define(wxStyledTextCtrl_GetMarginMask, 3011). --define(wxStyledTextCtrl_SetMarginSensitive, 3012). --define(wxStyledTextCtrl_GetMarginSensitive, 3013). --define(wxStyledTextCtrl_StyleClearAll, 3014). --define(wxStyledTextCtrl_StyleSetForeground, 3015). --define(wxStyledTextCtrl_StyleSetBackground, 3016). --define(wxStyledTextCtrl_StyleSetBold, 3017). --define(wxStyledTextCtrl_StyleSetItalic, 3018). --define(wxStyledTextCtrl_StyleSetSize, 3019). --define(wxStyledTextCtrl_StyleSetFaceName, 3020). --define(wxStyledTextCtrl_StyleSetEOLFilled, 3021). --define(wxStyledTextCtrl_StyleResetDefault, 3022). --define(wxStyledTextCtrl_StyleSetUnderline, 3023). --define(wxStyledTextCtrl_StyleSetCase, 3024). --define(wxStyledTextCtrl_StyleSetHotSpot, 3025). --define(wxStyledTextCtrl_SetSelForeground, 3026). --define(wxStyledTextCtrl_SetSelBackground, 3027). --define(wxStyledTextCtrl_GetSelAlpha, 3028). --define(wxStyledTextCtrl_SetSelAlpha, 3029). --define(wxStyledTextCtrl_SetCaretForeground, 3030). --define(wxStyledTextCtrl_CmdKeyAssign, 3031). --define(wxStyledTextCtrl_CmdKeyClear, 3032). --define(wxStyledTextCtrl_CmdKeyClearAll, 3033). --define(wxStyledTextCtrl_SetStyleBytes, 3034). --define(wxStyledTextCtrl_StyleSetVisible, 3035). --define(wxStyledTextCtrl_GetCaretPeriod, 3036). --define(wxStyledTextCtrl_SetCaretPeriod, 3037). --define(wxStyledTextCtrl_SetWordChars, 3038). --define(wxStyledTextCtrl_BeginUndoAction, 3039). --define(wxStyledTextCtrl_EndUndoAction, 3040). --define(wxStyledTextCtrl_IndicatorSetStyle, 3041). --define(wxStyledTextCtrl_IndicatorGetStyle, 3042). --define(wxStyledTextCtrl_IndicatorSetForeground, 3043). --define(wxStyledTextCtrl_IndicatorGetForeground, 3044). --define(wxStyledTextCtrl_SetWhitespaceForeground, 3045). --define(wxStyledTextCtrl_SetWhitespaceBackground, 3046). --define(wxStyledTextCtrl_GetStyleBits, 3047). --define(wxStyledTextCtrl_SetLineState, 3048). --define(wxStyledTextCtrl_GetLineState, 3049). --define(wxStyledTextCtrl_GetMaxLineState, 3050). --define(wxStyledTextCtrl_GetCaretLineVisible, 3051). --define(wxStyledTextCtrl_SetCaretLineVisible, 3052). --define(wxStyledTextCtrl_GetCaretLineBackground, 3053). --define(wxStyledTextCtrl_SetCaretLineBackground, 3054). --define(wxStyledTextCtrl_AutoCompShow, 3055). --define(wxStyledTextCtrl_AutoCompCancel, 3056). --define(wxStyledTextCtrl_AutoCompActive, 3057). --define(wxStyledTextCtrl_AutoCompPosStart, 3058). --define(wxStyledTextCtrl_AutoCompComplete, 3059). --define(wxStyledTextCtrl_AutoCompStops, 3060). --define(wxStyledTextCtrl_AutoCompSetSeparator, 3061). --define(wxStyledTextCtrl_AutoCompGetSeparator, 3062). --define(wxStyledTextCtrl_AutoCompSelect, 3063). --define(wxStyledTextCtrl_AutoCompSetCancelAtStart, 3064). --define(wxStyledTextCtrl_AutoCompGetCancelAtStart, 3065). --define(wxStyledTextCtrl_AutoCompSetFillUps, 3066). --define(wxStyledTextCtrl_AutoCompSetChooseSingle, 3067). --define(wxStyledTextCtrl_AutoCompGetChooseSingle, 3068). --define(wxStyledTextCtrl_AutoCompSetIgnoreCase, 3069). --define(wxStyledTextCtrl_AutoCompGetIgnoreCase, 3070). --define(wxStyledTextCtrl_UserListShow, 3071). --define(wxStyledTextCtrl_AutoCompSetAutoHide, 3072). --define(wxStyledTextCtrl_AutoCompGetAutoHide, 3073). --define(wxStyledTextCtrl_AutoCompSetDropRestOfWord, 3074). --define(wxStyledTextCtrl_AutoCompGetDropRestOfWord, 3075). --define(wxStyledTextCtrl_RegisterImage, 3076). --define(wxStyledTextCtrl_ClearRegisteredImages, 3077). --define(wxStyledTextCtrl_AutoCompGetTypeSeparator, 3078). --define(wxStyledTextCtrl_AutoCompSetTypeSeparator, 3079). --define(wxStyledTextCtrl_AutoCompSetMaxWidth, 3080). --define(wxStyledTextCtrl_AutoCompGetMaxWidth, 3081). --define(wxStyledTextCtrl_AutoCompSetMaxHeight, 3082). --define(wxStyledTextCtrl_AutoCompGetMaxHeight, 3083). --define(wxStyledTextCtrl_SetIndent, 3084). --define(wxStyledTextCtrl_GetIndent, 3085). --define(wxStyledTextCtrl_SetUseTabs, 3086). --define(wxStyledTextCtrl_GetUseTabs, 3087). --define(wxStyledTextCtrl_SetLineIndentation, 3088). --define(wxStyledTextCtrl_GetLineIndentation, 3089). --define(wxStyledTextCtrl_GetLineIndentPosition, 3090). --define(wxStyledTextCtrl_GetColumn, 3091). --define(wxStyledTextCtrl_SetUseHorizontalScrollBar, 3092). --define(wxStyledTextCtrl_GetUseHorizontalScrollBar, 3093). --define(wxStyledTextCtrl_SetIndentationGuides, 3094). --define(wxStyledTextCtrl_GetIndentationGuides, 3095). --define(wxStyledTextCtrl_SetHighlightGuide, 3096). --define(wxStyledTextCtrl_GetHighlightGuide, 3097). --define(wxStyledTextCtrl_GetLineEndPosition, 3098). --define(wxStyledTextCtrl_GetCodePage, 3099). --define(wxStyledTextCtrl_GetCaretForeground, 3100). --define(wxStyledTextCtrl_GetReadOnly, 3101). --define(wxStyledTextCtrl_SetCurrentPos, 3102). --define(wxStyledTextCtrl_SetSelectionStart, 3103). --define(wxStyledTextCtrl_GetSelectionStart, 3104). --define(wxStyledTextCtrl_SetSelectionEnd, 3105). --define(wxStyledTextCtrl_GetSelectionEnd, 3106). --define(wxStyledTextCtrl_SetPrintMagnification, 3107). --define(wxStyledTextCtrl_GetPrintMagnification, 3108). --define(wxStyledTextCtrl_SetPrintColourMode, 3109). --define(wxStyledTextCtrl_GetPrintColourMode, 3110). --define(wxStyledTextCtrl_FindText, 3111). --define(wxStyledTextCtrl_FormatRange, 3112). --define(wxStyledTextCtrl_GetFirstVisibleLine, 3113). --define(wxStyledTextCtrl_GetLine, 3114). --define(wxStyledTextCtrl_GetLineCount, 3115). --define(wxStyledTextCtrl_SetMarginLeft, 3116). --define(wxStyledTextCtrl_GetMarginLeft, 3117). --define(wxStyledTextCtrl_SetMarginRight, 3118). --define(wxStyledTextCtrl_GetMarginRight, 3119). --define(wxStyledTextCtrl_GetModify, 3120). --define(wxStyledTextCtrl_SetSelection, 3121). --define(wxStyledTextCtrl_GetSelectedText, 3122). --define(wxStyledTextCtrl_GetTextRange, 3123). --define(wxStyledTextCtrl_HideSelection, 3124). --define(wxStyledTextCtrl_LineFromPosition, 3125). --define(wxStyledTextCtrl_PositionFromLine, 3126). --define(wxStyledTextCtrl_LineScroll, 3127). --define(wxStyledTextCtrl_EnsureCaretVisible, 3128). --define(wxStyledTextCtrl_ReplaceSelection, 3129). --define(wxStyledTextCtrl_SetReadOnly, 3130). --define(wxStyledTextCtrl_CanPaste, 3131). --define(wxStyledTextCtrl_CanUndo, 3132). --define(wxStyledTextCtrl_EmptyUndoBuffer, 3133). --define(wxStyledTextCtrl_Undo, 3134). --define(wxStyledTextCtrl_Cut, 3135). --define(wxStyledTextCtrl_Copy, 3136). --define(wxStyledTextCtrl_Paste, 3137). --define(wxStyledTextCtrl_Clear, 3138). --define(wxStyledTextCtrl_SetText, 3139). --define(wxStyledTextCtrl_GetText, 3140). --define(wxStyledTextCtrl_GetTextLength, 3141). --define(wxStyledTextCtrl_GetOvertype, 3142). --define(wxStyledTextCtrl_SetCaretWidth, 3143). --define(wxStyledTextCtrl_GetCaretWidth, 3144). --define(wxStyledTextCtrl_SetTargetStart, 3145). --define(wxStyledTextCtrl_GetTargetStart, 3146). --define(wxStyledTextCtrl_SetTargetEnd, 3147). --define(wxStyledTextCtrl_GetTargetEnd, 3148). --define(wxStyledTextCtrl_ReplaceTarget, 3149). --define(wxStyledTextCtrl_SearchInTarget, 3150). --define(wxStyledTextCtrl_SetSearchFlags, 3151). --define(wxStyledTextCtrl_GetSearchFlags, 3152). --define(wxStyledTextCtrl_CallTipShow, 3153). --define(wxStyledTextCtrl_CallTipCancel, 3154). --define(wxStyledTextCtrl_CallTipActive, 3155). --define(wxStyledTextCtrl_CallTipPosAtStart, 3156). --define(wxStyledTextCtrl_CallTipSetHighlight, 3157). --define(wxStyledTextCtrl_CallTipSetBackground, 3158). --define(wxStyledTextCtrl_CallTipSetForeground, 3159). --define(wxStyledTextCtrl_CallTipSetForegroundHighlight, 3160). --define(wxStyledTextCtrl_CallTipUseStyle, 3161). --define(wxStyledTextCtrl_VisibleFromDocLine, 3162). --define(wxStyledTextCtrl_DocLineFromVisible, 3163). --define(wxStyledTextCtrl_WrapCount, 3164). --define(wxStyledTextCtrl_SetFoldLevel, 3165). --define(wxStyledTextCtrl_GetFoldLevel, 3166). --define(wxStyledTextCtrl_GetLastChild, 3167). --define(wxStyledTextCtrl_GetFoldParent, 3168). --define(wxStyledTextCtrl_ShowLines, 3169). --define(wxStyledTextCtrl_HideLines, 3170). --define(wxStyledTextCtrl_GetLineVisible, 3171). --define(wxStyledTextCtrl_SetFoldExpanded, 3172). --define(wxStyledTextCtrl_GetFoldExpanded, 3173). --define(wxStyledTextCtrl_ToggleFold, 3174). --define(wxStyledTextCtrl_EnsureVisible, 3175). --define(wxStyledTextCtrl_SetFoldFlags, 3176). --define(wxStyledTextCtrl_EnsureVisibleEnforcePolicy, 3177). --define(wxStyledTextCtrl_SetTabIndents, 3178). --define(wxStyledTextCtrl_GetTabIndents, 3179). --define(wxStyledTextCtrl_SetBackSpaceUnIndents, 3180). --define(wxStyledTextCtrl_GetBackSpaceUnIndents, 3181). --define(wxStyledTextCtrl_SetMouseDwellTime, 3182). --define(wxStyledTextCtrl_GetMouseDwellTime, 3183). --define(wxStyledTextCtrl_WordStartPosition, 3184). --define(wxStyledTextCtrl_WordEndPosition, 3185). --define(wxStyledTextCtrl_SetWrapMode, 3186). --define(wxStyledTextCtrl_GetWrapMode, 3187). --define(wxStyledTextCtrl_SetWrapVisualFlags, 3188). --define(wxStyledTextCtrl_GetWrapVisualFlags, 3189). --define(wxStyledTextCtrl_SetWrapVisualFlagsLocation, 3190). --define(wxStyledTextCtrl_GetWrapVisualFlagsLocation, 3191). --define(wxStyledTextCtrl_SetWrapStartIndent, 3192). --define(wxStyledTextCtrl_GetWrapStartIndent, 3193). --define(wxStyledTextCtrl_SetLayoutCache, 3194). --define(wxStyledTextCtrl_GetLayoutCache, 3195). --define(wxStyledTextCtrl_SetScrollWidth, 3196). --define(wxStyledTextCtrl_GetScrollWidth, 3197). --define(wxStyledTextCtrl_TextWidth, 3198). --define(wxStyledTextCtrl_GetEndAtLastLine, 3199). --define(wxStyledTextCtrl_TextHeight, 3200). --define(wxStyledTextCtrl_SetUseVerticalScrollBar, 3201). --define(wxStyledTextCtrl_GetUseVerticalScrollBar, 3202). --define(wxStyledTextCtrl_AppendText, 3203). --define(wxStyledTextCtrl_GetTwoPhaseDraw, 3204). --define(wxStyledTextCtrl_SetTwoPhaseDraw, 3205). --define(wxStyledTextCtrl_TargetFromSelection, 3206). --define(wxStyledTextCtrl_LinesJoin, 3207). --define(wxStyledTextCtrl_LinesSplit, 3208). --define(wxStyledTextCtrl_SetFoldMarginColour, 3209). --define(wxStyledTextCtrl_SetFoldMarginHiColour, 3210). --define(wxStyledTextCtrl_LineDown, 3211). --define(wxStyledTextCtrl_LineDownExtend, 3212). --define(wxStyledTextCtrl_LineUp, 3213). --define(wxStyledTextCtrl_LineUpExtend, 3214). --define(wxStyledTextCtrl_CharLeft, 3215). --define(wxStyledTextCtrl_CharLeftExtend, 3216). --define(wxStyledTextCtrl_CharRight, 3217). --define(wxStyledTextCtrl_CharRightExtend, 3218). --define(wxStyledTextCtrl_WordLeft, 3219). --define(wxStyledTextCtrl_WordLeftExtend, 3220). --define(wxStyledTextCtrl_WordRight, 3221). --define(wxStyledTextCtrl_WordRightExtend, 3222). --define(wxStyledTextCtrl_Home, 3223). --define(wxStyledTextCtrl_HomeExtend, 3224). --define(wxStyledTextCtrl_LineEnd, 3225). --define(wxStyledTextCtrl_LineEndExtend, 3226). --define(wxStyledTextCtrl_DocumentStart, 3227). --define(wxStyledTextCtrl_DocumentStartExtend, 3228). --define(wxStyledTextCtrl_DocumentEnd, 3229). --define(wxStyledTextCtrl_DocumentEndExtend, 3230). --define(wxStyledTextCtrl_PageUp, 3231). --define(wxStyledTextCtrl_PageUpExtend, 3232). --define(wxStyledTextCtrl_PageDown, 3233). --define(wxStyledTextCtrl_PageDownExtend, 3234). --define(wxStyledTextCtrl_EditToggleOvertype, 3235). --define(wxStyledTextCtrl_Cancel, 3236). --define(wxStyledTextCtrl_DeleteBack, 3237). --define(wxStyledTextCtrl_Tab, 3238). --define(wxStyledTextCtrl_BackTab, 3239). --define(wxStyledTextCtrl_NewLine, 3240). --define(wxStyledTextCtrl_FormFeed, 3241). --define(wxStyledTextCtrl_VCHome, 3242). --define(wxStyledTextCtrl_VCHomeExtend, 3243). --define(wxStyledTextCtrl_ZoomIn, 3244). --define(wxStyledTextCtrl_ZoomOut, 3245). --define(wxStyledTextCtrl_DelWordLeft, 3246). --define(wxStyledTextCtrl_DelWordRight, 3247). --define(wxStyledTextCtrl_LineCut, 3248). --define(wxStyledTextCtrl_LineDelete, 3249). --define(wxStyledTextCtrl_LineTranspose, 3250). --define(wxStyledTextCtrl_LineDuplicate, 3251). --define(wxStyledTextCtrl_LowerCase, 3252). --define(wxStyledTextCtrl_UpperCase, 3253). --define(wxStyledTextCtrl_LineScrollDown, 3254). --define(wxStyledTextCtrl_LineScrollUp, 3255). --define(wxStyledTextCtrl_DeleteBackNotLine, 3256). --define(wxStyledTextCtrl_HomeDisplay, 3257). --define(wxStyledTextCtrl_HomeDisplayExtend, 3258). --define(wxStyledTextCtrl_LineEndDisplay, 3259). --define(wxStyledTextCtrl_LineEndDisplayExtend, 3260). --define(wxStyledTextCtrl_HomeWrapExtend, 3261). --define(wxStyledTextCtrl_LineEndWrap, 3262). --define(wxStyledTextCtrl_LineEndWrapExtend, 3263). --define(wxStyledTextCtrl_VCHomeWrap, 3264). --define(wxStyledTextCtrl_VCHomeWrapExtend, 3265). --define(wxStyledTextCtrl_LineCopy, 3266). --define(wxStyledTextCtrl_MoveCaretInsideView, 3267). --define(wxStyledTextCtrl_LineLength, 3268). --define(wxStyledTextCtrl_BraceHighlight, 3269). --define(wxStyledTextCtrl_BraceBadLight, 3270). --define(wxStyledTextCtrl_BraceMatch, 3271). --define(wxStyledTextCtrl_GetViewEOL, 3272). --define(wxStyledTextCtrl_SetViewEOL, 3273). --define(wxStyledTextCtrl_SetModEventMask, 3274). --define(wxStyledTextCtrl_GetEdgeColumn, 3275). --define(wxStyledTextCtrl_SetEdgeColumn, 3276). --define(wxStyledTextCtrl_SetEdgeMode, 3277). --define(wxStyledTextCtrl_GetEdgeMode, 3278). --define(wxStyledTextCtrl_GetEdgeColour, 3279). --define(wxStyledTextCtrl_SetEdgeColour, 3280). --define(wxStyledTextCtrl_SearchAnchor, 3281). --define(wxStyledTextCtrl_SearchNext, 3282). --define(wxStyledTextCtrl_SearchPrev, 3283). --define(wxStyledTextCtrl_LinesOnScreen, 3284). --define(wxStyledTextCtrl_UsePopUp, 3285). --define(wxStyledTextCtrl_SelectionIsRectangle, 3286). --define(wxStyledTextCtrl_SetZoom, 3287). --define(wxStyledTextCtrl_GetZoom, 3288). --define(wxStyledTextCtrl_GetModEventMask, 3289). --define(wxStyledTextCtrl_SetSTCFocus, 3290). --define(wxStyledTextCtrl_GetSTCFocus, 3291). --define(wxStyledTextCtrl_SetStatus, 3292). --define(wxStyledTextCtrl_GetStatus, 3293). --define(wxStyledTextCtrl_SetMouseDownCaptures, 3294). --define(wxStyledTextCtrl_GetMouseDownCaptures, 3295). --define(wxStyledTextCtrl_SetSTCCursor, 3296). --define(wxStyledTextCtrl_GetSTCCursor, 3297). --define(wxStyledTextCtrl_SetControlCharSymbol, 3298). --define(wxStyledTextCtrl_GetControlCharSymbol, 3299). --define(wxStyledTextCtrl_WordPartLeft, 3300). --define(wxStyledTextCtrl_WordPartLeftExtend, 3301). --define(wxStyledTextCtrl_WordPartRight, 3302). --define(wxStyledTextCtrl_WordPartRightExtend, 3303). --define(wxStyledTextCtrl_SetVisiblePolicy, 3304). --define(wxStyledTextCtrl_DelLineLeft, 3305). --define(wxStyledTextCtrl_DelLineRight, 3306). --define(wxStyledTextCtrl_GetXOffset, 3307). --define(wxStyledTextCtrl_ChooseCaretX, 3308). --define(wxStyledTextCtrl_SetXCaretPolicy, 3309). --define(wxStyledTextCtrl_SetYCaretPolicy, 3310). --define(wxStyledTextCtrl_GetPrintWrapMode, 3311). --define(wxStyledTextCtrl_SetHotspotActiveForeground, 3312). --define(wxStyledTextCtrl_SetHotspotActiveBackground, 3313). --define(wxStyledTextCtrl_SetHotspotActiveUnderline, 3314). --define(wxStyledTextCtrl_SetHotspotSingleLine, 3315). --define(wxStyledTextCtrl_ParaDownExtend, 3316). --define(wxStyledTextCtrl_ParaUp, 3317). --define(wxStyledTextCtrl_ParaUpExtend, 3318). --define(wxStyledTextCtrl_PositionBefore, 3319). --define(wxStyledTextCtrl_PositionAfter, 3320). --define(wxStyledTextCtrl_CopyRange, 3321). --define(wxStyledTextCtrl_CopyText, 3322). --define(wxStyledTextCtrl_SetSelectionMode, 3323). --define(wxStyledTextCtrl_GetSelectionMode, 3324). --define(wxStyledTextCtrl_LineDownRectExtend, 3325). --define(wxStyledTextCtrl_LineUpRectExtend, 3326). --define(wxStyledTextCtrl_CharLeftRectExtend, 3327). --define(wxStyledTextCtrl_CharRightRectExtend, 3328). --define(wxStyledTextCtrl_HomeRectExtend, 3329). --define(wxStyledTextCtrl_VCHomeRectExtend, 3330). --define(wxStyledTextCtrl_LineEndRectExtend, 3331). --define(wxStyledTextCtrl_PageUpRectExtend, 3332). --define(wxStyledTextCtrl_PageDownRectExtend, 3333). --define(wxStyledTextCtrl_StutteredPageUp, 3334). --define(wxStyledTextCtrl_StutteredPageUpExtend, 3335). --define(wxStyledTextCtrl_StutteredPageDown, 3336). --define(wxStyledTextCtrl_StutteredPageDownExtend, 3337). --define(wxStyledTextCtrl_WordLeftEnd, 3338). --define(wxStyledTextCtrl_WordLeftEndExtend, 3339). --define(wxStyledTextCtrl_WordRightEnd, 3340). --define(wxStyledTextCtrl_WordRightEndExtend, 3341). --define(wxStyledTextCtrl_SetWhitespaceChars, 3342). --define(wxStyledTextCtrl_SetCharsDefault, 3343). --define(wxStyledTextCtrl_AutoCompGetCurrent, 3344). --define(wxStyledTextCtrl_Allocate, 3345). --define(wxStyledTextCtrl_FindColumn, 3346). --define(wxStyledTextCtrl_GetCaretSticky, 3347). --define(wxStyledTextCtrl_SetCaretSticky, 3348). --define(wxStyledTextCtrl_ToggleCaretSticky, 3349). --define(wxStyledTextCtrl_SetPasteConvertEndings, 3350). --define(wxStyledTextCtrl_GetPasteConvertEndings, 3351). --define(wxStyledTextCtrl_SelectionDuplicate, 3352). --define(wxStyledTextCtrl_SetCaretLineBackAlpha, 3353). --define(wxStyledTextCtrl_GetCaretLineBackAlpha, 3354). --define(wxStyledTextCtrl_StartRecord, 3355). --define(wxStyledTextCtrl_StopRecord, 3356). --define(wxStyledTextCtrl_SetLexer, 3357). --define(wxStyledTextCtrl_GetLexer, 3358). --define(wxStyledTextCtrl_Colourise, 3359). --define(wxStyledTextCtrl_SetProperty, 3360). --define(wxStyledTextCtrl_SetKeyWords, 3361). --define(wxStyledTextCtrl_SetLexerLanguage, 3362). --define(wxStyledTextCtrl_GetProperty, 3363). --define(wxStyledTextCtrl_GetStyleBitsNeeded, 3364). --define(wxStyledTextCtrl_GetCurrentLine, 3365). --define(wxStyledTextCtrl_StyleSetSpec, 3366). --define(wxStyledTextCtrl_StyleSetFont, 3367). --define(wxStyledTextCtrl_StyleSetFontAttr, 3368). --define(wxStyledTextCtrl_StyleSetCharacterSet, 3369). --define(wxStyledTextCtrl_StyleSetFontEncoding, 3370). --define(wxStyledTextCtrl_CmdKeyExecute, 3371). --define(wxStyledTextCtrl_SetMargins, 3372). --define(wxStyledTextCtrl_GetSelection, 3373). --define(wxStyledTextCtrl_PointFromPosition, 3374). --define(wxStyledTextCtrl_ScrollToLine, 3375). --define(wxStyledTextCtrl_ScrollToColumn, 3376). --define(wxStyledTextCtrl_SetVScrollBar, 3377). --define(wxStyledTextCtrl_SetHScrollBar, 3378). --define(wxStyledTextCtrl_GetLastKeydownProcessed, 3379). --define(wxStyledTextCtrl_SetLastKeydownProcessed, 3380). --define(wxStyledTextCtrl_SaveFile, 3381). --define(wxStyledTextCtrl_LoadFile, 3382). --define(wxStyledTextCtrl_DoDragOver, 3383). --define(wxStyledTextCtrl_DoDropText, 3384). --define(wxStyledTextCtrl_GetUseAntiAliasing, 3385). --define(wxStyledTextCtrl_AddTextRaw, 3386). --define(wxStyledTextCtrl_InsertTextRaw, 3387). --define(wxStyledTextCtrl_GetCurLineRaw, 3388). --define(wxStyledTextCtrl_GetLineRaw, 3389). --define(wxStyledTextCtrl_GetSelectedTextRaw, 3390). --define(wxStyledTextCtrl_GetTextRangeRaw, 3391). --define(wxStyledTextCtrl_SetTextRaw, 3392). --define(wxStyledTextCtrl_GetTextRaw, 3393). --define(wxStyledTextCtrl_AppendTextRaw, 3394). --define(wxArtProvider_GetBitmap, 3395). --define(wxArtProvider_GetIcon, 3396). --define(wxTreeEvent_GetKeyCode, 3397). --define(wxTreeEvent_GetItem, 3398). --define(wxTreeEvent_GetKeyEvent, 3399). --define(wxTreeEvent_GetLabel, 3400). --define(wxTreeEvent_GetOldItem, 3401). --define(wxTreeEvent_GetPoint, 3402). --define(wxTreeEvent_IsEditCancelled, 3403). --define(wxTreeEvent_SetToolTip, 3404). --define(wxNotebookEvent_GetOldSelection, 3405). --define(wxNotebookEvent_GetSelection, 3406). --define(wxNotebookEvent_SetOldSelection, 3407). --define(wxNotebookEvent_SetSelection, 3408). --define(wxFileDataObject_new, 3409). --define(wxFileDataObject_AddFile, 3410). --define(wxFileDataObject_GetFilenames, 3411). --define(wxFileDataObject_destroy, 3412). --define(wxTextDataObject_new, 3413). --define(wxTextDataObject_GetTextLength, 3414). --define(wxTextDataObject_GetText, 3415). --define(wxTextDataObject_SetText, 3416). --define(wxTextDataObject_destroy, 3417). --define(wxBitmapDataObject_new_1_1, 3418). --define(wxBitmapDataObject_new_1_0, 3419). --define(wxBitmapDataObject_GetBitmap, 3420). --define(wxBitmapDataObject_SetBitmap, 3421). --define(wxBitmapDataObject_destroy, 3422). --define(wxClipboard_new, 3424). --define(wxClipboard_destruct, 3425). --define(wxClipboard_AddData, 3426). --define(wxClipboard_Clear, 3427). --define(wxClipboard_Close, 3428). --define(wxClipboard_Flush, 3429). --define(wxClipboard_GetData, 3430). --define(wxClipboard_IsOpened, 3431). --define(wxClipboard_Open, 3432). --define(wxClipboard_SetData, 3433). --define(wxClipboard_UsePrimarySelection, 3435). --define(wxClipboard_IsSupported, 3436). --define(wxClipboard_Get, 3437). --define(wxSpinEvent_GetPosition, 3438). --define(wxSpinEvent_SetPosition, 3439). --define(wxSplitterWindow_new_0, 3440). --define(wxSplitterWindow_new_2, 3441). --define(wxSplitterWindow_destruct, 3442). --define(wxSplitterWindow_Create, 3443). --define(wxSplitterWindow_GetMinimumPaneSize, 3444). --define(wxSplitterWindow_GetSashGravity, 3445). --define(wxSplitterWindow_GetSashPosition, 3446). --define(wxSplitterWindow_GetSplitMode, 3447). --define(wxSplitterWindow_GetWindow1, 3448). --define(wxSplitterWindow_GetWindow2, 3449). --define(wxSplitterWindow_Initialize, 3450). --define(wxSplitterWindow_IsSplit, 3451). --define(wxSplitterWindow_ReplaceWindow, 3452). --define(wxSplitterWindow_SetSashGravity, 3453). --define(wxSplitterWindow_SetSashPosition, 3454). --define(wxSplitterWindow_SetSashSize, 3455). --define(wxSplitterWindow_SetMinimumPaneSize, 3456). --define(wxSplitterWindow_SetSplitMode, 3457). --define(wxSplitterWindow_SplitHorizontally, 3458). --define(wxSplitterWindow_SplitVertically, 3459). --define(wxSplitterWindow_Unsplit, 3460). --define(wxSplitterWindow_UpdateSize, 3461). --define(wxSplitterEvent_GetSashPosition, 3462). --define(wxSplitterEvent_GetX, 3463). --define(wxSplitterEvent_GetY, 3464). --define(wxSplitterEvent_GetWindowBeingRemoved, 3465). --define(wxSplitterEvent_SetSashPosition, 3466). --define(wxHtmlWindow_new_0, 3467). --define(wxHtmlWindow_new_2, 3468). --define(wxHtmlWindow_AppendToPage, 3469). --define(wxHtmlWindow_GetOpenedAnchor, 3470). --define(wxHtmlWindow_GetOpenedPage, 3471). --define(wxHtmlWindow_GetOpenedPageTitle, 3472). --define(wxHtmlWindow_GetRelatedFrame, 3473). --define(wxHtmlWindow_HistoryBack, 3474). --define(wxHtmlWindow_HistoryCanBack, 3475). --define(wxHtmlWindow_HistoryCanForward, 3476). --define(wxHtmlWindow_HistoryClear, 3477). --define(wxHtmlWindow_HistoryForward, 3478). --define(wxHtmlWindow_LoadFile, 3479). --define(wxHtmlWindow_LoadPage, 3480). --define(wxHtmlWindow_SelectAll, 3481). --define(wxHtmlWindow_SelectionToText, 3482). --define(wxHtmlWindow_SelectLine, 3483). --define(wxHtmlWindow_SelectWord, 3484). --define(wxHtmlWindow_SetBorders, 3485). --define(wxHtmlWindow_SetFonts, 3486). --define(wxHtmlWindow_SetPage, 3487). --define(wxHtmlWindow_SetRelatedFrame, 3488). --define(wxHtmlWindow_SetRelatedStatusBar, 3489). --define(wxHtmlWindow_ToText, 3490). --define(wxHtmlWindow_destroy, 3491). --define(wxHtmlLinkEvent_GetLinkInfo, 3492). --define(wxSystemSettings_GetColour, 3493). --define(wxSystemSettings_GetFont, 3494). --define(wxSystemSettings_GetMetric, 3495). --define(wxSystemSettings_GetScreenType, 3496). --define(wxSystemOptions_GetOption, 3497). --define(wxSystemOptions_GetOptionInt, 3498). --define(wxSystemOptions_HasOption, 3499). --define(wxSystemOptions_IsFalse, 3500). --define(wxSystemOptions_SetOption_2_1, 3501). --define(wxSystemOptions_SetOption_2_0, 3502). --define(wxAuiNotebookEvent_SetSelection, 3503). --define(wxAuiNotebookEvent_GetSelection, 3504). --define(wxAuiNotebookEvent_SetOldSelection, 3505). --define(wxAuiNotebookEvent_GetOldSelection, 3506). --define(wxAuiNotebookEvent_SetDragSource, 3507). --define(wxAuiNotebookEvent_GetDragSource, 3508). --define(wxAuiManagerEvent_SetManager, 3509). --define(wxAuiManagerEvent_GetManager, 3510). --define(wxAuiManagerEvent_SetPane, 3511). --define(wxAuiManagerEvent_GetPane, 3512). --define(wxAuiManagerEvent_SetButton, 3513). --define(wxAuiManagerEvent_GetButton, 3514). --define(wxAuiManagerEvent_SetDC, 3515). --define(wxAuiManagerEvent_GetDC, 3516). --define(wxAuiManagerEvent_Veto, 3517). --define(wxAuiManagerEvent_GetVeto, 3518). --define(wxAuiManagerEvent_SetCanVeto, 3519). --define(wxAuiManagerEvent_CanVeto, 3520). --define(wxLogNull_new, 3521). --define(wxLogNull_destroy, 3522). --define(wxTaskBarIcon_new, 3523). --define(wxTaskBarIcon_destruct, 3524). --define(wxTaskBarIcon_PopupMenu, 3525). --define(wxTaskBarIcon_RemoveIcon, 3526). --define(wxTaskBarIcon_SetIcon, 3527). --define(wxLocale_new_0, 3528). --define(wxLocale_new_2, 3530). --define(wxLocale_destruct, 3531). --define(wxLocale_Init, 3533). --define(wxLocale_AddCatalog_1, 3534). --define(wxLocale_AddCatalog_3, 3535). --define(wxLocale_AddCatalogLookupPathPrefix, 3536). --define(wxLocale_GetCanonicalName, 3537). --define(wxLocale_GetLanguage, 3538). --define(wxLocale_GetLanguageName, 3539). --define(wxLocale_GetLocale, 3540). --define(wxLocale_GetName, 3541). --define(wxLocale_GetString_2, 3542). --define(wxLocale_GetString_4, 3543). --define(wxLocale_GetHeaderValue, 3544). --define(wxLocale_GetSysName, 3545). --define(wxLocale_GetSystemEncoding, 3546). --define(wxLocale_GetSystemEncodingName, 3547). --define(wxLocale_GetSystemLanguage, 3548). --define(wxLocale_IsLoaded, 3549). --define(wxLocale_IsOk, 3550). --define(wxActivateEvent_GetActive, 3551). --define(wxPopupWindow_new_2, 3553). --define(wxPopupWindow_new_0, 3554). --define(wxPopupWindow_destruct, 3556). --define(wxPopupWindow_Create, 3557). --define(wxPopupWindow_Position, 3558). --define(wxPopupTransientWindow_new_0, 3559). --define(wxPopupTransientWindow_new_2, 3560). --define(wxPopupTransientWindow_destruct, 3561). --define(wxPopupTransientWindow_Popup, 3562). --define(wxPopupTransientWindow_Dismiss, 3563). +-define(wxWindow_SetTransparent, 284). +-define(wxWindow_CanSetTransparent, 285). +-define(wxWindow_IsDoubleBuffered, 286). +-define(wxWindow_SetDoubleBuffered, 287). +-define(wxTopLevelWindow_GetIcon, 288). +-define(wxTopLevelWindow_GetIcons, 289). +-define(wxTopLevelWindow_GetTitle, 290). +-define(wxTopLevelWindow_IsActive, 291). +-define(wxTopLevelWindow_Iconize, 292). +-define(wxTopLevelWindow_IsFullScreen, 293). +-define(wxTopLevelWindow_IsIconized, 294). +-define(wxTopLevelWindow_IsMaximized, 295). +-define(wxTopLevelWindow_Maximize, 296). +-define(wxTopLevelWindow_RequestUserAttention, 297). +-define(wxTopLevelWindow_SetIcon, 298). +-define(wxTopLevelWindow_SetIcons, 299). +-define(wxTopLevelWindow_CenterOnScreen, 300). +-define(wxTopLevelWindow_CentreOnScreen, 301). +-define(wxTopLevelWindow_SetShape, 303). +-define(wxTopLevelWindow_SetTitle, 304). +-define(wxTopLevelWindow_ShowFullScreen, 305). +-define(wxFrame_new_4, 307). +-define(wxFrame_new_0, 308). +-define(wxFrame_destruct, 310). +-define(wxFrame_Create, 311). +-define(wxFrame_CreateStatusBar, 312). +-define(wxFrame_CreateToolBar, 313). +-define(wxFrame_GetClientAreaOrigin, 314). +-define(wxFrame_GetMenuBar, 315). +-define(wxFrame_GetStatusBar, 316). +-define(wxFrame_GetStatusBarPane, 317). +-define(wxFrame_GetToolBar, 318). +-define(wxFrame_ProcessCommand, 319). +-define(wxFrame_SendSizeEvent, 320). +-define(wxFrame_SetMenuBar, 321). +-define(wxFrame_SetStatusBar, 322). +-define(wxFrame_SetStatusBarPane, 323). +-define(wxFrame_SetStatusText, 324). +-define(wxFrame_SetStatusWidths, 325). +-define(wxFrame_SetToolBar, 326). +-define(wxMiniFrame_new_0, 327). +-define(wxMiniFrame_new_4, 328). +-define(wxMiniFrame_Create, 329). +-define(wxMiniFrame_destroy, 330). +-define(wxSplashScreen_new_0, 331). +-define(wxSplashScreen_new_6, 332). +-define(wxSplashScreen_destruct, 333). +-define(wxSplashScreen_GetSplashStyle, 334). +-define(wxSplashScreen_GetTimeout, 335). +-define(wxPanel_new_0, 336). +-define(wxPanel_new_6, 337). +-define(wxPanel_new_2, 338). +-define(wxPanel_destruct, 339). +-define(wxPanel_InitDialog, 340). +-define(wxPanel_SetFocusIgnoringChildren, 341). +-define(wxScrolledWindow_new_0, 342). +-define(wxScrolledWindow_new_2, 343). +-define(wxScrolledWindow_destruct, 344). +-define(wxScrolledWindow_CalcScrolledPosition_4, 345). +-define(wxScrolledWindow_CalcScrolledPosition_1, 346). +-define(wxScrolledWindow_CalcUnscrolledPosition_4, 347). +-define(wxScrolledWindow_CalcUnscrolledPosition_1, 348). +-define(wxScrolledWindow_EnableScrolling, 349). +-define(wxScrolledWindow_GetScrollPixelsPerUnit, 350). +-define(wxScrolledWindow_GetViewStart, 351). +-define(wxScrolledWindow_DoPrepareDC, 352). +-define(wxScrolledWindow_PrepareDC, 353). +-define(wxScrolledWindow_Scroll, 354). +-define(wxScrolledWindow_SetScrollbars, 355). +-define(wxScrolledWindow_SetScrollRate, 356). +-define(wxScrolledWindow_SetTargetWindow, 357). +-define(wxSashWindow_new_0, 358). +-define(wxSashWindow_new_2, 359). +-define(wxSashWindow_destruct, 360). +-define(wxSashWindow_GetSashVisible, 361). +-define(wxSashWindow_GetMaximumSizeX, 362). +-define(wxSashWindow_GetMaximumSizeY, 363). +-define(wxSashWindow_GetMinimumSizeX, 364). +-define(wxSashWindow_GetMinimumSizeY, 365). +-define(wxSashWindow_SetMaximumSizeX, 366). +-define(wxSashWindow_SetMaximumSizeY, 367). +-define(wxSashWindow_SetMinimumSizeX, 368). +-define(wxSashWindow_SetMinimumSizeY, 369). +-define(wxSashWindow_SetSashVisible, 370). +-define(wxSashLayoutWindow_new_0, 371). +-define(wxSashLayoutWindow_new_2, 372). +-define(wxSashLayoutWindow_Create, 373). +-define(wxSashLayoutWindow_GetAlignment, 374). +-define(wxSashLayoutWindow_GetOrientation, 375). +-define(wxSashLayoutWindow_SetAlignment, 376). +-define(wxSashLayoutWindow_SetDefaultSize, 377). +-define(wxSashLayoutWindow_SetOrientation, 378). +-define(wxSashLayoutWindow_destroy, 379). +-define(wxGrid_new_0, 380). +-define(wxGrid_new_3, 381). +-define(wxGrid_new_4, 382). +-define(wxGrid_destruct, 383). +-define(wxGrid_AppendCols, 384). +-define(wxGrid_AppendRows, 385). +-define(wxGrid_AutoSize, 386). +-define(wxGrid_AutoSizeColumn, 387). +-define(wxGrid_AutoSizeColumns, 388). +-define(wxGrid_AutoSizeRow, 389). +-define(wxGrid_AutoSizeRows, 390). +-define(wxGrid_BeginBatch, 391). +-define(wxGrid_BlockToDeviceRect, 392). +-define(wxGrid_CanDragColSize, 393). +-define(wxGrid_CanDragRowSize, 394). +-define(wxGrid_CanDragGridSize, 395). +-define(wxGrid_CanEnableCellControl, 396). +-define(wxGrid_CellToRect_2, 397). +-define(wxGrid_CellToRect_1, 398). +-define(wxGrid_ClearGrid, 399). +-define(wxGrid_ClearSelection, 400). +-define(wxGrid_CreateGrid, 401). +-define(wxGrid_DeleteCols, 402). +-define(wxGrid_DeleteRows, 403). +-define(wxGrid_DisableCellEditControl, 404). +-define(wxGrid_DisableDragColSize, 405). +-define(wxGrid_DisableDragGridSize, 406). +-define(wxGrid_DisableDragRowSize, 407). +-define(wxGrid_EnableCellEditControl, 408). +-define(wxGrid_EnableDragColSize, 409). +-define(wxGrid_EnableDragGridSize, 410). +-define(wxGrid_EnableDragRowSize, 411). +-define(wxGrid_EnableEditing, 412). +-define(wxGrid_EnableGridLines, 413). +-define(wxGrid_EndBatch, 414). +-define(wxGrid_Fit, 415). +-define(wxGrid_ForceRefresh, 416). +-define(wxGrid_GetBatchCount, 417). +-define(wxGrid_GetCellAlignment, 418). +-define(wxGrid_GetCellBackgroundColour, 419). +-define(wxGrid_GetCellEditor, 420). +-define(wxGrid_GetCellFont, 421). +-define(wxGrid_GetCellRenderer, 422). +-define(wxGrid_GetCellTextColour, 423). +-define(wxGrid_GetCellValue_2, 424). +-define(wxGrid_GetCellValue_1, 425). +-define(wxGrid_GetColLabelAlignment, 426). +-define(wxGrid_GetColLabelSize, 427). +-define(wxGrid_GetColLabelValue, 428). +-define(wxGrid_GetColMinimalAcceptableWidth, 429). +-define(wxGrid_GetDefaultCellAlignment, 430). +-define(wxGrid_GetDefaultCellBackgroundColour, 431). +-define(wxGrid_GetDefaultCellFont, 432). +-define(wxGrid_GetDefaultCellTextColour, 433). +-define(wxGrid_GetDefaultColLabelSize, 434). +-define(wxGrid_GetDefaultColSize, 435). +-define(wxGrid_GetDefaultEditor, 436). +-define(wxGrid_GetDefaultEditorForCell_2, 437). +-define(wxGrid_GetDefaultEditorForCell_1, 438). +-define(wxGrid_GetDefaultEditorForType, 439). +-define(wxGrid_GetDefaultRenderer, 440). +-define(wxGrid_GetDefaultRendererForCell, 441). +-define(wxGrid_GetDefaultRendererForType, 442). +-define(wxGrid_GetDefaultRowLabelSize, 443). +-define(wxGrid_GetDefaultRowSize, 444). +-define(wxGrid_GetGridCursorCol, 445). +-define(wxGrid_GetGridCursorRow, 446). +-define(wxGrid_GetGridLineColour, 447). +-define(wxGrid_GridLinesEnabled, 448). +-define(wxGrid_GetLabelBackgroundColour, 449). +-define(wxGrid_GetLabelFont, 450). +-define(wxGrid_GetLabelTextColour, 451). +-define(wxGrid_GetNumberCols, 452). +-define(wxGrid_GetNumberRows, 453). +-define(wxGrid_GetOrCreateCellAttr, 454). +-define(wxGrid_GetRowMinimalAcceptableHeight, 455). +-define(wxGrid_GetRowLabelAlignment, 456). +-define(wxGrid_GetRowLabelSize, 457). +-define(wxGrid_GetRowLabelValue, 458). +-define(wxGrid_GetRowSize, 459). +-define(wxGrid_GetScrollLineX, 460). +-define(wxGrid_GetScrollLineY, 461). +-define(wxGrid_GetSelectedCells, 462). +-define(wxGrid_GetSelectedCols, 463). +-define(wxGrid_GetSelectedRows, 464). +-define(wxGrid_GetSelectionBackground, 465). +-define(wxGrid_GetSelectionBlockTopLeft, 466). +-define(wxGrid_GetSelectionBlockBottomRight, 467). +-define(wxGrid_GetSelectionForeground, 468). +-define(wxGrid_GetViewWidth, 469). +-define(wxGrid_GetGridWindow, 470). +-define(wxGrid_GetGridRowLabelWindow, 471). +-define(wxGrid_GetGridColLabelWindow, 472). +-define(wxGrid_GetGridCornerLabelWindow, 473). +-define(wxGrid_HideCellEditControl, 474). +-define(wxGrid_InsertCols, 475). +-define(wxGrid_InsertRows, 476). +-define(wxGrid_IsCellEditControlEnabled, 477). +-define(wxGrid_IsCurrentCellReadOnly, 478). +-define(wxGrid_IsEditable, 479). +-define(wxGrid_IsInSelection_2, 480). +-define(wxGrid_IsInSelection_1, 481). +-define(wxGrid_IsReadOnly, 482). +-define(wxGrid_IsSelection, 483). +-define(wxGrid_IsVisible_3, 484). +-define(wxGrid_IsVisible_2, 485). +-define(wxGrid_MakeCellVisible_2, 486). +-define(wxGrid_MakeCellVisible_1, 487). +-define(wxGrid_MoveCursorDown, 488). +-define(wxGrid_MoveCursorLeft, 489). +-define(wxGrid_MoveCursorRight, 490). +-define(wxGrid_MoveCursorUp, 491). +-define(wxGrid_MoveCursorDownBlock, 492). +-define(wxGrid_MoveCursorLeftBlock, 493). +-define(wxGrid_MoveCursorRightBlock, 494). +-define(wxGrid_MoveCursorUpBlock, 495). +-define(wxGrid_MovePageDown, 496). +-define(wxGrid_MovePageUp, 497). +-define(wxGrid_RegisterDataType, 498). +-define(wxGrid_SaveEditControlValue, 499). +-define(wxGrid_SelectAll, 500). +-define(wxGrid_SelectBlock_5, 501). +-define(wxGrid_SelectBlock_3, 502). +-define(wxGrid_SelectCol, 503). +-define(wxGrid_SelectRow, 504). +-define(wxGrid_SetCellAlignment_4, 505). +-define(wxGrid_SetCellAlignment_3, 506). +-define(wxGrid_SetCellAlignment_1, 507). +-define(wxGrid_SetCellBackgroundColour_3_0, 508). +-define(wxGrid_SetCellBackgroundColour_1, 509). +-define(wxGrid_SetCellBackgroundColour_3_1, 510). +-define(wxGrid_SetCellEditor, 511). +-define(wxGrid_SetCellFont, 512). +-define(wxGrid_SetCellRenderer, 513). +-define(wxGrid_SetCellTextColour_3_0, 514). +-define(wxGrid_SetCellTextColour_3_1, 515). +-define(wxGrid_SetCellTextColour_1, 516). +-define(wxGrid_SetCellValue_3_0, 517). +-define(wxGrid_SetCellValue_2, 518). +-define(wxGrid_SetCellValue_3_1, 519). +-define(wxGrid_SetColAttr, 520). +-define(wxGrid_SetColFormatBool, 521). +-define(wxGrid_SetColFormatNumber, 522). +-define(wxGrid_SetColFormatFloat, 523). +-define(wxGrid_SetColFormatCustom, 524). +-define(wxGrid_SetColLabelAlignment, 525). +-define(wxGrid_SetColLabelSize, 526). +-define(wxGrid_SetColLabelValue, 527). +-define(wxGrid_SetColMinimalWidth, 528). +-define(wxGrid_SetColMinimalAcceptableWidth, 529). +-define(wxGrid_SetColSize, 530). +-define(wxGrid_SetDefaultCellAlignment, 531). +-define(wxGrid_SetDefaultCellBackgroundColour, 532). +-define(wxGrid_SetDefaultCellFont, 533). +-define(wxGrid_SetDefaultCellTextColour, 534). +-define(wxGrid_SetDefaultEditor, 535). +-define(wxGrid_SetDefaultRenderer, 536). +-define(wxGrid_SetDefaultColSize, 537). +-define(wxGrid_SetDefaultRowSize, 538). +-define(wxGrid_SetGridCursor, 539). +-define(wxGrid_SetGridLineColour, 540). +-define(wxGrid_SetLabelBackgroundColour, 541). +-define(wxGrid_SetLabelFont, 542). +-define(wxGrid_SetLabelTextColour, 543). +-define(wxGrid_SetMargins, 544). +-define(wxGrid_SetReadOnly, 545). +-define(wxGrid_SetRowAttr, 546). +-define(wxGrid_SetRowLabelAlignment, 547). +-define(wxGrid_SetRowLabelSize, 548). +-define(wxGrid_SetRowLabelValue, 549). +-define(wxGrid_SetRowMinimalHeight, 550). +-define(wxGrid_SetRowMinimalAcceptableHeight, 551). +-define(wxGrid_SetRowSize, 552). +-define(wxGrid_SetScrollLineX, 553). +-define(wxGrid_SetScrollLineY, 554). +-define(wxGrid_SetSelectionBackground, 555). +-define(wxGrid_SetSelectionForeground, 556). +-define(wxGrid_SetSelectionMode, 557). +-define(wxGrid_ShowCellEditControl, 558). +-define(wxGrid_XToCol, 559). +-define(wxGrid_XToEdgeOfCol, 560). +-define(wxGrid_YToEdgeOfRow, 561). +-define(wxGrid_YToRow, 562). +-define(wxGridCellRenderer_Draw, 563). +-define(wxGridCellRenderer_GetBestSize, 564). +-define(wxGridCellEditor_Create, 565). +-define(wxGridCellEditor_IsCreated, 566). +-define(wxGridCellEditor_SetSize, 567). +-define(wxGridCellEditor_Show, 568). +-define(wxGridCellEditor_PaintBackground, 569). +-define(wxGridCellEditor_BeginEdit, 570). +-define(wxGridCellEditor_EndEdit, 571). +-define(wxGridCellEditor_Reset, 572). +-define(wxGridCellEditor_StartingKey, 573). +-define(wxGridCellEditor_StartingClick, 574). +-define(wxGridCellEditor_HandleReturn, 575). +-define(wxGridCellBoolRenderer_new, 576). +-define(wxGridCellBoolRenderer_destroy, 577). +-define(wxGridCellBoolEditor_new, 578). +-define(wxGridCellBoolEditor_IsTrueValue, 579). +-define(wxGridCellBoolEditor_UseStringValues, 580). +-define(wxGridCellBoolEditor_destroy, 581). +-define(wxGridCellFloatRenderer_new, 582). +-define(wxGridCellFloatRenderer_GetPrecision, 583). +-define(wxGridCellFloatRenderer_GetWidth, 584). +-define(wxGridCellFloatRenderer_SetParameters, 585). +-define(wxGridCellFloatRenderer_SetPrecision, 586). +-define(wxGridCellFloatRenderer_SetWidth, 587). +-define(wxGridCellFloatRenderer_destroy, 588). +-define(wxGridCellFloatEditor_new, 589). +-define(wxGridCellFloatEditor_SetParameters, 590). +-define(wxGridCellFloatEditor_destroy, 591). +-define(wxGridCellStringRenderer_new, 592). +-define(wxGridCellStringRenderer_destroy, 593). +-define(wxGridCellTextEditor_new, 594). +-define(wxGridCellTextEditor_SetParameters, 595). +-define(wxGridCellTextEditor_destroy, 596). +-define(wxGridCellChoiceEditor_new, 598). +-define(wxGridCellChoiceEditor_SetParameters, 599). +-define(wxGridCellChoiceEditor_destroy, 600). +-define(wxGridCellNumberRenderer_new, 601). +-define(wxGridCellNumberRenderer_destroy, 602). +-define(wxGridCellNumberEditor_new, 603). +-define(wxGridCellNumberEditor_GetValue, 604). +-define(wxGridCellNumberEditor_SetParameters, 605). +-define(wxGridCellNumberEditor_destroy, 606). +-define(wxGridCellAttr_SetTextColour, 607). +-define(wxGridCellAttr_SetBackgroundColour, 608). +-define(wxGridCellAttr_SetFont, 609). +-define(wxGridCellAttr_SetAlignment, 610). +-define(wxGridCellAttr_SetReadOnly, 611). +-define(wxGridCellAttr_SetRenderer, 612). +-define(wxGridCellAttr_SetEditor, 613). +-define(wxGridCellAttr_HasTextColour, 614). +-define(wxGridCellAttr_HasBackgroundColour, 615). +-define(wxGridCellAttr_HasFont, 616). +-define(wxGridCellAttr_HasAlignment, 617). +-define(wxGridCellAttr_HasRenderer, 618). +-define(wxGridCellAttr_HasEditor, 619). +-define(wxGridCellAttr_GetTextColour, 620). +-define(wxGridCellAttr_GetBackgroundColour, 621). +-define(wxGridCellAttr_GetFont, 622). +-define(wxGridCellAttr_GetAlignment, 623). +-define(wxGridCellAttr_GetRenderer, 624). +-define(wxGridCellAttr_GetEditor, 625). +-define(wxGridCellAttr_IsReadOnly, 626). +-define(wxGridCellAttr_SetDefAttr, 627). +-define(wxDC_Blit, 628). +-define(wxDC_CalcBoundingBox, 629). +-define(wxDC_Clear, 630). +-define(wxDC_ComputeScaleAndOrigin, 631). +-define(wxDC_CrossHair, 632). +-define(wxDC_DestroyClippingRegion, 633). +-define(wxDC_DeviceToLogicalX, 634). +-define(wxDC_DeviceToLogicalXRel, 635). +-define(wxDC_DeviceToLogicalY, 636). +-define(wxDC_DeviceToLogicalYRel, 637). +-define(wxDC_DrawArc, 638). +-define(wxDC_DrawBitmap, 639). +-define(wxDC_DrawCheckMark, 640). +-define(wxDC_DrawCircle, 641). +-define(wxDC_DrawEllipse_2, 643). +-define(wxDC_DrawEllipse_1, 644). +-define(wxDC_DrawEllipticArc, 645). +-define(wxDC_DrawIcon, 646). +-define(wxDC_DrawLabel, 647). +-define(wxDC_DrawLine, 648). +-define(wxDC_DrawLines, 649). +-define(wxDC_DrawPolygon, 651). +-define(wxDC_DrawPoint, 653). +-define(wxDC_DrawRectangle_2, 655). +-define(wxDC_DrawRectangle_1, 656). +-define(wxDC_DrawRotatedText, 657). +-define(wxDC_DrawRoundedRectangle_3, 659). +-define(wxDC_DrawRoundedRectangle_2, 660). +-define(wxDC_DrawText, 661). +-define(wxDC_EndDoc, 662). +-define(wxDC_EndPage, 663). +-define(wxDC_FloodFill, 664). +-define(wxDC_GetBackground, 665). +-define(wxDC_GetBackgroundMode, 666). +-define(wxDC_GetBrush, 667). +-define(wxDC_GetCharHeight, 668). +-define(wxDC_GetCharWidth, 669). +-define(wxDC_GetClippingBox, 670). +-define(wxDC_GetFont, 672). +-define(wxDC_GetLayoutDirection, 673). +-define(wxDC_GetLogicalFunction, 674). +-define(wxDC_GetMapMode, 675). +-define(wxDC_GetMultiLineTextExtent_4, 676). +-define(wxDC_GetMultiLineTextExtent_1, 677). +-define(wxDC_GetPartialTextExtents, 678). +-define(wxDC_GetPen, 679). +-define(wxDC_GetPixel, 680). +-define(wxDC_GetPPI, 681). +-define(wxDC_GetSize, 683). +-define(wxDC_GetSizeMM, 685). +-define(wxDC_GetTextBackground, 686). +-define(wxDC_GetTextExtent_4, 687). +-define(wxDC_GetTextExtent_1, 688). +-define(wxDC_GetTextForeground, 690). +-define(wxDC_GetUserScale, 691). +-define(wxDC_GradientFillConcentric_3, 692). +-define(wxDC_GradientFillConcentric_4, 693). +-define(wxDC_GradientFillLinear, 694). +-define(wxDC_LogicalToDeviceX, 695). +-define(wxDC_LogicalToDeviceXRel, 696). +-define(wxDC_LogicalToDeviceY, 697). +-define(wxDC_LogicalToDeviceYRel, 698). +-define(wxDC_MaxX, 699). +-define(wxDC_MaxY, 700). +-define(wxDC_MinX, 701). +-define(wxDC_MinY, 702). +-define(wxDC_IsOk, 703). +-define(wxDC_ResetBoundingBox, 704). +-define(wxDC_SetAxisOrientation, 705). +-define(wxDC_SetBackground, 706). +-define(wxDC_SetBackgroundMode, 707). +-define(wxDC_SetBrush, 708). +-define(wxDC_SetClippingRegion_2, 710). +-define(wxDC_SetClippingRegion_1_1, 711). +-define(wxDC_SetClippingRegion_1_0, 712). +-define(wxDC_SetDeviceOrigin, 713). +-define(wxDC_SetFont, 714). +-define(wxDC_SetLayoutDirection, 715). +-define(wxDC_SetLogicalFunction, 716). +-define(wxDC_SetMapMode, 717). +-define(wxDC_SetPalette, 718). +-define(wxDC_SetPen, 719). +-define(wxDC_SetTextBackground, 720). +-define(wxDC_SetTextForeground, 721). +-define(wxDC_SetUserScale, 722). +-define(wxDC_StartDoc, 723). +-define(wxDC_StartPage, 724). +-define(wxMirrorDC_new, 725). +-define(wxMirrorDC_destroy, 726). +-define(wxScreenDC_new, 727). +-define(wxScreenDC_destruct, 728). +-define(wxPostScriptDC_new_0, 729). +-define(wxPostScriptDC_new_1, 730). +-define(wxPostScriptDC_destruct, 731). +-define(wxPostScriptDC_SetResolution, 732). +-define(wxPostScriptDC_GetResolution, 733). +-define(wxWindowDC_new_0, 734). +-define(wxWindowDC_new_1, 735). +-define(wxWindowDC_destruct, 736). +-define(wxClientDC_new_0, 737). +-define(wxClientDC_new_1, 738). +-define(wxClientDC_destroy, 739). +-define(wxPaintDC_new_0, 740). +-define(wxPaintDC_new_1, 741). +-define(wxPaintDC_destroy, 742). +-define(wxMemoryDC_new_1_0, 744). +-define(wxMemoryDC_new_1_1, 745). +-define(wxMemoryDC_new_0, 746). +-define(wxMemoryDC_destruct, 748). +-define(wxMemoryDC_SelectObject, 749). +-define(wxMemoryDC_SelectObjectAsSource, 750). +-define(wxBufferedDC_new_0, 751). +-define(wxBufferedDC_new_2, 752). +-define(wxBufferedDC_new_3, 753). +-define(wxBufferedDC_destruct, 754). +-define(wxBufferedDC_Init_2, 755). +-define(wxBufferedDC_Init_3, 756). +-define(wxBufferedPaintDC_new_3, 757). +-define(wxBufferedPaintDC_new_2, 758). +-define(wxBufferedPaintDC_destruct, 759). +-define(wxGraphicsObject_destruct, 760). +-define(wxGraphicsObject_GetRenderer, 761). +-define(wxGraphicsObject_IsNull, 762). +-define(wxGraphicsContext_destruct, 763). +-define(wxGraphicsContext_Create_1_1, 764). +-define(wxGraphicsContext_Create_1_0, 765). +-define(wxGraphicsContext_Create_0, 766). +-define(wxGraphicsContext_CreatePen, 767). +-define(wxGraphicsContext_CreateBrush, 768). +-define(wxGraphicsContext_CreateRadialGradientBrush, 769). +-define(wxGraphicsContext_CreateLinearGradientBrush, 770). +-define(wxGraphicsContext_CreateFont, 771). +-define(wxGraphicsContext_CreateMatrix, 772). +-define(wxGraphicsContext_CreatePath, 773). +-define(wxGraphicsContext_Clip_1, 774). +-define(wxGraphicsContext_Clip_4, 775). +-define(wxGraphicsContext_ResetClip, 776). +-define(wxGraphicsContext_DrawBitmap, 777). +-define(wxGraphicsContext_DrawEllipse, 778). +-define(wxGraphicsContext_DrawIcon, 779). +-define(wxGraphicsContext_DrawLines, 780). +-define(wxGraphicsContext_DrawPath, 781). +-define(wxGraphicsContext_DrawRectangle, 782). +-define(wxGraphicsContext_DrawRoundedRectangle, 783). +-define(wxGraphicsContext_DrawText_3, 784). +-define(wxGraphicsContext_DrawText_4_0, 785). +-define(wxGraphicsContext_DrawText_4_1, 786). +-define(wxGraphicsContext_DrawText_5, 787). +-define(wxGraphicsContext_FillPath, 788). +-define(wxGraphicsContext_StrokePath, 789). +-define(wxGraphicsContext_GetPartialTextExtents, 790). +-define(wxGraphicsContext_GetTextExtent, 791). +-define(wxGraphicsContext_Rotate, 792). +-define(wxGraphicsContext_Scale, 793). +-define(wxGraphicsContext_Translate, 794). +-define(wxGraphicsContext_GetTransform, 795). +-define(wxGraphicsContext_SetTransform, 796). +-define(wxGraphicsContext_ConcatTransform, 797). +-define(wxGraphicsContext_SetBrush_1_1, 798). +-define(wxGraphicsContext_SetBrush_1_0, 799). +-define(wxGraphicsContext_SetFont_1, 800). +-define(wxGraphicsContext_SetFont_2, 801). +-define(wxGraphicsContext_SetPen_1_0, 802). +-define(wxGraphicsContext_SetPen_1_1, 803). +-define(wxGraphicsContext_StrokeLine, 804). +-define(wxGraphicsContext_StrokeLines, 805). +-define(wxGraphicsMatrix_Concat, 807). +-define(wxGraphicsMatrix_Get, 809). +-define(wxGraphicsMatrix_Invert, 810). +-define(wxGraphicsMatrix_IsEqual, 811). +-define(wxGraphicsMatrix_IsIdentity, 813). +-define(wxGraphicsMatrix_Rotate, 814). +-define(wxGraphicsMatrix_Scale, 815). +-define(wxGraphicsMatrix_Translate, 816). +-define(wxGraphicsMatrix_Set, 817). +-define(wxGraphicsMatrix_TransformPoint, 818). +-define(wxGraphicsMatrix_TransformDistance, 819). +-define(wxGraphicsPath_MoveToPoint_2, 820). +-define(wxGraphicsPath_MoveToPoint_1, 821). +-define(wxGraphicsPath_AddArc_6, 822). +-define(wxGraphicsPath_AddArc_5, 823). +-define(wxGraphicsPath_AddArcToPoint, 824). +-define(wxGraphicsPath_AddCircle, 825). +-define(wxGraphicsPath_AddCurveToPoint_6, 826). +-define(wxGraphicsPath_AddCurveToPoint_3, 827). +-define(wxGraphicsPath_AddEllipse, 828). +-define(wxGraphicsPath_AddLineToPoint_2, 829). +-define(wxGraphicsPath_AddLineToPoint_1, 830). +-define(wxGraphicsPath_AddPath, 831). +-define(wxGraphicsPath_AddQuadCurveToPoint, 832). +-define(wxGraphicsPath_AddRectangle, 833). +-define(wxGraphicsPath_AddRoundedRectangle, 834). +-define(wxGraphicsPath_CloseSubpath, 835). +-define(wxGraphicsPath_Contains_3, 836). +-define(wxGraphicsPath_Contains_2, 837). +-define(wxGraphicsPath_GetBox, 839). +-define(wxGraphicsPath_GetCurrentPoint, 841). +-define(wxGraphicsPath_Transform, 842). +-define(wxGraphicsRenderer_GetDefaultRenderer, 843). +-define(wxGraphicsRenderer_CreateContext_1_1, 844). +-define(wxGraphicsRenderer_CreateContext_1_0, 845). +-define(wxGraphicsRenderer_CreatePen, 846). +-define(wxGraphicsRenderer_CreateBrush, 847). +-define(wxGraphicsRenderer_CreateLinearGradientBrush, 848). +-define(wxGraphicsRenderer_CreateRadialGradientBrush, 849). +-define(wxGraphicsRenderer_CreateFont, 850). +-define(wxGraphicsRenderer_CreateMatrix, 851). +-define(wxGraphicsRenderer_CreatePath, 852). +-define(wxMenuBar_new_1, 854). +-define(wxMenuBar_new_0, 856). +-define(wxMenuBar_destruct, 858). +-define(wxMenuBar_Append, 859). +-define(wxMenuBar_Check, 860). +-define(wxMenuBar_Enable_2, 861). +-define(wxMenuBar_Enable_1, 862). +-define(wxMenuBar_EnableTop, 863). +-define(wxMenuBar_FindMenu, 864). +-define(wxMenuBar_FindMenuItem, 865). +-define(wxMenuBar_FindItem, 866). +-define(wxMenuBar_GetHelpString, 867). +-define(wxMenuBar_GetLabel_1, 868). +-define(wxMenuBar_GetLabel_0, 869). +-define(wxMenuBar_GetLabelTop, 870). +-define(wxMenuBar_GetMenu, 871). +-define(wxMenuBar_GetMenuCount, 872). +-define(wxMenuBar_Insert, 873). +-define(wxMenuBar_IsChecked, 874). +-define(wxMenuBar_IsEnabled_1, 875). +-define(wxMenuBar_IsEnabled_0, 876). +-define(wxMenuBar_Remove, 877). +-define(wxMenuBar_Replace, 878). +-define(wxMenuBar_SetHelpString, 879). +-define(wxMenuBar_SetLabel_2, 880). +-define(wxMenuBar_SetLabel_1, 881). +-define(wxMenuBar_SetLabelTop, 882). +-define(wxControl_GetLabel, 883). +-define(wxControl_SetLabel, 884). +-define(wxControlWithItems_Append_1, 885). +-define(wxControlWithItems_Append_2, 886). +-define(wxControlWithItems_appendStrings_1, 887). +-define(wxControlWithItems_Clear, 888). +-define(wxControlWithItems_Delete, 889). +-define(wxControlWithItems_FindString, 890). +-define(wxControlWithItems_getClientData, 891). +-define(wxControlWithItems_setClientData, 892). +-define(wxControlWithItems_GetCount, 893). +-define(wxControlWithItems_GetSelection, 894). +-define(wxControlWithItems_GetString, 895). +-define(wxControlWithItems_GetStringSelection, 896). +-define(wxControlWithItems_Insert_2, 897). +-define(wxControlWithItems_Insert_3, 898). +-define(wxControlWithItems_IsEmpty, 899). +-define(wxControlWithItems_Select, 900). +-define(wxControlWithItems_SetSelection, 901). +-define(wxControlWithItems_SetString, 902). +-define(wxControlWithItems_SetStringSelection, 903). +-define(wxMenu_new_2, 906). +-define(wxMenu_new_1, 907). +-define(wxMenu_destruct, 909). +-define(wxMenu_Append_3, 910). +-define(wxMenu_Append_1, 911). +-define(wxMenu_Append_4_0, 912). +-define(wxMenu_Append_4_1, 913). +-define(wxMenu_AppendCheckItem, 914). +-define(wxMenu_AppendRadioItem, 915). +-define(wxMenu_AppendSeparator, 916). +-define(wxMenu_Break, 917). +-define(wxMenu_Check, 918). +-define(wxMenu_Delete_1_0, 919). +-define(wxMenu_Delete_1_1, 920). +-define(wxMenu_Destroy_1_0, 921). +-define(wxMenu_Destroy_1_1, 922). +-define(wxMenu_Enable, 923). +-define(wxMenu_FindItem_1, 924). +-define(wxMenu_FindItem_2, 925). +-define(wxMenu_FindItemByPosition, 926). +-define(wxMenu_GetHelpString, 927). +-define(wxMenu_GetLabel, 928). +-define(wxMenu_GetMenuItemCount, 929). +-define(wxMenu_GetMenuItems, 930). +-define(wxMenu_GetTitle, 932). +-define(wxMenu_Insert_2, 933). +-define(wxMenu_Insert_3, 934). +-define(wxMenu_Insert_5_1, 935). +-define(wxMenu_Insert_5_0, 936). +-define(wxMenu_InsertCheckItem, 937). +-define(wxMenu_InsertRadioItem, 938). +-define(wxMenu_InsertSeparator, 939). +-define(wxMenu_IsChecked, 940). +-define(wxMenu_IsEnabled, 941). +-define(wxMenu_Prepend_1, 942). +-define(wxMenu_Prepend_2, 943). +-define(wxMenu_Prepend_4_1, 944). +-define(wxMenu_Prepend_4_0, 945). +-define(wxMenu_PrependCheckItem, 946). +-define(wxMenu_PrependRadioItem, 947). +-define(wxMenu_PrependSeparator, 948). +-define(wxMenu_Remove_1_0, 949). +-define(wxMenu_Remove_1_1, 950). +-define(wxMenu_SetHelpString, 951). +-define(wxMenu_SetLabel, 952). +-define(wxMenu_SetTitle, 953). +-define(wxMenuItem_new, 954). +-define(wxMenuItem_destruct, 956). +-define(wxMenuItem_Check, 957). +-define(wxMenuItem_Enable, 958). +-define(wxMenuItem_GetBitmap, 959). +-define(wxMenuItem_GetHelp, 960). +-define(wxMenuItem_GetId, 961). +-define(wxMenuItem_GetKind, 962). +-define(wxMenuItem_GetLabel, 963). +-define(wxMenuItem_GetLabelFromText, 964). +-define(wxMenuItem_GetMenu, 965). +-define(wxMenuItem_GetText, 966). +-define(wxMenuItem_GetSubMenu, 967). +-define(wxMenuItem_IsCheckable, 968). +-define(wxMenuItem_IsChecked, 969). +-define(wxMenuItem_IsEnabled, 970). +-define(wxMenuItem_IsSeparator, 971). +-define(wxMenuItem_IsSubMenu, 972). +-define(wxMenuItem_SetBitmap, 973). +-define(wxMenuItem_SetHelp, 974). +-define(wxMenuItem_SetMenu, 975). +-define(wxMenuItem_SetSubMenu, 976). +-define(wxMenuItem_SetText, 977). +-define(wxToolBar_AddControl, 978). +-define(wxToolBar_AddSeparator, 979). +-define(wxToolBar_AddTool_5, 980). +-define(wxToolBar_AddTool_4_0, 981). +-define(wxToolBar_AddTool_1, 982). +-define(wxToolBar_AddTool_4_1, 983). +-define(wxToolBar_AddTool_3, 984). +-define(wxToolBar_AddTool_6, 985). +-define(wxToolBar_AddCheckTool, 986). +-define(wxToolBar_AddRadioTool, 987). +-define(wxToolBar_AddStretchableSpace, 988). +-define(wxToolBar_InsertStretchableSpace, 989). +-define(wxToolBar_DeleteTool, 990). +-define(wxToolBar_DeleteToolByPos, 991). +-define(wxToolBar_EnableTool, 992). +-define(wxToolBar_FindById, 993). +-define(wxToolBar_FindControl, 994). +-define(wxToolBar_FindToolForPosition, 995). +-define(wxToolBar_GetToolSize, 996). +-define(wxToolBar_GetToolBitmapSize, 997). +-define(wxToolBar_GetMargins, 998). +-define(wxToolBar_GetToolEnabled, 999). +-define(wxToolBar_GetToolLongHelp, 1000). +-define(wxToolBar_GetToolPacking, 1001). +-define(wxToolBar_GetToolPos, 1002). +-define(wxToolBar_GetToolSeparation, 1003). +-define(wxToolBar_GetToolShortHelp, 1004). +-define(wxToolBar_GetToolState, 1005). +-define(wxToolBar_InsertControl, 1006). +-define(wxToolBar_InsertSeparator, 1007). +-define(wxToolBar_InsertTool_5, 1008). +-define(wxToolBar_InsertTool_2, 1009). +-define(wxToolBar_InsertTool_4, 1010). +-define(wxToolBar_Realize, 1011). +-define(wxToolBar_RemoveTool, 1012). +-define(wxToolBar_SetMargins, 1013). +-define(wxToolBar_SetToolBitmapSize, 1014). +-define(wxToolBar_SetToolLongHelp, 1015). +-define(wxToolBar_SetToolPacking, 1016). +-define(wxToolBar_SetToolShortHelp, 1017). +-define(wxToolBar_SetToolSeparation, 1018). +-define(wxToolBar_ToggleTool, 1019). +-define(wxStatusBar_new_0, 1021). +-define(wxStatusBar_new_2, 1022). +-define(wxStatusBar_destruct, 1024). +-define(wxStatusBar_Create, 1025). +-define(wxStatusBar_GetFieldRect, 1026). +-define(wxStatusBar_GetFieldsCount, 1027). +-define(wxStatusBar_GetStatusText, 1028). +-define(wxStatusBar_PopStatusText, 1029). +-define(wxStatusBar_PushStatusText, 1030). +-define(wxStatusBar_SetFieldsCount, 1031). +-define(wxStatusBar_SetMinHeight, 1032). +-define(wxStatusBar_SetStatusText, 1033). +-define(wxStatusBar_SetStatusWidths, 1034). +-define(wxStatusBar_SetStatusStyles, 1035). +-define(wxBitmap_new_0, 1036). +-define(wxBitmap_new_3, 1037). +-define(wxBitmap_new_4, 1038). +-define(wxBitmap_new_2_0, 1039). +-define(wxBitmap_new_2_1, 1040). +-define(wxBitmap_destruct, 1041). +-define(wxBitmap_ConvertToImage, 1042). +-define(wxBitmap_CopyFromIcon, 1043). +-define(wxBitmap_Create, 1044). +-define(wxBitmap_GetDepth, 1045). +-define(wxBitmap_GetHeight, 1046). +-define(wxBitmap_GetPalette, 1047). +-define(wxBitmap_GetMask, 1048). +-define(wxBitmap_GetWidth, 1049). +-define(wxBitmap_GetSubBitmap, 1050). +-define(wxBitmap_LoadFile, 1051). +-define(wxBitmap_Ok, 1052). +-define(wxBitmap_SaveFile, 1053). +-define(wxBitmap_SetDepth, 1054). +-define(wxBitmap_SetHeight, 1055). +-define(wxBitmap_SetMask, 1056). +-define(wxBitmap_SetPalette, 1057). +-define(wxBitmap_SetWidth, 1058). +-define(wxIcon_new_0, 1059). +-define(wxIcon_new_2, 1060). +-define(wxIcon_new_1, 1061). +-define(wxIcon_CopyFromBitmap, 1062). +-define(wxIcon_destroy, 1063). +-define(wxIconBundle_new_0, 1064). +-define(wxIconBundle_new_2, 1065). +-define(wxIconBundle_new_1_0, 1066). +-define(wxIconBundle_new_1_1, 1067). +-define(wxIconBundle_destruct, 1068). +-define(wxIconBundle_AddIcon_2, 1069). +-define(wxIconBundle_AddIcon_1, 1070). +-define(wxIconBundle_GetIcon_1_1, 1071). +-define(wxIconBundle_GetIcon_1_0, 1072). +-define(wxCursor_new_0, 1073). +-define(wxCursor_new_1_0, 1074). +-define(wxCursor_new_1_1, 1075). +-define(wxCursor_new_4, 1076). +-define(wxCursor_destruct, 1077). +-define(wxCursor_Ok, 1078). +-define(wxMask_new_0, 1079). +-define(wxMask_new_2_1, 1080). +-define(wxMask_new_2_0, 1081). +-define(wxMask_new_1, 1082). +-define(wxMask_destruct, 1083). +-define(wxMask_Create_2_1, 1084). +-define(wxMask_Create_2_0, 1085). +-define(wxMask_Create_1, 1086). +-define(wxImage_new_0, 1087). +-define(wxImage_new_3_0, 1088). +-define(wxImage_new_4, 1089). +-define(wxImage_new_5, 1090). +-define(wxImage_new_2, 1091). +-define(wxImage_new_3_1, 1092). +-define(wxImage_Blur, 1093). +-define(wxImage_BlurHorizontal, 1094). +-define(wxImage_BlurVertical, 1095). +-define(wxImage_ConvertAlphaToMask, 1096). +-define(wxImage_ConvertToGreyscale, 1097). +-define(wxImage_ConvertToMono, 1098). +-define(wxImage_Copy, 1099). +-define(wxImage_Create_3, 1100). +-define(wxImage_Create_4, 1101). +-define(wxImage_Create_5, 1102). +-define(wxImage_Destroy, 1103). +-define(wxImage_FindFirstUnusedColour, 1104). +-define(wxImage_GetImageExtWildcard, 1105). +-define(wxImage_GetAlpha_2, 1106). +-define(wxImage_GetAlpha_0, 1107). +-define(wxImage_GetBlue, 1108). +-define(wxImage_GetData, 1109). +-define(wxImage_GetGreen, 1110). +-define(wxImage_GetImageCount, 1111). +-define(wxImage_GetHeight, 1112). +-define(wxImage_GetMaskBlue, 1113). +-define(wxImage_GetMaskGreen, 1114). +-define(wxImage_GetMaskRed, 1115). +-define(wxImage_GetOrFindMaskColour, 1116). +-define(wxImage_GetPalette, 1117). +-define(wxImage_GetRed, 1118). +-define(wxImage_GetSubImage, 1119). +-define(wxImage_GetWidth, 1120). +-define(wxImage_HasAlpha, 1121). +-define(wxImage_HasMask, 1122). +-define(wxImage_GetOption, 1123). +-define(wxImage_GetOptionInt, 1124). +-define(wxImage_HasOption, 1125). +-define(wxImage_InitAlpha, 1126). +-define(wxImage_InitStandardHandlers, 1127). +-define(wxImage_IsTransparent, 1128). +-define(wxImage_LoadFile_2, 1129). +-define(wxImage_LoadFile_3, 1130). +-define(wxImage_Ok, 1131). +-define(wxImage_RemoveHandler, 1132). +-define(wxImage_Mirror, 1133). +-define(wxImage_Replace, 1134). +-define(wxImage_Rescale, 1135). +-define(wxImage_Resize, 1136). +-define(wxImage_Rotate, 1137). +-define(wxImage_RotateHue, 1138). +-define(wxImage_Rotate90, 1139). +-define(wxImage_SaveFile_1, 1140). +-define(wxImage_SaveFile_2_0, 1141). +-define(wxImage_SaveFile_2_1, 1142). +-define(wxImage_Scale, 1143). +-define(wxImage_Size, 1144). +-define(wxImage_SetAlpha_3, 1145). +-define(wxImage_SetAlpha_2, 1146). +-define(wxImage_SetData_2, 1147). +-define(wxImage_SetData_4, 1148). +-define(wxImage_SetMask, 1149). +-define(wxImage_SetMaskColour, 1150). +-define(wxImage_SetMaskFromImage, 1151). +-define(wxImage_SetOption_2_1, 1152). +-define(wxImage_SetOption_2_0, 1153). +-define(wxImage_SetPalette, 1154). +-define(wxImage_SetRGB_5, 1155). +-define(wxImage_SetRGB_4, 1156). +-define(wxImage_destroy, 1157). +-define(wxBrush_new_0, 1158). +-define(wxBrush_new_2, 1159). +-define(wxBrush_new_1, 1160). +-define(wxBrush_destruct, 1162). +-define(wxBrush_GetColour, 1163). +-define(wxBrush_GetStipple, 1164). +-define(wxBrush_GetStyle, 1165). +-define(wxBrush_IsHatch, 1166). +-define(wxBrush_IsOk, 1167). +-define(wxBrush_SetColour_1, 1168). +-define(wxBrush_SetColour_3, 1169). +-define(wxBrush_SetStipple, 1170). +-define(wxBrush_SetStyle, 1171). +-define(wxPen_new_0, 1172). +-define(wxPen_new_2, 1173). +-define(wxPen_destruct, 1174). +-define(wxPen_GetCap, 1175). +-define(wxPen_GetColour, 1176). +-define(wxPen_GetJoin, 1177). +-define(wxPen_GetStyle, 1178). +-define(wxPen_GetWidth, 1179). +-define(wxPen_IsOk, 1180). +-define(wxPen_SetCap, 1181). +-define(wxPen_SetColour_1, 1182). +-define(wxPen_SetColour_3, 1183). +-define(wxPen_SetJoin, 1184). +-define(wxPen_SetStyle, 1185). +-define(wxPen_SetWidth, 1186). +-define(wxRegion_new_0, 1187). +-define(wxRegion_new_4, 1188). +-define(wxRegion_new_2, 1189). +-define(wxRegion_new_1_1, 1190). +-define(wxRegion_new_1_0, 1192). +-define(wxRegion_destruct, 1194). +-define(wxRegion_Clear, 1195). +-define(wxRegion_Contains_2, 1196). +-define(wxRegion_Contains_1_0, 1197). +-define(wxRegion_Contains_4, 1198). +-define(wxRegion_Contains_1_1, 1199). +-define(wxRegion_ConvertToBitmap, 1200). +-define(wxRegion_GetBox, 1201). +-define(wxRegion_Intersect_4, 1202). +-define(wxRegion_Intersect_1_1, 1203). +-define(wxRegion_Intersect_1_0, 1204). +-define(wxRegion_IsEmpty, 1205). +-define(wxRegion_Subtract_4, 1206). +-define(wxRegion_Subtract_1_1, 1207). +-define(wxRegion_Subtract_1_0, 1208). +-define(wxRegion_Offset_2, 1209). +-define(wxRegion_Offset_1, 1210). +-define(wxRegion_Union_4, 1211). +-define(wxRegion_Union_1_2, 1212). +-define(wxRegion_Union_1_1, 1213). +-define(wxRegion_Union_1_0, 1214). +-define(wxRegion_Union_3, 1215). +-define(wxRegion_Xor_4, 1216). +-define(wxRegion_Xor_1_1, 1217). +-define(wxRegion_Xor_1_0, 1218). +-define(wxAcceleratorTable_new_0, 1219). +-define(wxAcceleratorTable_new_2, 1220). +-define(wxAcceleratorTable_destruct, 1221). +-define(wxAcceleratorTable_Ok, 1222). +-define(wxAcceleratorEntry_new_1_0, 1223). +-define(wxAcceleratorEntry_new_1_1, 1224). +-define(wxAcceleratorEntry_GetCommand, 1225). +-define(wxAcceleratorEntry_GetFlags, 1226). +-define(wxAcceleratorEntry_GetKeyCode, 1227). +-define(wxAcceleratorEntry_Set, 1228). +-define(wxAcceleratorEntry_destroy, 1229). +-define(wxCaret_new_3, 1234). +-define(wxCaret_new_2, 1235). +-define(wxCaret_destruct, 1237). +-define(wxCaret_Create_3, 1238). +-define(wxCaret_Create_2, 1239). +-define(wxCaret_GetBlinkTime, 1240). +-define(wxCaret_GetPosition, 1242). +-define(wxCaret_GetSize, 1244). +-define(wxCaret_GetWindow, 1245). +-define(wxCaret_Hide, 1246). +-define(wxCaret_IsOk, 1247). +-define(wxCaret_IsVisible, 1248). +-define(wxCaret_Move_2, 1249). +-define(wxCaret_Move_1, 1250). +-define(wxCaret_SetBlinkTime, 1251). +-define(wxCaret_SetSize_2, 1252). +-define(wxCaret_SetSize_1, 1253). +-define(wxCaret_Show, 1254). +-define(wxSizer_Add_2_1, 1255). +-define(wxSizer_Add_2_0, 1256). +-define(wxSizer_Add_3, 1257). +-define(wxSizer_Add_2_3, 1258). +-define(wxSizer_Add_2_2, 1259). +-define(wxSizer_AddSpacer, 1260). +-define(wxSizer_AddStretchSpacer, 1261). +-define(wxSizer_CalcMin, 1262). +-define(wxSizer_Clear, 1263). +-define(wxSizer_Detach_1_2, 1264). +-define(wxSizer_Detach_1_1, 1265). +-define(wxSizer_Detach_1_0, 1266). +-define(wxSizer_Fit, 1267). +-define(wxSizer_FitInside, 1268). +-define(wxSizer_GetChildren, 1269). +-define(wxSizer_GetItem_2_1, 1270). +-define(wxSizer_GetItem_2_0, 1271). +-define(wxSizer_GetItem_1, 1272). +-define(wxSizer_GetSize, 1273). +-define(wxSizer_GetPosition, 1274). +-define(wxSizer_GetMinSize, 1275). +-define(wxSizer_Hide_2_0, 1276). +-define(wxSizer_Hide_2_1, 1277). +-define(wxSizer_Hide_1, 1278). +-define(wxSizer_Insert_3_1, 1279). +-define(wxSizer_Insert_3_0, 1280). +-define(wxSizer_Insert_4, 1281). +-define(wxSizer_Insert_3_3, 1282). +-define(wxSizer_Insert_3_2, 1283). +-define(wxSizer_Insert_2, 1284). +-define(wxSizer_InsertSpacer, 1285). +-define(wxSizer_InsertStretchSpacer, 1286). +-define(wxSizer_IsShown_1_2, 1287). +-define(wxSizer_IsShown_1_1, 1288). +-define(wxSizer_IsShown_1_0, 1289). +-define(wxSizer_Layout, 1290). +-define(wxSizer_Prepend_2_1, 1291). +-define(wxSizer_Prepend_2_0, 1292). +-define(wxSizer_Prepend_3, 1293). +-define(wxSizer_Prepend_2_3, 1294). +-define(wxSizer_Prepend_2_2, 1295). +-define(wxSizer_Prepend_1, 1296). +-define(wxSizer_PrependSpacer, 1297). +-define(wxSizer_PrependStretchSpacer, 1298). +-define(wxSizer_RecalcSizes, 1299). +-define(wxSizer_Remove_1_1, 1300). +-define(wxSizer_Remove_1_0, 1301). +-define(wxSizer_Replace_3_1, 1302). +-define(wxSizer_Replace_3_0, 1303). +-define(wxSizer_Replace_2, 1304). +-define(wxSizer_SetDimension, 1305). +-define(wxSizer_SetMinSize_2, 1306). +-define(wxSizer_SetMinSize_1, 1307). +-define(wxSizer_SetItemMinSize_3_2, 1308). +-define(wxSizer_SetItemMinSize_2_2, 1309). +-define(wxSizer_SetItemMinSize_3_1, 1310). +-define(wxSizer_SetItemMinSize_2_1, 1311). +-define(wxSizer_SetItemMinSize_3_0, 1312). +-define(wxSizer_SetItemMinSize_2_0, 1313). +-define(wxSizer_SetSizeHints, 1314). +-define(wxSizer_SetVirtualSizeHints, 1315). +-define(wxSizer_Show_2_2, 1316). +-define(wxSizer_Show_2_1, 1317). +-define(wxSizer_Show_2_0, 1318). +-define(wxSizer_Show_1, 1319). +-define(wxSizerFlags_new, 1320). +-define(wxSizerFlags_Align, 1321). +-define(wxSizerFlags_Border_2, 1322). +-define(wxSizerFlags_Border_1, 1323). +-define(wxSizerFlags_Center, 1324). +-define(wxSizerFlags_Centre, 1325). +-define(wxSizerFlags_Expand, 1326). +-define(wxSizerFlags_Left, 1327). +-define(wxSizerFlags_Proportion, 1328). +-define(wxSizerFlags_Right, 1329). +-define(wxSizerFlags_destroy, 1330). +-define(wxSizerItem_new_5_1, 1331). +-define(wxSizerItem_new_2_1, 1332). +-define(wxSizerItem_new_5_0, 1333). +-define(wxSizerItem_new_2_0, 1334). +-define(wxSizerItem_new_6, 1335). +-define(wxSizerItem_new_3, 1336). +-define(wxSizerItem_new_0, 1337). +-define(wxSizerItem_destruct, 1338). +-define(wxSizerItem_CalcMin, 1339). +-define(wxSizerItem_DeleteWindows, 1340). +-define(wxSizerItem_DetachSizer, 1341). +-define(wxSizerItem_GetBorder, 1342). +-define(wxSizerItem_GetFlag, 1343). +-define(wxSizerItem_GetMinSize, 1344). +-define(wxSizerItem_GetPosition, 1345). +-define(wxSizerItem_GetProportion, 1346). +-define(wxSizerItem_GetRatio, 1347). +-define(wxSizerItem_GetRect, 1348). +-define(wxSizerItem_GetSize, 1349). +-define(wxSizerItem_GetSizer, 1350). +-define(wxSizerItem_GetSpacer, 1351). +-define(wxSizerItem_GetUserData, 1352). +-define(wxSizerItem_GetWindow, 1353). +-define(wxSizerItem_IsSizer, 1354). +-define(wxSizerItem_IsShown, 1355). +-define(wxSizerItem_IsSpacer, 1356). +-define(wxSizerItem_IsWindow, 1357). +-define(wxSizerItem_SetBorder, 1358). +-define(wxSizerItem_SetDimension, 1359). +-define(wxSizerItem_SetFlag, 1360). +-define(wxSizerItem_SetInitSize, 1361). +-define(wxSizerItem_SetMinSize_1, 1362). +-define(wxSizerItem_SetMinSize_2, 1363). +-define(wxSizerItem_SetProportion, 1364). +-define(wxSizerItem_SetRatio_2, 1365). +-define(wxSizerItem_SetRatio_1_1, 1366). +-define(wxSizerItem_SetRatio_1_0, 1367). +-define(wxSizerItem_SetSizer, 1368). +-define(wxSizerItem_SetSpacer_1, 1369). +-define(wxSizerItem_SetSpacer_2, 1370). +-define(wxSizerItem_SetWindow, 1371). +-define(wxSizerItem_Show, 1372). +-define(wxBoxSizer_new, 1373). +-define(wxBoxSizer_GetOrientation, 1374). +-define(wxBoxSizer_destroy, 1375). +-define(wxStaticBoxSizer_new_2, 1376). +-define(wxStaticBoxSizer_new_3, 1377). +-define(wxStaticBoxSizer_GetStaticBox, 1378). +-define(wxStaticBoxSizer_destroy, 1379). +-define(wxGridSizer_new_4, 1380). +-define(wxGridSizer_new_2, 1381). +-define(wxGridSizer_GetCols, 1382). +-define(wxGridSizer_GetHGap, 1383). +-define(wxGridSizer_GetRows, 1384). +-define(wxGridSizer_GetVGap, 1385). +-define(wxGridSizer_SetCols, 1386). +-define(wxGridSizer_SetHGap, 1387). +-define(wxGridSizer_SetRows, 1388). +-define(wxGridSizer_SetVGap, 1389). +-define(wxGridSizer_destroy, 1390). +-define(wxFlexGridSizer_new_4, 1391). +-define(wxFlexGridSizer_new_2, 1392). +-define(wxFlexGridSizer_AddGrowableCol, 1393). +-define(wxFlexGridSizer_AddGrowableRow, 1394). +-define(wxFlexGridSizer_GetFlexibleDirection, 1395). +-define(wxFlexGridSizer_GetNonFlexibleGrowMode, 1396). +-define(wxFlexGridSizer_RemoveGrowableCol, 1397). +-define(wxFlexGridSizer_RemoveGrowableRow, 1398). +-define(wxFlexGridSizer_SetFlexibleDirection, 1399). +-define(wxFlexGridSizer_SetNonFlexibleGrowMode, 1400). +-define(wxFlexGridSizer_destroy, 1401). +-define(wxGridBagSizer_new, 1402). +-define(wxGridBagSizer_Add_3_2, 1403). +-define(wxGridBagSizer_Add_3_1, 1404). +-define(wxGridBagSizer_Add_4, 1405). +-define(wxGridBagSizer_Add_1_0, 1406). +-define(wxGridBagSizer_Add_2_1, 1407). +-define(wxGridBagSizer_Add_2_0, 1408). +-define(wxGridBagSizer_Add_3_0, 1409). +-define(wxGridBagSizer_Add_1_1, 1410). +-define(wxGridBagSizer_CalcMin, 1411). +-define(wxGridBagSizer_CheckForIntersection_2, 1412). +-define(wxGridBagSizer_CheckForIntersection_3, 1413). +-define(wxGridBagSizer_FindItem_1_1, 1414). +-define(wxGridBagSizer_FindItem_1_0, 1415). +-define(wxGridBagSizer_FindItemAtPoint, 1416). +-define(wxGridBagSizer_FindItemAtPosition, 1417). +-define(wxGridBagSizer_FindItemWithData, 1418). +-define(wxGridBagSizer_GetCellSize, 1419). +-define(wxGridBagSizer_GetEmptyCellSize, 1420). +-define(wxGridBagSizer_GetItemPosition_1_2, 1421). +-define(wxGridBagSizer_GetItemPosition_1_1, 1422). +-define(wxGridBagSizer_GetItemPosition_1_0, 1423). +-define(wxGridBagSizer_GetItemSpan_1_2, 1424). +-define(wxGridBagSizer_GetItemSpan_1_1, 1425). +-define(wxGridBagSizer_GetItemSpan_1_0, 1426). +-define(wxGridBagSizer_SetEmptyCellSize, 1427). +-define(wxGridBagSizer_SetItemPosition_2_2, 1428). +-define(wxGridBagSizer_SetItemPosition_2_1, 1429). +-define(wxGridBagSizer_SetItemPosition_2_0, 1430). +-define(wxGridBagSizer_SetItemSpan_2_2, 1431). +-define(wxGridBagSizer_SetItemSpan_2_1, 1432). +-define(wxGridBagSizer_SetItemSpan_2_0, 1433). +-define(wxGridBagSizer_destroy, 1434). +-define(wxStdDialogButtonSizer_new, 1435). +-define(wxStdDialogButtonSizer_AddButton, 1436). +-define(wxStdDialogButtonSizer_Realize, 1437). +-define(wxStdDialogButtonSizer_SetAffirmativeButton, 1438). +-define(wxStdDialogButtonSizer_SetCancelButton, 1439). +-define(wxStdDialogButtonSizer_SetNegativeButton, 1440). +-define(wxStdDialogButtonSizer_destroy, 1441). +-define(wxFont_new_0, 1442). +-define(wxFont_new_1, 1443). +-define(wxFont_new_5, 1444). +-define(wxFont_destruct, 1446). +-define(wxFont_IsFixedWidth, 1447). +-define(wxFont_GetDefaultEncoding, 1448). +-define(wxFont_GetFaceName, 1449). +-define(wxFont_GetFamily, 1450). +-define(wxFont_GetNativeFontInfoDesc, 1451). +-define(wxFont_GetNativeFontInfoUserDesc, 1452). +-define(wxFont_GetPointSize, 1453). +-define(wxFont_GetStyle, 1454). +-define(wxFont_GetUnderlined, 1455). +-define(wxFont_GetWeight, 1456). +-define(wxFont_Ok, 1457). +-define(wxFont_SetDefaultEncoding, 1458). +-define(wxFont_SetFaceName, 1459). +-define(wxFont_SetFamily, 1460). +-define(wxFont_SetPointSize, 1461). +-define(wxFont_SetStyle, 1462). +-define(wxFont_SetUnderlined, 1463). +-define(wxFont_SetWeight, 1464). +-define(wxToolTip_Enable, 1465). +-define(wxToolTip_SetDelay, 1466). +-define(wxToolTip_new, 1467). +-define(wxToolTip_SetTip, 1468). +-define(wxToolTip_GetTip, 1469). +-define(wxToolTip_GetWindow, 1470). +-define(wxToolTip_destroy, 1471). +-define(wxButton_new_3, 1473). +-define(wxButton_new_0, 1474). +-define(wxButton_destruct, 1475). +-define(wxButton_Create, 1476). +-define(wxButton_GetDefaultSize, 1477). +-define(wxButton_SetDefault, 1478). +-define(wxButton_SetLabel, 1479). +-define(wxBitmapButton_new_4, 1481). +-define(wxBitmapButton_new_0, 1482). +-define(wxBitmapButton_Create, 1483). +-define(wxBitmapButton_GetBitmapDisabled, 1484). +-define(wxBitmapButton_GetBitmapFocus, 1486). +-define(wxBitmapButton_GetBitmapLabel, 1488). +-define(wxBitmapButton_GetBitmapSelected, 1490). +-define(wxBitmapButton_SetBitmapDisabled, 1492). +-define(wxBitmapButton_SetBitmapFocus, 1493). +-define(wxBitmapButton_SetBitmapLabel, 1494). +-define(wxBitmapButton_SetBitmapSelected, 1495). +-define(wxBitmapButton_destroy, 1496). +-define(wxToggleButton_new_0, 1497). +-define(wxToggleButton_new_4, 1498). +-define(wxToggleButton_Create, 1499). +-define(wxToggleButton_GetValue, 1500). +-define(wxToggleButton_SetValue, 1501). +-define(wxToggleButton_destroy, 1502). +-define(wxCalendarCtrl_new_0, 1503). +-define(wxCalendarCtrl_new_3, 1504). +-define(wxCalendarCtrl_Create, 1505). +-define(wxCalendarCtrl_destruct, 1506). +-define(wxCalendarCtrl_SetDate, 1507). +-define(wxCalendarCtrl_GetDate, 1508). +-define(wxCalendarCtrl_EnableYearChange, 1509). +-define(wxCalendarCtrl_EnableMonthChange, 1510). +-define(wxCalendarCtrl_EnableHolidayDisplay, 1511). +-define(wxCalendarCtrl_SetHeaderColours, 1512). +-define(wxCalendarCtrl_GetHeaderColourFg, 1513). +-define(wxCalendarCtrl_GetHeaderColourBg, 1514). +-define(wxCalendarCtrl_SetHighlightColours, 1515). +-define(wxCalendarCtrl_GetHighlightColourFg, 1516). +-define(wxCalendarCtrl_GetHighlightColourBg, 1517). +-define(wxCalendarCtrl_SetHolidayColours, 1518). +-define(wxCalendarCtrl_GetHolidayColourFg, 1519). +-define(wxCalendarCtrl_GetHolidayColourBg, 1520). +-define(wxCalendarCtrl_GetAttr, 1521). +-define(wxCalendarCtrl_SetAttr, 1522). +-define(wxCalendarCtrl_SetHoliday, 1523). +-define(wxCalendarCtrl_ResetAttr, 1524). +-define(wxCalendarCtrl_HitTest, 1525). +-define(wxCalendarDateAttr_new_0, 1526). +-define(wxCalendarDateAttr_new_2_1, 1527). +-define(wxCalendarDateAttr_new_2_0, 1528). +-define(wxCalendarDateAttr_SetTextColour, 1529). +-define(wxCalendarDateAttr_SetBackgroundColour, 1530). +-define(wxCalendarDateAttr_SetBorderColour, 1531). +-define(wxCalendarDateAttr_SetFont, 1532). +-define(wxCalendarDateAttr_SetBorder, 1533). +-define(wxCalendarDateAttr_SetHoliday, 1534). +-define(wxCalendarDateAttr_HasTextColour, 1535). +-define(wxCalendarDateAttr_HasBackgroundColour, 1536). +-define(wxCalendarDateAttr_HasBorderColour, 1537). +-define(wxCalendarDateAttr_HasFont, 1538). +-define(wxCalendarDateAttr_HasBorder, 1539). +-define(wxCalendarDateAttr_IsHoliday, 1540). +-define(wxCalendarDateAttr_GetTextColour, 1541). +-define(wxCalendarDateAttr_GetBackgroundColour, 1542). +-define(wxCalendarDateAttr_GetBorderColour, 1543). +-define(wxCalendarDateAttr_GetFont, 1544). +-define(wxCalendarDateAttr_GetBorder, 1545). +-define(wxCalendarDateAttr_destroy, 1546). +-define(wxCheckBox_new_4, 1548). +-define(wxCheckBox_new_0, 1549). +-define(wxCheckBox_Create, 1550). +-define(wxCheckBox_GetValue, 1551). +-define(wxCheckBox_Get3StateValue, 1552). +-define(wxCheckBox_Is3rdStateAllowedForUser, 1553). +-define(wxCheckBox_Is3State, 1554). +-define(wxCheckBox_IsChecked, 1555). +-define(wxCheckBox_SetValue, 1556). +-define(wxCheckBox_Set3StateValue, 1557). +-define(wxCheckBox_destroy, 1558). +-define(wxCheckListBox_new_0, 1559). +-define(wxCheckListBox_new_3, 1561). +-define(wxCheckListBox_Check, 1562). +-define(wxCheckListBox_IsChecked, 1563). +-define(wxCheckListBox_destroy, 1564). +-define(wxChoice_new_3, 1567). +-define(wxChoice_new_0, 1568). +-define(wxChoice_destruct, 1570). +-define(wxChoice_Create, 1572). +-define(wxChoice_Delete, 1573). +-define(wxChoice_GetColumns, 1574). +-define(wxChoice_SetColumns, 1575). +-define(wxComboBox_new_0, 1576). +-define(wxComboBox_new_3, 1578). +-define(wxComboBox_destruct, 1579). +-define(wxComboBox_Create, 1581). +-define(wxComboBox_CanCopy, 1582). +-define(wxComboBox_CanCut, 1583). +-define(wxComboBox_CanPaste, 1584). +-define(wxComboBox_CanRedo, 1585). +-define(wxComboBox_CanUndo, 1586). +-define(wxComboBox_Copy, 1587). +-define(wxComboBox_Cut, 1588). +-define(wxComboBox_GetInsertionPoint, 1589). +-define(wxComboBox_GetLastPosition, 1590). +-define(wxComboBox_GetValue, 1591). +-define(wxComboBox_Paste, 1592). +-define(wxComboBox_Redo, 1593). +-define(wxComboBox_Replace, 1594). +-define(wxComboBox_Remove, 1595). +-define(wxComboBox_SetInsertionPoint, 1596). +-define(wxComboBox_SetInsertionPointEnd, 1597). +-define(wxComboBox_SetSelection_1, 1598). +-define(wxComboBox_SetSelection_2, 1599). +-define(wxComboBox_SetValue, 1600). +-define(wxComboBox_Undo, 1601). +-define(wxGauge_new_0, 1602). +-define(wxGauge_new_4, 1603). +-define(wxGauge_Create, 1604). +-define(wxGauge_GetBezelFace, 1605). +-define(wxGauge_GetRange, 1606). +-define(wxGauge_GetShadowWidth, 1607). +-define(wxGauge_GetValue, 1608). +-define(wxGauge_IsVertical, 1609). +-define(wxGauge_SetBezelFace, 1610). +-define(wxGauge_SetRange, 1611). +-define(wxGauge_SetShadowWidth, 1612). +-define(wxGauge_SetValue, 1613). +-define(wxGauge_Pulse, 1614). +-define(wxGauge_destroy, 1615). +-define(wxGenericDirCtrl_new_0, 1616). +-define(wxGenericDirCtrl_new_2, 1617). +-define(wxGenericDirCtrl_destruct, 1618). +-define(wxGenericDirCtrl_Create, 1619). +-define(wxGenericDirCtrl_Init, 1620). +-define(wxGenericDirCtrl_CollapseTree, 1621). +-define(wxGenericDirCtrl_ExpandPath, 1622). +-define(wxGenericDirCtrl_GetDefaultPath, 1623). +-define(wxGenericDirCtrl_GetPath, 1624). +-define(wxGenericDirCtrl_GetFilePath, 1625). +-define(wxGenericDirCtrl_GetFilter, 1626). +-define(wxGenericDirCtrl_GetFilterIndex, 1627). +-define(wxGenericDirCtrl_GetRootId, 1628). +-define(wxGenericDirCtrl_GetTreeCtrl, 1629). +-define(wxGenericDirCtrl_ReCreateTree, 1630). +-define(wxGenericDirCtrl_SetDefaultPath, 1631). +-define(wxGenericDirCtrl_SetFilter, 1632). +-define(wxGenericDirCtrl_SetFilterIndex, 1633). +-define(wxGenericDirCtrl_SetPath, 1634). +-define(wxStaticBox_new_4, 1636). +-define(wxStaticBox_new_0, 1637). +-define(wxStaticBox_Create, 1638). +-define(wxStaticBox_destroy, 1639). +-define(wxStaticLine_new_2, 1641). +-define(wxStaticLine_new_0, 1642). +-define(wxStaticLine_Create, 1643). +-define(wxStaticLine_IsVertical, 1644). +-define(wxStaticLine_GetDefaultSize, 1645). +-define(wxStaticLine_destroy, 1646). +-define(wxListBox_new_3, 1649). +-define(wxListBox_new_0, 1650). +-define(wxListBox_destruct, 1652). +-define(wxListBox_Create, 1654). +-define(wxListBox_Deselect, 1655). +-define(wxListBox_GetSelections, 1656). +-define(wxListBox_InsertItems, 1657). +-define(wxListBox_IsSelected, 1658). +-define(wxListBox_Set, 1659). +-define(wxListBox_HitTest, 1660). +-define(wxListBox_SetFirstItem_1_0, 1661). +-define(wxListBox_SetFirstItem_1_1, 1662). +-define(wxListCtrl_new_0, 1663). +-define(wxListCtrl_new_2, 1664). +-define(wxListCtrl_Arrange, 1665). +-define(wxListCtrl_AssignImageList, 1666). +-define(wxListCtrl_ClearAll, 1667). +-define(wxListCtrl_Create, 1668). +-define(wxListCtrl_DeleteAllItems, 1669). +-define(wxListCtrl_DeleteColumn, 1670). +-define(wxListCtrl_DeleteItem, 1671). +-define(wxListCtrl_EditLabel, 1672). +-define(wxListCtrl_EnsureVisible, 1673). +-define(wxListCtrl_FindItem_3_0, 1674). +-define(wxListCtrl_FindItem_3_1, 1675). +-define(wxListCtrl_GetColumn, 1676). +-define(wxListCtrl_GetColumnCount, 1677). +-define(wxListCtrl_GetColumnWidth, 1678). +-define(wxListCtrl_GetCountPerPage, 1679). +-define(wxListCtrl_GetEditControl, 1680). +-define(wxListCtrl_GetImageList, 1681). +-define(wxListCtrl_GetItem, 1682). +-define(wxListCtrl_GetItemBackgroundColour, 1683). +-define(wxListCtrl_GetItemCount, 1684). +-define(wxListCtrl_GetItemData, 1685). +-define(wxListCtrl_GetItemFont, 1686). +-define(wxListCtrl_GetItemPosition, 1687). +-define(wxListCtrl_GetItemRect, 1688). +-define(wxListCtrl_GetItemSpacing, 1689). +-define(wxListCtrl_GetItemState, 1690). +-define(wxListCtrl_GetItemText, 1691). +-define(wxListCtrl_GetItemTextColour, 1692). +-define(wxListCtrl_GetNextItem, 1693). +-define(wxListCtrl_GetSelectedItemCount, 1694). +-define(wxListCtrl_GetTextColour, 1695). +-define(wxListCtrl_GetTopItem, 1696). +-define(wxListCtrl_GetViewRect, 1697). +-define(wxListCtrl_HitTest, 1698). +-define(wxListCtrl_InsertColumn_2, 1699). +-define(wxListCtrl_InsertColumn_3, 1700). +-define(wxListCtrl_InsertItem_1, 1701). +-define(wxListCtrl_InsertItem_2_1, 1702). +-define(wxListCtrl_InsertItem_2_0, 1703). +-define(wxListCtrl_InsertItem_3, 1704). +-define(wxListCtrl_RefreshItem, 1705). +-define(wxListCtrl_RefreshItems, 1706). +-define(wxListCtrl_ScrollList, 1707). +-define(wxListCtrl_SetBackgroundColour, 1708). +-define(wxListCtrl_SetColumn, 1709). +-define(wxListCtrl_SetColumnWidth, 1710). +-define(wxListCtrl_SetImageList, 1711). +-define(wxListCtrl_SetItem_1, 1712). +-define(wxListCtrl_SetItem_4, 1713). +-define(wxListCtrl_SetItemBackgroundColour, 1714). +-define(wxListCtrl_SetItemCount, 1715). +-define(wxListCtrl_SetItemData, 1716). +-define(wxListCtrl_SetItemFont, 1717). +-define(wxListCtrl_SetItemImage, 1718). +-define(wxListCtrl_SetItemColumnImage, 1719). +-define(wxListCtrl_SetItemPosition, 1720). +-define(wxListCtrl_SetItemState, 1721). +-define(wxListCtrl_SetItemText, 1722). +-define(wxListCtrl_SetItemTextColour, 1723). +-define(wxListCtrl_SetSingleStyle, 1724). +-define(wxListCtrl_SetTextColour, 1725). +-define(wxListCtrl_SetWindowStyleFlag, 1726). +-define(wxListCtrl_SortItems, 1727). +-define(wxListCtrl_destroy, 1728). +-define(wxListView_ClearColumnImage, 1729). +-define(wxListView_Focus, 1730). +-define(wxListView_GetFirstSelected, 1731). +-define(wxListView_GetFocusedItem, 1732). +-define(wxListView_GetNextSelected, 1733). +-define(wxListView_IsSelected, 1734). +-define(wxListView_Select, 1735). +-define(wxListView_SetColumnImage, 1736). +-define(wxListItem_new_0, 1737). +-define(wxListItem_new_1, 1738). +-define(wxListItem_destruct, 1739). +-define(wxListItem_Clear, 1740). +-define(wxListItem_GetAlign, 1741). +-define(wxListItem_GetBackgroundColour, 1742). +-define(wxListItem_GetColumn, 1743). +-define(wxListItem_GetFont, 1744). +-define(wxListItem_GetId, 1745). +-define(wxListItem_GetImage, 1746). +-define(wxListItem_GetMask, 1747). +-define(wxListItem_GetState, 1748). +-define(wxListItem_GetText, 1749). +-define(wxListItem_GetTextColour, 1750). +-define(wxListItem_GetWidth, 1751). +-define(wxListItem_SetAlign, 1752). +-define(wxListItem_SetBackgroundColour, 1753). +-define(wxListItem_SetColumn, 1754). +-define(wxListItem_SetFont, 1755). +-define(wxListItem_SetId, 1756). +-define(wxListItem_SetImage, 1757). +-define(wxListItem_SetMask, 1758). +-define(wxListItem_SetState, 1759). +-define(wxListItem_SetStateMask, 1760). +-define(wxListItem_SetText, 1761). +-define(wxListItem_SetTextColour, 1762). +-define(wxListItem_SetWidth, 1763). +-define(wxListItemAttr_new_0, 1764). +-define(wxListItemAttr_new_3, 1765). +-define(wxListItemAttr_GetBackgroundColour, 1766). +-define(wxListItemAttr_GetFont, 1767). +-define(wxListItemAttr_GetTextColour, 1768). +-define(wxListItemAttr_HasBackgroundColour, 1769). +-define(wxListItemAttr_HasFont, 1770). +-define(wxListItemAttr_HasTextColour, 1771). +-define(wxListItemAttr_SetBackgroundColour, 1772). +-define(wxListItemAttr_SetFont, 1773). +-define(wxListItemAttr_SetTextColour, 1774). +-define(wxListItemAttr_destroy, 1775). +-define(wxImageList_new_0, 1776). +-define(wxImageList_new_3, 1777). +-define(wxImageList_Add_1, 1778). +-define(wxImageList_Add_2_0, 1779). +-define(wxImageList_Add_2_1, 1780). +-define(wxImageList_Create, 1781). +-define(wxImageList_Draw, 1783). +-define(wxImageList_GetBitmap, 1784). +-define(wxImageList_GetIcon, 1785). +-define(wxImageList_GetImageCount, 1786). +-define(wxImageList_GetSize, 1787). +-define(wxImageList_Remove, 1788). +-define(wxImageList_RemoveAll, 1789). +-define(wxImageList_Replace_2, 1790). +-define(wxImageList_Replace_3, 1791). +-define(wxImageList_destroy, 1792). +-define(wxTextAttr_new_0, 1793). +-define(wxTextAttr_new_2, 1794). +-define(wxTextAttr_GetAlignment, 1795). +-define(wxTextAttr_GetBackgroundColour, 1796). +-define(wxTextAttr_GetFont, 1797). +-define(wxTextAttr_GetLeftIndent, 1798). +-define(wxTextAttr_GetLeftSubIndent, 1799). +-define(wxTextAttr_GetRightIndent, 1800). +-define(wxTextAttr_GetTabs, 1801). +-define(wxTextAttr_GetTextColour, 1802). +-define(wxTextAttr_HasBackgroundColour, 1803). +-define(wxTextAttr_HasFont, 1804). +-define(wxTextAttr_HasTextColour, 1805). +-define(wxTextAttr_GetFlags, 1806). +-define(wxTextAttr_IsDefault, 1807). +-define(wxTextAttr_SetAlignment, 1808). +-define(wxTextAttr_SetBackgroundColour, 1809). +-define(wxTextAttr_SetFlags, 1810). +-define(wxTextAttr_SetFont, 1811). +-define(wxTextAttr_SetLeftIndent, 1812). +-define(wxTextAttr_SetRightIndent, 1813). +-define(wxTextAttr_SetTabs, 1814). +-define(wxTextAttr_SetTextColour, 1815). +-define(wxTextAttr_destroy, 1816). +-define(wxTextCtrl_new_3, 1818). +-define(wxTextCtrl_new_0, 1819). +-define(wxTextCtrl_destruct, 1821). +-define(wxTextCtrl_AppendText, 1822). +-define(wxTextCtrl_CanCopy, 1823). +-define(wxTextCtrl_CanCut, 1824). +-define(wxTextCtrl_CanPaste, 1825). +-define(wxTextCtrl_CanRedo, 1826). +-define(wxTextCtrl_CanUndo, 1827). +-define(wxTextCtrl_Clear, 1828). +-define(wxTextCtrl_Copy, 1829). +-define(wxTextCtrl_Create, 1830). +-define(wxTextCtrl_Cut, 1831). +-define(wxTextCtrl_DiscardEdits, 1832). +-define(wxTextCtrl_ChangeValue, 1833). +-define(wxTextCtrl_EmulateKeyPress, 1834). +-define(wxTextCtrl_GetDefaultStyle, 1835). +-define(wxTextCtrl_GetInsertionPoint, 1836). +-define(wxTextCtrl_GetLastPosition, 1837). +-define(wxTextCtrl_GetLineLength, 1838). +-define(wxTextCtrl_GetLineText, 1839). +-define(wxTextCtrl_GetNumberOfLines, 1840). +-define(wxTextCtrl_GetRange, 1841). +-define(wxTextCtrl_GetSelection, 1842). +-define(wxTextCtrl_GetStringSelection, 1843). +-define(wxTextCtrl_GetStyle, 1844). +-define(wxTextCtrl_GetValue, 1845). +-define(wxTextCtrl_IsEditable, 1846). +-define(wxTextCtrl_IsModified, 1847). +-define(wxTextCtrl_IsMultiLine, 1848). +-define(wxTextCtrl_IsSingleLine, 1849). +-define(wxTextCtrl_LoadFile, 1850). +-define(wxTextCtrl_MarkDirty, 1851). +-define(wxTextCtrl_Paste, 1852). +-define(wxTextCtrl_PositionToXY, 1853). +-define(wxTextCtrl_Redo, 1854). +-define(wxTextCtrl_Remove, 1855). +-define(wxTextCtrl_Replace, 1856). +-define(wxTextCtrl_SaveFile, 1857). +-define(wxTextCtrl_SetDefaultStyle, 1858). +-define(wxTextCtrl_SetEditable, 1859). +-define(wxTextCtrl_SetInsertionPoint, 1860). +-define(wxTextCtrl_SetInsertionPointEnd, 1861). +-define(wxTextCtrl_SetMaxLength, 1863). +-define(wxTextCtrl_SetSelection, 1864). +-define(wxTextCtrl_SetStyle, 1865). +-define(wxTextCtrl_SetValue, 1866). +-define(wxTextCtrl_ShowPosition, 1867). +-define(wxTextCtrl_Undo, 1868). +-define(wxTextCtrl_WriteText, 1869). +-define(wxTextCtrl_XYToPosition, 1870). +-define(wxNotebook_new_0, 1873). +-define(wxNotebook_new_3, 1874). +-define(wxNotebook_destruct, 1875). +-define(wxNotebook_AddPage, 1876). +-define(wxNotebook_AdvanceSelection, 1877). +-define(wxNotebook_AssignImageList, 1878). +-define(wxNotebook_Create, 1879). +-define(wxNotebook_DeleteAllPages, 1880). +-define(wxNotebook_DeletePage, 1881). +-define(wxNotebook_RemovePage, 1882). +-define(wxNotebook_GetCurrentPage, 1883). +-define(wxNotebook_GetImageList, 1884). +-define(wxNotebook_GetPage, 1886). +-define(wxNotebook_GetPageCount, 1887). +-define(wxNotebook_GetPageImage, 1888). +-define(wxNotebook_GetPageText, 1889). +-define(wxNotebook_GetRowCount, 1890). +-define(wxNotebook_GetSelection, 1891). +-define(wxNotebook_GetThemeBackgroundColour, 1892). +-define(wxNotebook_HitTest, 1894). +-define(wxNotebook_InsertPage, 1896). +-define(wxNotebook_SetImageList, 1897). +-define(wxNotebook_SetPadding, 1898). +-define(wxNotebook_SetPageSize, 1899). +-define(wxNotebook_SetPageImage, 1900). +-define(wxNotebook_SetPageText, 1901). +-define(wxNotebook_SetSelection, 1902). +-define(wxNotebook_ChangeSelection, 1903). +-define(wxChoicebook_new_0, 1904). +-define(wxChoicebook_new_3, 1905). +-define(wxChoicebook_AddPage, 1906). +-define(wxChoicebook_AdvanceSelection, 1907). +-define(wxChoicebook_AssignImageList, 1908). +-define(wxChoicebook_Create, 1909). +-define(wxChoicebook_DeleteAllPages, 1910). +-define(wxChoicebook_DeletePage, 1911). +-define(wxChoicebook_RemovePage, 1912). +-define(wxChoicebook_GetCurrentPage, 1913). +-define(wxChoicebook_GetImageList, 1914). +-define(wxChoicebook_GetPage, 1916). +-define(wxChoicebook_GetPageCount, 1917). +-define(wxChoicebook_GetPageImage, 1918). +-define(wxChoicebook_GetPageText, 1919). +-define(wxChoicebook_GetSelection, 1920). +-define(wxChoicebook_HitTest, 1921). +-define(wxChoicebook_InsertPage, 1922). +-define(wxChoicebook_SetImageList, 1923). +-define(wxChoicebook_SetPageSize, 1924). +-define(wxChoicebook_SetPageImage, 1925). +-define(wxChoicebook_SetPageText, 1926). +-define(wxChoicebook_SetSelection, 1927). +-define(wxChoicebook_ChangeSelection, 1928). +-define(wxChoicebook_destroy, 1929). +-define(wxToolbook_new_0, 1930). +-define(wxToolbook_new_3, 1931). +-define(wxToolbook_AddPage, 1932). +-define(wxToolbook_AdvanceSelection, 1933). +-define(wxToolbook_AssignImageList, 1934). +-define(wxToolbook_Create, 1935). +-define(wxToolbook_DeleteAllPages, 1936). +-define(wxToolbook_DeletePage, 1937). +-define(wxToolbook_RemovePage, 1938). +-define(wxToolbook_GetCurrentPage, 1939). +-define(wxToolbook_GetImageList, 1940). +-define(wxToolbook_GetPage, 1942). +-define(wxToolbook_GetPageCount, 1943). +-define(wxToolbook_GetPageImage, 1944). +-define(wxToolbook_GetPageText, 1945). +-define(wxToolbook_GetSelection, 1946). +-define(wxToolbook_HitTest, 1948). +-define(wxToolbook_InsertPage, 1949). +-define(wxToolbook_SetImageList, 1950). +-define(wxToolbook_SetPageSize, 1951). +-define(wxToolbook_SetPageImage, 1952). +-define(wxToolbook_SetPageText, 1953). +-define(wxToolbook_SetSelection, 1954). +-define(wxToolbook_ChangeSelection, 1955). +-define(wxToolbook_destroy, 1956). +-define(wxListbook_new_0, 1957). +-define(wxListbook_new_3, 1958). +-define(wxListbook_AddPage, 1959). +-define(wxListbook_AdvanceSelection, 1960). +-define(wxListbook_AssignImageList, 1961). +-define(wxListbook_Create, 1962). +-define(wxListbook_DeleteAllPages, 1963). +-define(wxListbook_DeletePage, 1964). +-define(wxListbook_RemovePage, 1965). +-define(wxListbook_GetCurrentPage, 1966). +-define(wxListbook_GetImageList, 1967). +-define(wxListbook_GetPage, 1969). +-define(wxListbook_GetPageCount, 1970). +-define(wxListbook_GetPageImage, 1971). +-define(wxListbook_GetPageText, 1972). +-define(wxListbook_GetSelection, 1973). +-define(wxListbook_HitTest, 1975). +-define(wxListbook_InsertPage, 1976). +-define(wxListbook_SetImageList, 1977). +-define(wxListbook_SetPageSize, 1978). +-define(wxListbook_SetPageImage, 1979). +-define(wxListbook_SetPageText, 1980). +-define(wxListbook_SetSelection, 1981). +-define(wxListbook_ChangeSelection, 1982). +-define(wxListbook_destroy, 1983). +-define(wxTreebook_new_0, 1984). +-define(wxTreebook_new_3, 1985). +-define(wxTreebook_AddPage, 1986). +-define(wxTreebook_AdvanceSelection, 1987). +-define(wxTreebook_AssignImageList, 1988). +-define(wxTreebook_Create, 1989). +-define(wxTreebook_DeleteAllPages, 1990). +-define(wxTreebook_DeletePage, 1991). +-define(wxTreebook_RemovePage, 1992). +-define(wxTreebook_GetCurrentPage, 1993). +-define(wxTreebook_GetImageList, 1994). +-define(wxTreebook_GetPage, 1996). +-define(wxTreebook_GetPageCount, 1997). +-define(wxTreebook_GetPageImage, 1998). +-define(wxTreebook_GetPageText, 1999). +-define(wxTreebook_GetSelection, 2000). +-define(wxTreebook_ExpandNode, 2001). +-define(wxTreebook_IsNodeExpanded, 2002). +-define(wxTreebook_HitTest, 2004). +-define(wxTreebook_InsertPage, 2005). +-define(wxTreebook_InsertSubPage, 2006). +-define(wxTreebook_SetImageList, 2007). +-define(wxTreebook_SetPageSize, 2008). +-define(wxTreebook_SetPageImage, 2009). +-define(wxTreebook_SetPageText, 2010). +-define(wxTreebook_SetSelection, 2011). +-define(wxTreebook_ChangeSelection, 2012). +-define(wxTreebook_destroy, 2013). +-define(wxTreeCtrl_new_2, 2016). +-define(wxTreeCtrl_new_0, 2017). +-define(wxTreeCtrl_destruct, 2019). +-define(wxTreeCtrl_AddRoot, 2020). +-define(wxTreeCtrl_AppendItem, 2021). +-define(wxTreeCtrl_AssignImageList, 2022). +-define(wxTreeCtrl_AssignStateImageList, 2023). +-define(wxTreeCtrl_Collapse, 2024). +-define(wxTreeCtrl_CollapseAndReset, 2025). +-define(wxTreeCtrl_Create, 2026). +-define(wxTreeCtrl_Delete, 2027). +-define(wxTreeCtrl_DeleteAllItems, 2028). +-define(wxTreeCtrl_DeleteChildren, 2029). +-define(wxTreeCtrl_EditLabel, 2030). +-define(wxTreeCtrl_EnsureVisible, 2031). +-define(wxTreeCtrl_Expand, 2032). +-define(wxTreeCtrl_GetBoundingRect, 2033). +-define(wxTreeCtrl_GetChildrenCount, 2035). +-define(wxTreeCtrl_GetCount, 2036). +-define(wxTreeCtrl_GetEditControl, 2037). +-define(wxTreeCtrl_GetFirstChild, 2038). +-define(wxTreeCtrl_GetNextChild, 2039). +-define(wxTreeCtrl_GetFirstVisibleItem, 2040). +-define(wxTreeCtrl_GetImageList, 2041). +-define(wxTreeCtrl_GetIndent, 2042). +-define(wxTreeCtrl_GetItemBackgroundColour, 2043). +-define(wxTreeCtrl_GetItemData, 2044). +-define(wxTreeCtrl_GetItemFont, 2045). +-define(wxTreeCtrl_GetItemImage_1, 2046). +-define(wxTreeCtrl_GetItemImage_2, 2047). +-define(wxTreeCtrl_GetItemText, 2048). +-define(wxTreeCtrl_GetItemTextColour, 2049). +-define(wxTreeCtrl_GetLastChild, 2050). +-define(wxTreeCtrl_GetNextSibling, 2051). +-define(wxTreeCtrl_GetNextVisible, 2052). +-define(wxTreeCtrl_GetItemParent, 2053). +-define(wxTreeCtrl_GetPrevSibling, 2054). +-define(wxTreeCtrl_GetPrevVisible, 2055). +-define(wxTreeCtrl_GetRootItem, 2056). +-define(wxTreeCtrl_GetSelection, 2057). +-define(wxTreeCtrl_GetSelections, 2058). +-define(wxTreeCtrl_GetStateImageList, 2059). +-define(wxTreeCtrl_HitTest, 2060). +-define(wxTreeCtrl_InsertItem, 2062). +-define(wxTreeCtrl_IsBold, 2063). +-define(wxTreeCtrl_IsExpanded, 2064). +-define(wxTreeCtrl_IsSelected, 2065). +-define(wxTreeCtrl_IsVisible, 2066). +-define(wxTreeCtrl_ItemHasChildren, 2067). +-define(wxTreeCtrl_IsTreeItemIdOk, 2068). +-define(wxTreeCtrl_PrependItem, 2069). +-define(wxTreeCtrl_ScrollTo, 2070). +-define(wxTreeCtrl_SelectItem_1, 2071). +-define(wxTreeCtrl_SelectItem_2, 2072). +-define(wxTreeCtrl_SetIndent, 2073). +-define(wxTreeCtrl_SetImageList, 2074). +-define(wxTreeCtrl_SetItemBackgroundColour, 2075). +-define(wxTreeCtrl_SetItemBold, 2076). +-define(wxTreeCtrl_SetItemData, 2077). +-define(wxTreeCtrl_SetItemDropHighlight, 2078). +-define(wxTreeCtrl_SetItemFont, 2079). +-define(wxTreeCtrl_SetItemHasChildren, 2080). +-define(wxTreeCtrl_SetItemImage_2, 2081). +-define(wxTreeCtrl_SetItemImage_3, 2082). +-define(wxTreeCtrl_SetItemText, 2083). +-define(wxTreeCtrl_SetItemTextColour, 2084). +-define(wxTreeCtrl_SetStateImageList, 2085). +-define(wxTreeCtrl_SetWindowStyle, 2086). +-define(wxTreeCtrl_SortChildren, 2087). +-define(wxTreeCtrl_Toggle, 2088). +-define(wxTreeCtrl_ToggleItemSelection, 2089). +-define(wxTreeCtrl_Unselect, 2090). +-define(wxTreeCtrl_UnselectAll, 2091). +-define(wxTreeCtrl_UnselectItem, 2092). +-define(wxScrollBar_new_0, 2093). +-define(wxScrollBar_new_3, 2094). +-define(wxScrollBar_destruct, 2095). +-define(wxScrollBar_Create, 2096). +-define(wxScrollBar_GetRange, 2097). +-define(wxScrollBar_GetPageSize, 2098). +-define(wxScrollBar_GetThumbPosition, 2099). +-define(wxScrollBar_GetThumbSize, 2100). +-define(wxScrollBar_SetThumbPosition, 2101). +-define(wxScrollBar_SetScrollbar, 2102). +-define(wxSpinButton_new_2, 2104). +-define(wxSpinButton_new_0, 2105). +-define(wxSpinButton_Create, 2106). +-define(wxSpinButton_GetMax, 2107). +-define(wxSpinButton_GetMin, 2108). +-define(wxSpinButton_GetValue, 2109). +-define(wxSpinButton_SetRange, 2110). +-define(wxSpinButton_SetValue, 2111). +-define(wxSpinButton_destroy, 2112). +-define(wxSpinCtrl_new_0, 2113). +-define(wxSpinCtrl_new_2, 2114). +-define(wxSpinCtrl_Create, 2116). +-define(wxSpinCtrl_SetValue_1_1, 2119). +-define(wxSpinCtrl_SetValue_1_0, 2120). +-define(wxSpinCtrl_GetValue, 2122). +-define(wxSpinCtrl_SetRange, 2124). +-define(wxSpinCtrl_SetSelection, 2125). +-define(wxSpinCtrl_GetMin, 2127). +-define(wxSpinCtrl_GetMax, 2129). +-define(wxSpinCtrl_destroy, 2130). +-define(wxStaticText_new_0, 2131). +-define(wxStaticText_new_4, 2132). +-define(wxStaticText_Create, 2133). +-define(wxStaticText_GetLabel, 2134). +-define(wxStaticText_SetLabel, 2135). +-define(wxStaticText_Wrap, 2136). +-define(wxStaticText_destroy, 2137). +-define(wxStaticBitmap_new_0, 2138). +-define(wxStaticBitmap_new_4, 2139). +-define(wxStaticBitmap_Create, 2140). +-define(wxStaticBitmap_GetBitmap, 2141). +-define(wxStaticBitmap_SetBitmap, 2142). +-define(wxStaticBitmap_destroy, 2143). +-define(wxRadioBox_new, 2144). +-define(wxRadioBox_destruct, 2146). +-define(wxRadioBox_Create, 2147). +-define(wxRadioBox_Enable_2, 2148). +-define(wxRadioBox_Enable_1, 2149). +-define(wxRadioBox_GetSelection, 2150). +-define(wxRadioBox_GetString, 2151). +-define(wxRadioBox_SetSelection, 2152). +-define(wxRadioBox_Show_2, 2153). +-define(wxRadioBox_Show_1, 2154). +-define(wxRadioBox_GetColumnCount, 2155). +-define(wxRadioBox_GetItemHelpText, 2156). +-define(wxRadioBox_GetItemToolTip, 2157). +-define(wxRadioBox_GetItemFromPoint, 2159). +-define(wxRadioBox_GetRowCount, 2160). +-define(wxRadioBox_IsItemEnabled, 2161). +-define(wxRadioBox_IsItemShown, 2162). +-define(wxRadioBox_SetItemHelpText, 2163). +-define(wxRadioBox_SetItemToolTip, 2164). +-define(wxRadioButton_new_0, 2165). +-define(wxRadioButton_new_4, 2166). +-define(wxRadioButton_Create, 2167). +-define(wxRadioButton_GetValue, 2168). +-define(wxRadioButton_SetValue, 2169). +-define(wxRadioButton_destroy, 2170). +-define(wxSlider_new_6, 2172). +-define(wxSlider_new_0, 2173). +-define(wxSlider_Create, 2174). +-define(wxSlider_GetLineSize, 2175). +-define(wxSlider_GetMax, 2176). +-define(wxSlider_GetMin, 2177). +-define(wxSlider_GetPageSize, 2178). +-define(wxSlider_GetThumbLength, 2179). +-define(wxSlider_GetValue, 2180). +-define(wxSlider_SetLineSize, 2181). +-define(wxSlider_SetPageSize, 2182). +-define(wxSlider_SetRange, 2183). +-define(wxSlider_SetThumbLength, 2184). +-define(wxSlider_SetValue, 2185). +-define(wxSlider_destroy, 2186). +-define(wxDialog_new_4, 2188). +-define(wxDialog_new_0, 2189). +-define(wxDialog_destruct, 2191). +-define(wxDialog_Create, 2192). +-define(wxDialog_CreateButtonSizer, 2193). +-define(wxDialog_CreateStdDialogButtonSizer, 2194). +-define(wxDialog_EndModal, 2195). +-define(wxDialog_GetAffirmativeId, 2196). +-define(wxDialog_GetReturnCode, 2197). +-define(wxDialog_IsModal, 2198). +-define(wxDialog_SetAffirmativeId, 2199). +-define(wxDialog_SetReturnCode, 2200). +-define(wxDialog_Show, 2201). +-define(wxDialog_ShowModal, 2202). +-define(wxColourDialog_new_0, 2203). +-define(wxColourDialog_new_2, 2204). +-define(wxColourDialog_destruct, 2205). +-define(wxColourDialog_Create, 2206). +-define(wxColourDialog_GetColourData, 2207). +-define(wxColourData_new_0, 2208). +-define(wxColourData_new_1, 2209). +-define(wxColourData_destruct, 2210). +-define(wxColourData_GetChooseFull, 2211). +-define(wxColourData_GetColour, 2212). +-define(wxColourData_GetCustomColour, 2214). +-define(wxColourData_SetChooseFull, 2215). +-define(wxColourData_SetColour, 2216). +-define(wxColourData_SetCustomColour, 2217). +-define(wxPalette_new_0, 2218). +-define(wxPalette_new_4, 2219). +-define(wxPalette_destruct, 2221). +-define(wxPalette_Create, 2222). +-define(wxPalette_GetColoursCount, 2223). +-define(wxPalette_GetPixel, 2224). +-define(wxPalette_GetRGB, 2225). +-define(wxPalette_IsOk, 2226). +-define(wxDirDialog_new, 2230). +-define(wxDirDialog_destruct, 2231). +-define(wxDirDialog_GetPath, 2232). +-define(wxDirDialog_GetMessage, 2233). +-define(wxDirDialog_SetMessage, 2234). +-define(wxDirDialog_SetPath, 2235). +-define(wxFileDialog_new, 2239). +-define(wxFileDialog_destruct, 2240). +-define(wxFileDialog_GetDirectory, 2241). +-define(wxFileDialog_GetFilename, 2242). +-define(wxFileDialog_GetFilenames, 2243). +-define(wxFileDialog_GetFilterIndex, 2244). +-define(wxFileDialog_GetMessage, 2245). +-define(wxFileDialog_GetPath, 2246). +-define(wxFileDialog_GetPaths, 2247). +-define(wxFileDialog_GetWildcard, 2248). +-define(wxFileDialog_SetDirectory, 2249). +-define(wxFileDialog_SetFilename, 2250). +-define(wxFileDialog_SetFilterIndex, 2251). +-define(wxFileDialog_SetMessage, 2252). +-define(wxFileDialog_SetPath, 2253). +-define(wxFileDialog_SetWildcard, 2254). +-define(wxPickerBase_SetInternalMargin, 2255). +-define(wxPickerBase_GetInternalMargin, 2256). +-define(wxPickerBase_SetTextCtrlProportion, 2257). +-define(wxPickerBase_SetPickerCtrlProportion, 2258). +-define(wxPickerBase_GetTextCtrlProportion, 2259). +-define(wxPickerBase_GetPickerCtrlProportion, 2260). +-define(wxPickerBase_HasTextCtrl, 2261). +-define(wxPickerBase_GetTextCtrl, 2262). +-define(wxPickerBase_IsTextCtrlGrowable, 2263). +-define(wxPickerBase_SetPickerCtrlGrowable, 2264). +-define(wxPickerBase_SetTextCtrlGrowable, 2265). +-define(wxPickerBase_IsPickerCtrlGrowable, 2266). +-define(wxFilePickerCtrl_new_0, 2267). +-define(wxFilePickerCtrl_new_3, 2268). +-define(wxFilePickerCtrl_Create, 2269). +-define(wxFilePickerCtrl_GetPath, 2270). +-define(wxFilePickerCtrl_SetPath, 2271). +-define(wxFilePickerCtrl_destroy, 2272). +-define(wxDirPickerCtrl_new_0, 2273). +-define(wxDirPickerCtrl_new_3, 2274). +-define(wxDirPickerCtrl_Create, 2275). +-define(wxDirPickerCtrl_GetPath, 2276). +-define(wxDirPickerCtrl_SetPath, 2277). +-define(wxDirPickerCtrl_destroy, 2278). +-define(wxColourPickerCtrl_new_0, 2279). +-define(wxColourPickerCtrl_new_3, 2280). +-define(wxColourPickerCtrl_Create, 2281). +-define(wxColourPickerCtrl_GetColour, 2282). +-define(wxColourPickerCtrl_SetColour_1_1, 2283). +-define(wxColourPickerCtrl_SetColour_1_0, 2284). +-define(wxColourPickerCtrl_destroy, 2285). +-define(wxDatePickerCtrl_new_0, 2286). +-define(wxDatePickerCtrl_new_3, 2287). +-define(wxDatePickerCtrl_GetRange, 2288). +-define(wxDatePickerCtrl_GetValue, 2289). +-define(wxDatePickerCtrl_SetRange, 2290). +-define(wxDatePickerCtrl_SetValue, 2291). +-define(wxDatePickerCtrl_destroy, 2292). +-define(wxFontPickerCtrl_new_0, 2293). +-define(wxFontPickerCtrl_new_3, 2294). +-define(wxFontPickerCtrl_Create, 2295). +-define(wxFontPickerCtrl_GetSelectedFont, 2296). +-define(wxFontPickerCtrl_SetSelectedFont, 2297). +-define(wxFontPickerCtrl_GetMaxPointSize, 2298). +-define(wxFontPickerCtrl_SetMaxPointSize, 2299). +-define(wxFontPickerCtrl_destroy, 2300). +-define(wxFindReplaceDialog_new_0, 2303). +-define(wxFindReplaceDialog_new_4, 2304). +-define(wxFindReplaceDialog_destruct, 2305). +-define(wxFindReplaceDialog_Create, 2306). +-define(wxFindReplaceDialog_GetData, 2307). +-define(wxFindReplaceData_new_0, 2308). +-define(wxFindReplaceData_new_1, 2309). +-define(wxFindReplaceData_GetFindString, 2310). +-define(wxFindReplaceData_GetReplaceString, 2311). +-define(wxFindReplaceData_GetFlags, 2312). +-define(wxFindReplaceData_SetFlags, 2313). +-define(wxFindReplaceData_SetFindString, 2314). +-define(wxFindReplaceData_SetReplaceString, 2315). +-define(wxFindReplaceData_destroy, 2316). +-define(wxMultiChoiceDialog_new_0, 2317). +-define(wxMultiChoiceDialog_new_5, 2319). +-define(wxMultiChoiceDialog_GetSelections, 2320). +-define(wxMultiChoiceDialog_SetSelections, 2321). +-define(wxMultiChoiceDialog_destroy, 2322). +-define(wxSingleChoiceDialog_new_0, 2323). +-define(wxSingleChoiceDialog_new_5, 2325). +-define(wxSingleChoiceDialog_GetSelection, 2326). +-define(wxSingleChoiceDialog_GetStringSelection, 2327). +-define(wxSingleChoiceDialog_SetSelection, 2328). +-define(wxSingleChoiceDialog_destroy, 2329). +-define(wxTextEntryDialog_new, 2330). +-define(wxTextEntryDialog_GetValue, 2331). +-define(wxTextEntryDialog_SetValue, 2332). +-define(wxTextEntryDialog_destroy, 2333). +-define(wxPasswordEntryDialog_new, 2334). +-define(wxPasswordEntryDialog_destroy, 2335). +-define(wxFontData_new_0, 2336). +-define(wxFontData_new_1, 2337). +-define(wxFontData_destruct, 2338). +-define(wxFontData_EnableEffects, 2339). +-define(wxFontData_GetAllowSymbols, 2340). +-define(wxFontData_GetColour, 2341). +-define(wxFontData_GetChosenFont, 2342). +-define(wxFontData_GetEnableEffects, 2343). +-define(wxFontData_GetInitialFont, 2344). +-define(wxFontData_GetShowHelp, 2345). +-define(wxFontData_SetAllowSymbols, 2346). +-define(wxFontData_SetChosenFont, 2347). +-define(wxFontData_SetColour, 2348). +-define(wxFontData_SetInitialFont, 2349). +-define(wxFontData_SetRange, 2350). +-define(wxFontData_SetShowHelp, 2351). +-define(wxFontDialog_new_0, 2355). +-define(wxFontDialog_new_2, 2357). +-define(wxFontDialog_Create, 2359). +-define(wxFontDialog_GetFontData, 2360). +-define(wxFontDialog_destroy, 2362). +-define(wxProgressDialog_new, 2363). +-define(wxProgressDialog_destruct, 2364). +-define(wxProgressDialog_Resume, 2365). +-define(wxProgressDialog_Update_2, 2366). +-define(wxProgressDialog_Update_0, 2367). +-define(wxMessageDialog_new, 2368). +-define(wxMessageDialog_destruct, 2369). +-define(wxPageSetupDialog_new, 2370). +-define(wxPageSetupDialog_destruct, 2371). +-define(wxPageSetupDialog_GetPageSetupData, 2372). +-define(wxPageSetupDialog_ShowModal, 2373). +-define(wxPageSetupDialogData_new_0, 2374). +-define(wxPageSetupDialogData_new_1_0, 2375). +-define(wxPageSetupDialogData_new_1_1, 2376). +-define(wxPageSetupDialogData_destruct, 2377). +-define(wxPageSetupDialogData_EnableHelp, 2378). +-define(wxPageSetupDialogData_EnableMargins, 2379). +-define(wxPageSetupDialogData_EnableOrientation, 2380). +-define(wxPageSetupDialogData_EnablePaper, 2381). +-define(wxPageSetupDialogData_EnablePrinter, 2382). +-define(wxPageSetupDialogData_GetDefaultMinMargins, 2383). +-define(wxPageSetupDialogData_GetEnableMargins, 2384). +-define(wxPageSetupDialogData_GetEnableOrientation, 2385). +-define(wxPageSetupDialogData_GetEnablePaper, 2386). +-define(wxPageSetupDialogData_GetEnablePrinter, 2387). +-define(wxPageSetupDialogData_GetEnableHelp, 2388). +-define(wxPageSetupDialogData_GetDefaultInfo, 2389). +-define(wxPageSetupDialogData_GetMarginTopLeft, 2390). +-define(wxPageSetupDialogData_GetMarginBottomRight, 2391). +-define(wxPageSetupDialogData_GetMinMarginTopLeft, 2392). +-define(wxPageSetupDialogData_GetMinMarginBottomRight, 2393). +-define(wxPageSetupDialogData_GetPaperId, 2394). +-define(wxPageSetupDialogData_GetPaperSize, 2395). +-define(wxPageSetupDialogData_GetPrintData, 2397). +-define(wxPageSetupDialogData_IsOk, 2398). +-define(wxPageSetupDialogData_SetDefaultInfo, 2399). +-define(wxPageSetupDialogData_SetDefaultMinMargins, 2400). +-define(wxPageSetupDialogData_SetMarginTopLeft, 2401). +-define(wxPageSetupDialogData_SetMarginBottomRight, 2402). +-define(wxPageSetupDialogData_SetMinMarginTopLeft, 2403). +-define(wxPageSetupDialogData_SetMinMarginBottomRight, 2404). +-define(wxPageSetupDialogData_SetPaperId, 2405). +-define(wxPageSetupDialogData_SetPaperSize_1_1, 2406). +-define(wxPageSetupDialogData_SetPaperSize_1_0, 2407). +-define(wxPageSetupDialogData_SetPrintData, 2408). +-define(wxPrintDialog_new_2_0, 2409). +-define(wxPrintDialog_new_2_1, 2410). +-define(wxPrintDialog_destruct, 2411). +-define(wxPrintDialog_GetPrintDialogData, 2412). +-define(wxPrintDialog_GetPrintDC, 2413). +-define(wxPrintDialogData_new_0, 2414). +-define(wxPrintDialogData_new_1_1, 2415). +-define(wxPrintDialogData_new_1_0, 2416). +-define(wxPrintDialogData_destruct, 2417). +-define(wxPrintDialogData_EnableHelp, 2418). +-define(wxPrintDialogData_EnablePageNumbers, 2419). +-define(wxPrintDialogData_EnablePrintToFile, 2420). +-define(wxPrintDialogData_EnableSelection, 2421). +-define(wxPrintDialogData_GetAllPages, 2422). +-define(wxPrintDialogData_GetCollate, 2423). +-define(wxPrintDialogData_GetFromPage, 2424). +-define(wxPrintDialogData_GetMaxPage, 2425). +-define(wxPrintDialogData_GetMinPage, 2426). +-define(wxPrintDialogData_GetNoCopies, 2427). +-define(wxPrintDialogData_GetPrintData, 2428). +-define(wxPrintDialogData_GetPrintToFile, 2429). +-define(wxPrintDialogData_GetSelection, 2430). +-define(wxPrintDialogData_GetToPage, 2431). +-define(wxPrintDialogData_IsOk, 2432). +-define(wxPrintDialogData_SetCollate, 2433). +-define(wxPrintDialogData_SetFromPage, 2434). +-define(wxPrintDialogData_SetMaxPage, 2435). +-define(wxPrintDialogData_SetMinPage, 2436). +-define(wxPrintDialogData_SetNoCopies, 2437). +-define(wxPrintDialogData_SetPrintData, 2438). +-define(wxPrintDialogData_SetPrintToFile, 2439). +-define(wxPrintDialogData_SetSelection, 2440). +-define(wxPrintDialogData_SetToPage, 2441). +-define(wxPrintData_new_0, 2442). +-define(wxPrintData_new_1, 2443). +-define(wxPrintData_destruct, 2444). +-define(wxPrintData_GetCollate, 2445). +-define(wxPrintData_GetBin, 2446). +-define(wxPrintData_GetColour, 2447). +-define(wxPrintData_GetDuplex, 2448). +-define(wxPrintData_GetNoCopies, 2449). +-define(wxPrintData_GetOrientation, 2450). +-define(wxPrintData_GetPaperId, 2451). +-define(wxPrintData_GetPrinterName, 2452). +-define(wxPrintData_GetQuality, 2453). +-define(wxPrintData_IsOk, 2454). +-define(wxPrintData_SetBin, 2455). +-define(wxPrintData_SetCollate, 2456). +-define(wxPrintData_SetColour, 2457). +-define(wxPrintData_SetDuplex, 2458). +-define(wxPrintData_SetNoCopies, 2459). +-define(wxPrintData_SetOrientation, 2460). +-define(wxPrintData_SetPaperId, 2461). +-define(wxPrintData_SetPrinterName, 2462). +-define(wxPrintData_SetQuality, 2463). +-define(wxPrintPreview_new_2, 2466). +-define(wxPrintPreview_new_3, 2467). +-define(wxPrintPreview_destruct, 2469). +-define(wxPrintPreview_GetCanvas, 2470). +-define(wxPrintPreview_GetCurrentPage, 2471). +-define(wxPrintPreview_GetFrame, 2472). +-define(wxPrintPreview_GetMaxPage, 2473). +-define(wxPrintPreview_GetMinPage, 2474). +-define(wxPrintPreview_GetPrintout, 2475). +-define(wxPrintPreview_GetPrintoutForPrinting, 2476). +-define(wxPrintPreview_IsOk, 2477). +-define(wxPrintPreview_PaintPage, 2478). +-define(wxPrintPreview_Print, 2479). +-define(wxPrintPreview_RenderPage, 2480). +-define(wxPrintPreview_SetCanvas, 2481). +-define(wxPrintPreview_SetCurrentPage, 2482). +-define(wxPrintPreview_SetFrame, 2483). +-define(wxPrintPreview_SetPrintout, 2484). +-define(wxPrintPreview_SetZoom, 2485). +-define(wxPreviewFrame_new, 2486). +-define(wxPreviewFrame_destruct, 2487). +-define(wxPreviewFrame_CreateControlBar, 2488). +-define(wxPreviewFrame_CreateCanvas, 2489). +-define(wxPreviewFrame_Initialize, 2490). +-define(wxPreviewFrame_OnCloseWindow, 2491). +-define(wxPreviewControlBar_new, 2492). +-define(wxPreviewControlBar_destruct, 2493). +-define(wxPreviewControlBar_CreateButtons, 2494). +-define(wxPreviewControlBar_GetPrintPreview, 2495). +-define(wxPreviewControlBar_GetZoomControl, 2496). +-define(wxPreviewControlBar_SetZoomControl, 2497). +-define(wxPrinter_new, 2499). +-define(wxPrinter_CreateAbortWindow, 2500). +-define(wxPrinter_GetAbort, 2501). +-define(wxPrinter_GetLastError, 2502). +-define(wxPrinter_GetPrintDialogData, 2503). +-define(wxPrinter_Print, 2504). +-define(wxPrinter_PrintDialog, 2505). +-define(wxPrinter_ReportError, 2506). +-define(wxPrinter_Setup, 2507). +-define(wxPrinter_destroy, 2508). +-define(wxXmlResource_new_1, 2509). +-define(wxXmlResource_new_2, 2510). +-define(wxXmlResource_destruct, 2511). +-define(wxXmlResource_AttachUnknownControl, 2512). +-define(wxXmlResource_ClearHandlers, 2513). +-define(wxXmlResource_CompareVersion, 2514). +-define(wxXmlResource_Get, 2515). +-define(wxXmlResource_GetFlags, 2516). +-define(wxXmlResource_GetVersion, 2517). +-define(wxXmlResource_GetXRCID, 2518). +-define(wxXmlResource_InitAllHandlers, 2519). +-define(wxXmlResource_Load, 2520). +-define(wxXmlResource_LoadBitmap, 2521). +-define(wxXmlResource_LoadDialog_2, 2522). +-define(wxXmlResource_LoadDialog_3, 2523). +-define(wxXmlResource_LoadFrame_2, 2524). +-define(wxXmlResource_LoadFrame_3, 2525). +-define(wxXmlResource_LoadIcon, 2526). +-define(wxXmlResource_LoadMenu, 2527). +-define(wxXmlResource_LoadMenuBar_2, 2528). +-define(wxXmlResource_LoadMenuBar_1, 2529). +-define(wxXmlResource_LoadPanel_2, 2530). +-define(wxXmlResource_LoadPanel_3, 2531). +-define(wxXmlResource_LoadToolBar, 2532). +-define(wxXmlResource_Set, 2533). +-define(wxXmlResource_SetFlags, 2534). +-define(wxXmlResource_Unload, 2535). +-define(wxXmlResource_xrcctrl, 2536). +-define(wxHtmlEasyPrinting_new, 2537). +-define(wxHtmlEasyPrinting_destruct, 2538). +-define(wxHtmlEasyPrinting_GetPrintData, 2539). +-define(wxHtmlEasyPrinting_GetPageSetupData, 2540). +-define(wxHtmlEasyPrinting_PreviewFile, 2541). +-define(wxHtmlEasyPrinting_PreviewText, 2542). +-define(wxHtmlEasyPrinting_PrintFile, 2543). +-define(wxHtmlEasyPrinting_PrintText, 2544). +-define(wxHtmlEasyPrinting_PageSetup, 2545). +-define(wxHtmlEasyPrinting_SetFonts, 2546). +-define(wxHtmlEasyPrinting_SetHeader, 2547). +-define(wxHtmlEasyPrinting_SetFooter, 2548). +-define(wxGLCanvas_new_2, 2550). +-define(wxGLCanvas_new_3_1, 2551). +-define(wxGLCanvas_new_3_0, 2552). +-define(wxGLCanvas_GetContext, 2553). +-define(wxGLCanvas_SetCurrent, 2555). +-define(wxGLCanvas_SwapBuffers, 2556). +-define(wxGLCanvas_destroy, 2557). +-define(wxAuiManager_new, 2558). +-define(wxAuiManager_destruct, 2559). +-define(wxAuiManager_AddPane_2_1, 2560). +-define(wxAuiManager_AddPane_3, 2561). +-define(wxAuiManager_AddPane_2_0, 2562). +-define(wxAuiManager_DetachPane, 2563). +-define(wxAuiManager_GetAllPanes, 2564). +-define(wxAuiManager_GetArtProvider, 2565). +-define(wxAuiManager_GetDockSizeConstraint, 2566). +-define(wxAuiManager_GetFlags, 2567). +-define(wxAuiManager_GetManagedWindow, 2568). +-define(wxAuiManager_GetManager, 2569). +-define(wxAuiManager_GetPane_1_1, 2570). +-define(wxAuiManager_GetPane_1_0, 2571). +-define(wxAuiManager_HideHint, 2572). +-define(wxAuiManager_InsertPane, 2573). +-define(wxAuiManager_LoadPaneInfo, 2574). +-define(wxAuiManager_LoadPerspective, 2575). +-define(wxAuiManager_SavePaneInfo, 2576). +-define(wxAuiManager_SavePerspective, 2577). +-define(wxAuiManager_SetArtProvider, 2578). +-define(wxAuiManager_SetDockSizeConstraint, 2579). +-define(wxAuiManager_SetFlags, 2580). +-define(wxAuiManager_SetManagedWindow, 2581). +-define(wxAuiManager_ShowHint, 2582). +-define(wxAuiManager_UnInit, 2583). +-define(wxAuiManager_Update, 2584). +-define(wxAuiPaneInfo_new_0, 2585). +-define(wxAuiPaneInfo_new_1, 2586). +-define(wxAuiPaneInfo_destruct, 2587). +-define(wxAuiPaneInfo_BestSize_1, 2588). +-define(wxAuiPaneInfo_BestSize_2, 2589). +-define(wxAuiPaneInfo_Bottom, 2590). +-define(wxAuiPaneInfo_BottomDockable, 2591). +-define(wxAuiPaneInfo_Caption, 2592). +-define(wxAuiPaneInfo_CaptionVisible, 2593). +-define(wxAuiPaneInfo_Centre, 2594). +-define(wxAuiPaneInfo_CentrePane, 2595). +-define(wxAuiPaneInfo_CloseButton, 2596). +-define(wxAuiPaneInfo_DefaultPane, 2597). +-define(wxAuiPaneInfo_DestroyOnClose, 2598). +-define(wxAuiPaneInfo_Direction, 2599). +-define(wxAuiPaneInfo_Dock, 2600). +-define(wxAuiPaneInfo_Dockable, 2601). +-define(wxAuiPaneInfo_Fixed, 2602). +-define(wxAuiPaneInfo_Float, 2603). +-define(wxAuiPaneInfo_Floatable, 2604). +-define(wxAuiPaneInfo_FloatingPosition_1, 2605). +-define(wxAuiPaneInfo_FloatingPosition_2, 2606). +-define(wxAuiPaneInfo_FloatingSize_1, 2607). +-define(wxAuiPaneInfo_FloatingSize_2, 2608). +-define(wxAuiPaneInfo_Gripper, 2609). +-define(wxAuiPaneInfo_GripperTop, 2610). +-define(wxAuiPaneInfo_HasBorder, 2611). +-define(wxAuiPaneInfo_HasCaption, 2612). +-define(wxAuiPaneInfo_HasCloseButton, 2613). +-define(wxAuiPaneInfo_HasFlag, 2614). +-define(wxAuiPaneInfo_HasGripper, 2615). +-define(wxAuiPaneInfo_HasGripperTop, 2616). +-define(wxAuiPaneInfo_HasMaximizeButton, 2617). +-define(wxAuiPaneInfo_HasMinimizeButton, 2618). +-define(wxAuiPaneInfo_HasPinButton, 2619). +-define(wxAuiPaneInfo_Hide, 2620). +-define(wxAuiPaneInfo_IsBottomDockable, 2621). +-define(wxAuiPaneInfo_IsDocked, 2622). +-define(wxAuiPaneInfo_IsFixed, 2623). +-define(wxAuiPaneInfo_IsFloatable, 2624). +-define(wxAuiPaneInfo_IsFloating, 2625). +-define(wxAuiPaneInfo_IsLeftDockable, 2626). +-define(wxAuiPaneInfo_IsMovable, 2627). +-define(wxAuiPaneInfo_IsOk, 2628). +-define(wxAuiPaneInfo_IsResizable, 2629). +-define(wxAuiPaneInfo_IsRightDockable, 2630). +-define(wxAuiPaneInfo_IsShown, 2631). +-define(wxAuiPaneInfo_IsToolbar, 2632). +-define(wxAuiPaneInfo_IsTopDockable, 2633). +-define(wxAuiPaneInfo_Layer, 2634). +-define(wxAuiPaneInfo_Left, 2635). +-define(wxAuiPaneInfo_LeftDockable, 2636). +-define(wxAuiPaneInfo_MaxSize_1, 2637). +-define(wxAuiPaneInfo_MaxSize_2, 2638). +-define(wxAuiPaneInfo_MaximizeButton, 2639). +-define(wxAuiPaneInfo_MinSize_1, 2640). +-define(wxAuiPaneInfo_MinSize_2, 2641). +-define(wxAuiPaneInfo_MinimizeButton, 2642). +-define(wxAuiPaneInfo_Movable, 2643). +-define(wxAuiPaneInfo_Name, 2644). +-define(wxAuiPaneInfo_PaneBorder, 2645). +-define(wxAuiPaneInfo_PinButton, 2646). +-define(wxAuiPaneInfo_Position, 2647). +-define(wxAuiPaneInfo_Resizable, 2648). +-define(wxAuiPaneInfo_Right, 2649). +-define(wxAuiPaneInfo_RightDockable, 2650). +-define(wxAuiPaneInfo_Row, 2651). +-define(wxAuiPaneInfo_SafeSet, 2652). +-define(wxAuiPaneInfo_SetFlag, 2653). +-define(wxAuiPaneInfo_Show, 2654). +-define(wxAuiPaneInfo_ToolbarPane, 2655). +-define(wxAuiPaneInfo_Top, 2656). +-define(wxAuiPaneInfo_TopDockable, 2657). +-define(wxAuiPaneInfo_Window, 2658). +-define(wxAuiPaneInfo_GetWindow, 2659). +-define(wxAuiPaneInfo_GetFrame, 2660). +-define(wxAuiPaneInfo_GetDirection, 2661). +-define(wxAuiPaneInfo_GetLayer, 2662). +-define(wxAuiPaneInfo_GetRow, 2663). +-define(wxAuiPaneInfo_GetPosition, 2664). +-define(wxAuiPaneInfo_GetFloatingPosition, 2665). +-define(wxAuiPaneInfo_GetFloatingSize, 2666). +-define(wxAuiNotebook_new_0, 2667). +-define(wxAuiNotebook_new_2, 2668). +-define(wxAuiNotebook_AddPage, 2669). +-define(wxAuiNotebook_Create, 2670). +-define(wxAuiNotebook_DeletePage, 2671). +-define(wxAuiNotebook_GetArtProvider, 2672). +-define(wxAuiNotebook_GetPage, 2673). +-define(wxAuiNotebook_GetPageBitmap, 2674). +-define(wxAuiNotebook_GetPageCount, 2675). +-define(wxAuiNotebook_GetPageIndex, 2676). +-define(wxAuiNotebook_GetPageText, 2677). +-define(wxAuiNotebook_GetSelection, 2678). +-define(wxAuiNotebook_InsertPage, 2679). +-define(wxAuiNotebook_RemovePage, 2680). +-define(wxAuiNotebook_SetArtProvider, 2681). +-define(wxAuiNotebook_SetFont, 2682). +-define(wxAuiNotebook_SetPageBitmap, 2683). +-define(wxAuiNotebook_SetPageText, 2684). +-define(wxAuiNotebook_SetSelection, 2685). +-define(wxAuiNotebook_SetTabCtrlHeight, 2686). +-define(wxAuiNotebook_SetUniformBitmapSize, 2687). +-define(wxAuiNotebook_destroy, 2688). +-define(wxAuiTabArt_SetFlags, 2689). +-define(wxAuiTabArt_SetMeasuringFont, 2690). +-define(wxAuiTabArt_SetNormalFont, 2691). +-define(wxAuiTabArt_SetSelectedFont, 2692). +-define(wxAuiTabArt_SetColour, 2693). +-define(wxAuiTabArt_SetActiveColour, 2694). +-define(wxAuiDockArt_GetColour, 2695). +-define(wxAuiDockArt_GetFont, 2696). +-define(wxAuiDockArt_GetMetric, 2697). +-define(wxAuiDockArt_SetColour, 2698). +-define(wxAuiDockArt_SetFont, 2699). +-define(wxAuiDockArt_SetMetric, 2700). +-define(wxAuiSimpleTabArt_new, 2701). +-define(wxAuiSimpleTabArt_destroy, 2702). +-define(wxMDIParentFrame_new_0, 2703). +-define(wxMDIParentFrame_new_4, 2704). +-define(wxMDIParentFrame_destruct, 2705). +-define(wxMDIParentFrame_ActivateNext, 2706). +-define(wxMDIParentFrame_ActivatePrevious, 2707). +-define(wxMDIParentFrame_ArrangeIcons, 2708). +-define(wxMDIParentFrame_Cascade, 2709). +-define(wxMDIParentFrame_Create, 2710). +-define(wxMDIParentFrame_GetActiveChild, 2711). +-define(wxMDIParentFrame_GetClientWindow, 2712). +-define(wxMDIParentFrame_Tile, 2713). +-define(wxMDIChildFrame_new_0, 2714). +-define(wxMDIChildFrame_new_4, 2715). +-define(wxMDIChildFrame_destruct, 2716). +-define(wxMDIChildFrame_Activate, 2717). +-define(wxMDIChildFrame_Create, 2718). +-define(wxMDIChildFrame_Maximize, 2719). +-define(wxMDIChildFrame_Restore, 2720). +-define(wxMDIClientWindow_new_0, 2721). +-define(wxMDIClientWindow_new_2, 2722). +-define(wxMDIClientWindow_destruct, 2723). +-define(wxMDIClientWindow_CreateClient, 2724). +-define(wxLayoutAlgorithm_new, 2725). +-define(wxLayoutAlgorithm_LayoutFrame, 2726). +-define(wxLayoutAlgorithm_LayoutMDIFrame, 2727). +-define(wxLayoutAlgorithm_LayoutWindow, 2728). +-define(wxLayoutAlgorithm_destroy, 2729). +-define(wxEvent_GetId, 2730). +-define(wxEvent_GetSkipped, 2731). +-define(wxEvent_GetTimestamp, 2732). +-define(wxEvent_IsCommandEvent, 2733). +-define(wxEvent_ResumePropagation, 2734). +-define(wxEvent_ShouldPropagate, 2735). +-define(wxEvent_Skip, 2736). +-define(wxEvent_StopPropagation, 2737). +-define(wxCommandEvent_getClientData, 2738). +-define(wxCommandEvent_GetExtraLong, 2739). +-define(wxCommandEvent_GetInt, 2740). +-define(wxCommandEvent_GetSelection, 2741). +-define(wxCommandEvent_GetString, 2742). +-define(wxCommandEvent_IsChecked, 2743). +-define(wxCommandEvent_IsSelection, 2744). +-define(wxCommandEvent_SetInt, 2745). +-define(wxCommandEvent_SetString, 2746). +-define(wxScrollEvent_GetOrientation, 2747). +-define(wxScrollEvent_GetPosition, 2748). +-define(wxScrollWinEvent_GetOrientation, 2749). +-define(wxScrollWinEvent_GetPosition, 2750). +-define(wxMouseEvent_AltDown, 2751). +-define(wxMouseEvent_Button, 2752). +-define(wxMouseEvent_ButtonDClick, 2753). +-define(wxMouseEvent_ButtonDown, 2754). +-define(wxMouseEvent_ButtonUp, 2755). +-define(wxMouseEvent_CmdDown, 2756). +-define(wxMouseEvent_ControlDown, 2757). +-define(wxMouseEvent_Dragging, 2758). +-define(wxMouseEvent_Entering, 2759). +-define(wxMouseEvent_GetButton, 2760). +-define(wxMouseEvent_GetPosition, 2763). +-define(wxMouseEvent_GetLogicalPosition, 2764). +-define(wxMouseEvent_GetLinesPerAction, 2765). +-define(wxMouseEvent_GetWheelRotation, 2766). +-define(wxMouseEvent_GetWheelDelta, 2767). +-define(wxMouseEvent_GetX, 2768). +-define(wxMouseEvent_GetY, 2769). +-define(wxMouseEvent_IsButton, 2770). +-define(wxMouseEvent_IsPageScroll, 2771). +-define(wxMouseEvent_Leaving, 2772). +-define(wxMouseEvent_LeftDClick, 2773). +-define(wxMouseEvent_LeftDown, 2774). +-define(wxMouseEvent_LeftIsDown, 2775). +-define(wxMouseEvent_LeftUp, 2776). +-define(wxMouseEvent_MetaDown, 2777). +-define(wxMouseEvent_MiddleDClick, 2778). +-define(wxMouseEvent_MiddleDown, 2779). +-define(wxMouseEvent_MiddleIsDown, 2780). +-define(wxMouseEvent_MiddleUp, 2781). +-define(wxMouseEvent_Moving, 2782). +-define(wxMouseEvent_RightDClick, 2783). +-define(wxMouseEvent_RightDown, 2784). +-define(wxMouseEvent_RightIsDown, 2785). +-define(wxMouseEvent_RightUp, 2786). +-define(wxMouseEvent_ShiftDown, 2787). +-define(wxSetCursorEvent_GetCursor, 2788). +-define(wxSetCursorEvent_GetX, 2789). +-define(wxSetCursorEvent_GetY, 2790). +-define(wxSetCursorEvent_HasCursor, 2791). +-define(wxSetCursorEvent_SetCursor, 2792). +-define(wxKeyEvent_AltDown, 2793). +-define(wxKeyEvent_CmdDown, 2794). +-define(wxKeyEvent_ControlDown, 2795). +-define(wxKeyEvent_GetKeyCode, 2796). +-define(wxKeyEvent_GetModifiers, 2797). +-define(wxKeyEvent_GetPosition, 2800). +-define(wxKeyEvent_GetRawKeyCode, 2801). +-define(wxKeyEvent_GetRawKeyFlags, 2802). +-define(wxKeyEvent_GetUnicodeKey, 2803). +-define(wxKeyEvent_GetX, 2804). +-define(wxKeyEvent_GetY, 2805). +-define(wxKeyEvent_HasModifiers, 2806). +-define(wxKeyEvent_MetaDown, 2807). +-define(wxKeyEvent_ShiftDown, 2808). +-define(wxSizeEvent_GetSize, 2809). +-define(wxMoveEvent_GetPosition, 2810). +-define(wxEraseEvent_GetDC, 2811). +-define(wxFocusEvent_GetWindow, 2812). +-define(wxChildFocusEvent_GetWindow, 2813). +-define(wxMenuEvent_GetMenu, 2814). +-define(wxMenuEvent_GetMenuId, 2815). +-define(wxMenuEvent_IsPopup, 2816). +-define(wxCloseEvent_CanVeto, 2817). +-define(wxCloseEvent_GetLoggingOff, 2818). +-define(wxCloseEvent_SetCanVeto, 2819). +-define(wxCloseEvent_SetLoggingOff, 2820). +-define(wxCloseEvent_Veto, 2821). +-define(wxShowEvent_SetShow, 2822). +-define(wxShowEvent_GetShow, 2823). +-define(wxIconizeEvent_Iconized, 2824). +-define(wxJoystickEvent_ButtonDown, 2825). +-define(wxJoystickEvent_ButtonIsDown, 2826). +-define(wxJoystickEvent_ButtonUp, 2827). +-define(wxJoystickEvent_GetButtonChange, 2828). +-define(wxJoystickEvent_GetButtonState, 2829). +-define(wxJoystickEvent_GetJoystick, 2830). +-define(wxJoystickEvent_GetPosition, 2831). +-define(wxJoystickEvent_GetZPosition, 2832). +-define(wxJoystickEvent_IsButton, 2833). +-define(wxJoystickEvent_IsMove, 2834). +-define(wxJoystickEvent_IsZMove, 2835). +-define(wxUpdateUIEvent_CanUpdate, 2836). +-define(wxUpdateUIEvent_Check, 2837). +-define(wxUpdateUIEvent_Enable, 2838). +-define(wxUpdateUIEvent_Show, 2839). +-define(wxUpdateUIEvent_GetChecked, 2840). +-define(wxUpdateUIEvent_GetEnabled, 2841). +-define(wxUpdateUIEvent_GetShown, 2842). +-define(wxUpdateUIEvent_GetSetChecked, 2843). +-define(wxUpdateUIEvent_GetSetEnabled, 2844). +-define(wxUpdateUIEvent_GetSetShown, 2845). +-define(wxUpdateUIEvent_GetSetText, 2846). +-define(wxUpdateUIEvent_GetText, 2847). +-define(wxUpdateUIEvent_GetMode, 2848). +-define(wxUpdateUIEvent_GetUpdateInterval, 2849). +-define(wxUpdateUIEvent_ResetUpdateTime, 2850). +-define(wxUpdateUIEvent_SetMode, 2851). +-define(wxUpdateUIEvent_SetText, 2852). +-define(wxUpdateUIEvent_SetUpdateInterval, 2853). +-define(wxMouseCaptureChangedEvent_GetCapturedWindow, 2854). +-define(wxPaletteChangedEvent_SetChangedWindow, 2855). +-define(wxPaletteChangedEvent_GetChangedWindow, 2856). +-define(wxQueryNewPaletteEvent_SetPaletteRealized, 2857). +-define(wxQueryNewPaletteEvent_GetPaletteRealized, 2858). +-define(wxNavigationKeyEvent_GetDirection, 2859). +-define(wxNavigationKeyEvent_SetDirection, 2860). +-define(wxNavigationKeyEvent_IsWindowChange, 2861). +-define(wxNavigationKeyEvent_SetWindowChange, 2862). +-define(wxNavigationKeyEvent_IsFromTab, 2863). +-define(wxNavigationKeyEvent_SetFromTab, 2864). +-define(wxNavigationKeyEvent_GetCurrentFocus, 2865). +-define(wxNavigationKeyEvent_SetCurrentFocus, 2866). +-define(wxHelpEvent_GetOrigin, 2867). +-define(wxHelpEvent_GetPosition, 2868). +-define(wxHelpEvent_SetOrigin, 2869). +-define(wxHelpEvent_SetPosition, 2870). +-define(wxContextMenuEvent_GetPosition, 2871). +-define(wxContextMenuEvent_SetPosition, 2872). +-define(wxIdleEvent_CanSend, 2873). +-define(wxIdleEvent_GetMode, 2874). +-define(wxIdleEvent_RequestMore, 2875). +-define(wxIdleEvent_MoreRequested, 2876). +-define(wxIdleEvent_SetMode, 2877). +-define(wxGridEvent_AltDown, 2878). +-define(wxGridEvent_ControlDown, 2879). +-define(wxGridEvent_GetCol, 2880). +-define(wxGridEvent_GetPosition, 2881). +-define(wxGridEvent_GetRow, 2882). +-define(wxGridEvent_MetaDown, 2883). +-define(wxGridEvent_Selecting, 2884). +-define(wxGridEvent_ShiftDown, 2885). +-define(wxNotifyEvent_Allow, 2886). +-define(wxNotifyEvent_IsAllowed, 2887). +-define(wxNotifyEvent_Veto, 2888). +-define(wxSashEvent_GetEdge, 2889). +-define(wxSashEvent_GetDragRect, 2890). +-define(wxSashEvent_GetDragStatus, 2891). +-define(wxListEvent_GetCacheFrom, 2892). +-define(wxListEvent_GetCacheTo, 2893). +-define(wxListEvent_GetKeyCode, 2894). +-define(wxListEvent_GetIndex, 2895). +-define(wxListEvent_GetColumn, 2896). +-define(wxListEvent_GetPoint, 2897). +-define(wxListEvent_GetLabel, 2898). +-define(wxListEvent_GetText, 2899). +-define(wxListEvent_GetImage, 2900). +-define(wxListEvent_GetData, 2901). +-define(wxListEvent_GetMask, 2902). +-define(wxListEvent_GetItem, 2903). +-define(wxListEvent_IsEditCancelled, 2904). +-define(wxDateEvent_GetDate, 2905). +-define(wxCalendarEvent_GetWeekDay, 2906). +-define(wxFileDirPickerEvent_GetPath, 2907). +-define(wxColourPickerEvent_GetColour, 2908). +-define(wxFontPickerEvent_GetFont, 2909). +-define(wxStyledTextEvent_GetPosition, 2910). +-define(wxStyledTextEvent_GetKey, 2911). +-define(wxStyledTextEvent_GetModifiers, 2912). +-define(wxStyledTextEvent_GetModificationType, 2913). +-define(wxStyledTextEvent_GetText, 2914). +-define(wxStyledTextEvent_GetLength, 2915). +-define(wxStyledTextEvent_GetLinesAdded, 2916). +-define(wxStyledTextEvent_GetLine, 2917). +-define(wxStyledTextEvent_GetFoldLevelNow, 2918). +-define(wxStyledTextEvent_GetFoldLevelPrev, 2919). +-define(wxStyledTextEvent_GetMargin, 2920). +-define(wxStyledTextEvent_GetMessage, 2921). +-define(wxStyledTextEvent_GetWParam, 2922). +-define(wxStyledTextEvent_GetLParam, 2923). +-define(wxStyledTextEvent_GetListType, 2924). +-define(wxStyledTextEvent_GetX, 2925). +-define(wxStyledTextEvent_GetY, 2926). +-define(wxStyledTextEvent_GetDragText, 2927). +-define(wxStyledTextEvent_GetDragAllowMove, 2928). +-define(wxStyledTextEvent_GetDragResult, 2929). +-define(wxStyledTextEvent_GetShift, 2930). +-define(wxStyledTextEvent_GetControl, 2931). +-define(wxStyledTextEvent_GetAlt, 2932). +-define(utils_wxGetKeyState, 2933). +-define(utils_wxGetMousePosition, 2934). +-define(utils_wxGetMouseState, 2935). +-define(utils_wxSetDetectableAutoRepeat, 2936). +-define(utils_wxBell, 2937). +-define(utils_wxFindMenuItemId, 2938). +-define(utils_wxGenericFindWindowAtPoint, 2939). +-define(utils_wxFindWindowAtPoint, 2940). +-define(utils_wxBeginBusyCursor, 2941). +-define(utils_wxEndBusyCursor, 2942). +-define(utils_wxIsBusy, 2943). +-define(utils_wxShutdown, 2944). +-define(utils_wxShell, 2945). +-define(utils_wxLaunchDefaultBrowser, 2946). +-define(utils_wxGetEmailAddress, 2947). +-define(utils_wxGetUserId, 2948). +-define(utils_wxGetHomeDir, 2949). +-define(utils_wxNewId, 2950). +-define(utils_wxRegisterId, 2951). +-define(utils_wxGetCurrentId, 2952). +-define(utils_wxGetOsDescription, 2953). +-define(utils_wxIsPlatformLittleEndian, 2954). +-define(utils_wxIsPlatform64Bit, 2955). +-define(gdicmn_wxDisplaySize, 2956). +-define(gdicmn_wxSetCursor, 2957). +-define(wxPrintout_new, 2958). +-define(wxPrintout_destruct, 2959). +-define(wxPrintout_GetDC, 2960). +-define(wxPrintout_GetPageSizeMM, 2961). +-define(wxPrintout_GetPageSizePixels, 2962). +-define(wxPrintout_GetPaperRectPixels, 2963). +-define(wxPrintout_GetPPIPrinter, 2964). +-define(wxPrintout_GetPPIScreen, 2965). +-define(wxPrintout_GetTitle, 2966). +-define(wxPrintout_IsPreview, 2967). +-define(wxPrintout_FitThisSizeToPaper, 2968). +-define(wxPrintout_FitThisSizeToPage, 2969). +-define(wxPrintout_FitThisSizeToPageMargins, 2970). +-define(wxPrintout_MapScreenSizeToPaper, 2971). +-define(wxPrintout_MapScreenSizeToPage, 2972). +-define(wxPrintout_MapScreenSizeToPageMargins, 2973). +-define(wxPrintout_MapScreenSizeToDevice, 2974). +-define(wxPrintout_GetLogicalPaperRect, 2975). +-define(wxPrintout_GetLogicalPageRect, 2976). +-define(wxPrintout_GetLogicalPageMarginsRect, 2977). +-define(wxPrintout_SetLogicalOrigin, 2978). +-define(wxPrintout_OffsetLogicalOrigin, 2979). +-define(wxStyledTextCtrl_new_2, 2980). +-define(wxStyledTextCtrl_new_0, 2981). +-define(wxStyledTextCtrl_destruct, 2982). +-define(wxStyledTextCtrl_Create, 2983). +-define(wxStyledTextCtrl_AddText, 2984). +-define(wxStyledTextCtrl_AddStyledText, 2985). +-define(wxStyledTextCtrl_InsertText, 2986). +-define(wxStyledTextCtrl_ClearAll, 2987). +-define(wxStyledTextCtrl_ClearDocumentStyle, 2988). +-define(wxStyledTextCtrl_GetLength, 2989). +-define(wxStyledTextCtrl_GetCharAt, 2990). +-define(wxStyledTextCtrl_GetCurrentPos, 2991). +-define(wxStyledTextCtrl_GetAnchor, 2992). +-define(wxStyledTextCtrl_GetStyleAt, 2993). +-define(wxStyledTextCtrl_Redo, 2994). +-define(wxStyledTextCtrl_SetUndoCollection, 2995). +-define(wxStyledTextCtrl_SelectAll, 2996). +-define(wxStyledTextCtrl_SetSavePoint, 2997). +-define(wxStyledTextCtrl_GetStyledText, 2998). +-define(wxStyledTextCtrl_CanRedo, 2999). +-define(wxStyledTextCtrl_MarkerLineFromHandle, 3000). +-define(wxStyledTextCtrl_MarkerDeleteHandle, 3001). +-define(wxStyledTextCtrl_GetUndoCollection, 3002). +-define(wxStyledTextCtrl_GetViewWhiteSpace, 3003). +-define(wxStyledTextCtrl_SetViewWhiteSpace, 3004). +-define(wxStyledTextCtrl_PositionFromPoint, 3005). +-define(wxStyledTextCtrl_PositionFromPointClose, 3006). +-define(wxStyledTextCtrl_GotoLine, 3007). +-define(wxStyledTextCtrl_GotoPos, 3008). +-define(wxStyledTextCtrl_SetAnchor, 3009). +-define(wxStyledTextCtrl_GetCurLine, 3010). +-define(wxStyledTextCtrl_GetEndStyled, 3011). +-define(wxStyledTextCtrl_ConvertEOLs, 3012). +-define(wxStyledTextCtrl_GetEOLMode, 3013). +-define(wxStyledTextCtrl_SetEOLMode, 3014). +-define(wxStyledTextCtrl_StartStyling, 3015). +-define(wxStyledTextCtrl_SetStyling, 3016). +-define(wxStyledTextCtrl_GetBufferedDraw, 3017). +-define(wxStyledTextCtrl_SetBufferedDraw, 3018). +-define(wxStyledTextCtrl_SetTabWidth, 3019). +-define(wxStyledTextCtrl_GetTabWidth, 3020). +-define(wxStyledTextCtrl_SetCodePage, 3021). +-define(wxStyledTextCtrl_MarkerDefine, 3022). +-define(wxStyledTextCtrl_MarkerSetForeground, 3023). +-define(wxStyledTextCtrl_MarkerSetBackground, 3024). +-define(wxStyledTextCtrl_MarkerAdd, 3025). +-define(wxStyledTextCtrl_MarkerDelete, 3026). +-define(wxStyledTextCtrl_MarkerDeleteAll, 3027). +-define(wxStyledTextCtrl_MarkerGet, 3028). +-define(wxStyledTextCtrl_MarkerNext, 3029). +-define(wxStyledTextCtrl_MarkerPrevious, 3030). +-define(wxStyledTextCtrl_MarkerDefineBitmap, 3031). +-define(wxStyledTextCtrl_MarkerAddSet, 3032). +-define(wxStyledTextCtrl_MarkerSetAlpha, 3033). +-define(wxStyledTextCtrl_SetMarginType, 3034). +-define(wxStyledTextCtrl_GetMarginType, 3035). +-define(wxStyledTextCtrl_SetMarginWidth, 3036). +-define(wxStyledTextCtrl_GetMarginWidth, 3037). +-define(wxStyledTextCtrl_SetMarginMask, 3038). +-define(wxStyledTextCtrl_GetMarginMask, 3039). +-define(wxStyledTextCtrl_SetMarginSensitive, 3040). +-define(wxStyledTextCtrl_GetMarginSensitive, 3041). +-define(wxStyledTextCtrl_StyleClearAll, 3042). +-define(wxStyledTextCtrl_StyleSetForeground, 3043). +-define(wxStyledTextCtrl_StyleSetBackground, 3044). +-define(wxStyledTextCtrl_StyleSetBold, 3045). +-define(wxStyledTextCtrl_StyleSetItalic, 3046). +-define(wxStyledTextCtrl_StyleSetSize, 3047). +-define(wxStyledTextCtrl_StyleSetFaceName, 3048). +-define(wxStyledTextCtrl_StyleSetEOLFilled, 3049). +-define(wxStyledTextCtrl_StyleResetDefault, 3050). +-define(wxStyledTextCtrl_StyleSetUnderline, 3051). +-define(wxStyledTextCtrl_StyleSetCase, 3052). +-define(wxStyledTextCtrl_StyleSetHotSpot, 3053). +-define(wxStyledTextCtrl_SetSelForeground, 3054). +-define(wxStyledTextCtrl_SetSelBackground, 3055). +-define(wxStyledTextCtrl_GetSelAlpha, 3056). +-define(wxStyledTextCtrl_SetSelAlpha, 3057). +-define(wxStyledTextCtrl_SetCaretForeground, 3058). +-define(wxStyledTextCtrl_CmdKeyAssign, 3059). +-define(wxStyledTextCtrl_CmdKeyClear, 3060). +-define(wxStyledTextCtrl_CmdKeyClearAll, 3061). +-define(wxStyledTextCtrl_SetStyleBytes, 3062). +-define(wxStyledTextCtrl_StyleSetVisible, 3063). +-define(wxStyledTextCtrl_GetCaretPeriod, 3064). +-define(wxStyledTextCtrl_SetCaretPeriod, 3065). +-define(wxStyledTextCtrl_SetWordChars, 3066). +-define(wxStyledTextCtrl_BeginUndoAction, 3067). +-define(wxStyledTextCtrl_EndUndoAction, 3068). +-define(wxStyledTextCtrl_IndicatorSetStyle, 3069). +-define(wxStyledTextCtrl_IndicatorGetStyle, 3070). +-define(wxStyledTextCtrl_IndicatorSetForeground, 3071). +-define(wxStyledTextCtrl_IndicatorGetForeground, 3072). +-define(wxStyledTextCtrl_SetWhitespaceForeground, 3073). +-define(wxStyledTextCtrl_SetWhitespaceBackground, 3074). +-define(wxStyledTextCtrl_GetStyleBits, 3075). +-define(wxStyledTextCtrl_SetLineState, 3076). +-define(wxStyledTextCtrl_GetLineState, 3077). +-define(wxStyledTextCtrl_GetMaxLineState, 3078). +-define(wxStyledTextCtrl_GetCaretLineVisible, 3079). +-define(wxStyledTextCtrl_SetCaretLineVisible, 3080). +-define(wxStyledTextCtrl_GetCaretLineBackground, 3081). +-define(wxStyledTextCtrl_SetCaretLineBackground, 3082). +-define(wxStyledTextCtrl_AutoCompShow, 3083). +-define(wxStyledTextCtrl_AutoCompCancel, 3084). +-define(wxStyledTextCtrl_AutoCompActive, 3085). +-define(wxStyledTextCtrl_AutoCompPosStart, 3086). +-define(wxStyledTextCtrl_AutoCompComplete, 3087). +-define(wxStyledTextCtrl_AutoCompStops, 3088). +-define(wxStyledTextCtrl_AutoCompSetSeparator, 3089). +-define(wxStyledTextCtrl_AutoCompGetSeparator, 3090). +-define(wxStyledTextCtrl_AutoCompSelect, 3091). +-define(wxStyledTextCtrl_AutoCompSetCancelAtStart, 3092). +-define(wxStyledTextCtrl_AutoCompGetCancelAtStart, 3093). +-define(wxStyledTextCtrl_AutoCompSetFillUps, 3094). +-define(wxStyledTextCtrl_AutoCompSetChooseSingle, 3095). +-define(wxStyledTextCtrl_AutoCompGetChooseSingle, 3096). +-define(wxStyledTextCtrl_AutoCompSetIgnoreCase, 3097). +-define(wxStyledTextCtrl_AutoCompGetIgnoreCase, 3098). +-define(wxStyledTextCtrl_UserListShow, 3099). +-define(wxStyledTextCtrl_AutoCompSetAutoHide, 3100). +-define(wxStyledTextCtrl_AutoCompGetAutoHide, 3101). +-define(wxStyledTextCtrl_AutoCompSetDropRestOfWord, 3102). +-define(wxStyledTextCtrl_AutoCompGetDropRestOfWord, 3103). +-define(wxStyledTextCtrl_RegisterImage, 3104). +-define(wxStyledTextCtrl_ClearRegisteredImages, 3105). +-define(wxStyledTextCtrl_AutoCompGetTypeSeparator, 3106). +-define(wxStyledTextCtrl_AutoCompSetTypeSeparator, 3107). +-define(wxStyledTextCtrl_AutoCompSetMaxWidth, 3108). +-define(wxStyledTextCtrl_AutoCompGetMaxWidth, 3109). +-define(wxStyledTextCtrl_AutoCompSetMaxHeight, 3110). +-define(wxStyledTextCtrl_AutoCompGetMaxHeight, 3111). +-define(wxStyledTextCtrl_SetIndent, 3112). +-define(wxStyledTextCtrl_GetIndent, 3113). +-define(wxStyledTextCtrl_SetUseTabs, 3114). +-define(wxStyledTextCtrl_GetUseTabs, 3115). +-define(wxStyledTextCtrl_SetLineIndentation, 3116). +-define(wxStyledTextCtrl_GetLineIndentation, 3117). +-define(wxStyledTextCtrl_GetLineIndentPosition, 3118). +-define(wxStyledTextCtrl_GetColumn, 3119). +-define(wxStyledTextCtrl_SetUseHorizontalScrollBar, 3120). +-define(wxStyledTextCtrl_GetUseHorizontalScrollBar, 3121). +-define(wxStyledTextCtrl_SetIndentationGuides, 3122). +-define(wxStyledTextCtrl_GetIndentationGuides, 3123). +-define(wxStyledTextCtrl_SetHighlightGuide, 3124). +-define(wxStyledTextCtrl_GetHighlightGuide, 3125). +-define(wxStyledTextCtrl_GetLineEndPosition, 3126). +-define(wxStyledTextCtrl_GetCodePage, 3127). +-define(wxStyledTextCtrl_GetCaretForeground, 3128). +-define(wxStyledTextCtrl_GetReadOnly, 3129). +-define(wxStyledTextCtrl_SetCurrentPos, 3130). +-define(wxStyledTextCtrl_SetSelectionStart, 3131). +-define(wxStyledTextCtrl_GetSelectionStart, 3132). +-define(wxStyledTextCtrl_SetSelectionEnd, 3133). +-define(wxStyledTextCtrl_GetSelectionEnd, 3134). +-define(wxStyledTextCtrl_SetPrintMagnification, 3135). +-define(wxStyledTextCtrl_GetPrintMagnification, 3136). +-define(wxStyledTextCtrl_SetPrintColourMode, 3137). +-define(wxStyledTextCtrl_GetPrintColourMode, 3138). +-define(wxStyledTextCtrl_FindText, 3139). +-define(wxStyledTextCtrl_FormatRange, 3140). +-define(wxStyledTextCtrl_GetFirstVisibleLine, 3141). +-define(wxStyledTextCtrl_GetLine, 3142). +-define(wxStyledTextCtrl_GetLineCount, 3143). +-define(wxStyledTextCtrl_SetMarginLeft, 3144). +-define(wxStyledTextCtrl_GetMarginLeft, 3145). +-define(wxStyledTextCtrl_SetMarginRight, 3146). +-define(wxStyledTextCtrl_GetMarginRight, 3147). +-define(wxStyledTextCtrl_GetModify, 3148). +-define(wxStyledTextCtrl_SetSelection, 3149). +-define(wxStyledTextCtrl_GetSelectedText, 3150). +-define(wxStyledTextCtrl_GetTextRange, 3151). +-define(wxStyledTextCtrl_HideSelection, 3152). +-define(wxStyledTextCtrl_LineFromPosition, 3153). +-define(wxStyledTextCtrl_PositionFromLine, 3154). +-define(wxStyledTextCtrl_LineScroll, 3155). +-define(wxStyledTextCtrl_EnsureCaretVisible, 3156). +-define(wxStyledTextCtrl_ReplaceSelection, 3157). +-define(wxStyledTextCtrl_SetReadOnly, 3158). +-define(wxStyledTextCtrl_CanPaste, 3159). +-define(wxStyledTextCtrl_CanUndo, 3160). +-define(wxStyledTextCtrl_EmptyUndoBuffer, 3161). +-define(wxStyledTextCtrl_Undo, 3162). +-define(wxStyledTextCtrl_Cut, 3163). +-define(wxStyledTextCtrl_Copy, 3164). +-define(wxStyledTextCtrl_Paste, 3165). +-define(wxStyledTextCtrl_Clear, 3166). +-define(wxStyledTextCtrl_SetText, 3167). +-define(wxStyledTextCtrl_GetText, 3168). +-define(wxStyledTextCtrl_GetTextLength, 3169). +-define(wxStyledTextCtrl_GetOvertype, 3170). +-define(wxStyledTextCtrl_SetCaretWidth, 3171). +-define(wxStyledTextCtrl_GetCaretWidth, 3172). +-define(wxStyledTextCtrl_SetTargetStart, 3173). +-define(wxStyledTextCtrl_GetTargetStart, 3174). +-define(wxStyledTextCtrl_SetTargetEnd, 3175). +-define(wxStyledTextCtrl_GetTargetEnd, 3176). +-define(wxStyledTextCtrl_ReplaceTarget, 3177). +-define(wxStyledTextCtrl_SearchInTarget, 3178). +-define(wxStyledTextCtrl_SetSearchFlags, 3179). +-define(wxStyledTextCtrl_GetSearchFlags, 3180). +-define(wxStyledTextCtrl_CallTipShow, 3181). +-define(wxStyledTextCtrl_CallTipCancel, 3182). +-define(wxStyledTextCtrl_CallTipActive, 3183). +-define(wxStyledTextCtrl_CallTipPosAtStart, 3184). +-define(wxStyledTextCtrl_CallTipSetHighlight, 3185). +-define(wxStyledTextCtrl_CallTipSetBackground, 3186). +-define(wxStyledTextCtrl_CallTipSetForeground, 3187). +-define(wxStyledTextCtrl_CallTipSetForegroundHighlight, 3188). +-define(wxStyledTextCtrl_CallTipUseStyle, 3189). +-define(wxStyledTextCtrl_VisibleFromDocLine, 3190). +-define(wxStyledTextCtrl_DocLineFromVisible, 3191). +-define(wxStyledTextCtrl_WrapCount, 3192). +-define(wxStyledTextCtrl_SetFoldLevel, 3193). +-define(wxStyledTextCtrl_GetFoldLevel, 3194). +-define(wxStyledTextCtrl_GetLastChild, 3195). +-define(wxStyledTextCtrl_GetFoldParent, 3196). +-define(wxStyledTextCtrl_ShowLines, 3197). +-define(wxStyledTextCtrl_HideLines, 3198). +-define(wxStyledTextCtrl_GetLineVisible, 3199). +-define(wxStyledTextCtrl_SetFoldExpanded, 3200). +-define(wxStyledTextCtrl_GetFoldExpanded, 3201). +-define(wxStyledTextCtrl_ToggleFold, 3202). +-define(wxStyledTextCtrl_EnsureVisible, 3203). +-define(wxStyledTextCtrl_SetFoldFlags, 3204). +-define(wxStyledTextCtrl_EnsureVisibleEnforcePolicy, 3205). +-define(wxStyledTextCtrl_SetTabIndents, 3206). +-define(wxStyledTextCtrl_GetTabIndents, 3207). +-define(wxStyledTextCtrl_SetBackSpaceUnIndents, 3208). +-define(wxStyledTextCtrl_GetBackSpaceUnIndents, 3209). +-define(wxStyledTextCtrl_SetMouseDwellTime, 3210). +-define(wxStyledTextCtrl_GetMouseDwellTime, 3211). +-define(wxStyledTextCtrl_WordStartPosition, 3212). +-define(wxStyledTextCtrl_WordEndPosition, 3213). +-define(wxStyledTextCtrl_SetWrapMode, 3214). +-define(wxStyledTextCtrl_GetWrapMode, 3215). +-define(wxStyledTextCtrl_SetWrapVisualFlags, 3216). +-define(wxStyledTextCtrl_GetWrapVisualFlags, 3217). +-define(wxStyledTextCtrl_SetWrapVisualFlagsLocation, 3218). +-define(wxStyledTextCtrl_GetWrapVisualFlagsLocation, 3219). +-define(wxStyledTextCtrl_SetWrapStartIndent, 3220). +-define(wxStyledTextCtrl_GetWrapStartIndent, 3221). +-define(wxStyledTextCtrl_SetLayoutCache, 3222). +-define(wxStyledTextCtrl_GetLayoutCache, 3223). +-define(wxStyledTextCtrl_SetScrollWidth, 3224). +-define(wxStyledTextCtrl_GetScrollWidth, 3225). +-define(wxStyledTextCtrl_TextWidth, 3226). +-define(wxStyledTextCtrl_GetEndAtLastLine, 3227). +-define(wxStyledTextCtrl_TextHeight, 3228). +-define(wxStyledTextCtrl_SetUseVerticalScrollBar, 3229). +-define(wxStyledTextCtrl_GetUseVerticalScrollBar, 3230). +-define(wxStyledTextCtrl_AppendText, 3231). +-define(wxStyledTextCtrl_GetTwoPhaseDraw, 3232). +-define(wxStyledTextCtrl_SetTwoPhaseDraw, 3233). +-define(wxStyledTextCtrl_TargetFromSelection, 3234). +-define(wxStyledTextCtrl_LinesJoin, 3235). +-define(wxStyledTextCtrl_LinesSplit, 3236). +-define(wxStyledTextCtrl_SetFoldMarginColour, 3237). +-define(wxStyledTextCtrl_SetFoldMarginHiColour, 3238). +-define(wxStyledTextCtrl_LineDown, 3239). +-define(wxStyledTextCtrl_LineDownExtend, 3240). +-define(wxStyledTextCtrl_LineUp, 3241). +-define(wxStyledTextCtrl_LineUpExtend, 3242). +-define(wxStyledTextCtrl_CharLeft, 3243). +-define(wxStyledTextCtrl_CharLeftExtend, 3244). +-define(wxStyledTextCtrl_CharRight, 3245). +-define(wxStyledTextCtrl_CharRightExtend, 3246). +-define(wxStyledTextCtrl_WordLeft, 3247). +-define(wxStyledTextCtrl_WordLeftExtend, 3248). +-define(wxStyledTextCtrl_WordRight, 3249). +-define(wxStyledTextCtrl_WordRightExtend, 3250). +-define(wxStyledTextCtrl_Home, 3251). +-define(wxStyledTextCtrl_HomeExtend, 3252). +-define(wxStyledTextCtrl_LineEnd, 3253). +-define(wxStyledTextCtrl_LineEndExtend, 3254). +-define(wxStyledTextCtrl_DocumentStart, 3255). +-define(wxStyledTextCtrl_DocumentStartExtend, 3256). +-define(wxStyledTextCtrl_DocumentEnd, 3257). +-define(wxStyledTextCtrl_DocumentEndExtend, 3258). +-define(wxStyledTextCtrl_PageUp, 3259). +-define(wxStyledTextCtrl_PageUpExtend, 3260). +-define(wxStyledTextCtrl_PageDown, 3261). +-define(wxStyledTextCtrl_PageDownExtend, 3262). +-define(wxStyledTextCtrl_EditToggleOvertype, 3263). +-define(wxStyledTextCtrl_Cancel, 3264). +-define(wxStyledTextCtrl_DeleteBack, 3265). +-define(wxStyledTextCtrl_Tab, 3266). +-define(wxStyledTextCtrl_BackTab, 3267). +-define(wxStyledTextCtrl_NewLine, 3268). +-define(wxStyledTextCtrl_FormFeed, 3269). +-define(wxStyledTextCtrl_VCHome, 3270). +-define(wxStyledTextCtrl_VCHomeExtend, 3271). +-define(wxStyledTextCtrl_ZoomIn, 3272). +-define(wxStyledTextCtrl_ZoomOut, 3273). +-define(wxStyledTextCtrl_DelWordLeft, 3274). +-define(wxStyledTextCtrl_DelWordRight, 3275). +-define(wxStyledTextCtrl_LineCut, 3276). +-define(wxStyledTextCtrl_LineDelete, 3277). +-define(wxStyledTextCtrl_LineTranspose, 3278). +-define(wxStyledTextCtrl_LineDuplicate, 3279). +-define(wxStyledTextCtrl_LowerCase, 3280). +-define(wxStyledTextCtrl_UpperCase, 3281). +-define(wxStyledTextCtrl_LineScrollDown, 3282). +-define(wxStyledTextCtrl_LineScrollUp, 3283). +-define(wxStyledTextCtrl_DeleteBackNotLine, 3284). +-define(wxStyledTextCtrl_HomeDisplay, 3285). +-define(wxStyledTextCtrl_HomeDisplayExtend, 3286). +-define(wxStyledTextCtrl_LineEndDisplay, 3287). +-define(wxStyledTextCtrl_LineEndDisplayExtend, 3288). +-define(wxStyledTextCtrl_HomeWrapExtend, 3289). +-define(wxStyledTextCtrl_LineEndWrap, 3290). +-define(wxStyledTextCtrl_LineEndWrapExtend, 3291). +-define(wxStyledTextCtrl_VCHomeWrap, 3292). +-define(wxStyledTextCtrl_VCHomeWrapExtend, 3293). +-define(wxStyledTextCtrl_LineCopy, 3294). +-define(wxStyledTextCtrl_MoveCaretInsideView, 3295). +-define(wxStyledTextCtrl_LineLength, 3296). +-define(wxStyledTextCtrl_BraceHighlight, 3297). +-define(wxStyledTextCtrl_BraceBadLight, 3298). +-define(wxStyledTextCtrl_BraceMatch, 3299). +-define(wxStyledTextCtrl_GetViewEOL, 3300). +-define(wxStyledTextCtrl_SetViewEOL, 3301). +-define(wxStyledTextCtrl_SetModEventMask, 3302). +-define(wxStyledTextCtrl_GetEdgeColumn, 3303). +-define(wxStyledTextCtrl_SetEdgeColumn, 3304). +-define(wxStyledTextCtrl_SetEdgeMode, 3305). +-define(wxStyledTextCtrl_GetEdgeMode, 3306). +-define(wxStyledTextCtrl_GetEdgeColour, 3307). +-define(wxStyledTextCtrl_SetEdgeColour, 3308). +-define(wxStyledTextCtrl_SearchAnchor, 3309). +-define(wxStyledTextCtrl_SearchNext, 3310). +-define(wxStyledTextCtrl_SearchPrev, 3311). +-define(wxStyledTextCtrl_LinesOnScreen, 3312). +-define(wxStyledTextCtrl_UsePopUp, 3313). +-define(wxStyledTextCtrl_SelectionIsRectangle, 3314). +-define(wxStyledTextCtrl_SetZoom, 3315). +-define(wxStyledTextCtrl_GetZoom, 3316). +-define(wxStyledTextCtrl_GetModEventMask, 3317). +-define(wxStyledTextCtrl_SetSTCFocus, 3318). +-define(wxStyledTextCtrl_GetSTCFocus, 3319). +-define(wxStyledTextCtrl_SetStatus, 3320). +-define(wxStyledTextCtrl_GetStatus, 3321). +-define(wxStyledTextCtrl_SetMouseDownCaptures, 3322). +-define(wxStyledTextCtrl_GetMouseDownCaptures, 3323). +-define(wxStyledTextCtrl_SetSTCCursor, 3324). +-define(wxStyledTextCtrl_GetSTCCursor, 3325). +-define(wxStyledTextCtrl_SetControlCharSymbol, 3326). +-define(wxStyledTextCtrl_GetControlCharSymbol, 3327). +-define(wxStyledTextCtrl_WordPartLeft, 3328). +-define(wxStyledTextCtrl_WordPartLeftExtend, 3329). +-define(wxStyledTextCtrl_WordPartRight, 3330). +-define(wxStyledTextCtrl_WordPartRightExtend, 3331). +-define(wxStyledTextCtrl_SetVisiblePolicy, 3332). +-define(wxStyledTextCtrl_DelLineLeft, 3333). +-define(wxStyledTextCtrl_DelLineRight, 3334). +-define(wxStyledTextCtrl_GetXOffset, 3335). +-define(wxStyledTextCtrl_ChooseCaretX, 3336). +-define(wxStyledTextCtrl_SetXCaretPolicy, 3337). +-define(wxStyledTextCtrl_SetYCaretPolicy, 3338). +-define(wxStyledTextCtrl_GetPrintWrapMode, 3339). +-define(wxStyledTextCtrl_SetHotspotActiveForeground, 3340). +-define(wxStyledTextCtrl_SetHotspotActiveBackground, 3341). +-define(wxStyledTextCtrl_SetHotspotActiveUnderline, 3342). +-define(wxStyledTextCtrl_SetHotspotSingleLine, 3343). +-define(wxStyledTextCtrl_ParaDownExtend, 3344). +-define(wxStyledTextCtrl_ParaUp, 3345). +-define(wxStyledTextCtrl_ParaUpExtend, 3346). +-define(wxStyledTextCtrl_PositionBefore, 3347). +-define(wxStyledTextCtrl_PositionAfter, 3348). +-define(wxStyledTextCtrl_CopyRange, 3349). +-define(wxStyledTextCtrl_CopyText, 3350). +-define(wxStyledTextCtrl_SetSelectionMode, 3351). +-define(wxStyledTextCtrl_GetSelectionMode, 3352). +-define(wxStyledTextCtrl_LineDownRectExtend, 3353). +-define(wxStyledTextCtrl_LineUpRectExtend, 3354). +-define(wxStyledTextCtrl_CharLeftRectExtend, 3355). +-define(wxStyledTextCtrl_CharRightRectExtend, 3356). +-define(wxStyledTextCtrl_HomeRectExtend, 3357). +-define(wxStyledTextCtrl_VCHomeRectExtend, 3358). +-define(wxStyledTextCtrl_LineEndRectExtend, 3359). +-define(wxStyledTextCtrl_PageUpRectExtend, 3360). +-define(wxStyledTextCtrl_PageDownRectExtend, 3361). +-define(wxStyledTextCtrl_StutteredPageUp, 3362). +-define(wxStyledTextCtrl_StutteredPageUpExtend, 3363). +-define(wxStyledTextCtrl_StutteredPageDown, 3364). +-define(wxStyledTextCtrl_StutteredPageDownExtend, 3365). +-define(wxStyledTextCtrl_WordLeftEnd, 3366). +-define(wxStyledTextCtrl_WordLeftEndExtend, 3367). +-define(wxStyledTextCtrl_WordRightEnd, 3368). +-define(wxStyledTextCtrl_WordRightEndExtend, 3369). +-define(wxStyledTextCtrl_SetWhitespaceChars, 3370). +-define(wxStyledTextCtrl_SetCharsDefault, 3371). +-define(wxStyledTextCtrl_AutoCompGetCurrent, 3372). +-define(wxStyledTextCtrl_Allocate, 3373). +-define(wxStyledTextCtrl_FindColumn, 3374). +-define(wxStyledTextCtrl_GetCaretSticky, 3375). +-define(wxStyledTextCtrl_SetCaretSticky, 3376). +-define(wxStyledTextCtrl_ToggleCaretSticky, 3377). +-define(wxStyledTextCtrl_SetPasteConvertEndings, 3378). +-define(wxStyledTextCtrl_GetPasteConvertEndings, 3379). +-define(wxStyledTextCtrl_SelectionDuplicate, 3380). +-define(wxStyledTextCtrl_SetCaretLineBackAlpha, 3381). +-define(wxStyledTextCtrl_GetCaretLineBackAlpha, 3382). +-define(wxStyledTextCtrl_StartRecord, 3383). +-define(wxStyledTextCtrl_StopRecord, 3384). +-define(wxStyledTextCtrl_SetLexer, 3385). +-define(wxStyledTextCtrl_GetLexer, 3386). +-define(wxStyledTextCtrl_Colourise, 3387). +-define(wxStyledTextCtrl_SetProperty, 3388). +-define(wxStyledTextCtrl_SetKeyWords, 3389). +-define(wxStyledTextCtrl_SetLexerLanguage, 3390). +-define(wxStyledTextCtrl_GetProperty, 3391). +-define(wxStyledTextCtrl_GetStyleBitsNeeded, 3392). +-define(wxStyledTextCtrl_GetCurrentLine, 3393). +-define(wxStyledTextCtrl_StyleSetSpec, 3394). +-define(wxStyledTextCtrl_StyleSetFont, 3395). +-define(wxStyledTextCtrl_StyleSetFontAttr, 3396). +-define(wxStyledTextCtrl_StyleSetCharacterSet, 3397). +-define(wxStyledTextCtrl_StyleSetFontEncoding, 3398). +-define(wxStyledTextCtrl_CmdKeyExecute, 3399). +-define(wxStyledTextCtrl_SetMargins, 3400). +-define(wxStyledTextCtrl_GetSelection, 3401). +-define(wxStyledTextCtrl_PointFromPosition, 3402). +-define(wxStyledTextCtrl_ScrollToLine, 3403). +-define(wxStyledTextCtrl_ScrollToColumn, 3404). +-define(wxStyledTextCtrl_SetVScrollBar, 3405). +-define(wxStyledTextCtrl_SetHScrollBar, 3406). +-define(wxStyledTextCtrl_GetLastKeydownProcessed, 3407). +-define(wxStyledTextCtrl_SetLastKeydownProcessed, 3408). +-define(wxStyledTextCtrl_SaveFile, 3409). +-define(wxStyledTextCtrl_LoadFile, 3410). +-define(wxStyledTextCtrl_DoDragOver, 3411). +-define(wxStyledTextCtrl_DoDropText, 3412). +-define(wxStyledTextCtrl_GetUseAntiAliasing, 3413). +-define(wxStyledTextCtrl_AddTextRaw, 3414). +-define(wxStyledTextCtrl_InsertTextRaw, 3415). +-define(wxStyledTextCtrl_GetCurLineRaw, 3416). +-define(wxStyledTextCtrl_GetLineRaw, 3417). +-define(wxStyledTextCtrl_GetSelectedTextRaw, 3418). +-define(wxStyledTextCtrl_GetTextRangeRaw, 3419). +-define(wxStyledTextCtrl_SetTextRaw, 3420). +-define(wxStyledTextCtrl_GetTextRaw, 3421). +-define(wxStyledTextCtrl_AppendTextRaw, 3422). +-define(wxArtProvider_GetBitmap, 3423). +-define(wxArtProvider_GetIcon, 3424). +-define(wxTreeEvent_GetKeyCode, 3425). +-define(wxTreeEvent_GetItem, 3426). +-define(wxTreeEvent_GetKeyEvent, 3427). +-define(wxTreeEvent_GetLabel, 3428). +-define(wxTreeEvent_GetOldItem, 3429). +-define(wxTreeEvent_GetPoint, 3430). +-define(wxTreeEvent_IsEditCancelled, 3431). +-define(wxTreeEvent_SetToolTip, 3432). +-define(wxNotebookEvent_GetOldSelection, 3433). +-define(wxNotebookEvent_GetSelection, 3434). +-define(wxNotebookEvent_SetOldSelection, 3435). +-define(wxNotebookEvent_SetSelection, 3436). +-define(wxFileDataObject_new, 3437). +-define(wxFileDataObject_AddFile, 3438). +-define(wxFileDataObject_GetFilenames, 3439). +-define(wxFileDataObject_destroy, 3440). +-define(wxTextDataObject_new, 3441). +-define(wxTextDataObject_GetTextLength, 3442). +-define(wxTextDataObject_GetText, 3443). +-define(wxTextDataObject_SetText, 3444). +-define(wxTextDataObject_destroy, 3445). +-define(wxBitmapDataObject_new_1_1, 3446). +-define(wxBitmapDataObject_new_1_0, 3447). +-define(wxBitmapDataObject_GetBitmap, 3448). +-define(wxBitmapDataObject_SetBitmap, 3449). +-define(wxBitmapDataObject_destroy, 3450). +-define(wxClipboard_new, 3452). +-define(wxClipboard_destruct, 3453). +-define(wxClipboard_AddData, 3454). +-define(wxClipboard_Clear, 3455). +-define(wxClipboard_Close, 3456). +-define(wxClipboard_Flush, 3457). +-define(wxClipboard_GetData, 3458). +-define(wxClipboard_IsOpened, 3459). +-define(wxClipboard_Open, 3460). +-define(wxClipboard_SetData, 3461). +-define(wxClipboard_UsePrimarySelection, 3463). +-define(wxClipboard_IsSupported, 3464). +-define(wxClipboard_Get, 3465). +-define(wxSpinEvent_GetPosition, 3466). +-define(wxSpinEvent_SetPosition, 3467). +-define(wxSplitterWindow_new_0, 3468). +-define(wxSplitterWindow_new_2, 3469). +-define(wxSplitterWindow_destruct, 3470). +-define(wxSplitterWindow_Create, 3471). +-define(wxSplitterWindow_GetMinimumPaneSize, 3472). +-define(wxSplitterWindow_GetSashGravity, 3473). +-define(wxSplitterWindow_GetSashPosition, 3474). +-define(wxSplitterWindow_GetSplitMode, 3475). +-define(wxSplitterWindow_GetWindow1, 3476). +-define(wxSplitterWindow_GetWindow2, 3477). +-define(wxSplitterWindow_Initialize, 3478). +-define(wxSplitterWindow_IsSplit, 3479). +-define(wxSplitterWindow_ReplaceWindow, 3480). +-define(wxSplitterWindow_SetSashGravity, 3481). +-define(wxSplitterWindow_SetSashPosition, 3482). +-define(wxSplitterWindow_SetSashSize, 3483). +-define(wxSplitterWindow_SetMinimumPaneSize, 3484). +-define(wxSplitterWindow_SetSplitMode, 3485). +-define(wxSplitterWindow_SplitHorizontally, 3486). +-define(wxSplitterWindow_SplitVertically, 3487). +-define(wxSplitterWindow_Unsplit, 3488). +-define(wxSplitterWindow_UpdateSize, 3489). +-define(wxSplitterEvent_GetSashPosition, 3490). +-define(wxSplitterEvent_GetX, 3491). +-define(wxSplitterEvent_GetY, 3492). +-define(wxSplitterEvent_GetWindowBeingRemoved, 3493). +-define(wxSplitterEvent_SetSashPosition, 3494). +-define(wxHtmlWindow_new_0, 3495). +-define(wxHtmlWindow_new_2, 3496). +-define(wxHtmlWindow_AppendToPage, 3497). +-define(wxHtmlWindow_GetOpenedAnchor, 3498). +-define(wxHtmlWindow_GetOpenedPage, 3499). +-define(wxHtmlWindow_GetOpenedPageTitle, 3500). +-define(wxHtmlWindow_GetRelatedFrame, 3501). +-define(wxHtmlWindow_HistoryBack, 3502). +-define(wxHtmlWindow_HistoryCanBack, 3503). +-define(wxHtmlWindow_HistoryCanForward, 3504). +-define(wxHtmlWindow_HistoryClear, 3505). +-define(wxHtmlWindow_HistoryForward, 3506). +-define(wxHtmlWindow_LoadFile, 3507). +-define(wxHtmlWindow_LoadPage, 3508). +-define(wxHtmlWindow_SelectAll, 3509). +-define(wxHtmlWindow_SelectionToText, 3510). +-define(wxHtmlWindow_SelectLine, 3511). +-define(wxHtmlWindow_SelectWord, 3512). +-define(wxHtmlWindow_SetBorders, 3513). +-define(wxHtmlWindow_SetFonts, 3514). +-define(wxHtmlWindow_SetPage, 3515). +-define(wxHtmlWindow_SetRelatedFrame, 3516). +-define(wxHtmlWindow_SetRelatedStatusBar, 3517). +-define(wxHtmlWindow_ToText, 3518). +-define(wxHtmlWindow_destroy, 3519). +-define(wxHtmlLinkEvent_GetLinkInfo, 3520). +-define(wxSystemSettings_GetColour, 3521). +-define(wxSystemSettings_GetFont, 3522). +-define(wxSystemSettings_GetMetric, 3523). +-define(wxSystemSettings_GetScreenType, 3524). +-define(wxSystemOptions_GetOption, 3525). +-define(wxSystemOptions_GetOptionInt, 3526). +-define(wxSystemOptions_HasOption, 3527). +-define(wxSystemOptions_IsFalse, 3528). +-define(wxSystemOptions_SetOption_2_1, 3529). +-define(wxSystemOptions_SetOption_2_0, 3530). +-define(wxAuiNotebookEvent_SetSelection, 3531). +-define(wxAuiNotebookEvent_GetSelection, 3532). +-define(wxAuiNotebookEvent_SetOldSelection, 3533). +-define(wxAuiNotebookEvent_GetOldSelection, 3534). +-define(wxAuiNotebookEvent_SetDragSource, 3535). +-define(wxAuiNotebookEvent_GetDragSource, 3536). +-define(wxAuiManagerEvent_SetManager, 3537). +-define(wxAuiManagerEvent_GetManager, 3538). +-define(wxAuiManagerEvent_SetPane, 3539). +-define(wxAuiManagerEvent_GetPane, 3540). +-define(wxAuiManagerEvent_SetButton, 3541). +-define(wxAuiManagerEvent_GetButton, 3542). +-define(wxAuiManagerEvent_SetDC, 3543). +-define(wxAuiManagerEvent_GetDC, 3544). +-define(wxAuiManagerEvent_Veto, 3545). +-define(wxAuiManagerEvent_GetVeto, 3546). +-define(wxAuiManagerEvent_SetCanVeto, 3547). +-define(wxAuiManagerEvent_CanVeto, 3548). +-define(wxLogNull_new, 3549). +-define(wxLogNull_destroy, 3550). +-define(wxTaskBarIcon_new, 3551). +-define(wxTaskBarIcon_destruct, 3552). +-define(wxTaskBarIcon_PopupMenu, 3553). +-define(wxTaskBarIcon_RemoveIcon, 3554). +-define(wxTaskBarIcon_SetIcon, 3555). +-define(wxLocale_new_0, 3556). +-define(wxLocale_new_2, 3558). +-define(wxLocale_destruct, 3559). +-define(wxLocale_Init, 3561). +-define(wxLocale_AddCatalog_1, 3562). +-define(wxLocale_AddCatalog_3, 3563). +-define(wxLocale_AddCatalogLookupPathPrefix, 3564). +-define(wxLocale_GetCanonicalName, 3565). +-define(wxLocale_GetLanguage, 3566). +-define(wxLocale_GetLanguageName, 3567). +-define(wxLocale_GetLocale, 3568). +-define(wxLocale_GetName, 3569). +-define(wxLocale_GetString_2, 3570). +-define(wxLocale_GetString_4, 3571). +-define(wxLocale_GetHeaderValue, 3572). +-define(wxLocale_GetSysName, 3573). +-define(wxLocale_GetSystemEncoding, 3574). +-define(wxLocale_GetSystemEncodingName, 3575). +-define(wxLocale_GetSystemLanguage, 3576). +-define(wxLocale_IsLoaded, 3577). +-define(wxLocale_IsOk, 3578). +-define(wxActivateEvent_GetActive, 3579). +-define(wxPopupWindow_new_2, 3581). +-define(wxPopupWindow_new_0, 3582). +-define(wxPopupWindow_destruct, 3584). +-define(wxPopupWindow_Create, 3585). +-define(wxPopupWindow_Position, 3586). +-define(wxPopupTransientWindow_new_0, 3587). +-define(wxPopupTransientWindow_new_2, 3588). +-define(wxPopupTransientWindow_destruct, 3589). +-define(wxPopupTransientWindow_Popup, 3590). +-define(wxPopupTransientWindow_Dismiss, 3591). +-define(wxOverlay_new, 3592). +-define(wxOverlay_destruct, 3593). +-define(wxOverlay_Reset, 3594). +-define(wxDCOverlay_new_6, 3595). +-define(wxDCOverlay_new_2, 3596). +-define(wxDCOverlay_destruct, 3597). +-define(wxDCOverlay_Clear, 3598). diff --git a/lib/wx/src/wxe_server.erl b/lib/wx/src/wxe_server.erl index 6679fcfbe1..693a008e3d 100644 --- a/lib/wx/src/wxe_server.erl +++ b/lib/wx/src/wxe_server.erl @@ -240,6 +240,8 @@ handle_connect(Object, EvData=#evh{handler=Handler}, invoke_cb({{Ev=#wx{}, Ref=#wx_ref{}}, FunId,_}, _S) -> %% Event callbacks case get(FunId) of + {{nospawn, Fun}, _} when is_function(Fun) -> + invoke_callback_fun(fun() -> Fun(Ev, Ref), <<>> end); {Fun,_} when is_function(Fun) -> invoke_callback(fun() -> Fun(Ev, Ref), <<>> end); {Pid,_} when is_pid(Pid) -> %% wx_object sync event @@ -258,21 +260,10 @@ invoke_cb({FunId, Args, _}, _S) when is_list(Args), is_integer(FunId) -> invoke_callback(Fun) -> Env = get(?WXE_IDENTIFIER), - CB = fun() -> - wx:set_env(Env), - wxe_util:cast(?WXE_CB_START, <<>>), - Res = try - Return = Fun(), - true = is_binary(Return), - Return - catch _:Reason -> - ?log("Callback fun crashed with {'EXIT, ~p, ~p}~n", - [Reason, erlang:get_stacktrace()]), - <<>> - end, - wxe_util:cast(?WXE_CB_RETURN, Res) - end, - spawn(CB), + spawn(fun() -> + wx:set_env(Env), + invoke_callback_fun(Fun) + end), ok. invoke_callback(Pid, Ev, Ref) -> @@ -281,7 +272,7 @@ invoke_callback(Pid, Ev, Ref) -> wx:set_env(Env), wxe_util:cast(?WXE_CB_START, <<>>), try - case get_wx_object_state(Pid) of + case get_wx_object_state(Pid, 5) of ignore -> %% Ignore early events wxEvent:skip(Ref); @@ -302,16 +293,38 @@ invoke_callback(Pid, Ev, Ref) -> spawn(CB), ok. -get_wx_object_state(Pid) -> +invoke_callback_fun(Fun) -> + wxe_util:cast(?WXE_CB_START, <<>>), + Res = try + Return = Fun(), + true = is_binary(Return), + Return + catch _:Reason -> + ?log("Callback fun crashed with {'EXIT, ~p, ~p}~n", + [Reason, erlang:get_stacktrace()]), + <<>> + end, + wxe_util:cast(?WXE_CB_RETURN, Res). + + +get_wx_object_state(Pid, N) when N > 0 -> case process_info(Pid, dictionary) of {dictionary, Dict} -> case lists:keysearch('_wx_object_',1,Dict) of - {value, {'_wx_object_', {_Mod, '_wx_init_'}}} -> ignore; - {value, {'_wx_object_', Value}} -> Value; - _ -> ignore + {value, {'_wx_object_', {_Mod, '_wx_init_'}}} -> + timer:sleep(50), + get_wx_object_state(Pid, N-1); + {value, {'_wx_object_', Value}} -> + Value; + _ -> + ignore end; - _ -> ignore - end. + _ -> + ignore + end; +get_wx_object_state(_, _) -> + ignore. + attach_fun(Fun, S = #state{cb=CB,cb_cnt=Next}) -> case gb_trees:lookup(Fun,CB) of @@ -347,25 +360,8 @@ handle_disconnect(Object, Evh = #evh{cb=Fun}, From, State0 = #state{users=Users0, cb=Callbacks}) -> #user{events=Evs0} = gb_trees:get(From, Users0), FunId = gb_trees:lookup(Fun, Callbacks), - case find_handler(Evs0, Object, Evh#evh{cb=FunId}) of - [] -> - {reply, false, State0}; - Handlers -> - case disconnect(Object,Handlers) of - #evh{} -> {reply, true, State0}; - Result -> {reply, Result, State0} - end - end. - -disconnect(Object,[Ev|Evs]) -> - try wxEvtHandler:disconnect_impl(Object,Ev) of - true -> Ev; - false -> disconnect(Object, Evs); - Error -> Error - catch _:_ -> - false - end; -disconnect(_, []) -> false. + Handlers = find_handler(Evs0, Object, Evh#evh{cb=FunId}), + {reply, {try_in_order, Handlers}, State0}. find_handler([{Object,Evh}|Evs], Object, Match) -> case match_handler(Match, Evh) of diff --git a/lib/wx/src/wxe_util.erl b/lib/wx/src/wxe_util.erl index 1983e6783a..398ceddd4f 100644 --- a/lib/wx/src/wxe_util.erl +++ b/lib/wx/src/wxe_util.erl @@ -127,8 +127,21 @@ connect_cb(Object,EvData0 = #evh{cb=Callback}) -> disconnect_cb(Object,EvData) -> Server = (wx:get_env())#wx_env.sv, - gen_server:call(Server, {disconnect_cb,Object,EvData}, infinity). - + {try_in_order, Handlers} = + gen_server:call(Server, {disconnect_cb,Object,EvData}, infinity), + disconnect(Object, Handlers). + +disconnect(Object,[Ev|Evs]) -> + try wxEvtHandler:disconnect_impl(Object,Ev) of + true -> true; + false -> disconnect(Object, Evs); + Error -> Error + catch _:_ -> + false + end; +disconnect(_, []) -> false. + + debug_cast(1, Op, _Args, _Port) -> check_previous(), case ets:lookup(wx_debug_info,Op) of diff --git a/lib/wx/test/wx_basic_SUITE.erl b/lib/wx/test/wx_basic_SUITE.erl index 2c746158e5..0b919f6254 100644 --- a/lib/wx/test/wx_basic_SUITE.erl +++ b/lib/wx/test/wx_basic_SUITE.erl @@ -338,6 +338,20 @@ data_types(_Config) -> ?m(true, is_boolean(wxCalendarCtrl:setDate(Cal,DateTime))), ?m({Date,_}, wxCalendarCtrl:getDate(Cal)), + %% Images, test sending and reading binaries + Colors = << <<200:8, 199:8, 198:8 >> || _ <- lists:seq(1, 128*64) >>, + Alpha = << <<255:8>> || _ <- lists:seq(1, 128*64) >>, + ImgRGB = ?mt(wxImage, wxImage:new(128, 64, Colors)), + ?m(true, wxImage:ok(ImgRGB)), + ?m(false, wxImage:hasAlpha(ImgRGB)), + ?m(Colors, wxImage:getData(ImgRGB)), + + ImgRGBA = ?mt(wxImage, wxImage:new(128, 64, Colors, Alpha)), + ?m(true, wxImage:ok(ImgRGBA)), + ?m(true, wxImage:hasAlpha(ImgRGBA)), + ?m(Colors, wxImage:getData(ImgRGBA)), + ?m(Alpha, wxImage:getAlpha(ImgRGBA)), + wxClientDC:destroy(CDC), %%wx_test_lib:wx_destroy(Frame,Config). wx:destroy(). diff --git a/lib/wx/test/wx_class_SUITE.erl b/lib/wx/test/wx_class_SUITE.erl index fd6023a820..876db9893f 100644 --- a/lib/wx/test/wx_class_SUITE.erl +++ b/lib/wx/test/wx_class_SUITE.erl @@ -386,13 +386,26 @@ listCtrlSort(Config) -> io:format("Sorted ~p ~n",[Time]), Item = wxListItem:new(), + + %% Test that wx-asserts are sent to error logger + %% Force an assert on 3.0 (when debug compiled which it is by default) + wxListItem:setId(Item, 200), + case os:type() of + {win32, _} -> + wxListItem:setColumn(Item, 3), + io:format("Got ~p ~n", [wxListCtrl:insertItem(LC, Item)]), + wxListItem:setColumn(Item, 0); + _ -> %% Uses generic listctrl + %% we can't use the code above on linux with wx-2.8.8 because it segfaults. + io:format("Got ~p ~n", [wxListCtrl:getItem(LC, Item)]) + end, + wxListItem:setMask(Item, ?wxLIST_MASK_TEXT), _List = wx:map(fun(Int) -> wxListItem:setId(Item, Int), ?m(true, wxListCtrl:getItem(LC, Item)), io:format("~p: ~s~n",[Int, wxListItem:getText(Item)]) end, lists:seq(0,10)), - wxListItem:destroy(Item), wx_test_lib:wx_destroy(Frame,Config). @@ -513,19 +526,23 @@ toolbar(Config) -> Wx = wx:new(), Frame = wxFrame:new(Wx, ?wxID_ANY, "Frame"), TB = wxFrame:createToolBar(Frame), - wxToolBar:addTool(TB, 747, "PressMe", wxArtProvider:getBitmap("wxART_COPY", [{size, {16,16}}]), + BM1 = wxArtProvider:getBitmap("wxART_COPY", [{size, {16,16}}, {client, "wxART_TOOLBAR"}]), + BM2 = wxArtProvider:getBitmap("wxART_TICK_MARK", [{size, {16,16}}, {client, "wxART_TOOLBAR"}]), + wxToolBar:addTool(TB, 747, "PressMe", BM1, [{shortHelp, "Press Me"}]), - + catch wxToolBar:addStretchableSpace(TB), %% wxWidgets 3.0 only Add = fun(#wx{}, _) -> - wxToolBar:addTool(TB, -1, "Added", wxArtProvider:getBitmap("wxART_TICK_MARK", [{size, {16,16}}]), - [{shortHelp, "Test 2 popup text"}]) + wxToolBar:addTool(TB, -1, "Added", BM2, + [{shortHelp, "Test 2 popup text"}]), + catch wxToolBar:addStretchableSpace(TB), %% wxWidgets 3.0 only + wxToolBar:realize(TB) end, + wxToolBar:realize(TB), wxFrame:connect(Frame, command_menu_selected, [{callback, Add}, {id, 747}]), wxFrame:show(Frame), wx_test_lib:wx_destroy(Frame,Config). - popup(TestInfo) when is_atom(TestInfo) -> wx_test_lib:tc_info(TestInfo); popup(Config) -> Wx = wx:new(), @@ -575,3 +592,32 @@ popup(Config) -> wxPopupTransientWindow:dismiss(Pop) end, wx_test_lib:wx_destroy(Frame,Config). + +locale(TestInfo) when is_atom(TestInfo) -> wx_test_lib:tc_info(TestInfo); +locale(_Config) -> + wx:new(), + io:format("SystemEncoding: ~p~n",[wxLocale:getSystemEncoding()]), + io:format("SystemEncodingName: ~ts~n",[wxLocale:getSystemEncodingName()]), + io:format("SystemLanguage: ~p~n",[wxLocale:getSystemLanguage()]), + io:format("SystemLanguageName: ~p~n",[wxLocale:getLanguageName(wxLocale:getSystemLanguage())]), + lang_env(), + LC = wxLocale:new(), + %% wxLocale:addCatalog(LC, "wxstd"), + io:format("Swedish: ~p~n",[wxLocale:getLanguageName(?wxLANGUAGE_SWEDISH)]), + R0 = wxLocale:init(LC, [{language, ?wxLANGUAGE_SWEDISH}, {flags, 0}]), + io:format("initiated ~p~n",[R0]), + lang_env(), + ok. +%% wx_test_lib:wx_destroy(Frame,Config). + +lang_env() -> + Env0 = os:getenv(), + Env = [[R,"\n"]||R <- Env0], + %%io:format("~p~n",[lists:sort(Env)]), + Opts = [global, multiline, {capture, all, list}], + format_env(re:run(Env, "LC_ALL.*", Opts)), + format_env(re:run(Env, "^LANG.*=.*$", Opts)), + ok. +format_env({match, List}) -> + [io:format(" ~ts~n",[L]) || L <- List]; +format_env(nomatch) -> ok. diff --git a/lib/wx/test/wx_event_SUITE.erl b/lib/wx/test/wx_event_SUITE.erl index 2d6f7b6aaa..516133e3e2 100644 --- a/lib/wx/test/wx_event_SUITE.erl +++ b/lib/wx/test/wx_event_SUITE.erl @@ -46,8 +46,8 @@ end_per_testcase(Func,Config) -> %% SUITE specification suite() -> [{ct_hooks,[ts_install_cth]}]. -all() -> - [connect, disconnect, connect_msg_20, connect_cb_20, +all() -> + [connect, disconnect, disconnect_cb, connect_msg_20, connect_cb_20, mouse_on_grid, spin_event, connect_in_callback, recursive, dialog, char_events, callback_clean ]. @@ -78,7 +78,6 @@ connect(Config) -> Tester ! {got_size, UserD} end, - ?m(ok, wxFrame:connect(Frame, size)), ?m(ok, wxEvtHandler:connect(Panel, size,[{skip, true},{userData, panel}])), ?m(ok, wxEvtHandler:connect(Panel, size,[{callback,CB},{userData, panel}])), @@ -91,12 +90,16 @@ connect(Config) -> ?m(ok, wxWindow:connect(Window, size,[{callback,CB},{userData, window}])), ?m(ok, wxWindow:connect(Window, size,[{skip,true},{userData, window}])), + %% For trivial side effect free callbacks, can deadlock easily otherwise + CB1 = fun(_,_) -> Tester ! {got_size, nospawn_cb} end, + ?m(ok, wxWindow:connect(Frame, size, [{callback,{nospawn, CB1}}])), + ?m(ok, wxFrame:connect(Frame, size, [{skip, true}])), ?m(true, wxFrame:show(Frame)), wxWindow:setSize(Panel, {200,100}), wxWindow:setSize(Window, {200,100}), - get_size_messages(Frame, [frame, panel_cb, window_cb, window]), + get_size_messages(Frame, [frame, panel_cb, window_cb, window, nospawn_cb]), wx_test_lib:wx_destroy(Frame, Config). @@ -115,7 +118,9 @@ get_size_messages(Frame, Msgs) -> ?m(false, lists:member(window, Msgs)), get_size_messages(Frame, lists:delete(window_cb, Msgs)); {got_size,panel} -> - get_size_messages(Frame, lists:delete(panel_cb, Msgs)); + get_size_messages(Frame, lists:delete(panel_cb, Msgs)); + {got_size,nospawn_cb} -> + get_size_messages(Frame, lists:delete(nospawn_cb, Msgs)); Other -> ?error("Got unexpected msg ~p ~p~n", [Other,Msgs]) after 1000 -> @@ -157,9 +162,33 @@ disconnect(Config) -> ?m([], wx_test_lib:flush()), wx_test_lib:wx_destroy(Frame, Config). - + +disconnect_cb(TestInfo) when is_atom(TestInfo) -> wx_test_lib:tc_info(TestInfo); +disconnect_cb(Config) -> + ?mr(wx_ref, wx:new()), + Frame = ?mt(wxFrame, wxFrame:new(wx:null(), 1, "Event Testing")), + Panel = ?mt(wxPanel, wxPanel:new(Frame)), + + Tester = self(), + CB = fun(#wx{event=#wxSize{},userData=UserD}, SizeEvent) -> + ?mt(wxSizeEvent, SizeEvent), + wxEvtHandler:disconnect(Frame, close_window), + Tester ! {got_size, UserD} + end, + ?m(ok, wxFrame:connect(Frame, close_window)), + ?m(ok, wxFrame:connect(Frame, size)), + ?m(ok, wxEvtHandler:connect(Panel, size, [{callback,CB},{userData, panel}])), + + ?m(true, wxFrame:show(Frame)), + + wxWindow:setSize(Panel, {200,100}), + get_size_messages(Frame, [frame, panel_cb]), + wx_test_lib:flush(), + + wx_test_lib:wx_destroy(Frame, Config). + %% Test that the msg events are forwarded as supposed to connect_msg_20(TestInfo) when is_atom(TestInfo) -> wx_test_lib:tc_info(TestInfo); diff --git a/lib/wx/vsn.mk b/lib/wx/vsn.mk index 09fb9f384c..de723b2a2d 100644 --- a/lib/wx/vsn.mk +++ b/lib/wx/vsn.mk @@ -1 +1 @@ -WX_VSN = 1.4 +WX_VSN = 1.6.1 diff --git a/lib/xmerl/doc/src/notes.xml b/lib/xmerl/doc/src/notes.xml index a1558b224f..55367eb25e 100644 --- a/lib/xmerl/doc/src/notes.xml +++ b/lib/xmerl/doc/src/notes.xml @@ -32,6 +32,36 @@ <p>This document describes the changes made to the Xmerl application.</p> +<section><title>Xmerl 1.3.10</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> Suppress Dialyzer warnings. </p> + <p> + Own Id: OTP-12862</p> + </item> + </list> + </section> + +</section> + +<section><title>Xmerl 1.3.9</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Removed the built-in definitions of xml.xsd from the + xmerl_xsd module.</p> + <p> + Own Id: OTP-13070</p> + </item> + </list> + </section> + +</section> + <section><title>Xmerl 1.3.8</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/xmerl/src/xmerl_sax_parser_base.erlsrc b/lib/xmerl/src/xmerl_sax_parser_base.erlsrc index 2bbe0eea1a..2c5caab07b 100644 --- a/lib/xmerl/src/xmerl_sax_parser_base.erlsrc +++ b/lib/xmerl/src/xmerl_sax_parser_base.erlsrc @@ -152,6 +152,7 @@ parse_document(Rest, State) when is_record(State, xmerl_sax_parser_state) -> %% [22] prolog ::= XMLDecl? Misc* (doctypedecl Misc*)? %% [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>' %%---------------------------------------------------------------------- +-dialyzer({[no_fail_call, no_match], parse_xml_decl/2}). parse_xml_decl(?STRING_EMPTY, State) -> cf(?STRING_EMPTY, State, fun parse_xml_decl/2); parse_xml_decl(?BYTE_ORDER_MARK_1, State) -> @@ -1205,6 +1206,7 @@ send_character_event(_, true, String, State) -> %% Description: Parse whitespaces. %% [3] S ::= (#x20 | #x9 | #xD | #xA)+ %%---------------------------------------------------------------------- +-dialyzer({no_fail_call, whitespace/3}). whitespace(?STRING_EMPTY, State, Acc) -> case cf(?STRING_EMPTY, State, Acc, fun whitespace/3) of {?STRING_EMPTY, State} -> @@ -1716,6 +1718,7 @@ handle_external_entity({Tag, _Url}, State) -> %% Result : {Rest, State} %% Description: Parse the external entity. %%---------------------------------------------------------------------- +-dialyzer({[no_fail_call, no_match], parse_external_entity_1/2}). parse_external_entity_1(?STRING_EMPTY, #xmerl_sax_parser_state{file_type=Type} = State) -> case catch cf(?STRING_EMPTY, State, fun parse_external_entity_1/2) of {Rest, State1} when is_record(State1, xmerl_sax_parser_state) -> diff --git a/lib/xmerl/src/xmerl_scan.erl b/lib/xmerl/src/xmerl_scan.erl index 2bf3172d87..829716dcdb 100644 --- a/lib/xmerl/src/xmerl_scan.erl +++ b/lib/xmerl/src/xmerl_scan.erl @@ -1010,7 +1010,7 @@ scan_optional_version(T,S) -> scan_enc_name([], S=#xmerl_scanner{continuation_fun = F}) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_enc_name(MoreBytes, S1) end, - fun(S1) -> ?fatal(expected_encoding_name, S1) end, + fatal_fun(expected_encoding_name), S); scan_enc_name([H|T], S0) when H >= $"; H =< $' -> ?bump_col(1), @@ -1020,7 +1020,7 @@ scan_enc_name([H|T], S0) when H >= $"; H =< $' -> scan_enc_name([], S=#xmerl_scanner{continuation_fun = F}, Delim, Acc) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_enc_name(MoreBytes, S1, Delim, Acc) end, - fun(S1) -> ?fatal(expected_encoding_name, S1) end, + fatal_fun(expected_encoding_name), S); scan_enc_name([H|T], S0, Delim, Acc) when H >= $a, H =< $z -> ?bump_col(1), @@ -1034,7 +1034,7 @@ scan_enc_name([H|_T],S,_Delim,_Acc) -> scan_enc_name2([], S=#xmerl_scanner{continuation_fun = F}, Delim, Acc) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_enc_name2(MoreBytes, S1, Delim, Acc) end, - fun(S1) -> ?fatal(expected_encoding_name, S1) end, + fatal_fun(expected_encoding_name), S); scan_enc_name2([H|T], S0, H, Acc) -> ?bump_col(1), @@ -1058,7 +1058,7 @@ scan_enc_name2([H|T], S0, Delim, Acc) when H == $.; H == $_; H == $- -> scan_xml_vsn([], S=#xmerl_scanner{continuation_fun = F}) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_xml_vsn(MoreBytes, S1) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_xml_vsn([H|T], S) when H==$"; H==$'-> xml_vsn(T, S#xmerl_scanner{col = S#xmerl_scanner.col+1}, H, []). @@ -1066,7 +1066,7 @@ scan_xml_vsn([H|T], S) when H==$"; H==$'-> xml_vsn([], S=#xmerl_scanner{continuation_fun = F}, Delim, Acc) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> xml_vsn(MoreBytes, S1, Delim, Acc) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); xml_vsn([H|T], S=#xmerl_scanner{col = C}, H, Acc) -> {lists:reverse(Acc), T, S#xmerl_scanner{col = C+1}}; @@ -1089,7 +1089,7 @@ xml_vsn([H|T], S=#xmerl_scanner{col = C}, Delim, Acc) -> scan_pi([], S=#xmerl_scanner{continuation_fun = F}, Pos, Ps) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_pi(MoreBytes, S1, Pos, Ps) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_pi(Str = [H1,H2,H3 | T],S0=#xmerl_scanner{line = L, col = C}, Pos, Ps) when H1==$x;H1==$X -> @@ -1125,7 +1125,7 @@ scan_pi([], S=#xmerl_scanner{continuation_fun = F}, Target, ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_pi(MoreBytes, S1, Target, L, C, Pos, Ps, Acc) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_pi("?>" ++ T, S0 = #xmerl_scanner{hook_fun = Hook, event_fun = Event}, @@ -1152,7 +1152,7 @@ scan_pi2([], S=#xmerl_scanner{continuation_fun = F}, Target, ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_pi2(MoreBytes, S1, Target, L, C, Pos, Ps, Acc) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_pi2("?>" ++ T, S0 = #xmerl_scanner{hook_fun = Hook, event_fun = Event}, @@ -1180,7 +1180,7 @@ scan_pi2(Str, S0, Target, L, C, Pos, Ps, Acc) -> scan_doctype([], S=#xmerl_scanner{continuation_fun = F}) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_doctype(MoreBytes, S1) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_doctype(T, S) -> {_,T1,S1} = mandatory_strip(T,S), @@ -1194,7 +1194,7 @@ scan_doctype(T, S) -> scan_doctype1([], S=#xmerl_scanner{continuation_fun = F}) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_doctype1(MoreBytes, S1) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_doctype1("PUBLIC" ++ T, S0) -> ?bump_col(6), @@ -1217,7 +1217,7 @@ scan_doctype1(T, S) -> scan_doctype2([], S=#xmerl_scanner{continuation_fun = F},DTD) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_doctype2(MoreBytes, S1, DTD) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_doctype2("[" ++ T, S0, DTD) -> ?bump_col(1), @@ -1237,7 +1237,7 @@ scan_doctype2(_T,S,_DTD) -> scan_doctype3([], S=#xmerl_scanner{continuation_fun = F},DTD) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_doctype3(MoreBytes, S1,DTD) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_doctype3("%" ++ T, S0, DTD) -> ?bump_col(1), @@ -1549,7 +1549,7 @@ scan_decl_sep(T,S) -> scan_conditional_sect([], S=#xmerl_scanner{continuation_fun = F}) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_conditional_sect(MoreBytes, S1) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_conditional_sect("IGNORE" ++ T, S0) -> ?bump_col(6), @@ -1582,7 +1582,7 @@ scan_ignore(Str,S) -> scan_ignore([], S=#xmerl_scanner{continuation_fun = F},Level) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_ignore(MoreBytes, S1,Level) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_ignore("<![" ++ T, S0,Level) -> %% nested conditional section. Topmost condition is ignore, though @@ -1603,7 +1603,7 @@ scan_ignore([_H|T],S0,Level) -> scan_include([], S=#xmerl_scanner{continuation_fun = F}) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_include(MoreBytes, S1) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_include("]]>" ++ T, S0) -> ?bump_col(3), @@ -1745,7 +1745,7 @@ update_attributes1([],Acc) -> scan_attdef([], S=#xmerl_scanner{continuation_fun = F}) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_attdef(MoreBytes, S1) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_attdef(T, S) -> scan_attdef(T, S, _AttrAcc = []). @@ -1754,7 +1754,7 @@ scan_attdef(T, S) -> scan_attdef([], S=#xmerl_scanner{continuation_fun = F}, Attrs) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_attdef(MoreBytes, S1, Attrs) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_attdef(">" ++ T, S0, Attrs) -> ?bump_col(1), @@ -1798,7 +1798,7 @@ scan_attdef2(T, S, Attrs) -> scan_att_type([], S=#xmerl_scanner{continuation_fun = F}) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_att_type(MoreBytes, S1) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_att_type("CDATA" ++ T, S0) -> ?bump_col(5), @@ -1856,7 +1856,7 @@ scan_att_type("%" ++ T, S0) -> scan_notation_type([], S=#xmerl_scanner{continuation_fun = F}, Acc) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_notation_type(MoreBytes, S1, Acc) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_notation_type(")" ++ T, S0, Acc) -> ?bump_col(1), @@ -1889,7 +1889,7 @@ notation_exists(Name, #xmerl_scanner{rules_read_fun = Read, scan_enumeration([], S=#xmerl_scanner{continuation_fun = F}, Acc) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_enumeration(MoreBytes, S1, Acc) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_enumeration(")" ++ T, S0, Acc) -> ?bump_col(1), @@ -1907,7 +1907,7 @@ scan_enumeration("|" ++ T, S0, Acc) -> scan_default_decl([], S=#xmerl_scanner{continuation_fun = F}, Type) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_default_decl(MoreBytes, S1, Type) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_default_decl("#REQUIRED" ++ T, S0, _Type) -> ?bump_col(9), @@ -1936,7 +1936,7 @@ default_value(T, S, Type) -> scan_entity([], S=#xmerl_scanner{continuation_fun = F}) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_entity(MoreBytes, S1) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_entity("%" ++ T, #xmerl_scanner{rules_write_fun = Write} = S0) -> %% parameter entity @@ -1974,7 +1974,7 @@ scan_entity_completion(T,S) -> scan_entity_def([], S=#xmerl_scanner{continuation_fun = F}, EName) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_entity_def(MoreBytes, S1, EName) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_entity_def("'" ++ T, S0, EName) -> ?bump_col(1), @@ -2015,7 +2015,7 @@ scan_entity_def(Str, S, EName) -> scan_ndata_decl([], S=#xmerl_scanner{continuation_fun = F}) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_ndata_decl(MoreBytes, S1) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_ndata_decl(Str = ">"++_T, S) -> {[], Str, S}; @@ -2062,7 +2062,7 @@ scan_element("/", S=#xmerl_scanner{continuation_fun = F}, F(fun(MoreBytes, S1) -> scan_element("/" ++ MoreBytes, S1, Pos, Name, StartL, StartC, Attrs, Lang,Parents,NSI,NS,SpaceDefault) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_element([], S=#xmerl_scanner{continuation_fun = F}, Pos, Name, StartL, StartC, Attrs, Lang, Parents, @@ -2071,7 +2071,7 @@ scan_element([], S=#xmerl_scanner{continuation_fun = F}, F(fun(MoreBytes, S1) -> scan_element(MoreBytes, S1, Pos, Name, StartL, StartC, Attrs, Lang,Parents,NSI,NS,SpaceDefault) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_element("/>" ++ T, S0 = #xmerl_scanner{hook_fun = Hook, event_fun = Event, @@ -2099,7 +2099,7 @@ scan_element(">", S=#xmerl_scanner{continuation_fun = F}, F(fun(MoreBytes, S1) -> scan_element(">" ++ MoreBytes, S1, Pos, Name, StartL, StartC, Attrs, Lang,Parents,NSI,NS,SpaceDefault) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_element(">" ++ T, S0 = #xmerl_scanner{event_fun = Event, hook_fun = Hook, @@ -2344,7 +2344,7 @@ keyreplaceadd(_K, _Pos, [], Obj) -> scan_att_value([], S=#xmerl_scanner{continuation_fun = F},AT) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_att_value(MoreBytes, S1, AT) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_att_value("%"++_T,S=#xmerl_scanner{environment=prolog},_AttType) -> ?fatal({error,{wfc_PEs_In_Internal_Subset}},S); @@ -2385,7 +2385,7 @@ scan_att_chars([],S=#xmerl_scanner{continuation_fun=F},H,Acc,TmpAcc,AT,IsNorm)-> F(fun(MoreBytes, S1) -> scan_att_chars(MoreBytes, S1, H, Acc,TmpAcc,AT,IsNorm) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_att_chars([H|T], S0, H, Acc, TmpAcc,AttType,IsNorm) -> % End quote ?bump_col(1), @@ -2518,7 +2518,7 @@ scan_content("<", S= #xmerl_scanner{continuation_fun = F}, F(fun(MoreBytes, S1) -> scan_content("<" ++ MoreBytes, S1, Pos, Name, Attrs, Space, Lang, Parents, NS, Acc,[]) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_content([], S=#xmerl_scanner{environment={external,{entity,_}}}, _Pos, _Name, _Attrs, _Space, _Lang, _Parents, _NS, Acc,_) -> @@ -2532,7 +2532,7 @@ scan_content([], S=#xmerl_scanner{continuation_fun = F}, F(fun(MoreBytes, S1) -> scan_content(MoreBytes, S1, Pos, Name, Attrs, Space, Lang, Parents, NS, Acc,[]) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_content("</" ++ T, S0, _Pos, Name, _Attrs, _Space, _Lang, _Parents, _NS, Acc,[]) -> @@ -2636,7 +2636,7 @@ scan_content_markup([], S=#xmerl_scanner{continuation_fun = F}, F(fun(MoreBytes, S1) -> scan_content_markup( MoreBytes,S1,Pos,Name, Attrs,Space,Lang,Parents,NS) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_content_markup("![CDATA[" ++ T, S0, Pos, _Name, _Attrs, _Space, _Lang, Parents, _NS) -> @@ -2664,7 +2664,7 @@ scan_char_data([], S=#xmerl_scanner{environment=internal_parsed_entity}, scan_char_data([], S=#xmerl_scanner{continuation_fun = F}, Space, _MUD,Acc) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_char_data(MoreBytes,S1,Space,_MUD,Acc) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_char_data([$&|T], S,Space,"&",Acc) -> scan_char_data(T, S, Space,[], [$&|Acc]); @@ -2716,7 +2716,7 @@ scan_cdata(Str, S, Pos, Parents) -> scan_cdata([], S=#xmerl_scanner{continuation_fun = F}, Pos, Parents, Acc) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_cdata(MoreBytes, S1, Pos, Parents, Acc) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_cdata("]]>" ++ T, S0, Pos, Parents, Acc) -> ?bump_col(3), @@ -2741,7 +2741,7 @@ scan_cdata(Str, S0, Pos, Parents, Acc) -> scan_reference([], S=#xmerl_scanner{continuation_fun = F}) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_reference(MoreBytes, S1) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_reference("#x" ++ T, S0) -> %% [66] CharRef @@ -2783,7 +2783,7 @@ scan_reference(T, S) -> scan_entity_ref([], S=#xmerl_scanner{continuation_fun = F}) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_entity_ref(MoreBytes, S1) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_entity_ref("amp;" ++ T, S0) -> ?bump_col(4), @@ -2868,7 +2868,7 @@ expand_reference(Name, #xmerl_scanner{rules_read_fun = Read} = S) -> scan_char_ref_dec([], S=#xmerl_scanner{continuation_fun = F}, Acc) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_char_ref_dec(MoreBytes, S1, Acc) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_char_ref_dec([H|T], S0, Acc) when H >= $0, H =< $9 -> ?bump_col(1), @@ -2883,7 +2883,7 @@ scan_char_ref_dec(";" ++ T, S0, Acc) -> scan_char_ref_hex([], S=#xmerl_scanner{continuation_fun = F}, Acc) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_char_ref_hex(MoreBytes, S1, Acc) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_char_ref_hex([H|T], S0, Acc) when H >= $0, H =< $9 -> ?bump_col(1), @@ -2957,7 +2957,7 @@ scan_name_no_colons(Str, S) -> scan_name([], S=#xmerl_scanner{continuation_fun = F}) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_name(MoreBytes, S1) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_name(Str = [$:|T], S0 = #xmerl_scanner{namespace_conformant = NSC}) -> if NSC == false -> @@ -3007,7 +3007,7 @@ scan_nmtoken(Str, S, Acc, NSC) -> scan_nmtoken([], S=#xmerl_scanner{continuation_fun = F}) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_nmtoken(MoreBytes, S1) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_nmtoken("%"++T, S0=#xmerl_scanner{environment={external,_}}) -> ?bump_col(1), @@ -3084,7 +3084,7 @@ isLatin1(_,_) -> scan_system_literal([], S=#xmerl_scanner{continuation_fun = F}) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_system_literal(MoreBytes, S1) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_system_literal("\"" ++ T, S) -> scan_system_literal(T, S, $", []); @@ -3096,7 +3096,7 @@ scan_system_literal([], S=#xmerl_scanner{continuation_fun = F}, Delimiter, Acc) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_system_literal(MoreBytes,S1,Delimiter,Acc) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_system_literal([H|T], S, H, Acc) -> {lists:reverse(Acc), T, S#xmerl_scanner{col = S#xmerl_scanner.col+1}}; @@ -3114,7 +3114,7 @@ scan_system_literal(Str, S, Delimiter, Acc) -> scan_pubid_literal([], S=#xmerl_scanner{continuation_fun = F}) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_pubid_literal(MoreBytes, S1) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_pubid_literal([H|T], S) when H == $"; H == $' -> scan_pubid_literal(T, S#xmerl_scanner{col = S#xmerl_scanner.col+1}, H, []); @@ -3126,7 +3126,7 @@ scan_pubid_literal([], S=#xmerl_scanner{continuation_fun = F}, Delimiter, Acc) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_pubid_literal(MoreBytes,S1,Delimiter,Acc) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_pubid_literal([H|T], S, H, Acc) -> {lists:reverse(Acc), T, S#xmerl_scanner{col = S#xmerl_scanner.col+1}}; @@ -3161,7 +3161,7 @@ is_pubid_char(X) -> scan_contentspec([], S=#xmerl_scanner{continuation_fun = F}) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_contentspec(MoreBytes, S1) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_contentspec("EMPTY" ++ T, S0) -> ?bump_col(5), @@ -3195,7 +3195,7 @@ scan_elem_content([], S=#xmerl_scanner{continuation_fun = F}, Context, Mode, Acc) -> ?dbg("cont()...~n", []), F(fun(MoreBytes,S1) -> scan_elem_content(MoreBytes,S1,Context,Mode,Acc) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_elem_content(")" ++ T, S0, Context, Mode0, Acc0) -> ?bump_col(1), @@ -3282,7 +3282,7 @@ format_elem_content(Other) -> Other. scan_occurrence([], S=#xmerl_scanner{continuation_fun = F}) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_occurrence(MoreBytes, S1) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_occurrence([$?|T], S0) -> ?bump_col(1), @@ -3433,7 +3433,7 @@ wfc_whitespace_betw_attrs([$> |_]=L,S) -> wfc_whitespace_betw_attrs([],S=#xmerl_scanner{continuation_fun = F}) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> wfc_whitespace_betw_attrs(MoreBytes, S1) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); wfc_whitespace_betw_attrs(_,S) -> ?fatal({whitespace_required_between_attributes},S). @@ -3477,7 +3477,7 @@ vc_Element_valid(_,_) -> scan_pe_def([], S=#xmerl_scanner{continuation_fun = F}, PEName) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_pe_def(MoreBytes, S1, PEName) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_pe_def("'" ++ T, S0, PEName) -> ?bump_col(1), @@ -3510,7 +3510,7 @@ scan_notation_decl(T, #xmerl_scanner{rules_write_fun = Write, scan_notation_decl1([], S=#xmerl_scanner{continuation_fun = F}) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_notation_decl1(MoreBytes, S1) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_notation_decl1("SYSTEM" ++ T, S0) -> ?bump_col(6), @@ -3536,7 +3536,7 @@ scan_notation_decl1("PUBLIC" ++ T, S0) -> scan_external_id([], S=#xmerl_scanner{continuation_fun = F}) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_external_id(MoreBytes, S1) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_external_id("SYSTEM" ++ T, S0) -> ?bump_col(6), @@ -3582,7 +3582,7 @@ scan_entity_value([], S=#xmerl_scanner{continuation_fun = F}, scan_entity_value(MoreBytes,S1, Delim,Acc,PEName,Namespace,PENesting) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_entity_value([Delim|T], S=#xmerl_scanner{validation=dtd}, Delim,_Acc,PEName,_NS,PENesting) when length(PENesting) /= 0 -> @@ -3850,7 +3850,7 @@ scan_comment1([], S=#xmerl_scanner{continuation_fun = F}, Pos, Comment, Acc) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_comment1(MoreBytes, S1, Pos, Comment, Acc) end, - fun(S1) -> ?fatal(unexpected_end, S1) end, + fatal_fun(unexpected_end), S); scan_comment1("-->" ++ T, S0 = #xmerl_scanner{col = C, event_fun = Event, @@ -4100,6 +4100,13 @@ handle_schema_result({error,Reason},S5) -> %%% Helper functions +-compile({inline, [fatal_fun/1]}). + +-spec fatal_fun(_) -> fun((_) -> no_return()). + +fatal_fun(Reason) -> + fun(S) -> ?fatal(Reason, S) end. + fatal(Reason, S) -> exit({fatal, {Reason, {file,S#xmerl_scanner.filename}, diff --git a/lib/xmerl/src/xmerl_xsd.erl b/lib/xmerl/src/xmerl_xsd.erl index 847161e844..3038a54ee6 100644 --- a/lib/xmerl/src/xmerl_xsd.erl +++ b/lib/xmerl/src/xmerl_xsd.erl @@ -4888,7 +4888,6 @@ mk_EII_Att_QName(AttName,XMLEl,S) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% create_tables(S=#xsd_state{table=undefined}) -> Tid=ets:new(xmerl_schema_tab,[]), - initial_tab_data(Tid), S#xsd_state{table=Tid}; create_tables(S) -> S. @@ -5617,131 +5616,5 @@ format_error(Err) -> %% {shema_el_pathname(SchemaE,Env), %% xml_el_pathname(E)}. -initial_tab_data(Tab) -> - ets:insert(Tab, - binary_to_term( - <<131,108,0,0,0,9,104,2,104,2,100,0,9,97,116,116,114,105,98,117,116, - 101,104,3,100,0,5,115,112,97,99,101,106,100,0,36,104,116,116,112,58, - 47,47,119,119,119,46,119,51,46,111,114,103,47,88,77,76,47,49,57,57, - 56,47,110,97,109,101,115,112,97,99,101,104,9,100,0,16,115,99,104,101, - 109,97,95,97,116,116,114,105,98,117,116,101,104,3,100,0,5,115,112,97, - 99,101,106,100,0,36,104,116,116,112,58,47,47,119,119,119,46,119,51, - 46,111,114,103,47,88,77,76,47,49,57,57,56,47,110,97,109,101,115,112, - 97,99,101,108,0,0,0,1,104,2,100,0,10,115,105,109,112,108,101,84,121, - 112,101,104,3,100,0,15,95,120,109,101,114,108,95,110,111,95,110,97, - 109,101,95,108,0,0,0,1,100,0,5,115,112,97,99,101,106,106,106,100,0,5, - 102,97,108,115,101,106,100,0,8,111,112,116,105,111,110,97,108,100,0,9, - 117,110,100,101,102,105,110,101,100,100,0,9,117,110,100,101,102,105, - 110,101,100,100,0,9,117,110,100,101,102,105,110,101,100,104,2,104,2, - 100,0,6,115,99,104,101,109,97,107,0,7,120,109,108,46,120,115,100,104, - 7,100,0,6,115,99,104,101,109,97,100,0,11,117,110,113,117,97,108,105, - 102,105,101,100,100,0,11,117,110,113,117,97,108,105,102,105,101,100, - 100,0,36,104,116,116,112,58,47,47,119,119,119,46,119,51,46,111,114, - 103,47,88,77,76,47,49,57,57,56,47,110,97,109,101,115,112,97,99,101, - 106,106,106,104,2,104,2,100,0,9,97,116,116,114,105,98,117,116,101, - 104,3,100,0,4,98,97,115,101,106,100,0,36,104,116,116,112,58,47,47, - 119,119,119,46,119,51,46,111,114,103,47,88,77,76,47,49,57,57,56,47, - 110,97,109,101,115,112,97,99,101,104,9,100,0,16,115,99,104,101,109, - 97,95,97,116,116,114,105,98,117,116,101,104,3,100,0,4,98,97,115,101, - 106,100,0,36,104,116,116,112,58,47,47,119,119,119,46,119,51,46,111, - 114,103,47,88,77,76,47,49,57,57,56,47,110,97,109,101,115,112,97,99, - 101,108,0,0,0,1,104,2,100,0,10,115,105,109,112,108,101,84,121,112,101, - 104,3,100,0,6,97,110,121,85,82,73,106,100,0,32,104,116,116,112,58,47, - 47,119,119,119,46,119,51,46,111,114,103,47,50,48,48,49,47,88,77,76,83, - 99,104,101,109,97,106,100,0,5,102,97,108,115,101,106,100,0,8,111,112, - 116,105,111,110,97,108,100,0,9,117,110,100,101,102,105,110,101,100, - 100,0,9,117,110,100,101,102,105,110,101,100,100,0,9,117,110,100,101, - 102,105,110,101,100,104,2,104,2,100,0,14,97,116,116,114,105,98,117, - 116,101,71,114,111,117,112,104,3,100,0,12,115,112,101,99,105,97,108, - 65,116,116,114,115,106,100,0,36,104,116,116,112,58,47,47,119,119,119, - 46,119,51,46,111,114,103,47,88,77,76,47,49,57,57,56,47,110,97,109,101, - 115,112,97,99,101,104,5,100,0,22,115,99,104,101,109,97,95,97,116,116, - 114,105,98,117,116,101,95,103,114,111,117,112,104,3,100,0,12,115,112, - 101,99,105,97,108,65,116,116,114,115,106,100,0,36,104,116,116,112,58, - 47,47,119,119,119,46,119,51,46,111,114,103,47,88,77,76,47,49,57,57, - 56,47,110,97,109,101,115,112,97,99,101,100,0,9,117,110,100,101,102, - 105,110,101,100,100,0,9,117,110,100,101,102,105,110,101,100,108,0,0, - 0,3,104,2,100,0,9,97,116,116,114,105,98,117,116,101,104,3,100,0,4,98, - 97,115,101,106,106,104,2,100,0,9,97,116,116,114,105,98,117,116,101, - 104,3,100,0,4,108,97,110,103,106,106,104,2,100,0,9,97,116,116,114, - 105,98,117,116,101,104,3,100,0,5,115,112,97,99,101,106,106,106,104, - 2,104,2,100,0,10,115,105,109,112,108,101,84,121,112,101,104,3,100,0, - 15,95,120,109,101,114,108,95,110,111,95,110,97,109,101,95,108,0,0,0, - 1,100,0,5,115,112,97,99,101,106,106,104,9,100,0,18,115,99,104,101, - 109,97,95,115,105,109,112,108,101,95,116,121,112,101,104,3,100,0,15, - 95,120,109,101,114,108,95,110,111,95,110,97,109,101,95,108,0,0,0,1, - 100,0,5,115,112,97,99,101,106,106,108,0,0,0,1,100,0,5,115,112,97,99, - 101,106,104,3,100,0,6,78,67,78,97,109,101,106,100,0,32,104,116,116, - 112,58,47,47,119,119,119,46,119,51,46,111,114,103,47,50,48,48,49,47, - 88,77,76,83,99,104,101,109,97,100,0,5,102,97,108,115,101,106,108,0,0, - 0,1,104,2,100,0,11,101,110,117,109,101,114,97,116,105,111,110,108,0,0, - 0,2,107,0,7,100,101,102,97,117,108,116,107,0,8,112,114,101,115,101, - 114,118,101,106,106,100,0,6,97,116,111,109,105,99,108,0,0,0,1,104,2, - 100,0,11,114,101,115,116,114,105,99,116,105,111,110,104,2,104,3,100, - 0,6,78,67,78,97,109,101,106,100,0,32,104,116,116,112,58,47,47,119, - 119,119,46,119,51,46,111,114,103,47,50,48,48,49,47,88,77,76,83,99, - 104,101,109,97,108,0,0,0,2,104,2,100,0,11,101,110,117,109,101,114, - 97,116,105,111,110,107,0,7,100,101,102,97,117,108,116,104,2,100,0, - 11,101,110,117,109,101,114,97,116,105,111,110,107,0,8,112,114,101, - 115,101,114,118,101,106,106,104,2,104,2,100,0,10,115,105,109,112, - 108,101,84,121,112,101,104,3,100,0,15,95,120,109,101,114,108,95,110, - 111,95,110,97,109,101,95,108,0,0,0,1,100,0,4,108,97,110,103,106,106, - 104,9,100,0,18,115,99,104,101,109,97,95,115,105,109,112,108,101,95, - 116,121,112,101,104,3,100,0,15,95,120,109,101,114,108,95,110,111,95, - 110,97,109,101,95,108,0,0,0,1,100,0,4,108,97,110,103,106,106,108,0,0, - 0,1,100,0,4,108,97,110,103,106,100,0,9,117,110,100,101,102,105,110, - 101,100,100,0,5,102,97,108,115,101,106,106,100,0,6,97,116,111,109, - 105,99,108,0,0,0,1,104,2,100,0,5,117,110,105,111,110,108,0,0,0,2,104, - 2,100,0,10,115,105,109,112,108,101,84,121,112,101,104,3,100,0,8,108, - 97,110,103,117,97,103,101,106,100,0,32,104,116,116,112,58,47,47,119, - 119,119,46,119,51,46,111,114,103,47,50,48,48,49,47,88,77,76,83,99,104, - 101,109,97,104,2,100,0,10,115,105,109,112,108,101,84,121,112,101,104, - 3,100,0,15,95,120,109,101,114,108,95,110,111,95,110,97,109,101,95,108, - 0,0,0,2,100,0,15,95,120,109,101,114,108,95,110,111,95,110,97,109,101, - 95,100,0,4,108,97,110,103,106,106,106,106,104,2,104,2,100,0,9,97,116, - 116,114,105,98,117,116,101,104,3,100,0,2,105,100,106,100,0,36,104,116, - 116,112,58,47,47,119,119,119,46,119,51,46,111,114,103,47,88,77,76,47, - 49,57,57,56,47,110,97,109,101,115,112,97,99,101,104,9,100,0,16,115,99, - 104,101,109,97,95,97,116,116,114,105,98,117,116,101,104,3,100,0,2,105, - 100,106,100,0,36,104,116,116,112,58,47,47,119,119,119,46,119,51,46, - 111,114,103,47,88,77,76,47,49,57,57,56,47,110,97,109,101,115,112,97, - 99,101,108,0,0,0,1,104,2,100,0,10,115,105,109,112,108,101,84,121,112, - 101,104,3,100,0,2,73,68,106,100,0,32,104,116,116,112,58,47,47,119,119, - 119,46,119,51,46,111,114,103,47,50,48,48,49,47,88,77,76,83,99,104,101, - 109,97,106,100,0,5,102,97,108,115,101,106,100,0,8,111,112,116,105,111, - 110,97,108,100,0,9,117,110,100,101,102,105,110,101,100,100,0,9,117, - 110,100,101,102,105,110,101,100,100,0,9,117,110,100,101,102,105,110, - 101,100,104,2,104,2,100,0,9,97,116,116,114,105,98,117,116,101,104,3, - 100,0,4,108,97,110,103,106,100,0,36,104,116,116,112,58,47,47,119,119, - 119,46,119,51,46,111,114,103,47,88,77,76,47,49,57,57,56,47,110,97,109, - 101,115,112,97,99,101,104,9,100,0,16,115,99,104,101,109,97,95,97,116, - 116,114,105,98,117,116,101,104,3,100,0,4,108,97,110,103,106,100,0,36, - 104,116,116,112,58,47,47,119,119,119,46,119,51,46,111,114,103,47,88, - 77,76,47,49,57,57,56,47,110,97,109,101,115,112,97,99,101,108,0,0,0,1, - 104,2,100,0,10,115,105,109,112,108,101,84,121,112,101,104,3,100,0,15, - 95,120,109,101,114,108,95,110,111,95,110,97,109,101,95,108,0,0,0,1, - 100,0,4,108,97,110,103,106,106,106,100,0,5,102,97,108,115,101,106, - 100,0,8,111,112,116,105,111,110,97,108,100,0,9,117,110,100,101,102, - 105,110,101,100,100,0,9,117,110,100,101,102,105,110,101,100,100,0,9, - 117,110,100,101,102,105,110,101,100,104,2,104,2,100,0,10,115,105,109, - 112,108,101,84,121,112,101,104,3,100,0,15,95,120,109,101,114,108,95, - 110,111,95,110,97,109,101,95,108,0,0,0,2,100,0,15,95,120,109,101,114, - 108,95,110,111,95,110,97,109,101,95,100,0,4,108,97,110,103,106,106, - 104,9,100,0,18,115,99,104,101,109,97,95,115,105,109,112,108,101,95, - 116,121,112,101,104,3,100,0,15,95,120,109,101,114,108,95,110,111,95, - 110,97,109,101,95,108,0,0,0,2,100,0,15,95,120,109,101,114,108,95,110, - 111,95,110,97,109,101,95,100,0,4,108,97,110,103,106,106,108,0,0,0,2, - 100,0,15,95,120,109,101,114,108,95,110,111,95,110,97,109,101,95,100, - 0,4,108,97,110,103,106,104,3,100,0,6,115,116,114,105,110,103,106,100, - 0,32,104,116,116,112,58,47,47,119,119,119,46,119,51,46,111,114,103,47, - 50,48,48,49,47,88,77,76,83,99,104,101,109,97,100,0,5,102,97,108,115, - 101,106,108,0,0,0,1,104,2,100,0,11,101,110,117,109,101,114,97,116,105, - 111,110,108,0,0,0,1,106,106,106,100,0,6,97,116,111,109,105,99,108,0,0, - 0,1,104,2,100,0,11,114,101,115,116,114,105,99,116,105,111,110,104,2, - 104,3,100,0,6,115,116,114,105,110,103,106,100,0,32,104,116,116,112,58, - 47,47,119,119,119,46,119,51,46,111,114,103,47,50,48,48,49,47,88,77,76, - 83,99,104,101,109,97,108,0,0,0,1,104,2,100,0,11,101,110,117,109,101, - 114,97,116,105,111,110,106,106,106,106>>)). - default_namespace_by_convention() -> [{xml,'http://www.w3.org/XML/1998/namespace'}]. diff --git a/lib/xmerl/test/xmerl_xsd_SUITE.erl b/lib/xmerl/test/xmerl_xsd_SUITE.erl index 101fbcd50f..92c8287782 100644 --- a/lib/xmerl/test/xmerl_xsd_SUITE.erl +++ b/lib/xmerl/test/xmerl_xsd_SUITE.erl @@ -41,7 +41,8 @@ groups() -> [{group, primitive_datatypes}, {group, derived_datatypes}]}, {validation_tests, [], - [{group, xmlSchemaPrimerExamples}, + [{group, xmlXsdAndExample}, + {group, xmlSchemaPrimerExamples}, {group, miscXMLexamples}]}, {primitive_datatypes, [], [string, boolean, decimal, float, double, duration, @@ -55,6 +56,8 @@ groups() -> negativeInteger, long, int, short, byte, nonNegativeInteger, unsignedLong, unsignedInt, unsignedShort, unsignedByte, positiveInteger]}, + {xmlXsdAndExample, [], + [xml_xsd, xml_lang_attr]}, {xmlSchemaPrimerExamples, [], [po, po1, po2, ipo, ipo_redefine, '4Q99']}, {miscXMLexamples, [], @@ -863,6 +866,19 @@ compare_duration(_Config) -> ?line indefinite = xmerl_xsd_type:compare_durations("P5M","P153D"), ?line lt = xmerl_xsd_type:compare_durations("P5M","P154D"). +xml_xsd(suite) -> []; +xml_xsd(Config) -> + DataDir = ?config(data_dir, Config), + Options = [{fetch_path, [DataDir]}], + {ok, _} = xmerl_xsd:process_schema("xml.xsd", Options). + +xml_lang_attr(suite) -> []; +xml_lang_attr(Config) -> + DataDir = ?config(data_dir, Config), + {Element, _} = xmerl_scan:file(filename:join([DataDir, "book.xml"])), + Options = [{fetch_path, [DataDir]}], + {ok, Schema} = xmerl_xsd:process_schema("book.xsd", Options), + {Element, _} = xmerl_xsd:validate(Element, Schema). po(suite) -> []; po(Config) -> diff --git a/lib/xmerl/test/xmerl_xsd_SUITE_data/book.xml b/lib/xmerl/test/xmerl_xsd_SUITE_data/book.xml new file mode 100644 index 0000000000..17d7ceffee --- /dev/null +++ b/lib/xmerl/test/xmerl_xsd_SUITE_data/book.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8"?> +<book title="Title" xml:lang="EN"> + <author>Author1</author> + <author>Author2</author> +</book> diff --git a/lib/xmerl/test/xmerl_xsd_SUITE_data/book.xsd b/lib/xmerl/test/xmerl_xsd_SUITE_data/book.xsd new file mode 100644 index 0000000000..830951ec1b --- /dev/null +++ b/lib/xmerl/test/xmerl_xsd_SUITE_data/book.xsd @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> + <xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="xml.xsd"/> + <xs:element name="book"> + <xs:complexType> + <xs:sequence> + <xs:element name="author" type="xs:string" maxOccurs="unbounded"/> + </xs:sequence> + <xs:attribute name="title" type="xs:string"/> + <xs:attribute ref="xml:lang"/> + </xs:complexType> + </xs:element> +</xs:schema> diff --git a/lib/xmerl/test/xmerl_xsd_SUITE_data/xml.xsd b/lib/xmerl/test/xmerl_xsd_SUITE_data/xml.xsd new file mode 100644 index 0000000000..aea7d0db0a --- /dev/null +++ b/lib/xmerl/test/xmerl_xsd_SUITE_data/xml.xsd @@ -0,0 +1,287 @@ +<?xml version='1.0'?> +<?xml-stylesheet href="../2008/09/xsd.xsl" type="text/xsl"?> +<xs:schema targetNamespace="http://www.w3.org/XML/1998/namespace" + xmlns:xs="http://www.w3.org/2001/XMLSchema" + xmlns ="http://www.w3.org/1999/xhtml" + xml:lang="en"> + + <xs:annotation> + <xs:documentation> + <div> + <h1>About the XML namespace</h1> + + <div class="bodytext"> + <p> + This schema document describes the XML namespace, in a form + suitable for import by other schema documents. + </p> + <p> + See <a href="http://www.w3.org/XML/1998/namespace.html"> + http://www.w3.org/XML/1998/namespace.html</a> and + <a href="http://www.w3.org/TR/REC-xml"> + http://www.w3.org/TR/REC-xml</a> for information + about this namespace. + </p> + <p> + Note that local names in this namespace are intended to be + defined only by the World Wide Web Consortium or its subgroups. + The names currently defined in this namespace are listed below. + They should not be used with conflicting semantics by any Working + Group, specification, or document instance. + </p> + <p> + See further below in this document for more information about <a + href="#usage">how to refer to this schema document from your own + XSD schema documents</a> and about <a href="#nsversioning">the + namespace-versioning policy governing this schema document</a>. + </p> + </div> + </div> + </xs:documentation> + </xs:annotation> + + <xs:attribute name="lang"> + <xs:annotation> + <xs:documentation> + <div> + + <h3>lang (as an attribute name)</h3> + <p> + denotes an attribute whose value + is a language code for the natural language of the content of + any element; its value is inherited. This name is reserved + by virtue of its definition in the XML specification.</p> + + </div> + <div> + <h4>Notes</h4> + <p> + Attempting to install the relevant ISO 2- and 3-letter + codes as the enumerated possible values is probably never + going to be a realistic possibility. + </p> + <p> + See BCP 47 at <a href="http://www.rfc-editor.org/rfc/bcp/bcp47.txt"> + http://www.rfc-editor.org/rfc/bcp/bcp47.txt</a> + and the IANA language subtag registry at + <a href="http://www.iana.org/assignments/language-subtag-registry"> + http://www.iana.org/assignments/language-subtag-registry</a> + for further information. + </p> + <p> + The union allows for the 'un-declaration' of xml:lang with + the empty string. + </p> + </div> + </xs:documentation> + </xs:annotation> + <xs:simpleType> + <xs:union memberTypes="xs:language"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value=""/> + </xs:restriction> + </xs:simpleType> + </xs:union> + </xs:simpleType> + </xs:attribute> + + <xs:attribute name="space"> + <xs:annotation> + <xs:documentation> + <div> + + <h3>space (as an attribute name)</h3> + <p> + denotes an attribute whose + value is a keyword indicating what whitespace processing + discipline is intended for the content of the element; its + value is inherited. This name is reserved by virtue of its + definition in the XML specification.</p> + + </div> + </xs:documentation> + </xs:annotation> + <xs:simpleType> + <xs:restriction base="xs:NCName"> + <xs:enumeration value="default"/> + <xs:enumeration value="preserve"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + + <xs:attribute name="base" type="xs:anyURI"> <xs:annotation> + <xs:documentation> + <div> + + <h3>base (as an attribute name)</h3> + <p> + denotes an attribute whose value + provides a URI to be used as the base for interpreting any + relative URIs in the scope of the element on which it + appears; its value is inherited. This name is reserved + by virtue of its definition in the XML Base specification.</p> + + <p> + See <a + href="http://www.w3.org/TR/xmlbase/">http://www.w3.org/TR/xmlbase/</a> + for information about this attribute. + </p> + </div> + </xs:documentation> + </xs:annotation> + </xs:attribute> + + <xs:attribute name="id" type="xs:ID"> + <xs:annotation> + <xs:documentation> + <div> + + <h3>id (as an attribute name)</h3> + <p> + denotes an attribute whose value + should be interpreted as if declared to be of type ID. + This name is reserved by virtue of its definition in the + xml:id specification.</p> + + <p> + See <a + href="http://www.w3.org/TR/xml-id/">http://www.w3.org/TR/xml-id/</a> + for information about this attribute. + </p> + </div> + </xs:documentation> + </xs:annotation> + </xs:attribute> + + <xs:attributeGroup name="specialAttrs"> + <xs:attribute ref="xml:base"/> + <xs:attribute ref="xml:lang"/> + <xs:attribute ref="xml:space"/> + <xs:attribute ref="xml:id"/> + </xs:attributeGroup> + + <xs:annotation> + <xs:documentation> + <div> + + <h3>Father (in any context at all)</h3> + + <div class="bodytext"> + <p> + denotes Jon Bosak, the chair of + the original XML Working Group. This name is reserved by + the following decision of the W3C XML Plenary and + XML Coordination groups: + </p> + <blockquote> + <p> + In appreciation for his vision, leadership and + dedication the W3C XML Plenary on this 10th day of + February, 2000, reserves for Jon Bosak in perpetuity + the XML name "xml:Father". + </p> + </blockquote> + </div> + </div> + </xs:documentation> + </xs:annotation> + + <xs:annotation> + <xs:documentation> + <div xml:id="usage" id="usage"> + <h2><a name="usage">About this schema document</a></h2> + + <div class="bodytext"> + <p> + This schema defines attributes and an attribute group suitable + for use by schemas wishing to allow <code>xml:base</code>, + <code>xml:lang</code>, <code>xml:space</code> or + <code>xml:id</code> attributes on elements they define. + </p> + <p> + To enable this, such a schema must import this schema for + the XML namespace, e.g. as follows: + </p> + <pre> + <schema . . .> + . . . + <import namespace="http://www.w3.org/XML/1998/namespace" + schemaLocation="http://www.w3.org/2001/xml.xsd"/> + </pre> + <p> + or + </p> + <pre> + <import namespace="http://www.w3.org/XML/1998/namespace" + schemaLocation="http://www.w3.org/2009/01/xml.xsd"/> + </pre> + <p> + Subsequently, qualified reference to any of the attributes or the + group defined below will have the desired effect, e.g. + </p> + <pre> + <type . . .> + . . . + <attributeGroup ref="xml:specialAttrs"/> + </pre> + <p> + will define a type which will schema-validate an instance element + with any of those attributes. + </p> + </div> + </div> + </xs:documentation> + </xs:annotation> + + <xs:annotation> + <xs:documentation> + <div id="nsversioning" xml:id="nsversioning"> + <h2><a name="nsversioning">Versioning policy for this schema document</a></h2> + <div class="bodytext"> + <p> + In keeping with the XML Schema WG's standard versioning + policy, this schema document will persist at + <a href="http://www.w3.org/2009/01/xml.xsd"> + http://www.w3.org/2009/01/xml.xsd</a>. + </p> + <p> + At the date of issue it can also be found at + <a href="http://www.w3.org/2001/xml.xsd"> + http://www.w3.org/2001/xml.xsd</a>. + </p> + <p> + The schema document at that URI may however change in the future, + in order to remain compatible with the latest version of XML + Schema itself, or with the XML namespace itself. In other words, + if the XML Schema or XML namespaces change, the version of this + document at <a href="http://www.w3.org/2001/xml.xsd"> + http://www.w3.org/2001/xml.xsd + </a> + will change accordingly; the version at + <a href="http://www.w3.org/2009/01/xml.xsd"> + http://www.w3.org/2009/01/xml.xsd + </a> + will not change. + </p> + <p> + Previous dated (and unchanging) versions of this schema + document are at: + </p> + <ul> + <li><a href="http://www.w3.org/2009/01/xml.xsd"> + http://www.w3.org/2009/01/xml.xsd</a></li> + <li><a href="http://www.w3.org/2007/08/xml.xsd"> + http://www.w3.org/2007/08/xml.xsd</a></li> + <li><a href="http://www.w3.org/2004/10/xml.xsd"> + http://www.w3.org/2004/10/xml.xsd</a></li> + <li><a href="http://www.w3.org/2001/03/xml.xsd"> + http://www.w3.org/2001/03/xml.xsd</a></li> + </ul> + </div> + </div> + </xs:documentation> + </xs:annotation> + +</xs:schema> + diff --git a/lib/xmerl/vsn.mk b/lib/xmerl/vsn.mk index 1ed230316f..09d81e0533 100644 --- a/lib/xmerl/vsn.mk +++ b/lib/xmerl/vsn.mk @@ -1 +1 @@ -XMERL_VSN = 1.3.8 +XMERL_VSN = 1.3.10 diff --git a/make/otp_release_targets.mk b/make/otp_release_targets.mk index 97e9e4bb43..e104b68991 100644 --- a/make/otp_release_targets.mk +++ b/make/otp_release_targets.mk @@ -113,7 +113,16 @@ $(HTMLDIR)/$(APPLICATION).eix: $(XML_FILES) $(SPECS_FILES) docs: $(HTMLDIR)/$(APPLICATION).eix xmllint: $(XML_FILES) - $(XMLLINT) --noout --valid --nodefdtd --loaddtd --path $(DOCGEN)/priv/dtd:$(DOCGEN)/priv/dtd_html_entities $(XML_FILES) + @echo "Running xmllint" + @BookFiles=`awk -F\" '/xi:include/ {print $$2}' book.xml`; \ + for i in $$BookFiles; do \ + if [ $$i = "notes.xml" ]; then \ + echo Checking $$i; \ + xmllint --noout --valid --nodefdtd --loaddtd --path $(DOCGEN)/priv/dtd:$(DOCGEN)/priv/dtd_html_entities $$i; \ + else\ + awk -F\" '/xi:include/ {print "echo Checking " $$2 ;print "xmllint --noout --valid --nodefdtd --loaddtd --path $(DOCGEN)/priv/dtd:$(DOCGEN)/priv/dtd_html_entities " $$2}' $$i |sh; \ + fi \ + done # ---------------------------------------------------- # Local documentation target for testing @@ -1443,13 +1443,13 @@ case "$1" in do_debuginfo_win32 "$2";; env_win32) if [ x"$2" = x"x64" -o x"$2" = x"amd64" ]; then - if [ -x /usr/bin/msysinfo ]; then + if [ -x /usr/bin/msys-?.0.dll ]; then echo_env_msys64 else echo_env_win64 fi else - if [ -x /usr/bin/msysinfo ]; then + if [ -x /usr/bin/msys-?.0.dll ]; then echo_env_msys32 else echo_env_win32 diff --git a/otp_versions.table b/otp_versions.table index b5e64cf6dd..0910e96559 100644 --- a/otp_versions.table +++ b/otp_versions.table @@ -1,4 +1,35 @@ +OTP-18.3.4.3 : ssh-4.2.2.2 # asn1-4.0.2 common_test-1.12.1.1 compiler-6.0.3 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2.1 cosProperty-1.2 cosTime-1.2.1 cosTransactions-1.3.1 crypto-3.6.3 debugger-4.1.2 dialyzer-2.9 diameter-1.11.2 edoc-0.7.18 eldap-1.2.1 erl_docgen-0.4.2 erl_interface-3.8.2 erts-7.3.1.1 et-1.5.1 eunit-2.2.13 gs-1.6 hipe-3.15 ic-4.4 inets-6.2.4 jinterface-1.6.1 kernel-4.2 megaco-3.18 mnesia-4.13.4 observer-2.1.2 odbc-2.11.1 orber-3.8.1 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1.1 percept-0.8.11 public_key-1.1.1 reltool-0.7 runtime_tools-1.9.3 sasl-2.7 snmp-5.2.2 ssl-7.3.3.1 stdlib-2.8 syntax_tools-1.7 test_server-3.10 tools-2.8.3 typer-0.9.10 webtool-0.9.1 wx-1.6.1 xmerl-1.3.10 : +OTP-18.3.4.2 : common_test-1.12.1.1 erts-7.3.1.1 ssl-7.3.3.1 # asn1-4.0.2 compiler-6.0.3 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2.1 cosProperty-1.2 cosTime-1.2.1 cosTransactions-1.3.1 crypto-3.6.3 debugger-4.1.2 dialyzer-2.9 diameter-1.11.2 edoc-0.7.18 eldap-1.2.1 erl_docgen-0.4.2 erl_interface-3.8.2 et-1.5.1 eunit-2.2.13 gs-1.6 hipe-3.15 ic-4.4 inets-6.2.4 jinterface-1.6.1 kernel-4.2 megaco-3.18 mnesia-4.13.4 observer-2.1.2 odbc-2.11.1 orber-3.8.1 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1.1 percept-0.8.11 public_key-1.1.1 reltool-0.7 runtime_tools-1.9.3 sasl-2.7 snmp-5.2.2 ssh-4.2.2.1 stdlib-2.8 syntax_tools-1.7 test_server-3.10 tools-2.8.3 typer-0.9.10 webtool-0.9.1 wx-1.6.1 xmerl-1.3.10 : +OTP-18.3.4.1 : ssh-4.2.2.1 # asn1-4.0.2 common_test-1.12.1 compiler-6.0.3 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2.1 cosProperty-1.2 cosTime-1.2.1 cosTransactions-1.3.1 crypto-3.6.3 debugger-4.1.2 dialyzer-2.9 diameter-1.11.2 edoc-0.7.18 eldap-1.2.1 erl_docgen-0.4.2 erl_interface-3.8.2 erts-7.3.1 et-1.5.1 eunit-2.2.13 gs-1.6 hipe-3.15 ic-4.4 inets-6.2.4 jinterface-1.6.1 kernel-4.2 megaco-3.18 mnesia-4.13.4 observer-2.1.2 odbc-2.11.1 orber-3.8.1 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1.1 percept-0.8.11 public_key-1.1.1 reltool-0.7 runtime_tools-1.9.3 sasl-2.7 snmp-5.2.2 ssl-7.3.3 stdlib-2.8 syntax_tools-1.7 test_server-3.10 tools-2.8.3 typer-0.9.10 webtool-0.9.1 wx-1.6.1 xmerl-1.3.10 : +OTP-18.3.4 : inets-6.2.4 ssl-7.3.3 # asn1-4.0.2 common_test-1.12.1 compiler-6.0.3 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2.1 cosProperty-1.2 cosTime-1.2.1 cosTransactions-1.3.1 crypto-3.6.3 debugger-4.1.2 dialyzer-2.9 diameter-1.11.2 edoc-0.7.18 eldap-1.2.1 erl_docgen-0.4.2 erl_interface-3.8.2 erts-7.3.1 et-1.5.1 eunit-2.2.13 gs-1.6 hipe-3.15 ic-4.4 jinterface-1.6.1 kernel-4.2 megaco-3.18 mnesia-4.13.4 observer-2.1.2 odbc-2.11.1 orber-3.8.1 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1.1 percept-0.8.11 public_key-1.1.1 reltool-0.7 runtime_tools-1.9.3 sasl-2.7 snmp-5.2.2 ssh-4.2.2 stdlib-2.8 syntax_tools-1.7 test_server-3.10 tools-2.8.3 typer-0.9.10 webtool-0.9.1 wx-1.6.1 xmerl-1.3.10 : +OTP-18.3.3 : common_test-1.12.1 inets-6.2.3 ssl-7.3.2 # asn1-4.0.2 compiler-6.0.3 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2.1 cosProperty-1.2 cosTime-1.2.1 cosTransactions-1.3.1 crypto-3.6.3 debugger-4.1.2 dialyzer-2.9 diameter-1.11.2 edoc-0.7.18 eldap-1.2.1 erl_docgen-0.4.2 erl_interface-3.8.2 erts-7.3.1 et-1.5.1 eunit-2.2.13 gs-1.6 hipe-3.15 ic-4.4 jinterface-1.6.1 kernel-4.2 megaco-3.18 mnesia-4.13.4 observer-2.1.2 odbc-2.11.1 orber-3.8.1 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1.1 percept-0.8.11 public_key-1.1.1 reltool-0.7 runtime_tools-1.9.3 sasl-2.7 snmp-5.2.2 ssh-4.2.2 stdlib-2.8 syntax_tools-1.7 test_server-3.10 tools-2.8.3 typer-0.9.10 webtool-0.9.1 wx-1.6.1 xmerl-1.3.10 : +OTP-18.3.2 : inets-6.2.2 ssl-7.3.1 # asn1-4.0.2 common_test-1.12 compiler-6.0.3 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2.1 cosProperty-1.2 cosTime-1.2.1 cosTransactions-1.3.1 crypto-3.6.3 debugger-4.1.2 dialyzer-2.9 diameter-1.11.2 edoc-0.7.18 eldap-1.2.1 erl_docgen-0.4.2 erl_interface-3.8.2 erts-7.3.1 et-1.5.1 eunit-2.2.13 gs-1.6 hipe-3.15 ic-4.4 jinterface-1.6.1 kernel-4.2 megaco-3.18 mnesia-4.13.4 observer-2.1.2 odbc-2.11.1 orber-3.8.1 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1.1 percept-0.8.11 public_key-1.1.1 reltool-0.7 runtime_tools-1.9.3 sasl-2.7 snmp-5.2.2 ssh-4.2.2 stdlib-2.8 syntax_tools-1.7 test_server-3.10 tools-2.8.3 typer-0.9.10 webtool-0.9.1 wx-1.6.1 xmerl-1.3.10 : +OTP-18.3.1 : erts-7.3.1 inets-6.2.1 mnesia-4.13.4 # asn1-4.0.2 common_test-1.12 compiler-6.0.3 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2.1 cosProperty-1.2 cosTime-1.2.1 cosTransactions-1.3.1 crypto-3.6.3 debugger-4.1.2 dialyzer-2.9 diameter-1.11.2 edoc-0.7.18 eldap-1.2.1 erl_docgen-0.4.2 erl_interface-3.8.2 et-1.5.1 eunit-2.2.13 gs-1.6 hipe-3.15 ic-4.4 jinterface-1.6.1 kernel-4.2 megaco-3.18 observer-2.1.2 odbc-2.11.1 orber-3.8.1 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1.1 percept-0.8.11 public_key-1.1.1 reltool-0.7 runtime_tools-1.9.3 sasl-2.7 snmp-5.2.2 ssh-4.2.2 ssl-7.3 stdlib-2.8 syntax_tools-1.7 test_server-3.10 tools-2.8.3 typer-0.9.10 webtool-0.9.1 wx-1.6.1 xmerl-1.3.10 : +OTP-18.3 : asn1-4.0.2 common_test-1.12 compiler-6.0.3 cosNotification-1.2.1 cosTime-1.2.1 cosTransactions-1.3.1 crypto-3.6.3 debugger-4.1.2 dialyzer-2.9 diameter-1.11.2 edoc-0.7.18 eldap-1.2.1 erl_docgen-0.4.2 erl_interface-3.8.2 erts-7.3 eunit-2.2.13 hipe-3.15 inets-6.2 kernel-4.2 mnesia-4.13.3 observer-2.1.2 orber-3.8.1 public_key-1.1.1 runtime_tools-1.9.3 sasl-2.7 snmp-5.2.2 ssh-4.2.2 ssl-7.3 stdlib-2.8 test_server-3.10 tools-2.8.3 webtool-0.9.1 wx-1.6.1 xmerl-1.3.10 # cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosProperty-1.2 et-1.5.1 gs-1.6 ic-4.4 jinterface-1.6.1 megaco-3.18 odbc-2.11.1 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1.1 percept-0.8.11 reltool-0.7 syntax_tools-1.7 typer-0.9.10 : +OTP-18.2.4 : common_test-1.11.2 # asn1-4.0.1 compiler-6.0.2 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2 cosProperty-1.2 cosTime-1.2 cosTransactions-1.3 crypto-3.6.2 debugger-4.1.1 dialyzer-2.8.2 diameter-1.11.1 edoc-0.7.17 eldap-1.2 erl_docgen-0.4.1 erl_interface-3.8.1 erts-7.2.1 et-1.5.1 eunit-2.2.12 gs-1.6 hipe-3.14 ic-4.4 inets-6.1.1 jinterface-1.6.1 kernel-4.1.1 megaco-3.18 mnesia-4.13.2 observer-2.1.1 odbc-2.11.1 orber-3.8 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1.1 percept-0.8.11 public_key-1.1 reltool-0.7 runtime_tools-1.9.2 sasl-2.6.1 snmp-5.2.1 ssh-4.2.1 ssl-7.2 stdlib-2.7 syntax_tools-1.7 test_server-3.9.1 tools-2.8.2 typer-0.9.10 webtool-0.9 wx-1.6 xmerl-1.3.9 : +OTP-18.2.3 : inets-6.1.1 # asn1-4.0.1 common_test-1.11.1 compiler-6.0.2 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2 cosProperty-1.2 cosTime-1.2 cosTransactions-1.3 crypto-3.6.2 debugger-4.1.1 dialyzer-2.8.2 diameter-1.11.1 edoc-0.7.17 eldap-1.2 erl_docgen-0.4.1 erl_interface-3.8.1 erts-7.2.1 et-1.5.1 eunit-2.2.12 gs-1.6 hipe-3.14 ic-4.4 jinterface-1.6.1 kernel-4.1.1 megaco-3.18 mnesia-4.13.2 observer-2.1.1 odbc-2.11.1 orber-3.8 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1.1 percept-0.8.11 public_key-1.1 reltool-0.7 runtime_tools-1.9.2 sasl-2.6.1 snmp-5.2.1 ssh-4.2.1 ssl-7.2 stdlib-2.7 syntax_tools-1.7 test_server-3.9.1 tools-2.8.2 typer-0.9.10 webtool-0.9 wx-1.6 xmerl-1.3.9 : +OTP-18.2.2 : ssh-4.2.1 # asn1-4.0.1 common_test-1.11.1 compiler-6.0.2 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2 cosProperty-1.2 cosTime-1.2 cosTransactions-1.3 crypto-3.6.2 debugger-4.1.1 dialyzer-2.8.2 diameter-1.11.1 edoc-0.7.17 eldap-1.2 erl_docgen-0.4.1 erl_interface-3.8.1 erts-7.2.1 et-1.5.1 eunit-2.2.12 gs-1.6 hipe-3.14 ic-4.4 inets-6.1 jinterface-1.6.1 kernel-4.1.1 megaco-3.18 mnesia-4.13.2 observer-2.1.1 odbc-2.11.1 orber-3.8 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1.1 percept-0.8.11 public_key-1.1 reltool-0.7 runtime_tools-1.9.2 sasl-2.6.1 snmp-5.2.1 ssl-7.2 stdlib-2.7 syntax_tools-1.7 test_server-3.9.1 tools-2.8.2 typer-0.9.10 webtool-0.9 wx-1.6 xmerl-1.3.9 : +OTP-18.2.1 : erts-7.2.1 # asn1-4.0.1 common_test-1.11.1 compiler-6.0.2 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2 cosProperty-1.2 cosTime-1.2 cosTransactions-1.3 crypto-3.6.2 debugger-4.1.1 dialyzer-2.8.2 diameter-1.11.1 edoc-0.7.17 eldap-1.2 erl_docgen-0.4.1 erl_interface-3.8.1 et-1.5.1 eunit-2.2.12 gs-1.6 hipe-3.14 ic-4.4 inets-6.1 jinterface-1.6.1 kernel-4.1.1 megaco-3.18 mnesia-4.13.2 observer-2.1.1 odbc-2.11.1 orber-3.8 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1.1 percept-0.8.11 public_key-1.1 reltool-0.7 runtime_tools-1.9.2 sasl-2.6.1 snmp-5.2.1 ssh-4.2 ssl-7.2 stdlib-2.7 syntax_tools-1.7 test_server-3.9.1 tools-2.8.2 typer-0.9.10 webtool-0.9 wx-1.6 xmerl-1.3.9 : +OTP-18.2 : asn1-4.0.1 common_test-1.11.1 compiler-6.0.2 crypto-3.6.2 dialyzer-2.8.2 diameter-1.11.1 erl_docgen-0.4.1 erl_interface-3.8.1 erts-7.2 eunit-2.2.12 hipe-3.14 inets-6.1 jinterface-1.6.1 kernel-4.1.1 observer-2.1.1 parsetools-2.1.1 public_key-1.1 runtime_tools-1.9.2 sasl-2.6.1 snmp-5.2.1 ssh-4.2 ssl-7.2 stdlib-2.7 test_server-3.9.1 tools-2.8.2 typer-0.9.10 wx-1.6 xmerl-1.3.9 # cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2 cosProperty-1.2 cosTime-1.2 cosTransactions-1.3 debugger-4.1.1 edoc-0.7.17 eldap-1.2 et-1.5.1 gs-1.6 ic-4.4 megaco-3.18 mnesia-4.13.2 odbc-2.11.1 orber-3.8 os_mon-2.4 ose-1.1 otp_mibs-1.1 percept-0.8.11 reltool-0.7 syntax_tools-1.7 webtool-0.9 : +OTP-18.1.5 : ssh-4.1.3 # asn1-4.0 common_test-1.11 compiler-6.0.1 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2 cosProperty-1.2 cosTime-1.2 cosTransactions-1.3 crypto-3.6.1 debugger-4.1.1 dialyzer-2.8.1 diameter-1.11 edoc-0.7.17 eldap-1.2 erl_docgen-0.4 erl_interface-3.8 erts-7.1 et-1.5.1 eunit-2.2.11 gs-1.6 hipe-3.13 ic-4.4 inets-6.0.3 jinterface-1.6 kernel-4.1 megaco-3.18 mnesia-4.13.2 observer-2.1 odbc-2.11.1 orber-3.8 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1 percept-0.8.11 public_key-1.0.1 reltool-0.7 runtime_tools-1.9.1 sasl-2.6 snmp-5.2 ssl-7.1 stdlib-2.6 syntax_tools-1.7 test_server-3.9 tools-2.8.1 typer-0.9.9 webtool-0.9 wx-1.5 xmerl-1.3.8 : +OTP-18.1.4 : inets-6.0.3 # asn1-4.0 common_test-1.11 compiler-6.0.1 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2 cosProperty-1.2 cosTime-1.2 cosTransactions-1.3 crypto-3.6.1 debugger-4.1.1 dialyzer-2.8.1 diameter-1.11 edoc-0.7.17 eldap-1.2 erl_docgen-0.4 erl_interface-3.8 erts-7.1 et-1.5.1 eunit-2.2.11 gs-1.6 hipe-3.13 ic-4.4 jinterface-1.6 kernel-4.1 megaco-3.18 mnesia-4.13.2 observer-2.1 odbc-2.11.1 orber-3.8 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1 percept-0.8.11 public_key-1.0.1 reltool-0.7 runtime_tools-1.9.1 sasl-2.6 snmp-5.2 ssh-4.1.2 ssl-7.1 stdlib-2.6 syntax_tools-1.7 test_server-3.9 tools-2.8.1 typer-0.9.9 webtool-0.9 wx-1.5 xmerl-1.3.8 : +OTP-18.1.3 : ssh-4.1.2 # asn1-4.0 common_test-1.11 compiler-6.0.1 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2 cosProperty-1.2 cosTime-1.2 cosTransactions-1.3 crypto-3.6.1 debugger-4.1.1 dialyzer-2.8.1 diameter-1.11 edoc-0.7.17 eldap-1.2 erl_docgen-0.4 erl_interface-3.8 erts-7.1 et-1.5.1 eunit-2.2.11 gs-1.6 hipe-3.13 ic-4.4 inets-6.0.2 jinterface-1.6 kernel-4.1 megaco-3.18 mnesia-4.13.2 observer-2.1 odbc-2.11.1 orber-3.8 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1 percept-0.8.11 public_key-1.0.1 reltool-0.7 runtime_tools-1.9.1 sasl-2.6 snmp-5.2 ssl-7.1 stdlib-2.6 syntax_tools-1.7 test_server-3.9 tools-2.8.1 typer-0.9.9 webtool-0.9 wx-1.5 xmerl-1.3.8 : +OTP-18.1.2 : ssh-4.1.1 # asn1-4.0 common_test-1.11 compiler-6.0.1 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2 cosProperty-1.2 cosTime-1.2 cosTransactions-1.3 crypto-3.6.1 debugger-4.1.1 dialyzer-2.8.1 diameter-1.11 edoc-0.7.17 eldap-1.2 erl_docgen-0.4 erl_interface-3.8 erts-7.1 et-1.5.1 eunit-2.2.11 gs-1.6 hipe-3.13 ic-4.4 inets-6.0.2 jinterface-1.6 kernel-4.1 megaco-3.18 mnesia-4.13.2 observer-2.1 odbc-2.11.1 orber-3.8 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1 percept-0.8.11 public_key-1.0.1 reltool-0.7 runtime_tools-1.9.1 sasl-2.6 snmp-5.2 ssl-7.1 stdlib-2.6 syntax_tools-1.7 test_server-3.9 tools-2.8.1 typer-0.9.9 webtool-0.9 wx-1.5 xmerl-1.3.8 : +OTP-18.1.1 : inets-6.0.2 mnesia-4.13.2 # asn1-4.0 common_test-1.11 compiler-6.0.1 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2 cosProperty-1.2 cosTime-1.2 cosTransactions-1.3 crypto-3.6.1 debugger-4.1.1 dialyzer-2.8.1 diameter-1.11 edoc-0.7.17 eldap-1.2 erl_docgen-0.4 erl_interface-3.8 erts-7.1 et-1.5.1 eunit-2.2.11 gs-1.6 hipe-3.13 ic-4.4 jinterface-1.6 kernel-4.1 megaco-3.18 observer-2.1 odbc-2.11.1 orber-3.8 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1 percept-0.8.11 public_key-1.0.1 reltool-0.7 runtime_tools-1.9.1 sasl-2.6 snmp-5.2 ssh-4.1 ssl-7.1 stdlib-2.6 syntax_tools-1.7 test_server-3.9 tools-2.8.1 typer-0.9.9 webtool-0.9 wx-1.5 xmerl-1.3.8 : +OTP-18.1 : compiler-6.0.1 crypto-3.6.1 debugger-4.1.1 dialyzer-2.8.1 diameter-1.11 erts-7.1 eunit-2.2.11 hipe-3.13 inets-6.0.1 kernel-4.1 mnesia-4.13.1 odbc-2.11.1 public_key-1.0.1 sasl-2.6 ssh-4.1 ssl-7.1 stdlib-2.6 tools-2.8.1 wx-1.5 # asn1-4.0 common_test-1.11 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2 cosProperty-1.2 cosTime-1.2 cosTransactions-1.3 edoc-0.7.17 eldap-1.2 erl_docgen-0.4 erl_interface-3.8 et-1.5.1 gs-1.6 ic-4.4 jinterface-1.6 megaco-3.18 observer-2.1 orber-3.8 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1 percept-0.8.11 reltool-0.7 runtime_tools-1.9.1 snmp-5.2 syntax_tools-1.7 test_server-3.9 typer-0.9.9 webtool-0.9 xmerl-1.3.8 : +OTP-18.0.3 : erts-7.0.3 # asn1-4.0 common_test-1.11 compiler-6.0 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2 cosProperty-1.2 cosTime-1.2 cosTransactions-1.3 crypto-3.6 debugger-4.1 dialyzer-2.8 diameter-1.10 edoc-0.7.17 eldap-1.2 erl_docgen-0.4 erl_interface-3.8 et-1.5.1 eunit-2.2.10 gs-1.6 hipe-3.12 ic-4.4 inets-6.0 jinterface-1.6 kernel-4.0 megaco-3.18 mnesia-4.13 observer-2.1 odbc-2.11 orber-3.8 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1 percept-0.8.11 public_key-1.0 reltool-0.7 runtime_tools-1.9.1 sasl-2.5 snmp-5.2 ssh-4.0 ssl-7.0 stdlib-2.5 syntax_tools-1.7 test_server-3.9 tools-2.8 typer-0.9.9 webtool-0.9 wx-1.4 xmerl-1.3.8 : +OTP-18.0.2 : erts-7.0.2 runtime_tools-1.9.1 # asn1-4.0 common_test-1.11 compiler-6.0 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2 cosProperty-1.2 cosTime-1.2 cosTransactions-1.3 crypto-3.6 debugger-4.1 dialyzer-2.8 diameter-1.10 edoc-0.7.17 eldap-1.2 erl_docgen-0.4 erl_interface-3.8 et-1.5.1 eunit-2.2.10 gs-1.6 hipe-3.12 ic-4.4 inets-6.0 jinterface-1.6 kernel-4.0 megaco-3.18 mnesia-4.13 observer-2.1 odbc-2.11 orber-3.8 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1 percept-0.8.11 public_key-1.0 reltool-0.7 sasl-2.5 snmp-5.2 ssh-4.0 ssl-7.0 stdlib-2.5 syntax_tools-1.7 test_server-3.9 tools-2.8 typer-0.9.9 webtool-0.9 wx-1.4 xmerl-1.3.8 : +OTP-18.0.1 : erts-7.0.1 # asn1-4.0 common_test-1.11 compiler-6.0 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2 cosProperty-1.2 cosTime-1.2 cosTransactions-1.3 crypto-3.6 debugger-4.1 dialyzer-2.8 diameter-1.10 edoc-0.7.17 eldap-1.2 erl_docgen-0.4 erl_interface-3.8 et-1.5.1 eunit-2.2.10 gs-1.6 hipe-3.12 ic-4.4 inets-6.0 jinterface-1.6 kernel-4.0 megaco-3.18 mnesia-4.13 observer-2.1 odbc-2.11 orber-3.8 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1 percept-0.8.11 public_key-1.0 reltool-0.7 runtime_tools-1.9 sasl-2.5 snmp-5.2 ssh-4.0 ssl-7.0 stdlib-2.5 syntax_tools-1.7 test_server-3.9 tools-2.8 typer-0.9.9 webtool-0.9 wx-1.4 xmerl-1.3.8 : OTP-18.0 : asn1-4.0 common_test-1.11 compiler-6.0 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2 cosProperty-1.2 cosTime-1.2 cosTransactions-1.3 crypto-3.6 debugger-4.1 dialyzer-2.8 diameter-1.10 edoc-0.7.17 eldap-1.2 erl_docgen-0.4 erl_interface-3.8 erts-7.0 et-1.5.1 eunit-2.2.10 gs-1.6 hipe-3.12 ic-4.4 inets-6.0 jinterface-1.6 kernel-4.0 megaco-3.18 mnesia-4.13 observer-2.1 odbc-2.11 orber-3.8 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1 percept-0.8.11 public_key-1.0 reltool-0.7 runtime_tools-1.9 sasl-2.5 snmp-5.2 ssh-4.0 ssl-7.0 stdlib-2.5 syntax_tools-1.7 test_server-3.9 tools-2.8 typer-0.9.9 webtool-0.9 wx-1.4 xmerl-1.3.8 # : +OTP-17.5.6.9 : diameter-1.9.2.4 erts-6.4.1.6 ssl-6.0.1.2 # asn1-3.0.4 common_test-1.10.1 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3.1 dialyzer-2.7.4 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 inets-5.10.9 jinterface-1.5.12 kernel-3.2.0.1 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16.1 sasl-2.4.1 snmp-5.1.2 ssh-3.2.4 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8.1 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 : +OTP-17.5.6.8 : diameter-1.9.2.3 # asn1-3.0.4 common_test-1.10.1 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3.1 dialyzer-2.7.4 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.4.1.5 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 inets-5.10.9 jinterface-1.5.12 kernel-3.2.0.1 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16.1 sasl-2.4.1 snmp-5.1.2 ssh-3.2.4 ssl-6.0.1.1 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8.1 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 : +OTP-17.5.6.7 : diameter-1.9.2.2 # asn1-3.0.4 common_test-1.10.1 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3.1 dialyzer-2.7.4 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.4.1.5 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 inets-5.10.9 jinterface-1.5.12 kernel-3.2.0.1 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16.1 sasl-2.4.1 snmp-5.1.2 ssh-3.2.4 ssl-6.0.1.1 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8.1 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 : +OTP-17.5.6.6 : erts-6.4.1.5 # asn1-3.0.4 common_test-1.10.1 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3.1 dialyzer-2.7.4 diameter-1.9.2.1 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 inets-5.10.9 jinterface-1.5.12 kernel-3.2.0.1 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16.1 sasl-2.4.1 snmp-5.1.2 ssh-3.2.4 ssl-6.0.1.1 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8.1 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 : +OTP-17.5.6.5 : erts-6.4.1.4 kernel-3.2.0.1 ssl-6.0.1.1 # asn1-3.0.4 common_test-1.10.1 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3.1 dialyzer-2.7.4 diameter-1.9.2.1 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 inets-5.10.9 jinterface-1.5.12 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16.1 sasl-2.4.1 snmp-5.1.2 ssh-3.2.4 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8.1 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 : +OTP-17.5.6.4 : debugger-4.0.3.1 erts-6.4.1.3 # asn1-3.0.4 common_test-1.10.1 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 dialyzer-2.7.4 diameter-1.9.2.1 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 inets-5.10.9 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16.1 sasl-2.4.1 snmp-5.1.2 ssh-3.2.4 ssl-6.0.1 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8.1 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 : +OTP-17.5.6.3 : diameter-1.9.2.1 # asn1-3.0.4 common_test-1.10.1 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.4.1.2 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 inets-5.10.9 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16.1 sasl-2.4.1 snmp-5.1.2 ssh-3.2.4 ssl-6.0.1 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8.1 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 : +OTP-17.5.6.2 : erts-6.4.1.2 runtime_tools-1.8.16.1 # asn1-3.0.4 common_test-1.10.1 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 diameter-1.9.2 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 inets-5.10.9 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 sasl-2.4.1 snmp-5.1.2 ssh-3.2.4 ssl-6.0.1 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8.1 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 : +OTP-17.5.6.1 : erts-6.4.1.1 # asn1-3.0.4 common_test-1.10.1 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 diameter-1.9.2 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 inets-5.10.9 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16 sasl-2.4.1 snmp-5.1.2 ssh-3.2.4 ssl-6.0.1 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8.1 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 : OTP-17.5.6 : inets-5.10.9 ssh-3.2.4 ssl-6.0.1 # asn1-3.0.4 common_test-1.10.1 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 diameter-1.9.2 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.4.1 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16 sasl-2.4.1 snmp-5.1.2 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8.1 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 : OTP-17.5.5 : diameter-1.9.2 # asn1-3.0.4 common_test-1.10.1 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.4.1 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 inets-5.10.8 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16 sasl-2.4.1 snmp-5.1.2 ssh-3.2.3 ssl-6.0 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8.1 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 : OTP-17.5.4 : inets-5.10.8 ssh-3.2.3 # asn1-3.0.4 common_test-1.10.1 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 diameter-1.9.1 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.4.1 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16 sasl-2.4.1 snmp-5.1.2 ssl-6.0 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8.1 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 : diff --git a/system/doc/design_principles/des_princ.xml b/system/doc/design_principles/des_princ.xml index ba67a49585..0e087cf843 100644 --- a/system/doc/design_principles/des_princ.xml +++ b/system/doc/design_principles/des_princ.xml @@ -183,7 +183,7 @@ handle_cast({free, Ch}, Chs) -> <item>The server name, in this example the atom <c>ch2</c>, is hidden from the users of the client functions. This means that the name can be changed without affecting them.</item> - <item>The protcol (messages sent to and received from the server) + <item>The protocol (messages sent to and received from the server) is also hidden. This is good programming practice and allows one to change the protocol without changing the code using the interface functions.</item> diff --git a/system/doc/efficiency_guide/binaryhandling.xml b/system/doc/efficiency_guide/binaryhandling.xml index 51f8c4ebf0..0964b759d8 100644 --- a/system/doc/efficiency_guide/binaryhandling.xml +++ b/system/doc/efficiency_guide/binaryhandling.xml @@ -190,15 +190,15 @@ Bin4 = <<Bin1/binary,17>>, %% 5 !!! its size set to the size of the data stored in the binary, while the binary object has extra space allocated. The size of the binary object is either twice the - size of <c>Bin0</c> or 256, whichever is larger. In this case + size of <c>Bin1</c> or 256, whichever is larger. In this case it is 256.</item> <item>Line 3 is more interesting. <c>Bin1</c> <em>has</em> been used in an append operation, - and it has 255 bytes of unused storage at the end, so the 3 new + and it has 252 bytes of unused storage at the end, so the 3 new bytes are stored there.</item> - <item>Line 4. The same applies here. There are 252 bytes left, + <item>Line 4. The same applies here. There are 249 bytes left, so there is no problem storing another 3 bytes.</item> <item>Line 5. Here, something <em>interesting</em> happens. Notice diff --git a/system/doc/reference_manual/expressions.xml b/system/doc/reference_manual/expressions.xml index 668a51d6bc..893398b71b 100644 --- a/system/doc/reference_manual/expressions.xml +++ b/system/doc/reference_manual/expressions.xml @@ -568,10 +568,14 @@ Expr1 <input>op</input> Expr2</pre> <p>The arguments can be of different data types. The following order is defined:</p> <pre> -number < atom < reference < fun < port < pid < tuple < list < bit string</pre> +number < atom < reference < fun < port < pid < tuple < map < nil < list < bit string</pre> <p>Lists are compared element by element. Tuples are ordered by size, two tuples with the same size are compared element by element.</p> + <p>Maps are ordered by size, two maps with the same size are compared by keys in + ascending term order and then by values in key order. + In maps key order integers types are considered less than floats types. + </p> <p>When comparing an integer to a float, the term with the lesser precision is converted into the type of the other term, unless the operator is one of <c>=:=</c> or <c>=/=</c>. A float is more precise than @@ -591,7 +595,11 @@ true 2> <input>1=:=1.0.</input> false 3> <input>1 > a.</input> -false</pre> +false +4> <input>#{c => 3} > #{a => 1, b => 2}.</input> +false +4> <input>#{a => 1, b => 2} == #{a => 1.0, b => 2.0}.</input> +true</pre> </section> <section> diff --git a/system/doc/reference_manual/processes.xml b/system/doc/reference_manual/processes.xml index 6755bd8be6..f656d0318e 100644 --- a/system/doc/reference_manual/processes.xml +++ b/system/doc/reference_manual/processes.xml @@ -100,11 +100,9 @@ spawn(Module, Name, Args) -> pid() <item><c>exit(Reason)</c></item> <item><c>erlang:error(Reason)</c></item> <item><c>erlang:error(Reason, Args)</c></item> - <item><c>erlang:fault(Reason)</c></item> - <item><c>erlang:fault(Reason, Args)</c></item> </list> <p>The process then terminates with reason <c>Reason</c> for - <c>exit/1</c> or <c>{Reason,Stack} for the others</c>.</p> + <c>exit/1</c> or <c>{Reason,Stack}</c> for the others.</p> <p>A process can also be terminated if it receives an exit signal with another exit reason than <c>normal</c>, see <seealso marker="#errors">Error Handling</seealso>.</p> diff --git a/system/doc/reference_manual/typespec.xml b/system/doc/reference_manual/typespec.xml index 7891f3a6b9..22627058c1 100644 --- a/system/doc/reference_manual/typespec.xml +++ b/system/doc/reference_manual/typespec.xml @@ -197,6 +197,9 @@ <cell><c>char()</c></cell><cell><c>0..16#10ffff</c></cell> </row> <row> + <cell><c>nil()</c></cell><cell><c>[]</c></cell> + </row> + <row> <cell><c>number()</c></cell><cell><c>integer() | float()</c></cell> </row> <row> @@ -312,7 +315,7 @@ <p> As seen, the basic syntax of a type is an atom followed by closed parentheses. New types are declared using <c>-type</c> and <c>-opaque</c> - compiler attributes as in the following: + attributes as in the following: </p> <pre> -type my_struct_type() :: Type. @@ -435,8 +438,8 @@ <section> <title>Specifications for Functions</title> <p> - A specification (or contract) for a function is given using the new - compiler attribute <c>-spec</c>. The general format is as follows: + A specification (or contract) for a function is given using the + <c>-spec</c> attribute. The general format is as follows: </p> <pre> -spec Module:Function(ArgType1, ..., ArgTypeN) -> ReturnType.</pre> @@ -451,7 +454,7 @@ explicitly) import these functions. </p> <p> - Within a given module, the following shorthand suffice in most cases: + Within a given module, the following shorthand suffices in most cases: </p> <pre> -spec Function(ArgType1, ..., ArgTypeN) -> ReturnType.</pre> diff --git a/system/doc/tutorial/ei.c b/system/doc/tutorial/ei.c index b234a00768..c33e3fb78e 100644 --- a/system/doc/tutorial/ei.c +++ b/system/doc/tutorial/ei.c @@ -21,7 +21,7 @@ int main() { if (strncmp(ERL_ATOM_PTR(fnp), "foo", 3) == 0) { res = foo(ERL_INT_VALUE(argp)); - } else if (strncmp(ERL_ATOM_PTR(fnp), "bar", 17) == 0) { + } else if (strncmp(ERL_ATOM_PTR(fnp), "bar", 3) == 0) { res = bar(ERL_INT_VALUE(argp)); } diff --git a/system/doc/tutorial/example.xmlsrc b/system/doc/tutorial/example.xmlsrc index d49c7fe88c..91f09ec522 100644 --- a/system/doc/tutorial/example.xmlsrc +++ b/system/doc/tutorial/example.xmlsrc @@ -11,7 +11,7 @@ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software @@ -19,7 +19,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. - + </legalnotice> <title>Problem Example</title> @@ -39,7 +39,7 @@ <codeinclude file="complex.c" tag="" type="none"></codeinclude> <p>The functions are deliberately kept as simple as possible, for readability reasons.</p> - <p>From an Erlang perspektive, it is preferable to be able to call + <p>From an Erlang perspective, it is preferable to be able to call <c>foo</c> and <c>bar</c> without having to bother about that they are C functions:</p> <pre> |